Issue with retrieving readings from sensor

Hello there. I have been experiencing a problem while trying to read sensor data.

Hardware Info:
Board: ESP32S
Sensor: DHT11

My main issue is that my sensor reads the maximum value for a signed 32-bit integer which indicates that there is an error. I debugged my code and removing the Wifi connection would fix it. I am kind of a rookie here so i cant entirely explain the behaviour but would like some help on this.

Notes: I ended up using 2 seperate tasks for both of the lines of code which one of them connects to the wifi and the other is a loop which gets the humidity the sensor reads and with no luck, i still have the same issue. Also, i wasnt sure about the category so i chose this. Correct me if im wrong.

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#include <dht.h>
#include <HTTPClient.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClientSecure.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>

HTTPClient http;


WiFiMulti WiFiMulti;

WebSocketsClient webSocket;

TaskHandle_t readerHandle;
TaskHandle_t WiFiConnect;
SemaphoreHandle_t MainSemaphore = xSemaphoreCreateMutex();


DHT dht(26, DHT11);

[[noreturn]] void reader(void *pvParameters) {
    while (true) {
        if (xSemaphoreTake(MainSemaphore, portMAX_DELAY) == pdTRUE) { //We can take ownership of the semaphore
            if (WiFiClass::status() == WL_CONNECTED) {
                int hum = dht.readTemperature();
                int temp = dht.readTemperature();
                Serial.printf("Task 1 Reads %d\n", hum); // ocassioanlly reads max int
                vTaskDelay(pdMS_TO_TICKS(1000));
                xSemaphoreGive(MainSemaphore);
            }
        }
    }
}

[[noreturn]] void connectWifi(void *pvParameters) {
    while (true) {
        if (xSemaphoreTake(MainSemaphore, portMAX_DELAY) == pdTRUE) {
            WiFi.begin("ssid", "pass");
            while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                Serial.println("Connecting to WiFi...");
            }
            Serial.printf("[WS]: Connected to %s\n", WiFi.SSID().c_str());
            xSemaphoreGive(MainSemaphore);
            vTaskDelete(WiFiConnect);
        }
    }
};

void setup() {
    Serial.begin(9600);
    pinMode(2, OUTPUT);
    pinMode(26, OUTPUT); //DHT
    dht.begin();
    xSemaphoreGive(MainSemaphore); // Allow the semaphore to change ownership
    xTaskCreate(connectWifi, "wifiConnect", 4028, nullptr, 1, &WiFiConnect);
    xTaskCreate(reader, "readerHandler", 4028, nullptr, 1, &readerHandle);
}

void loop() {
}

The first thing to do is determine if you issue is FreeRTOS related or not - you can do that by trying to read the sensor from main() before the scheduler starts.

However, guiding two loops with a semaphore take can lead to unexpected results. I recommend reading from page 256 in the FreeRTOS book (under heading Mutexes and Task Scheduling).

In your code, the reader task only returns the mutex if the Wi-Fi is connected. Is that intentional? It will prevent the connectWiFi() task running.

How is delay() implemented? Is it going to spin? Did you intent to use vTaskDelay()?

Why does the task delete itself?

Hello, and thank you for your response. To start of, ive tested the sensor multiple of times and indeed it works without reading wrong values. The two loops were to debug the code which i forgot to remove before posting this. i have the WiFi connecting code at the setup and that functions correctly, i shouldnt have added it on the task. Also, the task was intended to delete itself since - from how i see it, done and it has connected to the WiFi and it shall be okay. The delay in the tempreature and humidity reading function is done bu using vTaskDelay(pdMS_TO_TICKS(1000) since the sensor can NOT read that fast as without using a delay. The code i will provide is the actual code, without the useless adjustments.
FYI: Here i am utilizing a differnet way of connecting to the WiFi network however it doesnt affect it.

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <dht.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClientSecure.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>

WiFiMulti WiFiMulti;
TaskHandle_t readerHandle;

DHT dht(26, DHT11);


[[noreturn]] void reader(void *pvParameters) {
    dht.begin();
    while (true) {
        if (WiFiClass::status() == WL_CONNECTED) {
            int hum = dht.readTemperature();
            int temp = dht.readTemperature();
            Serial.printf("Task 1 Reads %d\n", hum);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}





void setup() {
    Serial.begin(9600);
    pinMode(2, OUTPUT);
    WiFi.mode(WIFI_AP_STA);
    WiFi.enableLongRange(true);
    WiFi.softAP("ESP-32-Server", "12345678910");
    WiFi.begin("ssid", "pass");

    while (WiFiClass::status() != WL_CONNECTED) {
        Serial.println("Connecting..");
        delay(500);
    }
    Serial.printf("[WS]: Connected to %s\n", WiFi.SSID().c_str());
    xTaskCreate(reader, "reader", 4048, nullptr, 1, &readerHandle);
}

void loop() {
    
}

Assuming you are using this library, it uses strict timings and will likely not work if the task is interrupted. Can you try putting the call to readTemperature in a critical section?

[[noreturn]] void reader(void *pvParameters) {
    dht.begin();
    while (true) {
        if (WiFiClass::status() == WL_CONNECTED) {

            taskENTER_CRITICAL();
            int hum = dht.readTemperature();
            int temp = dht.readTemperature(); /* Also, you should probably use dht.readHumidity() here. */
            taskEXIT_CRITICAL();

            Serial.printf("Task 1 Reads %d\n", hum);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}

Thank you for your response.

Assuming this is what you asked, i did the following:

The taskEXIT_CRITICAL() function needed an argument mux so i supplied it.

The produced Output is as follows:

Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
Task 1 Reads 2147483647
DHT dht(26, DHT11);

static portMUX_TYPE mainMux;

[[noreturn]] void reader(void *pvParameters) {
    dht.begin();
    while (true) {
        if (WiFiClass::status() == WL_CONNECTED) {
            vPortCPUInitializeMutex(&mainMux);
            taskENTER_CRITICAL(&mainMux);
            int temp = dht.readTemperature();
            Serial.printf("Task 1 Reads %d\n", temp);
            taskEXIT_CRITICAL(&mainMux);
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

One quick thought that came to mind, could it be possible that the dht library is using the same timer that FreeRTOS is, so it is no longer setup right for dht?

Your results match the behavior if the library thinks it is timing out.

Yup - entering critical section is probably suppressing that timer ISR and as a result, library always times out. May be we can try vTaskSuspendAll -

[[noreturn]] void reader(void *pvParameters) {
    dht.begin();
    while (true) {
        if (WiFiClass::status() == WL_CONNECTED) {
            vTaskSuspendAll();
            int temp = dht.readTemperature();
            Serial.printf("Task 1 Reads %d\n", temp);
            xTaskResumeAll();
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

Another way is to use a different timer and put it at a priority so that it is not masked by FreeRTOS critical sections.

My thought was that if the class uses the same timer for its tick as FreeRTOS uses, then when FreeRTOS reprograms it at startup, it won’t work from the DHT class.

This is one common problem when using non-RTOS aware classes with an RTOS.

Hello and thank you for your response. I have tried the code snipet you attached but with no luck, i came across an error:

/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c:1438 (vTaskDelay)- assert failed!
abort() was called at PC 0x4008adda on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x4008860c:0x3ffcd890 0x40088889:0x3ffcd8b0 0x4008adda:0x3ffcd8d0 0x400d2395:0x3ffcd8f0 0x400d079f:0x3ffcd910 0x400d0891:0x3ffcda70 0x400d05a6:0x3ffcdaa0 0x4008989a
:0x3ffcdac0

Can you check the assert at this line? Can you match the symbols with the code and try to see the backtrace?

Also, as @richard-damon suggested, please check if DHT library is using the same timer as FreeRTOS tick.

Here is the assert

/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c:1438 (vTaskDelay)- assert failed!
abort() was called at PC 0x4008adda on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x4008860c:0x3ffcd510 0x40088889:0x3ffcd530 0x4008adda:0x3ffcd550 0x400d2395:0x3ffcd570 0x400d079f:0x3ffcd590 0x400d0891:0x3ffcd6f0 0x400d05a6:0x3ffcd720 0x4008989a
:0x3ffcd740
  #0  0x4008860c:0x3ffcd510 in invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #1  0x40088889:0x3ffcd530 in abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #2  0x4008adda:0x3ffcd550 in vTaskDelay at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c:3507
  #3  0x400d2395:0x3ffcd570 in delay at C:\Users\kount\.platformio\packages\framework-arduinoespressif32\cores\esp32/esp32-hal-misc.c:172
  #4  0x400d079f:0x3ffcd590 in DHT::read(bool) at .pio\libdeps\esp32dev\DHT sensor library/dht.cpp:178
  #5  0x400d0891:0x3ffcd6f0 in DHT::readTemperature(bool, bool) at .pio\libdeps\esp32dev\DHT sensor library/dht.cpp:178
  #6  0x400d05a6:0x3ffcd720 in reader(void*) at src/main.cpp:18
  #7  0x4008989a:0x3ffcd740 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator
1)

Also, it doesnt seem that they use the FreeRTOS tick

The question is how is millis() implemented, is it using the same physicals timer hardware as FreeRTOS is using.

This is a common problem when using non-rtos aware packages under an RTOS, (or even with other packages), you need to make sure there isn’t a hardware usage conflict, and time bases are a common source of problems. There may be a standard “bare metal” method of getting time that gets redefined when FreeRTOS starts itself (the it uses that nice convenient timer itself).

Also, the assert seems to be due to the operation calling “delay” which can’t be done with the scheduler disabled. My guess is that the issue isn’t needing a critical section or schedule disable block, but a conflict on the timer used for millis() and FreeRTOS. It seems that just SOME of the routines used by the operation map to FreeRTOS operations, but some do not, and that miss-match is causing problems.

To some extend i understand. Ive dug deeper, and this is what i found only. I found no FreeRTOS references.

i also found

 uint32_t _lastreadtime, _maxcycles;

Again, the question comes to how millis() is defined. You have found usages, but not a definition of how it works.

Agree - Looking at the back-trace, the library is calling vTaskDelay, so it likely is FreeRTOS aware and my initial guess of needing a critical section or scheduler disable block is wrong.

You should try contacting the author of DHT library also.

The library is calling “delay()”, which was made to call vTaskDelay(), but apparently millis() might not have been converted to use something in FreeRTOS.

The “Arduino” environment has mixed support for FreeRTOS, and I suspect that is the issue.

Alright ive taken into consideration most of the replies, and thanks to everyone for that. I will move onto appropriate libraries. Thanks everyone for the support