
This article will look at signals that are the simplest mechanisms for interaction between tasks in Nucleus SE. They provide a low-cost way to transfer simple messages between tasks.
Previous articles in the series:
Article # 15. Memory sections: services and data structuresArticle # 14. Memory sections: introduction and basic servicesArticle # 13. Task data structures and unsupported API callsArticle # 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.
Use of signals
Signals differ from all other types of kernel objects in that they are not autonomous: signals are associated with tasks and cannot exist without them. If the application is configured to use signals, then each task has a set of eight signal flags.
')
Any task can set signals for another task. Only the task owner of the signal can read signals. In the process of reading the signals are reset. Tasks cannot read or discard signals from other tasks.
In Nucleus RTOS, there is a tool that allows tasks to assign functions that run when another task sets one or more signal flags. This is somewhat similar to the interrupt handling procedure. This feature is not supported in the Nucleus SE, here tasks should request signal flags explicitly.
Signal setup
As with most Nucleus SE objects, the signal setting is determined by the
#define directives in
nuse_config.h . The main parameter is
NUSE_SIGNAL_SUPPORT , which activates support for functionality (for all tasks in the application). The question of specifying the number of signals is not worth it: 8 flags are allocated for each task.
The setting of this enable parameter serves as the main signal activator. This provides a well-defined data structure with an appropriate size. In addition, this parameter activates the API settings.
Activate API calls
Each API function (service call) in the Nucleus SE is activated by the
#define directive in
nuse_config.h . For signals, these include:
NUSE_SIGNALS_SEND NUSE_SIGNALS_RECEIVE
By default, they are assigned the value
FALSE , thus disabling each service call and preventing the inclusion of the code implementing them. To set up signals in the application, you need to select the necessary API calls and set the corresponding directives to
TRUE .
The following is an excerpt from the default
nuse_config.h file:
#define NUSE_SIGNAL_SUPPORT FALSE #define NUSE_SIGNALS_SEND FALSE #define NUSE_SIGNALS_RECEIVE FALSE
An activated API function with signal support disabled will result in a compilation error. If your code uses an API call that has not been activated, a build error will occur because the implementation code was not included in the application. Of course, the inclusion of two API functions is in some way unnecessary, since there is no point in activating signal support in the absence of these APIs. Activators have been added for compatibility with other features of Nucleus SE.
Alarm Calls
Nucleus RTOS supports four signal-related service calls, which provide the following functionality:
- Sending signals to a given task. The Nucleus SE is implemented as a NUSE_Signals_Send () function.
- Reception of signals. In Nucleus SE, it is implemented in the NUSE_Signals_Receive () function.
- Signal handler registration. Not implemented in the Nucleus SE.
- Enable / disable (control) signals. Not implemented in the Nucleus SE.
The implementation of each of these calls is discussed in detail below.
Signal sending and receiving services
The fundamental operations that can be performed on a set of task signals — sending data (can be done by any task) and reading data (and, therefore, clearing data, can only be done by the owner-task). Nucleus RTOS and Nucleus SE provide two basic API calls for these operations, which will be described below.
Since the signals are bits, they are best visualized as binary numbers. Since standard C does not historically support the representation of binary constants (octal and hexadecimal only), Nucleus SE has a useful header file
nuse_binary.h , which contains
#define characters of the form
b01010101 for all 256 8-bit values. The following is an excerpt from the
nuse_binary.h file:
#define b00000000 ((U8) 0x00) #define b00000001 ((U8) 0x01) #define b00000010 ((U8) 0x02) #define b00000011 ((U8) 0x03) #define b00000100 ((U8) 0x04) #define b00000101 ((U8) 0x05)
Sending Signals
Any task can send signals to any other task in the application. Sending signals involves setting one or more signal flags. This is an OR operation (OR), which does not affect the previously set flags.
Call to send signals to the Nucleus RTOSService Call Prototype:
STATUS NU_Send_Signals (NU_TASK * task, UNSIGNED signals);Options:
task - a pointer to the task control block to which the set signal flags belong;
signals - the value of the set signal flags.
Return value:
NU_SUCCESS - the call was successfully completed;
NU_INVALID_TASK - incorrect pointer to the task;
Call to send signals to the Nucleus SEThis API call supports the core Nucleus RTOS API.
Service Call Prototype:
STATUS_NUSE_Signals_Send (NUSE_TASK task, U8 signals);Options:
task - an index (ID) of the task to which the signal flags are being set;
signals - the value of the set signal flags.
Return value:
NUSE_SUCCESS - the service call was successfully completed;
NUSE_INVALID_TASK - incorrect task index.
Implementing sending signals to the Nucleus SEBelow is the complete code for the NUSE_Signals_Send () function:
STATUS NUSE_Signals_Send(NUSE_TASK task, U8 signals) { #if NUSE_API_PARAMETER_CHECKING if (task >= NUSE_TASK_NUMBER) { return NUSE_INVALID_TASK; } #endif NUSE_CS_Enter(); NUSE_Task_Signal_Flags[task] |= signals; NUSE_CS_Exit(); return NUSE_SUCCESS; }
The code is very simple. After any verification of the parameters, the signal values pass through the OR operation to the signal flags of the specified task. Task blocking does not affect the signals.
Reception of signals
A task can only read its own set of signal flags. In the process of reading the values of the flags are reset.
Call to receive signals in the Nucleus RTOSService Call Prototype:
UNSIGNED NU_Receive_Signals (VOID);Parameters: none.
Return value:
Values of signal flags.
Call to receive signals in the Nucleus SEThis API call supports Nucleus RTOS API key functionality.
Service Call Prototype:
U8 NUSE_Signals_Receive (void);Parameters: none.
Return value:
Values of signal flags.
Implementing Nucleus SE Signal AcquisitionThe following is the full code for the
NUSE_Signals_Receive () function:
U8 NUSE_Signals_Receive(void) { U8 signals; NUSE_CS_Enter(); Signals = NUSE_Task_Signal_Flags[NUSE_Task_Active]; NUSE_Task_Signal_Flags[NUSE_Task_Active] = 0; NUSE_CS_Exit(); return signals; }
The code is very simple. The value of the flags is copied, the initial value is reset, and the copy is returned by the API function. Task blocking does not affect signals.
Data structures
Since signals are not separate objects, memory usage depends on the tasks to which they belong. Below is some information for completeness. Signals use one data structure (in RAM), which, like other Nucleus SE objects, is a table whose dimensions correspond to the number of tasks in the application. This data structure is used only if signal support is enabled.
I highly recommend that the application code does not directly access this data structure, but use the existing API functions. This avoids incompatibility with future versions of the Nucleus SE, unwanted side effects, and also simplifies porting the application to the Nucleus RTOS. The data structure is discussed in detail below to simplify understanding of the principles of work calls and debugging.
The structure of the data placed in the RAM
Data structure:
NUSE_Task_Signal_Flags [] is an array of type U8 with one entry for each configured task, signal flags are stored in this array.
This data structure is initialized with zeros by the
NUSE_Init_Task () function when the Nucleus SE is loaded.
The structure of the data placed in the ROM
Signals do not have data structures in ROM.
The amount of memory for storing data signals
As with all Nucleus SE core objects, the amount of memory required for signals is predictable.
The amount of data in the ROM for all signals in the application is 0.
The amount of memory for storing data in RAM (in bytes) for all signals in the application is equal to the number of tasks configured (
NUSE_TASK_NUMBER ). But in fact, this data belongs to the tasks and is described in the previous article about the tasks.
Unrealized API calls
Two signal calls to the API of signals from Nucleus RTOS are not implemented in Nucleus SE:
Signal Handler Registration
This API call sets the signal processing procedure (function) for the current task. This is not necessary in Nucleus SE, since signal handlers are not supported.
Service Call Prototype:
STATUS NU_Register_Signal_Handler (VOID (* signal_handler) (UNSIGNED));Options:
signal_handler - a function that should be called when receiving signals
Return value:
NU_SUCCESS - the call was successfully completed;
NU_INVALID_POINTER - null pointer to a signal handler (
NULL )
Control (enable / disable) signals
This service activates and / or deactivates the signals for the current task. For each task 32 signals are available. Each signal is represented by a bit in
signal_enable_mask . Adding a bit to
signal_enable_mask enables the corresponding signal, and deleting the bit disables it.
Service Call Prototype:
UNSIGNED NU_Control_Signals (UNSIGNED enable_signal_mask);Options:
enable_signal_mask - a bit pattern representing the correct signals.
Return value:
Mask of activating / deactivating the previous signal.
Nucleus RTOS Compatibility
When developing the Nucleus SE, my goal was to maintain the maximum level of compatibility of code with the Nucleus RTOS. Signals are no exception, and, from a developer’s point of view, they are implemented in much the same way as in the Nucleus RTOS. There are some incompatibilities that I considered valid, given that the final code is much easier to understand and can use memory more efficiently. Otherwise, the Nucleus RTOS API calls can be almost directly transferred to the Nucleus SE calls.
Signal handlers
In Nucleus SE, signal handlers are not implemented to simplify the overall structure.
Signal availability and quantity
Nucleus RTOS tasks can have 32 signal flags each. In Nucleus SE, I decided to reduce their number to eight, since this will be enough for simpler applications and saves RAM resources. If necessary, the signals can be completely turned off.
Unrealized API calls
Nucleus RTOS supports four signaling service calls. Of these, two were not implemented in the Nucleus SE. Their description can be found above in the section "Unrealized API calls".
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.