Professional Documents
Culture Documents
Test Equipment
A REAL-TIME OPERATING
SYSTEM FOR THE
ARDUINO
By
Joe Jaworski
View In Digital Edition LATEST
NEWSLETTERS
» Skip to the Extras MARCH 12, 2021
What if you had multiple loop( ) sections in your Arduino sketch, all Wirespondence, Serial
running at the same time? With an RTOS, this and more is possible. Bluetooth with a Micro,
Analog Front End, AM/FM
Receiver Restoration
WHAT IS AN RTOS?
Wirespondence!
An RTOS (Real-Time Operating System) is a software component that lets you rapidly
switch between different running sections of your code. Think of it as having several Using Serial Bluetooth
loop() functions in an Arduino sketch where they all run at the same time.
With a Microcontroller
Everyone has experienced a multi-tasking operating system. On your smartphone or PC,
you can be playing a game while you get an incoming call or text message. At the same
Why You Need an
time, you might be downloading a software update. All these tasks appear to be running Analog Front End and
at the same time but, in fact, there is only one CPU that is switching back and forth How to Set It Up
rapidly to give the illusion of multi-tasking.
Restoring a Vintage
There is one important thing about these operating systems running on your phone or PC Zenith Table Top
in that they are not “real time” operating systems. There’s no way to predict when the text
application will alert you after you receive a text or that the game you’re playing will
AM/FM Receiver from
redraw the screen. In this environment, it doesn’t matter much. You might see a single the ‘60s
app slow down on your smartphone from time to time as other running tasks hog the
processor’s power.
When it comes to your sketch though, you need things to happen in real time. For MARCH 05, 2021
example, your sketch may be blinking an LED at a specific interval that indicates some
sort of status, and you wouldn’t want it to blink erratically as other tasks are getting Analog Waves from Digital
executed. If you have used a Raspberry Pi, you may have noticed how difficult it is to get Signals, DIY Electric Scooter,
an LED to blink consistently. This is a shortfall of using a non-real time OS. The magic of The Solar Alternative, Driving
an RTOS is that your LED will blink exactly at the time interval you programmed, even LEDs with a Microcontroller
though it’s running other tasks at the same time.
Generating Analog
GETTING STARTED Waves From Digital
Signals
There are many RTOS’s available. The one we’ll be using is called FreeRTOS. It is open-
source software that is free and doesn’t require a license to use it. It has already been Build a DIY Electric
“ported” (see sidebar) to the Arduino’s Atmel processor which makes it very easy to
Scooter
integrate into your sketches. It’s also part of the Arduino libraries, so it’s very easy to
install.
The Solar Alternative
To install FreeRTOS, open the Arduino IDE (integrated development environment). From
Driving LEDs with a
the TOOLS menu, select the “Manage Libraries...” item. You can scroll through the list or
type “FreeRTOS” into the search bar. You’ll see the window shown in Figure 1. Select the
Microcontroller
item “FreeRTOS by Richard Barry” and select the latest version. Click Install. After a few
moments, the installation will be complete.
VIEW ALL >
FROM THE
Q&A
Selected questions from
past Q&A columns.
Stepper Motor
Overview
The first thing we need to do is create a task. A task is a thread or a function that runs Wide-Range Current
independently of your other code. You create tasks in the setup() function of your sketch. Regulator
You create a task by calling the xTaskCreate() function which takes several parameters:
Sawtooth Generator
xTaskCreate (
);
Wirespondence!
MyTask – This is the name of a function in your sketch that holds the task code. You
RADAR And Electronic
probably want to use a name that describes the function like “blinkLED” or “readSensor.”
You then add a new function into your sketch that looks like this:
Warfare Fundamentals
MyTask(void *)
}
Turing Machines
const portCHAR *) “task1” – This is a name for the task. It’s not used at all by the RTOS. 1920s Radio Applause
You can’t use NULL here. It must be a string of characters less than eight. Cards
128 – This is the number of bytes to allocate for the stack. If you’re not familiar with a
CPU stack, it’s a portion of memory set aside to save return addresses and local function
variables when you call a function. If you call a function that calls another function, that
then calls another function, etc., you’ll need more memory for the stack.
LEARNING
ELECTRONICS
Here, we allocate 128 bytes, which is adequate for most sketches. If the stack size is too
low in any of your tasks, the RTOS will blink the LED on the Arduino at four second Need to brush up on your
intervals and stop your program. electronics principles? These
multi-part series may be just
NULL – This is a pointer to any predefined data or structure (defined by you) that you what you need!
would like to pass to the task function when it’s created. To keep things simple, we’re not
using this feature so it’s set to NULL.
Understanding Digital
1 – This parameter sets the task’s priority. It can be from 0 (lowest priority) to 2 (highest Logic ICs
priority). When you have multiple tasks, you can alter the order and priority in which tasks
run. This is an advanced feature. For now, set all your tasks to the same priority. Bipolar Transistor
Cookbook
NULL – This is a pointer to a place to store the newly created task handle. We don’t need
this for a simple sketch. Many RTOS functions will require the task handle when using
Op-Amp Cookbook
more advanced API calls.
FET Principles And
Once the setup() function ends, your tasks are created and they start to run. Figure 2
shows the process.
Circiuits
Understanding Digital
Buffer, Gate And Logic
IC Circuits
Checking Inductors
Security Electronics
Systems And Circuits
Using Seven-Segment
Displays
Think of Loop(), Task-1, and Task-2 all running at the same time. You can put whatever
code you want in each. For example, Task-1 could be displaying characters on an LCD ARCHIVES
display, while Loop() is blinking an LED, while Task-2 is reading a temperature sensor.
April 2017
FIRST SKETCH USING RTOS March 2017
Here’s a simple first sketch using FreeRTOS. We’re going to be blinking the built-in LED on January 2017
the Arduino board while at the same time sending a string of text to the serial monitor.
We’ll be creating two tasks, and just for fun, we won’t have any code in the loop() October 2016
function. You can type in this sketch in the Arduino IDE or download it as RTOS_1.ino as
part of the article.
June 2016
1. // RTOS_1 1st Example of using FreeRTOS
8. //
Opera?
9. void setup()
10. {
April 13 - 3D Printable
Tractor Beam
11. // Setup our LED Blinky Task
12. xTaskCreate
March 07 - Video
13. (
Games Turn 50
TaskBlink, // function name
2, // Priority
January 27 - World’s
NULL // returned task handle
Smallest Transistor —
14. );
Sort of
16. xTaskCreate
17. (
RECENT
TaskComm, // function name
Brad Hines
2, // Priority
22. //
happening...
23. void loop()
24. {
Build a Pocket-Sized
Altair Computer · 8
25. /* Nothing to do here! */
hours ago
26. } // End loop()
Brad Hines
27. // **********************
rtDelay(500);
Build a Pocket-Sized
digitalWrite(LEDPin, LOW); // Turn off Led Altair Computer · 1 day
ago
35. }
David Goodsell
45. } // End TaskComm
On an eight-bit processor like the Atmel, your sketches will run much faster if you use
uint8_t instead of int providing, of course, your data will fit into eight bits. Paul Ramasco
Line 5 is a bit confusing. It defines a macro called rtDelay(v), where v specifies the
number of milliseconds to delay (see “Why have a special delay function?”). You should
use this instead of the Arduino delay() function within tasks.
WHY HAVE A SPECIAL DELAY
FUNCTION?
The job of an RTOS is to switch back and forth so that all your tasks appear to be
running at the same time. The default run time of any given task (assuming equal
priority) is 15 ms. This is called the tick count. Each task gets a “time slice” of 15 ms
before it’s interrupted by the next task.
Just like most sketches, most tasks need to introduce delays in their code. Using a
special form of delay tells the RTOS that “my task has nothing else to do for the next x
milliseconds, so go run other tasks.” This makes the RTOS aware of the differences
between your code and the dummy loops that make up delays. The RTOS becomes
faster and more efficient.
There is one caveat to be aware of. Task switching occurs at a 15 ms rate, so the
smallest delay is 15 ms, and all other delays are truncated to the nearest 15 ms
increment. So, if you specify rtDelay(100), the delay will actually be 100 / 15 or 90 ms. If
you need precise delays in a task, you could use the delay() function to make up the
difference.
Lines 9-19 are the setup() function. Here, we create two RTOS tasks: one to blink the LED
and the other to write text to the serial monitor.
Lines 23–26 are the loop() function. In this sketch, it’s empty! All the work is being done
in tasks. However, you certainly could put whatever code you needed here without any
restrictions.
Lines 30-36 are the TaskBlink() function. We set the I/O pin connected to the LED to an
output, then blink the LED every 500 ms. Notice that we don’t call the delay() function and
instead call the rtDelay()macro. This informs the RTOS that we need to be idle during the
specified time. It’s best not to use the Arduino delay() function in a task; use rtDelay()
instead.
Notice that the TaskBlink() function is wrapped in a never-ending loop via the for(;;)
statement. This is very important! Tasks never return (where would they return to?) and
will crash if you don’t use an infinite loop around the repeating code.
Lines 40-46 are the TaskComm() function. Here, we initialize the serial port to 9600
baud, then have an infinite loop that displays a line of text every 500 ms as shown in
Figure 3.
Using a global variable requires special attention in an RTOS. The problem is we don’t
know exactly when the TaskComm() function or the TaskBlink() function is running at any
given time. (It’s switching back and forth about 66 times a second.) With both functions
having access to the same global variable, one function may be reading/writing to it
while another function is doing the same, resulting in corrupt data. This is not unlike the
problem faced when modifying global variables within an interrupt. We must somehow
tell a task not to use the global variable until another task is done changing it.
The mechanism to do this is called a semaphore. It’s a way to alert all tasks that it must
wait for the semaphore to be available before it can proceed. A semaphore is just a
signal to the RTOS. It doesn’t do anything by itself. Your code defines what a semaphore
does.
Semaphores have give and take functions. When you need to prevent other tasks from
accessing a shared variable, you “take” the semaphore, which blocks all other tasks from
using the variable until you’re done. When you’re finished, you “give” the semaphore back,
which frees others to use it. Between the give and take functions is where you put your
code. You can use a semaphore to protect global variables, sensors, hardware, or
anything else that is accessed by more than one task.
With semaphores in hand, we’ll now modify the first example so that both tasks can use
the global variable. At the top of the file, we add:
#include <semphr.h>
enum uint_8 {
LED_OFF, // LED ON
};
The #include <semphr.h> specifies the header file that allows us to link with the
semaphore library. Below that, we create the three states of the LED using the C enum
keyword. We define a variable to hold the semaphore handle, followed by the global
variable g_LEDStatus which is initialized to the LED blink state. Notice that both these
statements use the volatile keyword. This prevents the compiler from optimizing out the
variable, as it does not know that the variable will be modified within the RTOS task
(which, in essence, is an interrupt).
The only change in the setup() function is to create the semaphore with the
xSemaphoreCreateBinary() function and store its handle in the SemaStatus variable:
Within the infinite loop of the TaskBlink() function, we add a few lines to manage the
semaphore and get the global variable:
xSemaphoreTake(SemaStatus, portMAX_DELAY);
xSemaphoreGive(SemaStatus);
Notice that we “take” it, then make a copy of the g_LEDStatus global variable, then
immediately release it with the xSemaphoreGive(). It’s a good idea not to hold on to a
semaphore for long periods of time, as you force other tasks to stop executing, waiting
for you to release it. Same philosophies as using interrupt routines. You don’t want to
have a lot of code in it and want to return it as soon as possible.
The rest of the source in TaskBlink() uses a switch() statement to determine how to set
the state of the LED.
If you’re a seasoned Arduino sketch writer, you’re probably thinking you could figure out
how to do all this within the loop() function. Yes, you probably can, but dividing your code
up into separate tasks makes your code very readable so you can easily make changes
(especially six months from now when you forgot what you did).
As your code gets more complicated (especially where you have to have delays but need
to do other things in the meantime), nothing beats an RTOS to manage the situation.
I urge you to visit https://www.freertos.org to learn more about this amazing software
library and all it can do. NV
DOWNLOADS
download
201906-Jaworski-r1.zip
Sketches
Like One person likes this. Sign Up to see what your friends like.
Share 11
COMMENTS
11 Comments
1 Login
Name
Chuck Miller − ⚑
⏲ 3 years ago edited
I have down loaded the sketch, but get the following:
2 0 • Reply • Share ›
see more
1 0 • Reply • Share ›
1 0 • Reply • Share ›
ForrestErickson − ⚑
⏲ 2 years ago
20200821 I too got the "error: expected primary-
expression before 'const'"
see more
1 0 • Reply • Share ›
Edward Andrews − ⚑
⏲ 2 years ago
Joe - good article on Arduino RTOS; I really enjoyed the
read! Your article reminded me of my EE college days
learning software concepts on a DEC PDP-8. At the time,
my college was 'state of the art' as they had several PDP-
8s, one running as a multiuser Time-Sharing system.
Considering that a PDP-8 with its 4K words of 12 bit
memory is considerably less powerful that a typical
Arduino board, it will be interesting to see what can be
done with an Arduino-RTOS combination. I will definitely
be trying RTOS on my next Arduino project! Thanks again
for your article!
1 0 • Reply • Share ›
nutsvolts − ⚑
⏲ 2 years ago
A revised version of the sketches is now available. Since
the Arduino libraries have recently changed, this makes
everything work with the latest version.
1 0 • Reply • Share ›
Kenneth Ciszewski
nutsvolts
> − ⚑
⏲ 2 years ago
So where are the revised sketches located?
1 0 • Reply • Share ›
ForrestErickson
> Kenneth Ciszewski
− ⚑
⏲ 2 years ago
On 20200821 the down load link in
the article above has sketches that
work with my version 10.3.0-9
1 0 • Reply • Share ›
1 0 • Reply • Share ›
Chuck Miller − ⚑
⏲ 3 years ago edited
OK, I now have it working. I had installed the latest
version of FreeRTOS 10.8. It would't compile. I kept
getting the error I mentioned below. I rolled beck to the
version 10.2.0-2 and it now complies and runs..
1 0 • Reply • Share ›
CONNECT
WITH US
SUBSCRIBE TO
2022 ISSUE-2 2022 ISSUE-1 2020 ISSUE-6 2020 ISSUE-5
OUR
The Birth of the The Transistor BUILD A ONE Restoration of NEWSLETTER
Integrated Compound INCH SCOPE a Vintage
Circuit Pair Zenith G725 Sign Up Now
Vintage Tek:
AM/FM
Build an Build a Farmer, Current
Receiver
Electronic Tic- Fox, Chicken, Limiters
Tac-Toe Game Corn Puzzle Build a Digital
Clock Family
Finding the Vintage Tek:
Using Nextion
Outside Foil Continuously
Displays
Lead Variable
Autotransformers Beginning to
Build with
Tubes