赞
踩
/**
* 多任务的启动时用户通过调用OSStart()实现的
* 在启动之前,用户至少要建立一个应用任务
*/
int main(void)
{
OSInit(); /* 初始化uC/OS-II */
OSTaskCreate(task,(void *)0,(OS_STK *)&TASK_STK[STK_SIZE-1],TASK_PRIO );
OSStart(); /* 开始任务调度 */
}
void OSInit(void) { OSInitHookBegin(); /* Call port specific initialization code */ OS_InitMisc( ); //完成一般变量初始化 OS_InitRdyList( );//就绪列表初始化 OS_InitTCBList( );//空闲任务链表OSTCBFreeList建立 OS_InitEventList( );//事件空闲链表OSEventFreeList建立。 OS_FlagInit( ); //其它相关功能参数初始化。 OS_MemInit( ); OS_QInit( ); OS_InitTaskIdle( );//创建空闲任务OS_TaskIdle. OS_InitTaskStat( ); OSInitHookEnd( ); /* Call port specific init. code */ }
OSTCBTbl[]任务控制块数组清零,全部变成空闲任务控制块。
&OSTCBTbl[i]->OSTCBNext = &OSTCBTbl[i+1]
组成单向的空闲任务控制块链表,OSTCBFreeList = &OSTCBTbl[0];
OSTCBFreeList 为空闲任务控制块链表表头。OSTCBList = (OS_TCB *)0;
OSTCBList 为双向任务控制块链表,创建任务的时候会将这个OS_TCB类型的指针,指向新创建任务的任务控制块,OSTCBPrioTbl[]对应优先级的任务控制块数组清零。
可用过一下两个函数之一建立任务
OSTaskCreate的流程为,①初始化任务堆栈、②初始化任务控制块、③如果系统已启动,进行任务调度
/** * 代码有删减,去除宏定义等,便于梳理工作流程 * OSTaskCreate中,①初始化任务堆栈、②初始化任务控制块、③如果系统已启动,进行任务调度 */ INT8U OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio) { OS_ENTER_CRITICAL();//系统进入“临界区”,即关中断 psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* Initialize the task's stack */ err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u); if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */ OS_Sched(); } OS_EXIT_CRITICAL();//系统退出“临界区”,即开中断 }
1. 入栈顺序
根据Cortex-M3 权威指南
中断/异常触发时,硬件自动依次把xPSR, PC, LR, R12以及R3‐R0压入适当的堆栈中
R11-R4则需要手动压入堆栈中
Cortex-M3先把PC与xPSR的值保存,就可以更早地启动服务例程指令的预取——因为这需要修改PC;同时,也做到了在早期就可以更新xPSR中IPSR位段的值。(时间线不用考虑,只需要了解CM3寄存器组入栈的顺序即可,xPSR, PC, LR, R12以及R3‐R0)
2. M3寄存器组
3. OSTaskStkInit()
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt) { OS_STK *p_stk; p_stk = ptos + 1u; /* Load stack pointer */ /* Align the stack to 8-bytes. */ p_stk = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u); /* Registers stacked as if auto-saved on exception */ *(--p_stk) = (OS_STK)0x01000000uL; /* xPSR */ *(--p_stk) = (OS_STK)task; /* Entry Point */ *(--p_stk) = (OS_STK)OS_TaskReturn; /* R14 (LR) */ *(--p_stk) = (OS_STK)0x12121212uL; /* R12 */ *(--p_stk) = (OS_STK)0x03030303uL; /* R3 */ *(--p_stk) = (OS_STK)0x02020202uL; /* R2 */ *(--p_stk) = (OS_STK)0x01010101uL; /* R1 */ *(--p_stk) = (OS_STK)p_arg; /* R0 : argument */ /* Remaining registers saved on process stack */ *(--p_stk) = (OS_STK)0x11111111uL; /* R11 */ *(--p_stk) = (OS_STK)0x10101010uL; /* R10 */ *(--p_stk) = (OS_STK)0x09090909uL; /* R9 */ *(--p_stk) = (OS_STK)0x08080808uL; /* R8 */ *(--p_stk) = (OS_STK)0x07070707uL; /* R7 */ *(--p_stk) = (OS_STK)0x06060606uL; /* R6 */ *(--p_stk) = (OS_STK)0x05050505uL; /* R5 */ *(--p_stk) = (OS_STK)0x04040404uL; /* R4 */ return (p_stk); }
找一个空闲任务控制块,写入传入的参数,然后将任务块加入就绪任务控制块链表
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt) { OS_TCB *ptcb; //创建任务控制块指针 OS_ENTER_CRITICAL(); /** * 关于OSTCBFreeList,可以看一下OS_InitTCBList()函数,该函数在OSInit()中被调用。 * 在OS_InitTCBList()函数中,将空闲任务控制块数组OSTCBTbl[]先清0, * 然后将OSTCBTbl[]中的前一个空闲任务块元素的OSTCBNext指向下一个空闲任务块元素 * OSTCBFreeList = &OSTCBTbl[0]; */ /* 这里就是将找一个空闲任务控制块 */ ptcb = OSTCBFreeList; /* Get a free TCB from the free TCB list */ if (ptcb != (OS_TCB *)0) { /* OSTCBFreeList重新指向下一个空闲任务块 */ OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list */ OS_EXIT_CRITICAL(); /* 将当前任务堆栈的栈顶指针赋值给任务控制块 */ ptcb->OSTCBStkPtr = ptos; /* Load Stack pointer in TCB */ /* 优先级赋值给任务控制块 */ ptcb->OSTCBPrio = prio; /* Load task priority into TCB */ /* 状态先不看 */ ptcb->OSTCBStat = OS_STAT_RDY; /* Task is ready to run */ ptcb->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ ptcb->OSTCBDly = 0u; /* Task is not delayed */ /* 这里都是为了保存优先级,为了能更快的找到任务优先级最高的已就绪任务 */ /* 放在“③任务调度”总结优先级问题 */ /* A- 这里任务优先级小于64 */ ptcb->OSTCBY = (INT8U)(prio >> 3u); ptcb->OSTCBX = (INT8U)(prio & 0x07u); /* B- Pre-compute BitX and BitY */ ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); /* OSTCBInitHook\OSTaskCreateHook,这俩不知道干嘛,好像用户自定义的东西,后面再看 */ OSTCBInitHook(ptcb); /* ????????? */ OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio] = ptcb; /* 将赋值好的任务控制块放入对应优先级的任务控制块数组中 */ OS_EXIT_CRITICAL(); OSTaskCreateHook(ptcb); /* Call user defined hook ????????? */ OS_ENTER_CRITICAL(); /* OSTCBList指向的是上一个创建的任务的任务控制块 */ /* 将ptcb放入就绪任务控制块链表的头部 */ ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */ ptcb->OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) { OSTCBList->OSTCBPrev = ptcb; } /* OSTCBList指向最新创建的任务控制块 */ OSTCBList = ptcb; /* 这里为了能更快的找到任务优先级最高的已就绪任务 */ /* 将优先级分8组,每组八个优先级 */ /* 放在“③任务调度”总结优先级问题 */ OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OSTaskCtr++; /* Increment the #tasks counter */ OS_EXIT_CRITICAL(); return (OS_ERR_NONE); } OS_EXIT_CRITICAL(); return (OS_ERR_TASK_NO_MORE_TCB); }
创建任务的时候,如果多任务已开始,则查找优先级最高的任务。
判断当前‘正在进行的任务’是不是比‘所有的已就绪任务’的优先级更高,
不是最高,则进行一次任务调度;
是最高,则跳过。
void OS_Sched (void) { OS_ENTER_CRITICAL(); /* 在已就绪的任务中,找到最高优先级OSPrioHighRdy */ OS_SchedNew(); /* 根据优先级OSPrioHighRdy,将OSTCBHighRdy指向该任务的控制块 */ /* OSTCBPrioTbl[prio] = ptcb;在任务创建的时候赋值的 */ OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* 任务切换 */ if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ OSCtxSwCtr++; /* Increment context switch counter */ OS_TASK_SW(); /* Perform a context switch */ } OS_EXIT_CRITICAL(); } //============================================================================================ static void OS_SchedNew (void) { INT8U y; y = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]); } //============================================================================================ #define OS_TASK_SW() OSCtxSw() /** * OSCtxSw 在 os_cpu_a.asm 中 * 啃一下Cortex-M3 权威指南,再来总结 */ PUBLIC OSCtxSw OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
保存就绪就绪优先级
OSTCBY= prio >> 3; // OSTCBY= 0x00
OSTCBX= prio & 0x07; // OSTCBX= 0x05
OSTCBBitY = 1uL << OSTCBY; // OSTCBBitY = 0x01
OSTCBBitX = 1uL << OSTCBX; // OSTCBBitX = 0x05
OSRdyGrp |= OSTCBBitY ; // OSRdyGrp = 0x01 (00000001)
OSRdyTbl[OSTCBY] |= OSTCBBitX; // OSRdyTbl[0] = 00100000
查找优先级最高的就绪任务时
无需遍历,查表即可获得最高就绪优先级,速度MAX。
/* ********************************************************************************************************* * PRIORITY RESOLUTION TABLE * * Note: Index into table is bit pattern to resolve highest priority * Indexed value corresponds to highest priority bit position (i.e. 0..7) ********************************************************************************************************* */ INT8U const OSUnMapTbl[256] = { 0u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x00 to 0x0F */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x10 to 0x1F */ 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x20 to 0x2F */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x30 to 0x3F */ 6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x40 to 0x4F */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x50 to 0x5F */ 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x60 to 0x6F */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x70 to 0x7F */ 7u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x80 to 0x8F */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x90 to 0x9F */ 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xA0 to 0xAF */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xB0 to 0xBF */ 6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xC0 to 0xCF */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xD0 to 0xDF */ 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xE0 to 0xEF */ 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u /* 0xF0 to 0xFF */ };
void OSStart (void)
{
if (OSRunning == OS_FALSE) {
OS_SchedNew(); /* Find highest priority's task priority number */
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run */
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy(); /* Execute target specific code to start task */
}
}
;******************************************************************************************************** ; START MULTITASKING ; void OSStartHighRdy(void) ; ; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause ; the first task to start. ; ; 2) OSStartHighRdy() MUST: ; a) Setup PendSV exception priority to lowest; ; b) Set initial PSP to 0, to tell context switcher this is first run; ; c) Set the main stack to OS_CPU_ExceptStkBase ; d) Set OSRunning to TRUE; ; e) Trigger PendSV exception; ; f) Enable interrupts (tasks will run with interrupts enabled). ;******************************************************************************************************** OSStartHighRdy ; 设置PendSV中断优先级 LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority LDR R1, =NVIC_PENDSV_PRI STRB R1, [R0] ; 初始化PSP=0 MOVS R0, #0 ; Set the PSP to 0 for initial context switch call MSR PSP, R0 ; 初始化MSP地址,MSP=OS_CPU_ExceptStkBase LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase LDR R1, [R0] MSR MSP, R1 ;OSRunning = 1 表示系统开始运行 LDR R0, =OSRunning ; OSRunning = TRUE MOVS R1, #1 STRB R1, [R0] ;触发PendSV异常 (进入上下文切换) LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] ; 打开中断 CPSIE I ; Enable interrupts at processor level OSStartHang B OSStartHang ; Should never get here
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。