Task data structures and unsupported API calls
In this, the third and last article to focus on tasks, I will look at the relevant data structures in Nucleus SE, and outline the Nucleus RTOS API calls that are not supported by Nucleus SE along, with a summary other compatibility issues.
Tasks utilize a number of data structures – in RAM and ROM – which, as is the case with other Nucleus SE objects, are a series of tables, included and dimensioned according to the number of tasks configured and options selected.
I strongly recommend that application code does not access these data structures directly, but uses the provided API functions. This avoids incompatibility with possible future versions of Nucleus SE and unwanted side-effects, and simplifies porting of an application to Nucleus RTOS. The details of data structures are included here to facilitate easier understanding of the working of the service call code and for debugging.
Kernel RAM Data
These data structures are:
NUSE_Task_Context – This is a 2-dimensional array of type ADDR, with one row for each configured task. The number of columns is chip-specific and determined by the symbol NUSE_REGISTERS, which is defined in nuse_types.h. This array is used by the scheduler to save the context for each task and was described in detail under Context Saving in a previous article. It does not exist if the RTC scheduler is in use.
NUSE_Task_Signal_Flags – This array of type U8 is created if signals are enabled and contains the 8 signal flags for each task. Signals will be discussed in a future article.
NUSE_Task_Timeout_Counter – If the NUSE_Task_Sleep() API call is enabled, this U16 array is created to contain the down counters for each task.
NUSE_Task_Status – This U8 array contains the status of each task – NUSE_READY or a suspended status. It is only created is task suspend is enabled.
NUSE_Task_Blocking_Return – If API call blocking is enabled, this U8 array is created. It carries the return code which will be used after an API call has been blocked. Normally it will contain NUSE_SUCCESS or a code to indicate the object was reset (e.g. NUSE_MAILBOX_WAS_RESET).
NUSE_Task_Schedule_Count – This U16 array only exists if schedule counting has been enabled and contains the counts for each task.
NUSE_Task_Context is initialized mostly to zeros, except for the entries for status register (SR), program counter (PC) and stack pointer(SP), which are set to initial values (see ROM Data below) and all the other data structures are set to zeros by NUSE_Init_Task() when Nucleus SE starts up. A future article will include a full description of Nucleus SE start-up procedures.
Here are the definitions of these data structures in nuse_init.c file.
User RAM Data
It is the user’s responsibility to define a stack for each task (unless the RTC scheduler is in use). These should be arrays of type ADDR and are normally defined in nuse_config.c. The addresses and sizes of the stacks need to be placed the tasks’ entries in NUSE_Task_Stack_Base and NUSE_Task_Stack_Size respectively (see ROM Data below).
Between one and four data structures appertaining to tasks are stored in ROM. The exact number depends upon which options have been selected:
NUSE_Task_Start_Address – This is an array of type ADDR, with one entry for each configured task; this is a pointer to the entry point of the code for the task.
NUSE_Task_Stack_Base – This is an array of type ADDR, with one entry for each configured task; this is a pointer to the base address of the stack for the task. This array only exists if a scheduler other than RTC is selected.
NUSE_Task_Stack_Size – This is an array of type U16, with one entry for each configured task; this is the size of the stack (in words) for the task. This array only exists if a scheduler other than RTC is selected.
NUSE_Task_Initial_State – This is an array of type U8, with one entry for each configured task; this is the initial (start-up) state for the task. It may have values of NUSE_READY or NUSE_PURE_SUSPEND. This array only exists if initial task state support is selected.
These data structures are declared and initialized (statically, of course) in nuse_config.c, thus:
Task Data Footprint
Like all kernel objects in Nucleus SE, the amount of data memory required for tasks is readily predictable.
The ROM data footprint (in bytes) for all the tasks in an application is:
NUSE_TASK_NUMBER * sizeof(ADDR)
Plus, if the scheduler is not RTC:
NUSE_TASK_NUMBER * (sizeof(ADDR) + 2)
Plus, if initial task state support is selected:
The RAM data footprint (in bytes) for all the tasks in an application is totally governed by selected options and may be zero if none of them are selected.
If the scheduler is not RTC:
NUSE_TASK_NUMBER * NUSE_REGISTERS * sizeof(ADDR)
Plus, if support for signals is selected:
Plus, if the NUSE_Task_Sleep() API call is enabled:
NUSE_TASK_NUMBER * 2
Plus, if task suspend is enabled:
Plus, if API call blocking is enabled:
Plus, if schedule counting is enabled:
NUSE_TASK_NUMBER * 2