Some (very!) basic questions to RTOS...

Hello all -
I'm trying since a couple of days to find some basic informations how to get started with one of the RealTimeOS's out there.
Even here I found some related Topics, but nothing what really gets me started.

Here is what I bring:

  • some basic experiences in different programming languages, though I'm not a great programmer, I can hold my own

Here is what I want to do:

  • I want to run two independent Tasks
  • one of them has 3 PWM outputs running
  • both have interrups internal and external and timers
  • one task needs to read variables, which are updated by the other
  • the project should run on an Arduino Nano, Uno and Pro Mini

Here is where I need help with:

  • Is it doable?
  • what do I need for this?
  • how do I do the first steps, like what do I do with the files I can download somewhere etc.
  • some very simple examples how to programm in 'real time'

I hope, someone here can point me in the right direction to get me started.
Thank you in advance for any help,
EWo

This is not encouraging...
Is there really no one who could help with some hints and who could point me in the right direction?

I would appreciate, if someone could help here.
Thank you very much,
EWo

I have ported three RTOS's to Arduino Google Code Archive - Long-term storage for Google Code Project Hosting..

There are a number of examples so you can download the libraries and run the examples.

Both ChibiOS/RT and FreeRTOS have good websites.

http://www.chibios.org/dokuwiki/doku.php?id=start

I think that you're relatively confused. For example:

Here is what I want to do:

  • I want to run two independent Tasks
  • one of them has 3 PWM outputs running

The Arduino has 6 PWM outputs supported by hardware. That means you don't need a task to implement PWM; the PWM pins will happily output their waveforms with no SW intervention at all.

  • both have interrups internal and external and timers

Likewise, the interrupt and timers are hardware functions that have very little to do with any RTOS that may or may not be running; they can be thought of as things that occur "outside" of the task structure.

An RTOS tends to be useful when your tasks need to wait for some resource, like a slow interface (serial), a long timer, or a human. When one task is waiting, it can let other tasks do other things. An RTOS might provide access to a timer "utility" (via a "wait_us()" call or similar), and it might provide restrictions on what can be done in an interrupt service routine (or order to maintain the "real time" parts of its behavior), but your list of wants doesn't really include anything that requires, or would want, an RTOS to accomplish.

An example of an application that might benefit from an RTOS, at least for simplicity, is a robot that wants to control ten servos while having another task do some other process. The times involved in controlling a servo are "long" by CPU standard, so there should be lots of spare time for other code to run. You can implement it all without an RTOS, but it would be relatively complicated. WITH an RTOS, it might look like:

void setup() {
  task_start(mainTask);
  task_start(servosTask);
  task_scheduler();
}

void servosTask() {
 while (1) {
  for (i=0; i < N_SERVOS; i++)  {
     int t = servo_time[i];
     digitalWrite(servo_pins[i], HIGH);  // Start pulse
     task_wait_us(t);
     digitalWrite(servo_pins[i], LOW);  // Stop pulse
     task_wait_us(2000 - t);  // wait for rest of servo "slot"
  }
 }
}

void mainTask() {
  // Whatever
}

your list of wants doesn't really include anything that requires, or would want, an RTOS to accomplish.

This is probably true. I have found very few Arduino hobbyists who are doing projects that require a RTOS.

Quite a few users contact me with more professional uses for Arduino. I was just contacted by a Mechanical Engineering student who is doing a senior project. This student is doing experiments where he needs to log data from a number of sensors at several hundred Hz and others at a slower rate. The sensors include strain gauges, an IMU (inertial measurement unit), and pressure gauges. There are also some control functions for the Arduino.

He is using NilRTOS which runs on a 328 and is very small.

Likewise, the interrupt and timers are hardware functions that have very little to do with any RTOS that may or may not be running; they can be thought of as things that occur "outside" of the task structure.

This is absolutely false! A key reason for running a RTOS is to efficiently do I/O involving interrupts. A RTOS allows efficient synchronization of I/O with tasks

Here are some examples that are important for the Mechanical Engineering project.

NilRTOS has a replacement for AnalogRead that saves CPU time by allowing lower priority tasks to run while the ADC is digitizing a value. This replacement starts the ADC conversion then does a wait on a semaphore. This causes a context switch to a lower priority task. When the ADC done interrupt occurs, the ISR signals the semaphore which cause the return from the ISR to be a context switch to the higher priority task which reads the ADC value.

The ADC read in NilRTOS looks like this:

  v = nilAnalogRead(pin);

So the user doesn't see the RTOS complexity but about 90 us of CPU time is saved for each ADC read. The standard Arduino analogRead takes about 110 us and most of this time is wasted.

NilRTOS has a similar replacement for the Wire library. The Arduiono Wire library is interrupt driven but Wire just waits
in a busy loop while I2C I/O is done in interrupt routines. The replacement library has the same API as wire.

In addition the we replaced delay() calls in the sensor libraries with RTOS sleep calls. Some pressure sensors take a very long time to digitize. For example the standard Arduino library for the BMP085 Barometric Pressure sensor has a 26 ms delay calls.

It is easy to make an Arduino library RTOS friendly and more efficient with a few macros.

Replace analogRead calls:

#define analogRead(pin) nilAnalogRead(pin);

Replace delay calls:

#define delay(ms) nilSleep(ms)

Use the nil I2C library instead of Wire by including NilTwi.h instead of Wire.h

NilRTOS has a FIFO buffer class that allows easy communication between the high priority sensor read task that runs at several hundred Hz with low jitter and the SD logger task that can have occasional write latencies of over 100 ms.

This has worked well for the ME student and he didn't need to learn about ISRs and other Arduino tricks.

Hi fat16lib,
i'm working on a datalogger project.
I'm thinking of using NilRTOS but i have a question about the power management.
In what sleep modes niltros works? Idle, power down, power safe...?
Thank you for your attention and for your work.

NilRTOS has no built-in support for low power modes. You could implement low power sleep by by having all threads except the idle thread wait on a semaphore and implement sleep in the idle thread.

FreeRTOS has more low power features Tickless Low power features in FreeRTOS.

You will still need to implement the FreeRTOS portSUPPRESS_TICKS_AND_SLEEP() function for AVR.

Would it be possible to use watchdog for ie. 16ms or 32ms ticks with nilrtos?

pito,

It is not simple to change the tick since I use timer 0 which is setup by the Arduino init() program and is used by delay(), micros(), and millis(). I use the TIMER0_COMPA interrupt for tick.

I plan to implement optional use of timer 2 for tick. This would allow all kinds of options.

I like RTOS systems that allow deep sleep during periods when no threads needs to run. These systems have an API that allows the system clock to be updated when the CPU comes out of sleep. You just need to know how long the system was sleeping.

Too bad Arduino doesn't have better sleep primitives that could used for RTOS/schedulers and would synchronize with at least delay() and millis().

I see two ways:

  1. watchdog and to use 16ms tick also for millis(), not precise and low resolution, but it may cover 80% applications, lowest idle current
  2. T2 with 32khz watch resonator, millis() derived from T2 gives a 977us tick, more precise, a bit higher idle current, internal 8MHz clock needed (or internal clock set with OSCCAL somewhere within 5-15MHz range).