函数中调用了 prvPortStartFirstTask 来启动第一个任务, 该函数重新初始化了系统的栈指针,表示 FreeRtos 开始接手平台的控制, 同时通过触发 SVC 系统调用,运行第一个任务。具体实现如下
static void prvPortStartFirstTask( void )
{
__asm volatile(
" ldr r0, =0xE000ED08 \n" /*向量表偏移寄存器地址 CotexM3*/
" ldr r0, [r0] \n" /*取向量表地址*/
" ldr r0, [r0] \n" /*取 MSP 初始值*/
/*重置msp指针 宣示 系统接管*/
" msr msp, r0 \n"
" cpsie i \n" /*开中断*/
" cpsie f \n" /*开异常*/
/*流水线相关*/
" dsb \n" /*数据同步隔离*/
" isb \n" /*指令同步隔离*/
/*触发异常 启动第一个任务*/
" svc 0 \n"
" nop \n"
);
}
前面创建任务的文章介绍过, 任务创建后, 对其栈进行了初始化,使其看起来和任务运行过后被系统中断切换了一样。 所以,为了启动第一个任务,触发 SVC 异常后,异常处理函数中直接执行现场恢复, 把 pxCurrentTCB "恢复"到运行状态。
(另外,Cotex-M3 具有三级流水线,所以切换任务的时候需要清除预取的指令,避免错误。)
对于 Cotex-M3 , 其代码实现如下,
void vPortSVCHandler( void )
{
__asm volatile (
/*取 pxCurrentTCB 的地址*/
"ldr r3, pxCurrentTCBConst2 \n"
/*取出 pxCurrentTCB 的值 : TCB 地址*/
"ldr r1, [r3] \n"
/*取出 TCB 第一项 : 任务的栈顶 */
"ldr r0, [r1] \n"
/*恢复寄存器数据*/
"ldmia r0!, {r4-r11} \n"
/*设置线程指针: 任务的栈指针*/
"msr psp, r0 \n"
/*流水线清洗*/
"isb \n"
"mov r0, #0 \n"
"msr basepri, r0 \n"
/*设置返回后进入线程模式*/
"orr r14, #0xd \n"
"bx r14 \n"
" \n"
".align 4 \n"
"pxCurrentTCBConst2: .word pxCurrentTCB \n"
);
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-33581-3.html
狠狠打击美国在全世界的利益
前9个月的CPI是1