FreeRTOS运行于ARM Cortex-M0时UART中断不触发问题
问题根因
这个问题的核心是你参考了Cortex-M3/M4架构的FreeRTOS中断配置规则,完全忽略了STM32F0搭载的Cortex-M0内核的硬件特性,以及对应FreeRTOS移植层的实现差异:
- Cortex-M3/M4内核自带BASEPRI寄存器,可以通过硬件寄存器直接屏蔽所有逻辑优先级高于指定阈值的中断,不需要修改NVIC的中断通道使能位。
- Cortex-M0内核没有BASEPRI寄存器,根本不支持基于优先级的部分中断掩码功能,因此FreeRTOS的Cortex-M0移植层做了兼容处理:调度器启动时,会直接通过NVIC寄存器禁用所有优先级数值小于
configMAX_SYSCALL_INTERRUPT_PRIORITY的中断(ARM Cortex-M系列MCU的规则是优先级数值越小,逻辑优先级越高),以此模拟M3/M4上的中断屏蔽逻辑。
你的代码里把USART1的中断优先级NVIC_IRQChannelPriority设为了0,这是Cortex-M0支持的最高优先级(Cortex-M0仅实现2位优先级位,合法优先级范围为0~3,0为最高优先级,3为最低)。常规FreeRTOS配置中configMAX_SYSCALL_INTERRUPT_PRIORITY会设为1,优先级0属于高于系统调用阈值的“不受FreeRTOS管理”优先级,因此调度器启动时会直接把USART1对应的NVIC中断通道禁用。哪怕你后续正常调用USART_ITConfig打开了USART外设的TXE、RXNE中断,NVIC层面的通道是关的,中断服务函数永远不会被触发。
修复方案
- 调整USART1的NVIC中断优先级,将其设置为大于等于
configMAX_SYSCALL_INTERRUPT_PRIORITY、小于等于configKERNEL_INTERRUPT_PRIORITY之间的数值即可。比如常规配置下configMAX_SYSCALL_INTERRUPT_PRIORITY=1、configKERNEL_INTERRUPT_PRIORITY=3,把优先级设为2就符合要求。 - 额外修正代码隐患:你的初始化代码调用
USART_Init时传入的是s_port[uart].base指针,后续所有USART操作却硬编码使用USART1,如果s_port[uart].base不是指向USART1的地址,会导致初始化和操作的外设对象不一致,建议统一用指针变量访问外设寄存器,避免低级错误。 - Cortex-M0内核不支持优先级分组,所有优先级都是抢占优先级,不需要调用
NVIC_PriorityGroupConfig做配置,删掉相关代码即可。
注意:Cortex-M0/M0+内核上的FreeRTOS临界区是直接通过PRIMASK寄存器关闭所有可屏蔽中断实现的,高优先级中断(数值小于configMAX_SYSCALL_INTERRUPT_PRIORITY)不仅不能调用任何FreeRTOS API,还会被FreeRTOS直接禁用,不要尝试在这类MCU上照搬M3/M4的高优先级中断做快速响应的设计。
内容的提问来源于stack exchange,提问作者Mitch Ostler
相关产品推荐
相关产品推荐

