STM32F105换GD32F305踩坑实录:5个CAN驱动移植的坑点与填坑指南
STM32F105换GD32F305踩坑实录5个CAN驱动移植的坑点与填坑指南从STM32F105切换到GD32F305的过程看似简单但实际移植过程中遇到的CAN驱动问题却让我这个老嵌入式工程师踩了不少坑。国产MCU在寄存器命名和功能实现上的细微差异往往会导致原本在STM32上运行良好的代码在GD32上出现各种诡异行为。本文将详细复盘我在移植过程中遇到的5个典型问题包括现象描述、原因分析和解决方案希望能帮助正在进行类似移植的同行少走弯路。1. CAN初始化失败SLEEP位的隐藏陷阱移植后遇到的第一个问题就是CAN初始化失败。在GD32F305上调用HAL_CAN_Init()函数时总是返回错误状态。经过仔细排查发现问题出在SLEEP位的处理上。现象描述STM32F105上CAN初始化正常GD32F305上HAL_CAN_Init()返回错误调试发现卡在等待CAN_MSR.INAK置位的循环中原因分析 两个芯片在初始化后CAN_MCR.SLEEP位都默认为1但行为却有差异STM32设置CAN_MCR.INRQ后CAN_MSR.INAK会立即置1不受SLEEP位影响GD32CAN_MCR.INRQ置1后只有在SLEEP位为0时CAN_MSR.INAK才会置1解决方案 在调用HAL_CAN_Init()前需要先清除SLEEP位// 在HAL_CAN_MspInit()函数末尾添加 CLEAR_BIT(canHandle-Instance-MCR, CAN_MCR_SLEEP);或者直接调用HAL_CAN_WakeUp()函数唤醒CAN控制器。2. 连续发送数据异常发送邮箱逻辑差异第二个坑出现在连续发送CAN报文时。在GD32上连续调用HAL_CAN_AddTxMessage()发送两包数据时第二包数据总是无法发出。现象描述STM32上连续发送两包数据正常GD32上只能发送第一包数据无错误标志但第二包数据未出现在总线上原因分析 问题根源在于两个芯片对发送邮箱状态的处理逻辑不同特性STM32F105GD32F305状态寄存器CAN_TSRCAN_TSTAT邮箱号字段CODE[1:0]NUM[1:0]行为描述返回下一个空邮箱或优先级最低的邮箱返回下一个将要发送的邮箱或最后一个邮箱解决方案 需要修改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. CAN接收异常过滤器配置的坑第三个问题更加隐蔽GD32的CAN0对应STM32的CAN1能发送数据却接收不到任何报文。现象描述STM32上CAN1收发正常GD32上CAN0能发送但接收不到数据总线信号正常其他节点能收到GD32发送的数据原因分析 问题出在过滤器配置上。两个芯片的过滤器分配机制有差异STM32的CAN_FMR.CAN2SB和GD32的CAN_FCTL.HBC1F控制CAN1/CANb的过滤器起始位置默认值都是14(0x0E)但代码中未初始化sFilterConfig1.SlaveStartFilterBankSTM32存在与文档不符的行为即使CAN2SB0也能接收数据GD32严格遵循文档HBC1F0时CANa无法使用任何过滤器解决方案 在调用HAL_CAN_ConfigFilter()前正确初始化过滤器配置sFilterConfig1.SlaveStartFilterBank 14; // 保持与复位默认值一致4. 第二个CAN接口异常过滤器配置遗漏解决了CANa的接收问题后又发现GD32的CANb对应STM32的CAN2无法正常通信。现象描述修改过滤器配置后CANa工作正常但CANb无法收发数据总线终端电阻配置正确原因分析 原因在于原代码中只配置了CANa的过滤器没有配置CANb的过滤器。当CAN_FMR.CAN2SB被正确设置后影响了CANb的默认过滤器行为。解决方案 需要为CANb添加独立的过滤器配置CAN_FilterTypeDef sFilterConfig2; // 其他配置... sFilterConfig2.FilterBank 15; // 使用过滤器15与SlaveStartFilterBank14匹配 HAL_CAN_ConfigFilter(hcan2, sFilterConfig2);5. 数据发送丢失超时处理的临界条件最后一个问题是GD32在连续发送多包数据时会出现数据丢失。现象描述连续发送4包数据时第3包丢失现象在特定超时值下出现STM32上即使触发超时也能完整发送原因分析 问题出在发送超时处理上原代码使用固定超时值200对于GD32来说太小GD32执行速度更快在超时触发时可能正好完成发送STM32因速度较慢超时触发时数据还未发送完实际未终止发送GD32严格执行终止操作导致数据被真正丢弃测试数据对比芯片超时值范围行为表现STM32190丢失第3包STM32190-300触发超时但完整发送STM32300正常发送GD32255丢失第3包GD32255-395触发超时但完整发送GD32395正常发送解决方案 增大超时值考虑最坏情况// 将各处超时值统一修改为足够大的值 uint32_t timeout 10000; // 考虑低波特率情况注意更完善的解决方案应考虑波特率和时钟频率的影响动态计算超时值。移植过程中发现GD32F305在CAN外设行为上与STM32F105存在多处细微但关键的差异。这些差异往往不会在数据手册中特别标注需要开发者通过实际测试来发现。建议在移植时仔细对比每个寄存器的位定义不要假设默认行为一致对关键操作添加充分的调试信息边界条件测试要覆盖各种极端情况