4. CAN-FD通信开发实战
ST Stellar 系列 MCU 内部集成的 CAN-FD 控制器(常称为 M_CAN 或 Bosch M_CAN IP 的衍生实现)是车载区域控制器中最常用的通信外设之一。它同时支持经典 CAN 与 CAN-FD 帧格式,具备独立的报文 RAM(Message RAM)、多组过滤器、可配置的发送/接收 FIFO 与专用中断/DMA 通道。本节以 Stellar 上一路 CAN-FD 通道为例,从寄存器与消息 RAM 的配置入手,逐步完成过滤器、中断/DMA 处理,并给出用 CANoe 模拟节点进行收发测试与总线负载、错误处理的完整方法。
一、控制器初始化与位时序配置
CAN-FD 的位时序分为仲裁段(Nominal)与数据段(Data)两部分,二者独立配置。以常见的 500 kbps 仲裁段 + 2 Mbps 数据段为例,假设 Stellar 该 CAN 通道的时钟源为 40 MHz,则:
- 仲裁段:预分频 NBRP=1,TSEG1=31,TSEG2=8,SJW=8,采样点约 80%,位时间 = 40 × (1+31+8) / 40 MHz = 500 kbps。
- 数据段:预分频 DBRP=0(即 1 分频),TSEG1=15,TSEG2=4,SJW=4,采样点约 80%,位时间 = (1+15+4) / 40 MHz = 2 Mbps。
初始化顺序为:进入 INIT 位 → 配置 CCCR(使能 FD、设置 BRS 位速率切换)→ 写 NBTP/DBTP → 配置 TDCR(发送延迟补偿,用于数据段 ≥1 Mbps 时补偿收发器环路延迟)→ 退出 INIT。若 TDCR 未正确设置,在 2 Mbps 及以上速率时会出现位错误或采样点漂移。
/* 伪代码:Stellar CAN-FD 位时序配置 */
CAN->CCCR = CCCR_INIT | CCCR_FDOE | CCCR_BRSE;
CAN->NBTP = NBTP_NBRP(1) | NBTP_NTSEG1(31) | NBTP_NTSEG2(8) | NBTP_NSJW(8);
CAN->DBTP = DBTP_DBRP(0) | DBTP_DTSEG1(15) | DBTP_DTSEG2(4) | DBTP_DSJW(4);
CAN->TDCR = TDCR_TDCO(8) | TDCR_TDCF(4); /* 发送延迟补偿 */
CAN->CCCR &= ~CCCR_INIT; /* 退出初始化,进入正常模式 */
二、消息 RAM 分配
M_CAN 的消息 RAM 是一块独立于 CPU 地址空间的 SRAM,通过 SIDFC/XIDFC/RXF0C/RXF1C/TXBC/TXEFC 等寄存器以“元素个数 + 起始地址偏移”的方式划分。典型分配如下(以 2 KB 消息 RAM 为例):
| 区域 | 元素数 | 每元素字长 | 起始偏移 | 用途 |
|---|---|---|---|---|
| 标准过滤器 SIDFC | 8 | 1 word | 0x000 | 11 位 ID 过滤 |
| 扩展过滤器 XIDFC | 4 | 2 words | 0x020 | 29 位 ID 过滤 |
| RX FIFO0 | 16 | 4 words | 0x080 | 高优先级接收 |
| RX FIFO1 | 16 | 4 words | 0x180 | 普通接收 |
| TX Buffer | 8 | 4 words | 0x280 | 发送缓冲 |
| TX Event FIFO | 8 | 2 words | 0x300 | 发送完成事件 |
分配原则:RX FIFO 深度应能容纳最坏情况下中断/DMA 响应延迟内到达的报文数;TX Buffer 数量应覆盖同时挂起的发送请求。若 FIFO 溢出,RXF0S/RXF1S 的 RF0L/RF1L 标志会置位,需在错误处理中读取并清空。
三、过滤器设置
过滤器决定哪些报文进入哪个 FIFO。M_CAN 支持标准/扩展两种过滤器,每种又分为范围过滤(Range)与位掩码过滤(Mask)。以接收 0x100~0x1FF 的标准帧为例,配置 SIDFC 中一个元素:
/* 标准过滤器:范围 0x100 ~ 0x1FF,存入 FIFO0 */
SIDFC[0].SFT = 0x1; /* 范围过滤 */
SIDFC[0].SFID1 = 0x100; /* 起始 ID */
SIDFC[0].SFID2 = 0x1FF; /* 结束 ID */
SIDFC[0].SFEC = 0x1; /* 存入 FIFO0 */
若使用掩码过滤,SFID1 为 ID,SFID2 为掩码,掩码位为 1 表示该位必须匹配。过滤器按元素顺序匹配,命中即停止,因此应将高优先级报文放在前面。未命中任何过滤器的报文默认丢弃,可通过 GFC 的 ANFS/ANFE 位改为进入 FIFO1 或触发中断。
四、中断与 DMA 处理
接收中断源主要有 RF0N(FIFO0 新报文)、RF1N(FIFO1 新报文)、RF0L/RF1L(FIFO 溢出)、TC(发送完成)、BO(总线离线)、EW(错误警告)。推荐做法:
- RF0N/RF1N 使用 DMA 搬运:配置 DMA 通道源地址为 RXF0A/RXF1A 指向的 RAM 地址,目的地址为应用缓冲区,传输长度为一个元素(4 words),由 DMA 完成后再触发一次轻量中断通知应用。
- TC 中断用于释放 TX Buffer 并统计发送延迟。
- BO/EW 中断用于错误处理,读取 PSR 与 ECR 寄存器判断错误类型。
/* 使能中断 */
CAN->ILE = ILE_EINT0; /* 中断线 0 */
CAN->ILS = ILS_RF0NL; /* RF0N 走中断线 0 */
CAN->IE = IE_RF0NE | IE_RF0LE | IE_TCE | IE_BOE | IE_EWE;
CAN->GFC |= GFC_RRFE | GFC_RRFS; /* 接受远程帧请求 */
五、CANoe 模拟节点收发测试
在 CANoe 中新建一个 CAN-FD 通道,波特率设为 500 kbps / 2 Mbps,与 Stellar 配置一致。添加两个模拟节点:
- 节点 A 周期发送 0x100(DLC=8,经典帧)与 0x200(DLC=16,FD 帧,BRS=1),周期 10 ms。
- 节点 B 监听 0x300,接收 Stellar 发出的报文并记录时间戳。
Stellar 侧发送 0x300,DLC=12,BRS=1。测试时观察:CANoe Trace 窗口应看到 0x300 的 FD 帧,BRS 位为 1,数据段速率 2 Mbps;Stellar 侧 RX FIFO0 应收到 0x100 与 0x200,且 0x200 的 FDF/BRS 位正确。若 CANoe 未收到,先检查终端电阻(120 Ω×2)、采样点是否一致、TDCR 是否配置。
六、总线负载与错误处理
总线负载 = 单位时间内所有帧的位时间之和 / 总线可用位时间。以 500 kbps 仲裁段、2 Mbps 数据段为例,一帧 0x200(DLC=16,FD+BRS)约 100 位仲裁段 + 200 位数据段,总位时间约 100/500k + 200/2M = 200 μs + 100 μs = 300 μs。若 10 ms 周期发送,单帧负载约 3%;若同时有 20 个此类节点,负载约 60%,需评估是否接近 80% 的告警阈值。
错误处理要点:
- 读取 ECR 的 TEC/REC 判断错误计数,TEC>127 进入错误被动,TEC>255 进入总线离线。
- PSR 的 BO/EW/EP 位分别表示总线离线、错误警告、错误被动。
- 总线离线后需软件触发恢复:写 CCCR 的 INIT 位再清除,或等待 128×11 个连续隐性位后自动恢复。
- FIFO 溢出时读取 RXF0S/RXF1S 的 RF0L/RF1L,清空 FIFO 并记录丢失计数。