嵌入式操作系统 uCOS-II 堆栈溢出检测

只是篇随笔。

今天在测试自己修改后的SCI模块的时候发生了很奇怪的事情,很简单的三个任务互斥地往SCI口发送数据:

static void SCI0Task(void *p_arg){
   char str[] = "This is from Lin.\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,250);
    }
}
static void SCI0Task1(void *p_arg){
    char str[] = "This is from mama.\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,300);
    }
}
static void SCI0Task2(void *p_arg){
 char str[] = "This is from dogssssssssssssssss\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,333);
    }
}

正常情况下应该出现:

可实际输出却成了:

折腾了一晚上,各种设断点观测点,发现RAM中存放字符串的地方被不知道什么东西动了,值经常变化,导致输出异常,百思不得其解。

一觉起来,突然灵光一闪,该不会是哪个任务的栈溢出了冲进了“mama”的那个栈了吧,以前从没考虑过这个问题,一直以为128的栈大小够用了。现在看来必须要认真考虑这个问题了。于是正好用之前碰巧看到的(http://blog.csdn.net/u012252959/article/details/73741130)堆栈检测的方法试了试。

结果发现,果然是栈爆掉了。

于是乎一切就合理了,因为Lin、mama、dogs三个任务的栈是从低到高连续分配的,而栈是从高到低使用的,于是dogs的栈用完了之后就冲进了mama的栈中,正好把其中的字符串给改掉了,然后就出现了如上现象。将dogs的栈改大了之后就一切正常了。然后来看下实际使用了多少栈空间。

一看吓一跳,居然dogs用了140的堆栈,其他两个也快爆掉了,这样是很不安全的,起码要留20%的堆栈以防万一。而且可以看到下图的堆栈量和上图的使用量不太一样。这是因为堆栈的使用涉及很多因素,各种函数嵌套、中断等都会占用堆栈,需要检测一段时间等其稳定了才能大概确定潜在的最大值。

另:没想到一个任务居然会占到这么大的堆栈,以前一直以为只用占到几十就差不多了。

具体的检测方法就不详述了,上面那篇博文里有写。我就直接把这段测试的代码贴上来吧。
记得把OS_TASK_STAT_STK_CHK_EN和OS_TASK_CREATE_EXT_EN都设为1。
基于MC9S12XEP100和uCOS-II的SCI的驱动在此http://blog.csdn.net/lin_strong/article/details/73662524

/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                               Framework
*
* By  : Lin Shijun
* Note: This is a framework for uCos-ii project with only S12CPU, none float, banked memory model.
*       You can use this framework with same modification as the start point of your project.
*       I've removed the os_probe module,since I thought it useless in most case.
*       This framework is adapted from the official release.
*********************************************************************************************************
*/

#include "includes.h"
#include "SCI_def.h"
#include <string.h>
/*
*********************************************************************************************************
*                                      STACK SPACE DECLARATION
*********************************************************************************************************
*/
static  OS_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];
static  OS_STK  Sci0TaskStk[SCI0_TASK_STK_SIZE];
static  OS_STK  Sci0Task1Stk[SCI0_TASK1_STK_SIZE];
static  OS_STK  Sci0Task2Stk[SCI0_TASK2_STK_SIZE];
static  OS_STK  StkCheckTaskStk[STK_CHECK_STK_SIZE];
/*
*********************************************************************************************************
*                                      TASK FUNCTION DECLARATION
*********************************************************************************************************
*/

static  void    AppTaskStart(void *p_arg);
static  void    SCI0Task(void *p_arg);
static  void    SCI0Task1(void *p_arg);
static  void    SCI0Task2(void *p_arg);
static  void    StkCheckTask(void *p_arg);
/*
*********************************************************************************************************
*                                      LOCAL  FUNCTION  DECLARE
*********************************************************************************************************
*/

// 初始化看门狗
static void INIT_COP(void);

/*
*********************************************************************************************************
*                                           MAIN FUNCTION
*********************************************************************************************************
*/
void main(void) {
    INT8U  err;    
    BSP_IntDisAll();                                                    /* Disable ALL interrupts to the interrupt controller       */
    OSInit();                                                           /* Initialize uC/OS-II                                      */

    err = OSTaskCreate(AppTaskStart,
                          NULL,
                          (OS_STK *)&AppTaskStartStk[APP_TASK_START_STK_SIZE - 1],
                          APP_TASK_START_PRIO);                     
    OSStart();
}

static void AppTaskStart (void *p_arg)
{
   INT8U data,err,i = 0;
   char buf[30];
    (void)p_arg;                                            /* Prevent compiler warning    */
    BSP_Init(); 
    SCI_Init(SCI0);
    SCI_EnableTrans(SCI0);
    SCI_EnableRxInt(SCI0);
    SCI_EnableRecv(SCI0);
    SCI_Init(SCI1);
    SCI_EnableTrans(SCI1);
    SCI_EnableRxInt(SCI1);
    SCI_EnableRecv(SCI1);
    SCI_BufferInit(); 
    err = OSTaskCreate(StkCheckTask,
                    NULL,
                    (OS_STK *)&StkCheckTaskStk[STK_CHECK_STK_SIZE - 1],
                    STK_CHECK_TASK_PRIO);   

    err = OSTaskCreateExt(SCI0Task,
                    NULL,
                    (OS_STK *)&Sci0TaskStk[SCI0_TASK_STK_SIZE - 1],
                    SCI0_TASK_PRIO,
                    SCI0_TASK_PRIO,
                    (OS_STK *)&Sci0TaskStk[0],
                    SCI0_TASK_STK_SIZE,
                    NULL,
                    OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);     
    err = OSTaskCreateExt(SCI0Task1,
                    NULL,
                    (OS_STK *)&Sci0Task1Stk[SCI0_TASK1_STK_SIZE - 1],
                    SCI0_TASK1_PRIO,
                    SCI0_TASK1_PRIO,
                    (OS_STK *)&Sci0Task1Stk[0],
                    SCI0_TASK1_STK_SIZE,
                    NULL,
                    OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);                       


    err = OSTaskCreateExt(SCI0Task2,
                    NULL,
                    (OS_STK *)&Sci0Task2Stk[SCI0_TASK2_STK_SIZE - 1],
                    SCI0_TASK2_PRIO,
                    SCI0_TASK2_PRIO,
                    (OS_STK *)&Sci0Task2Stk[0],
                    SCI0_TASK2_STK_SIZE,
                    NULL,
                    OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);     
    // 初始化看门狗
    // INIT_COP();
    while (DEF_TRUE) 
    {
       buf[i++] = data = SCI_GetCharB(SCI0,0,&err);
       if(data == '\n' || i >= 30){
          SCI_PutCharsB_Mutex(SCI0,buf,i,0);
          i = 0;
       }
    }

}

static void SCI0Task(void *p_arg){
   char str[] = "This is from Lin.\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,250);
    }
}
static void SCI0Task1(void *p_arg){
    char str[] = "This is from mama.\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,300);
    }
}
static void SCI0Task2(void *p_arg){
 char str[] = "This is from dogssssssssssssssss\r\n";
    while (DEF_TRUE) 
    {
       SCI_PutCharsB_Mutex(SCI0,str,(sizeof(str)/sizeof(str[0]) - 1),0);
       OSTimeDlyHMSM(0,0,0,333);
    }
}

// 检测堆栈用
static void StkCheckTask(void *p_arg){
  INT8U i;
   char str[40];
   OS_STK_DATA StackBytes;
   OSTimeDlyHMSM(0,0,1,0);
    while (DEF_TRUE) 
    {
       OSTaskStkChk(SCI0_TASK_PRIO,&StackBytes);
       i = sprintf(str,"Lin Free:%u,Used:%u\r\n",(INT16U)StackBytes.OSFree,(INT16U)StackBytes.OSUsed);
       SCI_PutCharsB_Mutex(SCI1,str,i,0);
       OSTaskStkChk(SCI0_TASK1_PRIO,&StackBytes);
       i = sprintf(str,"mama Free:%u,Used:%u\r\n",(INT16U)StackBytes.OSFree,(INT16U)StackBytes.OSUsed);
       SCI_PutCharsB_Mutex(SCI1,str,i,0);
       OSTaskStkChk(SCI0_TASK2_PRIO,&StackBytes);
       i = sprintf(str,"dogs Free:%u,Used:%u\r\n",(INT16U)StackBytes.OSFree,(INT16U)StackBytes.OSUsed);
       SCI_PutCharsB_Mutex(SCI1,str,i,0);
       OSTimeDlyHMSM(0,0,0,111);
    }
}
void INIT_COP(void)
{
  COPCTL = 0x07;     //设置看门狗复位间隔为1.048576s
}

猜你喜欢

转载自blog.csdn.net/lin_strong/article/details/79360166