DuinOS: small and simple rtos

Hi Mark:

Although I found the bug, I would like to make first a few comments (anyway, in the point "6" below is the description of the bug and it's solution).

I see the following potential problems in your code:

  1. We do not recommend to call vSemaphoreCreateBinary(sem_pintest) from a taskLoop. It has to be done only once, so it will be better to call it in another place, like setup().

  2. Why use a for( ; ; ) inside a taskLoop? The taskLoops are already inside a for( ; ; ) cycle. So, a new cycle inside the taskLoop will not be the best practice, although it's possible, of course.
    I know this (as the whole project yet) is underdocumented, so I added a small section explaining the differences between FreeRTOS' tasks and DuinOS' tasks in the Tracker (still in the Tracker):

http://www.multiplo.org/duinos/wiki/index.php?title=Tracker

Please feel free to contribute!

I think in the v0.2 will add standard tasks (without the internal loop), comments are welcome. I'm studying if they will be better in some situations, and more efficient (due to the use of the stack).

  1. The xSemaphoreGive(sem_pintest) has to be called when your task frees the shared resource, so I do not understand why it's called from the loop() task, and not inside the if (xSemaphoreTake(sem_pintest, portMAX_DELAY) == pdTRUE). Please see the original FreeRTOS example, and the code below (point 6): This page describes the xSemaphoreTake() FreeRTOS API function which is part of the RTOS semaphore API source code function set.

  2. For the code below, please note that I used mutexes, cause think they are better for protecting resources (this is in general a case of mutual exclusion). If you want to use them, you will need to edit the FreeRTOS.h file, and define as "1" the configUSE_MUTEXES:

#ifndef configUSE_MUTEXES
      #define configUSE_MUTEXES 1
#endif

This will be the default in the DuinOS v0.2.

  1. This is not a problem, just a comment: If you only use binary semaphores, you do not need to include DuinOS/queue.h. But you will need it if using mutexes.

  2. The bug: The problem is that the println function uses too much LOCAL RAM when called from tasks. In DuinOS v0.1 the user can not redefine the RAM that the task STACK will alloc. So each new tasks, allocates only 85 bytes. I edited the main.cxx from the core, and modified the following line:

xTaskCreate(main_Task, (signed portCHAR *) "main", configMINIMAL_STACK_SIZE, NULL, mainLoopPriority, NULL);

changing it for this one:

xTaskCreate(main_Task, (signed portCHAR *) "main", 200, NULL, mainLoopPriority, NULL);

Fortunatly, DuinOS v0.2 will let the user to define the stack size for every task.

And finally, here you have a working sample, using mutexes, and I think a bit more clear, but please remember to make the modifications mentioned above (loop()'s stack size and MUTEXes inclussion):

#include <DuinOS.h>
#include <DuinOS/queue.h>
#include <DuinOS/semphr.h>

#define pinLED 13
volatile byte PIR_state = 0;
xSemaphoreHandle mutex_pintest = NULL;

taskLoop(PIR_sensor_task)
{
if(mutex_pintest != NULL)
{
if (xSemaphoreTake(mutex_pintest, portMAX_DELAY) == pdTRUE)
{
Serial.println("Task...");
Serial.println(0x1234, HEX);
xSemaphoreGive(mutex_pintest);
}
digitalWrite(pinLED, HIGH);
delay(200);
}
}

void setup()
{
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, LOW);

mutex_pintest = xSemaphoreCreateMutex();
if(mutex_pintest == NULL)
{
Serial.println("Mutex not created.");
}
createTaskLoop(PIR_sensor_task, LOW_PRIORITY);

Serial.begin(19200);
Serial.println("Hola!");
}

void loop()
{
Serial.println("Looping...");
Serial.println(PIR_state, HEX);
Serial.println(0x888, HEX);
delay(500);
digitalWrite(pinLED, LOW);
}

Regards (and happy 2010!)
Julián