Chapter 265: Bluetooth 5.0 Features on Newer Variants

Chapter Objectives

By the end of this chapter, you will be able to:

  • Distinguish between the capabilities of Bluetooth 4.x and the enhancements introduced in Bluetooth 5.0 for IoT applications.
  • Understand and explain the three core features of Bluetooth 5.0 LE: 2M PHY (high speed), Coded PHY (long range), and Advertising Extensions.
  • Identify which ESP32 variants support these advanced Bluetooth 5.0 features.
  • Configure the ESP-IDF Bluedroid stack to utilize these new PHYs and advertising methods.
  • Implement code to establish a long-range Bluetooth LE connection.
  • Appreciate the trade-offs between speed, range, and power consumption.

Introduction

In previous volumes, we explored the fundamentals of Bluetooth Low Energy (BLE) as it existed in the original ESP32. That implementation, based on the Bluetooth 4.2 specification, was revolutionary for short-range, low-power connectivity. However, the rapidly growing demands of the Internet of Things (IoT) pushed the boundaries of what was possible, calling for greater speed, longer range, and more efficient data broadcasting.

The Bluetooth 5.0 specification was a direct answer to this call. It didn’t replace the core of BLE but rather introduced powerful new physical layer (PHY) options and a completely revamped advertising mechanism. These enhancements transform BLE from a purely personal-area network technology into a robust solution for smart home, industrial, and asset-tracking applications.

This chapter delves into these Bluetooth 5.0 features, which are exclusively available on newer ESP32 variants like the ESP32-S3, ESP32-C3, and ESP32-C6. We will explore the theory behind each feature and implement a practical example to see them in action.

Theory

The Bluetooth 5.0 specification introduced several major enhancements to the Low Energy radio. We will focus on the three most impactful for IoT: the LE 2M PHY, the LE Coded PHY, and Advertising Extensions.

1. LE 2M PHY: The High-Speed Option

The original BLE standard (1M PHY) transmitted data at a symbol rate of 1 million symbols per second, which translates to a theoretical maximum data rate of 1 Mbps.

The LE 2M PHY doubles this symbol rate to 2 million symbols per second, effectively doubling the potential throughput to 2 Mbps.

  • How it Works: It achieves this higher speed without using more complex modulation. It simply transmits the symbols twice as fast.
  • Primary Use Case: Applications requiring faster data transfer, such as OTA firmware updates, streaming sensor data, or transferring audio over BLE.
  • The Trade-off: Physics dictates that to transmit faster with the same power, you sacrifice range. The 2M PHY has a noticeably shorter range compared to the standard 1M PHY.

Analogy: Think of the different PHYs as ways of speaking. The 1M PHY is speaking at a normal pace. The 2M PHY is like speaking very quickly. You can convey information faster, but the listener needs to be closer and in a quieter environment to understand you clearly.

2. LE Coded PHY: The Long-Range Option

This is perhaps the most significant feature for many IoT applications. The LE Coded PHY is designed to dramatically increase the reliable range of a BLE connection, potentially up to 4x that of the standard 1M PHY.

  • How it Works: It achieves this remarkable range not by increasing transmitter power, but by adding redundancy to the data. It uses a technique called Forward Error Correction (FEC). Each bit of data is encoded into multiple symbols on the air. The receiver can then use this redundant information to reconstruct the original data even if some of the signal was lost or corrupted by noise.
  • Primary Use Case: Smart agriculture sensors in a field, asset tracking in a large warehouse, smart home devices spread across a large property.
  • The Trade-off: The cost of this range is speed. Because each data bit is represented by multiple symbols, the effective data rate is significantly lower (either 500 Kbps or 125 Kbps, depending on the coding scheme used). This also means the radio is active for longer to transmit the same amount of data, increasing overall power consumption per bit.

Analogy: Continuing our analogy, the Coded PHY is like speaking very slowly and clearly in a loud, crowded room, repeating each word to ensure the listener can piece together the message even with all the background noise.

%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%%
graph TD
    subgraph Bluetooth 5.0 PHY Options

    direction TB

    A(<b>1M PHY</b><br><i>Baseline</i><br>1 Mbps Symbol Rate)

    A --> B{<b>2M PHY</b><br><i>Speak Faster</i><br>2 Mbps Symbol Rate}
    A --> C{<b>Coded PHY</b><br><i>Speak Slower & Repeat</i><br>500/125 kbps Data Rate}

    B -- "<b>Higher Speed</b><br><i>(e.g., OTA Updates)</i>" --> B_OUT((✔))
    B -- "<b>Shorter Range</b>" --> B_OUT_NEG((❌))

    C -- "<b>Lower Speed</b>" --> C_OUT_NEG((❌))
    C -- "<b>Longer Range</b><br><i>(e.g., Asset Tracking)</i>" --> C_OUT((✔))

    end

    classDef default fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF
    classDef startNode fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6
    classDef successNode fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46
    classDef failNode fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,color:#991B1B

    class A startNode
    class B,C default
    class B_OUT,C_OUT successNode
    class B_OUT_NEG,C_OUT_NEG failNode

3. Advertising Extensions

Legacy BLE advertising (from Bluetooth 4.x) was very limited. It used only 3 channels for discovery and had a maximum payload of just 31 bytes. In crowded environments, this led to congestion and limited the amount of data a device could broadcast without a connection.

Advertising Extensions overhaul this system completely.

  • Off-Channel Advertising: The initial advertisement on the primary channels (37, 38, 39) is now just a small pointer. This pointer directs a scanning device to a secondary advertising packet sent on one of the 37 data channels. This dramatically reduces congestion on the primary discovery channels.
  • Larger Payloads: By moving the main advertisement to data channels, the payload size is increased from 31 bytes to 255 bytes per packet.
  • Chained Packets: For even larger advertisements, multiple packets can be “chained” together, allowing for a theoretical maximum payload of up to 1650 bytes.

Primary Use Case: Broadcasting richer data in a connectionless state. This is ideal for advanced beacons (e.g., Eddystone, iBeacon) that can now send more information, or for broadcasting sensor data without requiring devices to connect.

%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%%
graph TD
    subgraph Advertising Extensions: From 31 to 1650 Bytes
        A(Start Advertising) --> B{"Primary Channels<br><b>(37, 38, 39)</b>"};
        B --> C["<b>ADV_EXT_IND</b> Packet<br>A small pointer packet"];
        C --> D{"Secondary Channel<br><b>(One of 37 Data Channels)</b>"};
        D --> E["<b>AUX_ADV_IND</b> Packet<br>Contains the main payload<br>Up to 255 bytes"];
        E --> F{More Data?};
        F -- Yes --> G["<b>AUX_CHAIN_IND</b><br>Points to the next<br>chained packet"];
        G --> E;
        F -- No --> H(End of Advertisement);
    end

    classDef startNode fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6;
    classDef processNode fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF;
    classDef decisionNode fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E;
    classDef endNode fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46;

    class A startNode;
    class B,C,D,E,G processNode;
    class F decisionNode;
    class H endNode;

Variant Notes

Support for Bluetooth 5.0 features is highly dependent on the ESP32 variant. It is crucial to select the right chip for your application’s requirements.

  • Original ESP32: Not Supported. Its radio hardware is compliant with Bluetooth 4.2. It has a 1M PHY only and does not support Coded PHY, 2M PHY, or Advertising Extensions.
  • ESP32-S2: Not Supported. This variant does not have a Bluetooth radio. Its focus is on USB-OTG and low-power WiFi.
  • ESP32-C3 / ESP32-S3: Fully Supported. These chips integrate a Bluetooth 5.0 LE compliant radio. They support 2M PHY, Coded PHY, Advertising Extensions, and other BT5 features. They are the ideal choice for new BLE designs.
  • ESP32-C6: Fully Supported & More. The ESP32-C6 supports all Bluetooth 5.0 features and is compliant with the newer Bluetooth 5.3 specification, which adds further enhancements not covered in this chapter.
  • ESP32-H2: Fully Supported.
Variant Bluetooth LE Version 2M PHY (High Speed) Coded PHY (Long Range) Advertising Extensions
Original ESP32 4.2
ESP32-S2 N/A (No BT Radio) N/A N/A N/A
ESP32-C3 5.0
ESP32-S3 5.0
ESP32-C6 5.3
ESP32-H2 5.0

Practical Example: Long-Range (Coded PHY) GATT Server

Let’s build an application for an ESP32-S3 that acts as a GATT server and advertises its preference for a long-range connection. When a client connects, the two devices will attempt to negotiate and switch to the Coded PHY.

Prerequisites: You will need two supported boards (e.g., two ESP32-S3 DevKits) to act as the server and client. For this example, we will only show the server code. The standard gatt_client example can be used on the second board to connect.

1. Project Setup and Configuration

  1. Start with the gatt_server_service_table example from the ESP-IDF examples.
  2. Set your target to a supported chip: idf.py set-target esp32s3
  3. Open the configuration editor: idf.py menuconfig
    • Navigate to Component config -> Bluetooth -> Bluedroid Options.
    • Ensure that BLE 5.0 new feature support is enabled. This is usually on by default for supported targets.

2. Writing the Application Code (main.c)

We only need to make small modifications to the standard GATT server example. The key is to use the esp_ble_gap_set_prefer_phys function after a connection is established.

%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%%
sequenceDiagram
    actor Client
    participant Server as ESP32-S3 GATT Server
    
    Server->>Server: Starts advertising (on 1M PHY)
    
    activate Server
    Client->>Server: Scans and finds Server
    Client->>Server: Requests connection
    deactivate Server
    
    activate Server
    Server->>Client: Connection established (on 1M PHY)
    Note over Server: Receives ESP_GAP_BLE_CONNECT_EVT
    
    Server->>Server: Calls esp_ble_gap_set_prefer_phys() <br> requesting Coded PHY
    Note over Server: Prefers TX: Coded, RX: Coded
    
    Server-->>Client: PHY Update Request
    activate Client
    
    Note over Client: Client receives request,<br>agrees to Coded PHY
    Client-->>Server: PHY Update Response (Accept)
    deactivate Client
    
    Server->>Server: Receives ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT <br> (status: success, phy: Coded)
    Note over Server,Client: Connection is now on Long-Range Coded PHY
    deactivate Server

C
// This is not a complete file. It shows only the modifications to the
// gatt_server_service_table example. Find the `gap_event_handler` function.

// ... other includes and definitions from the example ...
#include "esp_bt_main.h"
#include "esp_bt_defs.h"

// ...

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
    // ... case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT and other cases ...

    case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
         ESP_LOGI(GATTS_TABLE_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
                  param->update_conn_params.status,
                  param->update_conn_params.min_int,
                  param->update_conn_params.max_int,
                  param->update_conn_params.conn_int,
                  param->update_conn_params.latency,
                  param->update_conn_params.timeout);
        break;
    
    // THIS IS THE NEW PART WE ARE ADDING
    case ESP_GAP_BLE_CONNECT_EVT:
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_CONNECT_EVT, conn_id %d", param->connect.conn_id);
        // Log the connection parameters
        esp_log_buffer_hex(GATTS_TABLE_TAG, param->connect.remote_bda, 6);
        
        // After connection, set our preferred PHYs for this connection.
        // We prefer Coded PHY for both TX and RX.
        ESP_LOGI(GATTS_TABLE_TAG, "Setting preferred PHY to LE Coded");
        esp_ble_gap_set_prefer_phys(param->connect.remote_bda, ESP_BLE_GAP_PHY_BIT_CODED, ESP_BLE_GAP_PHY_BIT_CODED, ESP_BLE_GAP_PHY_OPTIONS_NO_PREF);
        break;
    
    // THIS EVENT TELLS US IF THE PHY UPDATE WAS SUCCESSFUL
    case ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT:
        ESP_LOGI(GATTS_TABLE_TAG, "PHY update complete, status = %d, TX_PHY = %d, RX_PHY = %d", 
                 param->phy_update.status, 
                 param->phy_update.tx_phy, 
                 param->phy_update.rx_phy);
        break;

    default:
        break;
    }
}

// ... the rest of the file remains the same ...

3. Build, Flash, and Observe

  1. Build and flash this modified GATT server code onto your first ESP32-S3 board.
  2. Build and flash the unmodified gatt_client example onto your second ESP32-S3 board.
  3. Open serial monitors for both boards.
  4. Once the server starts advertising, the client should automatically scan and connect.
  5. Observe the log output on the server’s monitor. You should see:
    • The ESP_GAP_BLE_CONNECT_EVT event, followed by our log “Setting preferred PHY to LE Coded”.
    • Shortly after, the ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT event. If successful, TX_PHY and RX_PHY will be 3, which corresponds to ESP_BLE_GAP_PHY_CODED.

Common Mistakes & Troubleshooting Tips

Mistake / Issue Symptom(s) Troubleshooting / Solution
PHY Update Fails The ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT event arrives, but the status field is not ESP_GATT_OK. The PHY remains 1M. Check Remote Device: The most common cause is that the client device does not support the requested PHY.
  • Ensure both devices are Bluetooth 5.0 capable (e.g., two ESP32-S3s).
  • You cannot force a BT 4.2 device (like the original ESP32) to use a Coded or 2M PHY.
No Noticeable Range Increase The Coded PHY connection is established successfully, but the connection seems just as unstable as the 1M PHY at long distances. Test at the Edge: The benefits of Coded PHY are most apparent at the edge of the normal 1M range.
  • Move the devices far enough apart that a standard 1M connection is unstable or fails completely.
  • Re-test with the Coded PHY at that same distance. You should now see a stable, reliable connection.
Using BT5 Functions on Original ESP32 The project compiles without errors, but at runtime, the call to esp_ble_gap_set_prefer_phys() returns an ESP_ERR_NOT_SUPPORTED error in the logs. Check Hardware Variant: These features are hardware-dependent.
  • Consult the Variant Support Table.
  • The function calls exist in the ESP-IDF for all targets, but will only execute successfully on compatible hardware (ESP32-S3, C3, C6, etc.).
Extended Advertising Fails to Start Calling esp_ble_gap_ext_adv_start() returns an error, or the device is not visible to scanners. Check Parameters: Extended advertising has more complex parameter setup.
  • Ensure you are using esp_ble_gap_ext_adv_set_params() and have configured at least one advertising set.
  • Verify that the advertising data length does not exceed the per-packet limit (251 bytes) or that you have configured chaining correctly.

Exercises

  1. Test 2M PHY: Modify the GATT server example to request the 2M PHY instead of the Coded PHY. Use ESP_BLE_GAP_PHY_BIT_2M in the esp_ble_gap_set_prefer_phys call. Connect with a client and verify that the PHY updates to 2.
  2. Extended Advertising: Modify the gatt_server example to use extended advertising. This involves using esp_ble_gap_ext_adv_set_params() and esp_ble_gap_ext_adv_start() instead of the legacy functions. Create an advertising payload that is larger than 31 bytes to confirm it is working.
  3. Asymmetric PHYs: The esp_ble_gap_set_prefer_phys function allows you to set different PHYs for transmitting (TX) and receiving (RX). Configure a connection where the server transmits on Coded PHY (for robust commands) but receives on 2M PHY (for high-speed data uploads from the client).

Summary

  • Bluetooth 5.0 introduces critical features for modern IoT applications, available on newer ESP32 variants like the C3, S3, and C6.
  • 2M PHY doubles the data rate at the cost of range, ideal for fast data transfers.
  • Coded PHY uses Forward Error Correction to dramatically increase range (up to 4x) at the cost of data rate, perfect for long-distance sensing and control.
  • Advertising Extensions relieve congestion and allow for much larger broadcast payloads by using data channels.
  • You can negotiate the PHY to use for a connection after the connection has been established using the esp_ble_gap_set_prefer_phys() function.
  • Selecting the right PHY involves a direct trade-off between range, speed, and power consumption.

Further Reading

Leave a Comment

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

Scroll to Top