ArticlesEmbedded C & MCUIoT

All about ESP32 – Part 4

Bluetooth Low Energy (BLE) Basics

 

Bluetooth Low Energy (BLE) is a multi-layer protocol or what’s known, as a terminology, a stack of protocols (Bluetooth stack). Before any practice with ESP32 Bluetooth peripheral, a solid background with most important BLE terms and basic overview is a must. That’s exactly why we wrote “Bluetooth Low Energy (BLE) 101 Tutorial: Intensive Introduction” article.

In this part of “All about ESP32” series we will explain the basics of using BLE. We will use one of ESP32 SDK (ESP-IDF) examples as a starting point. We will cite some content from our BLE introduction article, so try to get a look at it before starting.

 

ESP-IDF BLE GATT Server Example

 

This example is an example of a server that contains a set of services that clients will access to them. We will start explaining the most important parts of the example found in the following directory [ESP-IDF-DIR]\examples\bluetooth\gatt_server. This example will define TWO profiles and broadcast advertisements under the name of ESP_GATTS_DEMO. Each profile will contain one service and each service will contain one character. We will see and debug that in an Android Application called NRF Connect

The profile actually, doesn’t reflects any entry to the ATT table in the device. It’s a predefined set of services. In this example, they’ve defined identical service and characteristic in 2 profiles (Profile A & Profile B). This duplication has a design purpose described in the documentation:

In this way, a single design, enabled by different Application Profiles, can behave differently when used by different smartphone apps, allowing the server to react differently according to the client app that is being used. In practice, each profile is seen by the client as an independent BLE service. It is up to the client to discriminate the services that it is interested in.

GATT Server Demo ESP32

 

Initialization in Main function

 

Starting from main function with the very basic initialization part

As we saw before in WiFi part in this series, NVS (Non-Volatile Storage) should be initialized. The BLE stores some non-volatile variables in the NVS partition.

The code starts by initializing the Controller block of Bluetooth stack using some default parameters, they can be found in esp_bt.h. The Controller, as we discussed in the introduction article, basically manages everything that relates to the physical radio transaction,  and besides the initialization we should enable the Controller with BLE mode.

As Controller can run in one of the several modes, show below,and as ESP32 is a “Bluetooth Smart Ready” chip, it means that it can run in BLE mode, Classic Bluetooth mode or in dual-mode.

The next thing to do is to enable the Bluetooth software stack, which is the software in the background that does some internal bluetooth operations and controls bluetooth stack layers. ESP32 uses a modified version of the software stack called Bluedroid.

The next step is to register callback functions to serve GATT and GAP events, and BLE profiles that we’ve described in the beginning.

The top two layers in BLE stack that mostly matter for BLE developer are GAP, which is responsible mainly for advertising and broadcasting, and GATT which is responsible for storing and exchanging real data through a set of services that consist of characteristics which hold the concerning data.

Many different events may occur in GAP and GATT, thus each action is different depending on the event type. For this reason, the developer uses an event handler function for GAP and GATT. The BLE software stack calls these callback functions passing some parameters and other event information to be used in the handler.

The other thing to do is to register the two profiles

And finally, to set Maximum Transmission Unit (MTU) to 500.

What MTU defines is the size of Attribute PDU (packet not the bare ATT in the ATT table). To know more, you can check the very handy Punchthrough’s blog entry about MTU. Client and the Server should exchange their MTU when entering connection. Keep in mind that the ATT packets with a size larger than MTU cannot be transferred.

 

Starting Broadcasting/Advertisement

 

The first thing to do in the BLE firmware is to enable GAP advertisements, with connectable type packets and under a certain device name. To know more about advertising packets please read the Advertising (Advertiser & Scanner) section from our last article.

Back to the code, when we register the profile, an event will be triggered which is ESP_GATTS_REG_EVT, and by the way, GATT events defined in ESP-IDF can be one of the following:

Now let’s check gatts_event_handler :

What this function basically does, is to check if the event type is ESP_GATTS_REG_EVT, and if it’s true … first, it stores an interface number for each profile. The documentation says that GATT interface type in a different application on GATT client uses different gatt_if values.

The second thing to do is to call each profile call-back handler: gatts_profile_a_event_handler and gatts_profile_b_event_handler

Where these call-back functions were assigned while the declaration of gl_profile_tab array.

Part of gatts_profile_a_event_handler will set advertisement data using esp_ble_gap_config_adv_data(&adv_data) and esp_ble_gap_set_device_name(TEST_DEVICE_NAME), then the gap_event_handler will start the advertisement using esp_ble_gap_start_advertising function when the event type is ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT.

Now, the last thing to do is to create a service inside the profile using the esp_ble_gatts_create_service function. The function takes 3 parameters one of them is the number of handlers/ATT to allocate for the service as the service may contain more than one characteristic. The very basic service may contain one characteristic, and each characteristic will contain a characteristic declaration, Characteristic value attribute handle and the real value. Thus, the minimum attributes for the service are 4: service declaration,  characteristic declaration, Characteristic value attribute handle, and the real value. For more information, please refer to How Your Device Data Is Stored section in our last article and try to read An Espressif developer’ answer about a related question.

 

Making a Connection and Sending Read/Write Requests

 

As we said, first we need a connectable type of advertisement packets to make the Central ask the Peripheral to make a connection. We can see that advertisement packets type is ADV_TYPE_IND.

Let’s recall this table from the previous article.

“Getting Started with Bluetooth Low Energy” Book

 

Now, when a mobile (Central) connects to our device and specifically to the service of profile A. The connection parameters will be updated to new values making the timeout for the connection without any activity equal to 4000 ms. Look to this switch case inside gatts_profile_a_event_handler:

Now, after we connect we can read, write , or subscribe to notifications as the created characteristic in A and B has the following properties:

Let’s have a look at what read request will do. It will send a response containing dummy four bytes as described in the code:

 

Finally, The Example in Action

 

I used NRF Connect Android application to discover this example services and try reading and writing to it. Here are the images:

 

NRF Connect App ESP GATTS Demo ADVAdvertising under the name of “ESP_GATTS_DEMO”

 

NRF Connect App ESP GATTS Demo Services

Available services

 

NRF Connect App ESP GATTS Demo Read/writing request

Testing reading and writing to services

 

Conclusion

 

After our last article “Bluetooth Low Energy (BLE) 101 Tutorial: Intensive Introduction” and reading this technical article with explanations to most important parts of the “gatt_server” example from ESP-IDF SDK, you should now have a very basic idea of BLE concept and how to design a very simple BLE device starting from a ready demo like the one in this article. Although the ESP-IDF has made a very good walkthrough on Github, I found that it needs to be rewritten in a way more proper for a starter in BLE world.

In our next article, we will write a simple service to control the built-in LED of an ESP32 breakout board, starting from the same code of this example, but re-organized in a simpler and more straight-forward style.

 

Yahya Tawil

Embedded Hardware Engineer interested in open hardware and was born in the same year as Linux. Yahya is the editor-in-chief of Atadiat and believes in the importance of sharing free, practical, spam-free and high quality written content with others. His experience with Embedded Systems includes developing firmware with bare-metal C and Arduino, designing PCB&schematic and content creation.

2 Comments

  1. Excellent tutorials!! Please keep up the good work.
    Thank you very much for your time and effort.
    I subscribed to the mailing list awaiting new ESP32 tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.