FreeRTOS on Arduino

pingpair_freertos dataflow

As I’ve started to dig into [FreeRTOS], I have found too few useful compilable examples on how to get started. The FreeRTOS tutorial is complicated and theoretical. It doesn’t leave you with any working running code. The Officially Supported demo for STM32 works, but it’s way too complicated, and assumes you have lots of hardware. Not a great way to get started. Maple comes with a tragically simple freertos-blinky.cpp, but all it does is show you how to blink the LED. What’s next?? Fortunately, I came across a page of FreeRTOS examples for WSN430 that helped a lot.

In this blog post, I wanted to share my own experience with porting real code to FreeRTOS, which does something more useful than blink a light, but not something unfathomably complicated. Along the way, this will explain how to exploit many of the features of FreeRTOS

Get the code from github:

Warming up: The easy examples

My FreeRTOS port contains four simple examples, which serve as good warmups to understand FreeRTOS. They are best approached in this order:

  1. Blinky. The usual suspect… Blinks the LED, FreeRTOS style. Obviously overkill for this simple case, but it should help show what’s going on.
  2. Twotasks. Blinks the LED AND prints a message, both on separate timers.
  3. Buttonled. Toggles the LED when you press and release a button on Pin 2. Demonstrates one way to handle debouncing.
  4. Manybuttons. Prints the state of many buttons when they change state. Demonstrates how to use parameters for a task, using the same task handler for multiple buttons.

RF24 pingpair

My final goal for this post is to port the very simple ‘pingpair’ example from RF24. This is the ‘hello world’ of RF radios, sending a message back and forth between two radios.


Let’s start by looking at the tasks. These are the main worker bees of a FreeRTOS application:

  • vSendTask: Periodically sends a packet to the other unit
  • vReceiveTask: Waits for incoming packets on the payload queue, and prints them out to the Serial. Then prepares an ack packet for the next received packet.
  • vStatusTask: Waits for status information on the status queue, and prints them out to the Serial
  • vRadioSoftIrqTask: Handles the work of the radio interrupt.

Interrupt Handler

The handling of interrupts is particularly interesting, using a ‘soft irq’ to do the real work. The idea behind this is that the interrupt handler does the absolute minimum possible work in the handler itself. In this case, all it does is wake up the vRadioSoftIrqTask, and return to regular processing. The problem with doing a lot of work in the interrupt handler is that EVERYTHING is put on hold while it executes, without regard to whether there is something more important happening. In the case of RF radio, receiving an incoming packet is important, but there is a 3-packet FIFO buffer, so we can wait a bit before processing them if something more important is happening.


  • xRadioIrqSemaphore: This is the mechanism that the radio irq uses to launch the softirq. The vRadioSoftIrqTask simply waits forever on this semaphore, and the radio irq handler simply posts to this semaphone and exits.


Mutexes are used to protect resources where we only want to have one task using them at a time.

  • xRadioMutex: All accesses to the radio are protected by this mutex, otherwise a high-priority task could interrupt a lower one who is currently using the radio for something else.
  • xConsoleMutex: Ensures that two things don’t write to the serial console at once. Currently, I wait on the mutex. To avoid deadlocks, it may be better to just abort if it’s not free. So far this has not been a problem.


Queues are how we pass information between tasks. Some tasks generate information, another task consumes it and does something with it.

  • xPayloadQueue: When the radio receives a frame, it places it into the Payload Queue. This way the radio’s softirq can be decoupled from the application logic. The radio fills the queue, and the application consumes it to do what it likes.
  • xStatusQueue: Status messages are placed into this queue.

Porting Decisions

When porting FreeRTOS, there are a few decisions to be made. These are embodied in FreeRTOSConfig.h

  • Memory allocator. I use heap_1.c, which is manages a static heap, and allows allocation only. No memory is ever freed. I think this is appropriate for a microcontroller with 2K SRAM.
  • Heap size. 1500 bytes of heap seems to be the practical limit.
  • Minimum stack size. 100 bytes of stack per task was the limit I found under experimentation, but 150 was better. Most tasks that do anything will need to be created with a 150+ stack size.

FreeRTOS on Arduino Uno?

FreeRTOS works great on 1284P and Maple. After some heavy experimentation, I was able to get the pingpair sketch working on an Arduino Uno clone. It turns out that a heap of 1300 and per-task stacks of 150 did the job. In total, 380 bytes of SRAM remain free when the sketch is loaded.

The question is whether this is a good idea. This is just a simple ‘hello world’ for radios, 380 bytes doesn’t leave much for more complex application logic or more tasks.



Filed under Arduino

7 responses to “FreeRTOS on Arduino

  1. “As I’ve started to dig into [FreeRTOS], I have found too few useful compilable examples on how to get started”


    Here are a list of pre-configured ready to run examples:

    If these are to complex (they are also used to test the kernel), then choose a new demo and you will find they come with a “simple” example and a “comprehensive” example.

    If that is still to complex, then choose one of these, they come with compilable code and an application note to example how to compile, and what the demo does. One even runs in a simulator so you don’t need hardware:

    For complete newbies there are tutorial books, that come with 16 or 18 example projects that start from very simple, and then gradually introduce more and more concepts:

    • > Really?

      Yup. I found all of those insufficient for various reasons.

      > Here are a list of pre-configured ready to run examples:

      Too complex to start with. Anything used to “test the kernel” is almost by definition too complex to get up to speed fast.

      > simple-freertos-demos

      Compilable for Cortex-M3 and simulator, sure, but we don’t want to simulate! We want to run code on Arduino hardware! Also perhaps too simple? It wasn’t clear from looking at the simple demo what useful thing it did. The WSN examples I linked to in my post are much better. They approach real-life problems, and do it in a simple clear way. By the end, they’re writing a MAC layer for their radios with it, so it steps up nicely from super simple to super useful. Perhaps your books do this…

      > For complete newbies there are tutorial books, that come with 16 or 18 example projects that start from very simple, and then gradually introduce more and more concepts

      This is probably what I really want. Those sound very interesting. In my post, though, I should have referred to “freely available” resources. Shouldn’t have to buy a book just to learn a tech. My view is, you buy the book when you get deep and you really need the expert insight.

      • Greg

        I had previously looked at FreeRTOS. I personally found it to be too large and too complex given the target. IMOHO, it doesn’t begin to look useful until you’re in the 2560 (maybe one step down; 2560 is what I have) and beyond, class of uC. ChibiOS, on the other hand, seems to be useful even on the low end of the AVR mega series, and likely others, and has all the advanced primatives needed for very complex architectures. Even better, since ChibiOS is smaller, lighter, lower latency, and faster, there isn’t a premium to be paid for multitasking, as is the case with FreeRTOS.

        Unless you exclusively work with 2560s, or even better, ARM on up, or if you can find something ChibiOS can’t do for you, I personally see no reason to bother with FreeRTOS. Doubly so if you’re trying to run on the PDIP 8-bit AVRs. At this point, I’ve looked at four RTOS/schedulers which can run on 8-bit AVR and so far, ChibiOS is the only one which worked within five minutes with little extra hoops or gotchas. In fact, I think the only potential gotcha for ChibiOS may be exactly which AVRs are supported.

  2. FreeRTOS on Arduino (Pololu, Freetronics)… fits like a glove on a hand.

    On the ATmega328p (Uno), I typically get 3 or 4 useful tasks running, before SRAM limits hit.

    FreeRTOS is really useful where tasks have to be blocked waiting for data to be available, or where multiple loops are needed at very different speeds. For example, I built a Pong game with open loop screen updates (260Hz), but video buffer updates based interrupts and queues. Easy on FreeRTOS.

    Some of my code here.

    And posts.

    I agree that ATmega1284p MCU hardware would be a great upgrade for Arduino.
    I can’t see myself bothering to learn the ARM platform in the short term.

  3. I’m just getting started with FreeRTOS, I agree there is a lack of simple but realistic examples. From a business point of view, selling support makes sense, but selling a beginners guide doesn’t. I would want to get as many people as possible using the product, then charge for more advanced or personalised support.

  4. George Matthews

    Thanks for review maniacbug! I use your RF24 library in my sketches and was looking at using RTOS. Does not appear to be worth the effort on small AVRs.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s