μC/OS-III内核实现与应用开发实战指南:基于STM32
上QQ阅读APP看书,第一时间看更新

3.4 启动系统

任务创建好且系统初始化完毕之后,就可以启动系统了。系统启动函数OSStart()在os_core.c中定义,具体实现参见代码清单3-23。

代码清单3-23 OSStart()函数

1 void OSStart (OS_ERR *p_err)
 2 {
 3     if ( OSRunning == OS_STATE_OS_STOPPED ) {(1)
 4         /* 手动配置任务1先运行 */
 5         OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;(2)
 6 
 7         /* 启动任务切换,不会返回 */
 8         OSStartHighRdy();(3)
 9 
10         /* 不会运行到这里,如果运行到这里,则表示发生了错误 */
11         *p_err = OS_ERR_FATAL_RETURN;
12     } else {
13         *p_err = OS_STATE_OS_RUNNING;
14     }
15 }

代码清单3-23(1):如果系统是第一次启动,则if为真,继续往下运行。

代码清单3-23(2):OSTCBHighRdyPtr指向第一个要运行的任务的TCB。因为暂时不支持优先级,所以系统启动时先手动指定第一个要运行的任务。

代码清单3-23(3):OSStartHighRdy()用于启动任务切换,即配置PendSV的优先级为最低,然后触发PendSV异常,在PendSV异常服务函数中进行任务切换。该函数不再返回,在文件os_cpu_a.s中定义(第一次使用os_cpu_a.s时需要自行在文件夹μC/OS-III\Ports中新建并添加到工程的μC/OS-III Ports组),用汇编语言编写,具体实现参见代码清单3-24。os_cpu_a.s文件中涉及的ARM汇编指令的用法如表3-1所示。

表3-1 常用的ARM汇编指令

代码清单3-24 OSStartHighRdy()函数

1 ;*******************************************************************
 2 ;                        开始第一次上下文切换
 3 ; 1)配置PendSV异常的优先级为最低
 4 ; 2)在开始第一次上下文切换之前,设置psp=0
 5 ; 3)触发PendSV异常,开始上下文切换
 6 ;*******************************************************************
 7 OSStartHighRdy
 8   LDR     R0, = NVIC_SYSPRI14    ; 设置PendSV 异常优先级为最低(1)
 9   LDR     R1, = NVIC_PENDSV_PRI
10   STRB    R1, [R0]
11 
12   MOVS    R0, #0                 ;设置PSP的值为0,开始第一次上下文切换(2)
13   MSR     PSP, R0
14 
15   LDR     R0, =NVIC_INT_CTRL     ; 触发PendSV异常(3)
16   LDR     R1, =NVIC_PENDSVSET
17   STR     R1, [R0]
18 
19   CPSIE   I                      ; 启用总中断,NMI和HardFault除外(4)
20 
21 OSStartHang
22   B       OSStartHang            ; 程序应永远不会运行到这里

代码清单3-24中涉及的NVIC_INT_CTRL、NVIC_SYSPRI14、NVIC_PENDSV_PRI和NVIC_PENDSVSET这4个常量在os_cpu_a.s的开头定义,具体参见代码清单3-25,有关这4个常量的含义参见代码注释即可。

代码清单3-25 NVIC_INT_CTRL、NVIC_SYSPRI14、NVIC_PENDSV_PRI和NVIC_PENDSVSET常量定义

1 ;********************************************************************
 2 ;                               常量
 3 ;********************************************************************
 4 ;--------------------------------------------------------------------
 5 ;有关内核外设寄存器定义可参考官方文档:STM32F10xxx Cortex-M3 programming manual
 6 ;系统控制块外设地址范围:0xE000ED00~0xE000ED3F
 7 ;--------------------------------------------------------------------
 8 NVIC_INT_CTRL   EQU     0xE000ED04    ; 中断控制及状态寄存器 SCB_ICSR
 9 NVIC_SYSPRI14   EQU     0xE000ED22    ; 系统优先级寄存器 SCB_SHPR3
10                                       ; 位16~23
11 NVIC_PENDSV_PRI EQU           0xFF    ; PendSV 优先级的值(最低)
12 NVIC_PENDSVSET EQU      0x10000000    ; 触发PendSV异常的值位28:PENDSVSET

代码清单3-24(1):配置PendSV的优先级为0XFF,即最低。在μC/OS-III中,上下文切换是在PendSV异常服务程序中执行的,配置PendSV的优先级为最低,从而排除了在中断服务程序中执行上下文切换的可能。

代码清单3-24(2):设置PSP的值为0,开始第一个任务切换。在任务中,使用的栈指针都是PSP,后面如果判断出PSP为0,则表示第一次任务切换。

代码清单3-24(3):触发PendSV异常,如果中断启用且编写了PendSV异常服务函数,则内核会响应PendSV异常,去执行PendSV异常服务函数。

代码清单3-24(4):开中断,因为有些用户在main()函数中会先关掉中断,等全部初始化完成后,在启动操作系统时才开中断。为了快速地开关中断,ARM CM3专门设置了一条CPS指令,有4种用法,具体参见代码清单3-26。

代码清单3-26 CPS指令用法

1 CPSID I ;PRIMASK=1     ;关中断
 2 CPSIE I ;PRIMASK=0     ;开中断
 3 CPSID F ;FAULTMASK=1   ;关异常
 4 CPSIE F ;FAULTMASK=0   ;开异常

代码清单3-26中,PRIMASK和FAULTMASK是ARM CM3中3个中断屏蔽寄存器中的两个,还有一个是BASEPRI,有关这3个寄存器的详细用法如表3-2所示。

表3-2 ARM CM3中断屏蔽寄存器