The whole truth about RTOS. Article # 18. Event flag groups: helper services and data structures

Original author: Colin Walls
  • Transfer


This article continues to describe groups of event flags.

Previous articles in the series:

Article # 17. Event flag groups: introduction and basic services
Article # 16. Signals
Article # 15. Memory sections: services and data structures
Article # 14. Memory sections: introduction and basic services
Article # 13. Task data structures and unsupported API calls
Article # 12. Task Services
Article # 11. Tasks: configuration and introduction to the API
Article # 10. Scheduler: Additional Features and Saving Context
Article # 9. Scheduler: Implementation
Article # 8. Nucleus SE: Internal Design and Deployment
Article # 7. Nucleus SE: Introduction
Article # 6. Other RTOS services
Article # 5. Interaction between tasks and synchronization
Article # 4. Tasks, Context Switching and Interrupts
Article # 3. Tasks and planning
Article # 2. RTOS: Structure and Real-time Mode
Article # 1. RTOS: introduction.


Ancillary services for event flag groups


Nucleus RTOS has three API calls that provide helper functions for groups of event flags: getting information about a group, getting information about the number of groups of event flags in an application, and getting pointers to all groups of event flags. The first two calls are implemented in the Nucleus SE.

Getting information about a group of event flags


This service call returns information about a group of event flags. The implementation of this call in the Nucleus SE differs from the implementation in the Nucleus RTOS in that less information is returned, since the naming of objects and the order of suspending tasks are not supported, and the suspension of tasks itself can be deactivated.

Call for information about the event group in Nucleus RTOS
Service Call Prototype:
STATUS NU_Event_Group_Information (NU_EVENT_GROUP * group, CHAR * name, UNSIGNED * event_flags, UNSIGNED * tasks_waiting, NU_TASK ** first_task);

Parameters:
group - a pointer to a user-provided control unit for a group of event flags;
name- pointer to the 8-character field for the name of the group of event flags, which also includes the terminating zero;
event_flags - a pointer to a variable that will accept the current value of the specified group of event flags;
tasks_waiting - pointer to a variable that will receive the number of suspended tasks in this group of event flags;
first_task - a pointer to a variable of type NU_TASK , which will take a pointer to the first suspended task.

Return value:
NU_SUCCESS - the call was successfully completed;
NU_INVALID_GROUP - incorrect pointer to a group of event flags.

Call for information about a group of events in the Nucleus SE
This call supports the core functionality of the Nucleus RTOS API.

Service call prototype:
STATUS NUSE_Event_Group_Information (NUSE_EVENT_GROUP group, U8 * event_flags, U8 * tasks_waiting, NUSE_TASK * first_task);

Parameters:
group - the index of the group of event flags about which information is requested;
event_flags - a pointer to a variable that will accept the current value of the specified group of event flags;
tasks_waiting - pointer to the variable that will accept the number of suspended tasks in this group of event flags (nothing is returned if the task suspension is deactivated);
first_task - a pointer to a variable of type NUSE_TASKwhich will accept the index of the first suspended task (nothing is returned if the suspension of tasks is deactivated).

Return value:
NUSE_SUCCESS - the call was successfully completed;
NUSE_INVALID_GROUP - incorrect index of the group of event flags.

Implementing information about a group of events in Nucleus SE
The implementation of this API call is quite simple:

*event_flags = NUSE_Event_Group_Data[group];
#if NUSE_BLOCKING_ENABLE
    *tasks_waiting = NUSE_Event_Group_Blocking_Count[group];
    if (NUSE_Event_Group_Blocking_Count[group] != 0)
    {
        U8 index;
        for (index=0; index<NUSE_TASK_NUMBER; index++)
        {
            if ((LONIB(NUSE_Task_Status[index]) ==
                 NUSE_EVENT_SUSPEND)
                && (HINIB(NUSE_Task_Status[index]) == group))
            {
                *first_task = index;
                break;
            }
        }
    }
    else
    {
        *first_task = 0;
    }
#else
    *tasks_waiting = 0;
    *first_task = 0;
#endifreturn NUSE_SUCCESS;

The function returns the value of the group of event flags. Then, if the task blocking API calls are activated, the number of pending tasks and the index of the first one are returned (otherwise, these two parameters are assigned a zero value).

Getting the number of groups of event flags


This service call returns the number of groups of event flags in the application. In Nucleus RTOS, this value changes over time, and the return value shows the current number of groups, and in Nucleus SE, this value is determined at build time and does not change with time.

Calling the event flag group counter in Nucleus RTOS
Service Call Prototype:
UNSIGNED NU_Establised_Event_Groups (VOID);

Parameters:
None.

Return Value:
The current number of event flag groups created.

Calling the event flag group counter in the Nucleus SE
Service Call Prototype:
U8 NUSE_Event_Group_Count (void);

Parameters:
None.

Return value:
The number of configured event flag groups.

Implementing the event flag group counter in Nucleus SE
Implementing this API call is rather trivial: the value of the #define NUSE_EVENT_GROUP_NUMBER symbol is returned .

Data structures


Like all other Nucleus SE objects, groups of event flags use one or two arrays of data structures (both are located in RAM), the size of the arrays depends on the number of groups defined in the settings.

I strongly recommend that the application code does not use direct access to these data structures, but access them through the provided API functions. This will avoid incompatibility with future versions of the Nucleus SE and unwanted side effects, as well as simplify porting the application to the Nucleus RTOS. For a better understanding of how the service call code works and for debugging, a detailed overview of the data structures is provided below.

Data in ram


This data has the following structure:
NUSE_Event_Group_Data [] - an array of data of type U8 , having one entry for each configured group of flags; It stores event flag data.
NUSE_Event_Group_Blocking_Count [] is an array of type U8 containing the counter of blocked tasks in each group of event flags. This array exists only when the blocking functionality in the API is activated.

These data structures are initialized with zeros in the NUSE_Init_Event_Group () function when the Nucleus SE is started. One of the following articles will provide a complete description of the Nucleus SE startup procedures.

The following is a description of these data structures in the nuse_init.c file :

RAM U8 NUSE_Event_Group_Data[NUSE_EVENT_GROUP_NUMBER];
#if NUSE_BLOCKING_ENABLE
    RAM U8 NUSE_Event_Group_Blocking_Count[NUSE_EVENT_GROUP_NUMBER];
#endif

Data in the ROM


For the implementation of groups of event flags are not used data in the ROM.

Memory size for groups of event flags


As with all Nucleus SE core objects, the amount of memory required for groups of event flags is predictable.

The amount of data in the ROM for all groups of event flags in the application is 0.

The amount of memory in RAM for all groups of event flags when the API lock functionality is activated is NUSE_EVENT_GROUP_NUMBER * 2 .

Otherwise, it is NUSE_EVENT_GROUP_NUMBER .

Unrealized API calls


Three API calls for event flag groups that can be found in the Nucleus RTOS were not implemented in the Nucleus SE.

Creating a group of event flags


This API call creates a group of event flags. In Nucleus SE, this call is not necessary, as groups of event flags are created statically.

Service Call Prototype:
STATUS NU_Create_Event_Group (NU_EVENT_GROUP * group, CHAR * name);

Parameters:

group - a pointer to a user-provided control unit for a group of event flags; used as a descriptor to control groups of event flags in other API calls;
name is a pointer to the 8-character name of the group of event flags with the terminating zero byte included in this area.

Return value:

NU_SUCCESS - the call was successfully completed;
NU_INVALID_GROUP - null pointer to the control unit of the group of event flags (NULL ) or already in use.

Deleting a group of event flags


This API call removes the previously created group of event flags. In Nucleus SE, this call is not necessary, as groups of event flags are created statically and cannot be deleted.

Service Call Prototype:

STATUS NU_Delete_Event_Group (NU_EVENT_GROUP * group);

Parameters:

group - a pointer to a control unit for a group of event flags.

Return value:

NU_SUCCESS - the call was successfully completed;
NU_INVALID_GROUP - incorrect pointer to a group of event flags.

Event flag group pointers


This API call makes a sequential list of pointers to all groups of event flags in the system. In Nucleus SE, this call is not necessary, as the event flag groups have simple indexes, not pointers.

Service call prototype:

UNSIGNED NU_Event_Group_Pointers (NU_EVENT_GROUP * pointer_list, UNSIGNED maximum_pointers);

Parameters:

pointer_list - a pointer to an array of pointers NU_EVENT_GROUP , this array is filled with pointers to groups of event flags created in the system;
maximum_pointers - the maximum number of pointers in the array.

Return value: The

number of NU_EVENT_GROUP pointers in the array.

Nucleus RTOS Compatibility


When developing the Nucleus SE, my goal was to ensure the highest level of code compatibility with the Nucleus RTOS. Groups of event flags were no exception, and, from the developer’s point of view, they are implemented in almost the same way as in the Nucleus RTOS. There are some incompatibilities that I considered acceptable, given that the final code will become more understandable and more efficient in terms of the amount of memory required. Otherwise, Nucleus RTOS API calls can be almost directly used as Nucleus SE calls.

Object IDs


In Nucleus RTOS, all objects are described by data structures (control units) of a particular type. A pointer to this control unit serves as an identifier for a group of event flags. I decided that in the Nucleus SE, a different approach is needed for effective memory use: all kernel objects are described by several tables in RAM and / or ROM. The size of these tables is determined by the number of configured objects of each type. The specific object identifier is an index in this table. So I defined NUSE_EVENT_GROUP as equivalent to U8, a variable of this type (not a pointer) serves as an identifier for a group of event flags. This small incompatibility is easy to handle if the code is transferred from the Nucleus SE to the Nucleus RTOS and vice versa. Usually no operations are performed on object identifiers, except for moving and storing.

Nucleus RTOS also supports naming groups of event flags. These names are used only for debugging. I excluded them from the Nucleus SE to save memory.

The number of flags in the group


In Nucleus RTOS groups of event flags contain 32 flags each, in Nucleus SE I reduced their number to eight, since this is enough for simple applications and allows you to save RAM. Nucleus SE can be easily modified if larger groups of event flags are required.

Flag absorption function


In Nucleus RTOS, there is a function for clearing (absorbing) event flags after reading them. I decided to exclude this function from Nucleus SE to simplify the system, since the absorption (deletion) of flags occurs when all blocked tasks received flags for reading, which would be difficult to implement. If necessary, the task that reads the flags can always clear them with a separate API call.

Unrealized API calls


Nucleus RTOS supports seven service calls for working with groups of event flags. Of these, three are not implemented in the Nucleus SE. The details of these calls, as well as the decision to exclude them from Nucleus SE, have been described above.
The next article will cover semaphores.

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.

Also popular now: