Fast notifications with nRF5340 and nRF Connect SDK

Board: nRF5340dk

SDK version: v2.1.0

My goal is to transmit 240 bytes of data every 5 ms using GATT notifications and 1 Mb PHY.

In the attached sample, I have my dev kit set up to notify on a characteristic every 5 ms. The connection interval is set to 10 ms, the MTU to 247 bytes, and the data length to 251 bytes. My thought is to fit 240 bytes into a single PDU, and send 2 notification packets per connection interval. I also toggle GPIO P0.04 before and after calling `bt_gatt_notify_cb`.

Looking at a logic analyzer trace of P0.04, I can see that while this setup initially works, eventually `bt_gatt_notify_cb` starts blocking for longer than expected. This happens around 14.5 seconds into the attached capture.

Wireshark capture also attached.

Why is `bt_gatt_notify_cb` blocking this long, and do you have any suggestions to improve the setup?

fast_notifications.zip

  • Hi Edvin.

    To quote the nRF Connect SDK documentation:

    "The SoftDevice Controller is implemented by Nordic Semiconductor. The Zephyr Bluetooth LE Controller is an open source Link Layer developed in Zephyr, to which Nordic Semiconductor is a contributor.

    Both Link Layers integrate with the Zephyr Bluetooth Host, which completes the full Bluetooth LE protocol stack solution in the nRF Connect SDK. It is possible to select either Bluetooth LE Controller for application development. See Usage in samples for more information."

    So with both controllers the Zephyr Bluetooth Host is used, the code for this host is contained in the 'zephyr-ncs\subsys\bluetooth\host' directory. And there bt_gatt_notify_cb() is implemented in gatt.c and calls indirectly conn_tx_alloc() from conn.c in the same directory.

    For me it is unclear why you cannot see this call stack in your tests. You mention the function bt_gatt_notify_cb() from "ncs\nrf\subsys\bluetooth\rpc\client\bt_rpc_gatt_client.c", but I don't think this is part of the Zephyr Bluetooth Host.

    Regards,

    Benno

  • Is it possible that you build your test code with CONFIG_BT_RPC=y "Bluetooth over RPC [EXPERIMENTAL]"?

    In this case I see inclusion of code from the "ncs\nrf\subsys\bluetooth\rpc' directory. My project does not set CONFIG_BT_RPC!

  • For testing, I used the peripheral_uart sample found in ncs\nrf\samples\bluetooth\peripheral_uart. 

    According to my build folders, CONFIG_BT_RPC is not set. I didn't find any mentions of it in the autoconf.h, but searching for it in my build folder, these were all the hits:

    BR,
    Edvin

  • Hi Edvin.

    In this case your stack configuration should be the same as mine. But then it is unclear to my why your code calls the bt_gatt_notify_cb() from bt_rpc_gatt_client.c and not from gatt.c.

    Can you verify in zephyr.map from where bt_gatt_notify_cb() is really linked?

    In my zephyr.map I see:

    .text.bt_gatt_notify_cb
                    0x000478d0       0xe8 zephyr/subsys/bluetooth/host/libsubsys__bluetooth__host.a(gatt.c.obj)
                    0x000478d0                bt_gatt_notify_cb

  • Hello,

    Actually, it points to the same place. I just navigated using VS Code, and there it pointed to ncs\nrf\subsys\bluetooth\rpc\client\bt_rpc_gatt_client.c. I should have checked the .map file.

    I believe the reason I couldn't reproduce it was that I just tried to call bt_nus_send() (bt_gatt_notify_cb()) directly from my main() function. I discussed this with a colleague, who recently had a similar case, which I think you should check out:

     bt_gatt_notify() can block when running on Zephyr workqueue. 

    It turns out that it is the workqueue itself locking up. SInce the bt_gatt_notify_cb() is queued by the workqueue, but the workqueue is also required to actually process your BLE queue, you can end up in a deadlock. I guess the takeaway is that you should call bt_gatt_notify from another thread, so where you actually are calling bt_gatt_notify_cb() from now, you should rather trigger a task in another thread, (either the main thread, or a completely separate thread), so that it doesn't end up in a deadlock.

    As it is now, this is currently a limitation in the Zephyr Bluetooth Host stack.

    Best regards,

    Edvin

Related