3. CAN FD物理层与位时间:差分信号、位时间分段与采样点位置
讲采样点之前,咱得先把物理层那点事捋清楚。很多工程师调了一辈子CAN,对差分信号的理解还停留在「两根线一高一低」的水平。但到了CAN FD,速率翻了几倍,物理层那点「小脾气」全暴露出来了。
3.1 差分信号:为什么非得是两根线?
CAN总线用差分信号,说白了就是「两根线互为备份」。CAN_H和CAN_L的电压差决定了总线状态——显性时差2V左右,隐性时差0V。我见过不少刚入行的朋友问:「为啥不用单端?省一根线多好。」
嗯,现场环境要是那么干净,我也不想用差分。但工业现场什么妖魔鬼怪都有——电机启停、变频器辐射、地线飘移……单端信号在这种环境里基本就是「听天由命」。差分信号的一大好处就是共模抑制:干扰同时作用在两根线上,差值不变,信号照样稳。
我个人习惯在PCB布局时,把CAN_H和CAN_L走线尽量贴在一起、等长。原因很简单:让它们受到的干扰尽可能一致。我踩过一个坑——某次布线图省事,两根线走了不同层,结果现场跑高速时偶尔丢帧,排查了三天才找到原因。
CAN FD的物理层与经典CAN基本一致,但速率高了之后,对信号质量的要求更苛刻。显性/隐性的电平切换时间、边沿陡峭度、线缆终端匹配,每一个细节都可能是累死的骆驼身上的最后一根稻草。
3.2 位时间分段:5段结构是怎么拆出来的?
一个CAN FD的位时间,被拆成5段:
- 同步段 (Sync_Seg):1个时间量子。用于同步总线上的所有节点。这个段只有一个作用:让所有节点对齐边沿。
- 传播段 (Prop_Seg):补偿物理延迟。包括驱动器延迟、线缆传输延迟、接收器延迟。延迟越大,这个段就得越长。
- 相位缓冲段1 (Phase_Seg1):采样点前的一段缓冲区。可以「被动拉长」,用来适应时钟漂移。
- 相位缓冲段2 (Phase_Seg2):采样点后的一段缓冲区。可以「被动缩短」,同样用来补偿漂移。
- 采样点 (Sample Point):不是「段」,而是位于Phase_Seg1和Phase_Seg2之间的那个瞬间。
为什么会分这么多段?你想想看,总线上十几个节点,各自都有自己的时钟,不可能100%精确同频。位时间分段的目的就是给这些微小的频率差异留下「缓冲空间」。采样点前后各留一段缓冲区,哪怕节点时钟稍微偏快或偏慢,只要不超过缓冲量,照样能正确采样。
我在项目中遇到过一种情况:一条1米长的CAN FD总线,10个节点,设置成8Mbps。有3块板子总在特定温度下出错。查了半天,发现是它们的晶振精度在高温下飘了0.5%,加上位时间分段配置偏激进,采样点正好落在边沿附近。后来把Phase_Seg1加长了2个TQ,问题消失。嗯,这种坑靠仿真很难发现,只有现场才能逼出来。
3.3 采样点:那个「一锤定音」的位置
采样点就是接收器读取总线电平的那个精确时刻。它在Phase_Seg1结束、Phase_Seg2开始的位置。说通俗点:整个位时间的前半段留给信号稳定,采样点读取电平,后半段留给控制器处理数据。
采样点的位置通常用百分比表示:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| CAN (1Mbps) | 75% ~ 85% | 经典CAN速率低,对采样点要求没那么苛刻 |
| CAN FD (2Mbps) | 80% ~ 88% | 速率提高,采样点需要更靠后,留更长的Phase_Seg2同步裕量 |
| CAN FD (5Mbps+) | 82% ~ 90% | 高速下时钟漂移影响更大,采样点必须更靠后 |
我给你们一个经验公式:采样点百分比 = (Sync_Seg + Prop_Seg + Phase_Seg1) / (总TQ数) × 100%。举个例子,一个位时间拆成20个TQ,Sync占1个,Prop占7个,Phase_Seg1占8个,那么采样点就在(1+7+8)/20=80%的位置。
为什么这个很重要?因为采样点错了,轻则误码率升高,重则整个网络直接离线。我曾经在一条CAN FD 5Mbps的线路上,只因为采样点从85%调到了82%,错误帧减少了90%。你想想看,就差3个百分点,效果天差地别。
// 位时间配置示例 (TQ=20, 采样点80%)
// 控制器: STM32H7 FDCAN
// 目标速率: 5Mbps, 晶振40MHz, 预分频器=4 → TQ=10ns
// 位时间=20TQ → 200ns → 5Mbps
// TSEG1 = 15 (Prop+Phase1)
// TSEG2 = 4 (Phase2)
// SJW = 4
// 采样点 = (1+15)/20 = 80%
FDCAN_Config.NominalSyncJumpWidth = 4;
FDCAN_Config.NominalTimeSeg1 = 15;
FDCAN_Config.NominalTimeSeg2 = 4;
FDCAN_Config.DataSyncJumpWidth = 4;
FDCAN_Config.DataTimeSeg1 = 15; // 数据相位按同样比例
FDCAN_Config.DataTimeSeg2 = 4;