ESP32: Multithreading - Arduino IoT Cloud, MAX30100 and LM35

Hello

I have been trying recently to make use of the 2 cores of the ESP32, so that I could upload my POX and temperature date onto the Cloud.

But there is something I cannot comprehend. The POX sensor, MAX30100 just won't work with the Cloud!

I have tried using delays in every logical place, I have tried using millis() so that the pox.update() runs faster than ArduinoCloud.update() - it didn't work.

I also tried another Cloud platform - I tried using AWS instead, it still does not read the POX values and I want to mention that in all of the above cases the TEMPERATURE sensor LM35 works!

I tried to understand why? Is it because the 2 updates (pox.update, ArduinoCloud.update) both try to take hold of of some resource/s?

If yes, what would those resources be?

Most recently I have tried working with ArduinoCloud on core 0 and the sensor reading on core 1 of the ESP32 - to no avail. I have tried working both synchronously and asynchronously. Neither of those methods did work.

I have to mention that they both work together and individually LOCALLY.

The code for sync method is below, the async method doesn't make use of any semaphore.
I am thinking about making a workaround such that I write to a file and read and post data from that file with a python script onto cloud - but this would make the case / idea of a real-time patient monitoring system futile / useless.

The only option would be to change the sensor for something simpler, I guess.

Have you got any ideas on this? How would you approach this problem?

The code:

#include "arduino_secrets.h"
#include "thingProperties.h"
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"

#define PIN_LM35 33
#define ADC_VREF_mV    3300.0 // in millivolt
#define ADC_RESOLUTION 4096.0

TaskHandle_t Task1, Task2;
SemaphoreHandle_t baton;

int counter = 0;

uint32_t tsLastReport = 0;

#define REPORTING_PERIOD_MS     1000
PulseOximeter pox;

void codeForTask1( void * parameter )
{
  for (;;) {
    xSemaphoreTake( baton, portMAX_DELAY );
    ArduinoCloud.update(); // Wi-Fi works on core 0?
    xSemaphoreGive( baton );
    delay(50);
  }
}

void codeForTask2( void * parameter )
{
  for (;;) {
    xSemaphoreTake( baton, portMAX_DELAY );
    pox.update();
    if (millis() - tsLastReport > 1000) {
      hr_cloud = pox.getHeartRate();
      //Serial.println(hr_cloud);
      
      // read the ADC value from the temperature sensor
      int adcVal = analogRead(PIN_LM35);
      // convert the ADC value to voltage in millivolt
      float milliVolt = adcVal * (ADC_VREF_mV / ADC_RESOLUTION);
      // convert the voltage to the temperature in °C
      float tempC = milliVolt / 10 + 20.5;
      temp_cloud = tempC; // send to cloud
      
      // print the temperature in the Serial Monitor:
      Serial.print("Temperature: ");
      Serial.print(temp_cloud);   // print the temperature in °C
      Serial.print("°C");
      tsLastReport = millis();
    }

    xSemaphoreGive( baton );
    delay(50);

  }
}

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);

 // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  Serial.print("Initializing pulse oximeter..");

  // Initialize the PulseOximeter instance
  // Failures are generally due to an improper I2C wiring, missing power supply
  // or wrong target chip
  if (!pox.begin()) {
    Serial.println("FAILED");
    for (;;);
  } else {
    Serial.println("SUCCESS");
  }

  // The default current for the IR LED is 50mA and it could be changed
  //   by uncommenting the following line. Check MAX30100_Registers.h for all the
  //   available options.
  pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);

  // create a mutual exclusive semaphore (passing the baton - just like in racing, when one is finished running, he passes the baton so the next can run and win)
  baton = xSemaphoreCreateMutex();

  // Someone suggested to use :     &codeForTask1, because his ESP crashed

  xTaskCreatePinnedToCore(
    &codeForTask1, // Task function
    "task1", // name of task
    10000, // stack size of task - not sure of this
    NULL, // parameter of the task
    1, // priority of the task
    &Task1, // task handle to keep track of created task
    0); // core
  delay(500);  // needed to start-up task1

  xTaskCreatePinnedToCore(
    &codeForTask2, // task function
    "task2", // name of task
    10000, // stack size of task - not sure of this either
    NULL, // task parameters
    1, // priority of task
    &Task2, // task handle to keep track of created task
    1); // core

  vTaskDelete(NULL); // doesn't enter loop
}


void loop() {

  delay(10);
}


//no usage, needs to be referenced because I made temp_cloud a read/write variable
void onTempCloudChange()  {
  // Add your code here to act upon TempCloud change
}

void onHrCloudChange()  {
  // Add your code here to act upon HrCloud change
}

I am sure you do not posses the 'skills' I know I barely do, to put your task onto core0 where the WiFi/BT operations occur

Please remove that from setup(). That is an instruction to freeRTOS to kill setup.

loop() should contain no code. Nothing. Empty.

I'm sure you mean to use vTaskDelay(50) instead of extra code overhead?

Hello,

The multithreading implementation is based on the information of this video https://youtu.be/k_D_Qu0cgu8?t=119

I am just trying to do this (min 7:18).

I also looked down into the comment section.

I refined the code as per your answers. It behaves the same way:

It would be great if you could provide anymore insights on this.

Is there any chance that someone could do that? Moreover, is it worth it (time and effort wise)?
What are the chances that an analog sensor (PlayGround pulse sensor for example) would behave the same way?

Put the code on core1 if you are going to use the ESP32's radio.

Can you please share the new code?
Thank you,

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