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.