CAN Timing Sample Point

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 width
  uint32_t brp_min;                 // Bit-rate prescaler
  uint32_t brp_max;
  uint32_t brp_inc;
  uint32_t tseg1_min;               // Time segement 1 = prop_seg + phase_seg1
  uint32_t tseg1_max;
  uint32_t tseg2_min;               // Time segement 2 = phase_seg2
  uint32_t tseg2_max;
} CAN_BitTimingConst_TypeDef;

typedef struct
{
  uint32_t ref_clk;                 // CAN system clock frequency in Hz
  uint32_t bitrate;                 // Bit-rate in bits/second
  uint32_t sample_point;            // Sample point in one-tenth of a percent
  uint32_t brp;                     // Bit-rate prescaler
  uint32_t tq;                      // Time quanta ( TQ )  in nanoseconds
  uint32_t tseg1;                   // Time segement 1 = prop_seg + phase_seg1
  uint32_t tseg2;                   // Time segement 2 = phase_seg2
  uint32_t sjw;                     // Synchronisation jump width in TQs
//uint32_t prop_seg;                // Propagation segment in TQs
//uint32_t phase_seg1;              // Phase buffer segment 1 in TQs
//uint32_t phase_seg2;              // Phase buffer segment 2 in TQs
} CAN_BitTiming_TypeDef;

int32_t CAN_CalcBitTiming( CAN_BitTimingConst_TypeDef *btc,
  CAN_BitTiming_TypeDef *bt );
#define CAN_CALC_MAX_ERROR 50   // in one-tenth of a percent

int32_t CAN_UpdateSamplePoint( CAN_BitTimingConst_TypeDef *btc,
  int32_t sampl_pt, int32_t tseg, int32_t *tseg1, int32_t *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 );
}

// CIA Sample Point : 75.0% : Speed > 800000
// CIA Sample Point : 80.0% : Speed > 500000
// CIA Sample Point : 87.5% : Speed <= 500000
uint32_t CAN_CIA_SamplePoint( uint32_t bitrate )
{
  uint32_t sampl_pt;

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

  return sampl_pt;
}

int32_t CAN_CalcBitTiming( CAN_BitTimingConst_TypeDef *btc,
  CAN_BitTiming_TypeDef *bt )
{
  uint64_t v64;
  int32_t rate = 0;
  int32_t best_error = 1000000000, error = 0;
  int32_t best_tseg = 0, best_brp = 0, brp = 0;
  int32_t tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
  int32_t spt_error = 1000, spt = 0, sampl_pt;

  // Use gived sample points
  if ( bt->sample_point )
    sampl_pt = bt->sample_point;
  else
    // Use CIA recommended sample points
    sampl_pt = CAN_CIA_SamplePoint( bt->bitrate );

  // 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 = bt->ref_clk / ( 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 = bt->ref_clk / ( 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_UpdateSamplePoint( 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 )
    {
      // error ( "bitrate error %ld.%ld%% too high\n", error / 10, error % 10 );
      return DRIVER_ERROR_PARAMETER;
    }
    else
    {
      // warn( "bitrate error %ld.%ld%%\n", error / 10,  error % 10 );
    }
  }

  v64 = ( (uint64_t) best_brp * 1000000000UL ) / bt->ref_clk;

  bt->tq = (uint32_t) v64;
  bt->brp = best_brp;
  bt->tseg2 = tseg2;
  bt->tseg1 = tseg1;
  bt->sjw = 1;
  // bt->prop_seg = tseg1 / 2;
  // bt->phase_seg1 = tseg1 - bt->prop_seg;
  // bt->phase_seg2 = tseg2;

  // real bit-rate
  bt->bitrate = bt->ref_clk / ( bt->brp * ( tseg1 + tseg2 + 1 ) );
  // real sample point

  bt->sample_point = CAN_UpdateSamplePoint( btc, sampl_pt, best_tseg, &tseg1,
    &tseg2 );

  return DRIVER_OK;
}

 

### CAN 总线通信速率设置与计算 CAN(Controller Area Network)是一种广泛应用于汽车电子和工业控制中的串行通信协议。其通信速率通常由硬件设计决定,同时也受到网络拓扑结构、传输距离以及信号质量的影响。 #### 1. CAN 协议的波特率定义 CAN 的通信速率也称为波特率,它决定了每秒可以传输的数据位数。标准的 CAN 波特率范围通常是 10 kbps 到 1 Mbps[^1]。然而,在某些特殊应用中,例如低功耗模式下的 CAN FD(Flexible Data-rate),支持更高的数据速率。 #### 2. 影响波特率的因素 波特率的选择取决于多个因素: - **最大节点间距离**:随着传输距离增加,信号衰减加剧,因此需要降低波特率以减少误码率。 - **电气特性**:总线上的负载能力会限制最高可实现的波特率。 - **噪声环境**:电磁干扰较强的环境中可能需要更低的波特率来提高可靠性[^2]。 #### 3. 计算方法 为了正确配置 CAN 控制器的波特率寄存器,需考虑以下几个参数: - Tq (Time Quantum): 时间量子单位,用于分割一比特的时间长度。 - SJW (Synchronization Jump Width): 同步跳转宽度,表示允许调整同步边界的灵活性。 - Propagation Segment, Phase Buffer Segments 和 Sample Point: 这些定时段共同构成了一比特周期。 假设目标波特率为 `f_bit`,则可以通过以下公式估算所需时钟频率 `f_clock` 及其他相关参数: \[ f_{\text{clock}} \geq N \cdot f_{\text{bit}} \] 其中 \(N\) 是单个时间片的数量,具体数值依赖于所选控制器型号及其内部架构设定[^3]。 以下是 Python 实现的一个简单示例程序,帮助用户初步估计适合的 CAN 配置组合: ```python def calculate_can_timing(bitrate, prescaler_min=1, prescaler_max=128): results = [] for prescaler in range(prescaler_min, prescaler_max + 1): tseg_total = int(1e6 / bitrate / prescaler) - 1 if 7 <= tseg_total <= 16 and tseg_total % 2 == 0: prop_seg = phase_seg1 = phase_seg2 = tseg_total // 4 sample_point = round((prop_seg + phase_seg1 + 1) * prescaler / (tseg_total + 1), 2) results.append({ 'prescaler': prescaler, 'prop_seg': prop_seg, 'phase_seg1': phase_seg1, 'phase_seg2': phase_seg2, 'sample_point': sample_point}) return results print(calculate_can_timing(500_000)) ``` 此脚本尝试找到满足给定条件的最佳预分频系数及各阶段分配方案,并输出对应的采样点位置作为参考依据之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值