基于stm32的简单多任务切换设计

系统数据:

1)当前的PID

2)所有的进程总数PAMOUNT

 

//多任务系统的初始化

1.  设置MSP值

2.  设置临时的PSP值(因为这段实际上只在启动定时器之前有效)

3.  设置CONTROL[1]=1(设置双堆栈),马上会自动切换到PSP上

4.  设置PID=0,设置PAMOUNT=0

5.  设置为进程信息表起始地址到PLIST(注意进程信息表是向上生长的)

6.  设置为进程堆栈分配的起始地址到PSTACK(堆栈是向下生长的)

//调用AddTask添加任务

1.      写入配置信息到任务表中(任务起始地址,堆栈地址(首次进行分配)xPSR等等)

a)        至于输入参数,就存放在任务的堆栈中

//启动任务切换

1.  设置SysTick定时器的详细配置(定时间,开中断)

2.  启动定时器

//进程的切换过程

1.      当中断触发时,硬件会按照下表自动进行寄存器的入栈(如果当响应异常时,当前的代码正在使用PSP,则压入PSP,即使用线程堆栈;否则压入MSP,使用主堆栈。一旦进入了服务例程,就将一直使用主堆栈),通常Systick中断都是在PSP的情况下发生的,所以数据压入PSP

基于stm32的简单多任务切换设计_第1张图片

2.      入栈完毕,将堆栈切换到MSP,开始执行SysTick服务程序:

a)        将当前的堆栈切换为MSP

b)        取得进程堆栈指针,将堆栈指针备份到PID备份区域

c)        将R4到R11存储到PID对应的程序堆栈区域

d)        开始执行程序计算下一个PID=PID+1>PAMOUNT?1: PID+1;

e)        读取下一个PID进程堆栈指针,并将堆栈中的备份恢复到到R4到R11寄存器中

f)         将下一个进程PID的堆栈地址(弹出r4-r11后的地址)写到psp中

g)        进行中断返回,同时这样会触发中断返回的硬件过程,硬件会将堆栈切换为PSP并将PSP的内容恢复到相应寄存器中

3.      出栈完毕,硬件自动清除NVIC寄存器

4.      现场恢复完毕,继续执行任务

 

//任务的退出

1.      在写入进程信息的时候,已经把lr寄存器的值设置成为了ExitTask函数的地址,所以,当函数退出之后,会自动执行收尾。

 

 

 

补充资料:

1.      关于堆栈

a)        堆栈是向下生长的

b)        堆栈指针总是指向最后被压入堆栈的数据

c)        只有在CONTROL[1]=1时,才会使用双堆栈

d)        因为 C M 3 使用的是向下生长的满栈,所以 MSP 的初始值必须是堆栈内存的末地址加1 。
举例来说,如果你的堆栈区域在 0x20007C00 ‐ 0x20007FFF 之间,那么 MSP 的初始值就必须是0 x 20008000。

e)        在handler模式下CONTROL[1]不可以写入1,但是可以读取PSP的值

f)         堆栈的地址指针会和4对齐,例如:向sp写入0x20006001或者0x20006002或者0x20006003时,会自动变成0x20006000,而写入0x20006004就是直接写入0x20006004

g)        堆栈总是指向最后一个元素的,当写入四个字节的字时,会先指针减去4,再进行入栈。当堆栈指针为sp=0x20006004时,写入一个字  0x12345678时,会在0x20006000字节、0x20006001字节、0x20006002字节、0x20006003字节分别写入0x78、0x56、0x34、0x12。要想执行类似的操作可以使用存储指令(例如str)将数据存到0x20006000单元,会达到相同的效果

 

你可能感兴趣的:(基于stm32的简单多任务切换设计)