系统有两个任务切换函数
VOID osSchedule(VOID)
VOID LOS_Schedule(VOID)
两个函数最终切换调用的是用汇编编写的osTaskSchedule()函数,在移植的时候要根据不同的内核来修改
在COTEX-M3函数内核中用的是pendsv中断来切换任务。
osTaskSchedule
LDR R0, =OS_NVIC_INT_CTRL
LDR R1, =OS_NVIC_PENDSVSET
STR R1, [R0]
BX LR
这个函数就是直接操作寄存器触发pendsv异常
PendSV_Handler
MRS R12, PRIMASK
CPSID I
LDR R2, =g_pfnTskSwitchHook
LDR R2, [R2]
CBZ R2, TaskSwitch
PUSH {R12, LR}
BLX R2
POP {R12, LR}
异常直接调用TaskSwitch函数
TaskSwitch
MRS R0, PSP
STMFD R0!, {R4-R12}
VSTMDB R0!, {D8-D15}
LDR R5, =g_stLosTask
LDR R6, [R5]
STR R0, [R6]
LDRH R7, [R6 , #4]
MOV R8,#OS_TASK_STATUS_RUNNING
BIC R7, R7, R8
STRH R7, [R6 , #4]
LDR R0, =g_stLosTask
LDR R0, [R0, #4]
STR R0, [R5]
LDRH R7, [R0 , #4]
MOV R8, #OS_TASK_STATUS_RUNNING
ORR R7, R7, R8
STRH R7, [R0 , #4]
LDR R1, [R0]
VLDMIA R1!, {D8-D15}
LDMFD R1!, {R4-R12}
MSR PSP, R1
MSR PRIMASK, R12
BX LR
任务切换函数就是通过操作全局变量g_stLosTask,吧当前任务的寄存器入栈,其实就是存在任务控制块中pStackPointer指向的内存里面。然后把最新的就绪任务弹出来。这样就实现了任务切换。
typedef struct tagTaskCB
{
VOID *pStackPointer; /**< Task stack pointer */
UINT16 usTaskStatus;
UINT16 usPriority;
UINT32 uwStackSize; /**< Task stack size */
UINT32 uwTopOfStack; /**< Task stack top */
UINT32 uwTaskID; /**< Task ID */
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */
VOID *pTaskSem; /**< Task-held semaphore */
VOID *pThreadJoin; /**< pthread adaption */
VOID *pThreadJoinRetval; /**< pthread adaption */
VOID *pTaskMux; /**< Task-held mutex */
UINT32 auwArgs[4]; /**< Parameter, of which the maximum number is 4 */
CHAR *pcTaskName; /**< Task name */
LOS_DL_LIST stPendList;
LOS_DL_LIST stTimerList;
UINT32 uwIdxRollNum;
EVENT_CB_S uwEvent;
UINT32 uwEventMask; /**< Event mask */
UINT32 uwEventMode; /**< Event mode */
VOID *puwMsg; /**< Memory allocated to queues */
} LOS_TASK_CB;