STM32F105换GD32F305,我踩过的5个CAN通信坑(附完整代码修改)
2026/6/10 5:37:59 网站建设 项目流程

STM32F105换GD32F305:CAN通信移植实战避坑指南

移植过程中最令人头疼的往往不是技术文档的差异,而是那些隐藏在寄存器描述背后的"魔鬼细节"。本文将分享从STM32F105迁移到GD32F305时遇到的五个典型CAN通信问题及其解决方案,这些问题在官方文档中要么语焉不详,要么与实际行为存在出入。

1. CAN初始化失败的隐藏条件

第一次尝试初始化GD32F305的CAN控制器时,HAL_CAN_Init()函数总是返回错误。调试发现,问题出在初始化请求(INRQ)与睡眠模式(SLEEP)状态的交互上。

关键差异点

  • STM32F105:设置INRQ后,INAK标志不受SLEEP状态影响
  • GD32F305:必须清除SLEEP位后,INRQ才能触发INAK响应

解决方法是在初始化前强制清除SLEEP位:

// 在HAL_CAN_MspInit()中添加 CLEAR_BIT(canHandle->Instance->MCR, CAN_MCR_SLEEP);

或者调用HAL_CAN_WakeUp()唤醒控制器后再初始化。这个差异导致GD32在默认睡眠状态下无法完成初始化流程,而STM32则不受影响。

2. 发送邮箱分配策略的微妙区别

连续发送两帧数据时,第二帧数据神秘消失。问题根源在于两家厂商对发送邮箱分配策略的实现差异。

寄存器行为对比

特性STM32F105 (CAN_TSR)GD32F305 (CAN_TSTAT)
邮箱号字段CODE[1:0]NUM[1:0]
空闲邮箱判断逻辑下一个空邮箱明确检查TME标志

修改HAL_CAN_AddTxMessage()中的邮箱选择逻辑:

// 原代码 transmitmailbox = (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos; // 修改后 if(CAN_TSR_TME0 == (tsr & CAN_TSR_TME0)) { transmitmailbox = 0; } else if(CAN_TSR_TME1 == (tsr & CAN_TSR_TME1)) { transmitmailbox = 1; } else if(CAN_TSR_TME2 == (tsr & CAN_TSR_TME2)) { transmitmailbox = 2; } else { transmitmailbox = 3; }

3. 过滤器配置的"幽灵"问题

相同的过滤器配置代码,STM32能正常收发数据,GD32却收不到任何报文。问题出在过滤器bank分配寄存器上。

关键发现

  • 复位后CAN_FMR.CAN2SB默认值为14(0x0E)
  • 未初始化的SlaveStartFilterBank导致该值被清零
  • STM32实际行为与文档不符,GD32则严格遵循文档

解决方案是显式设置过滤器bank起始位置:

sFilterConfig1.SlaveStartFilterBank = 14; // 保持复位默认值 HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig1);

注意:STM32在此场景下表现出与文档不符的行为,可能是芯片本身的勘误项

4. 双CAN实例时的过滤器配置陷阱

解决第一个CAN实例的问题后,第二个CAN实例又出现收发异常。这是因为:

  1. 未显式配置第二个CAN的过滤器
  2. 第一个CAN的配置影响了全局过滤器分配

需要为第二个CAN实例单独配置过滤器:

CAN_FilterTypeDef sFilterConfig2; sFilterConfig2.FilterBank = 15; // 与SlaveStartFilterBank=14配合 sFilterConfig2.SlaveStartFilterBank = 14; HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig2);

5. 发送超时处理的临界条件

连续发送多帧数据时,第三帧经常丢失。根本原因是:

  1. GD32执行速度比STM32快约2倍
  2. 原超时值200太小,导致提前触发发送中止
  3. STM32因速度慢"侥幸"避开了这个问题

测试数据对比

超时值STM32行为GD32行为
<190丢第3帧丢第3帧
190-300完整发送丢第3帧
255-395N/A完整发送
>400完整发送完整发送

最终解决方案是增大超时阈值:

// 将各处timeout值统一调整为10000 UINT32 timeout = 10000; // 考虑不同波特率和时钟频率

这个值虽然保守,但能适应500kbps及以下的各种波特率场景。更精确的做法是根据实际波特率动态计算超时值。

移植过程中最宝贵的经验是:不要假设不同厂商的IP核行为完全一致,即使寄存器布局相似。每个问题解决后,建议在代码中添加详细注释说明背后的原因,这对后续维护和类似移植项目都有极大帮助。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询