📜 ⬆️ ⬇️

The whole truth about the RTOS. Article # 7. Nucleus SE: introduction



In the remaining part of the series The Whole Truth About RTOS, we will examine in detail how the RTOS is implemented and deployed. For this, we consider a specific RTOS: Nucleus SE. Even if you are not going to use this particular core or other related cores, understanding how it works will provide a good foundation for working with any RTOS.

To understand why the Nucleus SE was designed this way, it is important to highlight the core tasks and goals that guided me at the beginning of this project.

Previous articles in the series:
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
Article # 1. RTOS: introduction.

')
Simplicity

Kernel code should be simple, clear, well commented and documented. Nucleus SE is intended primarily for educational use.

The size

It should be a small, highly scalable kernel (since memory, especially operational (RAM), may be in short supply).

Functionality

The kernel must have a high level of functionality that supports standard RTOS services.

8/16 bit support

It should support 8- and 16-bit architectures: as far as possible, use byte-sized data; data structures should not require exotic addressing methods; Permanent data should not be copied into RAM unnecessarily.

Future

There must be a development path from the Nucleus SE to the Nucleus RTOS. Users should be able to easily transfer code between kernels. More importantly, their knowledge must be transferred. The Nucleus SE API effectively implements a subset of the Nucleus RTOS API.

Cost of

The business model should be attractive to all potential users: developers of 8/16-bit devices, those who use RTOS for the first time and those who are just learning the technology itself. Thus, the Nucleus SE is freely available, completely free for commercial and educational use; code can be used and modified.

Nucleus SE Target Audience

The result of this approach is a kernel that can be useful for three types of developers:


Design solutions and tradeoffs

To achieve the above objectives, it was necessary to take several carefully thought-out design decisions. Details will be described later when we consider specific functions, but here is a brief summary of the key points.

Static configuration

Nucleus SE is a static RTOS, that is, all configuration decisions are made at build time, not dynamically at run time. This has many advantages, including simplifying the data structure and reducing the size of the code, so there is no need to call the “create” and “delete” API functions. For most applications, dynamic object creation is not required.

Number of objects

The number of objects of each type is limited in the application based on Nucleus SE. There can be from one to sixteen tasks and from zero to sixteen different types of kernel object. This simplifies the addressing of objects (see below). This limitation is not a difficulty for small applications for which the kernel is intended.

Addressing Objects

Objects are addressed using an “index”, which can range from zero to fifteen. Compared to the usual use of pointers, this can be more efficient on smaller processors and will allow less memory to be used: the index only requires 4 bits of memory; The address is 16-32 bits.

Scheduler

The scheduler was a simplified area of ​​the core architecture. Instead of providing a flexible mechanism with different scheduling policies, four separate types of scheduler are available in the kernel; The specific scheduler for the application is selected during setup.

Limited functionality

Some of the functionality available in the Nucleus RTOS is not implemented in the Nucleus SE. In some cases, this is done for simplicity. In other cases, a small loss of functionality in one area makes another functionality easier to implement. These incompatibilities are covered in the corresponding articles of the series.

Memory usage

Since Nucleus SE must support applications with limited memory, special attention was paid to memory usage. The use of “classic” ROM and RAM was assumed: ROM was used for code and permanent data; RAM — for storing variables, stack, etc. Although a specific target may have a different scheme, the Nucleus SE code is quite flexible; Definitions (#defines) ROM and RAM are used to prefix all variable and data structures to indicate their location. This can be achieved with the help of tools.

The key requirement was to avoid unnecessary copying of data from the ROM to the RAM, since there may not be enough RAM. The mechanism by which this is achieved is described in the “Data Structures” section in the next article.

API implementation

The Nucleus SE API is implemented in the traditional way: the C language function implements each API call. These calls are logically grouped. Although the API calls in the Nucleus SE are not exactly the same as in the Nucleus RTOS, the general functionality is simulated, and the mapping between the API is simple. Details of the Nucleus RTOS API will be enabled.

Critical sections

The code for many API function calls includes sequences of instructions that manipulate kernel data. As a rule, the data may be in an invalid state during the execution of these instructions, so care must be taken to avoid interruption. Or it may be prohibited to run code from another task or interrupt handler, if it could get access to this (currently invalid) data. Such sequences of instructions are called critical sections.

A pair of macros named NUSE_CS_Enter () and NUSE_CS_Exit () are defined. All Nucleus SE API functions code uses them to span a critical section, thus:

NUSE_CS_Enter ();
<non-interruptable code>
NUSE_CS_Exit ();

As a rule, these macros will unfold in the instruction for disabling the interrupt command and the instruction for enabling the interrupt, respectively. This will need to be verified if the Nucleus SE is implemented on a different processor architecture. More information about porting Nucleus SE will be described in the next article.

Scalability

Like all modern RTOS, the Nucleus SE is scalable. To ensure that only the RTOS components used are included, all API functions are represented as a library. Thus, during linking, the functions referenced are extracted and included in the final image of the application. Nucleus RTOS uses this approach for both the kernel and all other components of the OS. Nucleus SE uses a different technique.

Instead of relying on the library in the selected toolkit, all the source files in the Nucleus SE package contain conditional compilation directives. To configure Nucleus SE for the program, the developer needs to set several #define characters (more on this in the next article). This determines which API functions are compiled and, therefore, included in the program.

Nucleus SE improves this approach by offering an object that I call “extreme scalability.” Several aspects of kernel functionality can be turned on and off or configured in other ways using similar #define symbols. Thus, the developer has a point control over the use of memory.

Which API?

Nucleus SE has its own API, which will be described in detail in future articles. For many users, simply including these API function calls in code will be sufficient.

Some users may prefer to use another API: either standard or the one with which they are familiar. The Nucleus SE API is quite flexible and allows you to create a wrapper that converts an interface to another API.

One of the main goals of the Nucleus SE development is a high user-level compatibility with the Nucleus RTOS. Although the APIs are different, they are designed to be easy to match. A wrapper will be available to facilitate the use of the Nucleus RTOS API on the Nucleus SE.

In the next article, we will continue to look at the Nucleus SE and pay special attention to the internal structure and deployment of the RTOS.

Source: https://habr.com/ru/post/418601/


All Articles