I'm using Arduino IDE with an ESP32-DevKitC V4 with Ble, Wifi and LVGL
I am running the BLE and Wifi together in a single thread on Core0 and the LCD using LVGL in the main loop in Core1
I'm having a problem that only occurs when I all 3 of the Wifi, BLE and LVGL running at the same time, When all 3 are enabled, uncommenting `lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );` in the `setupLcd()` function makes it start breaking.
In it's current state, when it breaks, initially it will run fine, the LCD will start up and work without problems, the Wifi will connect to the access point and the BLE will connect to a nearby CSC device, but once I connect to it using BLE UART it gives me an Error.
This error can vary, the most recent time it was:
Code: Select all
19:51:25.929 -> Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
19:51:25.929 -> Core 0 register dump:
19:51:25.929 -> PC : 0x4012635e PS : 0x00060c30 A0 : 0x8011dccd A1 : 0x3ffeb8b0
19:51:25.967 -> A2 : 0x3ffeb8f8 A3 : 0x3ffff7e0 A4 : 0x00000000 A5 : 0x00000004
19:51:25.967 -> A6 : 0x3ffe8cf0 A7 : 0xbaad5678 A8 : 0x00000001 A9 : 0x3f4112d4
19:51:25.967 -> A10 : 0x00000000 A11 : 0x3ffeb8f8 A12 : 0x00000001 A13 : 0x00000001
19:51:25.967 -> A14 : 0x00060e20 A15 : 0x00000000 SAR : 0x00000018 EXCCAUSE: 0x0000001c
19:51:26.004 -> EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
19:51:26.004 ->
19:51:26.004 -> ELF file SHA256: 0000000000000000
However If any 2 of BLE/Wifi/LVGL are run at the same time, they run flawlessly together. This leads me to think that the issue is memory related, but I have no idea what or how to debug it, could someone, pretty please with a cherry on top, help?
Code: Select all
///WIFI CONFIG
#include "WiFi.h"
#include <HTTPClient.h>
UBaseType_t uxHighWaterMark;
unsigned long lastTime = 0;
unsigned long timerDelay = 1000;
unsigned long lcdLastTime = 0;
unsigned long lcdTimerDelay = 1;
const char* ssid = "SSID";
const char* password = "PASS";
const char* serverName = "http://192.168.0.123:80/";
////////////LCD config///////////
#include <TFT_eSPI.h> // Hardware-specific library
#include <lvgl.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
/*Change to your screen resolution*/
static const uint32_t screenWidth = 240;
static const uint32_t screenHeight = 320;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];
int currentTile = 0;
int totalTiles = 3;
lv_obj_t *tv;
///////////BLE config///////////
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
TaskHandle_t wifiTask;
TaskHandle_t bleTask;
TaskHandle_t radioTask;
// The remote service we wish to connect to.
static BLEUUID crcServiceUUID("1816");
// The characteristic of the remote service we are interested in.
static BLEUUID crcMeasurementCharUUID("2A5B");
unsigned long lastBleTime = 0;
unsigned long bleDelay = 1000;
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
bool bleReady = false;
bool bleSetup = false;
bool bleConnectingToServer = false;
int currentSpeed = 0;
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
unsigned long prevRadioTime = millis();
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
connected = true;
Serial.println("onConnect");
}
void onDisconnect(BLEClient* pclient) {
connected = false;
Serial.println("onDisconnect");
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
Serial.println("*********");
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
char str[rxValue.length()];
for (int i = 0; i < rxValue.length(); i++)
str[i] = rxValue[i];
Serial.println(str);
}
}
};
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(crcServiceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
Serial.begin(115200);
setupLcd();
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
radioTaskCode, /* Task function. */
"RadioTask", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&radioTask, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
void loop()
{
delay(5);
}
void setupBle(){
// Create the BLE Device
BLEDevice::init("ble device");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
//Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
//SCAN for CSC device
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
bleSetup = true;
}
void loopBle() {
if ((millis() - lastBleTime) > bleDelay) {
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
if (connectToServer()) {
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
}
doConnect = false;
}
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
// with the current time since boot.
if (connected) {
String newValue = "Time since boot: " + String(millis()/1000);
Serial.println("Setting new characteristic value to \"" + newValue + "\"");
// Set the characteristic's value to be the array of bytes that is actually a string.
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
}else if(doScan){
Serial.println("doing BLE scan");
BLEDevice::getScan()->start(0); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
}
lastBleTime = millis();
}
if (deviceConnected) {
//pTxCharacteristic->setValue(&txValue, 1);
//pTxCharacteristic->notify();
// txValue++;
//delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
if(prevRadioTime == 0) {
prevRadioTime = millis();
} else if(millis() - prevRadioTime > 500){
//delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
//Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
prevRadioTime = 0;
}
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
Serial.print("Notify callback for characteristic ");
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
Serial.print("data: ");
//currentSpeed = getSpeed(pData[1]);
Serial.println(pData[1]);
}
bool connectToServer() {
bleConnectingToServer = true;
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
Serial.println(" - Connecting to device");
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(crcServiceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(crcServiceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(crcMeasurementCharUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(crcMeasurementCharUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our characteristic");
// Read the value of the characteristic.
if(pRemoteCharacteristic->canRead()) {
std::string value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
if(pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback);
bleConnectingToServer = false;
connected = true;
return true;
}
//WIFI
void setupRadio(){
setupWifi();
Serial.println("Connecting");
}
void loopRadio() {
if(WiFi.status() == WL_CONNECTED && !bleSetup){
setupBle();
}
else{
loopBle();
}
loopWifi();
vTaskDelay(1); // feed the IDLE0 watchdog
}
void setupWifi() {
WiFi.begin(ssid, password);
}
void loopWifi() {
if ((millis() - lastTime) > timerDelay) {
if(WiFi.status()== WL_CONNECTED) {
Serial.println("WiFi connected");
}
else {
Serial.println("WiFi Disconnected");
}
lastTime = millis();
}
}
void radioTaskCode( void * pvParameters ){
setupRadio();
for(;;){
loopRadio();
}
}
void setupLcd(){
tft.begin(); /* TFT init */
tft.setRotation( 0 ); /* Landscape orientation, flipped */
lv_init();
// uint16_t calData[5] = { 568, 3057, 562, 3176, 6 };
//tft.setTouch( calData );
/////////////////Uncommenting this line makes it break//////////////////////
/*lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );
//Initialize the display
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
//Change the following line to your display resolution
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = flush_display;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
//Initialize the (dummy) input device driver
static lv_indev_drv_t indev_drv;
lv_indev_drv_init( &indev_drv );
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = read_touchpad;
lv_indev_drv_register( &indev_drv );*/
Serial.println( "Setup done" );
}