FreeRTOS 任务栈
FreeRTOS不同于裸机,每个TASK都有一个任务栈。FreeRTOS的任务栈是在任务创建的时候从FreeRTOSConfig.h 定义的Heap 空间中申请:
#define configTOTAL_HEAP_SIZE ((size_t)1024 * 9)
注意:使用xTaskCreate()接口,这种创建方式是动态创建栈的方式,所以会放在Heap 空间中申请。
在创建任务栈的过程中,FreeRTOS 会切换 arm 的栈指针,将栈指针切换到PSP,通过将Control [1] 置 1实现
FreeRTOS 中每个任务都需要自己的栈空间,栈空间的大小需要考虑如下几个方面:
- 函数的嵌套调用:
- 函数局部变量。
- 函数形参,一般情况下函数的形参是直接使用的 CPU 寄存器,不需要使用栈空间,但是这个函数中如果还嵌套了一个函数的话,这个存储了函数形参的
CPU 寄存器内容是要入栈的。 - 函数返回地址,arm中一般函数的返回地址是专门保存到
LR(LinkRegister)寄存器中的,如果这个函数里面还调用了一个函数的话,这个存储了函数返回地址的 LR 寄存器内容是要入栈的。 - 函数内部的状态保存操作也需要额外的栈空间。
- 任务切换,任务切换时所有的寄存器都需要入栈。
- ARM 在任务执行过程中,如果发生中断: M3 内核的 MCU 有 8个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈。
- M4 内核的 MCU 有 8 个通用寄存器和 18
个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈。
注意:进入中断以后使用的局部变量以及可能发生的中断嵌套都是用的系统栈。进入中断后系统会自动将栈指针切换到MSP,退出中断后再切回PSP。
注意:进入中断以后使用的局部变量以及可能发生的中断嵌套都是用的系统栈。进入中断后系统会自动将栈指针切换到MSP,退出中断后再切回PSP。
FreeRTOS系统栈
arm M3 内核是具有双堆栈指针,MSP 主堆栈指针和 PSP 进程堆栈指针(PSP任务堆栈指针)
在 FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的,进程堆栈指针 PSP 是给任务栈使用的。 也就是说,在 FreeRTOS 任务中,所有栈空间的使用都是通过PSP 指针进行指向的。 一旦进入了中断函数以及可能发生的中断嵌套都是用的 MSP 指针。
实际应用中系统栈空间分配多大,主要是看可能发生的中断嵌套层数,下面我们就按照最坏执行情况进行考虑,所有的寄存器都需要入栈,此时分为两种情况:
(进入中断后,系统会自动将SP切到MSP)
64 字节
对于 Cortex-M3 内核和未使用 FPU(浮点运算单元)功能的 Cortex-M4 内核在发生中断时需要将 16 个通用寄存器全部入栈,每个寄存器占用 4 个字节,也就是 16*4 = 64 字节的空间。
可能发生几次中断嵌套就是要 64 乘以几即可。 当然,这种是最坏执行情况,也就是所有的寄存器都入栈。
(注:任务执行的过程中发生中断的话,有 8 个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈)
200 字节
对于具有 FPU(浮点运算单元)功能的 Cortex-M4 内核,如果在任务中进行了浮点运算,那么在发生中断的时候除了 16 个通用寄存器需要入栈,还有 34 个浮点寄存器也是要入栈的,也就是(16+34)*4 = 200 字节的空间。当然,这种是最坏执行情况,也就是所有的寄存器都入栈。
(注:任务执行的过程中发送中断的话,有 8 个通用寄存器和 18 个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈)