简单通信落地:FPGA 实现 CAN 总线接口与数据帧解析
CAN 总线在工业现场和汽车电子中应用极其广泛,它的可靠性、实时性和多主特性是 UART、SPI、I2C 无法比拟的。从零实现一个完整的 CAN 控制器确实有一定复杂度,但掌握核心的数据帧收发和解析能力,就能应对大多数 FPGA 与 CAN 总线交互的场景。下面我带你一步步落地。
1. 先理解 CAN 协议的核心特点
在写代码前,必须理解 CAN 总线与众不同的地方:
| 特性 | 说明 |
|---|
介绍在 FPGA 中实现 CAN 总线接口的方案。首先解析 CAN 协议核心特点及数据帧结构(标准帧/扩展帧)。接着对比使用外部控制器芯片与内部软核实现的优劣。重点阐述自研控制器的关键模块设计,包括位定时同步、位填充、CRC 校验及状态机逻辑。最后提供数据帧解析流程、多帧打包技巧及调试验证方法,帮助开发者掌握 CAN 通信核心技术。
CAN 总线在工业现场和汽车电子中应用极其广泛,它的可靠性、实时性和多主特性是 UART、SPI、I2C 无法比拟的。从零实现一个完整的 CAN 控制器确实有一定复杂度,但掌握核心的数据帧收发和解析能力,就能应对大多数 FPGA 与 CAN 总线交互的场景。下面我带你一步步落地。
在写代码前,必须理解 CAN 总线与众不同的地方:
| 特性 | 说明 |
|---|
| 物理层 | 差分信号(CAN_H 和 CAN_L),显性(逻辑 0)覆盖隐性(逻辑 1) |
| 多主通信 | 任何节点都可主动发送,通过标识符(ID)仲裁决定谁获得总线控制权 |
| 非破坏性仲裁 | ID 值越小(显性位越多),优先级越高。仲裁失败的节点自动转为接收 |
| 短帧结构 | 一帧最多携带 8 字节数据,有效降低干扰概率 |
| 强大的检错机制 | CRC 校验、位填充、格式检查、应答确认等 |
对比一下:UART 需要约定波特率,SPI 需要片选线,I2C 有地址。而 CAN 的仲裁机制使得多个节点可以同时发送,靠 ID 决定谁说话,这是它最核心的魅力。
我们最常用的是标准数据帧(CAN2.0A),它的组成如下:
帧起始 (1bit) + 仲裁段 (12bit) + 控制段 (6bit) + 数据段 (0~8byte) + CRC 段 (16bit) + ACK 段 (2bit) + 帧结束 (7bit)
逐段拆解:
扩展帧(CAN2.0B)有 29 位 ID,我们暂不涉及。
这是最稳妥的**'快速落地'**方式。FPGA 只负责与 CAN 控制器(如 SJA1000、MCP2515)通过并行或 SPI 接口通信,控制器完成繁琐的协议处理。
这是我们本次的重点——用 Verilog 自己实现 CAN 协议核心。
一个完整的 CAN 控制器通常包含以下模块:
| 模块 | 功能 |
|---|---|
| 寄存器模块 | 配置波特率、验收滤波、状态查询 |
| 位定时模块 | 产生位时间,实现硬同步和重同步 |
| 位流处理器(BSP) | 并串/串并转换,位填充/去填充 |
| CRC 模块 | 发送时计算 CRC,接收时校验 |
| 验收滤波器 | 判断接收到的 ID 是否匹配 |
| 状态机模块 | 控制发送、接收、错误处理等状态 |
| 错误计数器 | 统计错误,决定是否总线关闭 |
CAN 是异步通信,每个节点有自己的时钟,通过位同步来保持步调一致。
一个位时间分为 4 段:
波特率计算公式:
波特率 = 系统时钟频率 / (分频系数 × (Sync_Seg + Prop_Seg + Phase_Seg1 + Phase_Seg2))
采样点位置一般设置在 70%~90% 位时间处,例如 87.5%。
硬同步:在帧起始的下降沿,所有节点强制将位时间对齐到 Sync_Seg。
重同步:在后续位中,如果跳变沿偏离了 Sync_Seg,通过缩短 Phase_Seg2 或延长 Phase_Seg1 来调整。
CAN 协议规定:在发送时,如果连续出现 5 个相同极性的位,必须在第 5 位后插入一个相反极性的填充位。接收时,如果检测到连续 6 个相同位,则视为填充错误。
作用:提供足够的跳变沿用于时钟同步,防止 DC 分量累积。
FPGA 实现:发送时用计数器监控,满 5 个相同位就插入一个相反位;接收时同样计数,遇到第 6 个相同位报错。
CAN 标准帧使用 15 位 CRC,生成多项式为:
X^15 + X^14 + X^10 + X^8 + X^7 + X^4 + X^3 + 1
计算范围包括:帧起始、仲裁段、控制段、数据段。发送时计算并附加,接收时重新计算并与接收到的 CRC 比较。
CAN 控制器的状态机比 UART/SPI 复杂得多,主要包括:
IDLE → 发送/接收 → 仲裁 → 错误处理 → 间歇
假设我们已经有了一个 CAN 收发器(如 TJA1050)连接到 FPGA,FPGA 接收到的 RX 信号是经过电平转换的逻辑信号。解析一帧数据的流程如下:
总线空闲时,RX 为隐性(1)。检测到下降沿(1→0)表示 SOF 到来,启动接收状态机。
根据位定时配置,在每个位时间的采样点读取 RX 电平。建议采用3 次采样取多数的方式提高抗干扰性。
接下来的 11 位是 ID(MSB first),第 12 位是 RTR。如果是远程帧(RTR=1),则没有数据段。
根据 DLC,接收后续字节。每个字节 MSB 先行。
接收完数据段后,接下来 16 位是 CRC 段(15 位 CRC + 1 位界定符)。FPGA 边接收边计算 CRC,最后与收到的 CRC 比较。
CRC 界定符后,发送节点释放总线(隐性)。如果本节点正确接收,应在 ACK 槽位(第 1 位 ACK 段)拉低总线(发送显性)作为应答。
检测到 7 个隐性位,一帧结束。
always @(posedge clk) begin
case (rx_state)
IDLE:
if (rx_falling_edge) begin
rx_state <= GET_ID;
bit_cnt <= 0;
end
GET_ID:
if (sample_point) begin
id_reg[10-bit_cnt] <= rx;
if (bit_cnt == 10) begin
bit_cnt <= 0;
rx_state <= GET_RTR;
end else
bit_cnt <= bit_cnt + 1;
end
GET_RTR:
if (sample_point) begin
rtr <= rx;
rx_state <= GET_DLC;
bit_cnt <= 0;
end
GET_DLC:
if (sample_point) begin
dlc[3-bit_cnt] <= rx;
if (bit_cnt == 3) begin
bit_cnt <= 0;
rx_state <= (dlc > 0) ? GET_DATA : GET_CRC;
end else
bit_cnt <= bit_cnt + 1;
end
// 后续状态类似...
endcase
end
由于 CAN 每帧最多 8 字节,当需要传输超过 8 字节的数据时,必须进行多帧传输。工业应用中常用自定义的数据包格式来简化处理:
| 字段 | 长度 | 说明 |
|---|---|---|
| 帧头 | 1 字节 | 标识数据包起始 |
| 总长度 | 2 字节 | 有效数据总字节数 |
| 帧序号 | 1 字节 | 当前是第几帧 |
| 数据 | 0~4 字节 | 实际有效数据 |
| 校验 | 1 字节 | 累加和或异或校验 |
示例:要发送 20 字节数据,分成 5 帧,每帧数据段放 4 字节,再加上帧序号等信息。接收端根据帧序号重组。
$display 打印关键状态跳转。| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 无 ACK 应答 | 波特率不匹配 / 节点未上电 | 检查终端电阻(120Ω),用示波器测波形 |
| CRC 校验错误 | 位定时配置不当 / 采样点偏移 | 调整波特率分频和采样点位置 |
| 总线一直显性 | 某个节点故障 | 逐个断开节点,找出故障源 |
| 偶发性丢帧 | 同步问题 / 干扰 | 检查屏蔽和接地,调整采样点 |
| 实现层级 | 内容 | 难度 |
|---|---|---|
| 入门 | 用外部 CAN 控制器 + FPGA 简单读写 | ★★☆ |
| 进阶 | 自研 CAN 控制器核心(位定时 + 状态机) | ★★★★ |
| 精通 | 完整实现错误处理、总线关闭、TTCAN | ★★★★★ |
对于初学者,建议先从路径 A 入手:用 SJA1000 或 MCP2515 这类成熟的控制器,FPGA 只需实现 SPI 或并行总线读写,快速搭建起 CAN 通信链路。在这个过程中理解 CAN 协议,再用示波器观察波形,逐步深入。
当你能熟练解析数据帧、处理多帧传输后,再挑战自己用 Verilog 实现一个完整的 CAN 控制器软核。那时候,你就真正掌握了这个工业级通信协议的灵魂。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online