CAN 协议层

协议帧格式概览

协议层定义了数据在总线上的封装格式。CAN 协议主要包含以下几种帧格式:

ISO 11898-1 帧格式

帧类型

主要用途

发送时机/约束

关键特点

数据帧

传输实际数据

  • 总线空闲时主动发送

  • 需通过仲裁机制 (ID 越小优先级越高)

  • 仲裁失败自动重传(可配置)

  • 结构:SOF + ID + 控制 + 数据 + CRC + ACK + EOF

  • 容量:0~8 Byte

  • ACK:发送方发隐性位,接收方发显性位确认

远程帧

请求特定 ID 的数据

  • 总线空闲时发送 (需仲裁)

  • 目标节点必须支持并配置为响应

  • 结构:类似数据帧,但 RTR=1 且 无数据场

  • 注意:不仅引入延迟且占用带宽

错误帧

通知全局总线错误

  • 立即发送:检测到错误时立即触发,不等待总线空闲

  • 会破坏当前正在传输的帧

  • 结构:错误标志 (6 位) + 错误界定符 (8 位)

  • 主动错误:发送 6 个显性位 (破坏位填充规则)

  • 被动错误:发送 6 个隐性位

  • 触发:位、填充、CRC、格式、ACK 错误

过载帧

延迟下一帧接收

  • 在 EOF 最后 1bit、错误帧界定符最后 1bit、过载界定符最后 1bit、帧间隔第 1 或第 2bit 检测到显性电平时

  • 由控制器硬件自动处理,应用层无法主动发送

  • 结构:类似主动错误帧 (6 个显性位)

  • 现状:现代 CAN 控制器速度极快,几乎不再需要此帧

帧间隔

物理分隔连续的帧

  • 强制性时间间隙

  • 任何节点在此时段内不可发送数据/远程帧

  • 组成:间歇场 (3 个隐性位) + 总线空闲

  • 特殊情况:错误帧/过载帧后,先发送界定符 (8 位),再进入帧间隔

数据帧

数据帧(Data Frame)是 CAN 总线进行数据传输的常用类型,用于节点间的数据传输。

标准数据帧采用 11-bit 标识,格式如下:

../../../_images/can_standard_data.svg

标准数据帧

扩展数据帧采用 29-bit 标识符 (11-bit Base ID + 18-bit Extension ID),用于大型网络,格式如下:

../../../_images/can_extend_data.svg

扩展数据帧

关键字段解析

帧结构由显性位(逻辑 0)起始,以连续的隐性位(逻辑 1)结束。完整的数据帧由七个功能段组成,依序为:帧起始、仲裁段、控制段、数据段、CRC 段、ACK 段及帧结束。

数据帧结构定义

功能段 (Field)

组成/位定义

技术说明

帧起始 (SOF)

Start Of Frame,1 位 (显性)

标识帧开始,用于硬同步。

仲裁段

ID, RTR, IDE, SRR

  • ID: 11 位(标准)或 29 位(扩展),决定优先级,ID 编号越小优先级越高

  • RTR: Remote TransmissionRequest,区分数据帧(0)与远程帧(1)。数据帧优先级高于远程帧。

  • IDE: Identifier Extension,区分标准帧(0)与扩展帧(1)。标准帧的优先级高于扩展帧。

  • 仲裁机制: 线与逻辑,显性电平优先

控制段

DLC (4 位), r0/r1

DLC: Data Length Code,指示数据字节数 (0-8)。r0/r1 为保留位。

数据段

0-8 字节

有效载荷,MSB 先行。

CRC 段

CRC 序列(15 位) + 界定符

硬件计算校验码,界定符为隐性位。

ACK 段

ACK 槽 + 界定符

发送方发隐性,接收方拉低为显性以应答。

帧结束 (EOF)

7 位 (隐性)

标识帧结束,无位填充。

远程帧

用于接收节点向发送节点请求数据。与数据帧的主要区别在于: RTR 位为隐性 (1) 且 无数据段。格式如 标准远程帧 和 扩展远程帧 所示。

../../../_images/can_standard_remote.svg

标准远程帧

../../../_images/can_extend_remote.svg

扩展远程帧

错误帧

当节点检测到总线错误时发送,由错误标志 (6 bits) 和错误界定符 (8 bits) 组成。图 主动错误帧 和 被动错误帧 展示了两种帧格式。 由于不同节点可能在不同时间点检测到错误并发送错误帧,导致总线上的错误标志位叠加,最终的错误标志位间可能在 6 到 12 个位之间,可参考 错误检测和管理 获取详细信息。

../../../_images/can_active_error.svg

主动错误帧

../../../_images/can_passive_error.svg

被动错误帧

过载帧

当接收节点未准备好接收下一帧数据时发送,用于在两帧之间插入额外延时。过载帧格式如下:

../../../_images/can_overload.svg

过载帧的发送时机可参考 发送过载帧。

帧间隔

帧间隔用于分隔数据帧和远程帧的帧。帧间隔格式如下:

../../../_images/can_intermission.svg
  • 数据帧和远程帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、远程帧、错误帧、过载帧)分开。

  • 过载帧和错误帧前不能插入帧间隔。

其中:

  • Intermission:在前一帧报文(EOF 或 错误界定符)结束后,总线必须保持 3 个位的隐性电平(1)

  • Suspension:当发生错误时,

    • 如果一个节点处于 主动错误 状态,节点发完一帧,休息完 3 bit 的 Intermission 后,可以立刻争抢总线发送下一帧

    • 如果一个节点频繁出错,变成了 被动错误 状态,协议规定它在发完一帧后,必须额外多等 8 个隐性位(suspension)。

  • Bus idle:如果上面两个阶段都过完了,总线上依然没有数据,那就进入“空闲状态”。此时总线一直维持隐性(1)。任何节点只要想发数据,随时可以把电平拉低(0)来启动发送(即发送 SOF 位)。

位时序与同步机制

CAN 采用异步串行通信,收发双方需约定波特率。为解决时钟漂移和传输延迟问题,ISO 11898 定义了基于 时间量子 (Time Quantum, Tq) 的位时序分解与同步机制。

Bit 分解

根据 ISO 11898-1 标准,总线上的一个 Bit 时序分为四个段:

../../../_images/can_bit_timing.svg

单个 Bit 分解后的最小单位是 Time quantum(Tq),单位大小为 prescaler/core clk,其中 core clk 是 CAN 的时钟源输入。一个完整的 Bit 位一般由 8-25 个 Tq 组成。

  • 同步段 (Sync_Seg) :用于判断 总线上信号的跳变是否恰好在 Sync_Seg 段内,如果是,则表明通信节点和总线同步

  • 传播段 (Prop_Seg) :用于补偿信号在物理线路上的传输延迟及收发器内部延迟。电信号在总线上传播需要时间,例如在总线仲裁阶段,如果未预留这时间,节点 A 发送的信号还未到达对面节点 B,节点 A 就开始采样,此时采样错误

  • 相位缓冲段 1 (Phase_Seg1) :该段是采样前的弹性缓冲, 紧挨着采样点 。如果当前 Bit 的 Sync_Seg 发现信号跳变晚了(在 Sync_Seg 后面),说明当前 Bit 来得迟,为了不让采样点来得太早,因此需要延长此段

  • 相位缓冲段 2 (Phase_Seg2) :该段是采样后的弹性缓冲。如果当前 Bit 的 Sync_Seg 发现信号跳变早了(快了),说明当前 Bit 的结束的太早,需要缩短 Phase_Seg2 来使得下一 Bit 可以被正确采样

采样点 (Sample Point) 位于 Phase_Seg1 的结束时刻。通过控制各段的长度,可以对采样点的位置进行偏移,以便准确采样。

下表给出了各个段的参考范围。

时间段的最小配置范围

参数

取值范围

描述

位时间预分频器 (Prescaler)

1 ~ 32

Tq = prescaler / core_clk

Sync_Seg

1 个 Tq (固定)

同步总线上的各个 CAN 节点

Prop_Seg

1 ~ 8 个 Tq

补偿网络内的物理延迟时间

Phase_Seg1

1 ~ 8 个 Tq

补偿边缘相位误差,在同步过程中可能会暂时延长

Phase_Seg2

2 ~ 8 个 Tq

补偿边缘相位误差,在同步过程中可能会暂时缩短

SJW

1 ~ 4 个 Tq

不能长于任意一个相位缓冲段 (Phase_Seg1/2)

通信波特率

CAN 节点的通信速率是传输单个 Bit 的 Tq 总数的倒数,例如时钟源是 40MHz,分频系数是 2,则单个 Tq 的时间是 0.05us。假设单个 Bit 占用 20 个 Tq,则波特率结果为:

Baud Rate = core_clk / (BRP × Total Tq) = 1000000 baud/s

同步过程

前面约定的每个数据 bit 的段划分,并未涉及到相位细节。根据 ISO 11898 标准,同步分为:

  • 硬同步 :仅在当存在“帧起始信号(SOF)”时起作用

  • 重新同步 :在 SOF 后续信号时起作用

两者都使用 Sync_Seg 段来进行检测,同步的目的都是使节点内的 Sync_Seg 段把跳变沿包含起来

  1. 硬同步

当 总线空闲结束 时,第一个帧起始信号 SOF 到来。接收节点检测到总线的 SOF 不在节点内部时序的 SS 段范围,所以判断自己内部时序与总线不同步。此时接收节点会强行将 Bit Time 计数器清零,强行将 Sync_Seg 段对齐到 SOF 信号的下降沿。同步后采样便可正确进行。

../../../_images/can_hard_sync.png

硬同步

以图 硬同步 为例,

  1. 发送节点 Node_A 在发送 SOF 位时,SOF 位的下降沿在 SS 段

  2. 这个时候接收节点 Node_B 发现自己当前位的 SS 段和发送节点 SOF 位的 SS 段不同步。也就是说当 Node_A 产生 SOF 位 SS 段时,Node_B 的当前位的 SS 段已经在 5 个 Tq 之前产生了;

  3. 于是接收节点 Node_B 强行将自己当前位的 SS 段拉到与 SOF 位的 SS 段同步

  1. 重新同步

    在帧传输过程中(除 SOF 跳变外),每次检测到 隐性到显性(高电平至低电平)的跳变沿 时进行重新同步。以总线跳变沿与 Sync_Seg 段的相对位置进行区分,重新同步可分为:

    1. 相位超前时的重新同步,如图 相位超前时的重新同步 所示。

      1. 发送节点 Node_A 比接收节点 Node_B 的慢,也就是 Node_A 当前位的 ss 段产生的时候,Node_B 当前 Bit 的 ss 段已经在 2 个 Tq 之前产生

      2. 所以这个时候接收节点 Node_B 就将 PBS1 延长 2 个 Tq 的时间

      3. 于是此时 Node_A 当前位的采样点就和 Node_B 的采样点同步

    2. 相位滞后时的重新同步,如图 相位滞后时的重新同步 所示。

      1. 发送节点 Node_A 当前位的 SS 段诞生 2Tq 时长之后,接收节点 Node_B 的当前位才产生 SS 段

      2. 于是,接收节点 Node_B 当前位的 PBS2 段缩短

      3. 这样就会导致接收节点 Node_B 的下一 Bit 能够提前 2 个 Tq,从而 Node_B 的下一 Bit 采样点和 Node_A 下一 Bit 的采样点能够同步。

../../../_images/can_resync_phase_lead.png

相位超前时的重新同步

../../../_images/can_resync_phase_lag.png

相位滞后时的重新同步

重新同步时,Phase_Seg1 增加和 Phase_Seg2 减少的这段时长被定义为 重新同步补偿宽度 SJW (reSynchronization Jump Width),单次同步的时候不能增加或减少超过 SJW 的时间长度。若有需要, 控制器会通过多次小幅度调整来实现同步。 当控制器设置的 SJW 较大时,可以吸收的误差加大,但通信速度会下降。