Embedded Applications
An embedded application is a software product placed permanently inside some kind of device to perform a very specific set of functions.
The software is typically specialized for particular hardware with a specific purpose that must meet time, size, energy, and memory constraints.
As an example, some embedded applications are designed to run for months or years in a row without being turned off or receiving a reset command. It is used in areas from agriculture to space probes and more.
Elevators are a good example of embedded applications you can find in everyday life. They are designed to run for decades.
Introduction
There are some fundamental concepts related to embedded application development.
- Real-Time
-
Embedded applications receive continuous inputs, process the data, and generate outputs. The processing must often be performed in a short period of time.
As an example, some applications demand object detection in live stream videos, where processing involves inference and bounding boxes displayed on each frame.
- Fault-Tolerance
-
Is the capability of an embedded system to survive in the presence of faults? Faults can be caused by power cuts, hardware damaged parts, overheating, and more. The embedded software must be capable of detecting faults and making decisions according to how critical a fault is.
As an example, an embedded system working inside an airplane must be capable of identifying any possible fault and making decisions to keep the aircrew safe. Decisions can be as simple as sending an alert or as complex as performing changes in the command control.
- Portability
-
Is the measure of how easy it is to use the same embedded software in multiple environments? It requires generalized abstractions between the application program logic and the low-level system interfaces.
As an example, embedded devices used in domotics applications must be adjustable no matter the place where they have to be installed.
- Reliability
-
Is the survival probability of the system when the function is critical during the run time? As an example, embedded systems used in self-driven cars must be able to make decisions in runtime, where many tasks are critical to keep passengers and pedestrians safe. In this case, reliability must be as high as possible.
- Flexibility
-
An embedded system must be built with built-in debugging opportunities, allowing remote maintenance. For example, embedded systems in a satellite which must collect various types of data and send it back to a central station. If at some point the satellite loses control, people from the station should be able to make a diagnosis trying to reestablish the system. That is why flexibility is vital while designing an embedded system.
C++ Application Development
The C++ programming language has clear advantages when developing embedded and regular software products:
-
C++ is a standardized, well-known, popular language. The community is more dynamic and regularly updates the language and libraries through the ISO certification process. Regular embedded developers do not like abstractions and are often not interested in software engineering practices.
-
C++ is nearly a superset of C90 used in GCC.
-
The C subset of C++ is just as efficient as C.
-
C++ supports cleaner code in several significant cases. It provides better abstractions through support of multiple paradigms.
-
C++ makes it easier to write and enforce cleaner interfaces. Fewer bugs are delivered with the application due to more powerful constructs and compiler checks.
-
C++ never requires uglier code.
-
C++ is not a panacea, but it is an improvement. Projects finished sooner due to higher productivity. The learning curve to C++ craftsmanship is steep. Embedded developers have to commit to becoming software professionals.
C++ has way better support for unit and integration testing. The libraries are easier to use and better maintained. Modern approaches like TDD and BDD can be used. The quality of the delivered solution is often strikingly improved with these practices. |
Use standard tools:
-
Compiler chain for the target platform
-
CMake and CMake toolchain file for the above compiler chain including a linker script file
-
Static analysis tools integrated in the delivery pipeline
-
Continuous integration and delivery
-
Doxygen to document the source code
-
Package manager
You are free to use other languages such as Rust, Ada, or Python for developing embedded applications. Beware that the community support and the availability of libraries and tools are not as extensive as for C++. |
Realtime Operating System
The Actor Model is a powerful and efficient design approach for reactive and embedded applications. Actors require the creation of tasks, message queues for inter-task communication, and timer services. Support for interrupt routines shall also be available.
The C language and C++ language have added support for multithreaded and synchronization primitives since version 11. This standard API could become the preferred approach to developing multithreaded and realtime application. The various RTOS could disappear as standalone solutions. They should be relegated as variant implementation of standard library functions. |
The ARM world has defined an abstraction layer for realtime operating systems and published the functions under CMSIS RTOS-2.
RTOS and Application Partitioning
Most mainstream operating systems are built on the assumption that a system has a single privileged operating system running several unprivileged applications. Running multiple operating systems on the same platform requires a Hypervisor. Embedded systems often use a native hypervisor running on bare metal.
Application partitioning is not available to STM32 microcontrollers. Transparent partitioning requires a hypervisor to virtualize access to hardware components. The ARM Cortex M cores used in the STM32 products do not provide the necessary hardware support to implement a hypervisor [1].
The privileged and unprivileged modes are not sufficient to define a hypervisor. RTOS cannot be run in the unprivileged mode because they need access to the processor registers and interrupts.
Theoretically, it could be possible to implement a supervisor in privileged mode and a scheduling engine in unprivileged mode. The supervisor needs to provide interrupt handling, timers, task switch, and potentially access to privileged instructions or locations. It must transfer data to and receive from the scheduler.
This approach is incompatible with available RTOS products. It would be necessary to implement and maintain a proprietary scheduling engine emulating the services of a realtime operating system. This approach is called paravirtualization and requires a partial rewrite of the realtime kernel. For example, you could implement the services and data structures specified in the CMSIS_OS version 2 module [2].
Tips and Tricks
Here are some tips and tricks to help you develop embedded applications:
-
Use C++ as programming language for your embedded applications.
-
Use a 64-bit processor and plenty of memory for your embedded applications. Optimizing your hardware platform is only worth the effort if you are producing ten thousand units per year or more.
-
Use an open source RTOS like freeRTOS to manage your tasks. Avoid Programmable Logic Controller programming model for embedded applications if possible. They do not scale well and are not as efficient as a multitasking model.
-
Simulate your embedded application to run as much as possible on your development machine. Development tools on your development machine are more powerful and easier to use than on the target platform.
-
Use Git and a platform like GitHub or GitLab to manage your source code.
-
Beware of the various standards and regulations that apply to your embedded application.
Links
-
Agile Architecture Principles Marcel Baumann. 2019.
-
Agile Code is Clean Code! Marcel Baumann. 2019.
-
Agile Architecture within Scrum Marcel Baumann. 2019.
-
Agile Component Design Marcel Baumann. 2020.
-
Legacy Systems Refactoring Marcel Baumann. 2020.
-
How Agile Collaborators Learn Marcel Baumann. 2020.