在之前的代码中看到很多地方都用到OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()这两个函数。而且这两个函数总是成对的出现。
现在解释一下。这对函数实现的就是类似于原子操作的功能,在两个函数之间的代码部分再执行期间不会被中断或者是被其他任务抢占,会一次性执行完成。
如何实现这功能的,就是通过开关总中断来实现的,OS_ENTER_CRITICAL() 在关掉中断之后,任务切换(通过软中断)和中断函数都不会被执行。
在执行完这部分代码之后,调用OS_EXIT_CRITICAL()再开启中断。其必须成对出现,若是在关掉中断之后不再开启,整个系统就不能进行正常中断,任务调度切换更加无从执行,而且两个函数之间的代码需要尽可能的短。
其代码实现如下:
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
OS_CPU_SR_Save
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I
BX LR
OS_CPU_SR_Restore
MSR PRIMASK, R0
MSR PRIMASK, R0
BX LR
多任务启动OSStart
在多任务启动之前,系统必须调用了OSInit进行了初始化,而且至少创建了一个以上的任务。
在多任务启动之后,系统就正式开始调度运行了。
其实现代码如下:
void OSStart (void)
{
{
if (OSRunning == OS_FALSE) {
OS_SchedNew(); //查找就绪任务中优先级最高的任务
OSPrioCur = OSPrioHighRdy; //当前运行任务设置为最高优先级任务
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; //指向最高优先级任务的任务控制块指针
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy(); //执行最高优先级任务的代码,其具体实现在下面给出。
}
}
OSStartHighRdy函数
OSStartHighRdy函数在os_cpu_a.asm中定义
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; 设置Pendsv的中断优先级,设置为最小优先级。
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
STRB R1, [R0]
MOVS R0, #0 ; 将任务堆栈指针PSP设置为0。在任务调度的时候,
MSR PSP, R0
LDR R0, =OSRunning ; 将系统启动标志变量设为运行(即1)
MOVS R1, #1
STRB R1, [R0]
STRB R1, [R0]
LDR R0, =NVIC_INT_CTRL ; 悬挂起Pendsv中断,Pendsv中断函数会执行任务的调度和切换(具体看任务管理(4))。
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
STR R1, [R0]
CPSIE I ; 开启中断,一般情况下,这个时候系统不会有其他中断,那么就会立即执行Pendsv中断函数,执行任务的切换。若是有其他中断,则执行完其他中断之后,会再执行该中断。所以任务在这之后一定会切换,运行就绪任务优先级最高的任务。
OSStartHang
B OSStartHang ; //这里是一个死循环,在正常情况下,程序一般是运行不到这里的。