OS设计说明1. 任务状态切换 如下图,任务必须严格按这三个状态切换
2. 任务创建流程 该代码运行在系统特权级线程模式,堆栈使用MSP 申请任务控制块 申请堆栈内存,并赋值栈顶指针,注意:malloc的内存返回地址是内存的起始地址,而堆栈是向下生产的,所以栈顶指针赋值时必须加上堆栈深度 初始化堆栈空间,必须严格按Cortex M3的入栈要求执行 任务状态置为ready
static StackSize_t* TASK_TaskStackFirstInit(IN StackSize_t *topStack, IN TaskFunction_t func) { /* 按堆栈地址顺序入栈,而非寄存器入栈顺序 * PSR,PC,LR,R12,R3,R2,R1,R0 以上是芯片自动入栈的 * R4,R5,R6,R7,R8,R9,R10,R11 以上手工入栈,入出栈顺序注意保持一致 * 此处也可以增加计数,用于堆栈溢出检查 */ topStack--; *topStack = OS_TASK_INITIAL_XPSR; topStack--; *topStack = (((StackSize_t)func) & OS_TASK_START_ADDRESS_MASK); topStack--; /* 任务栈初次初始化,已是最上层了,返回即错,因此可以增加返回函数用户调试 */ topStack -= 5; /* 可用于函数入参 */ topStack -= 8; return topStack; }
S32 OS_TASK_CreateTask ( IN U8 id, IN TaskFunction_t taskHandle, IN U16 taskStackDeep, IN U32 *eventBitMap ) { TCB_S *newTcb = NULL; StackSize_t *topStack = NULL; if (id >= OS_TASK_MAX) { return OS_ERROR; } newTcb = (TCB_S*)malloc(sizeof(TCB_S)); if (NULL == newTcb) { return OS_ERROR; } newTcb->state = TASK_INIT; topStack = (StackSize_t *)malloc(sizeof(StackSize_t)*taskStackDeep); if (NULL == topStack) { return OS_ERROR; } topStack += sizeof(StackSize_t)*taskStackDeep;
newTcb->topStack = TASK_TaskStackFirstInit(topStack, taskHandle); newTcb->state = TASK_READY; newTcb->delay = 0; newTcb->delayMax = 0; newTcb->eventBitMap = eventBitMap; newTcb->id = id;
gTaskTcbList[id] = newTcb; return OS_OK; }
3. 任务首次调度流程
该流程的目的是把CPU的控制权,有特权级线程模式切成用户级线程模式,根据OS原理分析得知,需要做如下处理
找到当前优先级最高且处于Ready状态的任务,即gCurrentTCB指向的任务
触发svc 0,进入SVC中断,此时处于handler模式
PSP指向当前任务的堆栈指针
利用LR寄存器异常返回特性,返回到线程模式使用线程堆栈,完成CPU控制权交接给当前任务,如图
__asm static VOID TASK_SvcHandler(VOID)
{
extern gCurrentTCB;
/* 任务相关内容映射到入线程栈 */
ldr r3, =gCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp, r0
isb
/* 利用LR寄存器异常返回进入线程模式特性 */
mov r14, #0xfffffffd
bx r14
nop
}
void SVC_Handler(void)
{
TASK_GetCurrentTask();
TASK_SvcHandler();
}
__asm static VOID TASK_StartFirstTask(VOID)
{
/* 触发svc,在svc中断中通过修改LD寄存器值的方式进入线程模式 */
svc 0
nop
nop
}
VOID OS_TASK_SchedulerTask(VOID)
{
TASK_StartFirstTask();
return;
}
|