RESERVE8
AREA |.text|, CODE, READONLY
THUMB
;********************************************************************************************************
; CRITICAL SECTION METHOD 3 FUNCTIONS
;
;********************************************************************************************************
OS_CPU_SR_Save
MRS R0, PRIMASK ;读取PRIMASK到R0,R0为返回值
CPSID I
RIMASK=1,关中断(NMI和硬件FAULT可以响应)
BX LR ;返回
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;读取R0到PRIMASK中,R0为参数;open interrupt
BX LR ;返回
;/**************************************************************************************
;* 函数名称: OSStartTask
;*
;* 功能描述: 使用调度器运行第一个任务
;*
;* 参 数: None
;*
;* 返 回 值: None
;**************************************************************************************/
OSStartTask
LDR R4, =NVIC_SYSPRI2 ; set the PendSV exception priority
LDR R5, =NVIC_PENDSV_PRI
STR R5, [R4]
MOV R4, #0 ; set the PSP to 0 for initial context switch call
MSR PSP, R4
;切换到最高优先级的任务
LDR R4, =NVIC_INT_CTRL ;rigger the PendSV exception (causes context switch)
LDR R5, =NVIC_PENDSVSET ;触发PendSV异常 (causes context switch)
STR R5, [R4]
CPSIE I ;enable interrupts at processor level
OSStartHang
B OSStartHang ;should never get here
;/**************************************************************************************
;* 函数名称: OSCtxSw
;*
;* 功能描述: 任务级上下文切换
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSCtxSw
 
USH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
 
OP {R4, R5}
BX LR
NOP
;/**************************************************************************************
;* 函数名称: OSIntCtxSw
;*
;* 功能描述: 中断级任务切换
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSIntCtxSw
 
USH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
 
OP {R4, R5}
BX LR
NOP
;/**************************************************************************************
;* 函数名称: OSPendSV
;*
;* 功能描述: OSPendSV is used to cause a context switch.
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注
CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time
SUBS R0, R0, #0x20
STM R0, {R4-R11} ; Save remaining regs r4-11 on process stack
LDR R1, =OSCurTCB
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
PendSV_Handler_Nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSCurTCB ;OSCurTCB=OSNewTCB;
LDR R1, =OSNewTCB
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSCurTCB;
LDM R0, {R4-R11} ; Restore r4-11 from new process stac
ADD R0, R0, #0x20
MSR PSP, R0
ORR LR, LR, #0x04
CPSIE I ; Exception return will restore remaining context
BX LR
end
仔细看汇编部分,是否就是ucos在stm32系统上移植的翻版?利用以上汇编部分代码,你就可以不管汇编部分,专心做c语言部分任务调度方面的事了。该任务调度时调用OSCtxSw(),传递不同任务的堆栈指针OSCurTCB,OSNewTCB就完成了新旧任务之间的切换。
再来看看OSCurTCB,OSNewTCB分别是什么。
typedef struct taskControlBlock
{
/*当前的栈顶指针*/
OS_STK *pStackTop;
/*当前优先级*/
 
RIO_TYPE CurPriority;
/*任务状态*/
uint8 TaskStat;
/*等待时间片的个数*/
int32 TCBDelay;
} TCB;
/*当前运行的任务*/
TCB *OSCurTCB;
/*当前准备新运行的任务*/
TCB *OSNewTCB;
/*当前OS中所有的任务*/
uint8 TaskNUM=0;
TCB OSTCBTable[MAX_TASK_NUM];
可见OSCurTCB和OSNewTCB分别是当前运行任务的堆栈指针和要运行的新任务的堆栈指针。
下面关心的可能是任务的创建了,任务是如何创建的。每个任务都有自己的堆栈空间,就像是单独占用CPU一样,所以创建任务的一方面主要是完成任务堆栈的初始化。
以下是c语言写的任务堆栈的初始化函数,位于文件OS_CPU.c中,如果需要移植,除了汇编部分OS_CPU_A.asm文件修改外,OS_CPU.c和OS_TYPE.h等文件也需要修改。仅这几个文件,所以mini/OS移植很简单。
OS_STK实际上就是int32,因为stm32上堆栈指针就是32位长度。第一个参数是任务的地址,即函数的地址,第二个参数是任务的堆栈指针。
OS_STK *OSTaskStkInit (void (*task),OS_STK *ptos)
{
OS_STK *stk;
// (void)PSR; /* 'PSR' is not used, prevent warning */
stk = ptos; /* 获取堆栈指针 */
/* Registers stacked as if auto-saved on exception */
*(stk) = (uint32)0x01000000L; /* xPSR */
*(--stk) = (uint32)task; /* Entry Point */
*(--stk) = (uint32)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/
*(--stk) = (uint32)0x12121212L; /* R12 */
*(--stk) = (uint32)0x03030303L; /* R3 */
*(--stk) = (uint32)0x02020202L; /* R2 */
*(--stk) = (uint32)0x01010101L; /* R1 */
*(--stk) = (uint32)0; /* R0 : argument */
/* Remaining registers saved on process stack */
*(--stk) = (uint32)0x11111111L; /* R11 */
*(--stk) = (uint32)0x10101010L; /* R10 */
*(--stk) = (uint32)0x09090909L; /* R9 */
*(--stk) = (uint32)0x08080808L; /* R8 */
*(--stk) = (uint32)0x07070707L; /* R7 */
*(--stk) = (uint32)0x06060606L; /* R6 */
*(--stk) = (uint32)0x05050505L; /* R5 */
*(--stk) = (uint32)0x04040404L; /* R4 */
return (stk);
}