Selection of your embedded system’s software architecture
In an earlier blog post, we discussed the benefits and
drawbacks of both RTOS and bare-metal architectures. Bare metal is simply
defined as firmware development that takes place directly on your hardware,
without any intermediary layers. However, does this imply that bare metal exclusively
refers to firmware development in assembly? How about using memory-mapped
registers directly in C development, with the aid of header files that contain
macros for such addresses? Is that metal exposed? We can't always be certain
how a C compiler will convert our code to machine code because C is a
high-level language.
Why do vendor-provided HALs appear in C? That is an
additional layer of abstraction. Why do schedulers have sequencers? Although
the notion of bare metal is frequently ambiguous, many developers consider
firmware development in C utilizing HAL to be bare metal. job preemptiness, or
the capacity to allocate resources to a job with a higher priority, is the
primary distinction between RTOS and everything that isn't RTOS.
Since it's easy to get confused about what exactly constitutes bare metal,
we'll talk about a few architectures in this piece that aren't RTOS but might
be bare metal. Superloop is the most basic one that all embedded developers
begin with.
1. Superloop
The simplest bare-metal strategy is Superloop. Code is
executed on each iteration of the endless loop. The Arduino "loop"
function is the most well-known example. The most popular method of managing
the execution of individual functions is through the use of flags, which are
typically set by interrupts. Superloops carry out instructions in a sequential
fashion. Setting a flag from a timer ISR or determining how much time has
passed since the last iteration are common methods for time control.
We'll use a small piece of code to
demonstrate how to take data from a sensor in the event that a GPIO interrupt
is raised, process it, and send it to the server every ten seconds.
Superloop quickly ends in spaghetti code. It can be difficult to detect and fix errors, modify the logic of an existing application, and add new capabilities. Despite its simplicity, superloop is still frequently used to develop quick proof-of-concept solutions with restricted capabilities. Because it is difficult to predict how long a single task will take to complete, it is not a good option for time-sensitive systems. Furthermore, no framework exists that can ensure the timely completion of higher-priority activities.
One will begin to seek out more sophisticated solutions
that are easier to manage and more adaptable for adding new features. A
sequencer is the next step in the superloop's natural growth. We'll add tasks
(function pointers) to a sequencer, which will then carry out those tasks,
rather than designing logic that uses flags set in an ISR to control the
execution of specific functions.
2. Sequencer
Sequencer is a straightforward
design pattern that lets you add tasks that must be completed to the sequencer
module. The sequencer will run indefinitely and complete the jobs that are
accessible. The sequencer can receive tasks from internal (timer) or external
interruptions. In order for the sequencer to execute the first available tasks
with a greater priority, tasks can also be given a priority. To guarantee
deterministic behavior, a watchdog is deployed to guarantee the task duration,
and time-critical tasks must internally ensure execution time or call frequency
using timers.
The code is simpler and cleaner,
which is the first thing we notice from the above image. After the execution,
there are no flags that need to be put in ISR and reset. A great illustration
of bare-metal event-driven design is Sequencer.
A sequencer can be implemented in a variety of ways; tasks can be added and
defined during compile time with predetermined priority and indices, and they
can be scheduled to execute during run time as required.
3. Cooperative scheduler
A pattern that expands on the
sequencer is called a cooperative scheduler. It is a hybrid of a virtual timer
and a sequencer. Because it only permits one interrupt—a timer interrupt that
serves as a tick for the entire system—it is more constrained in terms of
timing needs. The developer also establishes an initial delay, following which
tasks are scheduled to be completed at a predetermined period.

Tasks are carried out at
predetermined intervals thanks to the cooperative scheduler. The firmware
developer is still in charge of ensuring job duration and preventing task
overlap, though. Ticks are created using a timer, and a data structure
describing individual jobs is updated using the sch_update function. These
structures include data members for counting the ticks and a function pointer
for a task. Sch_dispatch is called from the super loop rather than the timer
ISR to ensure updates of data structures describing tasks.
4. When to choose bare-metal architectures and when to go
with RTOS?
RTOS was briefly explained in a prior blog article. A
preemptive scheduler is one of RTOS's primary parts. It is a component of RTOS that
controls how tasks are carried out. Based on the tasks' current status and
priority, the scheduler decides which one should be completed next. It is
intended to offer deterministic task execution. This indicates that the tasks
are completed on schedule and with predictable results.
An RTOS is typically a suitable fit for Internet of Things
applications that make use of certain networking protocols. It is feasible to
run application logic and networking stacks on bare metal event-driven systems.
Writing discrete actions based on a ticker event is more difficult than
defining an RTOS task and assuming it would continue indefinitely.
Though it's not always the case, an RTOS appears to be the
recommended design for embedded systems. RTOS gives you the infrastructure to
guarantee scalability and deterministic behavior, but it comes at the expense
of using more resources. It needs a flash to hold the instructions and some RAM
to keep things operating.
Navigating the intricacies of embedded system software architecture can be
challenging, whether you're deciding between bare metal or RTOS, or optimizing
a superloop-based design. At Silicon Signals, we
specialize in developing tailored solutions for embedded systems, from
bare-metal firmware to RTOS integration and beyond.
Our expertise ensures your software architecture is optimized for
performance, scalability, and reliability. Ready to take your embedded system
design to the next level? Connect with us today and let’s build
smarter systems together!"

Comments
Post a Comment