STM32通过DMA读取ADC时导致FreeRTOS调度崩溃问题咨询
排查STM32 DMA+ADC+FreeRTOS导致HardFault的方向
1. 中断优先级配置冲突检查
- 确认FreeRTOS的
configMAX_SYSCALL_INTERRUPT_PRIORITY(或configKERNEL_INTERRUPT_PRIORITY)设置,确保TIM6、ADC、DMA的中断优先级不低于这个值(STM32优先级数值越小优先级越高,FreeRTOS要求系统调用相关中断优先级不能高于该阈值,否则会破坏内核上下文)。 - 检查TIM6(时基)、ADC、DMA的NVIC优先级分组是否一致,比如统一用4位抢占优先级+0位子优先级,避免分组混乱导致优先级计算错误。
- 查看HAL库生成的NVIC配置代码,确保TIM6、ADC、DMA的抢占/子优先级设置无重叠或不合理情况,比如DMA优先级不能被低优先级任务打断后引发上下文错误。
2. TIM6时基与FreeRTOS SysTick冲突排查
- 确认TIM6是否同时用作HAL库时基源(
HAL_InitTick中配置)和其他用途?如果FreeRTOS用SysTick作为内核时钟,需确保TIM6的时基中断优先级不会干扰SysTick。 - 检查
HAL_TIM_Base_Start_IT(&htim6)这类启动TIM6中断的代码,是否在FreeRTOS启动后被错误调用,导致中断上下文与任务上下文冲突。 - 尝试临时禁用TIM6时基(改用SysTick作为HAL时基),测试启动ADC_DMA是否仍触发HardFault,以此验证TIM6是否为冲突根源。
3. DMA与ADC配置合法性检查
- 确认ADC的DMA请求映射正确:ADC1对应DMA1的哪个通道、ADC2对应哪个通道,避免配错通道引发硬件错误。
- 检查DMA的内存地址合法性:传递给
HAL_ADC_Start_DMA的目标数组必须是全局变量或静态变量,不能用栈上的局部变量(任务栈空间有限,且DMA访问栈地址可能因任务切换导致地址失效)。 - 核对ADC配置:是否开启连续转换、扫描模式,DMA的传输方向、数据宽度(比如ADC是12位,DMA需对应半字传输)是否匹配;若同时使用ADC1和ADC2,双ADC模式及对应DMA配置是否正确。
4. HardFault现场调试定位
- 进入HardFault后查看寄存器值:
- 读取
MSP(主栈指针)指向的内存,获取栈帧里的PC(程序计数器)和LR(链接寄存器)值,定位触发HardFault的具体代码行。 - 检查
CFSR(配置故障状态寄存器)的值,判断是总线故障、用法故障还是存储器故障:- 总线故障:大概率是DMA访问非法地址,或外设寄存器访问冲突。
- 用法故障:可能是指令执行错误,比如对齐错误、未定义指令。
- 读取
- 在
PendSV_Handler处打断点,查看进入PendSV前的调用栈,确认任务切换过程中哪个环节触发错误,是否与DMA/ADC中断抢占任务切换有关。
5. FreeRTOS任务栈与上下文检查
- 检查
ReadTask01的任务栈大小是否足够,启动ADC_DMA时若有局部变量或中断嵌套,可能导致栈溢出引发HardFault,可暂时调大任务栈大小测试。 - 确保调用
HAL_ADC_Start_DMA时,ADC和DMA外设处于未被占用状态,避免其他任务或中断同时操作ADC/DMA资源引发竞争。可使用FreeRTOS互斥锁保护ADC/DMA的操作。
内容的提问来源于stack exchange,提问作者Runzolf
相关产品推荐
相关产品推荐

