赞
踩
问题:
FreeRTOS启动调度器的时候,会调用void vTaskStartScheduler(void);
void vTaskStartScheduler(void)
{
pxCurrentTCB = &Task1TCB; //手动指定第一个运行的任务
if(xPortStartScheduler() != pdFALSE) //启动调度
{
//调度后不会进入这里
}
}
其中调用了BaseType_t xPortStartScheduler(void);
BaseType_t xPortStartScheduler(void)
{
//配置PendSV和SysTick中断优先级最低
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
protNVIC_SYSPRI2_REG |= portVNIC_SYSTICK_PRI;
prvStartFirstTask(); //启动第一个任务,不再返回
return 0; //不会执行该行
}
其中又调用了_asm void prvStartFirstTask(void);
_asm void prvStartFirstTask(void) //_ASM为C中内嵌汇编的前缀声明
{
PRESERVE8 //8字节对齐
ldr r0, =0xE0000ED08 //加载SCB_VTOR寄存器地址到R0
ldr r0, [r0] //加载SCB_VTOR寄存器的值:0x00000000
ldr r0, [r0] //加载0X00000000地址上的内容,为向量表的起始地址即MSP的值
msr msp, r0 //R0存入MSP
cpsie i //开启中断
cpsie f //开启异常
dsb
isb
svc 0 //调用SVC
nop
nop
}
可以看到在第12行执行了一句:SVC 0,即产生一次SVC系统调用, 服务号0表示SVC中断。
随后执行SVC中断服务函数_ASM void vPortSVCHandler(void);
__asm void vPortSVCHandler(void)
{
extern pxCurrentTCB //外部变量
PRESERVE8 //8字节对齐
ldr r3, pxCurrentTCB //加载TCB指针的地址
ldr r1, [r3] //加载TCB指针
ldr r0, [r1] //加载TCB指向的任务块到R0,任务快的第一成员是栈顶指针,下图1
ldmia r0!, {r4-r11} //将R0指向的值依次赋给{R4~R11}并自增地址
msr psp, r0 //寄存器R4~R11加载完后,将此时R0的值赋给PSP 下图2
isb
mov r0, #0 //R0 = 0
msr basepri, r0 //BASEPRI = 0 不屏蔽任何中断
orr r14, #0xd //R14|=0X0D使得硬件在退出时使用PSP完成出栈操作并返回后进入任务模式Thumb状态,在SVC中断服务里面使用的是MSP,ARM状态
bx r14 //异常返回,由于上一句指令切换到PSP,返回时会自动出栈。因此PSP指针自动将栈中剩下的内容加载到CPU寄存器:xPSR, PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务形参)。出栈操作完成后,PSP指向任务栈的栈顶。 下图3
}
图1:
图2:
图3:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。