Have you ever had a conversation with your boss or a colleague about embedded software only to discover that you were talking past each other? Communicating embedded software architecture design intent often comes with assumptions based on the persons experience. You might view architecture design from the perspective of resource constrained microcontroller-based systems. Your boss might consider architecture from an application processor perspective. How you design your architecture will depend on the embedded software classifications of the system.
There are many different ways that we can classify embedded software. There are five simple embedded software classifications that I find help me to adjust my perspective to best understand the system at hand.
Let’s explore 5 simple embedded software classifications that you need to know to communicate and design your system successfully.
Embedded Software Classifications #1 – Baremetal
A baremetal embedded system utilizes a software architecture that does not rely on an operating system. Typically, a baremetal architecture will be event-driven, rely heavily on state machines, and/or use very simple cooperative task scheduling. Developers need to understand the underlying processor very well because there is no operating system to abstract out the low-level details.
You will typically find a baremetal software design on resource constrained devices such as 8-bit, 16-bit, and some 32-bit microcontrollers. However, resource availability is not a constraint for baremetal systems. You can design a baremetal architecture and implement it for any embedded processor. Unfortunately, the more sophisticated the processor, the more complex the implementation can become.
Baremetal architectures and implementations are recommended for products that have limited functionality, use a resource constrained microcontroller, have strict real-time requirements, and minimal need for scalability.
Embedded Software Classifications #2 – Real-Time Operating System (RTOS)
Embedded software architectures that utilize a real-time operating system have dramatically increased over the last several years. An RTOS-based embedded system typically has more complex timing requirements than a bare-metal architecture can manage. The RTOS abstracts out some low-level details, such as task scheduling, while also providing a developer with tools for task synchronization (semaphores and flags), data protection (mutexes), and communication (queues).
You typically find an RTOS software design on 32-bit microcontrollers and small application processors. While you might find them on a 16-bit processor, an RTOS typically needs at least 24 kilobytes of flash and 32 kilobytes of RAM to be used effectively. These requirements put a lower limit on where the use of an RTOS can be effective.
An RTOS can add additional complexity to a design, mainly when using preemptive task scheduling. There is an opportunity to starve threads, create priority inversions, and even deadlocks if the designer is not careful. However, an RTOS can provide you with the ability to quickly scale a system, improve maintainability, and gather more sophisticated performance about the system than is available on a bare-metal system.
RTOS-based architectures and implementations are recommended for products with complex timing requirements, use a modern microcontroller, benefit from multitasking, and need to scale or reuse application pieces.
Embedded Software Classifications #3 – “Full” Operating System
An embedded software architecture can leverage an entire operating system when using a sophisticated enough processor like an application processor. For example, embedded Linux can be considered a full operating system. I don’t include an RTOS in this category because an RTOS is a specialized, resource-constrained operating system, unlike embedded Linux. Designers have full access to libraries and operating system resources that they would if they were developing desktop or mobile applications.
You typically find an operating system software design on 32-bit application processors like a Raspberry Pi. However, these processors are complex enough that an operating system is required to manage all their resources. Now, that doesn’t mean you can’t go bare-metal or use an RTOS; it just means complexity and development time dramatically increase.
A full operating system can remove the burden of memory constraints from a developer. In addition, you can often get non-embedded software folks involved. The software specialization is much less for applications built on an operating system.
Full operating system architectures and implementations are recommended for products without strict real-time requirements, use a modern microprocessor, benefit from high levels of abstraction, and need to scale or reuse application pieces.
Embedded Software Classifications #4 – Container / Microservices
Microservices and containers are design types often found in the cloud, mobile, and desktop computing. However, they are quickly finding their way into embedded systems. I’ve lumped these two together because the architecture design strategies one uses are similar, even though the underlying technology is different.
Microservices structure an application as a collection of loosely coupled services, independently deployable and easy to maintain (if done right). A microservice builds applications as a collection of small autonomous services developed for a business domain. A microservice provides a loosely coupled service with a specific feature in mind.
Relatively resource-constrained embedded systems such as microcontrollers can run microservices. However, they often require at least the same amount of memory needed to run an RTOS. A microservice comprises the service itself, an inbound and outbound message queue, and log and status information.
Microservices can add additional complexity to a design by requiring an orchestrator and runtime environment. By no means is this a deal breaker, but you must be careful with the resources you use and carefully monitor the real-time responses of your system. However, microservices can provide very scalable systems that are easy to maintain and update in the field.
I would recommend using microservices in applications that require in-field updates, scalability, and modern Agile processes and benefit from a distributed model.
Containers are an implementation paradigm that can host microservices. Each container is an isolated sandbox that may run one or more microservices. Containers are often independently deployable and easy to maintain. A series of containers build the foundation for a more extensive application. Again, containers and microservices are closely related; the container provides an additional layer of isolation and separation for the microservices to run in.
At least a modern microcontroller is required to leverage containers. Each technology vendor is slightly different, but some claim the ability to use as little memory as an RTOS. However, most I’ve investigated target IoT applications and expect around 256 kilobytes of flash.
Containers are a modern architectural implementation that can add flexibility, scalability, and portability to an embedded application. They’ve been used in other areas of software for several years successfully. The biggest constraint to date has been size and performance.
I recommend using containers in applications that require in-field updates, scalability, additional security, and modern Agile processes.
Embedded Software Classifications #5 – Hybrid
Hybrid systems take advantage of multiple classifications simultaneously. For example, you might have an application processor that uses embedded Linux. However, that processor might have a built-in microcontroller that uses a bare-metal approach to manage real-time responses.
Hybrid systems allow developers to leverage more than one design approach to benefit from more than one system type. Unfortunately, this flexibility often comes with an increase in system complexity if teams don’t carefully manage the interactions between the various pieces of their design.
Hybrid architectures and implementations are recommended for products with complex processing and real-time requirements that use multicore processors, benefit from high levels of abstraction and need to scale or reuse application pieces.
Embedded software systems can be classified into a wide range types. How you design and architect your embedded software will depend on the classification that you choose. Each classification will dictate the design patterns and tools that you use to architect and implement your system. The next time you sit down to design a system, or discuss one, start by specifying the system type before proceeding. You’ll find that this simple exercise will help you get on the right page.