ESP32 wifi + ble not playing nicely with LVGL

not-the-messiah
Posts: 8
Joined: Mon Nov 22, 2021 7:27 pm

ESP32 wifi + ble not playing nicely with LVGL

Postby not-the-messiah » Mon Nov 22, 2021 8:21 pm

Hi,

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
The error code varies depending on how much of the LCD I've setup and start looping or which order I start the services up. And if there is more code it may break earlier on the line: `lv_init();` instead.

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" );
}

ESP_Sprite
Posts: 9724
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby ESP_Sprite » Tue Nov 23, 2021 3:24 am

The guru meditation tends to come with a backtrace. Can you decode that and post the results? That may point you/us in the right direction.

not-the-messiah
Posts: 8
Joined: Mon Nov 22, 2021 7:27 pm

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby not-the-messiah » Tue Nov 23, 2021 9:05 am

Hi, thanks for your response, here is the backtrace:

Code: Select all

Backtrace: 0x4012635e:0x3ffeb8b0 0x4011dcca:0x3ffeb8f0 0x400907a6:0x3ffeb920

ESP_Sprite
Posts: 9724
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby ESP_Sprite » Wed Nov 24, 2021 4:41 am

Okay, but can you also decode that? You can use this for that.

not-the-messiah
Posts: 8
Joined: Mon Nov 22, 2021 7:27 pm

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby not-the-messiah » Wed Nov 24, 2021 10:39 am

My apologies, I did actually decode it, but I sent it as a separate message that was marked as a duplicate for some reason...

Here is the decoded backtrace:

Code: Select all

10:35:05.653 -> Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
10:35:05.689 -> Core 0 register dump:
10:35:05.689 -> PC      : 0x4012635e  PS      : 0x00060430  A0      : 0x8011dccd  A1      : 0x3ffeb8b0  
10:35:05.689 -> A2      : 0x3ffeb8f8  A3      : 0x3ffffef0  A4      : 0x00000000  A5      : 0x00000004  
10:35:05.689 -> A6      : 0x3ffe8d38  A7      : 0xbaad5678  A8      : 0x00000001  A9      : 0x3f4112d4  
10:35:05.689 -> A10     : 0x00000000  A11     : 0x3ffeb8f8  A12     : 0x00000001  A13     : 0x00000001  
10:35:05.689 -> A14     : 0x00060620  A15     : 0x00000000  SAR     : 0x00000018  EXCCAUSE: 0x0000001c  
10:35:05.725 -> EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  
10:35:05.725 -> 
10:35:05.725 -> ELF file SHA256: 0000000000000000
10:35:05.725 -> 
10:35:05.725 -> Backtrace: 0x4012635e:0x3ffeb8b0 0x4011dcca:0x3ffeb8f0 0x400907a6:0x3ffeb920

PC: 0x4012635e: btc_gatts_cb_handler at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c line 831
EXCVADDR: 0x00000000

Decoding stack results
0x4012635e: btc_gatts_cb_handler at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c line 831
0x4011dcca: btc_task at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/common/btc/core/btc_task.c line 163
0x400907a6: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
I also got a different error from the same code when trying to reproduce, I can't remember seeing this one before:

Code: Select all

10:32:19.539 -> ESP_ERROR_CHECK failed: esp_err_t 0x101 (ESP_ERR_NO_MEM) at 0x4008f9cc
10:32:19.539 -> file: "/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/ets_timer_legacy.c" line 66
10:32:19.539 -> func: ets_timer_setfn
10:32:19.539 -> expression: esp_timer_create(&create_args, (esp_timer_handle_t*)&(ptimer->timer_arg))
10:32:19.575 -> 
10:32:19.575 -> ELF file SHA256: 0000000000000000
10:32:19.575 -> 
10:32:19.575 -> Backtrace: 0x4008f4b4:0x3ffdba60 0x4008f9cf:0x3ffdba80 0x401aed72:0x3ffdbaa0 0x401acd01:0x3ffdbad0 0x400fb06c:0x3ffdbaf0 0x400f847c:0x3ffdbb10 0x400f85e6:0x3ffdbb30 0x40116d7e:0x3ffdbb50 0x400907a6:0x3ffdbb80

Decoding stack results
0x4008f4b4: invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 156
0x4008f9cf: _esp_error_check_failed at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 721
0x401aed72: ets_timer_setfn at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/ets_timer_legacy.c line 66
0x401acd01: timer_setfn_wrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/esp_adapter.c line 392
0x400907a6: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Thanks again for your help!

ESP_Sprite
Posts: 9724
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby ESP_Sprite » Thu Nov 25, 2021 2:41 am

ESP_ERROR_CHECK failed: esp_err_t 0x101 (ESP_ERR_NO_MEM) at 0x4008f9cc
This may very well be the underlying issue: wifi+ble+lvgl may simply use too much RAM to fit in the ESP32 together.

not-the-messiah
Posts: 8
Joined: Mon Nov 22, 2021 7:27 pm

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby not-the-messiah » Thu Nov 25, 2021 12:15 pm

When I check the high water mark I get the following:

Code: Select all

12:07:23.099 -> loop high water mark:8436
12:07:23.137 -> radio high water mark:8052
I guess the heap is taking up too much space...

I'll try optimise the stack and see whether that helps....

Could you tell me what the best way is to see the heap usage?

ESP_Sprite
Posts: 9724
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby ESP_Sprite » Fri Nov 26, 2021 1:19 am

You'd use e.g. heap_caps_get_free_size(MALLOC_CAP_DEFAULT) for that. The docs may have some hints for optimization as well.

not-the-messiah
Posts: 8
Joined: Mon Nov 22, 2021 7:27 pm

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby not-the-messiah » Fri Nov 26, 2021 3:56 pm

Thanks a lot for your help! I'll dig into that and see how I get on.

20岁开始秃头
Posts: 4
Joined: Sat Mar 05, 2022 2:17 am

Re: ESP32 wifi + ble not playing nicely with LVGL

Postby 20岁开始秃头 » Sat Mar 05, 2022 8:53 am

hello, Did you solve the problem?

Who is online

Users browsing this forum: Majestic-12 [Bot] and 132 guests