Search code examples
crtos

What is Passing a parameter to stack in RTOS?


I'm a newbie to RTOS, 've around few months of experience on System side(Application side) programming in C/C++. But entering into this embedded domain, I'm stumbled by few questions.

What is meant by Passing a parameter to a task ? I didn't understand the below given example.

static void TaskEx(void* pData) {
    while (1) {
    OS_Delay ((OS_TIME) pData);
        }
}


void OS_CreateTask ( OS_TASK * pTask,char * pName,unsigned char Priority,voidRoutine * pRoutine,void * pStack,unsigned StackSize,unsigned char TimeSlice );

OS_CreateTask(&TaskMain, NULL, 50, TaskEx, StackMain, sizeof(StackMain), 2);

// ^ This is not passing a parameter is a task.

void OS_CreateTaskEx ( OS_TASK * pTask, char * pName, unsigned char Priority, voidRoutine *pRoutine, void * pStack, unsigned StackSize, unsigned char TimeSlice, void * pContext );

OS_CREATETASK_EX(&TCBLP, "LP Task", TaskEx, 50, StackLP, (void*) 200);

// ^ This is passing a parameter is a task.

  • I know to define a stack in normal C programming. But in RTOS, I didn't understand by stack that you define has to reside in an area that the CPU can actually use as stack?

Solution

  • It looks like you're using embOS - in that RTOS there are 2 general ways to start a task. One (the 'Ex' variant) will pass a void* parameter you specify in the API. The other way to start a task will not pass a parameter to your task.

    Since all you get to pass is a void* (if you chose that method), typically what will happen is you'll populate a structure with information for the task and pass a pointer to that structure as the parameter. This lets you do something like have a single task function that manages UART I/O, and pass a pointer to a structure that describes the I/O ports for a particular UART instance. That way the single function could, for example, handle all UARTs on your device by starting a separate task for each UART, passing a pointer to a different UART descriptor (and a different block of memory for the task's stack) to each.

    Confusingly, each of these mechanisms to start a task has 2 APIs:

    • a macro that automatically figures out the size of the stack area you're providing for the task (you had better pass an array name here, and not a pointer or it'll configure a stack that's far too small).
    • a non macro that you have to explicitly pass the stack size with

    In the small example you show, all the task does is delay repeatedly in an infinite loop. The delay is specified by the passed parameter (which is used as an int rather than as a pointer to a structure). So, you can start multiple tasks that each delay for different periods of time by passing a different delay timeout to each instance. Obviously not a useful bit of work, but it's intended to just demonstrate the technique.

    Some code using this example might look like:

    OS_TASK TCB_Task1;
    OS_TASK TCB_Task2;
    
    #define SHORT_DELAY 10
    #define LONG_DELAY 1000
    
    unsigned int task1_stack[64];
    unsigned int task2_stack[64];
    
    // start a task that delays only for 10ms
    OS_CreateTaskEx ( &TCB_Task1, "short delay", 20, &TaskEx,
         &task1_stack, sizeof(task1_stack), 2, (void*)SHORT_DELAY);
    
    // start a task (using same task function) that delays for 1000ms
    OS_CreateTaskEx ( &TCB_Task2, "long delay", 20, &TaskEx, 
         &task2_stack, sizeof(task2_stack), 2, (void*)LONG_DELAY);
    

    For your second question:

    I didn't understand by stack that you define has to reside in an area that the CPU can actually use as stack?

    All that is meant by this is that some microcontrollers have different memory ranges that might have special uses. On some microcontrollers, the stack will work only on certain memory ranges. For example, this describes the 8051's stack:

    The 8-bit 8051 stack pointer is restricted to the portion of the internal RAM between 0x08 and 0xFF, though to use all of this space the programmer must forego use of two of the register banks and also the bit-addressable area. It is more normal, therefore, to restrict the stack pointer to the region from 0x30 upwards, leaving only 192 bytes of stack space