在freertos中PendSV 中断服务函数是真正实现任务切换的地方,任务切换的本质就是CPU寄存器的切换
基本流程:
触发PendSV中断 → 硬件自动保存R0-R3, R12, LR, PC, xPSR → 手动保存R4-R11, LR → 切换TCB → 恢复新任务寄存器 → 返回新任务
本文主要讲解在任务切换过程中是如何保存上一个任务的寄存器到栈
当进入xPortPendSVHandler的这个时刻,硬件此时已经就帮我们将xPSR, PC(任务入口地址), R14, R12, R3, R2, R1, R0自动压入栈中了。
在 FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的, 进程堆栈指针 PSP 是给任务栈使用的。
PSP的值为0x20001100,在memory窗口中查看,与右边cpu寄存器的值相同
这里需要注意的是在flash中数据是小端存储(在 小端模式 下,低地址存 低字节,高地址存 高字节),以R2为例,实际值为:0x2000 0350,在flash中是这样存储的”50 03 00 20”
余下的9个寄存器(r4~r11,r14)需要我们手动更新
执行为这一句后,R0的地址将由0x20001100->0x200010DC
即 (9*4)= 36 十六进制为0x24
0x1100-0x24 = 0x10DC
Debug可知R0变为0x200010DC 与预期相符
r4~r11和r14的值也一一对应相同
至此,上下文切换中的上文已全部压入栈中保存完成
另外:在debug过程中需要注意一下:将pxCurrentTCB添加到wathc窗口后,value栏的值不是pxCurrentTCB的地址;而是TCB结构体第一个变量的地址, pxTopOfStack的地址。
pxCurrentTCB的地址我们通过代码逻辑可知为R3,通过观察debug窗口可知为0x2000001C。
如果你直接 watch pxCurrentTCB,watch 窗口默认解引用它,显示的是 pxCurrentTCB 指向的 TCB_t 结构的 第一个成员。
TCB_t 的第一个成员是 pxTopOfStack,所以 watch 窗口会显示 pxTopOfStack 的值,而不是 pxCurrentTCB 本身的地址。
(这里有些绕,值得好好咂摸一下)