Programming with Mbed OS on Arduino (part 2)

In this two-part tutorial, we will get started with Mbed OS (a powerful and lightweight RTOS from ARM) on recent Arduino boards such as those from the MKR and Nano families. Having Mbed OS integration has many advantages such as first class support for connectivity, security and more. This blog is the second of a two-part series, and shows example programs (including multithreading) running on the Arduino Nano 33 BLE and BLE Sense using Mbed OS. The previous part builds up a simple understanding of an RTOS and shows how to set up the Mbed Core on the Arduino IDE, click here to go to the first part.

Simple Blinky Example

The Blinky program could be considered the "Hello World" of Arduino Programming. In this section, we will rewrite the Blinky example for the Arduino using Mbed OS functions and classes. For reference, the regular Blinky is shown below.

void setup() {
	pinMode(LED_BUILTIN, OUTPUT);		// set LED_BUILTIN as an OUTPUT pin
}

void loop() {
	digitalWrite(LED_BUILTIN, HIGH);	// turn the LED on
	delay(1000);						// Wait for a second
	digitalWrite(LED_BUILTIN, LOW);		// turn the LED off
	delay(1000);						// wait for a second
}

Start by creating a new sketch, selecting the "Arduino Nano 33 BLE" under Tools>Boards, and including the mbed.h header file in the program. Additionally, bring all members of the mbed, rtos and std::chrono_literals namespaces into the current namespace through the using directive. This is required to be able to use all the Mbed OS functions and classes without having to repeatedly prefix them with mbed::, rtos:: and std::chrono_literals::. The code should look as follows -

#include <mbed.h>

using namespace mbed;
using namespace rtos;

using namespace std::chrono_literals;

Unlike in Arduino which uses functions to control the mode and state of the pins, Mbed OS encapsulates this behavior in classes. The following code can be used to create a global object of the DigitalOut class that controls the state of the pin LED1. I have named the object led, but any valid identifier name can be used. LED1, in this case, refers to pin 13 on the Arduino (which contains the built-in LED). A list of all pin numbers and their corresponding Mbed pin names is given at the end of this blog for your reference. The code should now look as follows -

#include <mbed.h>
 
using namespace mbed;
using namespace rtos;

using namespace std::chrono_literals;
 
DigitalOut led(LED1);

The above code implicitly sets the mode of pin 13, so the setup function can be left empty. Enter the following code in the loop, which switches on the pin, sleeps for a second, switches it off and waits for a second again. To set the state of the pin, the write method of the DigitalOut class has been used. To add delays within the program, the sleep_for function has been used from the ThisThread namespace. The function puts the current thread to sleep for the specified duration, during which other threads (or the OS) can execute.

Unlike the delay function used in regular Arduino programs, the function accepts the time as a chrono literal rather than an integer. The literal consists of a number with a suffix describing the units. For example, to create a delay of 500 milliseconds, the value 500ms should be used. For the current program, we use the value 1s to cause a delay of 1 second. A list of allowed suffixes for chrono literals are given at the end of this guide for your reference.

void loop() {
  led.write(1);                 // Switch the LED on
  ThisThread::sleep_for(1s);    // Wait for a second
  led.write(0);                 // Switch the LED off
  ThisThread::sleep_for(1s);    // Wait for a second
}

The complete code should look as follows -

#include <mbed.h>

using namespace mbed;
using namespace rtos;

using namespace std::chrono_literals;

DigitalOut led(LED1);

void setup() {
}

void loop() {
  led.write(1);                 // Switch the LED on
  ThisThread::sleep_for(1000);  // Wait for a second
  led.write(0);                 // Switch the LED off
  ThisThread::sleep_for(1000);  // Wait for a second
}

This concludes the Blinky program. You may verify and upload the program as with a regular Arduino program to see the LED blink.

Multitasking by spawning Threads

Now that we have finished blinking an LED, let's see how to spawn two threads to perform multiple tasks concurrently, therefore giving the effect of multi-tasking.

Once again, start by including the mbed.h header file and bringing members of the mbed and rtos namespaces into the current namespace. Also include all members from the std::chrono namespaces. This will be explained in a bit. Additionally, create two threads called t1 and t2 (you may use any valid identifier name, just make sure to substitute it in the remaining code) as shown below -

#include <mbed.h>

using namespace mbed;
using namespace rtos;
using namespace std::chrono_literals;

Thread t1;
Thread t2;

The threads will need functions to execute. Create two functions called func1 and func2. These functions should not return any value or accept any arguments. These functions will print the characters "A" and "B" to the Serial Monitor every 2 and 3 seconds respectively. The functions are also required to never return, so the code within them has been placed within infinite for(;;) loop blocks. The function

void func1() {
  for(;;) {                         // Repeat forever
    Serial.println("A");            // Print A to the Serial port
    ThisThread::sleep_for(2s);      // Wait for 2 seconds
  }
}

void func2() {
  for(;;) {                         // Repeat forever
    Serial.println("B");            // Print B to the Serial port
    ThisThread::sleep_for(3s);      // Wait for 3 seconds
  }
}

Finally, place the following code in the setup function to being Serial communication and start executing the threads using the provided functions. The loop function can be left empty.

void setup() {
  Serial.begin(9600);               // Start Serial communication

  t1.start(func1);                  // Pass func1 to t1 to start executing it as a independant thread
  t2.start(func2);                  // Pass func2 to t2 to start executing it as an independant thread
}

The complete code should look as follows -

#include <mbed.h>

using namespace mbed;
using namespace rtos;

using namespace std::chrono_literals;

Thread t1;
Thread t2;

void func1() {
  for(;;) {                         // Repeat forever
    Serial.println("A");            // Print A to the Serial port
    ThisThread::sleep_for(2s);      // Wait for 2 seconds
  }
}

void func2() {
  for(;;) {                         // Repeat forever
    Serial.println("B");            // Print B to the Serial port
    ThisThread::sleep_for(3s);      // Wait for 3 seconds
  }
}

void setup() {
  Serial.begin(9600);               // Start Serial communication

  t1.start(func1);                  // Pass func1 to t1 to start executing it as a independant thread
  t2.start(func2);                  // Pass func2 to t2 to start executing it as an independant thread
}

void loop() {                       // The loop function is executed in its own thread (left empty in this case)
}

This concludes the multi-tasking example. You may verify and upload the program as with a regular Arduino Program and upload the Serial Monitor to see the output.

Output on Serial Monitor for Mbed OS multitasking example program
Output on Serial Monitor

I hope you found this two-part series interesting and learnt something new. If you have any thoughts or queries, drop them in the comments below. I'd love to know them! Good Luck!

Reference

Allowed suffixes/units for chrono literals -

SuffixUnit of resulting LiteralExamples
hintegral/floating point hours1h, 1.5h
minintegral/floating point minutes10min, 20.5min
sintegral/floating-point seconds1s, 2.5s
msintegral/floating-point milliseconds500ms, 50.5ms
usintegral/floating-point microseconds750us, 1.5us
nsintegral/floating-point nanoseconds1ns, 10.5ns

Note that while all of the above literals are syntactically valid, the sleep_for function only accepts integral hours, minutes, seconds and milliseconds. Providing floating-point versions of these literals, or literals with smaller units causes an error during compilation.

Pin mappings from Arduino to Mbed -

Arduino Pin NumberMbed Pin NumberMicrocontroller Pin Name
D0P1_3Port 1 Pin 3
D1P1_10Port 1 Pin 10
D2P1_11Port 1 Pin 11
D3P1_12Port 1 Pin 12
D4P1_15Port 1 Pin 15
D5P1_13Port 1 Pin 13
D6P1_14Port 1 Pin 14
D7P1_23Port 1 Pin 23
D8P1_21Port 1 Pin 21
D9P1_27Port 1 Pin 27
D10P1_2Port 1 Pin 2
D11P1_1Port 1 Pin 1
D12P1_8Port 1 Pin 8
D13P0_13Port 0 Pin 13
A0P0_4Port 0 Pin 4
A1P0_5Port 0 Pin 5
A2P0_30Port 0 Pin 30
A3P0_29Port 0 Pin 29
A4P0_31Port 0 Pin 31
A5P0_2Port 0 Pin 2
A6P0_28Port 0 Pin 28
A7P0_3Port 0 Pin 3
Power LEDP1_9Port 1 Pin 9

9 thoughts on “Programming with Mbed OS on Arduino (part 2)”

  1. Pingback: Using Mbed with Arduino ARM Boards – DumbleBots

  2. For whatever reason wait() and wait_ms() do not work for me. I have resorted to wait_ns() to get your examples working here. Not sure what might have changed. Using arduino 1.8.13 on linux.

  3. I too am having issues with the “wait(n)” command. I’m also using IDE 1.8.13 and I’m using the latest board version (1.3.0). I noticed in your previous “getting started” page, you are using an much older version, 1.1.4. I’ve tried reverting to this older version and it did work.

  4. Mario Bochicchio

    The function wait is deprecated in favor of explicit sleep functions. To sleep, replace wait with ThisThread::sleep_for (C++) or thread_sleep_for (C). To wait (without sleeping), call wait_us. wait_us is safe to call from ISR context.

    1. Hi Mario,
      Thank you for your comment. I have updated the programs to use the latest APIs and removed the deprecated one.

  5. Nguyen Dang Tien Loi

    Thank you for you blog, it help me to start using my Arduino Portenta H7. Just a small comment on the Threads example, “using namespace rtos” instead of “usint namespace rtos”

Leave a Reply

Discover more from DumbleBots

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top