[uCOS/RTOS]uC/OS-II中的任务堆栈大小检测

 在uC/OS-II系统中,创建任务的时候除了需要配置任务的优先级以外,还需要对任务堆栈大小进行分配。而对于单片机这种RAM并不是非常大的微控制器来说,RAM显得格外珍贵,如果任务堆栈分配大了,会导致RAM不够用,分配小了任务运行又会受到影响,甚至系统的崩溃,所以在创建任务的时候合适的堆栈大小分配很重要。

  uC/OS-II中任务堆栈的作用主要有两个,一是在任务运行的时候保存任务的一些局部变量,二是当任务挂起时,保存任务现场,也就是CPU寄存器的值。uC/OS-II系统是在OSTaskCreate();中的OSTaskStkInit();来确定堆栈地址的。虽然任务堆栈大小也可以通过设计者认为去测算出来,但是要考虑的东西太多,而且也不能十分精确。

  实际上uC/OS-II在OS_TASK.C中提供了很多有关任务管理的功能函数,包括:
建立任务OSTaskCreate()、建立扩展任务OSTaskCreateExt()、删除任务OSTaskDel()等,其中还有一个关于堆栈的函数就是堆栈检验OSTaskStkChk(),这个函数的检测原理就是顺着堆栈的栈底开始计算空闲的堆栈空间大小,实现方法是统计存储值为0的连续堆栈入口的数量,直到发现存储值不为0的堆栈入口,这样就可以知道实际占用的堆栈大小了。
  该函数的调用和运行需要将OS_TASK_STAT_STK_CHK_EN和OS_TASK_CREATE_EXT_EN进行使能,而检测的任务对象是通过任务的优先级来获取的,即:INT8U  prio,并且需要定义一个OS_STK_DATA的结构体变量来存放堆栈情况的值,
其中的:
INT32U  OSFree    就是剩余的堆栈大小
INT32U  OSUsed    是已经使用的堆栈大小。
OSTaskStkChk()源码:
INT8U  OSTaskStkChk (INT8U         prio,

                     OS_STK_DATA  *p_stk_data)

{

    OS_TCB    *ptcb;

    OS_STK    *pchk;

    INT32U     nfree;

    INT32U     size;

#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */

    OS_CPU_SR  cpu_sr = 0u;

#endif







#if OS_ARG_CHK_EN > 0u

    if (prio > OS_LOWEST_PRIO) {                       /* Make sure task priority is valid             */

        if (prio != OS_PRIO_SELF) {

            return (OS_ERR_PRIO_INVALID);

        }

    }

    if (p_stk_data == (OS_STK_DATA *)0) {              /* Validate 'p_stk_data'                        */

        return (OS_ERR_PDATA_NULL);

    }

#endif

    p_stk_data->OSFree = 0u;                           /* Assume failure, set to 0 size                */

    p_stk_data->OSUsed = 0u;

    OS_ENTER_CRITICAL();

    if (prio == OS_PRIO_SELF) {                        /* See if check for SELF                        */

        prio = OSTCBCur->OSTCBPrio;

    }

    ptcb = OSTCBPrioTbl[prio];

    if (ptcb == (OS_TCB *)0) {                         /* Make sure task exist                         */

        OS_EXIT_CRITICAL();

        return (OS_ERR_TASK_NOT_EXIST);

    }

    if (ptcb == OS_TCB_RESERVED) {

        OS_EXIT_CRITICAL();

        return (OS_ERR_TASK_NOT_EXIST);

    }

    if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0u) { /* Make sure stack checking option is set      */

        OS_EXIT_CRITICAL();

        return (OS_ERR_TASK_OPT);

    }

    nfree = 0u;

    size  = ptcb->OSTCBStkSize;

    pchk  = ptcb->OSTCBStkBottom;

    OS_EXIT_CRITICAL();

#if OS_STK_GROWTH == 1u

    while (*pchk++ == (OS_STK)0) {                    /* Compute the number of zero entries on the stk */

        nfree++;

    }

#else

    while (*pchk-- == (OS_STK)0) {

        nfree++;

    }

#endif

    p_stk_data->OSFree = nfree * sizeof(OS_STK);          /* Compute number of free bytes on the stack */

    p_stk_data->OSUsed = (size - nfree) * sizeof(OS_STK); /* Compute number of bytes used on the stack */

    return (OS_ERR_NONE);

}

  对于需要检测的目标任务来说,需要采用OSTaskCreateExt()扩展任务来创建的,区别与普通的OSTaskCreate();函数,创建扩展任务不仅需要指定堆栈的底指针,还指定了堆栈的容量,这个容量值就是用来检验使用的,而该函数的最后一个参数opt 填入OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR即可。
OSTaskCreateExt ()源码:
INT8U  OSTaskCreateExt (void   (*task)(void *p_arg),

                        void    *p_arg,

                        OS_STK  *ptos,

                        INT8U    prio,

                        INT16U   id,

                        OS_STK  *pbos,

                        INT32U   stk_size,

                        void    *pext,

                        INT16U   opt)

{

    OS_STK    *psp;

    INT8U      err;

#if OS_CRITICAL_METHOD == 3u                 /* Allocate storage for CPU status register               */

    OS_CPU_SR  cpu_sr = 0u;

#endif







#ifdef OS_SAFETY_CRITICAL_IEC61508

    if (OSSafetyCriticalStartFlag == OS_TRUE) {

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif



#if OS_ARG_CHK_EN > 0u

    if (prio > OS_LOWEST_PRIO) {             /* Make sure priority is within allowable range           */

        return (OS_ERR_PRIO_INVALID);

    }

#endif

    OS_ENTER_CRITICAL();

    if (OSIntNesting > 0u) {                 /* Make sure we don't create the task from within an ISR  */

        OS_EXIT_CRITICAL();

        return (OS_ERR_TASK_CREATE_ISR);

    }

    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */

        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  */

                                             /* ... the same thing until task is created.              */

        OS_EXIT_CRITICAL();



#if (OS_TASK_STAT_STK_CHK_EN > 0u)

        OS_TaskStkClr(pbos, stk_size, opt);                    /* Clear the task stack (if needed)     */

#endif



        psp = OSTaskStkInit(task, p_arg, ptos, opt);           /* Initialize the task's stack          */

        err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt);

        if (err == OS_ERR_NONE) {

            if (OSRunning == OS_TRUE) {                        /* Find HPT if multitasking has started */

                OS_Sched();

            }

        } else {

            OS_ENTER_CRITICAL();

            OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* Make this priority avail. to others  */

            OS_EXIT_CRITICAL();

        }

        return (err);

    }

    OS_EXIT_CRITICAL();

    return (OS_ERR_PRIO_EXIST);

}
  这就是uC/OS-II自带检验任务堆栈大小的方法,但是由于任务运行受实际产品使用状态等很多方面的影响,必须在任务最大运行负载的情况下所测出来的使用率才是最可靠的,一般为了防止堆栈过小,在RAM空间够用的时候,建议最后可以将实际测出来的大小*2进行堆栈分配。
---------------------
作者:forgot
链接:https://bbs.21ic.com/icview-3285474-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值