-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Description
Answers checklist.
- I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
- I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
- I have searched the issue tracker for a similar issue and not found a similar issue.
General issue report
I've been working on a series of latency benchmarks for different wireless radios/stacks, and measured some odd behaviours from NimBLE when compared to Bluedroid for GATT/SPP style transfers.
These measurements are for one-way transfer latency - no ack/response behaviour is implemented or measured.
Is this behaviour reasonable/expected for the NimBLE + ESP32 stack? Any suggestions?
Comparing server notify and client WriteNoResp is also inconsistent between Bluedroid and NimBLE:
Reproduction Notes
Software
Code for esp32-spp
(classic), esp32-ble
, esp32-nimble
is on GitHub. These vary between minor changes from Espressif examples to heavier modifications to achieve feature parity.
The biggest difference from IDF examples: I've removed UART bridge behaviour, test payloads are handled directly on device.
Where test payloads exceed MTU, I manually send them as smaller MTU sized packets where the benchmark task requires some kind of library level event to signal the next packet i.e. BLE_GAP_EVENT_NOTIFY_TX
, similar to the approach used in Espressif throughput example.
I originally ran these tests with IDF 5.1.1
but can reproduce them with latest v5.3-dev-892-g692c1fcc52
which is ~3 days old.
docker run -i --privileged --rm -v $PWD:/project -w /project -it espressif/idf:latest
Other relevant changes with menuconfig:
- Change NimBLE internal logging to "Warning" to suppress extra terminal output (which affects results).
- Change compiler options to build for performance
-O2
Test Setup
- Two ESP32-WROOM-32 devkit boards, positioned on table 1m apart.
- Signal generator provides a 3.3V 50 μs square pulse at configurable interval (250 ms for all tests) as stimulus signal. Connected to IO19, handled via GPIO ISR.
- When trigger is flagged, and BT connection is already established, send test payload
- Receiving board rx event occurs, payload data is sent to user's benchmark task via FreeRTOS queue.
- Benchmark task checks payload for length and CRC, if valid, drives IO18 high to signal valid transmission.
- Saleae Logic 8 captures trigger and complete signals at 100 MS/s (10 ns resolution).
I've measured trigger-to-output overhead at ~4.11 μs when tested in a loopback configuration.
All firmware variants support both server notify and client writes, so swapping the trigger/valid signal connections allows testing client-server direction as needed.