第3章:CAN FD 位时间与采样点

做 CAN 或者 CAN FD 开发,说白了就是在跟时间做游戏。你想想看,一根总线上挂了好几个节点,大家得在同一个节拍里说话,谁都不能抢拍子或拖拍子。这个节拍怎么定义的?就是位时间。

一句话总结:位时间决定了总线上一个 bit 占多长,采样点决定了在什么时候读这个 bit。这两个值没设好,通讯就会出各种诡异问题。

3.1 位时间的组成

CAN FD 的位时间跟经典 CAN 很像,分成四个段。我拿我调试的一个 500 kbps 项目来举例:

  • 同步段 (Sync Seg):固定 1 个 TQ(Time Quantum,时间量子)。用来让所有节点对齐时钟边沿。简单讲,总线上的跳变沿必须落在这个段里。
  • 传播段 (Prop Seg):补偿物理延迟,包括驱动器、线缆、接收器。长度一般在 1~8 个 TQ。我个人习惯先取 2~3 个 TQ,然后根据实测再调。
  • 相位缓冲段 1 (Phase Seg 1):采样点之前,用于补偿边沿相位误差。可重同步时延长。长度 1~8 个 TQ。
  • 相位缓冲段 2 (Phase Seg 2):采样点之后,用于补偿边沿相位误差。可重同步时缩短。长度 1~8 个 TQ。
  • 采样点 (Sample Point):位于 Phase Seg1 和 Phase Seg2 之间。

整个位时间 Tbit = (Sync + Prop + Phase1 + Phase2) × TQ。每个 TQ 的时间由系统时钟分频得到。

3.2 采样点设置与计算

采样点位置 = (Sync + Prop + Phase1) / (Sync + Prop + Phase1 + Phase2) × 100%。对 CAN FD 来说,官方推荐的数据段采样点靠近 70%~80%,仲裁段保持一致。

我在项目里踩过一个坑:某次把采样点设到了 85%,结果低速时没问题,换了个温湿度环境就开始丢帧。后来发现线缆长了 3 米,相位裕量不够。嗯,所以我现在都老老实实卡在 75%~80% 之间。

经验值参考:对于 1 Mbps 以下的速率,采样点设在 75% 左右比较稳妥;速率高到 5 Mbps 时,可以稍微往后挪到 80%。但不要超过 85%,否则容错空间太小。

3.3 时间量子 TQ 的计算

TQ 由 CAN 控制器内部的晶振分频得到。公式很简单:TQ = 1 / (fclock / (BRP+1)),其中 BRP 是波特率预分频系数。

举个例子,系统时钟 80 MHz,目标位时间 1 µs(对应 1 Mbps),那我需要总 TQ 个数 = 位时间 / TQ。假如每个 TQ 是 12.5 ns,那么 1 µs / 12.5 ns = 80 个 TQ。80 TQ 够分给四个段,很舒服。

时钟频率 BRP TQ 时间 总 TQ 数 典型位时间
80 MHz 0 12.5 ns 80 1 µs (1 Mbps)
40 MHz 0 25 ns 40 1 µs (1 Mbps)
80 MHz 1 25 ns 40 1 µs (1 Mbps)

注意:BRP 分频系数越小,TQ 越精细,但分频器抖动也小一些。我一般习惯用 BRP=0 或 1,这样 TQ 数目多,段分配更灵活。

3.4 位时间配置的避坑指南

  • 同步跳转宽度 (SJW) 别太大:SJW 决定了一次重同步能调整多少个 TQ。设得太大会把采样点拉偏,我见过有人设成 4 TQ,结果总线抖动一大就直接超时。一般 SJW 取 1~2 TQ 就够了。
  • 不要忽略传播段:有次我同事把传播段设为 0,想着省 TQ。结果线长 10 米,信号来回延迟刚好卡在同步段边上,导致丢帧。最后加了 2 TQ 传播段才稳定。
  • CAN FD 数据段要单独设置:仲裁段 1 Mbps,数据段 5 Mbps,不能共用一套位时间参数。很多初学者一个配置通吃两段,会出大问题。
注意:CAN FD 控制器芯片的寄存器配置方式各不相同。有的把 Phase Seg1 和 Prop Seg 合并成一个寄存器字段,有的分开。务必看数据手册,别靠猜。

3.5 知识脉络图

下面这张图把位时间、采样点、TQ 计算、段分配串了起来。你可以把它存下来,以后配置位时间时当速查表用。

CAN FD 位时间与采样点知识框架 Bit Time (位时间) Sync Seg (1 TQ) Prop Seg Phase Seg 1 Phase Seg 2 采样点(Sample Point) TQ = 1 / (fc/(BRP+1)) 采样点占比 = (Sync+Prop+Phase1) / 总TQ × 100% 推荐范围:仲裁段 75%~80%,数据段 70%~80%

3.6 实际配置示例(伪代码)

下面是我在一个 STM32G4 项目上用过的 CAN FD 初始化配置片段,仲裁段 500 kbps,数据段 2 Mbps:

// 仲裁段:500kbps = 2 us位时间,TQ=50ns => 40 TQ
// Sync=1, Prop=3, Phase1=12, Phase2=24 -> 采样点 (1+3+12)/40=40% → 不对,改为:
// 重新算:若采样点75%,需要总TQ=40,T_{sync+prop+phase1}=30,所以Phase2=10
// 配置为:Sync=1, Prop=3, Phase1=26, Phase2=10 → 采样点=30/40=75%

CAN_FD_InitTypeDef canfd_conf = {
  .Prescaler = 1,         // BRP = 1 => TQ = 2 * 50 ns = 100 ns (时钟80MHz)
  .SyncJumpWidth = 2,
  .Seg1 = 26,             // Prop+Phase1
  .Seg2 = 10,
  .DataPrescaler = 0,     // 数据段分频
  .DataSeg1 = 12,
  .DataSeg2 = 5,          // 数据段采样点 ≈ 77%
  .Mode = CAN_FD_MODE
};

注意:Seg1 寄存器一般把 Prop 和 Phase1 合并。我每次配置完都会用示波器抓一下 CAN 总线上的显性位宽度,看是否跟理论值一致。别全信计算,实测最靠谱。

小技巧:找个现成的 CAN 位时间计算器 Excel 或者网页工具,把参数输进去自动算采样点。但一定要理解背后的数学关系,否则出了问题不知道怎么改。

3.7 总结

位时间是个细活,四个段各有各的使命。Sync 负责对齐,Prop 补偿物理延迟,Phase1 和 Phase2 做相位缓冲。采样点卡在 Phase1 和 Phase2 之间,位置不能瞎设。我建议新手先照着参考设计配,跑通了再微调。好了,这一章就到这里,后面我们会用这些参数去算实际的负载率。