
In this third and final article on tasks, I will look at the Nucleus SE data structures and describe the RTOS API calls that are not implemented in the Nucleus SE, and also talk about other compatibility issues.
Previous articles in the series:
Article # 12. Task ServicesArticle # 11. Tasks: configuration and introduction to the APIArticle # 10. Scheduler: additional features and context preservationArticle # 9. Scheduler: implementationArticle # 8. Nucleus SE: Inside and DeploymentArticle # 7. Nucleus SE: introductionArticle # 6. Other RTOS servicesArticle # 5. Interaction between tasks and synchronizationArticle # 4. Tasks, context switching and interruptsArticle # 3. Tasks and planningArticle # 2. RTOS: Structure and Real Time
Article # 1. RTOS: introduction.
Data structures
Tasks use different data structures (both in RAM and ROM), which, like other Nucleus SE objects, is a set of tables whose size corresponds to the number of selected tasks and parameters.
I strongly recommend that application code refer to these data structures using API functions, rather than directly. This avoids unwanted side effects, incompatibility with future versions of the Nucleus SE, and also simplifies porting the application to the Nucleus RTOS. For a better understanding of the work of the service call code and the debugging process, below is a detailed description of the data structures.
')
Kernel data structures hosted in RAM
These data structures include:
NUSE_Task_Context [] [] is a two-dimensional array of the type
ADDR , it has one line for each task. The number of columns depends on the controller architecture and is determined by the symbol
NUSE_REGISTERS , which is defined in
nuse_types.h . This array is used by the scheduler to save the context of each task and was described in detail in the “Saving Context” section of Article # 10. It is not created if the RTC scheduler is used.
NUSE_Task_Signal_Flags [] is an array of type
U8 , created when signals are turned on, and contains 8 signal flags for each task. Signals will be discussed in one of the following articles.
NUSE_Task_Timeout_Counter [] is an array of type
U16 , consists of subtractive counters for each task, and is created if the API call
NUSE_Task_Sleep () is activated.
NUSE_Task_Status [] is an array of type U8, contains the status of each task -
NUSE_READY or the status of suspension. It is created only if task suspension is activated.
NUSE_Task_Blocking_Return [] is an array of type U8, created if the blocking of API calls is activated. It contains the return code that will be used after blocking API calls. It usually contains
NUSE_SUCCESS or code indicating that the object was dropped (for example,
NUSE_MAILBOX_WAS_RESET ).
NUSE_Task_Schedule_Count [] is an array of type
U16 , contains the counter of each task and is created only if the scheduler count has been activated.
NUSE_Task_Context [] [] is initialized mainly with zeros, except for the entries corresponding to the status register (SR), the program counter (PC) and the stack pointer (SP), which are assigned initial values ​​(see in the ROM ”below), and all other data structures
NUSE_Init_Task () assigns zeros when running the Nucleus SE. One of the following articles will contain a complete list of Nucleus SE starting procedures with their descriptions.
Below are the definitions of the data structures that are contained in the nuse_init.c file.

User data in RAM
The user must define each task stack (if not using the RTC scheduler). These should be
ADDR arrays, which are typically defined in
nuse_config.c . Addresses and stack sizes should be placed in task entries
NUSE_Task_Stack_Base [] and
NUSE_Task_Stack_Size [], respectively (see. Data in ROM).
ROM data
The ROM contains from one to four data structures related to the tasks. The exact amount depends on the selected parameters:
NUSE_Task_Start_Address [] is an array of type
ADDR , having one entry for each task, which is a pointer to the entry point to the code for the task.
NUSE_Task_Stack_Base [] is an array of the type
ADDR , having one entry for each task, which is a pointer to the base address of the stack for the task. This array is created if any scheduler other than RTC is used.
NUSE_Task_Stack_Size [] is an array of type
U16 , having one entry for each task, which shows the stack size for the task (in words). This array is created if any scheduler other than RTC is used.
NUSE_Task_Initial_State [] is an array of type
U8 , which has one entry for each task, which shows the initial state of the task. May be
NUSE_READY or
NUSE_PURE_SUSPEND . This array is created if support for the initial state of the task is selected.
These data structures are declared and initialized (static) in
nuse_config.c :

Memory capacity for storing task data (Task Data Footprint)
Like all Nucleus SE core objects, the amount of memory required to store data is predictable.
ROM size (in bytes) required for all application tasks:
NUSE_TASK_NUMBER * sizeof (ADDR)Plus, if any planner other than RTC is selected:
NUSE_TASK_NUMBER * (sizeof (ADDR) +2)Plus, if support for the initial state of the task is selected:
NUSE_TASK_NUMBERFor storing data in RAM, the amount of memory (in bytes) is determined by the selected parameters, and it can be zero if none of the parameters are selected.
If a scheduler other than RTC is selected:
NUSE_TASK_NUMBER * NUSE REGISTER * sizeof (ADDR)Plus, if signal support is selected:
NUSE_TASK_NUMBERPlus, if the NUSE_Task_Sleep () API call is activated:
NUSE_TASK_NUMBER * 2Plus, if task suspension is activated:
NUSE_TASK_NUMBERPlus, if API call blocking is activated:
NUSE_TASK_NUMBERPlus, if the scheduler counter is activated:
NUSE_TASK_NUMBER * 2Non-implemented Nucleus SE API calls
Below are seven API calls that are in the Nucleus RTOS, not implemented in the Nucleus SE.
Create Task
This API call creates an application task. In Nucleus SE, this function is not necessary, since tasks are created statically.
Call prototype:
STATUS NU_Create_Task (NU_TASK * task, CHAR * name, VOID (* task_entry)) (UNSIGNED, VOID *), UNSIGNED argc, VOID * argv, VOID * stack_address, UNSIGNED stack_size, OPTION priority, UNSIGNED time_shtshir, OP_ priority, UNSIGNEDOptions:
task - a pointer to a user task management block, can be used as a descriptor / reference ("handle") of a task in other API calls;
name - pointers to the name of the task, a 7-character string with a terminating zero;
task_entry - specifies the input function for the task;
argc is a
UNSIGNED data element that can be used to transfer initial information to a task;
argv is a pointer that can be used to pass information to a task;
stack_address - sets the initial memory sector for the task stack;
stack_size - indicates the number of bytes in the stack;
priority - indicates the priority value of the task: from 0 to 255, where lower numbers correspond to the highest priority;
time_slice - indicates the maximum number of time
slices that can pass when performing this task. A value of “0” disables time slicing for this task;
preempt - indicates whether the task is being
repressed or not. May have values
NU_PREEMPT and
NU_NO_PREEMPT ;
auto_start - shows the initial state of the task.
NU_START means that the task is ready for execution, and
NU_NO_START - that the task is suspended.
Return value:
NU_SUCCESS indicates a successful completion of the service;
NU_INVALID_TASK - indicates that the pointer to the task control block is zero (
NULL );
NU_INVALID_ENTRY - indicates that the pointer to the input function of the task is zero (
NULL );
NU_INVALID_MEMORY - indicates that the memory sector assigned by the stack_address parameter is zero (
NULL );
NU_INVALID_SIZE - indicates that the specified stack size is insufficient;
NU_INVALID_PREEMPT - indicates that the
preempt parameter
is set incorrectly;
NU_INVALID_START - indicates that the
auto_start parameter is incorrect.
Delete Task
This API call removes the previously created application task, which should have the status of
Finished (terminated) or
Terminated (complete suspension). This call is also not necessary in Nucleus SE, since tasks are created statically and cannot be deleted.
Call prototype:
STATUS NU_Delete_Task (NU_TASK * task);Options:
task - pointer to task control block
Return value:
NU_SUCCESS indicates a successful completion of the service;
NU_INVALID_TASK - indicates that the pointer to the task is set incorrectly;
NU_INVALID_DELETE - indicates that the task is not in the “Finished” or “Terminated” state.
Get task pointers (Get Task Pointers)
This API call makes a sequential list of pointers to all tasks in the system. It is not needed in the Nucleus SE, since tasks are identified using a simple index, not a pointer.
Call prototype:
UNSIGNED NU_Task_Pointers (NU_TASK ** pointer_list, UNSIGNED maximum_pointers);Options:
pointer_list is a pointer to an array of pointers
NU_TASK . This array will be filled with pointers to the tasks installed in the system;
maximum_pointers - the maximum number of pointers that can be placed in an array.
Return value:
The number of
NU_TASK pointers placed in the array.
Change Task Priority
This API call assigns a new priority to the task. It is not required in Nucleus SE, as task priorities are constant.
Call prototype:
OPTION NU_Change_Priority (NU_TASK * task, OPTION new_priority);Options:
task - a pointer to the task management block;
new_priority - sets the priority from 0 to 255.
Return value:
The previous task priority value.
Change Task Preemption Algorithm
This API call reverses the order of the executing task. In Nucleus SE, it is not needed, since a simpler scheduling algorithm is used.
Call prototype:
OPTION NU_Change_Preemption (OPTION preempt);Options:
preempt is a new extrusion algorithm that accepts
NU_PREEMPT or
NU_NO_PREEMPT valuesReturn value:
The previous algorithm for crowding out the task.
Change Task Time Slice (Change Task Time Slice)
This API call changes the time slot of a specific task. In the Nucleus SE, it is not necessary, since the time quanta of the tasks are fixed.
Call prototype:
UNSIGNED NU_Change_Time_Slice (NU_TASK * task, UNSIGNED time_slice);Options:
task - a pointer to the task management block;
time_slice - the maximum number of time
slices that can pass when performing this task, the zero value of this field disables the time slicing for this task.
Return value:
The previous value of the time quantum of the problem.
Terminate Task
This API call completes a specific task. This is not necessary in the Nucleus SE, as the
Terminated state is not supported.
Call prototype:
STATUS NU_Terminate_Task (NU_TASK * task);Options:
task - a pointer to the task control block.
Return value:
NU_SUCCESS indicates a successful completion of the service;
NU_INVALID_TASK - indicates that the task pointer is set incorrectly.
Nucleus RTOS Compatibility
When developing the Nucleus SE, one of the main tasks was to ensure a high level of code compatibility with Nucleus RTOS. Tasks are no exception, and, from the user's point of view, they are implemented in much the same way as in the Nucleus RTOS. There are some incompatible areas where I came to the conclusion that such incompatibility would be acceptable, given that the final code is easier to understand and can use memory more efficiently. However, besides these incompatibilities, the other Nucleus RTOS API calls can be almost directly used as Nucleus SE calls. One of the following articles will contain more detailed information on the transition from Nucleus RTOS to Nucleus SE
Object IDs
In Nucleus RTOS, all objects are described by a data structure (control units) that have a specific type. A pointer to this control unit serves as an identifier for the task. In Nucleus SE, I decided that a different approach was needed to use memory efficiently. All kernel objects are described by a set of tables in RAM and / or ROM. The size of these tables is determined by the number of object types. The identifier of a particular object is the index in these tables. Therefore, I have defined
NUSE_TASK as equivalent to
U8 . A variable of this type (not a pointer) serves as a task identifier. This is a small incompatibility that is easy to figure out if the code is ported from or to Nucleus RTOS. Object identifiers are usually stored and transmitted unchanged.
Nucleus RTOS also supports task naming. These names are used only when debugging. I excluded them from the Nucleus SE to save memory.
Task states
In Nucleus, RTOS tasks can be in one of several states:
Executing ,
Ready ,
Suspended (which leads to uncertainty: the task is in standby mode or blocked by an API call),
Terminated or Finished.
Nucleus SE also supports
Executing and
Ready states. All three
Suspended options are supported optionally.
Terminated and Finished are not supported. No API calls to complete tasks. The external task function should never return a value either explicitly or implicitly (this will lead to a
Finished state in the Nucleus RTOS).
Unrealized API calls
Nucleus RTOS supports 16 task calls. Of these, 7 are not implemented in the Nucleus SE. Their description, as well as the reason for their exclusion, is described above.
In the next article, we’ll start looking at RTOS memory management.
About the author: Colin Walls has been working in the electronics industry for more than thirty years, spending a significant amount of time on embedded software. He is now an embedded software engineer in Mentor Embedded (a division of Mentor Graphics). Colin Walls often speaks at conferences and seminars, author of numerous technical articles and two books on embedded software. Lives in the UK.
Colin's professional
blog , e-mail: colin_walls@mentor.com.