FreeRTOS 的任务栈设置
不管是裸机编程还是 RTOS 编程,栈的分配大小都非常重要。 局部变量,函数调用时的现场保护和返
回地址,函数的形参,进入中断函数前和中断嵌套等都需要栈空间,栈空间定义小了会造成系统崩溃。
裸机的情况下,用户可以在这里配置栈大小:
为什么是堆中的?因为我们采用的就是动态创建任务的方式。如果静态创建,就和我们自己开辟的空间有关,通常静态创建任务用数组作为容器,但是通常静态创建的方式我们都不使用。
FreeRTOS 的系统栈设置
上面跟大家讲解了什么是任务栈,这里的系统栈又是什么呢?裸机的情况下,凡是用到栈空间的地方
都是在这里配置的栈空间:
在 RTOS 下,上面两个截图中设置的栈大小有了一个新的名字叫系统栈空间,而任务栈是不使用这里的空间的。 任务栈不使用这里的栈空间,哪里使用这里的栈空间呢?答案就在中断函数和中断嵌套。
? 由于 Cortex-M3 和 M4 内核具有双堆栈指针,MSP 主堆栈指针和 PSP 进程堆栈指针,或者叫 PSP
任务堆栈指针也是可以的。在 FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的,进
程堆栈指针 PSP 是给任务栈使用的。 也就是说,在 FreeRTOS 任务中,所有栈空间的使用都是通过
PSP 指针进行指向的。 一旦进入了中断函数以及可能发生的中断嵌套都是用的 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 个浮点寄存器是自动入栈的,
这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系
统栈)
FreeRTOS 的任务状态
FreeRTOS 的运行支持以下四种状态:
? Running—运行态
当任务处于实际运行状态被称之为运行态,即 CPU 的使用权被这个任务占用。
? Ready—就绪态
处于就绪态的任务是指那些能够运行(没有被阻塞和挂起) ,但是当前没有运行的任务,因为同优先
级或更高优先级的任务正在运行。
? Blocked—阻塞态
由于等待信号量,消息队列,事件标志组等而处于的状态被称之为阻塞态,另外任务调用延迟函数也
会处于阻塞态。
? Suspended—挂起态
类似阻塞态,通过调用函数 vTaskSuspend()对指定任务进行挂起,挂起后这个任务将不被执行,只
有调用函数 xTaskResume()才可以将这个任务从挂起态恢复。
使用如下函数即可启动 FreeRTOS:
? vTaskStartScheduler();
函数原型:
void vTaskStartScheduler( void );
函数描述:
函数 vTaskStartScheduler 用于启动 FreeRTOS 调度器,即启动 FreeRTOS 的多任务执行。
使用这个函数要注意以下几个问题:
1. 空闲任务和可选的定时器任务是在调用这个函数后自动创建的。
2. 正常情况下这个函数是不会返回的,运行到这里极有可能是用于定时器任务或者空闲任务的 heap 空
间不足造成创建失败,此时需要加大 FreeRTOSConfig.h 文件中定义的 heap 大小:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
FreeRTOS 的任务恢复
使用如下函数可以实现 FreeRTOS 的任务恢复:
? xTaskResume()
使用如下函数可以实现 FreeRTOS 的任务恢复(中断方式):
? xTaskResumeFromISR()
未完待续。。。