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
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?
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 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:
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
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.
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.
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.