FreeRTOS issues

I'm using FreeRTOS for a project on the uno, I'm waiting for a mega in the mail because the project is going to be scaled up and I need more outputs. Currently I'm trying to test basic features using the uno I currently have.

I have a main.ino in which the freeRTOS resides.

There are 3 tasks in the main and 3 other .cpp and .h files for each of those tasks that contain various functions the tasks need to use.

I have the 3 tasks communicating with a queue.

I ran into the issue where my tasks were being created but they were not started by the scheduler. I believe this is caused by the stack not having enough space but I'm not sure.

So I took one of the example programs and commented out everything in my main.c until it is essentially the same as one of the example programs that just displays which task is currently running in the serial monitor.

Once I start the serial monitor there is no output. The program got stuck in a while loop before the tasks start.

Then I copy and pasted my code into the example code's IDE then complied and uploaded and it worked perfectly.

In my main.ino's IDE I have the other 3 .cpp and .h files in tabs but in the example codes there is only the main.ino for the example.

Why does my code work in one IDE vs the other IDE when the code is exactly the same. I even commented out the #includes so they shouldn't even compile with the main.ino

Are we supposed to guess without being able to see ANY of your code? If so, then my guess is "you're doing something wrong". What that something is, I don't have the first clue. But, if we're just making wild-a$$ guesses, I'm trying to diagnose a problem with the traction control in my car. Can you tell me what's wrong with that?

Regards, Ray L.

If you find that figuring out FreeRTOS is using up more of your time than your own project then have a look at the simple way as illustrated in Several Things at a Time

...R

My apologies, I’m don’t think I made sense in my question originally the point I was trying to get across.

This is the code.

//#include "hardware.h"
//#include "initalize.h"
//#include "LCD.h"
//#include "pad.h"
//#include <Arduino.h> //arduino preproccessor includes by default
#include <Arduino_FreeRTOS.h>
//#include <queue.h>
#include <semphr.h>
//void manual_control(uint8_t array[]); //ardiuno ide work around
//typedef struct Message{
//  uint8_t mode_control;
//  uint8_t connection_status;
//  uint8_t button_status;
//  uint8_t LeftHatY;
//  uint8_t RightHatY;
//  uint8_t LeftHatX;
//  uint8_t RightHatX;  
//}xMESSAGE;
SemaphoreHandle_t xSerialSemaphore;
void TaskPad( void *pvParameters );
//void TaskLCD( void *pvParameters );
void TaskHardware( void *pvParameters );

//static QueueHandle_t xStatusQueue; // Creating Queue
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
  }
  if ( xSerialSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSerialSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage the Serial Port
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  // Make the Serial Port available for use, by "Giving" the Semaphore.
  }
  //  xStatusQueue = xQueueCreate(
  //    (unsigned portBASE_TYPE)10 // Queue size
  //    , (unsigned portBASE_TYPE) sizeof(xMESSAGE)// size of message
  //  );
  //lcd.clear();
  //lcd.print("queue created");
  xTaskCreate(
      TaskPad
      ,  (const portCHAR *)"PAD"   
      ,  128  // Stack size
      ,  NULL
      ,  2  // priority
      ,  NULL );
  //lcd.clear();
  //lcd.print("task1 created");
  xTaskCreate(
      TaskHardware
      ,  (const portCHAR *)"HARDWARE"   
      ,  128  // Stack size
      ,  NULL
      ,  2  // priority
      ,  NULL );
//
//  //lcd.clear();
//  //lcd.print("task2 created");
//  xTaskCreate(
//      TaskLCD
//      ,  (const portCHAR *) "LCD"
//      ,  32 
//      ,  NULL
//      ,  2  // priority //lower is lower priority
//      ,  NULL );
//  //lcd.clear();
//  //lcd.print("task3 created");

//  Serial.println(freeRAM());
  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
  //  vTaskStartScheduler();  // The scheduler is started in initVariant() found in variantHooks.c

}

void loop()
{
  //lcd.print("bad");
}

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

void TaskPad(void *pvParameters __attribute__((unused)) )  // This is a task.
{
//  initalize();
  
//  Serial.println("task test");

  //  xMESSAGE message; 
  //  portBASE_TYPE   status;
  //  uint8_t buttons;
  ////  if (0 == xStatusQueue) {
  ////    lcd.print("notinit"); 
  ////    return; //not initalized properly
  //  }
  

  for (;;) // A Task shall never return or exit.
  {
    
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
      // We were able to obtain or "Take" the semaphore and can now access the shared resource.
      // We want to have the Serial Port for us alone, as it takes some time to print,
      // so we don't want it getting stolen during the middle of a conversion.
      // print out the state of the button:
      Serial.println("task1");

      xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
    }

    //    Usb.Task();
    //    //polling pad values
    //    message.LeftHatY  = leftAnalogStickY();
    //    message.RightHatY = leftAnalogStickX();
    //    message.LeftHatX  = rightAnalogStickY();
    //    message.RightHatX = rightAnalogStickX();
    //    buttons = button_status_pad();  
    //    message.button_status=buttons;
    //
    //    if (buttons & (1 << 7)) message.connection_status = 1;
    //    else message.connection_status = 0;
    //
    ////    status = xQueueSend(xStatusQueue,(void*) &message,0); 
    ////    vTaskDelay(2);
    ////    if ( status != pdTRUE ){
    //      //queue full

    vTaskDelay(1);
  }
  
}
//void TaskLCD(void *pvParameters __attribute__((unused)) )  // This is a task.
//{
//  
////  Serial.println("task test");
//  //  xMESSAGE message; 
//  //  portBASE_TYPE   status;
//  //
//  ////  if (0 == xStatusQueue) return; //not initalized properly
//  //
//
//
//  for (;;)
//  {
//    
//    
//    //    status  = xQueueReceive (xStatusQueue,(void*) &message,portMAX_DELAY);
//
//    //    if (pdTrue == status)
//    //    {
//    //      connection_status_lcd((uint8_t)message.connection_status);  
//    //    }else
//    //    {
//    // no more messages in queue
//    //    vTaskDelay(2);
//    //    } 
//    vTaskDelay(2);
//  }
//}
void TaskHardware(void *pvParameters __attribute__((unused)) )  
{
//  lcd.clear();
  //Serial.println("task test");
  //  xMESSAGE  message;  
  //  portBASE_TYPE   status;
  ////  if (0 == xStatusQueue) return; //not initalized properly
  ////  uint8_t array[] = {127,127,127,127}; // initalize array to neutral value
  

  for (;;)
  {
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
      // We were able to obtain or "Take" the semaphore and can now access the shared resource.
      // We want to have the Serial Port for us alone, as it takes some time to print,
      // so we don't want it getting stolen during the middle of a conversion.
      // print out the value you read:
      Serial.println("task2");

      xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
    }
    vTaskDelay(2);
    //    status  = xQueueReceive (xStatusQueue,(void*) &message,portMAX_DELAY);
    ///   if (pdTrue == status)
    //    {
    //      if(message.connection_status==0) stop();
    //      array[0]=message.LeftHatY;  
    //      array[1]=message.RightHatY; 
    //      array[2]=message.LeftHatX;  
    //      array[3]=message.RightHatX; 
    //      manual_control(array);  
    //      vTaskDelay(2);
    //    }else
    //    {
    //      // no more messages in queue
    
    //    } 
  }
}

I have commented out everything not needed for a basic rtos program that will display which task is running in the serial console. I’ve done this because I could not figure out why my tasks were not running.

My project includes this as a main file, and various functions that are from the commented out header and c files. I’ve commented these out to eliminate anything that doesn’t have to do with just freeRTOS.

If I have my project open everything compiles and uploads to the board no issues. But no output from the serial console. I’ve triple check the baud rate in the serial console as well to make sure it matches.

This is the strange part to me. If I go open a example for the freeRTOS library, then delete all the code from the example, and then paste in the code above, upload to the board open the serial console, it does exactly what I’s suppose to do. Alternating between task1 and task2.

this is the code removing any lines with a comment.

#include <Arduino_FreeRTOS.h>
#include <semphr.h>

SemaphoreHandle_t xSerialSemaphore;
void TaskPad( void *pvParameters );
void TaskHardware( void *pvParameters );

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
  }
  if ( xSerialSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSerialSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage the Serial Port
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  // Make the Serial Port available for use, by "Giving" the Semaphore.
  }
  
  xTaskCreate(
      TaskPad
      ,  (const portCHAR *)"PAD"   
      ,  128  // Stack size
      ,  NULL
      ,  2  // priority
      ,  NULL );
  
  xTaskCreate(
      TaskHardware
      ,  (const portCHAR *)"HARDWARE"   
      ,  128  // Stack size
      ,  NULL
      ,  2  // priority
      ,  NULL );

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
  //  vTaskStartScheduler();  // The scheduler is started in initVariant() found in variantHooks.c

}

void loop()
{
 
}

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

void TaskPad(void *pvParameters __attribute__((unused)) )  // This is a task.
{

  for (;;) // A Task shall never return or exit.
  {
    
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
        Serial.println("task1");

      xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
    }

   
    vTaskDelay(1);
  }
  
}

void TaskHardware(void *pvParameters __attribute__((unused)) )  
{

  for (;;)
  {
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
        Serial.println("task2");

      xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
    }
    vTaskDelay(2);
   
  }
}

I have figured out the issue. The IDE will compile any code that is in the project and upload the board regardless if it is actually used or not.

This was causing a stack overflow causing my tasks not to run.

Hopefully once my mega board is in the main the 8kb of memory will be enough.

I doubt that is true (but I'm not a specialist in this area). The linker will happily throw away any compiled functions and variables that are not used.

Below code should demonstrate

void setup()
{
  char text[64] = "hello world";
  Serial.begin(250000);
  while (!Serial);

  Serial.println("hello world");  // 176 bytes of RAM used
  //Serial.println(text);         // 228 bytes of RAM used 
}

void loop()
{
}

As shown, the code use 176 bytes of RAM. If you comment out the first print and uncomment the second one, it used 228 bytes. The difference is 52 bytes; add to that the 11 plus 1 bytes used for the 'hello world' literal in the first print statement and it's exactly 64 bytes difference. Conclusion: the variable text is thrown away in the first version.

I'm referring to any .c or .cpp and .h files included in the project not in the .ino main sketch file

You commented out the vTASKScheduler here: // vTaskStartScheduler(); No tasks will run if you don't start the scheduler.