espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.52k stars 7.39k forks source link

Switching on and off BLE device causing reboot due to memory #7990

Open dharmikP17 opened 1 year ago

dharmikP17 commented 1 year ago

Board

ESP32

Device Description

ESP32 dev module

Hardware Configuration

No devices connected

Version

v2.0.5

IDE Name

Arduino IDE 2.0.2

Operating System

Windows 10

Flash frequency

80Mhz

PSRAM enabled

no

Upload speed

921600

Description

I want to turn off BLE device for which I am using BLEDevice::deinit(false); and then after some work I want to initialize it again and I am using BLEDevice::init(); for this. Problem is after few iterations it will run out of heap memory and will reboot esp. I am printing free heap on each call and I can see that it is decreasing after every deinit() call. From what I have gathered, If I set free space flag true i.e. BLEDevice::deinit(true); then I can never turn on BLE device again and I have tested this too.

Is there some configuration I am missing here to reuse this memory ? Is there any other way of doing this ? My aim is to do http request using wifi after switching off BLE. Can I do that without deinit() method ?

Sketch

void loop() {
    BLEDevice::init("ESP32_BLE_2____");
    pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyServerCallbacks());
    pServer->startAdvertising();
    Serial.println("server init");
    delay(1000);
    BLEDevice::deinit();
    delay(1000);
    Serial.print("free heap : ");
    Serial.println(ESP.getFreeHeap());
}

Debug Message

free heap : 140860
server init
free heap : 140188
server init
free heap : 139516
server init
free heap : 138844
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x4009545d  PS      : 0x00060633  A0      : 0x80094b95  A1      : 0x3fffc860  
A2      : 0x3ffd5020  A3      : 0x3ffc3390  A4      : 0x3ffc3390  A5      : 0x00060623  
A6      : 0x00060620  A7      : 0x00000001  A8      : 0xabba1234  A9      : 0x3ffd5008  
A10     : 0x00000000  A11     : 0x00000804  A12     : 0x3f405800  A13     : 0x00000003  
A14     : 0x007beeb8  A15     : 0x003fffff  SAR     : 0x00000003  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x00000008  LBEG    : 0x40090490  LEND    : 0x4009049b  LCOUNT  : 0x00000000  

Backtrace:0x4009545a:0x3fffc8600x40094b92:0x3fffc880 0x4011234b:0x3fffc8a0 0x400f8fb5:0x3fffc8f0 0x400eb259:0x3fffc910 0x400e6ee9:0x3fffc930 0x40110445:0x3fffc950 0x401122a3:0x3fffc970 

ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

SuGlider commented 1 year ago

@dharmikP17 The API has a flag, which default is to don't release all memory: static void deinit(bool release_memory = false);

I'll run some testing using BLEDevice::deinit(true); and report here the results.

dharmikP17 commented 1 year ago

@dharmikP17 The API has a flag, which default is to don't release all memory: static void deinit(bool release_memory = false);

I'll run some testing using BLEDevice::deinit(true); and report here the results.

Thank you for your time.

On thing I noticed is that, If I run only init() and deinit() functions in the loop than I don't loose memory. I have to create server and set callbacks every time and those are responsible for taking new memory which eventually eat up all memory. Is it possible to use previously defined callbacks ? I tried but failed.

dharmikP17 commented 1 year ago

@SuGlider Did you get to try ? Let me know if I can try something. I tried BLEDevice::deinit(true); but I have to set initialized flag to false somewhere else otherwise init() will not work. If I do that code gets stuck in btStart() function in init(). There is one while loop in this function probably that is blocking the code, but I was not able to go any deeper.

bool btStart(){
    esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){
        return true;
    }
    if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){
        esp_bt_controller_init(&cfg);
        while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){}
    }
    if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){
        if (esp_bt_controller_enable(BT_MODE)) {
            log_e("BT Enable failed");
            return false;
        }
    }
    if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){
        return true;
    }
    log_e("BT Start failed");
    return false;
}
SuGlider commented 1 year ago

I'll work on it along this week.

dharmikP17 commented 1 year ago

Hello,

Has anyone found anything related to this ? I waas recently trying A2DP with ESP32 and faced this same issue while switching on and off. Why I am not able to turn off and turn on bluetooth again ? It does work with bluetoothserial though.

AAJAY5 commented 1 year ago

Here is possible trick

image

#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

bool deviceConnected = false;

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

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

BLEServerCallbacks *cb;
void setup(){
    Serial.begin(115200);
    cb = new MyServerCallbacks();
}

void loop() {
    Serial.println("Start");
    BLEDevice::init("ESP32_BLE_2____");
    BLEServer *pServer = BLEDevice::createServer();
    pServer->setCallbacks(cb);
    pServer->startAdvertising();
    Serial.println("server init");
    delay(5000);
    BLEDevice::deinit(false);
    delete pServer;

    Serial.print("free heap : ");
    Serial.println(ESP.getFreeHeap());
    delay(2000);
    Serial.println("End");
}
sidwarkd commented 1 year ago

As @AAJAY5 hints at the memory loss you are seeing is not due to the deinit and init but to the fact that each time through the loop you are calling new MyServerCallbacks which is a memory leak because setCallbacks only does assignment and doesn't clean up that handler class.

Additionally your free heap is still quite high when your app crashes (still over 100k). (StoreProhibited)[https://docs.espressif.com/projects/esp-idf/en/v4.4.3/esp32/api-guides/fatal-errors.html?highlight=storeprohibited#loadprohibited-storeprohibited] doesn't mean you are out of memory. Based on the value of your EXCVADDR the docs suggest "If this address is close to zero, it usually means that the application has attempted to access a member of a structure, but the pointer to the structure is NULL"