aRdTOS - A Simple Real Time Operating System for Arduino

Nov 8, 2016

You're afraid it's all been wasted time. -- The Eagles

One difficulty that almost all programmers run into at some point is making things happen when they need them to. Arduino users are no exception. About the only support that the Arduino environment gives to timing is the millis() function and the delay() function. That leads to a lot of wasteful and hard to understand code.

A Real Time Operating System (RTOS) is designed to make timing issues easier. There are hundreds, perhaps thousands, of RTOSs available, but most of them are rather complex and difficult to use. In addition, many of them are large or take too many resources to be effective on an Arduino. So, for my own use, I decided to create a very simple RTOS that takes as few resources as possible while still providing good capabilities. I thought others might find it useful, so I am making it available

What is an RTOS?

An RTOS is a (usually small) operating system that allows you to break your program up into tasks that each handle one part of your application. You create the tasks and tell the operating system (OS) what it needs to know about the task and its timing, then the OS will handle the timing aspects for you. As an example, suppose as part of your larger program you want to blink an LED off and on once each second. You could put in a lot of checks for the right number of millis or, even worse, put in a bunch of calls to delay(). But your code will get really messy, really fast. Instead, with an RTOS, you create a blink task and tell the OS you want it to run every 1/2 second. The blink task is very simple; it simply changes the LED from off to on or from on to off each time it runs. You won't need any messy timing code or blinking code anywhere else in your program!

How to Use aRdTOS

In aRdTOS a task is simply a function. You create a function that doesn't take any input and does not return anything. Then, you add the name of that function to your task list with the timing information you want. aRdTOS needs to be initialized by placing a call to the OS_Setup() function into your setup() Arduino function. Then, in your loop() function, you place a call to OS_Run() and the OS will take over from there.

To define your tasks they should be simple functions with no parameters and no return.

    void first_task()
    {
      do_some_stuff();
      do_more_stuff();
    }
  
ITasks should be VERY short. They are like interrupt service routines. All the ITasks that are enabled get run every millisecond, so time is critical. They should not include any time-consuming operations, like serial input or output. Regular tasks are much more forgiving. Put all the time-consuming operations in regular tasks.

After the tasks are defined, they must be listed in the task tables. The task tables are pretty simple. There is a table for regular tasks and one for ITasks. They are almost identical. Each entry in the tables has four parts: the function name, the starting time in "ticks", the cycle time in "ticks", and either a "1" to start the task running or a "0" to create the task in an inactive, non-running, state. Each table will have one entry for each defined task:

    TASKLIST
    TASK(task1, 20, 500, 1)
    TASK(task2, 0, 20, 1)
    ENDLIST

    ITASKLIST
    ITASK(itask1, 0,20,1)
    ITASK(itask2, 0,5,0)
    ENDLIST
  
The above example creates four tasks: two regular tasks and two itasks. task1 is set to start after 20 ticks, run again every 500 ticks, and is created active so that it starts running immediately. task2 will start with no delay, run again every 20 ticks, and start running immediately. itask1 will start with no delay, cycle every 20 ticks, and start immediately. itask2 will have no delay, will cycle every 5 ticks, but is created in the inactive state. It will not run at all until some other task "activates" it.

The two task lists should go after all the task functions. I put my task functions at the top of the program with the task lists after them, but before setup() and loop(). Another good alternative is to place the functions after setup() and loop() and the task lists at the very end. One bug in the library at the moment is that neither task list can be empty. If you don't need any tasks of a particluar type, create an empty function, list it in the task list, and set it to inactive.

    void empty_task()
    {
    }

    TASKLIST
    TASK(empty_task, 0,1,0)
    ENDLIST
  

The only two things left to do are initialize the OS in your setup and start the OS running:

    void setup()
    {
      // other setup stuffs here
      OS_Setup();
    }

    void loop()
    {
      // other processing stuff here
      OS_Run();    // Once we get here, control will not return!!!
    }
  

aRdTOS is still under heavy development. And so is the documentation. But it is working. You can take a look at the code and try it out by downloading it from github. The code there uses aRdTOS to blink two LEDs, the one onboard connected to pin 13 and another connected to pin 12, at different rates. It also prints messages to the serial monitor at different rates from two different tasks.

Downloads

The latest download is here: aRdTOS.zip
Download and install the library using the Arduino IDE as usual (Sketch/include library/install zip library)

Here is an example program: aRdTOS.ino

Here is an early version of the QuickStart Guide.

Feedback

I would appreciate any feedback you may have.If you have questions, I will try to answer them as time permits. Questions will help make aRdTOS, and the doumentation, better. You can send email to
cpu
at
smalltimeelectronics
dot
com



© 2016 William R Cooke