1.它们是什么?
它们是程序堆栈,一个主堆栈和一个进程堆栈,任何时候都只能有一个堆栈使用,可以在pendSV handler()中决定,改变他的sp指针类型并返回。
2.什么是堆栈?
程序运行时存放程序数据的一个区域,一般存放,程序状态寄存器,程序入口地址,链接寄存器R14地址,R12,R3,R2,R1,R0(参数),R11~R4。这是一个最简单的堆栈区。一般由R13(sp指针)决定。
举个例子:
//这段代码是在特权模式下才能执行的,用的是MSP,进程模式严禁操作硬件,只能通过系统异常来提交
// 改变硬件的操作。
、....
u32 task_stack[128];//一个任务堆栈
u32 *ptop=task_stack-127;//栈顶指针
ptop=(u32*) ptop&(~(u32)0x00000007)//栈顶对齐
....
ptop-=8;//指向task_stack[119];
....
_asm
psp=ptop;
isb;
orr r14,#0xd
bx r14//程序返回后会从msp切换到psp
...
//关于LR(R14),进入异常中断时系统会写入0xffffffff
//退出中断时检测到0xffffffff,系统就知道退出中断进入新模式。
//0xfffffff1:handler模式 0xfffffff9:返回线程模式,sp=msp 0xfffffffd:返回线程模式,sp=psp
这段代码执行会有那些操作呢?
它创建了一个栈,然后又有一个栈顶指针,当汇编指令执行完成后,sp(堆栈指针)从msp变成psp。他会执行一个很恐怖的事情,就是:
//这一段代码是伪代码,不需要人管,机器会自动执行,psp的出栈操作
...
_asm
mov r0,psp//指向task_stack[119]
psp++
mov r1,psp//指向task_stack[120]
psp++
mov r2,psp//指向task_stack[121]
psp++
mov r3,psp//指向task_stack[122]
psp++
mov r12,psp//指向task_stack[123]
psp++
mov r14,psp//指向task_stack[124]
psp++
mov pc,psp//指向task_stack[125]
psp++
mov xpsr,psp//指向task_stack[126]
psp++
...
//出栈是从下往上,入栈是从上往下,所以这个栈是向下生长的,入栈先减4,是为了地址对齐
就是相当于将堆栈中的数据给寄存器,然后程序照常运行。发现了吗?
程序会自动从堆栈区读取数据和保存数据,这些数据就是程序运行时所需要的所有的状态地址。只要我们更改psp和msp所指向的地址,就可以决定程序从那个地方开始运行。
3.程序运行读写堆栈是设备自动读取的。
4.freertos的堆栈区存储的是这些数据:
总结一下就是R0~R15和一个状态指针,知道点的都知道,汇编的所有操作就是这几个寄存器数据的变化,任何某一时刻这几个寄存器的数据都是特定的。保存它们到一个数组中,过一会拿出来放到相应寄存器,它们又可以继续运行。
这就是Cm3内核的bootloader和freertos的任务切换原理。psp和msp所指向的堆栈中也就是存着这几个数据。