Debug exception reason: Stack canary watchpoint triggered (uart_event_task)

I have a program on a ESP32_S3 that uses a BLE server, Console.h with Freertos and Serial2 for uart communications with another device. Everything works up till I connect to the BLE server using a BLE serial app on my phone. I can use the CLI from serial with the console.h but when another method tries to send data using

pTxCharacteristic->setValue("BLE test");
pTxCharacteristic->notify();

i get a kernel panic

Debug exception reason: Stack canary watchpoint triggered (uart_event_task)

From what I can figure while there is an active BLE connection to the phone, there's something eating up the heap allocated to the uart_event_task.

What I want to do is increase the freertos task uart_event_task heap size but I can't find where its hidden in the libraries. Can someone point me to where its usually stored?

You could start here: arduino-esp32/cores/esp32/HardwareSerial.cpp at master · espressif/arduino-esp32 · GitHub

void HardwareSerial::_createEventTask(void *args) {
  // Creating UART event Task
  xTaskCreateUniversal(
    _uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask,
    ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
  );
  if (_eventTask == NULL) {
    log_e(" -- UART%u Event Task not Created!", _uart_nr);
  }
}

Your topic does not sound like a problem with IDE 2.x and has therefore been moved to a more suitable category on the forum.

Thank you, that helped me.

Hoo are you talking to ?

BLE communication can be the most complex part of a project

get the BLE communication working first them add other functionality

have you run any of the BLE examples?

Yes, I've run several examples and I have had success running them as stand alone code. However when I tried integrating the code into my project involving freertos and the Console I kept getting severe memory issues because parts of my code were not thread safe and kept overlapping memory regions. I"ve since had to abandon my over all project but I did learn from it and I've been scavenging parts of my code to use in a new project that will have the arrays and strings formatted thread safe for freertos. Just FYI the last time I tried writing to the BLE object with my phone connected the chip looped in a panic with the canary pointing to IPR0 as the fail point. Maybe this information will help someone else with the same issue.

I would like some advice.

I am using a ESP32_S3 chip, FreeRTOS, BLESerial.h and I am trying to write a function that captures the BLE input into a char* so I can parse the data and perform string search and substring extractions. The last time I tried implementing this code I encountered so many memory errors and kernel panics that now I'm paranoid I'm going to keep running into the same issues.

From what I understand FreeRTOS doesn't like the string type due to memory allocation errors but I can use pvPortMalloc to make thread safe char arrays however I am so frustrated and stressed out I'm not sure how to write this.

I have the following code and if anyone could point out a FreeRTOS thread safe way to do this I'd be grateful:

 void Send_to_LoRa()
{
  char bytearray\[200\];
  int bytesread = SerialBLE.readBytesUntil('\\n',bytearray,sizeof(bytearray)-1);
  Serial.printf("buffer --> %s", bytearray);
}

what is the BLE UUID you are using?
are you using the UART Service UUID receiving text from an app such as the Android terminal?

are you then wishing to transmit over LoRa ? LoRa P2P or LoRaWAN?

These are from the example that I got to work. I haven't modified the code.

template<typename T>
const char\* BLESerial<T>::SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";

template<typename T>
const char\* BLESerial<T>::RX_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";

template<typename T>
const char\* BLESerial<T>::TX_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";

The phone app is a bluetooth serial app using a terminal interface.

The LoRa is a separate hardware module thats bound to Serial1 and uses the UART interface.

in this program I copy text received from a BLE terminal into a char array which is then printed in loop()

// ESP32 BLE terminal transmit/receive text using a ring buffer

// Android Serial Bluetooth/BLE terminal
//    https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal&hl=en-US

/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
   Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" 
   Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with  "NOTIFY"

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

   In this example rxValue is the data received (only accessible inside that function).
   And txValue is the data to be sent, in this example just a byte incremented every second. 
*/
#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;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#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"


class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer) {
    deviceConnected = true;
  };

  void onDisconnect(BLEServer *pServer) {
    deviceConnected = false;
  }
};

#define RINGLENGTH 20     // ring buffer test length is 20 - in practice make it 1000?
volatile char ringData[RINGLENGTH] ={ 0 };  // ring buffer

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    String rxValue = pCharacteristic->getValue();
    // copy received string into text buffer
    if (rxValue.length() > 0) {
      static int ringIndex = 0;                 // index into ring buffer
      Serial.print("BLE Received: ");
      for (int i = 0; i < rxValue.length(); i++) {        // copy received text into ring buffer
        Serial.print(ringData[ringIndex++] = rxValue[i]);
        if (ringIndex >= RINGLENGTH) ringIndex = 0;       // if at end of ring buffer reset index
      }
      Serial.println();
    }
  }
};


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

  // Create the BLE Device
  BLEDevice::init("UART Service");

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

void loop() {
  static int loopIndex=0;
  // if available read string from serial - transmit over BLE
  if (deviceConnected) {
    // if text string received from BLE print it
    if(ringData[loopIndex])Serial.print("loop() received from BLE ");
    while (ringData[loopIndex]) {
      Serial.print(ringData[loopIndex]);    // print character and clear it
      ringData[loopIndex] = 0;
      // if at end of ring buffer reset index
      if (++loopIndex >= RINGLENGTH) { Serial.print("\nreset loopIndex ");loopIndex = 0;}
    }
    if (Serial.available()) {
      String s = Serial.readStringUntil('\n') + "\n";  // read line of text
      Serial.printf("BLE transmit: %s\n", s.c_str());
      pTxCharacteristic->setValue((uint8_t *)s.c_str(), strlen(s.c_str()));
      pTxCharacteristic->notify();  // transmit line of text
    }
  }
  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500);                   // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising();  // restart advertising
    Serial.println("start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }
}

serial monitor output

Waiting a client connection to notify...
BLE Received: hello from ble

loop() received from BLE hello from ble
BLE Received: loop() received from BLE ttest 2 from ble

loop() received from BLE est
reset loopIndex  2 from ble
BLE Received: test 3 from ble

loop() received from BLE test 3 
reset loopIndex from ble
BLE transmit: hello from pc

BLE transmit: test2 from pc 12345

Android terminal app

could you give some details of the overall project?

I'm just curious. Do you know what context the callbacks are called from?
I've not used Bluetooth on the ESP32, but I've used the async web server, which has similar call backs.
I assume both use a FreeRTOS thread to do the callbacks.
I had some buggy behaviour caused (I think) by doing a lot of things in the callbacks, such as debug serial prints.
I decided to serialise the callbacks by just pushing the information they provide onto a FreeRTOS queue which I read in loop(). After that change I didn't have any further problems with unexpected behaviour.

Hey thank you for the reply, I'll read over your code when I get more free time to focus.

What I"m trying to build is a bluetooth to LoRa device, small enough to fit in my pocket that my phone can connect to wirelessly. I want to use the USB as a CLI interface for the same commands that go over the bluetooth connection.

I don't want to store information about the outgoing LoRa transmission on the device, I"d rather that information be managed by the device on the other end of the bluetooth or USB connection. So from the BLE LoRa bridge to the phone all I need is to send data to the LoRa and a small buffer to store the last message received from the LoRa radio just incase I loose bluetooth connection.

On the other end I"m building a LoRa receiver using the same ESP32_S3 setup that will take traffic coming from the LoRa radio and communicate via UART to rs232 and rs485 devices.

For that part of my project I need to be able to store message from both the LoRa radio and the UART and pick out parts of the message to process. For instance the UART LoRa bridge might be connected to equipment that uses a rs232 and UART formatted messaging. The equipment sends out an error message across the rs232 interface and I want a buffer to store the message so I can retrieve it via the LoRa setup and send back a reset command.

For the LoRa radio I'm using a RYLR998 transceiver.

Thats a good point, I've just been using the built in library.

What BLESerial.h library are you using. There are several with the same name.

int bytesread = SerialBLE.readBytesUntil('\\\\n',bytearray,sizeof(bytearray)-1);

In the line of code in post 1 you are reading without checking SerialBLE.available() to see if there is anything to be read.

Using the BLE terminal code posted by @horace is probably a better way to go than using the BLESerial.h library if it does not use the call back functions under the hood.

Nordic UART service from an android phone to an esp32 s3 is a common application.

Can you post complete code, and indicate what the issues are.

for your BLE-LoRa bridge I assume you want the device to be as small as possible and battery powered
rather than an ESP32S3 module and a separate LoRa module I would use a module with an ESP32 and LoRa on the same PCB with facilities for being battery powered, e.g. Heltec WiFi LoRa 32(V4.3.1), ESP32S3 + SX1262 LoRa Node
when waiting for BLE connection you can power down the LoRa radio
also have a look at Wi-Fi/Bluetooth and Sleep Modes

I think for a smaller foot print than the Heltec you could use a Xiao esp32 s3 or c3 with a wio sx 1262 lora board which would plug onto the Xiao headers.

https://www.seeedstudio.com/Wio-SX1262-for-XIAO-p-6379.html?srsltid=AfmBOor8SaopsTq1Cjz2MrXr1BOc_mZJr22w8gpnLxGFjzz6a8_nNSZF

I have merged your forum topics due to them having too much overlap on the same subject matter @xelrebrus.

In the future, please only create one topic for each distinct subject matter.

The reason is that generating multiple forum topics on the same subject matter can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.

Thanks in advance for your cooperation.