第2章 STM32 CAN FD 外设概述
好,咱们直接进入正题。这一章我带你看看 STM32H7 系列上的 FDCAN 外设到底长什么样。说实话,我第一次接触 FDCAN 时,第一反应是——这玩意儿跟普通 CAN 长得有点像,但内核完全不一样。你如果之前只玩过 bxCAN,那这一章得仔细看。
2.1 STM32H7 系列 FDCAN 外设特性
STM32H7 系列搭载的 FDCAN 外设,是基于 Bosch M_CAN 内核的 IP。我当年在做一个车载网关项目时,第一次被要求支持 CAN FD,翻手册才发现 H7 的 FDCAN 跟 F4/F1 的 bxCAN 根本不是一个物种。
先列一下核心特性,你心里有个底:
| 特性 | 说明 |
|---|---|
| 协议标准 | ISO 11898-1:2015 (CAN FD) |
| 数据速率 | 仲裁段最高 1 Mbps,数据段最高 8 Mbps |
| 数据长度 | 经典 CAN 8 字节 → CAN FD 最大 64 字节 |
| 发送缓冲 | 最多 32 个专用发送缓冲 + 3 个发送 FIFO |
| 接收缓冲 | 最多 64 个专用接收缓冲 + 2 个接收 FIFO |
| 过滤能力 | 最多 128 个 11 位过滤元素 / 64 个 29 位过滤元素 |
| 时间戳 | 16 位或 32 位时间戳,支持外部时钟 |
| 中断 | 独立中断线,支持事件触发 |
关键点:H7 的 FDCAN 支持同时运行经典 CAN 和 CAN FD 两种模式。你可以在同一个网络上混用,但经典 CAN 节点收不到 FD 帧的数据段。这个坑我踩过——调试时发现经典 CAN 节点一直报错,后来才发现是 FD 帧的 BRS 位导致的。
2.2 FDCAN 内核架构
FDCAN 的内核架构,说白了就是三大部分:CAN 协议控制器、消息处理单元、以及配置寄存器组。我习惯把它理解成一个独立的小处理器——你给它配置好,它自己就能处理总线上的所有事务。
下面这张图是我画的内核架构,你看一眼就明白了:
你看这个架构,消息处理单元是核心。它负责把 CPU 写进消息 RAM 的数据,按照配置的过滤规则,通过协议控制器发到总线上。反过来,总线上的帧经过协议控制器解析后,由消息处理单元决定放到哪个接收缓冲里。
我的习惯:初始化时先把消息 RAM 的分配表画出来,再写代码。这样不容易搞混发送缓冲和接收缓冲的地址偏移。我曾经因为分配表没画清楚,导致发送缓冲和接收缓冲重叠,调试了整整一个下午。
2.3 消息 RAM 布局
消息 RAM 是 FDCAN 最灵活也最容易搞错的地方。它总共 2560 个 32 位字,你可以按需分配给发送缓冲、接收缓冲、过滤元素和触发存储。说白了,就是一块内存,你想怎么切就怎么切。
默认的布局是这样的:
| 起始地址偏移 | 大小 (字) | 用途 |
|---|---|---|
| 0x000 | 28 | 发送缓冲 0-2 (每个 4 字) |
| 0x01C | 16 | 发送 FIFO/队列 (4 个元素,每个 4 字) |
| 0x02C | 16 | 发送事件 FIFO (8 个元素,每个 2 字) |
| 0x03C | 64 | 接收 FIFO 0 (16 个元素,每个 4 字) |
| 0x07C | 64 | 接收 FIFO 1 (16 个元素,每个 4 字) |
| 0x0BC | 128 | 标准/扩展 ID 过滤元素 (最多 128 个) |
| 0x13C | ... | 保留 / 用户自定义 |
注意:消息 RAM 的分配必须在 FDCAN 进入初始化模式时进行。运行时修改分配会导致不可预料的错误。我见过有人试图在运行中动态调整过滤表,结果 FDCAN 直接挂死,只能复位。
每个发送缓冲元素的结构是这样的:
// 发送缓冲元素 (4 字 = 128 位)
// 字 0: 标识符 + 控制位
// 字 1: 数据长度 + 标志位
// 字 2-3: 数据 (最多 64 字节,占用 16 字)
嗯,这里要注意:CAN FD 的 64 字节数据段,在消息 RAM 里占用 16 个字。经典 CAN 的 8 字节只占 2 个字。所以如果你要支持 CAN FD,消息 RAM 的消耗会大很多。我建议你提前算好,别等到项目后期才发现 RAM 不够用。
2.4 FDCAN 与普通 CAN 外设的差异
如果你之前用过 STM32F1/F4 的 bxCAN,那下面这张表能帮你快速理解差异:
| 对比项 | bxCAN (经典) | FDCAN (H7) |
|---|---|---|
| 数据长度 | 固定 8 字节 | 最大 64 字节 |
| 数据速率 | 最高 1 Mbps | 最高 8 Mbps (数据段) |
| 发送缓冲 | 3 个邮箱 | 32 个专用缓冲 + 3 个 FIFO |
| 接收过滤 | 14 个过滤组 | 128 个过滤元素 |
| 消息 RAM | 集成在寄存器中 | 独立 RAM,可配置分配 |
| 时间戳 | 无 | 16/32 位可选 |
| 发送事件 | 无 | 发送事件 FIFO |
| 错误处理 | 简单状态机 | 协议异常中断 + 详细状态寄存器 |
最大的区别,我个人觉得是消息 RAM 的灵活性。bxCAN 的 3 个发送邮箱,你没法改。FDCAN 的 32 个发送缓冲,你可以按需分配——比如给高优先级消息分配专用缓冲,给普通消息用 FIFO。这种灵活性在复杂项目中特别有用。
避坑指南:我曾经在一个项目中,把 FDCAN 配置成纯经典 CAN 模式,结果发现发送事件 FIFO 一直没数据。查了半天手册才发现——经典 CAN 模式下,发送事件 FIFO 默认是禁用的。你得手动把 CCCR 寄存器的 TXEFC 位置 1 才能用。
还有一个差异值得提:FDCAN 的位时序配置更复杂。经典 CAN 只需要配一个波特率,FDCAN 要配两个——仲裁段和数据段。仲裁段通常用 500 kbps 或 1 Mbps,数据段可以跑到 2 Mbps、5 Mbps 甚至 8 Mbps。这两个段的采样点位置也不一样,配置时得分开算。
嗯,这一章的内容差不多就这些。你先把 FDCAN 的整体架构和消息 RAM 布局搞清楚,后面写初始化代码时就不会迷路。