ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Fri Sep 02, 2022 5:26 am

Hi.

I have a weird problem with BLE. If anyone can help, it would be greatly appreciated.

The issues is ONLY found on any Arduino ESP32 board drivers newer than Version 2.0.0, but 2.0.0 works perfectly. So, the latest 2.0.4 shows the bug. Is there a coding workaround?

My unique application sends a tiny amount of variable data periodically in the Device Name. Long story, but there is a reason for doing this but not using a beacon. So for example a device can be "Gadget 001" in the device ID advertisement shown on nRF Connect. Then after an event, a new device "Gadget 002" will appear and so-on.

The application is perfectly fit-for-purpose woth ESP32 board driver 2.0.0. No bugs, no issues.

Then, when I updated the Arduino board driver to esp32 2.0.4, it stopped working. In fact any version never than 2.0.0 fails. The symptom is the first advertisement works fine, then when an event happens, there is no update to the advertisement on a BLE device.

It is clear the problem is that, unlike with 2.0.0, the BLE device does not de-initialize and then re-intialise. Here is the code. The area of interest is line 107 to line 116...
  1.  
  2. #include <BLEDevice.h>
  3. #include <BLEUtils.h>
  4. #include <BLEServer.h>
  5. #include "Gizmo.h"
  6.  
  7. /* Timer variables */
  8. hw_timer_t * timer = NULL;
  9. volatile uint16_t timerTick1ms = 0;
  10. uint32_t timeStamp = 0;
  11.  
  12. /* Timer ISR */
  13. void ARDUINO_ISR_ATTR onTimer(){
  14.     /* Flash Blue LED every 2s for 5ms as heartbeat */
  15.     timerTick1ms++;
  16.     if (timerTick1ms >= 1995) {
  17.       digitalWrite(BLUE_LED_PIN,HIGH);
  18.     }
  19.     else {
  20.       digitalWrite(BLUE_LED_PIN,LOW);
  21.     }
  22.     if (timerTick1ms > 2000) {
  23.       timerTick1ms = 0;
  24.     }
  25. }
  26.  
  27. //                    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  
  28. char advertText[] = {'G','i','z','m','o',' ','0',' ', 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0};
  29. char inChar = 0;
  30. char i = 0, j = 8;
  31. uint8_t advertCounter = '0';
  32. const int button = 9;
  33.  
  34. void setup() {
  35.   Serial.begin(9600);           // Default baud rate
  36.  
  37.   pinMode(button, INPUT);
  38.   pinMode(BLUE_LED_PIN, OUTPUT);    
  39.   pinMode(GREEN_LED_PIN, OUTPUT);    
  40.  
  41.   /* Flash Blue LED three times on POR */
  42.   for (i=0; i<3; i++) {
  43.     digitalWrite(BLUE_LED_PIN, HIGH);
  44.     delay(100);
  45.     digitalWrite(BLUE_LED_PIN, LOW);
  46.     delay(100);
  47.   }
  48.    
  49.   /* Set  up 1ms timer */
  50.   //timerSemaphore = xSemaphoreCreateBinary();   // Create semaphore to inform us when the timer has fired
  51.   timer = timerBegin(0, 80, true);// Use 1st timer of 4 (counted from zero), 80 prescaler.
  52.   timerAttachInterrupt(timer, &onTimer, true);  // Attach onTimer function to our timer.
  53.   timerAlarmWrite(timer, 1000, true); // Set alarm to 1ms (in microseconds) & repeat the alarm (third parameter)
  54.   timerAlarmEnable(timer);
  55.  
  56.   /* Advertise empty data when starting up */
  57.   advertText[5] = VERSION;
  58.  
  59.   BLEDevice::init(advertText);
  60.   BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  61.   pAdvertising->addServiceUUID(SERVICE_UUID);
  62.   pAdvertising->setScanResponse(true);
  63.   pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  64.   pAdvertising->setMinPreferred(0x12);
  65.   BLEDevice::startAdvertising();
  66.   delay(500);
  67.    
  68.   /* Get rid of any extraneous serial data on startup */
  69.   Serial.flush();                              
  70.   while(Serial.available()) Serial.read();
  71. }
  72.  
  73. void loop() {
  74.  
  75.   /* RESET IF BUTTON IS PRESSED */  
  76.   if (digitalRead(button) == LOW) { // Reboot if button is pressed
  77.      ESP.restart();
  78.      delay(1000);
  79.   }
  80.  
  81.   /* PROCESS EACH INCOMING CHARACTER FROM THE WEIGHING MACHINE */  
  82.   if (Serial.available() > 0)                           // A character has been received    
  83.   {
  84.       digitalWrite(GREEN_LED_PIN, HIGH);                // Flash of green LED
  85.  
  86.       inChar = Serial.read();                
  87.  
  88.       if((inChar != '\n') && (inChar != '\r') && (j <= MAX_ADVERT_CHARS))   // Ignore the CRLF characters and truncate if too many characters
  89.       {
  90.         advertText[j]= inChar;
  91.       }
  92.            
  93.       digitalWrite(GREEN_LED_PIN, LOW);
  94.      
  95.       if (inChar == '\n') {                             // Linefeed is the end of the incoming string
  96.    
  97.          if ((millis() - timeStamp) > 750)             // Only transmit at a maximum of once per second (750ms + adv setup time) to avoid buffer overrun screwing up the adverts.
  98.          {        
  99.            /* One-digit advertisement counter (1 to 9, then repeat) */
  100.            advertCounter++;
  101.            if (advertCounter > '9')
  102.            {
  103.               advertCounter = '1';  
  104.            }
  105.            advertText[6] = advertCounter;
  106.  
  107.            /* Update the BLE advertisement */
  108.            BLEDevice::deinit(false);
  109.            delay(20);
  110.            BLEDevice::init(advertText);
  111.            BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  112.            pAdvertising->addServiceUUID(SERVICE_UUID);
  113.            pAdvertising->setScanResponse(true);
  114.            pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  115.            pAdvertising->setMinPreferred(0x12);
  116.            BLEDevice::startAdvertising();
  117.            //delay(5);
  118.  
  119.            /* Advert has gone out, so re-initialise advert to null characters */
  120.            for (j=8; j<=MAX_ADVERT_CHARS; j++)
  121.            {
  122.               advertText[j] = 0;
  123.            }
  124.    
  125.            j=8;  // We start collecting incoming data at the ninth character in the entire advertisement, eg: after "GadgetA1 "
  126.            timeStamp = millis();
  127.          }  
  128.       }
  129.       else j++;   // Data is still coming in prior to advert going out.
  130.    }
  131. }
  132.  
  133.  

chegewara
Posts: 2364
Joined: Wed Jun 14, 2017 9:00 pm

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby chegewara » Fri Sep 02, 2022 7:30 am

Did you try to re-start advertising?

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Fri Sep 02, 2022 2:07 pm

Hi Chegewara.

Line 59 to 65 at setup is repeated on lines 110 to 116 in the loop, but on line 108 we de-init the device.
So isn't that effectively re-advertising?

And it does not explain by 2.0.0 of the ESP32 board driver works fine and newer versions all fail with the same code.

There will be one of two things: A bug in all these versions after 2.0.0, or there was a bug in 2.0.0 which allowed this to work. I might be the only person after 2.0.0 to have ever used re-advertising. Maybe there is a one-line command that was introduced after 2.0.0 that I am missing. Hopefully that is the case... I am hoping :? .

regards,
Dave

chegewara
Posts: 2364
Joined: Wed Jun 14, 2017 9:00 pm

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby chegewara » Fri Sep 02, 2022 7:25 pm

There was some changes, including disable auto-restart advertising if i remember.

There may be some timing issue and it would be good to add delays in your code, just in case, but to be honest it is better to use this code instead of deinit/init:

Code: Select all

		errRc = ::esp_ble_gap_set_device_name(deviceName.c_str());
		if (errRc != ESP_OK) {
			log_e("esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
		};

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Mon Sep 05, 2022 12:21 am

Hi.

I tried several things.

I replaced esp_ble_gap_set_device_name(advertText); it did not fix the problem. Advertising did not restart.

I also added a 20ms delay between each line of code in that advertising code - no difference. I don't think timing delays is the issue.

However, you may have hit on something..."There was some changes, including disable auto-restart advertising if i remember."
So there were changes after 2.0.0 with respect to restarting advertising. It seems dodgy and dangerous that functionality that works fine then breaks with a newer release of "driver".

I looked at https://docs.espressif.com/projects/esp ... p_ble.html and there is nothing that I can see which will fix this issue. I also tried esp_ble_gap_stop_advertising(void). No effect.

I could live with 2.0.0. I just got 60 boards made and it works fine on all. However, I am worried that Espressif will one day manufacture a revision of the hardware that REQUIRES a newer version than 2.0.0. If that happens, I am in trouble. I could make another 60 boards with a newer rev of the ESP32-C3 and it fails because of this problem. Hence why I should get this working with the latest version 2.0.4 at least so I can sleep at night.

My code, is essentially quite simple. I just might be the only person who changes the advertising string during program execution.

Maybe there is a simple command to reset the entire BLE state machine, which might be a crude workaround? Remember, the first adverting upon boot up in the Setup works fine. It is just the subsequent changes in advertising in the loop code that do not work.




regards,
David

chegewara
Posts: 2364
Joined: Wed Jun 14, 2017 9:00 pm

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby chegewara » Mon Sep 05, 2022 1:40 am

Hi,
there is 2 ways to advertise device name. I will test your code and let you know what may work for you.

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Mon Sep 05, 2022 1:44 am

Hi. Thank you! If you do that, and you ever visit Melbourne (Australia), I will shout you lunch and free beer. It will be interesting to see how to get around this issue. It may also help others who might come across a similar issue.

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Thu Sep 08, 2022 4:47 am

Hi Chegewara.

How are you going with reproducing the advertising bug? There is another reason I want to get this issue sorted out. I am using the same re-advertising technique on a another program which used the ESP32-C3. That program talks to a 128 x 64 OLED and other I/O devices. I found with ESP32 2.0.0 it crashes occasionally when writing to the OLED, but with 2.0.4 never crashes. The I2C signals and the power rails are clean. I tried latest drivers for OLED etc, and they don't make any difference. I can only assume some bugs between 2.0.0 and 2.0.4 have been sorted out that fixed the crashing issue.

So, running with 2.0.4 with the re-advertising working seems to be the way to get me out of trouble.... no crashing and (hopefully) re-advertising works.

regards,
David

vk3drb
Posts: 13
Joined: Wed Oct 20, 2021 9:42 am

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby vk3drb » Mon Sep 12, 2022 5:54 am

Hi Chegewara,

Were you able to reproduce this re-advertising issue?

Please test the relevant part of the code, or at least advise what are the two workarounds for this issue.

regards,
David

chegewara
Posts: 2364
Joined: Wed Jun 14, 2017 9:00 pm

Re: ESP32 ESP32C3 board newer than 2.0.0 has BLE bug, but 2.0.0 is OK.

Postby chegewara » Mon Sep 12, 2022 10:11 pm

Like I said in previous post, it's easy:
- before
Screenshot_20220913-000958_nRF Connect.jpg
Screenshot_20220913-000958_nRF Connect.jpg (360.93 KiB) Viewed 3891 times
- after
Screenshot_20220913-001005_nRF Connect.jpg
Screenshot_20220913-001005_nRF Connect.jpg (394.2 KiB) Viewed 3891 times
Code:

Code: Select all

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
 
/* Timer variables */
hw_timer_t * timer = NULL;
volatile uint16_t timerTick1ms = 0;
uint32_t timeStamp = 0;
 

//                    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  
char advertText[] = {'G','i','z','m','o',' ','0',' ', 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0};
char inChar = 0;
char i = 0, j = 8;
uint8_t advertCounter = '0';
const int button = 0;
 
void setup() {
  Serial.begin(115200);           // Default baud rate

  /* Advertise empty data when starting up */
  advertText[5] = 9;
 
  BLEDevice::init(advertText);
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID("5678");
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  delay(500);
   
  /* Get rid of any extraneous serial data on startup */
  Serial.flush();                              
  while(Serial.available()) Serial.read();
}
 
void loop() {
 
  /* RESET IF BUTTON IS PRESSED */  
  if (digitalRead(button) == LOW) { // Reboot if button is pressed
     ESP.restart();
     delay(1000);
  }
 
  /* PROCESS EACH INCOMING CHARACTER FROM THE WEIGHING MACHINE */  
  if (Serial.available() > 0)                           // A character has been received    
  {
      inChar = Serial.read();                
 
      if((inChar != '\n') && (inChar != '\r') && (j <= 20))   // Ignore the CRLF characters and truncate if too many characters
      {
        advertText[j]= inChar;
      }
           
    
      if (inChar == '\n') {                             // Linefeed is the end of the incoming string
   
         if ((millis() - timeStamp) > 750)             // Only transmit at a maximum of once per second (750ms + adv setup time) to avoid buffer overrun screwing up the adverts.
         {        
           /* One-digit advertisement counter (1 to 9, then repeat) */
           advertCounter++;
           if (advertCounter > '9')
           {
              advertCounter = '1';  
           }
           advertText[6] = advertCounter;
           String test = "test";
           esp_err_t errRc = ::esp_ble_gap_set_device_name(test.c_str());
           if (errRc != ESP_OK) {
              log_e("esp_ble_gap_set_device_name: rc=%d", errRc);
           };
           /* Update the BLE advertisement */
           BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
           pAdvertising->addServiceUUID("1234");
           pAdvertising->setScanResponse(true);
           pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
           pAdvertising->setMinPreferred(0x12);
           BLEDevice::startAdvertising();
           //delay(5);
 
           /* Advert has gone out, so re-initialise advert to null characters */
           for (j=8; j<=20; j++)
           {
              advertText[j] = 0;
           }
   
           j=8;  // We start collecting incoming data at the ninth character in the entire advertisement, eg: after "GadgetA1 "
           timeStamp = millis();
         }  
      }
      else j++;   // Data is still coming in prior to advert going out.
   }
   delay(10);
}
i tested it with S3, but should works with any esp32 with BLE.

PS all you have to do is to change code with the correct order; first change advertising value, then set it with esp_ble_gap_set_device_name and finally start advertising

Who is online

Users browsing this forum: Majestic-12 [Bot] and 74 guests