Giovanni Di Sirio has posted an updated version of Nil RTOS and I have ported this version to AVR Arduinos.
Giovanni Di Sirio is also the author of ChibiOS/RT and his current plan is for Nil RTOS to have "API and types reorganized in order to converge Nil with ChibiOS 3.0.".
The download file is NilRTOS20130720.zip http://code.google.com/p/rtoslibs/downloads/list.
Nil RTOS is an excellent fit for Uno. Here is an example of its small size. This simple Standard Arduino sketch to blink the pin 13 LED uses 1076 bytes of flash.
/* Simple blink for sizze comprare with Nil RTOS blink */
// The LED is attached to pin 13 on Arduino.
const uint8_t LED_PIN = 13;
//------------------------------------------------------------------------------
void setup() {
pinMode(LED_PIN, OUTPUT);
}
//------------------------------------------------------------------------------
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
delay(200);
}
This Nil RTOS demo sketch with the idle thread plus two higher priority threads, a semaphore, and sleep functionality takes only 2116 bytes of flash. Only 1076 bytes for a priority based preemptive RTOS.
/*
* Example to demonstrate thread definition, semaphores, and thread sleep.
*/
#include <NilRTOS.h>
// The LED is attached to pin 13 on Arduino.
const uint8_t LED_PIN = 13;
// Declare a semaphore with an inital counter value of zero.
SEMAPHORE_DECL(sem, 0);
//------------------------------------------------------------------------------
/*
* Thread 1, turn the LED off when signalled by thread 2.
*/
// Declare a stack with 128 bytes beyond context switch and interrupt needs.
NIL_WORKING_AREA(waThread1, 128);
// Declare the thread function for thread 1.
NIL_THREAD(Thread1, arg) {
while (TRUE) {
// Wait for signal from thread 2.
nilSemWait(&sem);
// Turn LED off.
digitalWrite(LED_PIN, LOW);
}
}
//------------------------------------------------------------------------------
/*
* Thread 2, turn the LED on and signal thread 1 to turn the LED off.
*/
// Declare a stack with 128 bytes beyond context switch and interrupt needs.
NIL_WORKING_AREA(waThread2, 128);
// Declare the thread function for thread 2.
NIL_THREAD(Thread2, arg) {
pinMode(LED_PIN, OUTPUT);
while (TRUE) {
// Turn LED on.
digitalWrite(LED_PIN, HIGH);
// Sleep for 200 milliseconds.
nilThdSleepMilliseconds(200);
// Signal thread 1 to turn LED off.
nilSemSignal(&sem);
// Sleep for 200 milliseconds.
nilThdSleepMilliseconds(200);
}
}
//------------------------------------------------------------------------------
/*
* Threads static table, one entry per thread. A thread's priority is
* determined by its position in the table with highest priority first.
*
* These threads start with a null argument. A thread's name may also
* be null to save RAM since the name is currently not used.
*/
NIL_THREADS_TABLE_BEGIN()
NIL_THREADS_TABLE_ENTRY("thread1", Thread1, NULL, waThread1, sizeof(waThread1))
NIL_THREADS_TABLE_ENTRY("thread2", Thread2, NULL, waThread2, sizeof(waThread2))
NIL_THREADS_TABLE_END()
//------------------------------------------------------------------------------
void setup() {
// Start Nil RTOS.
nilSysBegin();
}
//------------------------------------------------------------------------------
// Loop is the idle thread. The idle thread must not invoke any
// kernel primitive able to change its state to not runnable.
void loop() {
// Not used.
}
The nilContext example demonstrates the speed of the Nil RTOS scheduler. A semaphore signal plus a thread context switch takes just over 12 microseconds on an Uno.
I wrote a ascii data-logging sketch as a more realistic example. This sketch is able to log four analog pins on an Uno at 2,000 Hz, a total of 8,000 ascii analog values/second, to an SD without dropping data points. This is very difficult to do without a small fast RTOS.