I'm trying to run 6 tasks in FreeRTOS on my embedded ESP32 board and got this error:
E (51687) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (51687) task_wdt: - IDLE0 (CPU 0)
E (51687) task_wdt: Tasks currently running:
E (51687) task_wdt: CPU 0: Read Modbus
E (51687) task_wdt: CPU 1: Connect MQTT
E (51687) task_wdt: Aborting.
The program will then reboot. I also can't read Modbus data as it returns timeout error, eventhough I can read it in superloop code. Here's my code:
#include <Arduino.h>
#include <ModbusRTUClient.h>
#include <ArduinoRS485.h>
#include <PubSubClient.h>
#include <RtcDS3231.h>
#include <iostream>
#include <string>
#include <Wire.h>
#include <SPI.h>
#include "FS.h"
#include "SD.h"
#define TINY_GSM_MODEM_SIM7600
#define SIM_RXD 32
#define SIM_TXD 33
#define PUSH_INTERVAL 60000
using namespace std;
#include <TinyGsmClient.h>
HardwareSerial SerialAT(1);
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqtt(client);
RtcDS3231 <TwoWire> Rtc(Wire);
RtcDateTime now = Rtc.GetDateTime();
RtcDateTime compiled; // Time at which the program is compiled
float volume, ullage;
char logString[200];
char monitorString[200];
String speed, latitude, altitude, longitude;
// GPRS credentials
const char apn[] = "v-internet";
const char gprsUser[] = "";
const char gprsPass[] = "";
// WiFi credentials
const char* ssid = "VIETCIS";
const char* password = "0976168268";
// MQTT credentials
const char* topic = "";
const char* broker = "";
const char* clientID = "";
const char* brokerUser = "";
// Task handles
static TaskHandle_t lteTaskHandle = NULL;
static TaskHandle_t gpsTaskHandle = NULL;
static TaskHandle_t modbusTaskHandle = NULL;
static TaskHandle_t rtcTaskHandle = NULL;
static TaskHandle_t sdTaskHandle = NULL;
static TaskHandle_t mqttTaskHandle = NULL;
// Task delay times
const TickType_t lteDelay = pdMS_TO_TICKS(5000);
const TickType_t gpsDelay = pdMS_TO_TICKS(1000);
const TickType_t modbusDelay = pdMS_TO_TICKS(1000);
const TickType_t rtcDelay = pdMS_TO_TICKS(60000);
const TickType_t sdDelay = pdMS_TO_TICKS(5000);
const TickType_t mqttDelay = pdMS_TO_TICKS(1000);
// Task prototypes
void connectLTE(void *pvParameters);
void readGPS(void *pvParameters);
void readModbus(void *pvParameters);
void checkRTC(void *pvParameters);
void logToSD(void *pvParameters);
void connectMQTT(void *pvParameters);
//Function prototypes
void appendFile(fs::FS &fs, const char * path, const char * message);
void writeFile(fs::FS &fs, const char * path, const char * message);
void mqttCallback(char* topic, byte* message, unsigned int len);
void parseGPS(String gpsData);
String getValue(String data, char separator, int index);
void setup() {
// Initialize serial communication
Serial.begin(115200);
SerialAT.begin(115200, SERIAL_8N1, 32, 33);
vTaskDelay(pdMS_TO_TICKS(3000));
Serial.println("Initializing modem...");
modem.restart();
// Enable GPS
Serial.println("Enabling GPS...");
modem.sendAT("+CGPS=1,1"); // Start GPS in standalone mode
modem.waitResponse(10000L);
Serial.println("Waiting for GPS data...");
vTaskDelay(pdMS_TO_TICKS(500));
// Print out compile time
Serial.print("Compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
vTaskDelay(pdMS_TO_TICKS(500));
// Initialize the Modbus RTU client
while (!ModbusRTUClient.begin(9600)) {
Serial.println("Failed to start Modbus RTU Client!");
Serial.println("Trying to reconnect");
ModbusRTUClient.begin(9600);
}
vTaskDelay(pdMS_TO_TICKS(500));
// Initialize DS3231 communication
Rtc.Begin();
compiled = RtcDateTime(__DATE__, __TIME__);
Serial.println();
// Disable unnecessary functions of the RTC DS3231
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
// Initialize the microSD card
if(!SD.begin(5)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
// Check SD card type
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
// Check SD card size
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
vTaskDelay(pdMS_TO_TICKS(500));
// If the log.txt file doesn't exist
// Create a file on the SD card and write the data labels
File file = SD.open("/log.txt");
if(!file) {
Serial.println("File doens't exist");
Serial.println("Creating file...");
writeFile(SD, "/log.txt", "Date,Time,Latitude, Longitude,\
Speed(km/h),Altitude(m), Volume(l),Ullage(l)\n");
}
else {
Serial.println("File already exists");
}
file.close();
// Initialize MQTT broker
mqtt.setServer(broker, 1883);
mqtt.setCallback(mqttCallback);
Serial.println("FAFNIR TANK LEVEL");
// Create FreeRTOS tasks
xTaskCreate(connectLTE, "Connect LTE", 2048, NULL, 1, <eTaskHandle);
xTaskCreate(readGPS, "Read GPS", 2048, NULL, 1, &gpsTaskHandle);
xTaskCreate(readModbus, "Read Modbus", 1280, NULL, 1, &modbusTaskHandle);
xTaskCreate(checkRTC, "Check RTC", 2048, NULL, 1, &rtcTaskHandle);
xTaskCreate(logToSD, "Log to SD", 3072, NULL, 1, &sdTaskHandle);
xTaskCreate(connectMQTT, "Connect MQTT", 2048, NULL, 1, &mqttTaskHandle);
vTaskDelete(NULL);
}
void loop() {
}
void connectLTE(void *pvParameters){
while(1){
Serial.print("Connecting to APN: ");
Serial.println(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
Serial.println("Fail to connect to LTE network");
ESP.restart();
} else {
Serial.println("OK");
}
if (modem.isGprsConnected()) {
Serial.println("GPRS connected");
}
vTaskDelay(lteDelay);
}
}
void readGPS(void *pvParameters){
while(1){
modem.sendAT("+CGPSINFO");
if (modem.waitResponse(10000L, "+CGPSINFO:") == 1) {
String gpsData = modem.stream.readStringUntil('\n');
// Check if the data contains invalid GPS values
if (gpsData.indexOf(",,,,,,,,") != -1) {
Serial.println("Error: GPS data is invalid (no fix or no data available).");
} else {
Serial.println("Raw GPS Data: " + gpsData);
// Call a function to parse the GPS data if valid
parseGPS(gpsData);
}
vTaskDelay(pdMS_TO_TICKS(5000));
} else {
Serial.println("GPS data not available or invalid.");
}
vTaskDelay(gpsDelay);
}
}
void readModbus(void *pvParameters){
while(1){
volume = ModbusRTUClient.holdingRegisterRead<float>(4, 0x0036, BIGEND);
if (volume < 0) {
Serial.print("Failed to read volume: ");
Serial.println(ModbusRTUClient.lastError());
} else {
Serial.println("Volume: " + String(volume));
}
vTaskDelay(pdMS_TO_TICKS(100));
ullage = ModbusRTUClient.holdingRegisterRead<float>(4, 0x003C, BIGEND);
if (ullage < 0) {
Serial.print("Failed to read ullage: ");
Serial.println(ModbusRTUClient.lastError());
} else {
Serial.println("Ullage: " + String(ullage));
}
vTaskDelay(modbusDelay);
}
}
void checkRTC(void *pvParameters){
while(1){
// Validate RTC date and time
if (!Rtc.IsDateTimeValid())
{
if ((Rtc.LastError()) != 0)
{
Serial.print("RTC communication error = ");
Serial.println(Rtc.LastError());
}
else
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
}
// Ensure the RTC is running
if (!Rtc.GetIsRunning())
{
Serial.println("RTC was not actively running, starting now");
Rtc.SetIsRunning(true);
}
// Compare RTC time with compile time
if (now < compiled)
{
Serial.println("RTC is older than compile time! (Updating DateTime)");
Rtc.SetDateTime(compiled);
}
else if (now > compiled)
{
Serial.println("RTC is newer than compiled time! (as expected)");
}
else if (now == compiled)
{
Serial.println("RTC is the same as compile time! (not expected but acceptable)");
}
vTaskDelay(rtcDelay);
}
}
void logToSD(void *pvParameters){
while(1){
char datestring[20];
char timestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u"),
now.Month(),
now.Day(),
now.Year());
snprintf_P(timestring,
countof(timestring),
PSTR("%02u:%02u:%02u"),
now.Hour(),
now.Minute(),
now.Second());
snprintf(logString, sizeof(logString), "%s,%s,%s,%s,%s,%s,%f,%f\n",
datestring, timestring, latitude, longitude, speed, altitude, volume, ullage);
appendFile(SD, "/log.txt", logString);
snprintf(monitorString, sizeof(monitorString), "%s %s\nLatitude: %s\nLongtitude: %s\
\nSpeed: %s(km/h)\nAltitude: %s(m)\nVolume: %.1f(l)\nUllage: %.1f(l)",
datestring, timestring, latitude, longitude, speed, altitude, volume, ullage);
mqtt.publish(topic, monitorString);
vTaskDelay(sdDelay);
}
}
void connectMQTT(void *pvParameters){
while(1){
while (!mqtt.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (mqtt.connect(clientID)) {
Serial.println("Connected");
// Subscribe
mqtt.subscribe(topic);
} else {
Serial.print("Failed, rc=");
Serial.print(mqtt.state());
Serial.println("Try again in 5 seconds");
vTaskDelay(mqttDelay);
}
}
mqtt.loop();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void parseGPS(String gpsData){
// Split the string by commas
int index = 0;
latitude = getValue(gpsData, ',', 0) + getValue(gpsData, ',', 1);
longitude = getValue(gpsData, ',', 2) + getValue(gpsData, ',', 3);
altitude = getValue(gpsData, ',', 6);
speed = getValue(gpsData, ',', 7);
}
String getValue(String data, char separator, int index) {
int found = 0; // Found separator
int strIndex[] = {0, -1}; // Array to hold the start and end index of the value
int maxIndex = data.length() - 1; // Get the maximum index of the string
// Loop ends when it reaches the end of the string and there are more separators than indices
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void mqttCallback(char* topic, byte* message, unsigned int len) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < len; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
}
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file) {
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("File does not exist, creating file...");
file = fs.open(path, FILE_WRITE); // Create the file
if(!file){
Serial.println("Failed to create file");
return;
}
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
I have tried adding more non-blocking vTaskDelay
and changing the priority of the tasks but the same error happens.
I'm still new to FreeRTOS. Any help is appreciated.
Use esp_err_t esp_task_wdt_init(uint32_t timeout_seconds, bool panic)
to configure watchdog timeout in setup()
. The range of timeout is 0-60 secs. panic
sets the alarm:true
if alarm is needed, otherwise it's false