Task Scheduling with FreeRTOS

I have scheduled 3 different process to run at every 10s, 1min and 1 min respectively using FreeRTOS. However I relized that the timing is totally off and some processes do not even run as well. Below is my code. Am I doing something wrong here. This is my first tiime using any RTOS.

#include <Arduino_FreeRTOS.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

TaskHandle_t smsChecker_Handler;
TaskHandle_t toggleLED_Handler;
TaskHandle_t readGPS_Handler;

int n = 0;
String lon;
String lat;
byte c;
byte ch;
String recvMsgs = "";
String recvMsg;
String sdata = "";
byte Rx = 10;
byte Tx = 11;
//float readings[4];
SoftwareSerial gpsmodule(Rx,Tx); 
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.begin();
  Serial.begin(115200);
  gpsmodule.begin(115200);
  pinMode(13,OUTPUT);
  pinMode(9,OUTPUT);
  digitalWrite(13,LOW);
  digitalWrite(9,LOW);
  // Giving time for GSM/GPS module to lock onto a network
  delay(2000);
  xTaskCreate(readGPS, "Task1", 100, NULL, 1, &readGPS_Handler);
  xTaskCreate(toggleLED, "Task2", 100, NULL, 1, &toggleLED_Handler);
  xTaskCreate(smsChecker, "Task3", 100, NULL, 2, &smsChecker_Handler);
  //xTaskCreate(MyIdleTask, "IdleTask", 100, NULL, 0, NULL);
}

void loop(){
  //do nothing
}

void readGPS(void* pvParameters){
  TickType_t getTick1;
  getTick1 = xTaskGetTickCount();
  
  lcd.clear();
  gpsmodule.print("AT+GPS=1\r");
  delay(1000);
  while (gpsmodule.available() > 0){
    Serial.write(gpsmodule.read());
  }
  gpsmodule.print("AT+LOCATION=2\r");
  delay(5000);
  while (gpsmodule.available() > 0){
    c = gpsmodule.read();
    sdata+=(char)c;
  }
  delay(10);
  lat = sdata.substring(16,23);
  lon = sdata.substring(25,31);
  lcd.setCursor(0,0);
  lcd.print("Lat: ");
  lcd.print(lat);
  lcd.setCursor(0,1);
  lcd.print("Lon: ");
  lcd.print(lon);
  //coordinates = sdata.substring(16,32);
  //Serial.println(coordinates);
  //vTaskDelay(60000/portTICK_PERIOD_MS);
  vTaskDelayUntil(&getTick1,60000/portTICK_PERIOD_MS);
}

void toggleLED(void* pvParameters){
  TickType_t getTick2;
  getTick2 = xTaskGetTickCount();
  Serial.println(n);
  if (n % 2 == 0){
    digitalWrite(13,LOW);
    digitalWrite(9,HIGH);
  } else {
    digitalWrite(13,HIGH);
    digitalWrite(9,LOW);
  }
  n++;
  vTaskDelayUntil(&getTick2,60000/portTICK_PERIOD_MS);
}

void smsChecker(void* pvParameters){
  TickType_t getTick3;
  getTick3 = xTaskGetTickCount();
  lcd.clear();
  gpsmodule.print("AT+CMGF=1\r");
  delay(500);
  while (gpsmodule.available() > 0){
    Serial.write(gpsmodule.read());
  }
  gpsmodule.print("AT+CNMI=2,2,0,0,0\r");
  delay(2000);
  while (gpsmodule.available() > 0){
     ch = gpsmodule.read();
     recvMsgs+=(char)ch;
   } 
   delay(10);
   //recvMsg = recvMsgs.substring();
   lcd.setCursor(0,0);
   lcd.print(recvMsgs);
   Serial.println(recvMsgs);
   //vTaskDelay(10000/portTICK_PERIOD_MS);
   vTaskDelayUntil(&getTick3,10000/portTICK_PERIOD_MS);  
}

Which Arduino board do you use ?

100 bytes of stack ? That is a very small stack. Does FreeRTOS have a runtime check for stack overflow ?

I am using an arduino uno

The SoftwareSerial uses almost the complete Arduino Uno. I think combining that with FreeRTOS will not work smooth. In the sketch are about 5 String objects. They allocate memory from the heap. Some say it is better not to use the String objects on a Arduino Uno, because of the small SRAM memory.

I did some tests with FreeRTOS on a Arduino Uno, but that was not combined with String objects nor with the SoftwareSerial library. Even then I ran into problems very quickly.

It is just too much for the Arduino Uno.

When you would use a Leonardo with millis(), then you don't need FreeRTOS to do multiple things at the same time, and you don't need the SoftwareSerial and the stack usage will be very little.

Or try an ESP32. That has extra serial ports and already FreeRTOS.

About the timing, I think there must be better ways, for example start a task from a timer. But I don't know FreeRTOS that well.

I tried doing the same thing with millis() and it worked quite well until I added the smsChecker function which broke everything. I figured using RTOS would sort that out for me. Guess I was mistaking.

Edit - SoftwareSerial does not work well at high baud rates. Try reduce to gpsmodule.begin(9600); It may solve a lot of your problems, but you don't need FreeRTOS.

Try these two tutorials. You can get very effective multi-tasking without using FreeRTOS

How to write Timers and Delays in Arduino and
Multi-tasking in Arduino

multitaskingDiagramSmall

Other things to look at. Strings on Uno are very very safe and memory allocation does not take much cpu time. They do use memory but if you reserve space, they only use a few bytes more than a char [ ] and are much safer to code with.
See Taming Arduino Strings for guidelines on using lots of Strings in your projects.

Debug output can also cause you problems. Serial.print( ) will block once the TX buffer fills up, see Arduino Serial I/O for the Real World for how to get a non-blocking debug output and how you increase your RX buffer size to avoid missing input.
I would start by reducing this baud rate
gpsmodule.begin(115200);
to say 9600

1 Like

@drmpf this looks quite interesting. I am trying out some of functionalities of the safestring library specifically millisDelay and it appears to respond really good. I am getting way more better responses.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.