Cube IDE下MINI M4 STM32无法设置CAN波特率为500Kbps问题
STM32F4 CAN波特率高于250kbps时无法发报文排查方案
问题基础信息
- 运行环境:搭载STM32F4RG15 MCU的MINI M4 STM32开发板,Cube IDE开发环境
- 故障表现:CAN通信最高仅能在250kbps波特率下正常运行,将波特率配置为500kbps、1Mbps时CAN模块停止工作,无法向总线发送任何报文
- 已尝试操作:使用两款CAN位时序计算器提供的全量推荐参数配置,均未解决问题
- 250kbps下正常运行的位时序参数:
- SJW:1 Tq
- 分频系数(Prescaler):4
- TS1:13 Tq
- TS2:2 Tq
- 测试使用的核心代码:
HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN1_Init(); MX_ADC2_Init(); CAN_TxHeaderTypeDef header1; CAN_RxHeaderTypeDef rxheader; uint8_t rxdata[8]; int a; HAL_CAN_Start(&hcan1); uint32_t mailbox1; while (1) { uint8_t txdata[8]; uint32_t mailbox1; header1.StdId = 32; header1.ExtId = 2; header1.DLC = 8; header1.IDE = CAN_ID_STD; header1.RTR = CAN_RTR_DATA; header1.TransmitGlobalTime = ENABLE; uint16_t time= HAL_CAN_GetTxTimestamp(&hcan1,mailbox1); txdata[7]=time; HAL_CAN_AddTxMessage(&hcan1, &header1, txdata, &mailbox1); }
故障成因与解决方法
1. 时钟基准配置错误(最高概率原因)
从250kbps正常运行的参数反推,当前CAN外设的实际输入时钟为16MHz(计算逻辑:波特率=CAN时钟/(分频*(1+TS1+TS2)),代入250kbps参数可得CAN时钟=2500004(1+13+2)=16MHz)。
如果配置高波特率时,直接套用计算器默认的42MHz APB1时钟基准计算参数,实际输出的波特率会和目标值偏差2倍以上,完全超出CAN总线允许的时序容差范围,直接导致通信失败。
排查与修复:
- 打开
SystemClock_Config()函数,确认HSE外部晶振参数和开发板实际硬件匹配、APB1总线分频配置正确,拿到CAN外设的实际输入时钟值,所有位时序参数必须以这个实际时钟为基准计算,不能直接套用计算器默认参数。- 以16MHz CAN时钟为例,正确参数参考:
- 500kbps:分频=2,TS1=13Tq,TS2=2Tq,SJW=1Tq
- 1Mbps:分频=1,TS1=13Tq,TS2=2Tq,SJW=1Tq
2. 物理层硬件问题
- 收发器性能不足:MINI板载的低价CAN收发器在供电不足、走线过长时,高波特率下信号边沿畸变严重,无法输出符合要求的差分电平。用示波器测量CANH、CANL的差分信号,确认1Mbps下位时间为1us、500kbps下位时间为2us,差分幅值达到1.5V以上,信号边沿无明显过缓、振铃问题。
- 终端电阻不匹配:CAN总线必须在首尾两端各接1个120Ω终端电阻,总线总等效电阻为60Ω左右,多接、漏接都会导致高波特率下信号反射严重,通信失败。
- GPIO配置错误:CAN_TX、CAN_RX引脚的复用功能选择错误,或者引脚速度配置为2MHz低速模式,高波特率下引脚翻转速率跟不上。需要将两个引脚配置为复用推挽输出,速度等级设置为50MHz以上,选择正确的CAN复用功能编号。
3. 代码逻辑bug
当前测试代码存在3个会直接导致高波特率下CAN锁死的问题:
- 重复定义
mailbox1变量,且调用HAL_CAN_GetTxTimestamp()时传入的mailbox1是未初始化的野值,高波特率下发送队列填充速度快,野值访问会直接触发CAN错误标志,导致外设进入Bus-Off锁死状态。 - 未配置CAN接收过滤器,部分HAL库版本下,不配置过滤器会导致CAN收发逻辑异常。
- 开启了
TransmitGlobalTime全局时间戳发送选项,但没有在CAN初始化时开启时间触发通信模式,会导致报文发送异常;同时主循环无间隔连续发送报文,高波特率下会瞬间占满3个发送邮箱,触发发送错误。
修复后的核心代码参考:
// CAN初始化后先配置接收过滤器 CAN_FilterTypeDef sFilterConfig = {0}; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.SlaveStartFilterBank = 14; HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig); // 开启自动重传,调试阶段避免单次错误锁死总线 hcan1.Init.AutoRetransmission = ENABLE; HAL_CAN_Start(&hcan1); uint32_t mailbox1; CAN_TxHeaderTypeDef header1 = {0}; while (1) { uint8_t txdata[8] = {0}; header1.StdId = 32; header1.DLC = 8; header1.IDE = CAN_ID_STD; header1.RTR = CAN_RTR_DATA; header1.TransmitGlobalTime = DISABLE; // 未使用时间戳功能时关闭该选项 HAL_StatusTypeDef tx_ret = HAL_CAN_AddTxMessage(&hcan1, &header1, txdata, &mailbox1); if(tx_ret == HAL_OK) { // 只有发送成功后才读取对应邮箱的时间戳 uint16_t time = HAL_CAN_GetTxTimestamp(&hcan1, mailbox1); txdata[7] = time; } HAL_Delay(10); // 加适当延时,避免无间隔发报文占满邮箱 }
4. 外设模式配置错误
确认CAN初始化时配置为正常工作模式,不要误设为静默模式、环回模式;高波特率下建议将SJW设置为2Tq,提升总线时序同步的容差能力,降低通信失败概率。
内容的提问来源于stack exchange,提问作者Krishnapal Jadeja
相关产品推荐
相关产品推荐

