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 为例):

区域元素数每元素字长起始偏移用途
标准过滤器 SIDFC81 word0x00011 位 ID 过滤
扩展过滤器 XIDFC42 words0x02029 位 ID 过滤
RX FIFO0164 words0x080高优先级接收
RX FIFO1164 words0x180普通接收
TX Buffer84 words0x280发送缓冲
TX Event FIFO82 words0x300发送完成事件

分配原则:RX FIFO 深度应能容纳最坏情况下中断/DMA 响应延迟内到达的报文数;TX Buffer 数量应覆盖同时挂起的发送请求。若 FIFO 溢出,RXF0S/RXF1S 的 RF0L/RF1L 标志会置位,需在错误处理中读取并清空。

Stellar CAN-FD 消息 RAM 分配与数据流 Message RAM (2 KB) SIDFC 标准过滤器 ×8 XIDFC 扩展过滤器 ×4 RX FIFO0 ×16 RX FIFO1 ×16 TX Buffer ×8 TX Event FIFO ×8 保留 / 扩展区 过滤器匹配 ID + Mask / Range → FIFO0 / FIFO1 / 丢弃 中断 / DMA IR: RF0N/RF1N/TC DMA: RXF0/RXF1/TX CPU / 应用层 报文解析、信号处理 发送请求、错误统计 CAN-FD 收发器 CAN_H / CAN_L → CANoe 模拟节点 匹配 接收 发送

三、过滤器设置

过滤器决定哪些报文进入哪个 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 配置一致。添加两个模拟节点:

  1. 节点 A 周期发送 0x100(DLC=8,经典帧)与 0x200(DLC=16,FD 帧,BRS=1),周期 10 ms。
  2. 节点 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 并记录丢失计数。
建议在应用层维护一个错误统计结构体,记录 TEC、REC、FIFO 溢出次数、总线离线次数,便于整车诊断与复盘。
CAN-FD 数据段速率 ≥2 Mbps 时,必须正确配置 TDCR 的 TDCO/TDCF,否则收发器环路延迟会导致采样错误;同时确保所有节点采样点一致,否则会出现间歇性位错误。