2. CANFD协议详解:CANFD帧结构、DLC、BRS与ESI

好,咱们进入正题。CANFD协议,说白了就是经典CAN的“升级版”。它保留了CAN的大部分优点,比如可靠性、实时性,同时把数据传输速度提了上去。我最早接触CANFD时,第一反应是:“这不就是CAN吗?” 但仔细一看,帧结构里多了几个新东西。

这一节,咱们就掰开揉碎,把CANFD的帧结构讲清楚。重点看四个核心点:帧结构(标准帧/扩展帧)、数据场长度编码(DLC)、位速率切换(BRS)和错误状态指示(ESI)。嗯,这几个是CANFD的灵魂。

2.1 CANFD帧结构:标准帧 vs 扩展帧

CANFD的帧结构,和经典CAN很像。但多了几个关键位。咱们先看整体结构。

一个完整的CANFD数据帧,包含这些部分:

  • 帧起始(SOF):1个显性位,告诉总线“我要发数据了”。
  • 仲裁场:包含ID和RTR位。标准帧ID是11位,扩展帧是29位。
  • 控制场:这里变化最大。经典CAN是IDE、r0、DLC;CANFD变成了IDE、r0、BRS、ESI、DLC。多出来的BRS和ESI,咱们后面细说。
  • 数据场:经典CAN最多8字节,CANFD最多64字节。这是质的飞跃。
  • CRC场:CANFD的CRC算法和经典CAN不同,支持更多数据。
  • ACK场:应答位,和经典CAN一样。
  • EOF:帧结束。

标准帧和扩展帧的区别,主要在ID长度。标准帧ID是11位,扩展帧是29位。我个人习惯,如果节点不多,用标准帧就够了。但项目里如果涉及多个ECU,或者需要兼容不同厂商,扩展帧更灵活。

关键点:CANFD的帧结构,在控制场之后,数据场之前,多了一个“位速率切换”区域。这是CANFD能跑高速的秘密。

2.2 数据场长度编码(DLC)

DLC,全称Data Length Code。它告诉接收方:“我这帧数据有多长”。

经典CAN的DLC是4位,能表示0到8。但CANFD的DLC,虽然也是4位,但编码方式变了。它能表示0到64字节的数据长度。

具体编码规则如下:

DLC值(二进制) 经典CAN数据长度(字节) CANFD数据长度(字节)
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 8 12
1010 8 16
1011 8 20
1100 8 24
1101 8 32
1110 8 48
1111 8 64

你看,DLC从1001到1111,在经典CAN里都代表8字节。但在CANFD里,它们代表12、16、20……一直到64字节。为什么会这样?因为CANFD需要更大的数据场,但DLC只有4位,所以只能重新编码。

避坑指南:我曾经在项目里,用CANFD发64字节数据,但接收端配置成了经典CAN模式。结果接收端只读到8字节,后面的数据全丢了。所以,发送和接收的DLC编码必须一致。否则,数据会错乱。

2.3 位速率切换(BRS)

BRS,全称Bit Rate Switch。这是CANFD最核心的特性之一。

经典CAN的整个帧,都用同一个速率传输。比如500kbps。但CANFD不一样。它在仲裁场和控制场的前半部分,用“慢速”(比如500kbps)。到了数据场,它切换到“快速”(比如2Mbps甚至5Mbps)。

BRS位就控制这个切换。BRS=1,表示“我要切换速率了”。BRS=0,表示“我不切换,全程用慢速”。

你想想看,为什么这么设计?因为仲裁场需要所有节点参与总线仲裁,必须用统一的慢速。但数据场是点对点传输,不需要仲裁,所以可以跑高速。这样既保证了可靠性,又提升了效率。

关键点:BRS位只在CANFD帧里有效。经典CAN帧里,这个位是保留位(r0),必须为0。

我在实际项目中,常用配置是:仲裁场500kbps,数据场2Mbps。这样既能兼容老设备,又能享受高速传输。但要注意,总线上的所有节点,必须支持相同的快速速率。否则,数据场会出错。

2.4 错误状态指示(ESI)

ESI,全称Error State Indicator。它告诉接收方:“我这个发送节点,现在状态好不好”。

CAN节点有三种错误状态:

  • 主动错误(Error Active):节点正常工作,能正常发送和接收。
  • 被动错误(Error Passive):节点出过一些错误,但还能工作。发送时,会发送被动错误标志。
  • 总线关闭(Bus Off):节点彻底罢工,不再参与通信。

ESI位的作用,就是让发送节点告诉接收方:“我现在是主动错误还是被动错误”。

  • ESI=0:发送节点处于主动错误状态。这是正常状态。
  • ESI=1:发送节点处于被动错误状态。接收方看到这个位,就知道“这个节点可能不太稳定”。

嗯,这里要注意。ESI位只在CANFD帧里有效。经典CAN帧里,这个位是保留位(r1),必须为0。

注意事项:ESI位是发送节点主动设置的。接收节点不能修改它。如果接收节点发现ESI=1,它可以选择忽略这帧数据,或者记录下来做诊断。我建议,在诊断协议里,把ESI位作为节点健康状态的一个指标。这样能提前发现潜在问题。

2.5 实战:如何配置CANFD帧

咱们用STM32的HAL库,配置一个CANFD帧。假设仲裁场速率500kbps,数据场速率2Mbps,数据长度64字节。

/* CANFD配置示例 */
CANFD_HandleTypeDef hcanfd;

hcanfd.Instance = CANFD1;
hcanfd.Init.Mode = CANFD_MODE_NORMAL;
hcanfd.Init.NominalPrescaler = 4;    // 仲裁场:500kbps
hcanfd.Init.NominalSyncJumpWidth = 1;
hcanfd.Init.NominalTimeSeg1 = 13;
hcanfd.Init.NominalTimeSeg2 = 2;

hcanfd.Init.DataPrescaler = 1;       // 数据场:2Mbps
hcanfd.Init.DataSyncJumpWidth = 1;
hcanfd.Init.DataTimeSeg1 = 13;
hcanfd.Init.DataTimeSeg2 = 2;

hcanfd.Init.StdId = 0x123;           // 标准帧ID
hcanfd.Init.ExtId = 0;               // 扩展帧ID
hcanfd.Init.IdType = CANFD_ID_STD;   // 标准帧
hcanfd.Init.DLC = CANFD_DLC_64B;     // 64字节
hcanfd.Init.BRS = CANFD_BRS_ENABLE;  // 启用位速率切换
hcanfd.Init.ESI = CANFD_ESI_ACTIVE;  // 主动错误状态

HAL_CANFD_Init(&hcanfd);

这段代码里,我配置了BRS为启用,ESI为主动错误。实际项目中,如果节点刚上电,ESI应该是主动错误。如果节点检测到多次发送失败,它会自动切换到被动错误,ESI位也会变成1。

个人经验:我调试CANFD时,经常用逻辑分析仪抓波形。看BRS位有没有正确切换,ESI位是不是预期的状态。有一次,我发现BRS位一直为0,查了半天,原来是配置里忘了使能BRS。所以,配置完一定要检查寄存器

2.6 总结

这一节,咱们把CANFD帧结构的核心点讲透了。标准帧和扩展帧的区别,DLC的编码规则,BRS的速率切换,ESI的错误状态指示。这些是CANFD协议的基础,也是你写代码时必须掌握的。

下一节,咱们会讲CANFD的同步机制和采样点配置。嗯,那又是另一个坑。到时候我分享几个实战案例,保证让你少走弯路。