2. STM32 CAN FD外设架构:FDCAN外设框图解析、FDCAN内核与消息RAM、FDCAN的时钟与位时序
好,我们直接进入正题。上一章聊了CAN FD的协议基础,这一章咱们把目光聚焦到STM32的FDCAN外设上。说白了,就是看看这个硬件模块到底长什么样,内部是怎么工作的。
我个人习惯,在写代码之前,一定要先把芯片手册里的外设框图看透。你想想看,连硬件怎么连的、数据怎么流的都不知道,写出来的驱动心里能踏实吗?
2.1 FDCAN外设框图解析
先看整体架构。STM32的FDCAN模块,其实是一个独立的外设核心,挂载在总线矩阵上。我拿STM32H7系列举例,它的FDCAN框图大致可以分成这么几块:
- FDCAN内核:负责协议解析、错误处理、位时序控制。这是大脑。
- 消息RAM:存放发送/接收缓冲区、过滤器配置。这是内存。
- 寄存器接口:通过AHB/APB总线与CPU交互。这是门。
- 时钟与复位:提供工作时钟和复位信号。这是心跳。
- GPIO接口:连接到芯片的CAN TX和CAN RX引脚。这是手脚。
下面这张图,是我根据手册整理出来的FDCAN内部数据流关系,你可以对照着看:
关键点:FDCAN 内核和消息 RAM 是分开的。内核只管协议解析,消息 RAM 只管存数据。这种设计的好处是,CPU 可以在不干扰内核工作的情况下,直接通过 DMA 访问消息 RAM,效率很高。
2.2 FDCAN内核与消息RAM
这两个东西是FDCAN的核心,我分开讲。
2.2.1 FDCAN内核
FDCAN内核,本质上是一个状态机。它负责把CPU要发的数据,按照CAN FD的帧格式,一位一位地发送到总线上;反过来,也负责从总线上接收数据,解析成帧,存到消息RAM里。
内核里包含几个关键模块:
- 协议控制器:处理帧起始、仲裁、控制场、数据场、CRC、ACK、帧结束等所有协议细节。
- 位时序逻辑 (BTL):负责采样点的位置控制,直接决定了通信速率和稳定性。
- 错误管理逻辑 (EML):记录发送/接收错误计数,控制总线状态(主动错误、被动错误、总线关闭)。
- 接收过滤器:在硬件层面就完成ID匹配,不符合条件的帧直接丢弃,不占用CPU资源。
我记得刚开始做CAN FD项目时,遇到一个奇怪的问题:总线上的节点都能正常通信,但我的板子就是收不到某些报文。查了半天,发现是接收过滤器配置错了,把需要的ID给屏蔽了。嗯,从那以后,我每次配过滤器都会反复确认掩码。
2.2.2 消息RAM
消息RAM是FDCAN的“数据仓库”。它是一块专用的SRAM,不占用系统内存。STM32的FDCAN消息RAM大小通常是2.5KB到10KB不等,具体看型号。
消息RAM里主要包含这些区域:
| 区域名称 | 功能说明 | 配置要点 |
|---|---|---|
| Rx FIFO 0 / 1 | 接收到的报文按顺序存入FIFO,CPU按序读取。 | 每个FIFO深度可配,建议至少配64个元素。 |
| Rx Buffer | 用于存储特定ID的报文,配合过滤器使用。 | 适合需要高优先级处理的报文。 |
| Tx Buffer | 待发送的报文队列,支持最多32个发送缓冲区。 | 支持取消发送、事件存储。 |
| Tx Event FIFO | 记录已发送报文的时间戳和ID,用于调试和时序分析。 | 建议开启,对排查总线冲突很有帮助。 |
| 标准/扩展ID过滤 | 存储过滤规则,支持11位和29位ID。 | 每个过滤器可配置为范围过滤或位掩码过滤。 |
我的经验:消息RAM的分配是在初始化时通过寄存器配置的。你需要在启动前就规划好:要几个FIFO?每个多深?要几个发送缓冲区?一旦配好,运行中就不能改了。我习惯把Rx FIFO 0配得大一些,用于接收所有常规报文;Rx FIFO 1配小一些,专门接收高优先级报文。
2.3 FDCAN的时钟与位时序
时钟和位时序,是决定CAN FD能不能稳定通信的关键。说白了,就是你要告诉FDCAN内核:总线上的一个位(bit)持续多长时间,采样点在哪里。
2.3.1 时钟源
STM32的FDCAN模块,时钟源通常有两个选择:
- APB时钟 (PCLK):与AHB总线同步,频率由系统时钟分频得到。
- 外部时钟 (FDCAN_Kernel_Clock):独立的时钟源,通常来自芯片内部的PLL或外部晶振,频率可以独立于APB总线。
我个人强烈建议使用独立的内核时钟。为什么?因为APB时钟可能会随着系统负载变化而抖动,影响CAN FD的位时序精度。尤其是在高速率(比如5Mbps以上)时,时钟抖动会直接导致采样点偏移,产生位错误。
注意:FDCAN内核时钟的频率,直接决定了你能达到的最高波特率。比如,如果内核时钟是40MHz,那么理论上最高波特率可以到20Mbps(因为一个位至少需要2个时钟周期)。但实际上,考虑到采样点的精度,建议内核时钟至少是目标波特率的8倍以上。
2.3.2 位时序详解
CAN FD的位时序,比传统CAN更灵活。一个位时间被分成四个段:
- 同步段 (Sync_Seg):固定为1个时间量子(tq)。用于同步总线上的所有节点。
- 传播段 (Prop_Seg):补偿物理延迟(线缆、收发器)。长度可配,1-8 tq。
- 相位缓冲段1 (Phase_Seg1):采样点之前的部分。长度可配,1-8 tq。
- 相位缓冲段2 (Phase_Seg2):采样点之后的部分。长度可配,1-8 tq。
采样点就位于Phase_Seg1和Phase_Seg2之间。采样点的位置,通常建议在75%到87.5%之间。我一般习惯设在80%左右,这样既能容忍一定的线缆延迟,又能保证有足够的余量处理同步跳变。
下面这个表格,是我做项目时常用的位时序配置参考:
| 目标波特率 | 内核时钟 | 时间量子 (tq) | Sync_Seg | Prop_Seg | Phase_Seg1 | Phase_Seg2 | 采样点 |
|---|---|---|---|---|---|---|---|
| 1 Mbps | 40 MHz | 40 ns | 1 tq | 2 tq | 3 tq | 2 tq | 80.0% |
| 2 Mbps | 40 MHz | 25 ns | 1 tq | 1 tq | 2 tq | 2 tq | 75.0% |
| 5 Mbps | 40 MHz | 25 ns | 1 tq | 1 tq | 2 tq | 1 tq | 80.0% |
| 8 Mbps | 80 MHz | 12.5 ns | 1 tq | 1 tq | 2 tq | 1 tq | 80.0% |
你看,同样的内核时钟,通过调整分频系数和段长度,就能适配不同的波特率。这里有个坑:CAN FD在数据段(Data Phase)和仲裁段(Arbitration Phase)可以使用不同的位时序。仲裁段通常用较慢的速率(比如1Mbps),数据段可以切换到高速率(比如5Mbps)。这个切换是由FDCAN内核自动完成的,你只需要在初始化时分别配置好两套参数。
避坑指南:我曾经在一个项目里,把仲裁段和数据段配置成完全相同的位时序,结果在高速率下(8Mbps)通信极不稳定。后来发现,数据段对采样点的要求比仲裁段更苛刻。我的建议是:数据段的采样点尽量往75%靠,仲裁段可以往80%靠。这样既能保证高速率下的稳定性,又能兼容低速节点。
好了,这一章的内容就到这里。FDCAN的架构和时序,是后续所有开发的基础。你把这些搞清楚了,后面写驱动、调bug就会顺手很多。