STM32 HAL I2C DMA回调未触发及H7传输错误排查求助
问题梳理
STM32 Nucleo F401(FreeRTOS + I2C1 DMA)
- 轮询模式下I2C读写传感器正常,同板UART+DMA2工作正常,MX_DMA_Init在MX_I2C1_Init前执行
- 禁用I2C1事件/错误中断:FreeRTOS并行任务运行正常,但
HAL_I2C_MasterTxCpltCallback回调未触发 - 启用I2C1事件/错误中断:FreeRTOS仅两个并行任务运行一次后调度异常,
HAL_I2C_EV_IRQHandler被周期性调用但进入无操作分支
STM32 H723ZG(I2C DMA)
- I2C DMA仅完成一次传输即失败,错误码为
HAL_DMA_ERROR_TE(传输错误) - 已尝试DMA数据对齐、D-cache清理操作,问题未解决
排查与解决办法
针对F401平台
修正中断优先级配置
FreeRTOS要求中断优先级必须低于configMAX_SYSCALL_INTERRUPT_PRIORITY(由NVIC_PRIORITYGROUP决定)。检查CubeMX中I2C1事件/错误中断的抢占优先级:- 若使用优先级分组4(4位抢占优先级),确保I2C中断抢占优先级≥
configMAX_SYSCALL_INTERRUPT_PRIORITY(通常设为5或更高) - 避免中断优先级高于FreeRTOS内核中断优先级,否则会破坏任务调度逻辑
- 若使用优先级分组4(4位抢占优先级),确保I2C中断抢占优先级≥
确保回调函数的C++兼容性
必须将HAL_I2C_MasterTxCpltCallback声明为extern "C",或在C++文件中用extern "C"包裹回调实现:extern "C" { void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) { // 业务回调逻辑 } }同时确认启动文件中
HAL_I2C_IRQHandler已正确映射到I2C1的中断向量,未被用户代码覆盖。验证DMA与I2C的绑定配置
- 检查CubeMX中I2C1的DMA传输设置:确保发送/接收通道正确绑定到DMA1的对应数据流(F401的I2C1_TX对应DMA1_Stream6,I2C1_RX对应DMA1_Stream5)
- 禁用DMA循环模式(除非业务明确需要),避免DMA自动重启导致中断异常
排查FreeRTOS任务栈溢出
若任务栈空间不足,中断触发时可能破坏任务上下文。使用FreeRTOS的uxTaskGetStackHighWaterMarkAPI检查任务栈剩余空间,确保涉及I2C DMA操作的任务栈大小足够。
针对H723ZG平台
定位DMA传输错误的核心原因
HAL_DMA_ERROR_TE通常由以下情况导致:- 地址对齐错误:H7的DMA要求源/目标地址与数据宽度对齐(8位数据无要求,16位需2字节对齐,32位需4字节对齐)。可使用宏确保缓冲区地址对齐:
__ALIGN_BEGIN uint8_t tx_buffer[32] __ALIGN_END; - D-cache一致性问题:确认cache清理时机正确:
- 传输前对发送缓冲区执行
SCB_CleanDCache_by_Addr() - 接收后对接收缓冲区执行
SCB_InvalidateDCache_by_Addr() - 若问题持续,可修改链接脚本将缓冲区放在非缓存内存段
- 传输前对发送缓冲区执行
- 地址对齐错误:H7的DMA要求源/目标地址与数据宽度对齐(8位数据无要求,16位需2字节对齐,32位需4字节对齐)。可使用宏确保缓冲区地址对齐:
检查时钟配置匹配性
- 确保I2C时钟速率符合传感器的时序要求,避免时钟过高导致传输错误
- 确认DMA时钟(AHB总线)与I2C时钟(APB总线)的速率匹配,排除跨总线传输的时钟域问题
调整DMA FIFO配置
H7的DMA带有FIFO,需根据传输数据宽度设置合适的FIFO阈值:- 8位I2C传输时,将FIFO阈值设为"1/4 full"或"1/2 full",避免FIFO溢出或欠载
- 在CubeMX的DMA配置中找到对应数据流的FIFO Mode选项,调整阈值参数
验证硬件连接与兼容性
- 检查H7板上的I2C上拉电阻是否为合适阻值(通常4.7kΩ),避免信号过弱导致传输错误
- 尝试降低I2C时钟速率(如从400kHz降至100kHz),排除高速传输下的硬件兼容性问题
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

