CAN总线要点总结(CAN2.0A/B)

前言

工作也有几年了,在项目中也接触过几次CAN总线,但总是止步于会用即可,对于很多细节上的东西有时还是稀里糊涂的状态,这几天正好有点时间,因此整理了这篇文章来对自己的CAN总线知识体系查漏补缺。

发展历史

  1. 1986年发布CAN1.0。
  2. 1991年博世发布CAN2.0规范,分为CAN2.0A(11位标识符)和CAN2.0B(11+18=29位标识符)。
  3. 1993年ISO组织发布ISO11898规范:
    • ISO11898-1 涵盖数据链路层。
    • ISO 11898-2 涵盖高速CAN的CAN物理层(经典CAN速度1Mbps,CAN FD 5Mbps)。
    • ISO 11898-3 涵盖低速、容错CAN的物理层(速度125kbps)。
    • 后续推出ISO 11898-4 -5 和-6标准。
  4. 2012年博世发布CAN FD 1.0(速度2Mbps,使用加强版CAN PHY的CAN FD-SiC可以做到5-8Mbps)。
  5. 2018年发布第三代CAN数据链路层协议CAN XL,速度提升至10Mbps,兼容CAN FD。

电气特性

  1. 总线与总线上各个节点使用双绞线连接,两端各自端接120Ω,1/2W电阻。

  2. 差分通信,总线执行逻辑线与机制(为后续冲突仲裁服务),显性电平为0,隐性电平为1。在物理层上目前主流有两种标准。
    image-20230511130233321
    image-20230511130315972

  3. 理论通信速率VS最大长度(以经典CAN为例,所有节点应该使用同一速率)。

    速度 长度
    1Mbps 40m
    500kbps 100m
    250kbps 200m
    125kbps 500m
    10kbps 6km

总线拓扑

image-20230511110225220

Tips: 如果手头没有收发器,但是又想对CAN应用进行简单验证,可以考虑如下方法,此方法适用于CAN2.0A/B,后续实际采集的波形,都是按这种方法采集的:

image-20230511110340510

CAN协议报文

1、数据帧

  1. 数据帧在物理层的实际样子,这里以CAN2.0A为例子(这里可以发现每当出现连续的5个相同bit,则需要填充一个相反的bit作为stuff bit,此规则不适用于CRC段和其后的段):
    image-20230510221450705

  2. CAN2.0A数据帧和CAN FD数据帧对比:
    image-20230510221628231
    这里有个地方我觉得是有问题的,IFS

  3. CAN2.0A/B数据帧构成说明:
    image-20230511150119875
    CAN2.0A为标准帧,CAN2.0B为拓展帧,两者主要差异在于仲裁段不同。上图灰色部分固定为显性(0),白色部分固定为隐性(1),蓝色部分的电平状态根据数据而定,ACK位的图示表示TXD输出隐形,同时RXD接收显性输入。

    以下表格说明标准帧的各部分组成:

    隶属段 缩写 长度 说明
    帧起始 SOF(Start of Frame) 1 固定为显性(0)
    仲裁段 ID(Identifier) 11 基本ID,越小优先级越高,禁止高7位都为隐性,即禁止ID=1111111XXXX
    仲裁段 RTR 1 远程传输请求位,在数据帧中固定为显性(0),同ID数据帧优先于远程帧
    控制段 IDE 1 拓展帧标记,在标准帧中固定为显性(0)
    控制段 r0 1 保留位,固定为显性(0)
    控制段 DLC 4 数据段长度,CAN2.0A/B中允许长度为0~8
    数据段 Data 0~64 数据长度由DLC指定,支持0~8字节
    CRC段 CRC 15 CRC校验值
    CRC段 CRC界定符 1 用于分隔CRC和ACK段,固定输出1位隐性(1)
    ACK段 ACK Slot 1 发送节点输出隐性(1),同时接收接收节点发送的显性(0)
    ACK段 ACK界定符 1 同CRC界定符,分隔ACK段与后续段,固定输出隐性(1)
    帧结束 EOF 7 固定输出7位隐性(1)

    可以看到,由于RTR位的存在,相同ID的数据帧和遥控帧(远程帧)同时发送时,总是数据帧赢得仲裁

    CAN2.0B拓展数据帧只是仲裁段和控制段有差异,这里说明拓展数据帧的仲裁段和控制段:

    隶属段 缩写 长度 说明
    仲裁段 ID(Identifier) 11 基本ID,越小优先级越高,禁止高7位都为隐性,即禁止ID=1111111XXXX
    仲裁段 SRR 1 Substitute Remote Request,固定为隐性(1)
    仲裁段 IDE 1 拓展帧标记,在拓展帧中固定为隐性(1)
    仲裁段 拓展ID 18 扩展ID
    仲裁段 RTR 1 远程传输请求位,在数据帧中固定为显性(0),同ID数据帧优先于远程帧
    控制段 r1 1 保留位,固定为显性(0)
    控制段 r0 1 保留位,固定为显性(0)
    控制段 DLC 4 数据段长度,CAN2.0A/B中允许长度为0~8

    可以看到,由于SRR位的存在,基本ID(11位ID)相同的标准数据帧与拓展数据帧仲裁时,总是标准数据帧赢得仲裁。

2、遥控帧(远程帧)

遥控帧与数据帧并无大的差异,与数据帧相比,遥控帧将RTR位置为隐性(1),同时不包含数据段。在遥控帧中,DLC表示请求传输的数据长度。

image-20230511162614540

3、错误帧

错误帧用于在节点检测到错误时通知其他节点,十分简易的帧结构,由6位错误标志(根据节点当前所处的错误状态来确定错误标志的电平),8位错误界定符组成。

image-20230511164335446

一个值得关注的小问题:

  1. 为什么会有错误标志重叠部?
    不同节点发现错误的时机可能不同,这会导致节点开始发送错误标志的开始时间不同。最坏的情况是某个节点收到其他节点发送的6位错误标志位才反应过来出现了错误,此时它才开始发送自己的错误标志位。因此错误标志位重叠部最长可以为12位。

4、过载帧

过载帧和错误帧有着几乎一模一样的帧结构!

image-20230511165534837

这里就会有一个问题,要怎么区分过载帧和错误帧呢?
一般来说,错误帧会在一帧数据的收发过程中发出,比如发送时发现数据帧没有收到ACK回复,或者接收时发现报文的CRC不对,此时错误帧会被发出以终止这条数据帧的继续发送,发送节点会在下次总线空闲时重新尝试发送此条报文。而过载帧一般会在总线空闲时由接收节点发出,这会拉低总线以阻止其他发送节点继续发送数据帧到总线上,给接收节点留出喘息的时间来处理上一帧。

5、帧间隔

每条数据帧与遥控帧发送前需要等待至少3个位的隐性帧将自己与前面的任何帧(数据帧、遥控帧、错误帧、过载帧) 分隔开来。过载帧和错误帧发送前不需要等待帧间隔!
image-20230512092435667
我们在图上还看到了延迟传送部分,当一个处于被动错误状态下的节点要发送数据帧或遥控帧时,它不但要等待3位的帧间隔,还需要额外再等待8位的延迟传送。“被动错误状态”这个概念见后面的错误处理相关章节。

CAN协议收发流程

发送过程

  1. 设置ID、DLC、数据帧等。
  2. 任何节点在总线空闲时都可以发送数据,这时启动发送帧。
  3. 除了正在发送数据的节点,其他节点处于监听状态。
  4. 多个节点同时发送将启动仲裁,ID值小的优先发送,仲裁失败的进入监听状态。
  5. 最终在完成仲裁后,同一时间,只会有一个节点发送数据。
  6. 数据发送完成后,发送的节点释放总线(通过发送一个隐性的1),开始监听接收节点返回的ACK。
  7. 成功接收ACK(一个显性的0)后,继续发送帧数据中的结束段,之后发送节点发送下一帧或进入接收状态。
  8. 如果第7步没有收到ACK,将放弃后续发送并进入CAN错误处理流程**(错误处理?发送节点在内的所有节点都会监测是否出现错误,监测到错误的一个或多个节点会将总线保持在逻辑0至少6个总线周期,此时所有节点注意到此错误并采取措施,发送失败的消息将会被重新发送)**。
  9. 发送节点维护发送错误计数器TEC,当错误数到达0xFF时,节点将会从网络中断开(进入bus-off状态)。

接收过程

  1. 除了处于发送状态和总线关闭状态(bus-off)的节点,所有节点都处于接收状态。
  2. 如果收到有效的CAN消息,监听节点将进行应答。
  3. 如果接收节点设置了过滤器,将根据过滤设置过滤掉不需要的消息(不影响应答,也就是控制器应答后自己把报文丢掉了,没有通知应用层)。
  4. 过滤后收到的数据存入FIFO,用户根据DLC值处理数据大小。
  5. 推荐用CAN中断或DMA方式,及时处理数据。

发送报文时的仲裁问题

  1. 所有CAN单元都可以在总线空闲时(最后一个ACK后出现连续11个隐性电平)发出消息。
  2. 先发送报文的CAN单元可获得发送权(通过发送一个显性的起始位使得总线退出空闲状态)。
  3. 如果两个CAN单元同时发出起始位,则通过线与机制对仲裁段进行仲裁,ID标识符更小的优先发送,输掉仲裁的CAN单元停止发送并等待下一次总线空闲时重发。
  4. 仲裁的本质,是对发送到总线的信号进行回读,如果发送的是隐性位但读回的是显性位,则输掉仲裁并退出发送。由于显性位对应为“0”,因此越小的ID(开头0越多)在仲裁时具有越高的优先级。

CAN错误处理

错误类型

image-20230512103610068
image-20230512131848388

帧错误检测

  1. 检测到错误的节点将发送错误帧来发出错误通知,收到错误通知的节点也开始发送错误帧。
  2. 检测到错误的发送节点放弃发送当前帧,并根据错误类型增加内部的发送错误计数器TEC;检测到错误的接收节点放弃当前帧接收,并根据错误类型增加内部的接收错误计数器REC。
  3. 当TEC到达0xFF时,发送节点进入bus-off状态,从总线上断开;如果不是,则尝试在下一次总线空闲时重发当前帧。
  4. 之后每次传输成功或接收成功一帧,对应的TEC和REC减1(有一个例外,当REC大于127时,REC会在接收成功时直接设置为127)。

节点错误状态

  1. TEC和REC的计数值决定了CAN节点处于什么错误状态,如下图:
    image-20230511113108683
  2. 处于主动错误状态的CAN节点可以正常参加总线通讯,并在检测出错误时输出主动错误标志。
  3. 处于被动错误状态的CAN节点,在每次检测到总线空闲准备发送数据前,需要额外多等待8位隐性位出现来进行“延迟传送”,并且在检测到接收错误时输出被动错误标志,此时如果没有处于主动错误状态的节点检测到错误发生,则总线表现为无错误状态。
  4. 处于总线关闭状态的CAN节点将会从总线断开,并在满足重连要求后重新连接。

错误计数变化依据

image-20230511125210228

位组成与位同步

位组成

CAN控制器将采样1位数据的时间进一步细分为以Tq(Time Quantum)为单位的4段,一般在应用中,我们需要设置各个段分别为多少TQ,这影响到实际的位传输速率,即总线上的传输速率。在实际应用中,一般1Tq的时长为总线提供给CAN控制器的时钟频率的倒数。

1位时间 = 同步段(SS)+传播时间段(PTS)+相位缓冲段1(PBS1)+相位缓冲段2(PBS2)。同时还有一个再同步补偿宽度(SJW)的概念。

image-20230512153004985

  • 同步段(SS):在不存在总线误差(各节点时钟误差,总线传输延迟等因素导致)的情况下,总线上的电平变化边沿应该落在此段区间内,当电平变化边沿超前或滞后此段,则需要进行再同步操作。
  • 传播时间段(PTS):当总线信号传输延迟比较严重,电平变化边沿就会落在此段而不是同步段,此时就需要进行同步操作防止延迟越来越严重。
  • 相位缓冲段(PBS1,PBS2):对总线电平的采样发生在PBS1和PBS2之间,通过调整PBS1和PBS2的长度,我们可以调整采样的时间点来对总线进行再同步,一般在实际使用中需要设置控制器的 再同步补偿宽度(SJW) 来规定长度调整允许的最大值

下面是1位组成的示例,在本示例中,设定1bit的长度为10Tq。所谓采样点是读取总线电平,并将读到的电平作为位值的点。位置在PBS1 结束处。

image-20230512160717955

位同步

为了解决信号传输延迟或CAN控制器时钟误差等因素导致的时序累积误差,需要在符合同步条件的情况下对位数据的采样时间点进行同步,同步分为两种:硬件同步和再同步。

硬件同步:

  • 接收单元在总线空闲状态下检测出帧起始(SOF)位的下降沿时,进行同步调整。方法是直接将下降沿开始的地方做为同步段(SS)的起始时间,并以此为基准向后重新计算1位中其他段的对应时间。这种调整方法与我们常用的串口通过一帧的起始位下降沿来同步时序的方法是类似的!
    image-20230512161521969

再同步:

  • 在接收报文的过程中,当检测到总线上出现边沿时,依然会进行同步,但此时不是改变同步段(SS)的起始位置,而是根据实际边沿与预期的同步段(SS)(代表预期的边沿出现位置)的差值来调整PBS1和PBS2以改变采样点位置来进行调整。
  • 当实际边沿出现在同步段(SS)之后,则在PBS1段后插入Tq来相应的延后采样点时间,插入的Tq最大不超过SJW设置的大小。
    image-20230512164652448
  • 当实际边沿出现在同步段(SS)之前,即上一帧报文的PBS2段的结尾,则减少PBS2段的长度来使得下一帧的同步段(SS)位置提前,减小长度最长不超过SJW设置的大小。
    image-20230512165017053

进行同步调整时遵循的一些规则(对于应用开发来说,我们知道怎么设置CAN控制器中位相关的参数就行,对这个只做一般了解):
image-20230512165230349

实际捕获的CAN数据帧

写这篇笔记时手头没有CAN收发器,所以使用如下方法进行了CAN帧捕获:

image-20230511110340510

搭建电路后,使用CAN1和CAN2发送并接收报文,实际捕获的波形如下:

20230513145644

  • CAN1发送ID=001,DLC=1,DATA=31的CAN帧,CAN2发送ID=002,DLC=1,DATA=32的CAN帧。
  • 这里可以注意到,在两帧之间间隔了44微秒,我设置的位率为250kbps,一位用时4us,也就是说两帧之间间隔了11位,与数据手册中的说明对应得上,这里给出stm32f407手册中关于帧间隔得图示,可以看出跟前文的帧间隔图示有一定差异(前文的帧间隔图示来自于瑞萨的教程):
    image-20230513145627709

更好的英文版本CAN2.0A/B帧格式说明

在查阅stm32f407的手册时,发现手册中对CAN帧格式的描述有个汇总,而且英文描述有时比中文描述更加准确,因此截图补充在这:
image-20230513112510971

部分帧的描述与前文还是有些差异(前文的帧相关图片大多数来自瑞萨的教程),这可能跟CAN控制器的实际实现方式有关?

参考资料

  1. 安富莱出的一篇CAN教程:https://www.armbbs.cn/forum.php?mod=viewthread&tid=117387
  2. 瑞萨CAN入门书:https://www.armbbs.cn/forum.php?mod=viewthread&tid=14546
  3. RM0090 stm32f407参考手册

猜你喜欢

转载自blog.csdn.net/lczdk/article/details/130660869
今日推荐