Calculate CAN bit timing parameters

Calculate CAN bit timing parameters

TSYNC_SEG === 1

TSEG1 = Prop_Seg + Phase_Seg1

TSEG2 = Phase_Seg2

TBit = TSYNC_SEG + TSEG1 + TSEG2

TSEG2 / TBit = Sample Point

A detailed description about setting the correct CAN bit timing is given in a paper

by Florian Hartwich and Armin Bassemir by Robert Bosch:

The Configuration of the CAN Bit Timing.

Basically the CAN bit period can be subdivided into four time segments.

Each time segment consists of a number of Time Quanta (tq). The Time Quanta is the smallest time unit for all configuration values.

  • SYNC_SEG is 1 Time Quantum long. It is used to synchronize the various bus nodes.
  • PROP_SEG is programmable to be 1, 2,... 8 Time Quanta long.
    It is used to compensate for signal delays across the network.
  • PHASE_SEG1 is programmable to be 1,2, ... 8 Time Quanta long.
    It is used to compensate for edge phase errors and may be lengthened during resynchronization.
  • PHASE_SEG2 is the maximum of PHASE_SEG1 and the Information Processing Time long.
    It is also used to compensate edge phase errors and may be shortened during resynchronization.
    For this the minimum value of PHASE_SEG2 is the value of SJW.
  • Information Processing Time is less than or equal to 2 Time Quanta long.
  • The total number of Time Quanta has to be from 8 to 25.
    (Newer CAN controllers might allow other ranges. Check e.g. the BOSCH M_CAN.
  • The SJW ist not calculated by the tool. Values are always zero, which means the Synchronization Jump Width is 1 tq.
  • SAM or (SAMP) determines the number of CAN bus samples taken per bit time. and sometimes offered to be configured


Programming of the Sample Point allows optimizing the Bit Timing:

A late sampling for example allows a maximum bus length. 

an early sampling allows slower rising and falling edges. 

Step-by-Step Calculation of Bit Timing Parameters

The following steps provide a method for determining the optimum bit timing parameters which satisfy the requirements for proper bit sampling.

Step 1:

Determine minimum permissible time for the PROP_SEG segment.
Obtain the maximum propagation delay of the physical interface
for both the transmitter and the receiver from the manufacturers data sheet.

Calculate the propagation delay of the bus by multiplying the maximum length of the bus
by the signal propagation delay of the bus cable.

Use these values to calculate tPROP_SEG using equation (8).

Step 2:

Choose CAN System Clock Frequency As the CAN system clock is derived from the MCU system clock or oscillator,
the possible CAN system clock frequencies will be limited to whole fractions of the MCU system clock or oscillator by the prescaler.

The CAN system clock is chosen so that the desired CAN bus Nominal Bit Time (NBT)
is an integer number of time quanta (CAN system clock periods) from 8 to 25.

Step 3:

Calculate PROP_SEG duration. From equation (9), the number of time quanta required for the PROP_SEG segment are calculated.
If the result is greater than 8, go back to Step 2 and choose a lower CAN system clock frequency.

Step 4:

Determine PHASE_SEG1, PHASE_SEG2 From the number of time quanta per bit obtained in Step 2,
subtract the PROP_SEG value calculated in Step 3 and subtract 1 tQ for SYNC_SEG.

If the remaining number is less than 3 then go back to Step 2 and select a higher CAN system clock frequency.

If the remaining number is an odd number greater than 3 then add one to the PROP_SEG value and recalculate.

If the remaining number is equal to 3 then PHASE_SEG1 = 1 and PHASE_SEG2 = 2
and only one sample per bit may be chosen.

Otherwise divide the remaining number by two and assign the result to PHASE_SEG1 and PHASE_SEG2.

Step 5:

Determine RJW RJW is chosen as the smaller of 4 and PHASE_SEG1

Step 6:

Calculate required oscillator tolerance from equations (10) and (11).

In the case of PHASE_SEG1 > 4 tQ, it is recommended to repeat steps 2 to 6 with a larger value for the prescaler,
i.e. smaller TQ period, as this may result in a reduced oscillator tolerance requirement.
Conversely, if PHASE_SEG1 < 4 tQ, it is recommended to repeat steps 2 to 6 with a smaller value for the prescaler,
as long as PROP_SEG ð 8, as this may result in a reduced oscillator tolerance requirement.

If the prescaler is already equal to 1 and a reduced oscillator tolerance is still required,
the only option is to consider using a higher frequency for the prescaler clock source.

ST Microelectronics bxCAN

The bXCAN module is used in the very popular Cortex M3 family STM32.

All relevant parameters are concentrated in one CAN bit timing register (CAN_BTR).

The bit timing pre-scaler is 10 bit wide and can divide by 1 to 1024.

Use the table calculated value of BTR and add all additional bits according your requirements to get the final value for CAN_BTR.

Clock Rate : 8 MHz, Sample Point : 87.5%, SJW : 1

Type: bxCAN, Clock: 8, max brp: 1024, SP: 87.5, min tq: 8, max tq: 25, FD factor: undefined, SJW: 1

Yellow background rows are settings with an bittime consisting of 16 time quanta tq.

At the time this tool was first developed, this seems to be the best value.

In these days where we talk about CAN FD, as much as possible tq should be used to construct an bit time.

Bit Rate accuracy Pre-scaler Number of time quanta Seg 1 (Prop_Seg+Phase_Seg1) Seg 2 Sample Point at Register  CAN_BTR
1000 0.00 1 8 6 1 87.5 0x00050000
800 0.00 1 10 8 1 90.0 0x00070000
500 0.00 1 16 13 2 87.5 0x001c0000
500 0.00 2 8 6 1 87.5 0x00050001
250 0.00 2 16 13 2 87.5 0x001c0001
250 0.00 4 8 6 1 87.5 0x00050003
125 0.00 4 16 13 2 87.5 0x001c0003
125 0.00 8 8 6 1 87.5 0x00050007
100 0.00 4 20 17 2 90.0 0x00100003
100 0.00 5 16 13 2 87.5 0x001c0004
100 0.00 8 10 8 1 90.0 0x00070007
100 0.00 10 8 6 1 87.5 0x00050009
83.333 0.00 4 24 20 3 87.5 0x00330003
83.333 0.00 6 16 13 2 87.5 0x001c0005
83.333 0.00 8 12 10 1 91.7 0x00090007
83.333 0.00 12 8 6 1 87.5 0x0005000b
50 0.00 8 20 17 2 90.0 0x00100007
50 0.00 10 16 13 2 87.5 0x001c0009
50 0.00 16 10 8 1 90.0 0x0007000f
50 0.00 20 8 6 1 87.5 0x00050013
20 0.00 16 25 21 3 88.0 0x0034000f
20 0.00 20 20 17 2 90.0 0x00100013
20 0.00 25 16 13 2 87.5 0x001c0018
20 0.00 40 10 8 1 90.0 0x00070027
20 0.00 50 8 6 1 87.5 0x00050031
10 0.00 32 25 21 3 88.0 0x0034001f
10 0.00 40 20 17 2 90.0 0x00100027
10 0.00 50 16 13 2 87.5 0x001c0031
10 0.00 80 10 8 1 90.0 0x0007004f
10 0.00 100 8 6 1 87.5 0x00050063
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
 *
 * Copyright (C) 2008 Wolfgang Grandegger <[email protected]>
 *
 * Derived from:
 *   can_baud.c - CAN baudrate calculation
 *   Code based on LinCAN sources and H8S2638 project
 *   Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
 *   Copyright 2005      Stanislav Marek
 *   email:[email protected]
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 */

#include <errno.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <linux/types.h>

/* seems not to be defined in errno.h */
#ifndef ENOTSUPP
#define ENOTSUPP  524 /* Operation is not supported */
#endif

/* useful defines */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

#define do_div(a,b) a = (a) / (b)

#define abs(x) ({           long __x = (x);         (__x < 0) ? -__x : __x;     })

/**
 * clamp - return a value clamped to a given range with strict typechecking
 * @val: current value
 * @min: minimum allowable value
 * @max: maximum allowable value
 *
 * This macro does strict typechecking of min/max to make sure they are of the
 * same type as val.  See the unnecessary pointer comparisons.
 */
#define clamp(val, min, max) ({       typeof(val) __val = (val);      typeof(min) __min = (min);      typeof(max) __max = (max);      (void) (&__val == &__min);      (void) (&__val == &__max);      __val = __val < __min ? __min: __val;   __val > __max ? __max: __val; })

/* we don‘t want to see these prints */
#define dev_err(dev, format, arg...)  do { } while (0)
#define dev_warn(dev, format, arg...) do { } while (0)

/* define in-kernel-types */
typedef __u64 u64;
typedef __u32 u32;

/*
 * CAN bit-timing parameters
 *
 * For futher information, please read chapter "8 BIT TIMING
 * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
 * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
 */
struct can_bittiming
{
  __u32 bitrate; /* Bit-rate in bits/second */
  __u32 sample_point; /* Sample point in one-tenth of a percent */
  __u32 tq; /* Time quanta (TQ) in nanoseconds */
  __u32 prop_seg; /* Propagation segment in TQs */
  __u32 phase_seg1; /* Phase buffer segment 1 in TQs */
  __u32 phase_seg2; /* Phase buffer segment 2 in TQs */
  __u32 sjw; /* Synchronisation jump width in TQs */
  __u32 brp; /* Bit-rate prescaler */
};

/*
 * CAN harware-dependent bit-timing constant
 *
 * Used for calculating and checking bit-timing parameters
 */
struct can_bittiming_const
{
  char name[ 16 ]; /* Name of the CAN controller hardware */
  __u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */
  __u32 tseg1_max;
  __u32 tseg2_min; /* Time segement 2 = phase_seg2 */
  __u32 tseg2_max;
  __u32 sjw_max; /* Synchronisation jump width */
  __u32 brp_min; /* Bit-rate prescaler */
  __u32 brp_max;
  __u32 brp_inc;

  /* added for can-calc-bit-timing utility */
  __u32 ref_clk; /* CAN system clock frequency in Hz */
  void (*printf_btr)( struct can_bittiming *bt, int hdr );
};

/*
 * CAN clock parameters
 */
struct can_clock
{
  __u32 freq; /* CAN system clock frequency in Hz */
};

/*
 * minimal structs, just enough to be source level compatible
 */
struct can_priv
{
  const struct can_bittiming_const *bittiming_const;
  struct can_clock clock;
};

struct net_device
{
  struct can_priv priv;
};

static inline void *netdev_priv( const struct net_device *dev )
{
  return (void *) &dev->priv;
}

static void print_usage( char* cmd )
{
  printf( "Usage: %s [options] [<CAN-contoller-name>]\n"
    "\tOptions:\n"
    "\t-q           : don‘t print header line\n"
    "\t-l           : list all support CAN controller names\n"
    "\t-b <bitrate> : bit-rate in bits/sec\n"
    "\t-s <samp_pt> : sample-point in one-tenth of a percent\n"
    "\t               or 0 for CIA recommended sample points\n"
    "\t-c <clock>   : real CAN system clock in Hz\n", cmd );

  exit( EXIT_FAILURE );
}

static void printf_btr_sja1000( struct can_bittiming *bt, int hdr )
{
  uint8_t btr0, btr1;

  if ( hdr )
  {
    printf( "BTR0 BTR1" );
  }
  else
  {
    btr0 = ( ( bt->brp - 1 ) & 0x3f ) | ( ( ( bt->sjw - 1 ) & 0x3 ) << 6 );
    btr1 = ( ( bt->prop_seg + bt->phase_seg1 - 1 ) & 0xf )
      | ( ( ( bt->phase_seg2 - 1 ) & 0x7 ) << 4 );
    printf( "0x%02x 0x%02x", btr0, btr1 );
  }
}

static void printf_btr_at91( struct can_bittiming *bt, int hdr )
{
  if ( hdr )
  {
    printf( "%10s", "CAN_BR" );
  }
  else
  {
    uint32_t br = ( ( bt->phase_seg2 - 1 ) | ( ( bt->phase_seg1 - 1 ) << 4 )
      | ( ( bt->prop_seg - 1 ) << 8 ) | ( ( bt->sjw - 1 ) << 12 )
      | ( ( bt->brp - 1 ) << 16 ) );
    printf( "0x%08x", br );
  }
}

static void printf_btr_flexcan( struct can_bittiming *bt, int hdr )
{
  if ( hdr )
  {
    printf( "%10s", "CAN_CTRL" );
  }
  else
  {
    uint32_t ctrl = ( ( ( bt->brp - 1 ) << 24 ) | ( ( bt->sjw - 1 ) << 22 )
      | ( ( bt->phase_seg1 - 1 ) << 19 ) | ( ( bt->phase_seg2 - 1 ) << 16 )
      | ( ( bt->prop_seg - 1 ) << 0 ) );

    printf( "0x%08x", ctrl );
  }
}

static void printf_btr_mcp251x( struct can_bittiming *bt, int hdr )
{
  uint8_t cnf1, cnf2, cnf3;

  if ( hdr )
  {
    printf( "CNF1 CNF2 CNF3" );
  }
  else
  {
    cnf1 = ( ( bt->sjw - 1 ) << 6 ) | ( bt->brp - 1 );
    cnf2 = 0x80 | ( ( bt->phase_seg1 - 1 ) << 3 ) | ( bt->prop_seg - 1 );
    cnf3 = bt->phase_seg2 - 1;
    printf( "0x%02x 0x%02x 0x%02x", cnf1, cnf2, cnf3 );
  }
}

static void printf_btr_ti_hecc( struct can_bittiming *bt, int hdr )
{
  if ( hdr )
  {
    printf( "%10s", "CANBTC" );
  }
  else
  {
    uint32_t can_btc;

    can_btc = ( bt->phase_seg2 - 1 ) & 0x7;
    can_btc |= ( ( bt->phase_seg1 + bt->prop_seg - 1 ) & 0xF ) << 3;
    can_btc |= ( ( bt->sjw - 1 ) & 0x3 ) << 8;
    can_btc |= ( ( bt->brp - 1 ) & 0xFF ) << 16;

    printf( "0x%08x", can_btc );
  }
}

static struct can_bittiming_const can_calc_consts[ ] =
{
{ .name = "sja1000", .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

  .ref_clk = 8000000, .printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 32000000, .printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 33000000, .printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 33300000, .printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 33333333, .printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 66660000, /* mpc5121 */
.printf_btr = printf_btr_sja1000, },
{ .name = "mscan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

.ref_clk = 66666666, /* mpc5121 */
.printf_btr = printf_btr_sja1000, },
{ .name = "at91", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 2, .brp_max = 128, .brp_inc = 1,

.ref_clk = 100000000, .printf_btr = printf_btr_at91, },
{ .name = "at91", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max =
  8, .sjw_max = 4, .brp_min = 2, .brp_max = 128, .brp_inc = 1,

/* real world clock as found on the ronetix PM9263 */
.ref_clk = 99532800, .printf_btr = printf_btr_at91, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 24000000, /* mx28 */
  .printf_btr = printf_btr_flexcan, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 49875000, .printf_btr = printf_btr_flexcan, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 66000000, .printf_btr = printf_btr_flexcan, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 66500000, .printf_btr = printf_btr_flexcan, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 66666666, .printf_btr = printf_btr_flexcan, },
{ .name = "flexcan", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 83368421, .printf_btr = printf_btr_flexcan, /* vybrid */
},
{ .name = "mcp251x", .tseg1_min = 3, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

  .ref_clk = 8000000, .printf_btr = printf_btr_mcp251x, },
{ .name = "mcp251x", .tseg1_min = 3, .tseg1_max = 16, .tseg2_min = 2,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 64, .brp_inc = 1,

  .ref_clk = 16000000, .printf_btr = printf_btr_mcp251x, },
{ .name = "ti_hecc", .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1,
  .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 256, .brp_inc = 1,

  .ref_clk = 13000000, .printf_btr = printf_btr_ti_hecc, } };

static long common_bitrates[ ] =
{ 1000000, 800000, 500000, 250000, 125000, 100000, 50000, 20000, 10000, };

#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */

static int can_update_spt( const struct can_bittiming_const *btc, int sampl_pt,
  int tseg, int *tseg1, int *tseg2 )
{
  *tseg2 = tseg + 1 - ( sampl_pt * ( tseg + 1 ) ) / 1000;
  if ( *tseg2 < btc->tseg2_min )
    *tseg2 = btc->tseg2_min;
  if ( *tseg2 > btc->tseg2_max )
    *tseg2 = btc->tseg2_max;
  *tseg1 = tseg - *tseg2;
  if ( *tseg1 > btc->tseg1_max )
  {
    *tseg1 = btc->tseg1_max;
    *tseg2 = tseg - *tseg1;
  }
  return 1000 * ( tseg + 1 - *tseg2 ) / ( tseg + 1 );
}

static int can_calc_bittiming( struct net_device *dev,
  struct can_bittiming *bt )
{
  struct can_priv *priv = netdev_priv( dev );
  const struct can_bittiming_const *btc = priv->bittiming_const;
  long rate = 0;
  long best_error = 1000000000, error = 0;
  int best_tseg = 0, best_brp = 0, brp = 0;
  int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
  int spt_error = 1000, spt = 0, sampl_pt;
  u64 v64;

  if ( !priv->bittiming_const )
    return -ENOTSUPP;

  /* Use CIA recommended sample points */
  if ( bt->sample_point )
  {
    sampl_pt = bt->sample_point;
  }
  else
  {
    if ( bt->bitrate > 800000 )
      sampl_pt = 750;
    else if ( bt->bitrate > 500000 )
      sampl_pt = 800;
    else
      sampl_pt = 875;
  }

  /* tseg even = round down, odd = round up */
  for ( tseg = ( btc->tseg1_max + btc->tseg2_max ) * 2 + 1;
      tseg >= ( btc->tseg1_min + btc->tseg2_min ) * 2; tseg-- )
  {
    tsegall = 1 + tseg / 2;
    /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
    brp = priv->clock.freq / ( tsegall * bt->bitrate ) + tseg % 2;
    /* chose brp step which is possible in system */
    brp = ( brp / btc->brp_inc ) * btc->brp_inc;
    if ( ( brp < btc->brp_min ) || ( brp > btc->brp_max ) )
      continue;
    rate = priv->clock.freq / ( brp * tsegall );
    error = bt->bitrate - rate;
    /* tseg brp biterror */
    if ( error < 0 )
      error = -error;
    if ( error > best_error )
      continue;
    best_error = error;
    if ( error == 0 )
    {
      spt = can_update_spt( btc, sampl_pt, tseg / 2, &tseg1, &tseg2 );
      error = sampl_pt - spt;
      if ( error < 0 )
        error = -error;
      if ( error > spt_error )
        continue;
      spt_error = error;
    }
    best_tseg = tseg / 2;
    best_brp = brp;
    if ( error == 0 )
      break;
  }

  if ( best_error )
  {
    /* Error in one-tenth of a percent */
    error = ( best_error * 1000 ) / bt->bitrate;
    if ( error > CAN_CALC_MAX_ERROR )
    {
      dev_err( dev->dev.parent, "bitrate error %ld.%ld%% too high\n",
        error / 10, error % 10 );
      return -EDOM;
    }
    else
    {
      dev_warn( dev->dev.parent, "bitrate error %ld.%ld%%\n", error / 10,
        error % 10 );
    }
  }

  /* real sample point */
  bt->sample_point = can_update_spt( btc, sampl_pt, best_tseg, &tseg1, &tseg2 );

  v64 = (u64) best_brp * 1000000000UL;
  do_div( v64, priv->clock.freq );
  bt->tq = (u32) v64;
  bt->prop_seg = tseg1 / 2;
  bt->phase_seg1 = tseg1 - bt->prop_seg;
  bt->phase_seg2 = tseg2;
  bt->sjw = 1;
  bt->brp = best_brp;

  /* real bit-rate */
  bt->bitrate = priv->clock.freq / ( bt->brp * ( tseg1 + tseg2 + 1 ) );

  return 0;
}

static __u32 get_cia_sample_point( __u32 bitrate )
{
  __u32 sampl_pt;

  if ( bitrate > 800000 )
    sampl_pt = 750;
  else if ( bitrate > 500000 )
    sampl_pt = 800;
  else
    sampl_pt = 875;

  return sampl_pt;
}

static void print_bit_timing( const struct can_bittiming_const *btc,
  __u32 bitrate, __u32 sample_point, __u32 ref_clk, int quiet )
{
  struct net_device dev =
  { .priv.bittiming_const = btc, .priv.clock.freq = ref_clk, };
  struct can_bittiming bt =
  { .bitrate = bitrate, .sample_point = sample_point, };
  long rate_error, spt_error;

  if ( !quiet )
  {
    printf( "Bit timing parameters for %s with %.6f MHz ref clock\n"
      "nominal                                 real Bitrt   nom  real SampP\n"
      "Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ",
      btc->name, ref_clk / 1000000.0 );

    btc->printf_btr( &bt, 1 );
    printf( "\n" );
  }

  if ( can_calc_bittiming( &dev, &bt ) )
  {
    printf( "%7d ***bitrate not possible***\n", bitrate );
    return;
  }

  /* get nominal sample point */
  if ( !sample_point )
    sample_point = get_cia_sample_point( bitrate );

  rate_error = abs( ( __s32 )( bitrate - bt.bitrate ) );
  spt_error = abs( ( __s32 )( sample_point - bt.sample_point ) );

  printf( "%7d "
    "%6d %3d %4d %4d "
    "%3d %3d "
    "%7d %4.1f%% "
    "%4.1f%% %4.1f%% %4.1f%% ", bitrate, bt.tq, bt.prop_seg, bt.phase_seg1,
    bt.phase_seg2, bt.sjw, bt.brp,

    bt.bitrate, 100.0 * rate_error / bitrate,

    sample_point / 10.0, bt.sample_point / 10.0,
    100.0 * spt_error / sample_point );

  btc->printf_btr( &bt, 0 );
  printf( "\n" );
}

static void do_list( void )
{
  unsigned int i;

  for ( i = 0; i < ARRAY_SIZE( can_calc_consts ); i++ )
    printf( "%s\n", can_calc_consts[ i ].name );
}

int main( int argc, char *argv[ ] )
{
  __u32 bitrate = 0;
  __u32 opt_ref_clk = 0, ref_clk;
  int sampl_pt = 0;
  int quiet = 0;
  int list = 0;
  char *name = NULL;
  unsigned int i, j;
  int opt, found = 0;

  const struct can_bittiming_const *btc = NULL;

  while ( ( opt = getopt( argc, argv, "b:c:lps:" ) ) != -1 )
  {
    switch ( opt )
    {
      case ‘b‘:
        bitrate = atoi( optarg );
        break;

      case ‘c‘:
        opt_ref_clk = atoi( optarg );
        break;

      case ‘l‘:
        list = 1;
        break;

      case ‘q‘:
        quiet = 1;
        break;

      case ‘s‘:
        sampl_pt = atoi( optarg );
        break;

      default:
        print_usage( argv[ 0 ] );
        break;
    }
  }

  if ( argc > optind + 1 )
    print_usage( argv[ 0 ] );

  if ( argc == optind + 1 )
    name = argv[ optind ];

  if ( list )
  {
    do_list( );
    exit( EXIT_SUCCESS );
  }

  if ( sampl_pt && ( sampl_pt >= 1000 || sampl_pt < 100 ) )
    print_usage( argv[ 0 ] );

  for ( i = 0; i < ARRAY_SIZE( can_calc_consts ); i++ )
  {
    if ( name && strcmp( can_calc_consts[ i ].name, name ) )
      continue;

    found = 1;
    btc = &can_calc_consts[ i ];

    if ( opt_ref_clk )
      ref_clk = opt_ref_clk;
    else
      ref_clk = btc->ref_clk;

    if ( bitrate )
    {
      print_bit_timing( btc, bitrate, sampl_pt, ref_clk, quiet );
    }
    else
    {
      for ( j = 0; j < ARRAY_SIZE( common_bitrates ); j++ )
        print_bit_timing( btc, common_bitrates[ j ], sampl_pt, ref_clk, j );
    }
    printf( "\n" );
  }

  if ( !found )
  {
    printf( "error: unknown CAN controller ‘%s‘, try one of these:\n\n", name );
    do_list( );
    exit( EXIT_FAILURE );
  }

  exit( EXIT_SUCCESS );
}
时间: 2024-10-26 19:06:20

Calculate CAN bit timing parameters的相关文章

Calculate CAN bit timing parameters -- STM32

Calculate CAN bit timing parameters Calculate CAN bit timing parameters typedef struct { //char name[ 16 ]; // Name of the CAN controller hardware //uint32_t ref_clk; // CAN system clock frequency in Hz //uint32_t sjw_max; // Synchronisation jump wid

CRT/LCD/VGA Information and Timing

彩色阴极射线管的剖面图: 1. 电子QIANG Three Electron guns (for red, green, and blue phosphor dots)2. 电子束 Electron beams3. 聚焦线圈 Focusing coils4. 偏向线圈 Deflection coils5. 阳极接点 Anode connection6. Mask for separating beams for red, green, and blue part of displayed ima

0xWS2812 STM32 driver for WS2812(B) RGB LEDs

0xWS2812 STM32 driver for WS2812(B) RGB LEDs 0xWS2812 pronounced "hex-WS2812" This code aims at providing a basic interface to the WS2812(B) individually addressable RGB LEDs by WorldSemi. The code outputs 16 parallel data streams to 16 parallel

uboot2011.09源代码ReadMe译文

# # (C) Copyright 2000 - 2011 # Wolfgang Denk, DENX Software Engineering, [email protected] #查看建立这个工程的文件列表人 # #这个程序是自由软件,你可以重新分配它或者修改它在GNU通用公共许可证以由自由软件基#金会发布:第二版或者任何之后的版本. #本程序是分布在希望它是有用的,但没有任何保证:甚至没有隐含保证. #查看 GNU通用公共许可证对于更多的细节. #你应该收到一份GNU通用公共许可证随着这

【转】linux设备驱动之MMC SD卡——核心层简单分析

原文网址:http://blog.chinaunix.net/uid-28685940-id-3889878.html /*************************************************************************************************************************************//* bus.c */ /* *  linux/drivers/mmc/core/bus.c * *  Cop

Nmap 源码学习三 nmap_main主程序分析

主体程序位置在nmap.cc line:1640 学习要点: 程序在1650行,新建一个主机的单例对象, #ifndef NOLUA /* Only NSE scripts can add targets */ NewTargets *new_targets = NULL; /* Pre-Scan and Post-Scan script results datastructure */ ScriptResults *script_scan_results = NULL; #endif 从168

Timequest静态时序分析(STA)基础

Setup Slack Hold Slack Recovery&Removal Recovery: The minimum time an asynchronous signal must be stable BEFORE clock edgeRemoval  : The minimum time an asynchronous signal must be stable AFTER clock edge I/O Analysis Analyzing I/O performance in a s

selenium docs

Note to the Reader - Docs Being Revised for Selenium 2.0! Introduction Test Automation for Web Applications To Automate or Not to Automate? Introducing Selenium Brief History of The Selenium Project Selenium’s Tool Suite Choosing Your Selenium Tool S

SDRAM总结

使用的流程 W9825G6JH winbond sdram 4M words X 4banks X 16bits=. Accesses to the SDRAM are burst oriented. Up to 200MHz CAS Latency 2 and 3 Burst Length 1,2,4,9 and Full page BUrst Read, Single Writes Mode 8K Refresh Cycles/64mS 1 After power up, an initia