FreeRTOS STM32中断详解
文章目录
一、三种优先级的概念辨析
本篇文章将对下面三种优先级进行概念辨析:
1. 先理清楚两个概念:CPU 和 MPU
“CPU”:“Central Processing Unit”,即中央处理器。它是计算机系统中的主要组件,负责执行指令并进行数据处理和计算。CPU通常由控制单元、算术逻辑单元(ALU)和寄存器等部分组成。
“MPU:”“Microprocessor Unit”,微处理器单元。MPU通常用来指代一种单芯片的微处理器,它集成了处理器核心、内存、接口和其他外设等功能,常用于嵌入式系统和嵌入式设备。MPU可以被视为一种较小规模的计算机系统。
2. Cortex-M3 内核与 STM32F1XX 控制器有什么关系
先看看较为官方的解释:
Cortex-M3内核是一种由Arm公司设计的低功耗、高性能的32位RISC处理器内核。它具有较高的执行效率和能效,专门针对嵌入式系统设计。
STMicroelectronics的STM32F1系列是十分流行的Cortex-M3微控制器系列,提供了多个型号和配置选项,包括STM32F103、STM32F107等
简而言之,Cortex-M3 内核是 ARM 这个公司设计的一种 CPU 架构,而 STM32F1XX 控制器是 ST 公司在 CPU 上连接了片上外设、存储器、接口的一种 MPU,也就是 Cortex-M3 芯片。
此图片来自《CM3 权威指南》一书。
3. 优先级的概念辨析
① Cortex-M3 内核和 STM32F1XX 的中断优先级
由于芯片制造商可以对 Cortex-M3 内核进行裁剪(只使用 Cortex-M3 的一部分),所以在内核方面, STM32F1XX 芯片实际上使用了完整的 Cortex-M3 内核的一部分。
所以这两者的优先级是相通的。(注意我使用的是“相通”,而不是“相同”,这意味着 STM32F1XX 芯片的各种设置可以在 Cortex-M3 架构的规定下由芯片厂商灵活自行设计)
② FreeRTOS 的任务的优先级
FreeRTOS 是运行于 STM32 芯片上的操作系统,其任务的优先级决定了设置的各类任务的执行顺序,是任务之间的优先级。
任务之间的优先级限制于 FreeRTOS 框架内,而 FreeRTOS 内核又被限制于 STM32 框架上。
二、 Cortex-M3 内核的中断优先级
(注:以下混合使用“中断”和“异常”这俩个术语,意思一致)
1. 中断编号
2. 优先级与编号的关系


3. 优先级配置寄存器

三、STM32F1XX 的中断优先级
1. 中断数量和编号


等等等等
2. 中断优先级配置
抢占优先级 | 子优先级 |
---|---|
0 位 | 4 位 |
1 位 | 3 位 |
2 位 | 2 位 |
3 位 | 1 位 |
4 位 | 0 位 |
三、SVC 和 PendSV 详解
1. SVC
① SVC 是什么
用户程序(基于 FreeRTOS 之上的程序)通过 SVC 使用系统服务函数。
一个例子是当启动任务调度器的时候, FreeRTOS 通过 SVC 启动第一个任务,详见:【学习日记】【FreeRTOS】调度器函数实现详解
② SVC 的中断优先级
实际上,在 FreeRTOS 中并未显式配置 SVC 的中断优先级。
我们可以开启调试查看,可以看到默认优先级是 0:
③ 使用 SVC 的好处
- 操作系统(OS)负责控制具体的硬件,使用户程序从控制硬件的繁文缛节中解脱出来。
- OS的代码经过充分的测试,提高系统的健壮性和可靠性。
- 用户程序无需在特权级下执行,避免用户程序误操作导致系统瘫痪的风险。
- 通过SVC的机制,使用户程序与硬件无关,简化了开发难度和繁琐度,使应用程序跨硬件平台移植成为可能。
- 应用程序只需了解操作系统提供的应用编程接口(API),并使用SVC提出请求,而无需了解硬件的操作细节。
2. PendSV
① PendSV 是什么
可悬起的系统调用,顾名思义,是可以像普通的中断一样被悬起的中断。也就是触发后如果优先级不够,会等到时机合适再执行。
在 FreeRTOS 默认配置为优先级最低的 15。
② PendSV 的应用
在 FreeRTOS 中,被用于任务的切换。
在 FreeRTOS 中,我们在 SysTick 中断中触发 PendSV,在 PendSV 进行任务切换。
如果不使用 PendSV 进行任务切换,那么当 SysTick 的优先级不是最低时:
理想情况下,任务A 执行一段时间后进入 SysTick 中断,在 SysTick 中断中进行上下文切换到任务B
糟糕的情况是,任务A 执行一段时间后进入了一个中断,在中断中又进入到 SysTick 中断,并在其中尝试上下文切换,也就是切换到主线程中,但是第一个中断还未执行完毕(这会导致 Usage Fault,因为其使中断执行一半就跳会到主线程,如果允许这样做系统将没有实时性的保证)
如果使用了 PendSV,则可以使上下文切换的动作暂时搁置,先执行完中断再进行上下文的切换。
不过,值得深思的是,在 FreeRTOS 的默认配置中, SysTick 的中断优先级被配置为最低的 15,这意味着其不能打断任何的中断,那么使用 PendSV 可能有其他更充分的理由。
四、运行在 STM32 上的 FreeRTOS 中断优先级的配置
1. 中断优先级分组
使用分组 4,也就是 16 级的抢占优先级、0 级的子优先级:
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
2. FreeRTOS 内核优先级
① 定义
在 FreeRTOSConfig.h
中,由 configKERNEL_INTERRUPT_PRIORITY 定义:
#define configPRIO_BITS 4
//中断最低优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
② 内核优先级的作用范围
那么这个内核优先级究竟是谁在用呢?实际上就是 SysTick 中断和 PendSV 中断在使用。
SysTick 用于时间片轮转、PendSV 用于上下文切换:
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
3. 临界段保护的中断优先级
① 临界段保护就是关中断

② 如何关中断
详情见【学习日记】【FreeRTOS】临界段的保护
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
basepri 是 MSB 对齐(在 STM32F1 中,basepri 是八位的寄存器,可只使用其中某几位,MSB 对齐指最高位对齐,也就是当只使用其中某几位时从最高位开始用,低位不管)用法和优先级配置寄存器类似:
basepri 设定为大于其值的中断都会被屏蔽(此处的中断优先级指 STM32 的中断优先级而不是 FreeRTOS 我们为任务设定的优先级):
下面是 FreeRTOS 中进入临界段时对 basepri 的设置,设置为 5,也就是 FreeRTOS 进入临界段时,中断优先级 5-15 的中断都被屏蔽:
//系统可管理的最高中断优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
后记
如果您觉得本文写得不错,可以点个赞激励一下作者!
如果您发现本文的问题,欢迎在评论区或者私信共同探讨!
共勉!