第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 协议控制器、消息处理单元、以及配置寄存器组。我习惯把它理解成一个独立的小处理器——你给它配置好,它自己就能处理总线上的所有事务。

下面这张图是我画的内核架构,你看一眼就明白了:

FDCAN 内核架构 CAN 总线 (CANH / CANL) CAN 协议控制器 位时序 / 同步 / CRC / 错误处理 消息处理单元 (Message Handler) 发送调度 / 接收过滤 / 状态跟踪 消息 RAM (Message RAM) 发送缓冲 / 接收缓冲 / 过滤表 / 触发存储 2560 字 (32-bit) 可配置分配 CPU 接口 配置寄存器 CCCR / NBTP / DBTP 说明:消息 RAM 通过 CPU 接口直接访问,配置寄存器控制协议控制器的工作模式

你看这个架构,消息处理单元是核心。它负责把 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 布局搞清楚,后面写初始化代码时就不会迷路。