We upgraded our custom PCB to ESP32-S3 and thus I am upgrading my firmware too.
Unfortunately, the BLE connecting to it, I got a crash in the BTC_TASK (See below for extended information)
By looking at the stack, it appears in the `vfprintf.c file. I've been pulling my hair for days now without success. Anyone could put me on a path to a solution? And don't hesitate to point me to weird things in my setup or versions I use.
The crash I have:
Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception).
Debug exception reason: Stack canary watchpoint triggered (BTC_TASK)
Core 0 register dump:
PC : 0x4216e4f1 PS : 0x00060236 A0 : 0x8216aa0c A1 : 0x3fcb71c0
A2 : 0x3fcb755c A3 : 0x00000004 A4 : 0x00000001 A5 : 0x00000010
A6 : 0x3fcb71d0 A7 : 0x0000000c A8 : 0x00000001 A9 : 0x3fcb71d0
A10 : 0x0000005a A11 : 0x0000002a A12 : 0x00000064 A13 : 0x3c1f4220
A14 : 0x00000064 A15 : 0xff000000 SAR : 0x0000000a EXCCAUSE: 0x00000001
EXCVADDR: 0x00000000 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xffffffff
Backtrace: 0x4216e4ee:0x3fcb71c0 0x4216aa09:0x3fcb74d0 0x42045db1:0x3fcb7590 0x42045e2d:0x3fcb75c0 0x42046069:0x3fcb7620 0x420108a9:0x3fcb7690 0x421858a3:0x3fcb79c0 0x42051721:0x3fcb79e0 0x420571ed:0x3fcb7ca0 0x42054aa5:0x3fcb7cc0 0x42055215:0x3fcb7d10 0x420545d1:0x3fcb7d30 0x4205276d:0x3fcb7d90 0x4209d122:0x3fcb7db0 0x4209dca1:0x3fcb7dd0 0x420c20c1:0x3fcb7e20 0x420c6d33:0x3fcb7e40
The stack is as follows:
0x4216e4ee: _svfprintf_r at /Users/brnomac003/.gitlab-runner/builds/qR2TxTby/1/idf/crosstool-NG/.build/xtensa-esp32s3-elf/src/newlib/newlib/libc/stdio/vfprintf.c:1192
0x3fcb7620: ?? ??:0
0x42054aa5: BLEService::handleGATTServerEvent(esp_gatts_cb_event_t, unsigned char, esp_ble_gatts_cb_param_t*) at /Users/stephanedeluca/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src/BLEService.cpp:362
0x3fcb7db0: ?? ??:0
I upgraded some libs, and my platformio.ini excerpt is as follows:
[env]
platform = espressif32
;@ ~3.5.0
board = esp32-s3-devkitm-1 ; PCB_REV ≥ 10 ;
; board = esp32-s3-devkitc-1
; board = esp-wrover-kit ; PCB_REC < 10
framework = arduino
platform_packages =
framework-arduinoespressif32@3.20017.0 ;@ 3.20003.220626
;@3.20005.220925
;@3.10006.210326
tool-esptoolpy@ 1.30300.0
;@1.40201.0
;@1.30100.210531
toolchain-xtensa-esp32 @ 12.2.0+20230208 ;@ 8.4.0+2021r2-patch3
toolchain-xtensa32 ;@ 2.50200.97
;@2.50200.97
;@2.50200.97
And the compilation trace is as follows:
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitm-1.html
PLATFORM: Espressif 32 (6.9.0) > Espressif ESP32-S3-DevKitM-1
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
- framework-arduinoespressif32 @ 3.20017.0 (2.0.17)
- tool-esptoolpy @ 1.30300.0 (3.3.0)
- toolchain-riscv32-esp @ 8.4.0+2021r2-patch5
- toolchain-xtensa-esp32 @ 12.2.0+20230208
- toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
- toolchain-xtensa32 @ 2.50200.97 (5.2.0)
LDF: Library Dependency Finder -> xxxxx
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 43 compatible libraries
Scanning dependencies...
Dependency Graph
|-- Tone32 @ 1.0.0
|-- NTPClient @ 3.2.1
|-- base64 @ 1.2.1
|-- PubSubClient @ 2.8.0
|-- ArduinoJson @ 6.21.3
|-- EspSoftwareSerial @ 6.16.1
|-- Time32 @ 1.1.3
|-- idf-flash-vendor-patches @ 0.0.0+20231025182901.sha.182e042
|-- SSLClient @ 1.6.11+sha.712e593
|-- ESP32 BLE Arduino @ 2.0.0
|-- FFat @ 2.0.0
|-- SPIFFS @ 2.0.0
|-- Update @ 2.0.0
|-- WiFi @ 2.0.0
|-- Preferences @ 2.0.0
|-- HTTPClient @ 2.0.0
|-- SPI @ 2.0.0
|-- FS @ 2.0.0
|-- SD @ 2.0.0
|-- Wire @ 2.0.0
|-- WiFiClientSecure @ 2.0.0
Building in debug mode
None of the suggestions made my day as they didn't fixed my issue.
I finally came up with a nice solution that consists on offloading the processing of the incoming BLE value in a RTOS task. And I use a couple semaphores to synchronize the whole thing.
Characteristic call back:
/// BLE OTA service characteristics callbacks
class FirmwareUpdateCallbacks : public BLECharacteristicCallbacks {
/// Handles what OlenPEPS mobile app is asking for
void onWrite(BLECharacteristic *pCharacteristic) {
// Get the binary data and its length
const uint8_t *pData = pCharacteristic->getData();
const size_t len = pCharacteristic->getLength();
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
ble.success("OTA: onWrite(): Received %d bytes of data vvvvvvvvvvvvvvvvvvvvvvv", len);
#endif
if (len == 0) {
ble.alert("OTA: onWrite(): Received no data");
return;
}
if (len > sizeof ble.fuOtaDataReceptionBuffer) ble.alert("OTA: onWrite(): Received data from SDLTP for FU OTA overflows buffer. Truncated.");
if (*pData == OTA_RX_FB_RECEIVE_DATA_CHUNK) {
const unsigned chunkIndex = (pData[1]<<8)|pData[2];
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
ble.log("OTA: onWrite(): Received OTA_RX_FB_RECEIVE_DATA_CHUNK for chunk index: %d", chunkIndex);
#endif
}
// Copy the data in the static buffer
ble.fuOtaDataReceptionBufferSize = min(sizeof ble.fuOtaDataReceptionBuffer, len);
memcpy(ble.fuOtaDataReceptionBuffer, pData, ble.fuOtaDataReceptionBufferSize);
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
ble.success("OTA:onWrite(): Copied %d bytes of data, triggering task _processOtaFuPendingCommandIfAny() with semaphore", ble.fuOtaDataReceptionBufferSize);
#endif
// And trigger the semaphore for the task to process it
xSemaphoreGive(ble._sdltpPendingCommandSemaphore);
// Wait for the semaphore to allows for reading BLE, not to be too quick, I have to wait for the previous
// message to be processed
xSemaphoreTake(ble._waitPriorToReadOtaFuChracteristicSemaphore, portMAX_DELAY);
}
};
And the processing function:
/// Process FU OTA SDLTP command
bool Ble :: _processOtaFuPendingCommandIfAny() {
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
const auto o = LogEnter(this, "OTA: _processOtaFuPendingCommandIfAny()");
#endif
const auto p = RaiiScopeCloser(
[this](){},
[this](){
fuOtaDataReceptionBufferSize=0;
// Enable reading on the next incoming message on BLE
xSemaphoreGive(_waitPriorToReadOtaFuChracteristicSemaphore);
}
);
const auto pCharacteristic = serviceOtaCharacteristicTX;
const size_t len = fuOtaDataReceptionBufferSize;
// DO THE PROCESSING RIGHT HERE
}
PS: My RaiiScopeCloser
object is a simple helper class that runs the first closure at construction time and the second at destruction time. This to make sure the semaphore is given when the processing is complete.
With this code variation, I didn't have a need to a raise in stack size when compared with my previous ESP32-S1 code. I am happy.