Question

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?
Was it helpful?

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

OTHER TIPS

You omitted some parts. As you can see there is no Prototype for OS_CREATETASK_EX and the prototy above OS_CreateTaskEx needs more parameters.

It's obvious that the stuff in upper case is some sort of Macro

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

if we look thought it we see: a pointer to a function returning nothing is required than we have a StackSize (which seems to be the place for reserving stack space. there is however no parameter named argumentVorVoidRoutine * arg, the only thing there is pContext. I assume that this will match with the above (void*) 200.

We never will know what parameter type the Routine will take and so we use the void* which can be any pointer. I'd a little bit cautiosu about just taking an integer and cast it to void* but it's C. So well maybe we are supposed to live with it forever ;-)

It seems you can put apart some area of RAM into the so called Stack and in the lower example this Stack pointer is named StackLP. Without seeing the actual code, we still can just assume...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top