Rationale
M2OS aims at providing an alternative framework for programming small microcontrollers. Compared to the traditional approach based on sequential C/C++ code, M2OS offers two interesting characteristics:
- Multitasking: M2OS allows to implement multitasking applications even in the smallest microcontrollers.
- Safe programming language: the Ada language includes many safety characteristics (e.g., strong typing or contract-based programming among others) that are very useful for embedded systems.
Consequently, M2OS allows to apply the advanced techniques used in high integrity systems (i.e. aircraft flight control, medical devices, critical industrial control, Advanced driver-assistance systems, etc.) to the smallest MCUs used by industry and hobbyists.
Main features
- Small memory footprint.
- Simple scheduling policy based on non-preemptive one-shot tasks.
- Easy connection to external devices (Arduino Uno target).
- Allows using all the interesting features of the Ada Languaje.
- Advanced tasking features.
- Synchronization mechanism for many-cores (M2OS-mc).
Small memory footprint
The footprint of M2OS stub applications is small enough to fit in the reduced memory of the smallest microcontrollers.
The table below shows the sizes in bytes of some stub applications compiled for M2OS for Arduino Uno with full optimization options enabled:
text | data | bss | total | |
---|---|---|---|---|
Two periodic tasks | 3502B | 188B | 64B | 3754B |
Ten periodic tasks | 6374B | 284B | 296B | 6954B |
One periodic task and one task activated in a suspension object | 3958B | 404B | 56B | 4418B |
One periodic task and one task activated in a PO entry | 4446B | 322B | 79B | 4847B |
In the examples shown in the table, the stack size required by the run-time and kernel primitives always remains under 100B.
Scheduling policy
Tasks stacks require quite large amount of memory that could rapidly exhaust the RAM available in a small MCU. Consequently, in such small systems it is paramount use some kind of “stack sharing ” among tasks.
M2OS implements the one-shot non-preemptive scheduling policy:
- One-shot tasks: tasks which do not keep any local state in the stack between releases. They are made of initialization instructions (executed only at the first release of the task) and job instructions (executed at subsequent releases). Job instructions must end in a blocking operation to wait for the next release event.
- Non-preemptive scheduling: once the CPU is allocated to a tasks it is not released until the task calls a blocking operation.
With this scheduling policy the same stack area can be used by all the tasks and, consequently, the system only needs to allocate a stack area large enough to fit the largest task stack.
Connection to external devices (Arduino Uno)
One of the strongest aspects of the Arduino Uno is its connectivity. M2OS facilitates this connectivity by providing bindings to some standard, third party and M2OS specific libraries.
More details in the Arduino Uno documentation section.
Ada characteristics
Most features of the Ada language are interesting for small embedded systems. Ada features allow applying modern software engineering techniques and producing safe and reliable software:
- Strong typing.
- Scalar ranges.
- Array bounds checking.
- Programming by contract.
- Representation clauses.
- Generic programming.
- Run-time checking.
- Advanced modularity mechanisms (packages with specification separated from implementation).
- Concurrency primitives included in the language (tasks, protected objects, suspension objects, timing events, …).
- Interface to other languages (C, C++, …).
- etc.
Tasking features
Tasking constructs:
- Tasks
- Protected objects
- Synchronous task control
- “Delay until” statements
- Timing events
The same restrictions than in the Ravenscar profile (a subset of the Ada tasking features designed for safety-critical hard real-time computing):
- Tasks restrictions: static number of tasks, know at compile time. Tasks cannot terminate.
- Protected objects restrictions: a maximum of one entry per object and with a maximum of one task queued at any time on that entry. The entry barrier must be a single Boolean variable (or a Boolean literal).
Synchronization mechanism for many-cores
The version of M2OS for many-cores (M2OS-mc) includes a synchronization mechanism to communicate tasks in different cores. The mechanism is inspired in the ARINC’s sampling ports.
M2OS-mc is currently implemented for the Epiphany III processor. More details in the Epiphany section.