Arm ContxM FreeRTOS MSP之间PSP相互切换"/>
Arm ContxM FreeRTOS MSP之间PSP相互切换
Arm ContxM FreeRTOS MSP之间PSP相互切换
代码从main()函数开始执行的时候,栈默认是MSP开始.当创建线程后从main函数切换到线程的时候,栈从MSP->PSP. 这个过程如下.
简单概况:
FreeRTOS 创建线程的时候,事先往堆栈中保存EXC_TURN值,然后做线程切换的时候,先把保存的EXC_TURN值反映到CPU寄存器,这样执行线程的时候就变成了PSP.也就是说线程的时候使用PSP是人为设置的.相反MSP是硬件自己完成的,比如当发生中断后,执行中断函数的时候硬件吧SP改成MSP.
然后把执行中断函数之前的SP状态保存成EXC_TURN,这样退出中断函数的时候可以知道需不需要转成PSP
图1: 中断函数中退出
图2: 中断发生过程与说明
详细流程:
1. FreeRTOS 中创建线程的时候,堆栈中保存EXC_TURN
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{//创建线程的时候,先填充栈数据//填充:xPSR 值pxTopOfStack--;*pxTopOfStack = portINITIAL_XPSR; /* xPSR *///填充:PC 值(线程入口的函数地址)pxTopOfStack--;*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC *///填充:LR 值pxTopOfStack--;*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR *///保留 R12, R3, R2 R1寄存器的地方pxTopOfStack -= 5; /* R12, R3, R2 and R1. *///填充:R0 线程入口函数的 参数.*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 *///填充:EXC_TURN. (0xFFFF_FFFD(即返回异常时进入线程模式,使用PSP堆栈)pxTopOfStack--;*pxTopOfStack = portINITIAL_EXC_RETURN; //#define portINITIAL_EXC_RETURN( 0xfffffffd )//保留 R11, R10, R9, R8, R7, R6, R5 R4寄存器的地方pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */return pxTopOfStack;
}
1.1 EXC_RETURN 说明
根据Cortex-M3的异常处理流程,当发生异常时,CPU先将核心寄存器压入当前堆栈(如果当前是线程模式,则压入PSP堆栈,如果当前是Handler模式,则压入MSP堆栈),然后CPU会将LR设置为一个特殊的值,比如0xFFFFFFFD,然后切换到Handler模式,切换成MSP堆栈,最后进入异常处理例程(异常处理例程总是使用MSP堆栈)。在异常处理例程完成后需要从中断返回时,就将LR的值载入到PC中(通常是BX LR指令,也可以是MOV PC,LR指令,或者POP {…, PC}等指令,只要能将LR赋给PC即可),由于LR的值是0xFFFFFFFD,CPU检测到向PC中载入的是这个特殊值时,就知道是中断返回,于是做中断返回的动作(与压入动作相反:从堆栈中弹出核心寄存器的值,恢复到线程模式或Handler模式等)。
这里这个特殊的值(0xFFFFFFFD)就是EXC_RETURN,它的特点是高28位全部是1,只有低4位可变化,不同的低4位表示不同的中断返回动作。
2.步骤如下
1.从函数main()开始.这个时候默认是MSP
2 . 启动线程前,根据线程中预存的数据重新设置寄存器.
执行汇编"svc 0" -> 应的中断函数
__asm void vPortSVCHandler( void )
{PRESERVE8/* 当前线程的TCB地址 */ldr r3, =pxCurrentTCB//获取具体的当前线程地址ldr r1, [r3]//TCB中的第一个数据是 线程堆栈的地址.ldr r0, [r1]//从线程堆栈中 Pop 数据 //r14:portINITIAL_EXC_RETURN( 0xfffffffd )ldmia r0!, {r4-r11, r14}//获取当前的堆栈位置,设置成PSPmsr psp, r0isbmov r0, #0msr basepri, r0//执行 bx 0xfffffffd 的结果就是,把SP切换到PSP.bx r14
}
3.过上面的函数,已经重新设置了SP, 且退出的时候还会把存储的R0~R3, R12, R14, 返回地址(PC)、xPSR 恢复给寄存器.
4.执行线程的代码,除非线程结束,不然不会再继续main()函数
更多推荐
Arm ContxM FreeRTOS MSP之间PSP相互切换
发布评论