UCOS-II 任务栈空间合理分配

最近利用空闲时间跑了一下正点原子的stm32f4开发板的实时操作系统demo,发现了一个比较有意思的东西,分享如下:

硬件平台:正点原子stm32f4开发板

软件开发平台:MDK uVision v5.14.0.0

代码:正点原子官方例程 实验56 UCOSII实验1-2-任务创建删除挂起恢复

需要了解的基础知识

  1、会点亮LED灯

  2、会读取按键输入

  3、会操作串口

  4、会RTOS基本知识

官方文档描述实验现象:首先下载代码之后可以看到 LED0 LED1 不断闪烁,同时蜂鸣器不
断鸣叫。这个时候我们按下 KEY0 之后 led_task 任务被挂起,我们可以看到 LED 不再闪烁。接
着我们按下 KEY2led_task 任务重新恢复,可以看到 LED 恢复闪烁。然后我们按下 KEY_UP
任务 beep_task 被删除,所以蜂鸣器不再鸣叫。这个时候我们再按下按键 KEY_DOWN,任务
beep_task 被重新创建,所以蜂鸣器恢复鸣叫。

一切工具准备就绪,烧录代码观察现象,神奇的bug出现了

首先,确实LED0 和 LED1 不断闪烁,但是一旦按下任意一个按键直接死机。

第一想法,分析代码,打印调试信息

 

 

 测试现象:果然,按下按键后,所有用户任务停止运行了,可以初步得出结论:程序跑飞了(由于本例程未初始化看门狗,所以程序跑飞,就飞不回来了)

第二想法:调试

 

 测试方法:进入调试模式后,run代码,点击stop,程序会停在正常的代码行,如停在用户代码区、内核代码区的正常逻辑区

 

进入调试模式后,run代码,按下按键,点击stop,会发现程序停在stm32f4xx_it.c这个文件的HardFault_Handler函数里,这是个死循环,就是这里导致程序跑飞了

cpu进入中断后一直执行死循环,回不来了,无法再进行任务切换了!可

 

 

 以在这个中断函数里追加printf("HardFault_Handler\r\n");以观察现象如下:

 

 串口助手打印的信息刚好验证了上述结论

整理思路如下:运行ucos ii 应用程序,按下按键后程序发生硬件错误,一般发生硬件错误,很可能就是跟内存有关,最典型的就是栈溢出了,

分析到这里,基本上排查bug就很easy了,检查代码各个任务栈大小发现:三个任务都是设置64字节,经过多次实验,发现只需把KEY_STK_SIZE设置

为大于64时,实验现象就正常了,说明再执行按键任务时,此任务堆栈大小超过64字节了。

#define KEY_TASK_PRIO       3 
#define KEY_STK_SIZE  	64
OS_STK KEY_TASK_STK[KEY_STK_SIZE];
void key_task(void *pdata); 

那么当我们在编写任务函数时,到底栈大小设置多少合适呢?我怎么知道新建的任务运行起来用了多少栈空间呢?

若栈空间设置过大,无疑会导致空间的浪费,这在嵌入式产品中简直就是极其浪费

若栈空间过小,那真运行起来,搞不好某个时间点,栈空间就溢出了,这个时间点可能是一触即发,可能会一年后,甚至10年后

经过一顿百度操作,发现ucosii 系统早都给你设计好了,通过下面的函数即可统计指定任务运行时用了多少栈空间,还剩多少栈空间

OSTaskCreateExt(key_task,(void *)0,(OS_STK *)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO, KEY_TASK_PRIO, KEY_TASK_STK, KEY_STK_SIZE, (void*)0,OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSTaskStkChk(KEY_TASK_PRIO, &StackBytes);
printf("%d\r\n", StackBytes.OSUsed); 

 这也只是一种估测栈空间使用量,测试时,得模拟各种极端条件,尽量让最大使用量测出来

最后,一般堆栈大小设置为任务实际使用量的1.5-2倍即可

具体原理,大家可自行百度理解,也可以自己尝试手撕一波栈空间检测算法(栈基地址----栈顶地址) 

 

posted @ 2022-05-12 22:57  念经似的zzz  阅读(1280)  评论(0编辑  收藏  举报