SOLVED: ESP32 - Binary Semaphore causes reboot

Hi, I have successfully created 3 tasks to run on the ESP32. I have to share the I2C between two tasks and therefor decided that a binary semaphore will be best to share this resource between two tasks.

I followed the FreeRTOS documentation and several online tutorials, but my processor continuously reboots when the the xSemaphoreTake and Give API's are called.

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLrv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00mode:DIO, clock di12 room 4load:0x40078000,len:10944load:0x40080400,len:6388entry 0x400806b4/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-bueive)- assert failed!abort() was called at PC 0x4008a00d on coilder/esp-idf/components/freertos/queue.c:1442 (xQueueGenericRec54:0x3ffcab90 0x400892d1:0x3ffcabb0 0x4008a00d:0x3ffcabd0 0x400drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00mode:DIO, clock dire 1ELF file SHA256: 0000000000000000Backtrace: 0x400890119e:0x3ffcac10 0x4008a2e2:0x3ffcac30Rebooting...ets Jun 8 2016 00:22:57

My code:


 /**********************************************************************************
TITLE: GROWSPACE

AUTHOR: SHAWN TAYLOR

VERSION: 1.0.1

NOTE: CONTROL LIGHT SCHEDULE
    : CONTROL INLET FANS AND OUTLET FANS
    : MONITOR TEMPERATURE AND HUMIDITY
    : MONITOR VPD
 **********************************************************************************/

// Fill-in information from your Blynk Template here
#define BLYNK_TEMPLATE_ID "xxxxxxxxxxxxx"
#define BLYNK_DEVICE_NAME "xxxxxxxxxxxx"

#define BLYNK_FIRMWARE_VERSION        "1.0.1"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG
//#define APP_DEBUG

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

// Comment this out to disable prints and save space
#define BLYNK_PRINT Serial

//I2C Comms
#include <Wire.h>

//OLED Related Code
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

//CAN BUS Related code
#include <ESP32CAN.h>
#include <CAN_config.h>
CAN_device_t CAN_cfg;

//RTC Related Code
#include <RTClib.h>
RTC_DS3231 rtc;

// Define Switch Pins
#define s1 26 // LIGHTS
#define s2 25 // INLET
#define s3 33 // OUTLET
#define s4 32 // HUMIDIFIER
#define s5 35 // UNDEFINED
#define s6 34 
#define s7 39
#define s8 36

// Define Relay Pins
#define r1 14 // LIGHT 1
#define r2 13 // LIGHT 2
#define r3 15 // INLET
#define r4 16 // OUTLET
#define r5 17 // HUMIDIFIER
#define r6 18
#define r7 19
#define r8 23

// Define IND LED
#define intLED 27

// Define Hysteresis
#define tempDeadBand 3

//OLED Definitions
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

//FreeRTOS Mutex Handle
SemaphoreHandle_t xI2CSemaphore;

uint8_t currentMin = 0;
uint8_t currentHour = 0;
int currentMinCalc = 0;
uint8_t currentCalcMin = 0;
uint8_t lightsON = 0;
uint16_t waitMin = 0;
uint16_t waitMinFans = 0;
uint8_t hourScheduler = 02;
uint16_t r1Time = 0;
uint16_t r2Time = 0;
uint16_t r3Time = 0;
uint16_t r4Time = 0;
uint8_t timeFlag = 0;

//Relay Timer Bool
bool r1TimeBool = 0;
uint8_t r1SwitchState = 0;

//Switch State Bool
bool s1Bool = 1;

struct SCHEDULER
{
  uint8_t Month;
  uint8_t Day;
  uint8_t Hour;
  uint8_t Minute;
  uint16_t OnTime;
};

SCHEDULER Scheduler[4][8];

//Millis related variables
const uint16_t readInterval = 6;
unsigned long previousTime = 0;
unsigned long currentTime = 0;

//RTOS Millisecond Counter
 unsigned long eMillis = 0;

//char auth[] = BLYNK_AUTH_TOKEN;

#define VPIN_BUTTON_1    V1 
#define VPIN_BUTTON_2    V2
#define VPIN_BUTTON_3    V3 
#define VPIN_BUTTON_4    V4
#define VPIN_BUTTON_5    V5 

#define VPIN_TEMPERATURE V9
#define VPIN_HUMIDITY    V10

// Relay State
bool relayState_1 = HIGH; //Define integer to remember the toggle state for relay 1
bool relayState_2 = HIGH; //Define integer to remember the toggle state for relay 2
bool relayState_3 = HIGH; //Define integer to remember the toggle state for relay 3
bool relayState_4 = HIGH; //Define integer to remember the toggle state for relay 4
bool relayState_5 = HIGH; //Define integer to remember the toggle state for relay 5

// Switch State
bool SwitchState_1 = LOW;
bool SwitchState_2 = LOW;
bool SwitchState_3 = LOW;
bool SwitchState_4 = LOW;
bool SwitchState_5 = LOW;

//BlynkEdgent: Class
#include "BlynkEdgent.h"

//Instances
BlynkTimer timer;

//BLYNK_CONNECTED() {
//  // Request the latest state from the server
//  Blynk.syncVirtual(VPIN_BUTTON_1);
//  Blynk.syncVirtual(VPIN_BUTTON_2);
//  Blynk.syncVirtual(VPIN_BUTTON_3);
//  Blynk.syncVirtual(VPIN_BUTTON_4);
//  Blynk.syncVirtual(VPIN_BUTTON_5);
//  Blynk.syncVirtual(VPIN_BUTTON_6);
//  Blynk.syncVirtual(VPIN_BUTTON_7);
//  Blynk.syncVirtual(VPIN_BUTTON_8);
//  Blynk.syncVirtual(VPIN_TEMPERATURE);
//  Blynk.syncVirtual(VPIN_HUMIDITY);
//  Blynk.syncVirtual(VPIN_LDR);
//}

// When App button is pushed - switch the state
BLYNK_WRITE(VPIN_BUTTON_1) 
{
  relayState_1 = param.asInt(); // Blynk Virtual Pin state to relayState_1 var
  Serial.print("relayState_1 from Blynk: ");
  Serial.println(relayState_1);
  if(relayState_1 == 1) //If Virtual Button 1 - automation is on
  {
    //digitalWrite(r1, LOW);
    //digitalWrite(r2, LOW);
    SwitchState_1 = HIGH;
  }
  else //If Virtual Button is 0 - automation is off
  { 
    //digitalWrite(r1, HIGH);
    //digitalWrite(r2, HIGH);
    SwitchState_1 = LOW;
  }
}

BLYNK_WRITE(VPIN_BUTTON_2) 
{
  relayState_2 = param.asInt();
  if(relayState_2 == 1)
  {
    //digitalWrite(r3, LOW);
    SwitchState_2 = HIGH;
  }
  else 
  { 
    //digitalWrite(r3, HIGH);
    SwitchState_2 = LOW;
  }
}

BLYNK_WRITE(VPIN_BUTTON_3) 
{
  relayState_3 = param.asInt();
  if(relayState_3 == 1)
  {
    //digitalWrite(r4, LOW);
    SwitchState_3 = HIGH;
  }
  else 
  { 
    //digitalWrite(r4, HIGH);
    SwitchState_3 = LOW;
  }
}

BLYNK_WRITE(VPIN_BUTTON_4) 
{
  relayState_4 = param.asInt();
  if(relayState_4 == 1)
  {
    //digitalWrite(r5, LOW);
    SwitchState_4 = HIGH;
  }
  else 
  { 
    //digitalWrite(r5, HIGH);
    SwitchState_4 = LOW;
  }
}

BLYNK_WRITE(VPIN_BUTTON_5) 
{
  all_SwitchOff();
}

void all_SwitchOff()
{
  relayState_1 = 0; digitalWrite(r1, HIGH); Blynk.virtualWrite(VPIN_BUTTON_1, relayState_1); delay(100); //1. Switch off relays 2. relayState_1 = 0 3. Update virtual pin to display 0
                    digitalWrite(r2, HIGH);
  relayState_2 = 0; digitalWrite(r3, HIGH); Blynk.virtualWrite(VPIN_BUTTON_2, relayState_2); delay(100);
  relayState_3 = 0; digitalWrite(r4, HIGH); Blynk.virtualWrite(VPIN_BUTTON_3, relayState_3); delay(100);
  relayState_4 = 0; digitalWrite(r5, HIGH); Blynk.virtualWrite(VPIN_BUTTON_4, relayState_4); delay(100);
  relayState_5 = 0;                         Blynk.virtualWrite(VPIN_BUTTON_5, relayState_5); delay(100);

  Blynk.virtualWrite(VPIN_HUMIDITY, humTemp.humidity.floatVal);
  Blynk.virtualWrite(VPIN_TEMPERATURE, humTemp.temp.floatVal);
}

// This function sends Arduino's uptime every second to Virtual Pin 2.
void myTimerEvent()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  Blynk.virtualWrite(VPIN_HUMIDITY, humTemp.humidity.floatVal);
  Blynk.virtualWrite(VPIN_TEMPERATURE, humTemp.temp.floatVal);
}

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

  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);
  pinMode(r3, OUTPUT);
  pinMode(r4, OUTPUT);
  pinMode(r5, OUTPUT);
  pinMode(r6, OUTPUT);
  pinMode(r7, OUTPUT);
  pinMode(r8, OUTPUT);

  //pinMode(wifiLed, OUTPUT);

  pinMode(s1, INPUT);
  pinMode(s2, INPUT);
  pinMode(s3, INPUT);
  pinMode(s4, INPUT);
  pinMode(s5, INPUT);
  pinMode(s6, INPUT);
  pinMode(s7, INPUT);
  pinMode(s8, INPUT);
  
  //During Startup all Relays should TURN OFF
  digitalWrite(r1, HIGH);
  digitalWrite(r2, HIGH);
  digitalWrite(r3, HIGH);
  digitalWrite(r4, HIGH);
  digitalWrite(r5, HIGH);
  digitalWrite(r6, HIGH);
  digitalWrite(r7, HIGH);
  digitalWrite(r8, HIGH);

  pinMode(intLED, OUTPUT);
  digitalWrite(intLED, LOW);

  /* FreeRTOS Related Code */
  xTaskCreate(genTask, "genTaskE", 2048, NULL, 3, NULL);
  xTaskCreate(i2cTask, "i2cTaskE", 16384, NULL, 4, NULL);
  xTaskCreate(rtcTask, "rtcTaskE", 8192, NULL, 6, NULL); //4096 / 8 = 512 
  //Binary Semaphore for I2C
  xI2CSemaphore = xSemaphoreCreateBinary(); 
  
  BlynkEdgent.begin();

  // Set up a function to be called every x-amount of seconds //
  timer.setInterval(12000L, myTimerEvent);

  /* Initialize Can Bus Parameters */
  CAN_cfg.speed = CAN_SPEED_250KBPS;
  CAN_cfg.tx_pin_id = GPIO_NUM_5;
  CAN_cfg.rx_pin_id = GPIO_NUM_4;
  //Create a queue for CAN receiving
  CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));
  //Initialize CAN Module
  ESP32Can.CANInit();

//OLED Setup Code
  if(display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) 
  {
    Serial.println(F("SSD1306 allocated"));
  }
  delay(2000);
   display.clearDisplay();
   display.setTextSize(1);
   display.setTextColor(WHITE);
   display.setCursor(0, 10);
  // Display static text
  display.println(" ");
  display.display(); 

  //Initialize Scheduler Struct to 0xFF
  for (int i = 0; i < 4; i++)
  {
    for (int z = 0; z < 8; z++)
    {
      Scheduler[i][z].Month = 0xFF;
      Scheduler[i][z].Day = 0xFF;
      Scheduler[i][z].Hour = 0xFF;
      Scheduler[i][z].Minute = 0xFF;
      Scheduler[i][z].OnTime = 0;
    }
  }

  // LIGHT RELAY 1 :: 07:00 - 01:00
  Scheduler[0][0].Hour = 14;      // [0] - RELAY 1 :: [0] - TIME SCHEDULE 1
  Scheduler[0][0].Minute = 12;    // [0] - RELAY 1 :: [0] - TIME SCHEDULE 1
  Scheduler[0][0].OnTime = 3;  // [0] - RELAY 1 :: [0] - TIME SCHEDULE 1

  // LIGHT RELAY 2 :: 07:00 - 01:00
  Scheduler[1][0].Hour = 07;      // [1] - RELAY 2 :: [0] - TIME SCHEDULE 1
  Scheduler[1][0].Minute = 00;    // [1] - RELAY 2 :: [0] - TIME SCHEDULE 1
  Scheduler[1][0].OnTime = 1080;  // [1] - RELAY 2 :: [0] - TIME SCHEDULE 1

  // INLET FAN :: 07:00 - 01:20
  Scheduler[2][0].Hour = 07;      // [2] - RELAY 3 :: [0] - TIME SCHEDULE 1
  Scheduler[2][0].Minute = 00;    // [2] - RELAY 3 :: [0] - TIME SCHEDULE 1
  Scheduler[2][0].OnTime = 1110;  // [2] - RELAY 3 :: [0] - TIME SCHEDULE 1
  
  for (int i = 1; i < 6; i++)
  {
    Scheduler[2][i].Hour = hourScheduler;  // [2] - RELAY 3 :: [1] - TIME SCHEDULE 2
    Scheduler[2][i].Minute = 15;           // [2] - RELAY 3 :: [1] - TIME SCHEDULE 2
    Scheduler[2][i].OnTime = 15;           // [2] - RELAY 3 :: [1] - TIME SCHEDULE 2
    hourScheduler++;
  }

  hourScheduler = 02;

  // OUTLET FAN
  Scheduler[3][0].Hour = 07;      // [3] - RELAY 4 :: [0] - TIME SCHEDULE 1
  Scheduler[3][0].Minute = 00;    // [3] - RELAY 4 :: [0] - TIME SCHEDULE 1
  Scheduler[3][0].OnTime = 1110;  // [3] - RELAY 4 :: [0] - TIME SCHEDULE 1

    for (int i = 1; i < 6; i++)
  {
    Scheduler[3][i].Hour = hourScheduler; // [3] - RELAY 4 :: [i] - TIME SCHEDULE 2
    Scheduler[3][i].Minute = 15;          // [3] - RELAY 4 :: [i] - TIME SCHEDULE 2
    Scheduler[3][i].OnTime = 15;          // [3] - RELAY 4 :: [i] - TIME SCHEDULE 2
    hourScheduler++;
  }

  if (! rtc.begin()) 
  {
     Serial.println("Couldn't find RTC");
  }

  if (rtc.lostPower()) 
  {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
     rtc.adjust(DateTime(2022, 1, 17, 13, 39, 0));
  }
}

void loop() 
{
    /* RTOS API for Milliseconds */
    //eMillis = xTaskGetTickCount(); - not working as loop task lowest priority
    /* RTC DS3231 */
    //currentTime = now.unixtime();
    BlynkEdgent.run();
    //manual_control(); //Manual Switch Control
    timer.run();
    /* Manual Control Logic for override Switches */
    manual_control();
    /* Timer from RTC :: 6s */
    //if(currentTime - previousTime >= readInterval)
    //{
    //previousTime = currentTime; 
    //}
    startScheduler();
}

//FreeRTOS Tasks:
/* Task 1: GenTask */
void genTask(void * parameters)
{
  for(;;)
  { 
    eMillis++;
    if(eMillis %  8 == 0)
    {
      digitalWrite(intLED, HIGH);
      if(eMillis % 16 == 0)
      {
        digitalWrite(intLED, LOW);
      }
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

/* Task 2: Update OLED Display */
void i2cTask(void * parameters)
{
  int i;
  for(;;)
  { 
    i++;
    //xSemaphoreTake(xI2CSemaphore, portMAX_DELAY);
    if(i % 128 == 0)
    {
      BlynkEdgent.displayTemponOLED(); 
    } 
    if(i % 256 == 0)
    {
      BlynkEdgent.displayHumOnOLED();
    }
    //xSemaphoreGive(xI2CSemaphore);
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

//Task 3: RTC Task 
void rtcTask(void * parameters)
{
  for(;;)
  { 
    xSemaphoreTake(xI2CSemaphore, portMAX_DELAY);
    Serial.println("rtcTask");
      //getHumTemp();
      //getDateTime();
      //controlHumidity();
    //DateTime now = rtc.now();
    //Serial.print(now.hour(), DEC);
    //currentHour = now.hour();
    //Serial.print(':');
    //Serial.print(now.minute(), DEC);
    //currentMin = now.minute();
    //Serial.print(':');
    //Serial.print(now.second(), DEC);
    //Serial.println();
    //Serial.print("Scheduler[0][0]: ");
    //Serial.print(Scheduler[0][0].Hour );
    //Serial.print(Scheduler[0][0].Minute );
    //Serial.println(Scheduler[0][0].OnTime );
    //Serial.print("Scheduler[1][0]: ");
    //Serial.print(Scheduler[1][0].Hour );
    //Serial.print(Scheduler[1][0].Minute );
    //Serial.println(Scheduler[1][0].OnTime );
      //if(timeFlag == 0)
       // {
      //    waitMin = currentMin;
      //    Serial.print("waitMin: ");
      //    Serial.println(waitMin);
      //    Serial.print("currenttMin: ");
     //     Serial.println(currentMin);
      //    timeFlag = 1;
      //  }
    xSemaphoreGive(xI2CSemaphore);  
    vTaskDelay(2000 / portTICK_PERIOD_MS);
  }
}

TIA.

Seems like you have to create the semaphore before creating the tasks:

  /* FreeRTOS Related Code */
  //Binary Semaphore for I2C
  xI2CSemaphore = xSemaphoreCreateBinary();  
  //FreeRTOS Tasks
  xTaskCreate(genTask, "genTaskE", 2048, NULL, 3, NULL);
  xTaskCreate(i2cTask, "i2cTaskE", 16384, NULL, 4, NULL);
  xTaskCreate(rtcTask, "rtcTaskE", 8192, NULL, 6, NULL); //4096 / 8 = 512 

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