Using FreeRTOS along with Arduino

Hello Everyone, So I was trying to implement the FreeRTOS along with Arduino by setting up a simple circuit.

Working: I have two LED's - Blue (Pin 11) and Red (Pin 12). So, My idea was to make Red Led as a lower priority task and the Blue Led will be the higher priority task which will turn on when the potentiometer is rotated (I used Analog Comparator for this instance). When the poteniometer is rotated, it runs the in-built function called enableinterrupt() which is inside of the analogComp library. So, when the interrupt is raised I try to create an Event by setting BIT_0 of the Event Group to 1 which leads to Blue LED to light up.

Results: I do see the Blue LED lighting up when I rotate the potentiometer. But there is something I noticed in two instances:
1.) When I keep the Red LED just HIGH, The Blue LED lights up and goes low but the Red stays high during whole time.
2.) When I toggle the Red LED high to low and also incorporate delays within, I still see that for some time the both LED's are on.

I was under the impression that since the Blue LED is of a higher priority task, it would lead the lower priority task to be suspended while it finishes execution which I am not able to see with my naked eye. So, to resolve this Can you please suggest what I should be doing so that I becomes evident to the visible eye that Red Led should be off when Blue Led is on?

Here is a code that I am running:

#include <Arduino_FreeRTOS.h>
#include <event_groups.h>
#include <analogComp.h>

// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );

//define function call for setting bits for Event group
void aFunction(EventGroupHandle_t  xEventGroup);

//Declaring a variable to hold the event group which will be created
EventGroupHandle_t xCreatedEventGroup;

//define bit for event
#define BIT_0 (1<<0)

// the setup function runs once when you press reset or power the board
void setup() {
  
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);


  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
  }
  //We create a event group
  xCreatedEventGroup = xEventGroupCreate();
  
  //If the event group was not created successfully. 
  if(xCreatedEventGroup == NULL){
  Serial.println("The event group did not get created.");
  }
  //if the event group was created succesfully.
  else {
    //aFunction(xCreatedEventGroup);
    analogComparator.setOn(AIN0,AIN1);
    analogComparator.enableInterrupt(aFunction,CHANGE);
    }

  // Now set up two tasks to run independently.
  xTaskCreate(
    TaskBlink
    ,  "Blink"   // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  1  // Priority, with 1 (configMAX_PRIORITIES - 1) 3 being the highest, and 0 being the lowest.
    ,  NULL );
    
      xTaskCreate(
    TaskAnalogRead
    ,  "AnalogRead"
    ,  128  // Stack size
    ,  NULL
    ,  2  // Priority
    ,  NULL );

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop()
{
  // Empty. Things are done in Tasks.
}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  pinMode(12,OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    digitalWrite(12, HIGH);   // turn the LED on (HIGH is the voltage level)
    vTaskDelay(pdMS_TO_TICKS(1000) ); // wait for one second
    digitalWrite(12, LOW);    // turn the LED off by making the voltage LOW
    vTaskDelay( pdMS_TO_TICKS(1000) ); // wait for one second
  }

}

void TaskAnalogRead(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  
  EventBits_t uxBit;
  
  for (;;)
  {
    uxBit = xEventGroupWaitBits(xCreatedEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);
      if((uxBit & BIT_0) != 0){
       digitalWrite(11,HIGH);
       vTaskDelay(pdMS_TO_TICKS(500));
       digitalWrite(11,LOW);
    }
  }
  
}

void aFunction(){
     xEventGroupSetBitsFromISR(xCreatedEventGroup,BIT_0,pdFALSE);
  }

Your description of what you want is not very clear. Perhaps post a timing diagram of the LED behavior that you're looking for relative to the comparator trigger event.

Hello gfvalvo,

Thank you for your reply. I meant by the question that how can I change/edit the code so that the lower priority task which is turning on RED LED is blocked or suspended when the higher priority task is pre-empted by potentiometer rotation?

unless a task terminates, what do you think "finishes execution" means?

My request still stands:

You're mis-understanding "suspend" or "block."
Whenever your task does a vTaskDelay(), that causes the task to suspend, and (perhaps) run other tasks. Regardless of priority. Essentially, the normal state of a task is suspended, and it only runs the scheduler decides that:

  1. The task is runnable: it is not delaying, or waiting for some event to occur.
  2. No higher priority task is also runnable.
    In your case both tasks are spending most of their time in vTaskDelay(), which is to say that they are NOT runnable.

Likewise, a task suspends (stops running) when:

  1. It voluntarily suspends by calling a blocking function (like vTaskDelay())
  2. A higher priority task becomes runnable (due to some event occurring.)
  3. The task's runtime limit is exceeded.

"Priority" is frequently a red herring - you don't need each task to have a different priority, and in fact the usual state of a multi-tasking systems is that nearly ALL of the tasks will be running at the same priority.

Ohhh, So If I understand it right when the vTaskDelay() is called either from higher or lower priority task, that just enables the next available task to be run? In that sense do you think the time I gave for the delay is what I need to resolve? As I am trying to visually see these two different LEDs light up.

Make the Blue LED task stop the Red LED task and turn the Red LED off. Also make it resume the Red LED task if no event is detected.

In FreeRTOS parlance, Blocked and Suspended are two different states. What you subsequently described is the Blocked state. A task enters this state voluntarily (vTaskDelay, pending on a Queue, Semaphore, Event Bit, Timer, etc) and exits (into the Ready-to-Run state) when the condition is met. Suspending a task entirely removes it from consideration by the scheduler. It can only be restarted by another task calling vTaskResume(). There is usually no reason to suspend a task.

The following concisely describes the scheduler’s operation:

A task that is running will continue to run unless one of three things happens:

  1. A task of higher priority enters the Ready to Run state.

  2. The running task’s time slice has expired and there are one or more tasks of equal priority that are in the Ready to Run state. If so, one of these tasks will run.

  3. The running task enters the Blocked state.

Hello @DrDiettrich , Thank you for your reply. As per your comment I did two things:

1.) I declared a global variable of type boolean which is help me keep status of the event. So, if the event occurred I will make this variable true and if not then I will make it false.

2.) Based on this status the one of the tasks will be running at a time. Also, I have set the RED LED to LOW when the Blue LED function is being executed.

Hello @gfvalvo, Thank you for your insight. I think I understand it better now. Can you please shed light on one more instance?
1.) So, in the code that I have given in the question. The tasks are running as per the requirement where the the blue led turns on when potentiometer is rotated, else red led will keep on toggling but these tasks switching happen so fast that it seems that the switching is not happening.

2.) Do you think if I were to use Mutex or Semaphore for further synchronization between tasks that would help me achieve what I want?

Then you don't need two tasks. A single task can check the status (or event) and act accordingly.

1 Like

To me anyway, exactly what you want is unclear. That's why I asked (twice) for a timing diagram showing the actions of each LED both before and after the potentiometer event.

The thing is am not quite sure as to how to get the timing diagram.

Draw it by hand. Scan. Post.

So basically, you want the red led to stop flashing when the blue led flashes??
kind of defeats multitasking but there are times when you want to control one task from the other..
maybe this helps..
Control blinks..

hopefully be able to port..

good luck.. ~q

Hello @qubits-us , Thank you for your reply. I did check the post that you pasted. I see that both the tasks are of same priority in this case and you are running the two tasks independently based on timing if am not wrong? and the synchronization between two tasks is taken care by Semaphore?

I also want to ask that why did you say: kind of defeats multitasking?

I also tried using Semaphore but I too had to make both the tasks of same priority but the RED LED blinked only once whereas the BLUE LED could be made to blink as many times I rotated the potentiometer.

How odd. I'm used to OSes where suspend() was the equivalent of what I guess is yield() in FreeRTOS or MBed. Tasks could voluntarily call suspend() if they wanted to (essentially) shorten their time-slice ("I am doing a long compute-bound operation. but I don't really care how long it takes.")

Hello friends of the Arduino Forum

I am always curious about new knowledge.

Why do you need an operating system to make LEDs flash?

Can't this be done more easily and quickly with a structured array with member functions?

You don't. But it's a way to learn about how to use an RTOS (and how it works.)

1 Like