0% found this document useful (0 votes)
21 views16 pages

Ardu

The paper introduces ARTe, a real-time extension for the Arduino programming model that enables multitasking by allowing concurrent execution of multiple loops at different rates. This extension utilizes a low-footprint real-time operating system to enhance the efficiency of resource usage while maintaining adherence to the original Arduino programming style. Experimental results demonstrate its advantages, including improved control over latencies and energy consumption, with a minimal increase in overhead and memory usage, exemplified through a case study involving a mechanical ventilator for COVID-19 patients.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views16 pages

Ardu

The paper introduces ARTe, a real-time extension for the Arduino programming model that enables multitasking by allowing concurrent execution of multiple loops at different rates. This extension utilizes a low-footprint real-time operating system to enhance the efficiency of resource usage while maintaining adherence to the original Arduino programming style. Experimental results demonstrate its advantages, including improved control over latencies and energy consumption, with a minimal increase in overhead and memory usage, exemplified through a case study involving a mechanical ventilator for COVID-19 patients.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

The Journal of Systems & Software 186 (2022) 111185

Contents lists available at ScienceDirect

The Journal of Systems & Software


journal homepage: www.elsevier.com/locate/jss

ARTe: Providing real-time multitasking to Arduino✩



Francesco Restuccia a,b , , Marco Pagani a , Agostino Mascitti a , Michael Barrow b ,
Mauro Marinoni a , Alessandro Biondi a , Giorgio Buttazzo a , Ryan Kastner b
a
Scuola Superiore Sant’Anna Pisa, Italy
b
University of California San Diego, USA

article info a b s t r a c t

Article history: In the last decade, thanks to its modular hardware and straightforward programming model, the
Received 24 September 2020 Arduino ecosystem became a reference for learning the development of embedded systems by various
Received in revised form 20 November 2021 users, ranging from amateurs and students to makers. However, while the latest released platforms
Accepted 6 December 2021
are equipped with modern microcontrollers, the programming model is still tied to a single-threaded,
Available online 10 December 2021
legacy approach. This limits the exploitation of the underlying hardware platform and poses limitations
Keywords: in new application scenarios, such as IoT and UAVs.
Real-time This paper presents the Arduino real-time extension (ARTe), which seamlessly extends the Ar-
Multi-tasking duino programming model to enable the concurrent execution of multiple loops at different rates
Arduino configurable by the programmer. This is obtained by embedding a low-footprint, real-time operating
Educational
system in the Arduino framework. The adherence to the original programming model, together with
the hidden support for managing the inherent complexity of concurrent software, allows expanding
the applicability of the Arduino framework while ensuring a more efficient usage of the computational
resources. Furthermore, the proposed approach allows a finer control of the latencies and the energy
consumption. Experimental results show that such advantages are obtained at the cost of a small
additional overhead and memory footprint. To highlight the benefits introduced by ARTe, the paper
finally presents two case studies, one of such in which ARTe has been leveraged to rapidly prototype
a mechanical ventilator for acute COVID-19 cases. We found that ARTe allowed our ventilator design
to rapidly adapt to changes in the available components and to the evolving needs of Intensive Care
Units (ICU) in the Americas.
© 2021 Elsevier Inc. All rights reserved.

1. Introduction and expanding range of features and devices. Over the years, this
approach proved to be successful and pushed the producers to de-
The Arduino project started in the early 2000s with the goal velop more and more powerful boards, still compatible with the
of providing a simple framework to support people with very original programming model, as well as extension boards (namely
limited programming skills in the development of embedded shields) to expand hardware features and interoperability.
projects. This purpose was pursued by creating a user-friendly de- The programming model requires the application developer to
velopment environment based on a simple programming model. provide a C file that only defines the setup() function, executed
Then, the team started a company to design and produced a at the startup to initialize the system, and the loop() function,
simple and low-cost board to create working prototypes inter- which executes endlessly. The simplicity of this solution signif-
acting with the physical world. The growth of the project was icantly alleviates the learning phase and motivates the base of
fueled by the decision to adopt an open-source approach that the massive number of projects using Arduino. However, in the
aggregated a community keen on supporting the development, last decade target applications became more and more complex,
creating examples and tutorials, and providing libraries for a wide including multiple sensors and actuators, and required interac-
tion with other systems through communication devices. These
✩ Editor: Neil Ernst. scenarios proved to be challenging to get along with the Arduino
∗ Corresponding author. programming model. For instance, a typical solution adopted
E-mail addresses: [email protected] (F. Restuccia), by Arduino users to deal with such a complexity consists in
[email protected] (M. Pagani), [email protected]
offloading the communication stack to a shield board that is gen-
(A. Mascitti), [email protected] (M. Barrow), [email protected]
(M. Marinoni), [email protected] (A. Biondi), erally more powerful than the microcontroller within the Arduino
[email protected] (G. Buttazzo), [email protected] (R. Kastner). board. Delegating multi-rate sensors and communication devices

https://doi.org/10.1016/j.jss.2021.111185
0164-1212/© 2021 Elsevier Inc. All rights reserved.
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Listing 1: Implementation of functions executing at different Listing 2: Implementation of functions executing at different
rates making use of delay. rates making use of millis().
int count = 0; // it counts the number of minor cycles #define N 3 // number of functions
int T1 = 10; // period (ms) for executing function1
int T2 = 25; // period (ms) for executing function2 int T[3] = {10, 25, 50}; // function periods (ms)
int T3 = 50; // period (ms) for executing function3 unsigned long time; // current time (ms)
int Tmin; // GCD of the periods (minor cycle) unsigned long prevtime; // previous time (ms)
int Tmaj; // lcm of the periods (major cycle) int i;
int K1; // counter value for triggering function1 void (*func_ptr[3])() = {function1, function2,
int K2; // counter value for triggering function2 function3};
int K3; // counter value for triggering function3
time = millis();
Tmin = GCD(T1, T2, T3); // minor cycle for (i=0; i<N; i++) prevtime[i] = time - T[i];
Tmaj = lcm(T1, T2, T3); // major cycle
while (1) {
K1 = T1/Tmin; // number of minor cycles in T1 for (i=0; i<N; i++) {
K2 = T2/Tmin; // number of minor cycles in T2 time = millis();
K3 = T3/Tmin; // number of minor cycles in T3 if (time - prevtime[i] >= T[i]) {
H = Tmaj/Tmin; // number of minor cycles in Tmaj prevtime[i] = time;
(*func_ptr[i])();
while (!end) { }
if (count%K1 == 0) function1(); }
if (count%K2 == 0) function2(); }
if (count%K3 == 0) function3();
count++;
if (count == H) count = 0;
delay(Tmin); // suspend for a minor cycle
} and their execution times are comparable with their periods,
this approach does no longer guarantee a regular activation of
the activities, since each function will delay the next one. Fig. 1
illustrates two examples of schedule: Fig. 1a shows the case in
which computation times are negligible, whereas Fig. 1b shows
to external boards produces complex solutions that are also in-
the case in which they are not (namely, C1 = 2.5 ms, C2 = 5 ms,
efficient in terms of cost, weight, and power consumption. This
C3 = 10 ms). The shadowed areas denote the delay at the end of
problem is even more evident with modern Arduino platforms
the loop and the number above each area represents the value of
(e.g., the Arduino Due board), where the main microcontroller
the counter during that interval.
remains mostly underutilized.
Note that, even in the case of negligible computation times,
1.1. Limits of the Arduino programming model the functions tend to accumulate a delay that, after a number
of executions, will cause a period skip. For instance, function1
The Arduino programming model works fine for simple con- skips a period every six instances (see intervals [50 ,60] and [110,
trol systems where sensors have to be acquired at the same 120] in Fig. 1a).
frequency, but becomes problematic when the control system In the case of non-negligible computation times (Fig. 1b),
requires actions that need to be triggered at different rates. function1 skips five periods out of eleven, and two of them are
Consider, for example, a system equipped with an infrared consecutive ([90, 100] and [100, 110]). Also, function2 does not
sensor, an inertial sensor, and a communication transceiver, execute properly, since only one instance is executed in the inter-
which need to be acquired with different periods, e.g., dictated val [25, 75], equivalent to two full periods. It is worth observing
by the sensor dynamics and the computation times required to that such a misbehavior is not due to an overload (in fact the
process the corresponding data. Suppose that the infrared sensor overall processor utilization is U = 2.5/10+5/25+10/50 = 0.65,
has to be sampled every T1 = 10 ms, the inertial sensor every i.e., the 65%), but it is due to that specific implementation.
T2 = 25 ms, and the communication device every T3 = 50 ms. A better solution, sometimes used by Arduino developers, is
The solution typically adopted by Arduino users in these situa- to keep track of the activation times by the function millis(),
tions is to program the main loop to execute with a period Tmin which returns the number of milliseconds passed since the pro-
(also called minor cycle) equal to the greatest common divisor gram started and activate each activity after a period is passed.
(GCD) of the three periods and trigger the other activities every An implementation following this approach is reported in Listing
Ki executions of the main loop. In our example, we have: 2.
T3 The implementation reported in Listing 2 reduces most of the
Tmin = 5 ms; K1 =
T1
Tmin
= 2; K2 = T2
Tmin
= 5; K3 = Tmin
= 10. (1) delays introduced by the previous one, but it still does provide a
A possible implementation of this approach is to use a counter general solution to the problem of executing functions at different
that counts the number of minor cycles and calls the function that rates. Fig. 2 illustrates two schedules produced for different com-
has to be executed with period Ti when the counter reaches the putation times. Fig. 2a refers to the case in which computation
value Ki = Ti /Tmin , as shown in Listing 1. times are C1 = 2.5 ms, C2 = 5 ms, C3 = 10 ms, leading to a
To avoid the counter overflow, the counter has to be reset total processor utilization U = 0.65, whereas Fig. 2b refers to the
when it reaches the value of the least common multiple (lcm) of case in which computation times are C1 = 5 ms, C2 = 5 ms,
the periods, also called major cycle. This solution works fine when C3 = 15 ms, leading to a total processor utilization U = 1.0.
the execution times of the three functions are negligible with While the schedule in Fig. 2a respects all the specified periods,
respect to the periods (e.g., for the case of blinking LEDs). How- the one in Fig. 2b does not, since only three instances of function1
ever, when the functions perform more complex computations are executed out of five (in fact, the function is not executed in
2
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Fig. 1. Schedule obtained for the three functions under the solution illustrated in Listing 1, when their computation times are negligible (a) and when they are not
(b). Triangles below the axes denote activation times and vertical bands represent minor-cycle suspension intervals (the number on top is the value of the counter).

Fig. 2. Schedule obtained for the three functions under the solution illustrated in Listing 2, for different values of the computation times.

the intervals [10, 20], [30, 40], [60, 70], [80, 90], and so on). The provided by a real-time operating system. This is done by keeping
problem is that the functions are executed one after the other the scheduler and the operating system transparent to the pro-
and cannot be preempted (i.e., temporarily interrupted to be later grammer, so that each loop can be developed by following the
resumed) during their execution. For instance, in the schedule of classical Arduino programming style. The software development
Fig. 2b, at time t = 10 function1 should be reactivated, but of the overall application is actually simplified, since the user does
it cannot run since the sketch will call it in the next cycle, after not have to explicitly trigger the functions, as in the previous
the execution of function3, which completes at time t = 25, implementation shown above.
i.e., in the middle of the third period of function1. This type Listing 3 reports the code that implements the three functions
of problem can only be solved by handling the functions by a according to the proposed extended programming model.
preemptive scheduler.
The solution presented in this paper extends the Arduino Paper structure. The rest of the paper is organized as follows:
programming model by allowing the user to specify multiple Section 2 presents an overview of the Arduino framework, the
loops, each with its own execution period, and by treating each proposed extensions to provide multitasking, and the Erika Enter-
loop as a concurrent thread scheduled by a preemptive scheduler prise kernel that is leveraged in the proposed approach; Section 3
3
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Table 1
Listing 3: Implementation of functions executing at different Features comparison of popular Arduino boards.
rates using the ARTe programming model. Arduino Processor Arch. Freq. SRAM NV Memory

void setup() { UNO ATmega328 8 bit 16 MHz 2 KB 1 KB


DUE Cortex M3 32 bit 84 MHz 96 KB 512 KB
<<setup code>>
Zero Cortex M0+ 32 bit 48 MHz 32 KB 256 KB
}

void loop() {
<<background code>> 2. Background and state of the art
}

void loop1(10) { While the user experience for Arduino developers remained
function1(); mostly unaltered along the years, the internals of the Arduino
} framework evolved to include new features and increase its mod-
ularity and portability. This section first presents the current
void loop2(25) { status of the official Arduino framework and then provides an
function2(); overview of some custom extensions proposed by other authors
} to support multitasking in Arduino. Finally, the section illustrates
how the work proposed in this paper advances the state of
void loop3(50) { the art and introduces the main features of the ERIKA Enter-
function3();
prise (Anon, 0000a)1 real-time operating system (RTOS), which has
}
been leveraged to realize the proposed solution.

Listing 4: Implementation of an application similar to the one 2.1. The Arduino framework
proposed in Listing 3 using the FreeRTOS-Arduino programming
model. Arduino is an open-source project based on easy-to-use em-
#include <Arduino_FreeRTOS.h> bedded hardware and software. The Arduino ecosystem consists
of a set of single-board microcontrollers and a software frame-
void TaskLoop1(void *pvParameters); work that comes with an integrated development environment
void TaskLoop2(void *pvParameters); (IDE). Over the years, many Arduino boards with different com-
void TaskLoop3(void *pvParameters); putational and I/O capabilities have been released. The first board
has been the Arduino UNO, which is based on a Microchip AT-
void setup() {
xTaskCreate(TaskLoop1,(const portCHAR *)"loop1",128, mega microcontroller running at 16 MHz and offers 14 digital
NULL,2,NULL); I/O pins and six analog input pins. The original Arduino UNO
xTaskCreate(TaskLoop2,(const portCHAR *)"loop2",128, board has been later updated with different releases and is still
NULL,2,NULL); supported nowadays. However, it offers limited computational
xTaskCreate(TaskLoop3,(const portCHAR *)"loop3",128, capabilities and small amount of volatile (SRAM) and non-volatile
NULL,2,NULL); (NV) memory. To overcome these limitations, the Arduino com-
} munity released more advanced boards such as the Arduino DUE
and Arduino Zero based on ARM Cortex microcontrollers. Both
void loop(){ these boards dispose of more powerful computational and I/O
<<background code>>
capabilities with respect to Arduino UNO, and are hence better
}
void TaskLoop1(void *pvParameters) { suited for more complex application scenarios. Table 1 reports a
(void) pvParameters; feature comparison of these three Arduino boards.
for(;;){ The software side of the Arduino project consists of a software
function1(); framework, initially based on the Wiring project (Barragán, 2004),
} which includes an IDE in charge of the building process and the
} device flashing. A block diagram of the Arduino building process
void TaskLoop2(void *pvParameters) { performed by the IDE is illustrated in Fig. 3. Basically, the building
(void) pvParameters; process can be divided into two phases: a pre-processing phase
for(;;){ and a compilation-and-linking phase. During the pre-processing
function2();
phase, the Arduino framework performs a few transformations
}
} like adding additional headers and generating prototypes for all
void TaskLoop3(void *pvParameters) { the functions defined in the application source file, which is de-
(void) pvParameters; noted by sketch. Then, the source files are passed to the compiler
for(;;){ tool-chain to be compiled and linked with the Arduino libraries.
function3();
} 2.2. Related work
}
Several solutions are well known to support multitasking and
provide solutions to simplify the development of applications
on microcontrollers. An example is the work proposed by Ri-
describes the proposed approach, while Section 4 highlights rele- vas and Tijero (2019), which aims at simplifying the use of the
vant implementation details. Experimental results and use cases Ada safety language for the development of applications running
are reported in Section 5, whereas Section 6 states our closing
remarks. 1 ERIKA Enterprise project website: https://www.erika-enterprise.com/.

4
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Fig. 3. Arduino building flow chart.

on small microcontroller devices. However, it is not straightfor- for periodic activities. The user must explicitly specify ini-
ward to integrate some multitasking support in Arduino while tialization procedures and possible preemption points, with
minimizing the impact on its programming model and ensuring the result that code modifications are required to support
retro-compatibility. The Arduino programming model is based multitasking.
on the use of only two constructs: the loop() function and • Tasks are executed cooperatively. Under this multitasking ap-
the setup() function. The former contains the code that is proach, the context switch is triggered by the running task,
cyclically executed as long as the device is powered, while the which voluntarily yields the processor to other tasks. This
latter is executed at the startup of the device. This simple pro- increases the latency variability and the complexity in guar-
gramming model allows entry-level users to develop applications anteeing response-time bounds for the tasks.
in Arduino without requiring specific skills in programming a • No protection against task overruns. When a task instance
microcontroller. On the other hand, this model is not suitable runs longer than its period, the entire schedule can expe-
for multitasking as the user is limited to a single, sequential rience a domino effect, jeopardizing the whole application.
execution flow given by the code of the loop() function.
Several methods with different degrees of complexity have Many of such issues are originated by the fact that no operat-
been proposed to fill this gap. The most straightforward ones do ing system is adopted, hence forcing the user to implement some
not require any third-party library or extension, and just allow form of scheduling in the loop() function. This approach can be
defining the tasks as C functions to be executed in the standard particularly error-prone, especially for users that are not familiar
Arduino loop() function. The scheduling logic is implemented with scheduling techniques and concurrent programming.
with ad-hoc conditional statements and delay functions (such as FreeRTOS-Arduino (Barry, 0000) has been proposed to address
delay() and millis()) to mimic a periodic activation of the these issues. It is based on a porting of the FreeRTOS kernel
tasks. In this paper, this basic approach is adopted as a baseline as an Arduino library and provides fixed-priority preemptive
for comparison purposes: more details are provided in Section 5. scheduling. Despite being a powerful solution, FreeRTOS-Arduino
Other solutions were proposed by relying on the use of third- introduces several complications at the level of the program-
party libraries that implement multitasking in a way that is ming model, as it requires the user to be confident with both
similar to the one just discussed, but offering a more friendly the FreeRTOS API and concurrent programming, which are skills
interface to the developer. Some examples of such libraries are that typically exceed those of the general user of Arduino. A
the following: sample application developed following the Arduino-FreeRTOS
programming model is reported in Listing 4.
• The Scheduler library (Anon, 0000b) allows registering mul- Furthermore, FreeRTOS is not a static operating system, i.e., not
tiple loops in the setup function that will cyclically be all kernel code and data structures can be tailored to the ap-
executed at run-time. There is no control in terms of pe- plication at compile time. Therefore, it is characterized by a
riods and timing still relies on explicit delays, like in the larger footprint,2 and memory and run-time overhead with re-
original Arduino paradigm. In order to reduce the impact spect to those that would be actually required to handle a cer-
of loops with significant execution times, the library pro- tain set of tasks. This waste of resources can be a severe issue
vides a yield function that the application programmer can on resource-constrained platforms such as Arduino UNO and
explicitly use. Arduino Zero.
• SoftTimer (Kelemen, 0000) library enables multitasking by Another solution based on an RTOS is Qduino (Cheng et al.,
defining each task as a C++ object. The constructor of such
2015), which extends the Arduino framework with a custom
objects takes as arguments the period of the task and a
API to allow implementing concurrent loops with support for
pointer to a callback function. The callback functions are
mutual exclusion on shared resources. As for FreeRTOS-Arduino,
meant to be executed in a periodic non-preemptable fashion
Arduino users are required to acquire additional knowledge on
according to the task period. Tasks are registered in the
real-time concurrent programming and the specific Qduino API.
Arduino setup() function. This library originally prevented
In addition, Qduino only supports Arduino platforms based on
the use of the standard loop() function, hence breaking the
Intel x86 processors (e.g., Galileo, Arduino 101). Therefore, this
original Arduino programming model. This limitation has
solution is not compatible with the majority of Arduino boards.
been removed only recently.
Note also that the Arduino framework comes with a rich set of
• ArduinoThreads (Anon, 0000c) works similarly to the Sched-
libraries that have been developed to work under singletasking,
uler library discussed above but implements a more com-
i.e., their internal state can be left inconsistent whenever they
plex set of constructs to manage the execution of tasks in a
are suspended to execute other computational activities. Both
periodic fashion. This approach allows more flexibility but
FreeRTOS-Arduino and Qduino require explicitly managing mu-
requires a significant impact in terms of knowledge and
tual exclusion when using these libraries, hence complicating the
resulting application code.
programming model even for simple and typical operations that
Such a class of solutions suffer from the following drawbacks: are present in many Arduino example sketches.
• The programming model becomes more complex with respect
to the original one. Also, most of such extensions (with the 2 For instance, the footprint of a simple blink application with FreeRTOS on
exception of SoftTimer) do not provide explicit support Arduino UNO is 8264 bytes (25% of the available memory).

5
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Like FreeRTOS-Arduino and Qduino, also ARTe (Buonocunto


et al., 2016) relies on an RTOS to support multitasking, but differ-
ently from such previous approaches, it preserves the simplicity
of the Arduino programming model. ARTe is characterized by a
minimal impact in terms of footprint and run-time overhead. This
was possible by building ARTe upon the ERIKA Enterprise (Anon,
0000a) RTOS that, among other choices (e.g., FreeRTOS Anon,
0000d and NuttX Anon, 0000e), resulted in an excellent can-
didate to efficiently use the scarce computational resources of
Arduino platforms thanks to its static configuration at compile
time. The preliminary version of ARTe presented in Buonocunto
et al. (2016) did not provide support to handle shared variables
and mutual exclusion. Furthermore, the work in Buonocunto et al.
(2016) was conceived for older versions of the Arduino IDE, which
were designed in a monolithic way; thus, it was not possible to
customize the building process without modifying the IDE source Fig. 4. General architecture of the ARTe framework.
code. Consequently, Buonocunto et al. (2016) was based on a
customized version of the IDE, extensively modified to integrate
a custom parser and a modified build process to support the application objects must be known at compile-time and cannot
RTOS. However, this approach originates considerable limitations be changed at run-time.
in terms of portability and extensibility, as any new release of This approach is crucial for ensuring a small run-time over-
the Arduino IDE requires a porting of the extension presented head and contain the memory footprint, as it allows producing
in Buonocunto et al. (2016) while major updates of the IDE tailored images of the RTOS that are optimized for a specific
codebase may totally break compatibility. Thankfully, the most application. While designing an application, the programmer can
recent versions of the Arduino IDE include a more flexible build define the RTOS objects and the kernel configuration by using the
mechanism that allows developers and board manufacturers to OSEK Implementation Language (OIL). OIL files are translated by
customize the entire building process (Anon, 0000f). The mecha- RT-Druid, a tool included in the ERIKA developing environment,
nism works by exporting to the developer a set of hooks (i.e., code into a set of C source files that define the kernel configuration.
injection points) for each step of the building process. Once the kernel configuration files are generated, the customized
ERIKA kernel can be compiled together with the application code.
Aside from the standard OSEK/VDX features, ERIKA also pro-
2.3. This work
vides additional conformance classes, such as fixed-priority
scheduling with preemption thresholds (Wang and Saksena,
This paper presents a new version of ARTe (officially called
1999), Earliest Deadline First (EDF) scheduling algorithm (Liu and
ARTe v2 and referred to as just ARTe in the following) that
Layland, 1973), resource reservations (Marzario et al., 2004), and
introduces novel features to support multitasking and a radi-
hierarchical scheduling (Bertogna et al., 1991; Biondi et al., 2015).
cally different way to integrate multitasking in the novel Ar-
ERIKA provides two types of interrupt service routines (ISRs) for
duino IDE. In particular, such a new version of ARTe includes
handling interrupts: (i) fast interrupts, called Type 1 ISRs, and (ii)
an automatic protection mechanism for global variables and a
lower-priority interrupts, called Type 2 ISRs. Type 1 ISRs are meant
fine-grained mechanism that allows extending current Arduino to be used for short and urgent I/O operations, returning to the
libraries for thread safety. Both mechanisms are crucial for en- application without calling kernel services (e.g., the scheduler).
abling the seamless integration of the large Arduino codebase On the other hand, Type 2 ISRs can call selected kernel primi-
within the ARTe multi-threaded environment. Furthermore, ARTe tives and interact with the scheduler (e.g., activating a task), but
supports the most common Arduino platforms, i.e., Arduino UNO introduce a larger latency than Type 1 ISRs.
and Arduino Due.
Differently from Buonocunto et al. (2016), thanks to a new
3. Proposed approach
development available in recent versions of the Arduino IDE, ARTe
does not require any modification to the official source code of
This section presents a general overview of the approach pro-
the IDE and can easily be updated and maintained as a third-party
posed in this paper, with a particular focus on the extensions
plug-in module. to the original Arduino programming model and the integration
To keep the paper self-contained, a brief description of ERIKA within its toolchain.
Enterprise is reported next.
3.1. General architecture
2.4. ERIKA enterprise
The general architecture of the ARTe framework is illustrated
ERIKA Enterprise (Anon, 0000a) is an RTOS that offers a real- in Fig. 4. ARTe is designed to keep its programming model as sim-
time scheduler and resource managers suited for developing ilar as possible to the standard Arduino one, meaning that it sup-
highly-predictable applications on microcontrollers. ERIKA is ports the setup and loop functions with minimal modifications
characterized by a very small run-time overhead (in the order of a to their original behaviors.
few microseconds) and a tiny memory footprint (a few kilobytes). The key difference with respect to the standard Arduino pro-
ERIKA has been certified to conform to the OSEK/VDX (Anon, gramming model is that ARTe allows the user to execute con-
0000g) standard and implements the OSEK/VDX API. Following current tasks (such as loop_1, loop_2, . . . , loop_n in Fig. 4), whose
the OSEK/VDX standard, all objects provided by ERIKA, such definitions are substantially similar to the standard Arduino loop
as tasks, alarms, and semaphores, must be statically defined function. Each task (i.e., each loop) is executed in a periodic
alongside the application. That is, the RTOS configuration and all fashion and its period can be specified as an argument of the
6
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

corresponding function. The ARTe programming model is detailed


in Section 3.2. Listing 5: Example of periodic activities using standard Arduino
Since the original Arduino programming model has not been programming model.
originally designed to support multitasking, this feature may void setup() {
originate race conditions in accessing shared resources, such as << setup code >>*@void loop() static int ticks =
global variables, or shared peripheral devices. To address this 0;const int interval = 10;if (ticks activity1();if
issue and safely support multitasking, ARTe comes with two pro- (ticks activity2();if (ticks activity3();ticks +=
tection mechanisms for shielding shared resources. These mech-
interval;if (ticks == 210)ticks =
0;delay(interval);
anisms can then be leveraged by concurrent tasks to synchronize
with each other, e.g., to avoid leaving inconsistent a global data
structure or the internal state of a device in the presence of
a task preemption. In particular, to avoid requiring the user
More complex examples are presented in the following sec-
to explicitly synchronize the access to global variables under
multitasking, ARTe comes with a transparent protection that au- tions.
tomatically takes care of possible race conditions. This is accom-
plished by employing static code analysis and a form of wait-free
synchronization: further details are provided in Section 3.4.
ARTe also allows tasks to use Arduino libraries (both the
official ones and those provided by third-party contributors).
However, as Arduino libraries are typically not designed to sup- 3.3. Example of an ARTe application
port multitasking, some modifications to them are required. To
this purpose, ARTe offers a simple locking interface for shared
resources protection, which is discussed in details in Section 3.5.
A set of popular and essential Arduino libraries have already been
modified and are distributed with the ARTe package. With the traditional Arduino programming paradigm, appli-
Under the hood, ARTe adopts the ERIKA Enterprise RTOS. All cations consisting of concurrent periodic activities can be pro-
the RTOS services and their configuration are completely masked
grammed using the (so-called) loop scheduling technique. Listing
to the ARTe user. ARTe already supports the Arduino UNO and Ar-
duino DUE platforms.3 The support for Arduino Zero is currently 5 shows a sample application that comprises three periodic tasks:
under development (no significant differences in the implemen- activity1, activity2, and activity3, having periods of T1 =
tation are expected). Thanks to the modular implementation and
the flexibility of ERIKA, limited efforts are envisaged to support 10 ms, T2 = 30 ms, and T3 = 70 ms, respectively. The delay
other popular Arduino platforms. value at the end of the Arduino loop defines the granularity of
the periodic activations. The optimal delay value corresponds to
3.2. ARTe programming model
the greatest common divisor of the tasks’ periods (10 in this
As already mentioned in Section 2, the key design principle of example). A time counter (ticks in the example) is used to
ARTe is to preserve the simplicity of the Arduino programming
model. As a first step towards matching this principle, both the detect when the tasks need to be activated. Note that the time
setup and loop functions are preserved in ARTe. However, while counter can be reset only after the time at which the schedule
the setup function maintains the original functionality, in ARTe
repeats itself (known as the hyperperiod). The hyperperiod is
the loop function hosts code that is executed in background,
i.e., whenever there are no tasks ready to execute. Multitasking equal to the least common multiple of the tasks’ periods, which
is supported by extending the semantic of the loop function. equals to 210 in the presented example.
In ARTe, the user can define an arbitrary number of tasks, each
As anticipated in the introduction of this paper, this approach
specified by a function of the following format:
works reasonably well when the application consists of tasks that
void loop<name>(int period) {
// Here goes the task code
have very short computation times, e.g., tasks for blinking a set
} of LEDs, but is unsuitable for complex applications that include
tasks with short computation times and short periods along with
Specifically, all C functions whose name begin with the key-
word loop and ends with other characters are interpreted as tasks with long computation times and long periods.
tasks. Examples of suitable names for such functions are loopi, ARTe solves these issues by relying on the multitasking sup-
loop_42, loopfoo. To maintain the simple and intuitive ap-
port offered by ERIKA, which implements fixed-priority preemp-
proach of Arduino, such functions have been designed to take
one and only one argument that denotes the period, in millisec- tive scheduling. Listing 6 shows how the application of Listing
onds, with which the corresponding task must be executed. For 5 can be implemented under ARTe. As it can be observed from
instance, the following code defines a task in ARTe that prints
‘‘Hello World" in the serial console every 100 ms: the listing, compared to the baseline solution discussed above,
ARTe provides a simpler, more concise, and less error-prone
void loop_example(100) {
Serial.println("Hello world"); programming paradigm.
} Listing 7 shows an excerpt of the OIL configuration file gener-
ated by the ARTe builder for the sample application reported in
3 For Arduino UNO the newest version 3 of ERIKA is used, while for Arduino
Listing 6, while Listing 8 presents the extended setup function.
DUE ERIKA version 2 is adopted since Erika v3 does not still support the
corresponding Cortex-M microcontrollers. ARTe creates a variable of type COUNTER named TaskCounter,
7
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Listing 6: Example of periodic activities using ARTe programming


model.
void setup() {
<< setup code >>*@void loop() @*<< background code
>>*@void loop1(10) activity1();void loop2(30)
activity2();void loop3(70) activity3();

Listing 7: OIL configuration for the periodic activities examples.


CPU m3 {
<< ERIKA OS settings >>*@ TASK loop1 PRIORITY =
3;@*<<Task settings>>*@ ;ALARM Alarmloop1 COUNTER
= TaskCounter;ACTION = ACTIVATETASK TASK =
loop1;;;TASK loop2 PRIORITY = 2;@*<<Task
settings>>*@ ;ALARM Alarmloop2 COUNTER =
TaskCounter;ACTION = ACTIVATETASK TASK =
loop2;;;TASK loop3 PRIORITY = 1;@*<<Task
settings>>*@ ;ALARM Alarmloop3 COUNTER =
TaskCounter;ACTION = ACTIVATETASK TASK =
loop3;;;;

Listing 8: Generated setup function for the periodic activities


examples.
void setup() {
<< setup code >>

SetRelAlarm(Alarmloop1, ARTE_TASK_INIT_OFFSET, 10)


;
SetRelAlarm(Alarmloop2, ARTE_TASK_INIT_OFFSET, 30)
;
SetRelAlarm(Alarmloop3, ARTE_TASK_INIT_OFFSET, 70)
;
}

which is incremented by the ISR handling the hardware timer.


The counter can be connected with multiple alarms (e.g., Alarm-
loop1), each one in charge of activating a task when the desired
value (a multiple of the hardware timer period) is reached. This
configuration is static and specified in the OIL file shown in Listing
7. Instead, the current value for each period can be varied; hence
the periods are configured injecting the needed code in the setup
function, as shown in Listing 8. Fig. 5. Flow chart of the ARTe building process.

3.4. Sharing data among tasks

the handling of shared global variables. This approach enforces


Global variables are one of the most practical solutions for
correctness and prevents errors originating from race conditions,
implementing communications channels among concurrent tasks
which are notoriously challenging to be spotted.
in a shared-memory environment. Furthermore, global variables
The simplest way for implementing an automatic protection
are a natural choice for preserving the simplicity of the Ar-
mechanism for global variables would be to protect all of them
duino framework being in line with the intuitiveness of the
with a centralized lock that is taken at the beginning of each task
typical programming style of Arduino users. However, in a con-
and released at the end of the task. Unfortunately, such a simple
current environment, global variables must be accessed in mutual approach reduces concurrency and may introduce unnecessary
exclusion to avoid race conditions and preserve the program and long blocking times in high-priority tasks, which is unde-
correctness. In a more traditional programming environment, sirable for systems with timing constraints. ARTe protects global
a professional programmer is responsible for implementing a variables by utilizing a more evolved technique based on local
proper access to global data by employing adequate primitive proxy variables. During the compilation process, the ARTe parser,
objects, like mutexes or monitors. In the domain of real-time a component of ARTe that transforms the ARTe program into
operating systems, several resource access protocols, such as the intermediate files that are used afterwards in the compilation (see
Priority Inheritance Protocol (PIP), the Priority Ceiling Protocol Fig. 5), creates a table listing all global variables and then analyzes
(PCP), and the Stack Resource Policy (SRP) have been designed all tasks to detect the statements in which such global variables
to bound the blocking delays caused by concurrent resource are accessed. If more than one task accesses a global variable, the
accesses. However, correctly using these mechanisms requires builder defines a Mutex object associated with that global vari-
expertise in concurrent programming, which may be beyond able. Then, on each task that accesses that variable, the builder (i)
the typical Arduino user background. Therefore, to preserve the replaces the global variable with a local proxy variable, and (ii) in-
accessibility of the original Arduino framework, ARTe automatizes jects code fragments at the head and at the tail of the task’s code
8
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

to synchronize the local proxy with the global variable. Such code
fragments are referred to as synchronization prolog and epilogue, Listing 9: ARTe locking primitives.
respectively. In practice, the synchronization prolog locks the void arteLock(void);
mutex associated with the global variable, performs a copy of the void arteUnlock(void);
global variable on the local proxy, and then releases the mutex.
The synchronization epilogue locks the global variable mutex, void arteLockRes(enum arteRes resource);
copies back the value of the local proxy variable into the global void arteUnlockRes(enum arteRes resource);
variable, and then releases the mutex. If a task performs read-
only access on a global variable, the ARTe builder injects only /* For testing purposes */
uint8_t arteEnabled(void);
the head snippet. The builder ignores global constants. It is worth
uint8_t arteNestingLevel(void);
noting that this mechanism is entirely transparent to the user, it uint8_t arteNestingLevelRes(enum arteRes resource);
does not require changes to the programming paradigm, and is
fully compatible with existing code. The approach is applied to
all global variables to maintain a consistent behavior across dif-
ferent platforms (hardware-dependent optimizations for atomic
Listing 10: ARTe resources declaration.
variables are possible but currently not supported).
While this approach is simple and effective, it also has some enum arteRes {
limitations. Indeed, to synchronize a global variable with its local arteIO,
proxy, it is necessary to know the size of the variable at compile
arteADC,
arteDAC,
time. Therefore, the ARTe protection mechanism does not support
arteSPI,
dynamically allocated memory and data types accessed through arteI2C,
pointers (e.g., linked lists). In fact, the ARTe protection mechanism arteTIMER,
is limited to standard C++ primitive data types and user-defined arteUSART,
C-like passive data structures (PDS). However, since typical Ar- arteSTREAM
duino sketches do not make use of pointers and user-defined };
types, this limitation is expected to have a minimal impact. Please
note that the scope of the ARTe protection mechanism is limited Listing 11: Example of an Arduino library function extended
to the Sketch code. On the contrary, libraries developers are using ARTe locking primitives.
responsible for protecting library code against race conditions
using the mutual exclusion support mechanism described in Sec- int TwoWire::read(void) {
tion 3.5. Finally, it is worth remarking that the ARTe protection
int retval;
mechanism is not semantically equivalent to mutual exclusion.
/* *** ARTe - begin critical section *** */
Indeed, the protection mechanism is intended to provide easy-to- arteLockRes(arteI2C);
use deadlock-free communication channels between tasks based
on local proxy copies. Such local copies are initialized at the if (rxBufferIndex < rxBufferLength)
beginning of the task with the value of the corresponding global retval = rxBuffer[rxBufferIndex++];
variable. Then, global variables are updated back at the end of the else
task with the values of local copies. Hence, whenever multiple retval = -1;
tasks access the same global variable, the updates made by one
task are not visible to the other tasks until it completes and the /* *** ARTe - end critical section *** */
other tasks begin a new job. For this reason, it is recommended to arteUnlockRes(arteI2C);
use only one writer task for each global variable, i.e., each global
return retval;
variable implements a 1-to-N channel. }
3.5. Adapting libraries for concurrent execution

The Arduino framework owes part of its popularity to the large


codebase of proprietary and third-party libraries that relieve the to define critical sections for protecting specific hardware re-
programmer from the need of knowing the low-level details of sources. From the programmer perspective, these resources are
each hardware peripheral. However, as stated before, the ma- available using an enumerated type as visible from Listing 10.
jority of such libraries are not thread-safe and thus cannot be On the ERIKA side, mutual exclusion is implemented using a
directly integrated into ARTe. A simple solution for adapting ex- predefined set of OSEK RESOURCE objects representing the basic
isting Arduino libraries to the ARTe multi-threaded environment set of I/O devices available on Arduino boards. Additional or
would be to execute each library call as a non-preemptive sec- custom peripheral devices that are not included in the set of
tion. However, this approach would be unsuitable for real-time predefined resources reported in Listing 10 can be protected
applications since some libraries include long busy waits that may using the global arteLock() and arteUnlock() primitives.
jeopardize the timing performance of the entire application, as no These functions implement mutual exclusion with a global lock
other task would be capable of making progress in its execution related to a special resource, named RES_SCHEDULER, which is
during such busy waits. part of the OSEK standard. When the calling task acquires such
To address this issue while preserving the simplicity of the a resource, it becomes non-preemptive until it releases the re-
Arduino framework, ARTe provides a fine-grained support mech- source. To avoid unbounded priority inversions, ERIKA makes use
anism that allows developers to extend libraries for a multi- of the Immediate Priority Ceiling protocol (also known as Highest
threaded environment. The support mechanism provides the Locker Priority) (Buttazzo, 2011) while accessing these resources.
developers with a set of primitives, summarized in Listing 9, Listing 11 shows how an existing library can be extended to
which can be used to define critical sections. The arteLock- support multitasking in ARTe by including critical sections using
Res() and arteUnlockRes() primitives allow the programmer the primitives mentioned above.
9
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Since ARTe follows a programming model based on periodic and their affinity with the tasks, the timer to periodically activate
activities, there is no need to explicitly introduce delays in the the tasks, etc. This file is created starting from a template OIL file
code using functions such as millis(), micros(), delay(), and de- that contains the configuration parameters of ERIKA that pertain
layMicroseconds(). More importantly, the use of such functions to the hardware platform. Finally, the OIL file is provided to the
is discouraged, since they could introduce delays longer than RT-DRUID configuration tool (distributed with the ERIKA RTOS)
expected due to preemptions, depending on their internal imple- to generate tailored version of the RTOS as a linkable library.
mentation. The second file is a processed version of the original sketch code
Finally, the support library provides a set of auxiliary functions augmented with the necessary calls to the ERIKA kernel. These
that can be used by the developer for debugging and testing system calls will be later resolved at linking time while combining
purposes. the sketch object file with the ERIKA library. In this way, the
The arteLockNestingLevel() and arteLockNesting ERIKA core and the Arduino code can be compiled through dif-
LevelRes() functions return the nesting level of the critical ferent compilation flows and combined together only in the end
section. The arteEnabled() function returns true if the ARTe during the linking phase. This approach allows for maintaining
framework is enabled or false if ARTe is disabled and the code a higher level of modularity, facilitating maintainability. Fig. 6
is compiled using the regular Arduino environment. details the internal behavior of ARTe parser.
Arduino Build Process. In this stage, the Arduino Builder
4. ARTe implementation proceeds by compiling all the Arduino-related files needed by the
application and produces a library. At the end of the build process,
This section describes the entire process employed by ARTe the Arduino binary files are provided to the linker together with
to produce the final (binary) executable of the application to be ERIKA binary files.
programmed on the platform starting from the application code.
To avoid discussing several aspects of the Arduino framework that RT-DRUID. When this stage is executed, the ERIKA config-
do not pertain to the contribution of this work, the presentation uration file produced by ARTe is ready to be analyzed by the
is mainly focused on the modifications that have been performed RT-DRUID tool, which generates C code to configure ERIKA and
to the Arduino building process. Particular attention is taken at a makefile to build the RTOS.
the code parsing stage provided by the ARTe parser. ERIKA build process. After the execution of RT-DRUID, it
The starting point for the ARTe building procedure remains is possible to perform the compilation of ERIKA. This building
the sketch file written by the user. ARTe just requires sketches process produces in output two libraries. The first one contains
written according to the programming model presented in the the architecture-independent code of the ERIKA kernel, while the
previous section with at least one periodic task defined. The second one includes the code needed to instantiate it on the
trivial case composed only of the classic Arduino loop() is not specific platform and is different for each available platform.
handled by ARTe, since it would add the cost due to the ERIKA
kernel to perform the same activities already provided by Arduino Linking stage. The linking stage is realized by extending the
itself. standard linking procedure performed by Arduino, which has
been modified to merge the ERIKA kernel produced by ARTe with
4.1. ARTe build chain the object files of the application. The result is an ELF binary file
ready to be downloaded on the board via the standard Arduino
Fig. 5 shows the build flow for an ARTe application, which tools.
starts with the standard Arduino pre-processor that generates
a C++ source file from the sketch (.ino file). A parsing stage 4.2. Internals of the ARTe parser
(i.e., the ARTe parser) is first employed to process the C++ source
file for the purpose of producing two outputs: another Arduino- This section details the internal steps performed by the ARTe
compatible C++ source file and an OIL configuration file for the parser.
ERIKA kernel. These two files are then processed in parallel by C++ file split. The C++ file produced by the Arduino pre-
the following stages (see Fig. 5). One branch involves the regular processing stage contains a long inclusion of Arduino-related
Arduino building process, whose documentation is available on header files. ARTe does not need to analyze the code in these
the official Arduino website (Anon, 0000h). The other branch, header files (and performing such an activity would slow down
called ARTe Builder and invoked through a pre-build hook recipe, the build process). Therefore, as a preliminary step, ARTe extracts
is in charge of managing all the stages to obtain an instance of the user source code from the C++ file in input. The user code is
the ERIKA kernel tailored to the application under compilation. saved in a temporary file and utilized as the input for the static
The main stages of the build flow are discussed in details next. analysis performed by Doxygen. The ARTe parser works on this
temporary file and finally publishes the changes it applies in the
Arduino pre-processing. This is the first stage invoked by the
original C++ file, hence replacing the user code generated by the
Arduino Builder and is in charge of creating a unified C++ file that
Arduino pre-processing stage.
includes all the Arduino-related header files and the user code
present in the sketch. Since the Arduino IDE gives no access to the Doxygen Analysis. Doxygen analyzes the user code and pro-
sketch, ARTe has been designed to process the C++ file generated vides an XML file that models the code structure and allows
by this stage. identifying all the functions and all the global variables. This XML
file is imported in the Java environment using the Java Element
ARTe parser. This is the core component of ARTe. It has
interface (Anon, 0000j) to keep track of functions and global
been developed in the Java programming language to simplify
variables in proper data structures.
extensibility and relies on Doxygen (Anon, 0000i) as a parsing
engine. The ARTe parser inputs the C++ file produced by the ERIKA task creation. All the ARTe loops are converted into
Arduino pre-processing stage and provides two outputs. The first ERIKA tasks, like in the example reported in Listings 12 and 13. All
one is the configuration file for the ERIKA RTOS (OIL file), which other functions defined in the sketch are not modified by ARTe.
specifies a number of parameters such as the number of tasks The background loop is executed as background activity, i.e., a
and their setting (e.g., priorities), the number of shared resources task running with the lowest priority in the system.
10
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Fig. 6. Flow chart that describes the interval behavior of the ARTe parser.

ERIKA alarms, which control the periodic activation of tasks, to update the global variable __ARTE_GLOBAL_var__ with
are configured at the end of the Arduino setup function by the content of the local variable var. Such an approach
injecting calls to the corresponding ERIKA primitives. In this way, ensures that the updated value is correctly saved on the
tasks can start executing only after the user code in the setup global variable when the task terminates the execution,
function has completed its execution. The definitions of some hence publicizing the output produced by the task.
ERIKA functions are also injected at the top of the temporary C++
file. Furthermore, some header files are included to access the Oil file creation. The last step is the generation of the OIL
ERIKA and ARTe API. configuration file, which follows the OSEK standard to configure
the ERIKA RTOS. This step makes use of a template file, which
Global variables protection. Thanks to the Doxygen analysis,
is chosen by the ARTe builder within a library of templates
the ARTe parser is capable of detecting which global variables are
as a function of the Arduino board selected by the user. The
accessed by more than one task. Such global variables are then
template contains all the architecture-dependent configurations
protected with the mechanism discussed in Section 3.4, which and parameters. The final OIL file produced by this stage includes
also requires defining an ERIKA resource for each global variable the declarations of all the global resources and tasks. Each task
in the OIL configuration of the RTOS. As stated in Section 3.4, the is assigned a priority based on the Rate Monotonic algorithm,
protection mechanism is restricted to primitive types and C-like i.e., the shorter the task period the higher the priority. ERIKA
passive data structures. alarms are used to periodically activate the tasks. They are set
The functions of the ERIKA API that are used to implement together with the corresponding action to take when the alarm
mutual exclusion are: fires (i.e., the task to be executed). An example of how a task and
• void GetResource(ResourceType ResID), to lock the the relative alarm are declared in the file is reported in Listing 8.
resource specified as a parameter; and
• void ReleaseResource(ResourceType ResID), to un-
5. Experimental evaluation
lock the resource specified as parameter.
More specifically, the protection of a global variable var re- This section presents a practical evaluation conducted to as-
quires performing the following actions: sess the performance of the ARTe framework.
As a first step, the scalability of ARTe with respect to the
1. The name of the global variable is changed from var to traditional approach is evaluated by comparing the memory foot-
__ARTE_GLOBAL_var__; print of the runtime support as a function of the number of
2. A local variable var is defined in the local scope of each loops. Following, two complete case-study applications have been
ARTe task that uses the global variable of interest; developed to test the ARTe framework in a realistic scenario
3. A short critical section is placed at the beginning of the task where multiple peripherals devices on the Arduino board are
body to safely perform the copy of the value of the global used under multitasking.
variable __ARTE_GLOBAL_var__ into the local variable
var; 5.1. Memory footprint
4. If the task performs some modifications on the global vari-
able, which can be detected via the Doxygen analysis, an- Arduino boards are typically memory-constrained embedded
other short critical section is placed at the end of task body platforms. Therefore, to assess the sustainability of the ARTe
11
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Table 2
Listing 12: Example of a sketch containing two ARTe loops Evaluation of the memory footprint of ARTe vs. the standard Arduino
sharing a global variable. programming model on an Arduino Due platform.
Number of loops Footprint (bytes)
Arduino ARTe
int global_var;
1 10708 (2.042%) 12556 (2.395%)
void loop_1(100) 2 10732 (2.047%) 12608 (2.405%)
4 10788 (2.058%) 12696 (2.422%)
{
8 10900 (2.079%) 12880 (2.457%)
int local_var; 16 11124 (2.122%) 13248 (2.527%)

local_var = global_var;
}

void loop_2(100)
{
global_var++;
}

Listing 13: Corresponding code generated by the ARTe builder.


TASK (loop_1)
{
//--------------------------------
int global_var;
GetResource(__ARTE_MUTEX_global_var__);
memcpy(&global_var,&__ARTE_GLOBAL_global_var__, Fig. 7. Arduino and ARTe footprints on the Arduino Due platform with respect
sizeof(int)); to the number of tasks.
ReleaseResource(__ARTE_MUTEX_global_var__);
//--------------------------------

int local_var;

local_var = global_var;
}

TASK (loop_2)
{
//--------------------------------
int global_var;
GetResource(__ARTE_MUTEX_global_var__);
memcpy(&global_var,&__ARTE_GLOBAL_global_var__,
sizeof(int));
ReleaseResource(__ARTE_MUTEX_global_var__);
//--------------------------------

global_var++; Fig. 8. Arduino and ARTe footprints on the Arduino UNO platform with respect
to the number of tasks.
//--------------------------------
GetResource(__ARTE_MUTEX_global_var__);
memcpy(&__ARTE_GLOBAL_global_var,&global_var__, The results obtained for the case of a single task show that
sizeof(int)); the ARTe runtime support, i.e., the ERIKA RTOS plus the support
ReleaseResource(__ARTE_MUTEX_global_var__); libraries for mutual exclusion, requires only 1848 bytes of ad-
//--------------------------------
ditional memory in the worst case, corresponding to less than
}
0.4% of the available memory on an Arduino Due. It is also worth
noting that the memory footprint scales almost linearly with the
number of tasks with a rate of fewer than 50 bytes per task.
Fig. 7 shows a graphical representation of this trend where the
framework, it is worth evaluating the impact of the runtime
support in terms of memory consumption. To this end, a simple first value of the curve labeled Arduino is the size of the standard
modular application consisting of up to 16 tasks (each perform- Arduino sketch, including only the loop() function.
ing a single GPIO operation only) has been programmed with The same experimental evaluation has been performed by
both the standard Arduino framework using the loop scheduling using the Arduino UNO platform, and the results are reported
technique, and then with the ARTe framework. Table 2 reports in Table 3. In this setting, the ARTe runtime support demands
and compares the memory footprint of both implementations about 8 KB with 16 periodic tasks (considering both program
while varying the number of loops (in bytes and as percentage storage space and dynamic memory), while ARTe for Arduino
of the total amount of resources available on the board). These Due demands 13 KB. This is caused by the different architectures
measurements have been collected when building an application and the implementations of the hardware-specific code. Also,
for the Arduino Due platform. remember that the two platforms rely on different versions of the
12
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Table 3
Evaluation of ARTe memory footprints on the Arduino UNO platform. Since the Arduino UNO toolchain differentiates
between Program storage space (first addend in sum) and Global variables dynamic memory (second addend in sum),
this distinction is preserved in the table.
Number of loops Footprint (bytes)
Arduino ARTe
1 964 + 11 (2.98% + 0.54%) 5494 + 791 (17.03% + 38.62%)
2 958 + 11 (2.96% + 0.54%) 5552 + 853 (17.21% + 41.65%)
4 1006 + 11 (3.11% + 0.54%) 5668 + 977 (17.57% + 47.70%)
8 1080 + 11 (3.4% + 0.54%) 5900 + 1225 (18.29% + 59.81%)
16 1204 + 11 (3.73% + 0.54%) 6364 + 1721 (19.73% + 84.03%)

Table 4
Comparison of the worst-case profiled response times (pWCRT) for Arduino
native and ARTe implementations of the case study application.
Loop Period (ms) pWCRT (ms)
ARTe Loop sched
IMU 20 6.603 6.689
FIR 40 0.148 6.529
Servo 50 0.008 6.532
Web server 100 11.253 20.993
LED-1 1000 0.010 13.990
LED-2 2000 0.010 11.000
LED-3 3000 0.010 11.002

ERIKA kernel (ERIKA v2 for Arduino Due and ERIKA v3 for Arduino
UNO).
As illustrated in Fig. 8 and detailed in Table 3, the footprint
of an application increases with the number of tasks (i.e., ARTe
loops). The test application is the same as the one considered in
Fig. 7). Overall, ARTe tasks require a linearly increasing amount
of memory, which is only slightly larger than the one required by
the stock Arduino framework.

5.2. Case-study application 1

This section presents a case study developed as a test-bed


to assess the effectiveness of the ARTe framework in a realistic
application scenario. The hardware setup for the case study con- Fig. 9. Software stack for the case study application.
sists of an Arduino Due board equipped with an Ethernet shield,
and connected to an inertial measurement unit (IMU) and a
servo motor to realize radio-controlled applications. The Ethernet
on top of the Ethernet library and uses the Server-Sent Events
shield communicates with the Arduino board through the SPI bus
(SSE) technology, which is standardized as part of HTML5, to
while the IMU is connected to the board using the I2C bus. The
servo motor is connected to a general-purpose output pin and push updates to the clients using lightweight messages. Each
is managed using a control signal generated by an MCU internal iteration of the webserver loop (i) checks if a new client is
timer. The application cyclically (i) reads the angular displace- available and then (ii) updates already connected clients using
ment from the IMU sensor; (ii) filters the incoming displacement SSE messages. When a new connection request from a client
data using a FIR filter; (iii) actuates the servo motor to replicate is detected, the webserver replies by sending a web page that
the displacement angle; and (iv) updates a hosted web page that contains the JavaScript (JS) code used by the client to initiate
shows a graphical representation of the displacement angle. the SSE data stream (through the EventSource JS interface) and
Each of these activities is implemented as an ARTe loop. The visualize the data using an HTML5 Canvas element. Next, once
software stack of the case study, which includes both the ARTe the client sends the SSE events stream initialization request, the
loops and the runtime support, is illustrated in Fig. 9. webserver registers the client as connected and acknowledges the
The IMU loop periodically reads the displacement angle from request by starting sending SSE events.
the IMU using a software stack comprising the MPU6050 6-axis The case-study application also includes three additional loops,
accelerometer/gyroscope, I2Cdev, and Wire libraries, and writes each blinking a LED at a different rate, presenting to the user
the acquired value to a global variable. The FIR loop reads such a visual feedback of the running application. These loops also serve
variable and processes the samples coming from the IMU loop as overload indicators since they will be preempted by other tasks
using a 40-tap low-pass filter, storing the result into another in case of overload, thus freezing the LEDs blinking activity.
global variable. The servo loop reads such a variable, maps the The memory footprint of the Arduino native implementation
displacement angle into the servo motor configuration space, and is 52.8 kB bytes, while the memory footprint of the ARTe imple-
finally generates the control signal using the Servo library. The mentation is 55.2 kB bytes, corresponding to about 10% of the
same variable is used by the webserver loop (WS loop) to notify total flash memory in both cases. Table 4 describes the loops
the displacement of the IMU to the connected clients. (tasks) that constitute the case study application and compares
The webserver loop is a complex activity supporting up to the longest response times (pWCRT) profiled for two different
four concurrent web clients. Internally, the webserver is built implementations. The first implementation has been built using
13
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Table 5
Ventilator IO Hardware used in the case study. ARTe was used to test all IO peripherals, with the optimal configuration
highlighted.
Part ID Part Function Quantity Interface Vendor Part Serial
AF1 Airflow sensor 2 I2C Honeywell HAFUNH0300L4AXT
PS1 Pressure sensor 3 ADC (onboard) Honeywell 150PAAB5
PS2 Pressure sensor 0/2 ADC (onboard) Honeywell 015PAAB5
O21 O2 Sensor 0/2 ADC (external) Maxtec Max-23
O22 O2 Sensor 2 ADC (external) Maxtec Max-12C
O23 O2 Sensor 0/2 ADC (external) Maxtec Max-250ESF
PV1 Proportional Valve 0/2/4 PWM (12V drive) Yong Chuang YCLT21-35-1GBV-5B61B
PV2 Proportional Valve 0/2/4 PWM (12V drive) Yong Chuang YCLT21-2C-1GBV-5B61B
PV3 Proportional Valve 4 PWM (12V drive) IQ valves Tesla iQ
OI1 O2 Sensor IO 1 I2C Texas Instruments ADS1115
CM1 Control Modem 1 ADC (onboard) C-19 Crisis Tech TVCV19 Univ Controller
VD1 Valve driver 4 PWM (onboard) C-19 Crisis Tech TVCV19 AJak Controller
VD2 Valve driver 0/2/4 PWM (onboard) Infineon Technologies IRFZ44NPBF

the Arduino native approach described in Section 3.3, while the


second implementation has been built using ARTe. In both cases,
the response times have been measured during a 30-minute
run with two clients connected to the webserver. It is worth
observing how the preemptive scheduling available on ARTe can
significantly improve the response times of high-priority loops,
such as the FIR task. On the contrary, with the Arduino native
approach, high-priority tasks (shorter period) can significantly be
delayed by low-priority tasks (larger period).

5.3. Case-study application 2

This section presents a demonstration application of ARTe as


part of a RMVS001 compliant makeshift ventilator platform. The
platform was developed as treatment of last resort and has not
been used to administer life support therapy.
During the COVID-SARS-2 pandemic of 2020, the global health-
care system has been under immense strain. Mechanical ven-
tilators, which are used to treat acute COVID-19 cases, have
been in short supply globally. Ventilating a COVID-19 patient
requires safety-critical control of a sophisticated pneumatic sys-
tem that drives the breathing cycle of a sedated patient using
feedback from an array of pressure and airflow sensors. Existing
designs have proven too costly for many healthcare systems
or require parts that are not available locally where needed.
This has created an urgent demand for the rapid development
of safety-critical embedded systems adaptable for locally avail-
able sensors that can meet the performance requirements for
life-saving ventilation treatments (Barrow et al., 2021).
Depending on vendor supplies, a wide range of suitable I/O
peripherals could be integrated into a ventilator platform. How-
ever, it is difficult to adapt to available parts using conventional
RTOS software stacks. Slow RTOS development cycles can be- Fig. 10. Software stack for the example devices configuration of the ventilator.
come a bottleneck to meeting the needs of healthcare systems
experiencing a crisis. Specialized driver software must be de-
veloped for each peripherals combination, limiting the possible Implementing ventilator I/O requires the coordination and
configurations. By contrast, ARTe is particularly suited for the scheduling of many peripheral management tasks. A high-level
rapid development of ventilators. Community provided software pseudo-code of the proposed ventilator application is given in
drivers are readily available for every peripheral or are simple Listing 14, illustrating how ARTe has been leveraged to achieve
to add using templates and their companion tutorials (Bayle, the goals of rapid development and timing predictability, crucial
2013). By exploiting ARTe, it is possible to dramatically reduce for patient safety. The application has two high-level activities to
the time needed to adapt to part shortages and create a hardware manage: the ventilation itself and a user interface to adjust the
configuration that meets performance requirements and safety ventilation therapy. The mechanical ventilation is implemented
specifications. as a PID closed control loop, whereby ARTe is used to set the
Implementation details are presented for one of the possible discrete integration time step as precisely as possible to 20 ms
ventilator designs whose custom set of I/O peripheral can quickly (50 Hz). Our user interface is mostly offloaded to a secondary
be modified according to hardware availability. The selected ex- device and only a minimal set of PID variable setting and mon-
ample configuration is highlighted in the table of ventilator parts itoring functionalities are implemented on the ARTe host board.
evaluated using ARTe, shown in Table 5. The synchronous user interface task is implemented as an ARTe
A block diagram of the example ventilator software stack is loop, called loop_UI, with a period of 50 ms for the most re-
shown in Fig. 10. sponsive user experience. The footprint of the application is 7.7
14
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

⋆ void init_af0-1() maps two TWI bus mounted air-


Listing 14: Pseudo-code of the ventilator application. flow sensors to an air flow reading library that main-
tains the afs buffer.
struct raw_data <t> { ⋆ void init_ps1-4 initializes four on board ADC chan-
<< ... >> nels provided by the Arduino library and maps them to
}; a gas pressure reading library that maintains the pss
buffer.
raw_data adcs;
raw_data pwms; • void loop(), polls the modem control library for venti-
raw_data afs; lator commands. Commands are used to set parameters to
raw_data pss; the Proportional Integral Derivative (PID) respiratory control
function and to interrogate the PID status to update the user
void setup() { on how the ventilator is performing.
init_adc0-1();
init_modem(); ⋆ modem.tx() and modem.rx() calls a modem library
init_pwm0-4(); function that sends data to and receives data from an
init_af0-1(); external remote control software that updates the user
init_ps1-4(); interface displaying data.
}
• void loop_pwm(), maintains ventilator gas valve aperture
void loop() { settings as specified by the PID. This safety critical task
command = modem.rx(); uses an ARTe loop to guarantee that the valve aperture is
switch (command) { maintained at a timely interval.
case read_sensor: • void loop_adc(), monitors the O2 gas concentration read-
modem.tx(JSON_buffer); ing at a fixed interval for PID. This timing critical task uses
break;
an ARTe loop to ensure stability of the PID integral that
case write_valves:
pwms = modem.rx(); consumes this data.
break;
The pseudo code illustrates how ARTe has provided the re-
<< ... >>
} quired benefit of timing predictability, shared task memory man-
} agement, and task management along with the rapid develop-
ment capability of the Arduino ecosystem. Specifically, Timing
loop_pwm(20) { predictability leveraged in loop_pwm and loop_adc were essen-
pwm.set(pwms); tial for accurate respiratory control in the PID loop.
}
6. Conclusions
loop_adc(20) {
adcs = adc.read(); The Arduino framework has become a reference solution to
} learn the basic principles to program small embedded systems,
quickly develop software interacting with real hardware, and
loop_UI(50) {
fast prototype application to assess their advantages. However,
JSON_buffer = data_to_JSON(adcs, pwms, afs, pss);
} the standard Arduino approach is limited to a single loop, thus
limiting the exploitation of modern hardware platforms and the
// Other tasks follow the same pattern applicability to more complex fields, such as IoT. This paper
<< ... >> presented ARTe, an extension to the Arduino framework able to
seamlessly provide concurrent programming to the developer.
ARTe is designed to handle transparently most of the issues
arising from concurrency, leaving the application developer with
KB, which correspond to 24% of the program storage space of an a solution almost unaltered with respect to the original one.
The internals of the extension has been explained to show the
Arduino UNO platform. A description of the functionalities of the
solutions applied to the various issues and its extensibility. A set
application reported in Listing 14 follows.
of experiments has also been presented to show the simplicity
and usability of the framework, evaluate the limited cost in terms
• void setup(), calls all transducer peripheral boot strap-
of footprint, and show its applicability to a real-world use case. In
ping functions such that they read (monitor) or write (main-
particular, the mechanical ventilator use case highlights the rapid
tain) global data structures, where: prototyping and extensibility advantages of the ARTe framework.
⋆ void init_modem() configures an analog modem pe-
ripheral used for remote control of the ventilator, in- CRediT authorship contribution statement
cluding configuring an ISR triggered by the modem to
Francesco Restuccia: Conceptualization, Methodology, Soft-
allow for asynchronous remote control.
ware, Writing – original draft. Marco Pagani: Investigation,
⋆ void init_adc0-1() maps two ADC channels on a
Methodology, Software, Writing – original draft. Agostino
TWI ADC peripheral to a Oxygen level reading library Mascitti: Software, Writing – original draft. Michael Barrow:
that maintains the adcs buffer. Software, Writing – original draft. Mauro Marinoni: Resources,
⋆ void init_pwm0-4() initializes four on board PWM Methodology, Supervision, Writing – review & editing. Alessan-
channels provided by the Arduino library and maps dro Biondi: Methodology, Supervision, Writing – review &
them to a gas valve control library that monitors the editing. Giorgio Buttazzo: Supervision, Writing – review &
pwms buffer. editing. Ryan Kastner: Resources, Supervision.
15
F. Restuccia, M. Pagani, A. Mascitti et al. The Journal of Systems & Software 186 (2022) 111185

Declaration of competing interest Barrow, M., Restuccia, F., Gobulukoglu, M., Rossi, E., Kastner, R., 2021. A remote
control system for emergency ventilators during sars-cov-2. IEEE Embedded
The authors declare that they have no known competing finan- Systems Letters.
cial interests or personal relationships that could have appeared Barry, R., 0000. Arduino freertos, https://github.com/feilipu/Arduino_FreeRTOS_
Library.
to influence the work reported in this paper.
Bayle, J., 2013. C Programming for Arduino. Packt Publishing Ltd.
Bertogna, M., Fisher, N., Baruah, S., 1991. Resource-sharing servers for open
Acknowledgments environments. IEEE Trans. Ind. Inf. 5 (3), 202–220.
Biondi, A., Buttazzo, G., Bertogna, M., 2015. 2015. Supporting component-
based development in partitioned multiprocessor real-time systems. in:
The authors would like to thank Pasquale Buonocunto4 for the proceedings of the 27th euromicro conference on real-time systems, ecrts
vision and the fundamental contribution given to the first version 2015, lund, sweden.
of the ARTe framework. Buonocunto, P., Biondi, A., Pagani, M., Marinoni, M., Buttazzo, G., 2016. ARTE:
arduino real-time extension for programming multitasking applications. In:
References Proceedings of the 31st Annual ACM Symposium on Applied Computing.
ACM, pp. 1724–1731.
Anon, 0000a. Erika enterprise RTOS kernel, http://erika.tuxfamily.org/drupal/. Buttazzo, G.C., 2011. Highest locker priority. In: Hard Real-Time Computing
Anon, 0000b. Arduino scheduler library, https://www.arduino.cc/en/Reference/ Systems: Predictable Scheduling Algorithms and Applications. p. 212, Section
Scheduler. 7.5.
Anon, 0000c. ArduinoThreads, https://github.com/ivanseidel/ArduinoThread. Cheng, Z., Li, Y., West, R., 2015. Qduino: A multithreaded arduino system for
Anon, 0000d. The freertos kernel, https://www.freertos.org/. embedded computing. In: 2015 IEEE Real-Time Systems Symposium. IEEE,
Anon, 0000e. Nuttx real-time operating system, https://nuttx.apache.org/. pp. 261–272.
Anon, 0000f. Pre and post build hooks documentation, https://arduino.github.io/ Kelemen, B., 0000. Softtimer pseudo multitasking solution, https://github.com/
arduino-cli/latest/platform-specification/#pre-and-post-build-hooks-since- prampec/arduino-softtimer.
arduino-ide-165. Liu, C., Layland, J., 1973. Scheduling algorithms for multiprogramming in a
Anon, 0000g. OSEK/VDX Operating system specification 2.2.1., https://www.iso. hard-real-time environment. J. Assoc. Comput. Mach. 20 (1), 46–61.
org/standard/40079.html. Marzario, L., Lipari, G., Balbastre, P., Crespo, A., 2004. IRIS: A New reclaiming
Anon, 0000h. The arduino official webpage, https://www.arduino.cc/. algorithm for server-based real-time systems. In: Proc. of the IEEE Real-Time
Anon, 0000i. The doxygen parser official webpage, http://www.doxygen.nl/. and Embedded Technology and Applications Symposium, Toronto, Canada.
Anon, 0000j. The oracle documentation for the element interface, https://docs. Rivas, M.A., Tijero, H.P., 2019. Leveraging real-time and multitasking Ada
oracle.com/javase/8/docs/api/javax/lang/model/element/Element.html. capabilities to small microcontrollers. J. Syst. Archit. 94, 32–41.
Barragán, H., 2004. Wiring: Prototyping physical interaction design. Interaction Wang, Y., Saksena, M., 1999. Scheduling fixed-priority tasks with preemption
Design Institute, Ivrea, Italy. threshold. In: Proc. of the 6th IEEE Int. Conference on Real-Time Computing
Systems and Applications, RTCSA’99, Hong Kong, China.

4 Formerly Scuola Superiore Sant’Anna, currently Buontech solutions Srl.

16

You might also like