20251115 - 从零到1详细剖析STM32的CAN架构【以STM32F407为例】

从零到1详细剖析STM32的CAN架构【以STM32F407为例】

1 概览:bxCAN 在 STM32F407 中的位置与作用

  • bxCAN(Basic extended CAN) 是 STM32F4 系列内部实现的 CAN 控制器硬件 IP,用来在物理 CAN 差分总线上收/发 CAN 帧(支持 CAN2.0A/2.0B)。bxCAN 负责仲裁、位填充、CRC、ACK、FIFO/邮箱管理等,极大减轻 CPU 负担。(STMicroelectronics)
  • STM32F407 通常有 CAN1CAN2 两个控制器(注意:CAN1是主设备,CAN2无法直接访问存储区域,因此使用CAN2的时候必须使能CAN1外设的时钟)。在 F4 系列中,滤波器-bank 在 CAN1/CAN2 之间分配(例如 28 个 bank 分割)。(community.st.com)

2 物理层

  • STM32 只实现了 控制器(bxCAN)不包含物理收发器(transceiver)。因此必须外接常见的收发器芯片(例如 TJA1050、MCP2551 等),且需配用差分信号线(CAN_H,CAN_L)和两端的 120Ω 终端电阻。
  • MCU 的 CAN 引脚需配置为复用 AF(Alternate Function),并保持合适的 IO 电气设置(推挽/开漏、上拉/下拉 )。

3 外设时钟与寄存器映射总结

  • 启用外设:在 RCC_APB1ENR 中使能 CAN1EN(与 CAN2 相关的使能也在 RCC),确保 APB1 时钟给 CAN 外设。
  • 重要寄存器组:
    • 控制/状态/模式:CAN_MCRCAN_MSR
    • 传输状态:CAN_TSR
    • 收发邮箱寄存器:CAN_TI0R/TDTR/TDLR/TDHR(Tx mailbox0,1,2 对应)与 CAN_RI0R/RDTR/RDLR/RDHR(Rx)
    • 接收 FIFO 状态:CAN_RF0RCAN_RF1R
    • 中断/错误:CAN_IERCAN_ESRCAN_ERR(ESR 包含 TEC/REC/LEC)
    • 位时序:CAN_BTR(BRP、SJW、TS1、TS2)
    • 过滤器控制:CAN_FMRCAN_FM1RCAN_FS1RCAN_FFA1RCAN_FA1R、滤波器寄存器数组(CAN_FilterRegister[x])。

4 模式与关键位

  • 工作模式(通过 CAN_MCR / CAN_MSR 控制):
    • 初始化模式(Initialization Mode,init)—— 在配置寄存器(位时序、滤波器)前必须进入 init。设 INRQ 并等待 INAK 被置位。(STMicroelectronics)
    • 正常模式(Normal)—— 退出 init 后开始正常通信。
    • 回环(Loopback)/静听(Silent/Listen-only)模式用于测试。
  • CAN_MCR 中常用控制位:
    • INRQ(请求进入初始化)、SLEEPAWUM(自动唤醒)、ABOM(自动总线恢复/自动bus-off管理)、NART(禁止自动重发)、RFLM(Rx FIFO 锁模式)、TXFP(Tx FIFO 优先级或 Mailbox 优先)等。

5 位时序(Bit Timing)

  • CAN_BTR 决定比特率与采样点:包含 BRP(波特率预分频器)、SJW(同步跳宽 SJW)、BS1(TimeSeg1,PhaseSeg1)和 BS2(TimeSeg2,PhaseSeg2)。正确设置 BRP/BS1/BS2/SJW 对保证总线稳定和避免位错误至关重要。

6 发送(Tx)结构与流程(寄存器级)

  • STM32 bxCAN 提供 3 个 Tx Mailboxes(Tx0,Tx1,Tx2),每个 mailbox 有 4 个寄存器:TIR(Identifier)、TDTR(DLC+timestamp)、TDLR(data low)、TDHR(data high)。
  • 发送步骤(寄存器级伪流程):
    1. 在可用邮箱上检查 CAN_TSRTME(Tx mailbox empty)位或 CAN_TI[x]R.TXREQ。选择空的 mailbox。
    2. 配置 TIR:设置 IDERTR、并写入 11-bit 或 29-bit ID 到相应位域。
    3. 配置 TDTR:写入 DLC(0~8),可以包含时间戳相关位(若使用)。
    4. 写数据到 TDLRTDHR(每寄存器 4 字节)。
    5. 发起发送:在 TIR 写入 TXRQ(Transmit Request)位。硬件将开始仲裁并在总线上发送。
    6. 发送完成/状态:查询 CAN_TSR 或中断(CAN_IER)查看 RQCPx / TXOK 等位,清除相应标志并释放 mailbox(硬件自动清 TXRQ 或需软件清某些位)。

7 接收(Rx)结构与流程(寄存器级)

  • 接收使用 FIFO0 与 FIFO1,滤波器决定把哪条消息送到哪个 FIFO。每个 FIFO 的状态由 CAN_RF0R / CAN_RF1R 管理(包含 FMP0/1 = FIFO message pending)。
  • 接收步骤(寄存器级伪流程):
    1. 检查 CAN_RF0R.FMP0(或 FIFO1)是否 >0(有消息)。
    2. 读取 RIR(ID、IDE、RTR)、RDTR(DLC、时间戳)、RDLRRDHR(数据)。
    3. 处理完后,释放该 FIFO 消息:在 CAN_RF0R 写入 RFOM0(release FIFO output mailbox)位(或相应位),FIFO 指针前移。
    4. 可通过中断(FMPIE0/FMPIE1)在新消息到达时触发 CPU。

8 过滤器(Filter)机制(STM 的特色)

  • STM32 的 bxCAN 提供灵活的 硬件滤波器 bank(例如 28 个 bank,在 CAN1/CAN2 之间分配)。每个滤波器可以配置为 16-bit list / 16-bit mask / 32-bit list / 32-bit mask(scale),并可选择将匹配消息放入 FIFO0 或 FIFO1。配置前需将 Filter Master 置入初始化(在 CAN_FMR 设置 FINIT)。

9 错误处理与状态

  • CAN_ESR 提供错误统计与类型:TEC(Transmit Error Counter)REC(Receive Error Counter)LEC(Last Error Code)等。依计数器,节点可处于 Error ActiveError PassiveBus-Off。当发生严重错误,硬件可自动发送 Error Flag(错误帧),并进入错误恢复(若启用 ABOM 等)。(STMicroelectronics)

10 中断与事件

  • CAN_IER:可使能的中断包括 Tx mailbox empty / Tx OK / Rx FIFO message pending / Error / Wake-up / Sleep ack 等。

11 常见配置坑与注意事项(实践经验)

  • 必须在初始化模式下配置位时序与滤波器,否则设置不会生效(先写 INRQ,等待 INAK)。(STMicroelectronics)
  • 滤波器组(Filter Bank)分配:当使用 CAN2 时要注意滤波器分配(通常 lower banks 分给 CAN1,upper banks 给 CAN2,需在 FMR 中配置 split)。若配置不当会导致 CAN2 无法接收消息。
  • GPIO 与收发器:IO 上拉/下拉、速率及终端必须按硬件参考设计做,不正确的物理连接会导致总线抖动/错误帧频发。
  • NART 位:若设了 NART(禁止自动重发),发送失败将不会重试;用于诊断时方便。
  • ABOM 位:若启用自动 bus-off 管理,MCU 能在 bus-off 后自动恢复,生产系统中请根据需求慎重选择。
  • 时钟源:确保 APB1 的频率与 BRP 配比能得到所需比特率(1Mbps、500kbps 等)。若 BRP 取整后误差过大,会导致位错误。

12 寄存器级伪代码

// 1. 使能 RCC APB1 CAN 时钟
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; // 若使用 CAN2, 也启 CAN2EN(视芯片)

// 2. 进入初始化模式
CAN1->MCR |= (1<<0); // INRQ
while(!(CAN1->MSR & (1<<0))) {} // wait INAK set

// 3. 配置位时序:BRP, SJW, BS1, BS2(例:1Mbps 需计算 BRP)
CAN1->BTR = (SJW<<24)|(BS1<<16)|(BS2<<20)|(BRP-1);

// 4. 配置过滤器 (进入 filter init)
CAN1->FMR |= (1<<0); // FINIT
// 设置 filter bank i:模式(16/32bit list/mask), FIFO assignment, ID/mask 值...
// 例如 CAN1->sFilterRegister[0].FR1 = ...; CAN1->sFilterRegister[0].FR2 = ...;
CAN1->FMR &= ~(1<<0); // 出 filter init (FINIT=0)

// 5. 配置 MCR 其他位:ABOM/AWUM/NART/RFLM/TXFP as needed
CAN1->MCR |= (ABOM|AWUM|...);

// 6. 退出初始化(normal mode)
CAN1->MCR &= ~INRQ;
while(CAN1->MSR & INAK) {} // wait cleared

// 7. 发送一帧(寄存器级)
if (CAN1->TSR & TME0) { // mailbox0 empty
  CAN1->sTxMailBox[0].TIR = (IDE?ID_29bit:ID_11bit) | (RTR?RTR_BIT:0);
  CAN1->sTxMailBox[0].TDTR = (DLC & 0xF);
  CAN1->sTxMailBox[0].TDLR = data_low32;
  CAN1->sTxMailBox[0].TDHR = data_high32;
  CAN1->sTxMailBox[0].TIR |= TXRQ; // 请求发送
}

// 8. 接收(poll 或 ISR)
if (CAN1->RF0R & FMP0) {
  id = CAN1->sFIFOMailBox[0].RIR;
  dlc = CAN1->sFIFOMailBox[0].RDTR & 0xF;
  data_low = CAN1->sFIFOMailBox[0].RDLR;
  data_high = CAN1->sFIFOMailBox[0].RDHR;
  CAN1->RF0R |= RFOM0; // 释放 FIFO0 输出
}

13 调试技巧与建议

  1. 先用 loopback 模式或静听模式在板上自测,不用外接收发器即可验证寄存器配置与位时序。
  2. 若两片 STM32 互联测试,先用单端(同板) loopback,再连收发器到真实总线做全链路测试。
  3. 若收不到数据,检查:GPIO AF 配置→收发器供电→终端电阻→滤波器 bank 分配(CAN2 特别容易错)→是否在 init 模式配置滤波器。
  4. 观察总线波形(示波器)验证边沿干净、终端与差分对称性;若抖动多,降低波特率或检查物理接线。
posted @ 2025-11-15 23:05  zeku  阅读(322)  评论(0)    收藏  举报