OSTaskStkInit

Description

This function is called by OSTaskCreate() to setup the stack frame of the task being created. Typically, the stack frame will look as if an interrupt just occurred, and all CPU registers were pushed onto the task’s stack. The stacking order of CPU registers is very CPU specific.

OSTaskStkInit() is part of the CPU port code and this function must not be called by the application code. OSTaskStkInit() is actually defined by the µC/OS-III port developer.

Files

os.h/os_cpu_c.c

Prototype

CPU_STK  *OSTaskStkInit (OS_TASK_PTR    p_task,
                         void          *p_arg,
                         CPU_STK       *p_stk_base,
                         CPU_STK       *p_stk_limit,
                         CPU_STK_SIZE   stk_size,
                         OS_OPT         opt)

Arguments

p_task

is the address of the task being created (see MyTask() below). Tasks must be declared as follows:

          void   MyTask (void  *p_arg)
          {
              /* Do something with "p_arg" (optional) */
              while (DEF_ON) {
                  /* Wait for an event to occur */
                  /* Do some work               */
              }
          }

Or,

          void   MyTask (void  *p_arg)
          {
              OS_ERR  err;
           
           
              /* Do something with "p_arg" (optional) */
              /* Do some work                         */
              OSTaskDel((OS_TCB *)0,
                        &err);
          }

p_arg

is the argument that the task will receive when the task first start (see code above).

p_stk_base

is the base address of the task’s stack. This is typically the lowest address of the area of storage reserved for the task stack. In other words, if declaring the task’s stack as follows:

          CPU_STK  MyTaskStk[100];

OSTaskCreate() would pass &OSMyTaskStk[0] to p_stk_base.

p_stk_limit

is the address of the task’s stack limit watermark. This pointer is computed by OSTaskCreate() prior to calling OSTaskStkInit().

stk_size

is the size of the task’s stack in number of CPU_STK elements. In the example above, the stack size is 100.

opt

is the options passed to OSTaskCreate() for the task being created.

Returned Value

The new top of stack after the task’s stack is initialized. OSTaskStkInit() will place values on the task’s stack and will return the new pointer for the stack pointer for the task. The value returned is very processor specific. For some processors, the returned value will point to the last value placed on the stack while, with other processors, the returned value will point at the next free stack entry.

Required Configuration

None

Callers

OSTaskCreate().

Notes/Warnings

  1. Do not call this function from the application.

Example Usage

The pseudo code below shows the typical steps performed by this function. Consult an existing µC/OS-III port for examples. Here it is assumed that the stack grows from high memory to low memory.

OSTaskStkInit() example usage
          CPU_STK  *OSTaskStkInit (OS_TASK_PTR    p_task,
                                   void          *p_arg,
                                   CPU_STK       *p_stk_base,
                                   CPU_STK       *p_stk_limit,
                                   CPU_STK_SIZE   stk_size,
                                   OS_OPT         opt)
          {
              CPU_STK  *p_stk;
           
           
              p_stk    = &p_stk_base[stk_size - 1u];                            (1)
              *p_stk-- = Initialize the stack as if an interrupt just occurred; (2)
              return (p_stk);                                                   (3)
          }

(1) p_stk is set to the top-of-stack. It is assumed that the stack grows from high memory locations to lower ones. If the stack of the CPU grew from low memory locations to higher ones, the user would simply set p_stk to point at the base. However, this also means that it would be necessary to initialize the stack frame in the opposite direction.

(2) The CPU registers are stored onto the stack using the same stacking order as used when an interrupt service routine (ISR) saves the registers at the beginning of the ISR. The value of the register contents on the stack is typically not important. However, there are some values that are critical. Specifically, you need to place the address of the task in the proper location on the stack frame and it may be important to load the value of the CPU register and possibly pass the value of p_arg in one of the CPU registers. Finally, if the task is to return by mistake, it is a good idea to place the address of OS_TaskReturn() in the proper location on the stack frame. This ensures that a faulty returning task is intercepted by µC/OS-III.

(3) Finally, your code will need to return the value of the stack pointer at the new top-of-stack frame. Some processors point to the last stored location, while others point to the next empty location. You should consult the processor documentation so that the return value points at the proper location.

Below is an example showing which arguments OSTaskCreate() passes to OSTaskStkInit().

          CPU_STK  MyTaskStk[100];
          OS_TCB   MyTaskTCB;
           
           
          void  MyTask (void *p_arg)
          {
              /* Do something with "parg" (optional) */
          }
           
           
          void  main (void)
          {
              OS_ERR  err;
              :
              :
              OSInit(&err);
              /* Check "err" */
              :
              :
              OSTaskCreate ((OS_TCB        *)&MyTaskTCB,
                            (CPU_CHAR      *)"My Task",
                            (OS_TASK_PTR    )MyTask,                                        /* "p_task"      of OSTaskStkInit() */
                            (void          *)0,                                             /* "p_arg"       of OSTaskStkInit() */
                            (OS_PRIO        )prio,
                            (CPU_STK       *)&MyTaskStk[0],                                 /* "p_stk_base"  of OSTaskStkInit() */
                            (CPU_STK_SIZE   )10,                                            /* "p_stk_limit" of OSTaskStkInit() */
                            (CPU_STK_SIZE   )100,                                           /* "stk_size"    of OSTaskStkInit() */
                            (OS_MSG_QTY     )0,
                            (OS_TICK        )0,
                            (void          *)0,
                            (OS_OPT         )(OS_OPT_TASK_STK_CLR + OS_OPT_TASK_STK_CHK),   /* "opt"         of OSTaskStkInit() */
                            (OS_ERR        *)&err);
              /* Check "err" */
              :
              :
              OSStart(&err);
              /* Check "err" */
              :
              :
          }