Arm ContxM FreeRTOS MSP之间PSP相互切换

编程入门 行业动态 更新时间:2024-10-19 18:28:55

<a href=https://www.elefans.com/category/jswz/34/1766218.html style=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相互切换

本文发布于:2024-02-26 19:11:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1703570.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:ContxM   Arm   FreeRTOS   PSP   MSP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!