The whole truth about RTOS. Article # 8. Nucleus SE: Inside and Deployment
This article continues the Nucleus SE review.
Nucleus SE provides a set of tools that can be expected from any RTOS.
First, the Nucleus SE contains a fairly simple scheduler, however, thanks to the four options available, it provides flexibility. The scheduler supports Run to Completion, Round Robin, Time Slice, and Priority algorithms.
The Nucleus SE API includes about 50 service calls that provide developers with access to managing tasks, memory sections, signals, groups of event flags, semaphores, mailboxes, queues, pipelines, system time, application timers, and diagnostics.
In addition to simple task scheduling, Nucleus SE (optionally) supports suspending tasks. This function can be “clean” (for example, as the result of an explicitly defined service API call suspension), it can be a “sleep” function (when the task is suspended for a certain period of time), or it can be the result of another API call in which the task is blocked (the so-called "conditional" suspension), waiting for access to the kernel resource. Unlike Nucleus RTOS, Nucleus SE does not support timeouts when blocking API calls.
The variety of mechanisms presented allows you to choose from the hierarchy of inter-task synchronization and communication tools: from semaphores to signals, event flags, mailboxes and queues / pipelines.
Previous articles in the series:
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.
When choosing the NUSE_API_PARAMETER_CHECKING configuration, the code for verification of parameters is included in all API functions: verification of null pointers, object indexes, etc. Since this is additional code that requires additional memory, it will be reasonable to enable this function during debugging, but turn it off in the release build.
Nucleus SE has a flexible structure, which gives us two positive points. On the one hand, the kernel can have a fine-modular configuration that satisfies the tasks of a particular application due to simple adjustment of the available functionality and simple memory management. On the other hand, the Nucleus SE code is easily transferred both between tools and between processors.
Since the development of the Nucleus SE was important clarity and ease of understanding of the code, the naming conventions were carefully thought out. Each character code has a NUSE_ prefix . Everything that follows this prefix obeys a set of simple rules.
Each API call function in the Nucleus SE begins with NUSE_, which is almost always followed by the type of the object, followed by a mixed-case operation that is divided using an underscore. An example is the NUSE_Queue_Send () function , which places messages in a queue.
Other functions and variables
The remaining functions and (global) variables in Nucleus SE code also use the prefix NUSE_, but the rest of the name does not always have a “structure”. This is unimportant for a regular user of the kernel, since API functions will be sufficient for it.
Since the Nucleus SE is configured with #define characters, they are also subject to naming conventions. They are written only in upper case. The names of API call activators coincide with the names of functions and are also written in upper case, for example, NUSE_QUEUE_SEND.
Other characters #define
Any other #define characters (for example, API call parameters and return status values) that can be used by application code follow the same rules, they start with NUSE_ and are written in upper case. For example, NUSE_SUCCESS.
All RTOSs have a set of data structures describing kernel objects. In most implementations, they are data structures in C that form linked lists, often with bidirectional and even circular communications. This is logical, since important data is conveniently encapsulated, and list items can be added or deleted as objects are created and deleted.
In Nucleus SE, all objects are static, so organizing all the structures of these objects into a simple list was an obvious solution. This reduces the volume and complexity of direct and reverse pointers. However, I decided to strengthen the optimization of the system and refused to use structures at all. In Nucleus SE, all data on kernel objects is represented by several simple arrays (also called tables) of different types, one for each object type and one more. There are several arguments in favor of such a decision:
- Nucleus SE was designed for compatibility with 8-bit structures. Most small CPUs do not have the best tools for implementing data structures in the C compiler. Simple arrays are much more efficient.
- Since the maximum allowed number of objects of each type is 16, and accessing the elements of each array requires four bits, one byte is often used. This is more efficient than the address, which usually takes 16 or 32 bits.
- It is necessary that the object's permanent data is stored in the ROM (ROM) and not copied into the RAM (RAM). Since the structure cannot be divided between ROM and RAM (in the traditional portable C), each type of object can have two structures, which is excessively complex. In the Nucleus SE, object description tables can be located both in ROM and in RAM, in accordance with the requirements.
- Due to the highly configurable Nucleus SE ("ultra-high scalability"), some of these object descriptions may be optional, depending on the means chosen. This leads to widespread use of conditional compilation. Structural definitions with built-in conditional compilation directives are very difficult to understand. Controlling the instantiation of individual arrays using this method is, in turn, fairly easy to understand.
All object data tables are subject to the hierarchical naming convention mentioned above. Thus, it is fairly easy to understand which tables are logically related.
Key Differences from Nucleus RTOS
Although the Nucleus SE was designed with a high degree of compatibility with the Nucleus RTOS, some small and larger differences could not be avoided. They will be described in detail in the relevant articles, and a brief description is given below.
In Nucleus RTOS objects are created and deleted upon request. In Nucleus SE, all objects are created statically and are determined at build time.
Number of objects
Nucleus RTOS supports an indefinite number of objects of each type. Nucleus SE supports a maximum of sixteen objects of each type.
Nucleus RTOS allows you to assign some types of objects text names that can be used when debugging. There is no such possibility in the Nucleus SE.
Task locking mechanism
The API task blocking mechanism in Nucleus SE is pretty simple. When a resource is released, all pending tasks are resumed and compete with each other (with the help of the task scheduler) for resources. Losing tasks are again suspended (blocked). In Nucleus, the RTOS mechanism is more complex, only important tasks continue in it, which is more efficient.
API call timeout
When you call the blocking API, Nucleus RTOS allows the developer to specify a timeout period after which the call will resume, even if the resource is not released. There is no such possibility in the Nucleus SE.
The Nucleus RTOS Scheduler is flexible, efficient, and well-defined. Nucleus SE offers a set of schedulers, each of which is simple and effective enough for a reduced number of supported tasks: from 1 to 16.
A system that uses Nucleus RTOS can have an arbitrary number of tasks that can be assigned one of 256 priority levels, and several tasks can have one priority level. Task priority levels can also change during execution. In Nucleus SE, if a priority scheduler is selected, each task must have a unique priority level that cannot be changed dynamically. There can be only one priority level for each task.
Nucleus RTOS supports the sophisticated two-level interrupt handler architecture, which enables efficient interrupt handler interaction and kernel services. Nucleus SE uses a similar approach that supports both simple interrupt handlers that do not interact with the kernel (unmanaged interrupts) and interrupt handlers with full context that can use API calls (controlled interrupts).
Nucleus RTOS has a well thought out device driver architecture. Nucleus SE does not have such an architecture, leaving the developer with the task of distributing device management between tasks and the interrupt handler code.
Nucleus SE Spread
Nucleus SE source codes will be published as this series of articles develops. Available files will be provided upon request by email. Towards the end of a series of articles, a repository will be created for downloading all published files.
about the author
Колин Уоллс уже более тридцати лет работает в сфере электронной промышленности, значительную часть времени уделяя встроенному ПО. Сейчас он — инженер в области встроенного ПО в Mentor Embedded (подразделение Mentor Graphics). Колин Уоллс часто выступает на конференциях и семинарах, автор многочисленных технических статей и двух книг по встроенному ПО. Живет в Великобритании. Профессиональный блог Колина, e-mail