FreeRTOS学习第3篇--任务栈使用与理解


FreeRTOS学习第3篇–任务栈使用与理解

FreeRTOS中的栈

FreeRTOS是一个可剥夺型的多任务内核,它可以管理多个任务,每个任务都是一个独立的程序,通常是一个死循环。

FreeRTOS的内核负责管理所有的任务,内核决定了运行哪个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。

为了实现多任务管理,FreeRTOS需要保存每个任务的上下文信息,即任务运行时的状态,包括寄存器值、局部变量等。这些信息就存储在栈中。

在FreeRTOS中,每个任务都有自己的栈空间,这样可以实现任务的切换和恢复。当内核切换任务时,它会先保存当前任务的上下文信息到当前任务的栈中,然后从即将运行的任务的栈中恢复该任务的上下文信息,最后跳转到该任务的执行地址。

FreeRTOS支持两种栈模式:静态栈和动态栈。静态栈是在编译时就分配好的固定大小的栈空间,动态栈是在运行时根据需要分配的可变大小的栈空间。静态栈的优点是节省内存,缺点是不灵活;动态栈的优点是灵活,缺点是可能产生内存碎片。

如何确定栈大小

栈大小确定的问题在实际中都比较麻烦,而且栈使用不够动不动就进入HardFault_Handler错误,挺烦的。那么有没有简单的办法来计算呢?有的,一般 IDE 开发环境都有这样的功能,比如 MDK 会生成一个 htm 文件,通过这个文件用户可以知道每个被调用函数的最大栈需求以及各个函数之间的调用关系。但是 MDK 无法确定通过函数指针实现函数调用时的栈需求。另外,发生中断或中断嵌套时的现场保护需要的栈空间也不会统计。

简单例子:确认任务的栈大小

ColorLED_Test任务中的源码

void ColorLED_Test(void * pvParameters)
{
    uint32_t color = 0;

    ColorLED_Init();

    while (1)
    {
        //LCD_PrintString(0, 0, "Show Color: ");
        //LCD_PrintHex(0, 2, color, 1);
        
        ColorLED_Set(color);

        color += 200000;
        color &= 0x00ffffff;
        mdelay(1000);
    }    
}

在我的这个任务中,分配的任务和栈情况如下:

static StackType_t g_pucStackOfColorTask[128];
static StaticTask_t g_TCBofColorTask;
static TaskHandle_t xColorTaskHandle;
xColorTaskHandle = xTaskCreateStatic(ColorLED_Test, "ColorTask", 128, NULL,osPriorityNormal, g_pucStackOfColorTask, &g_TCBofColorTask);

那么查看ColorLED_Test所使用的最大栈深度,查看编译出来的htm文件,

在这里插入图片描述

在htm文件中寻找对应的函数发现有Max Depth关键词,根据这个参考情况,也就说我的ColorLED_Test这个函数最大的栈深度是148字节。

在这里插入图片描述

实际分配我们分配栈大小时可以在最小栈需求的基础上乘以一个安全系数,一般取 1.5-2。

栈任务大小实践

那么基于以上的分析,我进行了实验,更改任务的栈情况:

static StackType_t g_pucStackOfColorTask[36];
static StaticTask_t g_TCBofColorTask;
static TaskHandle_t xColorTaskHandle;
 xColorTaskHandle = xTaskCreateStatic(ColorLED_Test, "ColorTask", 36, NULL, osPriorityNormal, g_pucStackOfColorTask, &g_TCBofColorTask);

工程中跑的任务有三个如下:

在这里插入图片描述

我工程中找到对应的map文件中查找任务使用的栈地址如下:

在这里插入图片描述

查看栈的内存情况

在这里插入图片描述

实验发现,因为我ColorLED_Test函数这个函数的栈大小比较极限,我给了36*4=144字节,比编译出来的148字节小一点点,程序起初运行时各项任务的功能都正常的,随着时间的运行,大概跑了几分钟,我的其他任务功能出现了异常,已经不稳定了,但是系统现在还没死机,因为我发现ColorLED_Test能够正常运行,当我改回148字节的任务时,时间久了也一样出现问题,所以在最小需要的栈基础上乘以一个安全系数(1.5-2之间)更为保险。

总结

通过本次的工程实践,为分配任务时的栈大小情况积攒下经验,为以后更加复杂的编程积累工程经验。

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS中的任务是指用于保存任务执行上下文信息的内存区域。任务通常位于芯片的RAM中。在FreeRTOS中,任务的大小可以通过配置文件或任务创建函数来确定。任务的大小要足够容纳任务执行所需的变量和函数调用的帧信息。 在FreeRTOS中,任务创建函数中的参数值是以字为单位的。而uxTaskGetStackHighWaterMark()函数返回的值也是以字为单位的。因此,需要将这些字节大小的值转换为实际的字节大小。任务的大小应该根据任务的需求和RAM的可用空间来确定。 需要注意的是,在uC/OS-II中,没有类似FreeRTOS中的configTOTAL_HEAP_SIZE这样的大堆需要配置。在uC/OS-II中,任务是静态分配的,没有动态的内存管理,也没有类似malloc()和free()这样的内存管理函数。因此,在uC/OS-II中不存在由于频繁的内存管理导致的内存碎片问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [freertos与STM32分析、堆、全局区、常量区、代码区、RAM、ROM,及如何分配堆空间](https://blog.csdn.net/qq6738966/article/details/118441134)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [FreeRTOS任务内存分配](https://blog.csdn.net/weixin_47321452/article/details/121691339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独处东汉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值