前言
本篇文章将带大家学习在FreeRTOS中怎么样去确认栈的大小,在确认栈的大小后就可以根据实际情况来分配栈空间,防止栈空间被浪费。
反汇编文件分析
首先我们来看一下什么是汇编文件,什么是反汇编文件:
汇编文件 (.s 文件):
定义:在嵌入式系统中,汇编文件通常是指包含汇编语言代码的文本文件,其中的指令和数据使用特定的汇编语法表示。这些文件以 .s 作为文件扩展名。
作用:汇编文件用于编写底层的系统级代码,通常包括中断服务程序、启动代码、设备驱动程序等。它们直接与硬件交互,并对系统资源进行管理。
例如,一个嵌入式系统的汇编文件可能包含了与硬件设备通信的指令,如对寄存器的读写、对外设的控制等。
我们会通过keil5来生成反汇编文件来查看如何估算栈的大小:
使用下面这句话可以将.axf文件生成.dis文件:
fromelf --text -a -c --output=xxx.dis xxx.axf
–text:这个选项告诉 fromelf 工具将输出的内容以文本形式显示。这意味着输出将以可读的文本格式呈现,而不是二进制格式。
-a:这个选项告诉 fromelf 工具生成汇编伪指令(assembly pseudo-instructions)。这样生成的反汇编文件将包含一些更易读的汇编指令,而不是完全的机器码。
-c:这个选项告诉 fromelf 工具在输出时显示注释。注释通常包含有关代码和数据的信息,有助于理解反汇编输出。
–output=xxx.dis:这个选项指定了输出文件的名称,其中 xxx.dis 是你希望生成的反汇编文件的文件名。反汇编文件将被写入到这个文件中。
xxx.axf:这是输入的 ARM 可执行文件(.axf 文件)的名称。fromelf 将会对这个文件执行反汇编操作,并根据指定的参数生成相应的输出文件。
生成的反汇编文件如图所示:
图中函数a调用了函数b和c,并将对应的寄存器进行入栈和出栈处理。
任务栈和系统栈的区分
任务栈不使用系统栈空间,中断函数和中断嵌套使用系统栈空间.
- 在 FreeRTOS情况下,在KEIL中设置的栈大小有了一个新的名字叫系统栈空间(在FreeRTOS情况下,任务栈是不使用这里的空间的,任务栈使用的是FreeRTOSConfig.h文件中定义的HEAP空间)。
- 由于Cortex-M3 和 M4 内核具有双堆栈指针,MSP 主堆栈指针和 PSP 进程堆栈指针,或者叫 PSP任务堆栈指针也是可以的。在FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的,进程堆栈指针 PSP 是给任务栈使用的。也就是说,在FreeRTOS 任务中,所有任务栈空间的使用都是通过PSP 指针进行指向的。中断服务函数以及可能发生的中断嵌套都是用的 MSP指针。这个知识点要记住它。
任务栈大小的确定
在基于 RTOS 的应用设计中,每个任务都需要自己的栈空间,应用不同,每个任务需要的栈大小也是不同的。将如下的几个选项简单的累加就可以得到一个粗略的栈大小:
- 函数局部变量。
包含每个嵌套调用的局部变量(结构体,数组,字符等) - 函数的嵌套调用
- 函数形参,一般情况下函数的形参是直接使用的 CPU 寄存器,不需要使用栈空间,但是这个函数中如果还嵌套了一个函数的话,这个存储了函数形参的 CPU 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。
- 函数返回地址,针对 M3 和 M4 内核的 MCU,一般函数的返回地址是专门保存到 LR(LinkRegister)寄存器里面的,如果这个函数里面还调用了一个函数的话,这个存储了函数返回地址的 LR 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。
- 函数内部的状态保存操作也需要额外的栈空间。
一般情况下每个函数最多保存R4-R11以及LR共9个寄存器,即9×4共36个字节)
- 任务的切换
- 任务切换时所有的寄存器都需要入栈,对于带 FPU 浮点处理单元的 M4 内核 MCU 来说, FPU 寄存器也是需要入栈的。- 对于 Cortex-M3 内核和未使用 FPU(浮点运算单元18个浮点寄存器)功能的 Cortex-M4 内核在发生中断时需要将 16 个通用寄存器全部入栈,每个寄存器占用 4 个字节,也就是 16*4 = 64 字节的空间。
- 进入中断以后使用的局部变量以及可能发生的中断嵌套都是用的系统栈,这点要注意。
- 最终计算结果:
任务切换64字节(如无浮点运算,有的话需要加上)+ 函数的嵌套层数×36(按最大的算)+局部变量。
参考文献:
链接: FreeRTOS 任务栈大小确定及其溢出检测方法【杂记】
链接: RTOS中如何确定使用栈的大小