I have a small project with Arduino that uses FreeRTOS.
In this project I create 2 tasks:
task 1 function is to read temperature, humidity and gas concentration sensor values from DHT11 and MQ2 sensors, then it displays these values on LCD and Serial, and sends data to queue for task 2
task 2 is responsible for reading the values received from the queue and processing, giving warnings if the allowed value is exceeded.
The problem here is:
If there is only task 1, the program runs fine. But if there is task 2, the whole program does not run, only runs through the Setup() function.
I let 2 tasks have the same priority and the same stack value of 400.
I've been trying to fix this problem for over two days now to no result.
Hope to get help from everyone. Source code :
And you may need more then 400 stack space address for your code. Use highwatermark freeRTOS macro and print out the memory use for troubleshooting.
log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) ); << is the print out task stack use macro.
I like to set the stack use space for a task about 2000 above the max used space during task operations. I let the task run for about 10 minutes before deciding on the stack size.
I just got through setting the task memory use for this app I am currently working on:
/*
Connect the SD card to the following pins:
SD Card | ESP32
D2 -
D3 SS
CMD MOSI
VSS GND
VDD 3.3V
CLK SCK
VSS GND
D0 MISO
D1 -
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
*/
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
//#include <LinearRegression.h>
#include <ESP32Time.h>
////
ESP32Time rtc;
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
Adafruit_AMG88xx amgL;
//Adafruit_AMG88xx amgR;
//LinearRegression lr;
//LinearRegression bgi; //background image
////
const int pixels = 64;
const int toFileSize = 2500;
const int payloadSize = 100;
int sensorDelay = 125;
int count = 0;
int mqttOK = 0;
float FrameR[pixels] = { 0.0f };
float FrameL[pixels] = { 0.0f };
float outsideTemperature = 0.0f;
//float dpAtom = 1.0f / 80.0f; // low/high from data sheet
//float tsAtom = 1.0f / 64.0f; // 64 data points 64 time stamps.
//double valuesModelR[2] = { 0.0f };
//double valuesR[2] = { 0.0f };
//double valuesModelL[2] = { 0.0f };;
//double valuesL[2] = { 0.0f };
//float daChange = 0.0f;
bool TimeSet = false;
bool startTheThing = false;
QueueHandle_t xQ_Message;
QueueHandle_t Q_toFIle;
////
struct stu_message
{
char payload [150] = {'\0'};
String topic;
} x_message;
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
SemaphoreHandle_t sema_mqttOK;
////
////
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
// clear locations
memset( x_message.payload, '\0', 150 );
x_message.topic = ""; //clear string buffer
x_message.topic = topic;
int i = 0;
for ( i; i < length; i++)
{
x_message.payload[i] = ((char)payload[i]);
}
x_message.payload[i] = '\0';
xQueueOverwrite( xQ_Message, (void *) &x_message );// send data
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
// interrupt service routine for WiFi events put into IRAM
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
break;
default: break;
}
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
void setup()
{
// if (!SD.begin())
// {
// log_i("Card Mount Failed");
// return;
// }
//
String toFile = "";
toFile.reserve( toFileSize );
Q_toFIle = xQueueCreate( 5, sizeof(toFile) );
x_message.topic.reserve(150);
xQ_Message = xQueueCreate( 1, sizeof(stu_message) );
//
sema_mqttOK = xSemaphoreCreateBinary();
xSemaphoreGive( sema_mqttOK );
//
xTaskCreatePinnedToCore( fSendToFile, "fSendToFile", 9500, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 3500, NULL, 5, NULL, 1 );
xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 12000, NULL, 4, NULL, 1 ); // assign all to core 1, WiFi in use.
xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 2000, NULL, 3, NULL, 1 ); // assign all to core 1
xTaskCreatePinnedToCore( fMain, "fMain", 11000, NULL, 3, NULL, 1 ); // assign all to core 1
} // setup()
////
void fMain( void *pvParameters )
{
while ( !MQTTclient.connected() )
{
vTaskDelay( 250 );
}
bool status;
status = amgL.begin(0x68);
if (!status) {
log_i( "Could not find a valid AMG88xxL sensor, check wiring!" );
while (1);
}
float theThing = 0.0f;
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = sensorDelay; //delay for mS
String toFile = "";
toFile.reserve( toFileSize );
for (;;)
{
if ( startTheThing )
{
amgL.readPixels( FrameL );
//collect data
for (int i = 0; i < pixels; i++)
{
theThing = ((float)FrameL[i - 1] * 1.8f) + 32.0f;
toFile.concat( String(theThing) );
toFile.concat( "," );
toFile.concat( String(outsideTemperature) );
toFile.concat( "," );
toFile.concat( String( theThing - outsideTemperature) );
toFile.concat( "\n" );
}
}
if ( toFile.length() != 0 )
{
xQueueSend( Q_toFIle, (void *) &toFile, 1 );// send data to sd card handler
}
toFile = "";
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete ( NULL );
}
////
void fSendToFile( void * parameter )
{
String toFile = "";
toFile.reserve( toFileSize );
for (;;)
{
if ( xQueueReceive(Q_toFIle, &toFile, portMAX_DELAY) == pdTRUE )
{
//appendFile(SD, "/readings.txt", toFile.c_str() );
toFile = "";
}
//log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete( NULL );
}
////
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 86300; // 1st time update in 100 counts
int maxNonMQTTresponse = 60;
for (;;)
{
vTaskDelay( 1000 );
if ( mqttOK >= maxNonMQTTresponse )
{
ESP.restart();
}
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK++;
xSemaphoreGive( sema_mqttOK );
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
//log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete( NULL );
}
//////
void fparseMQTT( void *pvParameters )
{
struct stu_message px_message;
for (;;)
{
if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
{
if ( px_message.topic == topicOK )
{
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK = 0; // clear mqtt ok count
xSemaphoreGive( sema_mqttOK );
}
if ( !TimeSet )
{
String temp = "";
temp = px_message.payload[0];
temp += px_message.payload[1];
temp += px_message.payload[2];
temp += px_message.payload[3];
int year = temp.toInt();
temp = "";
temp = px_message.payload[5];
temp += px_message.payload[6];
int month = temp.toInt();
temp = "";
temp = px_message.payload[8];
temp += px_message.payload[9];
int day = temp.toInt();
temp = "";
temp = px_message.payload[11];
temp += px_message.payload[12];
int hour = temp.toInt();
temp = "";
temp = px_message.payload[14];
temp += px_message.payload[15];
int min = temp.toInt();
rtc.setTime( 0, min, hour, day, month, year );
log_i( "%s ", rtc.getTime() );
TimeSet = true;
}
if ( px_message.topic == topicOutsideTemperature )
{
startTheThing = true;
outsideTemperature = String(px_message.payload).toFloat();
}
}
//log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
} //for(;;)
vTaskDelete ( NULL );
} // void fparseMQTT( void *pvParameters )
////
void MQTTkeepalive( void *pvParameters )
{
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
// setting must be set before a mqtt connection is made
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
for (;;)
{
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
vTaskDelay( 250 ); //task runs approx every 250 mS
//log_i( " high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete ( NULL );
}
////
void connectToWiFi()
{
int TryCount = 0;
while ( WiFi.status() != WL_CONNECTED )
{
TryCount++;
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
vTaskDelay( 4000 );
if ( TryCount == 10 )
{
ESP.restart();
}
}
WiFi.onEvent( WiFiEvent );
} // void connectToWiFi()
////
void connectToMQTT()
{
MQTTclient.setKeepAlive( 90 ); // needs be made before connecting
byte mac[5];
WiFi.macAddress(mac);
String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
while ( !MQTTclient.connected() )
{
// boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password, NULL , 1, true, NULL );
vTaskDelay( 250 );
}
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( topicOK );
MQTTclient.subscribe( mqtt_topic );
} // void connectToMQTT()
////
void writeFile(fs::FS &fs, const char * path, const char * message) {
File file = fs.open(path, FILE_WRITE);
if (!file) {
log_i("Failed to open file for writing");
return;
}
if (file.print(message)) {
log_i("File written");
} else {
log_i("Write failed");
}
}
////
void appendFile(fs::FS &fs, const char * path, const char * message) {
log_i("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file)
{
log_i("Failed to open file for appending");
return;
}
if (file.print(message))
{
log_i("Message appended");
} else {
log_i("Append failed");
}
}
////
void renameFile(fs::FS &fs, const char * path1, const char * path2) {
log_i("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
log_i("File renamed");
} else {
log_i("Rename failed");
}
}
////
//void renameFile(fs::FS &fs, const char * path1, const char * path2) {
// log_i("Renaming file %s to %s\n", path1, path2);
// if (fs.rename(path1, path2)) {
// log_i("File renamed");
// } else {
// log_i("Rename failed");
// }
//}
////
void deleteFile(fs::FS &fs, const char * path) {
log_i("Deleting file: %s\n", path);
if (fs.remove(path)) {
log_i("File deleted");
} else {
log_i("Delete failed");
}
}
////
////
void loop() {}