Create a BLE Peripheral

Last update: June 29th, 2023

Introduction

Overview

In this first step, you'll learn how to use Espressif IoT Development Framework (ESP-IDF) to build a simple Bluetooth Low Energy peripheral. We will customize it to display a specific name and configure the Security Manager to enable bonding.

Configuring ESP-IDF

For convenience, we already cloned the esp-idf repository and installed ESP32 board support. The framework is located in the /home/cyberinsophia/esp/esp-idf directory.

On the Virtual Machine, open a terminal and use the cd command to change the working directory to ~/esp/esp-idf:

cyberinsophia@vm:~$ cd esp/esp-idf
cyberinsophia@vm:~/esp/esp-idf$ ls
add_path.sh      export.ps1    README_CN.md
CMakeLists.txt   export.sh     README.md
components       install.bat   sdkconfig.rename
conftest.py      install.fish  SECURITY.md
CONTRIBUTING.md  install.ps1   sonar-project.properties
docs             install.sh    SUPPORT_POLICY_CN.md
examples         Kconfig       SUPPORT_POLICY.md
export.bat       LICENSE       tools
export.fish      pytest.ini
Then, you need to run the following command to configure the environment:
cyberinsophia@vm:~/esp/esp-idf$ . ./export.sh
  Setting IDF_PATH to '/home/cyberinsophia/esp/esp-idf'
  Detecting the Python interpreter
  Checking "python3" ...
  Python 3.10.6
  "python3" has been detected
  Checking Python compatibility
  Checking other ESP-IDF version.
  Adding ESP-IDF tools to PATH...
  Checking if Python packages are up to date...
  Constraint file: /home/cyberinsophia/.espressif/espidf.constraints.v5.2.txt
  Requirement files:
   - /home/cyberinsophia/esp/esp-idf/tools/requirements/requirements.core.txt
  Python being checked: /home/cyberinsophia/.espressif/python_env/idf5.2_py3.10_env/bin/python
  /home/cyberinsophia/esp/esp-idf/tools/check_python_dependencies.py:12: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
    import pkg_resources
  Python requirements are satisfied.
  Added the following directories to PATH:
    /home/cyberinsophia/esp/esp-idf/components/espcoredump
    /home/cyberinsophia/esp/esp-idf/components/partition_table
    /home/cyberinsophia/esp/esp-idf/components/app_update
    /home/cyberinsophia/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin
    /home/cyberinsophia/.espressif/tools/xtensa-esp32-elf/esp-12.2.0_20230208/xtensa-esp32-elf/bin
    /home/cyberinsophia/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin
    /home/cyberinsophia/.espressif/tools/openocd-esp32/v0.12.0-esp32-20230419/openocd-esp32/bin
    /home/cyberinsophia/.espressif/python_env/idf5.2_py3.10_env/bin
    /home/cyberinsophia/esp/esp-idf/tools
  Done! You can now compile ESP-IDF projects.
  Go to the project directory and run:

    idf.py build
  
If everything went fine, you should now be able to use the idf.py command:

cyberinsophia@vm:~/esp/esp-idf$ idf.py
/home/cyberinsophia/esp/esp-idf/tools/check_python_dependencies.py:12: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  import pkg_resources
Usage: idf.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
              [ARGS]...]...

  ESP-IDF CLI build management tool. For commands that are
  not known to idf.py an attempt to execute it as a build
  system target will be made. Selected target: None
  [...]
This command is the ESP-IDF CLI build management tool, used to create and configure a new project, compile it, flash it on the ESP32 development kit and monitor the serial output. We will use it intensively during this lab !

Using NimBLE peripheral example

NimBLE bleprph example

In ~/esp/esp-idf/examples, you'll find a large set of examples provided by Espressif Systems to illustrate how to use ESP32. In our case, we want to use an example from NimBLE, one of the two Bluetooth stack that can be embedded on the ESP32. NimBLE is an open-source Bluetooth Low Energy stack, providing both Host and Controller implementations (in the ESP32 case, the Controller is implemented in a proprietary hardware, so NimBLE will only provide the Host component of the stack). We will use the example named bleprph, which simulates a simple Bluetooth Low Energy peripheral.

This example is located in ~/esp/esp-idf/examples/bluetooth/nimble/bleprph. Copy it in your home directory using cp command:

cyberinsophia@vm:~$ cp -r ~/esp/esp-idf/examples/bluetooth/nimble/bleprph/ ~/bleprph

Then, go to the folder and run idf.py to configure ESP32 as the target board:

cyberinsophia@vm:~$ cd ~/bleprph
cyberinsophia@vm:~$ idf.py set-target esp32

Modifying device name

By default, the BLE peripheral use the name "nimble-bleprph". To facilitate the identification of your device, you will change the source code located in main/main.c to use an unique name.

Open the main.c, identify the function used to configure the BLE peripheral and modify the function call to use an unique name instead.

Display solution

Enabling bonding

Now, we need to configure the example to enable bonding. We can configure this by running idf.py menuconfig command. If everything works fine, you should observe the following menu:

Navigate to Example configuration item, then select Use bonding:

It will configure the Security Manager and allow your BLE device to perform a bonding operation and to transmit the Long Term Key (LTK). Type S to save your modifications and exit the utility using ESC key.

Compile the modified example

Once these modifications have been done, you are now ready to compile the example. To do so, run idf.py build.

cyberinsophia@vm:~/esp/esp-idf/examples/bluetooth/nimble/bleprph$ idf.py build
/home/cyberinsophia/esp/esp-idf/tools/check_python_dependencies.py:12: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  import pkg_resources
Executing action: all (aliases: build)
Running cmake in directory /home/cyberinsophia/esp/esp-idf/examples/bluetooth/nimble/bleprph/build
Executing "cmake -G Ninja -DPYTHON_DEPS_CHECKED=1 -DPYTHON=/home/cyberinsophia/.espressif/python_env/idf5.2_py3.10_env/bin/python -DESP_PLATFORM=1 -DCCACHE_ENABLE=0 /home/cyberinsophia/esp/esp-idf/examples/bluetooth/nimble/bleprph"...
-- IDF_TARGET not set, using default target: esp32
-- Found Git: /usr/bin/git (found version "2.34.1")
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /home/cyberinsophia/.espressif/tools/xtensa-esp32-elf/esp-12.2.0_20230208/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
[...]
If everything works, you should observe an output similar to:

Creating esp32 image...
Merged 25 ELF sections
Successfully created esp32 image.
Generated /home/cyberinsophia/esp/esp-idf/examples/bluetooth/nimble/bleprph/build/bleprph.bin
[995/995] cd /home/cyberinsop...ble/bleprph/build/bleprph.bin
bleprph.bin binary size 0x941e0 bytes. Smallest app partition is 0x100000 bytes. 0x6be20 bytes (42%) free.

Project build complete. To flash, run:
 idf.py flash
or
 idf.py -p PORT flash
or
 python -m esptool --chip esp32 -b 460800 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 2MB --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/bleprph.bin
or from the "/home/cyberinsophia/esp/esp-idf/examples/bluetooth/nimble/bleprph/build" directory
 python -m esptool --chip esp32 -b 460800 --before default_reset --after hard_reset write_flash @flash_args
Indicating that a build directory has been created, including the ESP32 binary image. You are now ready to flash this image on your ESP32 board.

Flash the modified example

If needed, plug the ESP32 board and enable the corresponding USB device in VirtualBox (Devices > USB > Silicon Labs CP210x USB to UART bridge). Then, flash the image using idf.py flash utility. A typical output indicating a successful flashing will look like this:

Congratulations, you managed to compile and flash your first ESP32 project ! Your ESP32 device should now transmit advertisements. You can monitor the output generated on the serial port using idf.py monitor.