Using ESP32 BLE

by ai0xuexi in Circuits > Microcontrollers

3058 Views, 7 Favorites, 0 Comments

Using ESP32 BLE

ESP32_BLE.jpg

Introduction.

This is an extension of my previous article by adding a new feature of displaying my solar charger status on my cell phone using BlueTooth Low Energy, BLE.

My solar charge controller is in my garage. A remote display unit was built to display the controller status using NRF24L01. The remote display was at a fixed location inside my home. It was not that convenient. I decided to build a device so that the controller status was displaying on my cell phone.

I had 2 choices, one was using WiFi, the other was using Bluetooth. I knew nothing about both of them. I thought Bluetooth did not require a password and could be easier to learn and implement. So I chose Bluetooth. But with my programming skill, it was far from the truth.

I decided to use ESP32 as my next solar charger controller. It has a lot of built-in memory and its speed is 10x faster than an Arduino nano. Best of all, it has built-in Bluetooth and WiFi functions and is inexpensive.

To familiarize me with the ESP32 operation, the Bluetooth display project will be a good training ground.

Learning ESP32 was much harder than I thought. It took me weeks to get my codes working.

There is a lot of programming syntax I don’t understand. I will be appreciated if anyone could tell me how the event handler works in the Bluetooth library. So far my program works faultlessly for days.

I don’t advise beginners with no knowledge of microcontrollers to use ESP32 or follow my article since myself is also a beginner.

If you like me without a Bluetooth background, watch all the videos in the Bluetooth Low Energy link. They are very informative.

There is a lot of videos and instructions about ESP32 Bluetooth on Youtube as well as in Instructable. Most of them are explaining the example listed in Arduino IDE in detail. But innovation outside the example is rare.

At first, I used Bluetooth classic by following the examples in Arduino IDE. I was able to establish communication between my cell phone and ESP32. But once the connection was disconnected due to loss of signal or manual disconnecting. Then reconnection was impossible unless rebooting the ESP32. But rebooting the microcontroller after power-up will have major consequences.

I tried to resolve the issue by reading “BluetoothSerial.h” and “BluetoothSerial.ccp”. For a beginner like me, to understand what in those files, which had no comments nor explanation on their functions and their parameters, I needed divine intervention. Those library files were so user-unfriendly.


I googled the issue, but I couldn’t find any solution. If anybody knows how please tell me.

Also, can someone explain to me the programming syntax for the following statements especially the '->'.

// Obtain a reference to the characteristic in the service of the remote BLE server.

pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);

Lack of knowledge is not an excuse for me. An engineer’s main task is to make things work, not whining.

After weeks of trial and error, I was able to make connections and disconnections successfully using Bluetooth Low Energy even with a lot of codes I don't understand.

My goal to publish this article is to keep a detailed record for myself as well as to show anybody, who has no BlueTooth background like me, how to use a cell phone to control a remote device through BlueTooth Low Energy.

Supplies

A Computer.

A Cell Phone.

A ESP-VROOM-32D or equivalent.

One NRF24L01. This is optional. The ESP32 can self-generate some data for transfer instead of getting it from NRF24L01.

USB cable.

Requirements for the Microcontroller

ESP32-VROOM-32D.jpg

For the details of ESP32, please refer to the ESP32 datasheet.

There are a lot of videos and articles that talk about how to set it up and how to use it. I am not presenting them here.


Functions that are required by my Solar Controller project.

A. Wireless data Communication.

ESP32 has WiFi and BlueTooth.

B. Wired data Communication.

ESP32 has SPI and I2C.

C. PWM for the buck converter.

ESP32 PWM frequency is higher than 200KHz. That is adequate.

D. Analog to digital converter. ESP32 has a 12 bits ADC.

It seems good enough. But reading the datasheet, the ADC INL is +/-12 bits. That is equivalent to minus 3.5bits out of the ADC resolution. The effective bits for the ADC are 8.5 bits. That is not good enough for my project.

E. 6 or more GPIO to control input, output, and balancing switches.

ESP32 has 40 GPIO pins, but most of them cannot be used freely as a GPIO.

A Brief Description for the GPIO

ESP32_pins.jpg

There are 40 GPIO pins, For GPIO 20,24,28-31, 37, 38, I did not find them on my ESP32 board.

Most GPIO pins have a secondary function. They can’t be used freely as input and output. As you see in the cheat sheet I created, only 9 pins in light green color are qualified as General Purpose Input Output.

There is 2 SPI bus, VSPI and HSPI. In most standard libraries, they use VSPI. There is no need to use the HSPI (MOSI=G13 MISO=G12 CLK=G14 CS=G15) that frees up those pins.

For I2C, most standard libraries using SDA=G21 and SCL=G22. Those pins assignments can be changed by Wire.begin(SDA, SCL); but why bother.

G34 to G39 is for input-only pins. Use them for ADC measurements or digital inputs to free up other pins. G36 and G39 are for Hall effect sensor pins. I can't make the Hall effect sensor work or use it for anything. It is useless. I don’t enable it.

G25, G26 secondary function is an 8 bits digital to analog converter programming by dacWrite(25, i) or dacWrite(26, I).

PlatformIO uses GPIO 12 to 15 for debugging. I am not using PlatformIO. So those pins are good to use as GPIO.

All ADC2 can’t be used when WIFI is enabled. They are in orange color.

For GPIO with underline, they have PWM signal during boot up. If using them, make sure your circuit can tolerate the PWM during boot up.

So far, I have not used the touch pins yet. So no comments on those pins.

RF Radio NRF24L01

nrf24l01.jpg

In my former project, NRF24L01 was used for broadcasting solar charger data. Now ESP32 uses the NRF24L01 to capture the broadcasted data and retransmits the data in text format through BLE to a cell phone.

NRF24L01 is not required if it is just for testing communication between ESP32 and a cell phone. The receiving data can be substituted by any type of data generated by ESP32.

NRF24L01 has its merit over BlueTooth. Any NRF24L01 with the same address can send and receive data. For BlueTooth, once it is paired and connected, it blocks out any other devices.

Programming Codes for NRF24L01.

It was copied and modified from the examples > NRFLite > Basic_RX_ESP32

To use NRF24L01, 2 libraries are needed
#include // SPI library

#include // NRF24L01 library

Wires connections

// Radio ESP32

// CE -> 4

// CSN -> 5

// MOSI -> 23

// MISO -> 19

// SCK -> 18

// IRQ -> No connection

// VCC -> 3.3V

// GND -> GND

// Defining and config the NRF24L01

#define RADIO_TX_ID 13 // Transmitter Radio ID. Not use in receiving

#define DESTINATION_RADIO_ID 18 // The Receiving Radio ID.

#define RF_CHAN 108 // Channel used by NRF24L01

#define PIN_RADIO_CE 4 // CE pin

#define PIN_RADIO_CSN 5 // CSN pin

#define PIN_RADIO_MOSI 23 //MOSI pin

#define PIN_RADIO_MISO 19 //MISO pin

#define PIN_RADIO_SCK 18 //SCK pin.

NRFLite _radio; // using the NRF24L01.

Codes Inside the setup()

// configure the NRF24L01 pins

SPI.begin(PIN_RADIO_SCK, PIN_RADIO_MISO, PIN_RADIO_MOSI, PIN_RADIO_CSN);

// Indicate to NRFLite that it should not call SPI.begin() during initialization since it has already been done. uint8_t callSpiBegin = 0;

//Check for connection

if (!_radio.init(DESTINATION_RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE250KBPS, RF_CHAN, callSpiBegin)) { Serial.println(" Initial communicate with radio fail"); while (1);

else Serial.println(" NRF24L01 Connected");

Codes inside the loop()

// wait for the availability of data and store the data to Vm.

while (_radio.hasData()) {

_radio.readData(&vm);

....

}

BLE Programming Codes

IMG_20210330_220711.jpg

Download the ble_ex1.ino and start the Arduino IDE and open the downloaded file.

The ble_ex1.ino was a modified copy from Examples>ESP32 BLE Ardinio> BLE uart

Make your UUID unique, go to line 144 and click on the UUID link and generate 3 version-4 UUID. Then replacing the UUID in line 146,147,148 with the newly generated UUID. Then go to line 194 and change "Solar Charger" to “whatever name you want”.

Code explanation

Lines 13 to 19

#include "BLEDevice.h"

#include "BLEServer.h"

#include "BLEUtils.h"

#include "BLE2902.h"

BLEServer *pServer = NULL;

BLECharacteristic * pTxCharacteristic;

No explanation on all the BlueTooth-related codes since I know little about them. All I know they are BLE libraries and some address pointers. I am just blindly following those codes since they work. If I know more later, then I will update this article.

Line 33 to 40

#define RADIO_TX_ID 13 // Transmitter Radio ID. Not use in this program

#define DESTINATION_RADIO_ID 18 // Our Receiving Radio ID.

#define RF_CHAN 108 //Using Radio Channel

#define PIN_RADIO_CE 4

#define PIN_RADIO_CSN 5

#define PIN_RADIO_MOSI 23

#define PIN_RADIO_MISO 19

#define PIN_RADIO_SCK 18

NRFLite _radio;

They define the NRF24L01 configuration. Delete them if NRF24L01 is not in use.

Line 43 to 53

char strf1[10];

char strf2[10];

char strf3[10];

char strout1[40];

char strout2[40];

char strout3[40];

char strout4[40];

char strout5[40];

char strout6[40];

char strout7[40];

They are char arrays used for storing the text messages sent out to the cell phone.

Line 54

uint8_t BCdata[40];

BCdata is the integer array to be shipped out by BlueTooth.

At line 233 to 258, the BlueTooth function does the data transfer

pTxCharacteristic->setValue(BCdata, strlen(strout1));

pTxCharacteristic->notify();

Which requires a uint8_t array. The compiler does not allow char arrays.

The conversion from char array to uin8_t array is done by

for(int i=0;i<32;i++) BCdata[i] = strout1[i];

By the way, the BlueTooth function only transfers 32 bytes max, The text message needs a \n char and a NULL char at the end of the array. That means there are only 30 bytes of data in the message. The array length can be 32 bytes. To avoid my careless mistake of overrunning the array and hang the program, I set the array length to 40 for safety.

Line 56 to 136

They are for reading and interpreting the data from NRF24L01. Delete them if not using NRF24L01.

Line 139, 140

bool deviceConnected = false;

bool oldDeviceConnected = false;

Line 150 to 158

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

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

They define the connection state. But I don’t know what it means.

Line 160 to 174

class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue();

if (rxValue.length() > 0) { Serial.println("*********");

Serial.print("Received Value: "); for (int i = 0; i < rxValue.length(); i++) Serial.print(rxValue[i]);

Serial.println(); Serial.println("*********"); } } };

rxValue is the message sent from a cell phone to ESP32. I am going to use it as a command for the ESP32.

Line 176

RadioPacket vm; This is the data structure sent by NRF24L01.

Line 183 to 191

SPI.begin(PIN_RADIO_SCK, PIN_RADIO_MISO, PIN_RADIO_MOSI, PIN_RADIO_CSN);

// Indicate to NRFLite that it should not call SPI.begin() during initialization since it has already been done.

uint8_t callSpiBegin = 0;

if (!_radio.init(DESTINATION_RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE250KBPS, RF_CHAN, callSpiBegin)) { Serial.println(" Initial communicate with radio fail");

while (1); // Wait here forever. }

else Serial.println(" NRF24L01 Connected");

This is to initialize the SPI bus and NRF24N01. Can be deleted if not using NRF24L01

Line 196 to 223 This is to initialize BLE, other than this, I don’t know what it is doing.

Line 226 to 275

loop()

It checks whether there is data available from NRF24L01, If data available and BLE are connected, get the data, and convert to a text message and send it out through BLE. to the cell phone. Otherwise, broadcast the BLE advertisement,

Downloads

Setting Up Cell Phone

steps.jpg

I can create my own cell phone APP using MIT App Inventor for a prettier user interface. But I am lazy, I installed the Serial BlueTooth Terminal from Play Store on my cell phone. Its appearance is not nice, but it got the job done.

After installing the Serial BlueTooth Terminal, power up the ESP32 and upload the Arduino program to the ESP32. I don't like pressing and holding the boot button when uploading, then press the reset button to start the program. There must be some way to make uploading more convenient.

Setting up the Cell phone

Turn the cell phone BlueTooth on, and scan for devices. You should find your device name which you changed in the program line 194. Then pair with that device and open the Serial BlueTooth Terminal App.

Following the steps in the picture. If you are at step 5, and your cell phone displays messages from ESP32, and your messages to the ESP32 are displayed on the Serial Monitor. Then power off and on the cell phone BlueTooth. If the Serial BlueTooth Terminal App can reconnect to your device,

Congratulation, you make it.