bluetooth-lowenergyesp32arduino-esp32

I got a crash in the BTC_TASK while migrating to ESP32-S3 from S1


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

Solution

  • 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.