[nRF54L15DK] hci_uart as external HCI controller for Channel Sounding — configuration validation and session drop issue

Summary :

We are using the nRF54L15DK as an external HCI controller (running the hci_uart sample from NCS v3.3.0) connected to a custom BLE host on a
separate MCU via HCI H4 UART. The host implements the Channel Sounding Reflector role. When a Pixel 10 (running Android native ranging via nRF
Toolbox) connects, pairing succeeds and CS procedures start, but the Android session eventually terminates with "Session disappeared. Try
reconnecting" (REASON_UNKNOWN). The same Pixel 10 paired against a standalone nRF54L15DK running the ras_reflector sample works correctly and
displays distance.

We want to:
1. Confirm our hci_uart configuration is correct for this use case.
2. Understand whether there are known limitations or additional settings required when the controller is driven by an external host over
HCI-UART for Channel Sounding.

---
Hardware

- nRF54L15DK (PCA10156) as the BLE controller
- Separate MCU as the BLE host, connected via HCI H4 UART
- Pixel 10 as the Channel Sounding initiator (via Android native ranging)

---
NCS Version

NCS v3.3.0

---
Build command

source ~/ncs/tmp/ncs_v33_activate.sh
cd ~/ncs/v3.3.0/zephyr/samples/bluetooth/hci_uart
west build -p -b nrf54l15dk/nrf54l15/cpuapp -- -DEXTRA_CONF_FILE="cs.conf"
west flash

---
Files used

1. Base config — samples/bluetooth/hci_uart/prj.conf (unmodified from the sample)
2. Extra CS overlay — samples/bluetooth/hci_uart/cs.conf (custom file placed in sample root):

CONFIG_BT_CTLR_CHANNEL_SOUNDING=y
CONFIG_BT_CTLR_SDC_CS_ROLE_BOTH=y
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_SDC_CS_MAX_ANTENNA_PATHS=2
CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS=1
CONFIG_BT_CTLR_SDC_CS_STEP_MODE3=n
CONFIG_BT_CTLR_DTM_HCI=y
CONFIG_BT_TRANSMIT_POWER_CONTROL=y
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_EVT_RX_COUNT=16
CONFIG_BT_BUF_EVT_RX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255

3. Board overlay — samples/bluetooth/hci_uart/boards/nrf54l15dk_nrf54l15_cpuapp.overlay (default from sample, unmodified):

&uart20 {
compatible = "nordic,nrf-uarte";
current-speed = <115200>;
status = "okay";
};

&uart20_default {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 11)>,
<NRF_PSEL(UART_RTS, 1, 14)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 1, 10)>,
<NRF_PSEL(UART_CTS, 1, 12)>;
bias-pull-up;
};
};

The external host is configured to match: UART baud 115200, hardware flow control enabled (RTS/CTS), H4 framing.

---
Observed behaviour

- nRF54L15DK (as HCI controller) enumerates correctly over HCI-UART; the host receives valid HCI events.
- Extended advertising works; the Pixel 10 connects and completes LE Secure Connections pairing.
- CS security (LE_CS_Security_Enable) completes successfully.
- CS configuration (LE_CS_Set_Default_Settings, LE_CS_Create_Config) is accepted by the controller.
- Reconnecting does not recover the session.
- Erasing flash and re-flashing the controller does not help.
- The identical Pixel 10 against the standalone ras_reflector sample on nRF54L15DK works flawlessly.

---
Questions

1. Is the above cs.conf configuration correct and sufficient to enable Channel Sounding support in hci_uart mode when driven by an external
host? Specifically:
- Are CONFIG_BT_CTLR_SDC_CS_MAX_ANTENNA_PATHS=2 and CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS=1 the right values to match the nRF54L15DK hardware
(single antenna, 2 paths) so that a Pixel 10 with 2 antennas can negotiate antenna config index 1?
- Is CONFIG_BT_CTLR_SDC_CS_ROLE_BOTH=y required, or is _ROLE_REFLECTOR sufficient?
2. Are there HCI buffer sizes (BT_BUF_EVT_RX_SIZE, BT_BUF_EVT_RX_COUNT, etc.) or other SDC Kconfig knobs specific to CS over hci_uart that
differ from the standalone ras_reflector build?
3. Are there any known issues with the SoftDevice Controller's CS subevent result HCI events being dropped or truncated when relayed over
HCI-UART to an external host, particularly for large step-result payloads?
4. Does the SoftDevice Controller require the external host to acknowledge RAS data (via GATT RAS characteristics) within a specific timeout,
failing which it terminates the CS session? If so, what is that timeout?

---
What we have already ruled out

- UART wiring: physical connection and hardware flow control are verified working (HCI commands and events exchange correctly).
- Controller capability: the standalone ras_reflector with the same board and Pixel 10 works, confirming the hardware supports CS with this
phone.
- Baud rate mismatch: both sides are at 115200 with flow control.

---
Reference

- Standalone reflector build that works: ncs/v3.3.0/nrf/samples/bluetooth/ras_reflector built with android_ranging.conf for
nrf54l15dk/nrf54l15/cpuapp.
- hci_uart sample location: ncs/v3.3.0/zephyr/samples/bluetooth/hci_uart.

  • Hi

    Just to make sure I understand you correctly, the Pixel 10 also connects to the nRF54L15 DK BLE controller to do the ranging, correct, and the BLE Host is a separate connection that is not included in the ranging in this setup? If that's right, my initial hunch is that the BLE controller is not configured to hold multiple connections at once and that's why the session disappears and disconnects. Can you please confirm whether that is the case? What is the CONFIG_BT_MAX_CONN set to in your application?

    I also see you use the hci_uart sample from the Zephyr branch, so can you confirm whether you use the SoftDevice controller or Zephyr Bluetooth controller? AFAIK the Android app is only tested with the SoftDevice controller.

    To your questions:

    1. I don't see any issues with the .conf you have uploaded. CONFIG_BT_CTLR_SDC_CS_ROLE_BOTH is not required, but shouldn't make a difference if you don't call the Initiator role in your application.
    2. No, I don't think so. Do you see anything pointing to this being due to HCI buffer sizes? Do you have any logging from the nRF54L15 to see what happens when the Android app reports that the session disappeared?
    3. I don't think this is related to the HCI specifically, rather to the device handling another connection while also trying to do a ranging session. You need to make sure that the nRF54L15 doesn't drop the ranging session to maintain the connection to the BLE host while it's ongoing.
    4. Not that I'm aware, but I need to look further into that and come back to you.

    Best regards,

    Simon

  • Hi Simon, thanks for the quick response. Let me clarify the topology and answer your two questions directly.

    Topology. There is only one over-the-air BLE connection here: the Pixel 10 (initiator) connects to the nRF54L15 acting as peripheral/reflector.
    The "BLE host" is not a second radio peer — it's our external MCU (running rxternal host with its own controller disabled), and it
    talks to the nRF54L15 purely as an HCI H4 controller over UART. So the nRF is not holding two connections at once; it has a single link to the
     phone, and the HCI-UART is just the host <--> controller transport. That means connection-count contention shouldn't apply.

    CONFIG_BT_MAX_CONN. On the controller build it's 16, with CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=1. The host maintains a single connection. So
    there's only ever one link to manage.

    Controller — what we're using, and a request for your recommendation. We're using the SoftDevice Controller: the merged build config has
    CONFIG_BT_LL_SOFTDEVICE=y (BUILD_TYPE_LIB, MULTIROLE), not the Zephyr LL. Our controller firmware is the zephyr/samples/bluetooth/hci_uart
    sample from NCS v3.3.0, built for nrf54l15dk/nrf54l15/cpuapp with our cs.conf overlay, exposed to the external host as HCI H4 over UART. 
    My question: is this the right controller and sample to use for driving Channel Sounding from an external HCI host, or would you recommend a
    different setup? For example, is the hci_uart (SoftDevice Controller) sample the intended/supported base for relaying CS to an external host, or
    is there another sample, controller build option, or SDC configuration you'd suggest for this use case? If our current approach is correct,
    please confirm; if there's a change you'd recommend, we'll adopt it.

    Following your note on ROLE_BOTH, we also changed cs.conf to match the proven ras_reflector as the phone sees it:
    CONFIG_BT_CTLR_SDC_CS_ROLE_REFLECTOR_ONLY=y (Roles_Supported = 0x02) and CONFIG_BT_CTLR_CHANNEL_SOUNDING_TEST=n. Behaviour is unchanged — the
    session still disappears.

    The one real difference: the transport. Our HCI-UART is currently 115200 8N1 with no hardware flow control (the nRF overlay sets
    current-speed=<115200> and does not set hw-flow-control; the host matches). Since CS emits a burst of subevent-result HCI events per procedure,
    our leading suspicion is that at 115200 with no RTS/CTS the controller outruns the UART — HCI events get queued/dropped, the host falls behind
    packing RAS ranging data to the phone, and Android sees the session stall (REASON_UNKNOWN). Two questions:
    1. Would you expect CS-over-HCI-UART to require a higher baud rate and hardware flow control? Is there a recommended minimum HCI-UART
    configuration for relaying CS subevent results to an external host?
    2. If the host is slow to read HCI events, does the SDC ever abort the CS procedure or the connection on its own, or does it just
    back-pressure/queue?

    Logging. The hci_uart build uses uart20 for HCI itself, so we'll capture the HCI H4 traffic on the host side (btmon/btsnoop) and/or sniff the
    UART line around the moment the phone reports the session gone, and share the last events before the drop.

    Thanks!

  • Hi

    Thank you for explaining, and my bad for the misunderstanding. The connection and Controller seems to be set up correctly from what I can see. AFAIK there haven't been much testing with channel sounding over HCI UART from our side yet, so I don't have much more than assumptions as of now. We're understaffed during the summer period, so I have not had time to do any testing on my end either, but the HCI UART baud rate theory sounds reasonable, so if you can I'd recommend trying to increase the baud rate.

    For the events, I think this depends on the buffer for the HCI UART. It should be queued for as long as there is room in the buffer at least.

    Best regards,

    Simon

  • Hi

    Thank you for explaining, and my bad for the misunderstanding. The connection and Controller seems to be set up correctly from what I can see. AFAIK there haven't been much testing with channel sounding over HCI UART from our side yet, so I don't have much more than assumptions as of now. We're understaffed during the summer period, so I have not had time to do any testing on my end either, and I'm still awaiting some feedback from the developers on the GATT RAS timeout question. But the HCI UART baud rate theory sounds reasonable, so if you can I'd recommend trying to increase the baud rate and test with some increased baud rates on your end. 

    For the events, I think this depends on the buffer for the HCI UART. It should be queued for as long as there is room in the buffer at least.

    Best regards,

    Simon

Related