参考资料:
《Cortex-M3权威指南》:Embedded/RTOS/Cortex-M3权威指南(中文版).pdf · guorong/study - 码云 - 开源中国 (gitee.com)
代码:Embedded/RTOS/PENDSV · guorong/study - 码云 - 开源中国 (gitee.com)
在开发了一段时间单片机裸机代码之后,可以进阶学习一些RTOS的知识,本文开始,逐步介绍一些RTOS的实现方式
在主流的rtos中,都是使用了pendsv来进行任务的切换,在Cortex-M3权威指南中具体介绍了任务切换的几种历史的方法,之前有用systick中断来做的,但是由于和其余的中断的优先级的冲突,主要是在中断的过程中,不能进行任务的切换,否则会影响堆栈的切换。后来的ARM内核中增加了可以设置为最低优先级的pendsv中断之后,完美地解决了中断和切换任务的冲突的问题,后续都是在中断完成后,才进行任务的切换。
所以进行rtos任务切换的第一步就是要配置和触发pendsv中断
在Cortex-M3权威指南中,有两个寄存器需要关心,一个是中断触发寄存器,一个是优先级配置寄存器。分别如下,在135页有中断触发寄存器
在131页有关于优先级的说明
按照之前STM32的专栏里介绍的新建汇编文件的方式,新建一个汇编文件,然后参照上边的寄存器地址,定义三个函数,分别为pendsv的中断处理函数,这个函数后续需要做任务切换,暂时只做一些寄存器的操作,用于观察现象。另外两个是配置pendsv的优先级和手动触发pendsv中断,代码如下:
NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register.
NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14).
NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest).
NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
EXPORT PendSV_Handler
EXPORT SET_PENDSV_PRI
EXPORT TRIGGER_PENDSV
PRESERVE8
THUMB
AREA CODE, CODE, READONLY
PendSV_Handler
MOV R0 ,#0X10000000
MOV R1 ,#0X10000000
MOV R2 ,#0X10000000
MOV R3 ,#0X10000000
MOV R4 ,#0X10000000
MOV R5 ,#0X10000000
BX LR
SET_PENDSV_PRI
LDR R0, =NVIC_SYSPRI14
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
BX LR
TRIGGER_PENDSV
LDR R0, =NVIC_INT_CTRL
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
ALIGN
END
在main函数中,初始化的时候,配置一下中断的优先级,然后在while(1)的循环中,不断触发pendsv中断
#include"stm32f10x.h"
int main()
{
SET_PENDSV_PRI();
while(1)
{
TRIGGER_PENDSV();
}
}
在线运行跟踪一下,打开中断控制器
运行之后,可以看到优先级被配置为15,数值越大,优先级越低
然后运行到TRIGGER_PENDSV中的STR R1,[R0]之后,就会进入PendSV_Handler中运行,可以看到R0~R5寄存器会被依次置为0x10000000,然后会返回到TRIGGER_PENDSV中的BX LR 然后会跳到main函数,完成一次中断的触发,运行,退出