Non-Blocking Edgent Examples

I tried OTA firmware update twice. The firmware update went smoothly, and the device instantly connected to the cloud after the update without any issues. Everything worked as expected.

Huh, well that is odd, I must have messed something up.

I’ll know more when I have physical access to the device this evening.

Ok, so I think the crash is likely my fault. I tried to adapt one of my simple sketches to use your format, I didn’t use your direct sketch outside of making sure it would compile, upload and away config, which it did. When I did an OTA update using my own updated sketch I borked it.

I think my issue lays within the use of Blynk Timer. I’m going to adapt my code over to use vTaskdelay (which from my reading is non-blocking) as opposed to Blynk timer, which is the only notable difference I can see in my sketch compared to yours.

Here is the crash data I got when I connect over USB:

load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608
entry 0x400805f0
Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
Memory dump at 0x400d50cc: 25004136 f01dfff2 d2004136
Core  1 register dump:
PC      : 0x400d50d2  PS      : 0x00060430  A0      : 0x00000000  A1      : 0x3ffb3830  
A2      : 0x00000000  A3      : 0x00000000  A4      : 0x00000000  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x800d50d2  A9      : 0x3ffb37f0  
A10     : 0xb04fc5a7  A11     : 0x3ffc47fc  A12     : 0x00000014  A13     : 0x00000004  
A14     : 0x3ffb9114  A15     : 0x80000001  SAR     : 0x0000000e  EXCCAUSE: 0x00000000  
EXCVADDR: 0x00000000  LBEG    : 0x400e2a32  LEND    : 0x400e2a3e  LCOUNT  : 0x00000009  


Backtrace:0x400d50cf:0x3ffb3830




ELF file SHA256: 0000000000000000

Rebooting...

I’ll update again once I rebuild and upload using vTaskDelay

Hey John,

Fixed,

I’m not sure if it was the transition to vTaskDelay or another fix I made (adding an endless for loop to the task) but I am up and running.

I have an issue with variables not updating across the cores (my Virtual LEDS no longer illuminate as they should) but the program seems to be working as a whole, thanks!

The vTaskDelay is a blocking function. In FreeRTOS, you can use a timer instead of the vTaskDelay function to make a non-blocking delay. Timers in FreeRTOS are created and managed using the xTimerCreate, xTimerStart, and xTimerStop functions.

A system running FreeRTOS offers a number of options for sending data between cores, such:

  1. Queues: FreeRTOS includes a queue API that allows tasks on different cores to send and receive data using a queue. You can use the xQueueSend and xQueueReceive functions to send and receive data on a queue, respectively. Queues can be used to pass data between tasks on different cores, as well as between tasks on the same core.

  2. Semaphores: Semaphores are a synchronization mechanism that can be used to send data between tasks on different cores. You can use the xSemaphoreGive and xSemaphoreTake functions to send and receive data using a semaphore, respectively.

  3. Messages: FreeRTOS includes a message buffer API that allows tasks on different cores to send and receive messages. You can use the xMessageBufferSend and xMessageBufferReceive functions to send and receive messages, respectively.

  4. Shared memory: You can also use shared memory to pass data between tasks on different cores. For example, you can use the FreeRTOS heap functions (such as pvPortMalloc and vPortFree) to allocate memory that is shared between cores.
    It’s important to note that you will need to take care to synchronize access to shared memory between cores to avoid race conditions and other issues. You can use mechanisms such as mutexes, semaphores, or disabling interrupts to synchronize access to shared memory.

Which method you choose will depend on your specific requirements and constraints. Queues and semaphores are typically used for synchronizing tasks, while message buffers and shared memory are better suited for sending data between tasks. It’s a good idea to consider the performance and scalability requirements of your system, as well as the complexity of the implementation, when deciding which method to use.

1 Like

This is great info John, thank you!

I’ll do some reading and do another rebuild on my sketch. Thanks to you I’m way, way further ahead than I would be on my own, thanks again!

1 Like

I tried to use BlynkTimer with freeRTOS, and it worked normally without any issues. So I can confirm that BlynkTimer and freeRTOS can work together.

1 Like

Thanks John, you are correct, that issue ended up being the adding a for loop and not the timer.

I have managed to break something again while trying to use queues hahaha. I won’t have access to the device until tomorrow for serial logs but the OTA broke it. Here is the sketch I used:

#define BLYNK_TEMPLATE_ID "xxxxxx"
#define BLYNK_DEVICE_NAME "xxxxxx"

#define BLYNK_FIRMWARE_VERSION        "0.2.9"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

#include "BlynkEdgent.h"

WidgetLED led1(V1);
WidgetLED led2(V2);
WidgetLED led3(V12);
WidgetLED led4(V13);


#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7
//#define USE_ESP32C3_DEV_MODULE
//#define USE_ESP32S2_DEV_KIT

BlynkTimer timer;

QueueHandle_t queue_scaleOff;
QueueHandle_t queue_scaleRun;
QueueHandle_t queue_scaleBoot;

int realSwitch = 0;
const int realSwitchPin = 27;
const int batteryPin = 36;
int adc_read = 0;
float batteryVoltage = 0;
int batteryPercent = 0;
bool scaleSwitchOn = false;
bool blynkScaleSwitchOn = false; 
bool scaleStart = false;
bool scaleBoot = false;
bool scaleRun = false;
bool scaleOff = false;

bool scaleStartBlynk;
bool scaleBootBlynk;
bool scaleRunBlynk;
bool scaleOffBlynk;

const int output1 = 4;
const int scaleDisplayMOSFET = 16;
const int scaleMOSFET = 17;
const int output4 = 18;


void TaskCheck( void *pvParameters );


void setup()
{
  Serial.begin(115200);
  delay(100); 

  pinMode(realSwitchPin, INPUT);
  pinMode(batteryPin, INPUT);  
  pinMode(scaleMOSFET, OUTPUT);
  pinMode(output1, OUTPUT);
  pinMode(output4, OUTPUT);
  pinMode(scaleDisplayMOSFET, OUTPUT);

  digitalWrite(output1, LOW);
  digitalWrite(scaleDisplayMOSFET, LOW);
  digitalWrite(scaleMOSFET, LOW);
  digitalWrite(output4, LOW);
  Blynk.syncAll();
  Blynk.virtualWrite(V2, LOW);
  timer.setInterval(750,blynkData);

  queue_scaleOff = xQueueCreate(1, sizeof(bool));
  queue_scaleRun = xQueueCreate(1, sizeof(bool));
  queue_scaleBoot = xQueueCreate(1, sizeof(bool));

  
  xTaskCreatePinnedToCore(
    TaskCheck
    ,  "TaskCheck"
    ,  4096
    ,  NULL
    ,  1
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);


  vTaskStartScheduler();

  BlynkEdgent.begin();
}

void loop() {
  
   BlynkEdgent.run();
}



BLYNK_WRITE (V0) {
  if (param.asInt() == 0) {
    blynkScaleSwitchOn = false;
  }
  else if (param.asInt() == 1) {
    blynkScaleSwitchOn = true;
  }
}

void realScaleSwitch() {
 realSwitch = digitalRead(realSwitchPin);
 if (realSwitch == 0) {
   scaleSwitchOn = true;
 }
 else if (realSwitch == 1) {
   scaleSwitchOn = false;
 }
}

void switchState() {
  if ((blynkScaleSwitchOn) || (scaleSwitchOn)) {
    if (!scaleRun) {
    scaleOff = false;
    scaleStart = true;
    }
  }
  if ((!scaleSwitchOn) && (!blynkScaleSwitchOn)) {
    scaleOff = true;
    scaleStart = false;
  }
}

void batteryMonitor() {
  adc_read = analogRead(batteryPin);
  batteryVoltage = (adc_read * 0.003241);
  batteryPercent = map(adc_read, 3708, 3920, 0, 100);
}

void scaleOperation() {
  realScaleSwitch();
  switchState();
  if (scaleStart) {
    scaleBoot = true;
    digitalWrite(scaleMOSFET, HIGH);
    digitalWrite(output4, HIGH);
    timer.setTimeout(30000, []() 
    {
      scaleStart = false;
      scaleBoot = false;
      scaleRun = true;
      digitalWrite(scaleDisplayMOSFET, HIGH);
    });
  }
  else if (scaleOff) {
    scaleRun = false;
    digitalWrite(scaleDisplayMOSFET, LOW);
    digitalWrite(scaleMOSFET, LOW);
    digitalWrite(output4, LOW);
  }
}

void blynkData() {
  if (xQueueReceive(queue_scaleOff, &scaleOffBlynk, portMAX_DELAY) == pdPASS) {    
    if (scaleOffBlynk) {
      Blynk.virtualWrite(V1, LOW);
      Blynk.virtualWrite(V2, LOW);
      Blynk.virtualWrite(V12, LOW);
      Blynk.virtualWrite(V13, HIGH);
    }
  }    
  if (xQueueReceive(queue_scaleBoot, &scaleBootBlynk, portMAX_DELAY) == pdPASS) {
    if (scaleBootBlynk) {
      Blynk.virtualWrite(V1, HIGH);
      Blynk.virtualWrite(V13, LOW);
    }
  }    
  if (xQueueReceive(queue_scaleRun, &scaleRunBlynk, portMAX_DELAY) == pdPASS) {
    if (scaleRunBlynk) {        
      Blynk.virtualWrite(V1, LOW);
      Blynk.virtualWrite(V2, HIGH);
      Blynk.virtualWrite(V12, HIGH);      
    }
  }
    batteryMonitor();
    Blynk.virtualWrite(V5, realSwitch);
    Blynk.virtualWrite(V9, adc_read);
    Blynk.virtualWrite(V4, batteryVoltage);
    Blynk.virtualWrite(V3, batteryPercent);     
}

void TaskCheck(void *pvParameters)
{
  (void) pvParameters;
  for (;;) {
    scaleOperation();
    xQueueSend(queue_scaleOff, &scaleOff, portMAX_DELAY);
    xQueueSend(queue_scaleRun, &scaleRun, portMAX_DELAY);
    xQueueSend(queue_scaleBoot, &scaleBoot, portMAX_DELAY);          
    vTaskDelay(1);       
  }
}

It compiles fine and I sent it OTA and it never came back. I tried semaphores unsuccessfully but it might have been my implementation. The Semaphore code uploaded fine but I still wasn’t successfully sharing variables.

I’ll update again with the serial data tomorrow.

1 Like

Hey John! Sorry for the delay in response!

I finally managed to have a chance to connect directly to this device. The code I posted above compiles and uploads fine to the board but the board never boots properly after the upload. It seems to be constantly rebooting with the following messages in the serial monitor:

rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608
entry 0x400805f0

ets Jun  8 2016 00:22:57

Nothing that is an obvious error message but I think the first line might have some info on the reset reason so I’m going to start digging there.

Thanks again for all your help!