Skip to content

ubluetooth: nimble fatal assert when using nimble hci controller #6269

Closed
@andrewleech

Description

@andrewleech

I'm in the process of adding support for using micropython on stm32 nimble bluetooth with a "generic" hci radio, where my radio for testing consists of a nRF52810 running zephyr hci radio firmware or mynewt nimble hci firmware.

Thankfully there aren't many changes needed for this to work, this will be all in a follow up PR once it's ready. I wanted to get this particular issue investigation documented while it's fresh for me.

Initial bring-up running on zephyr hci radio firmware went fairly smoothly.

Considering we're using nimble on micropython though, I feel it'd be preferable to also use nimble on the radio.
This didn't go quite as smoothly, I suspect it's exposed a small race-condition bug in the micropython/nimble bindings.

When running

import bluetooth
ble = bluetooth.BLE()
ble.active(True)

I get a

Assertion '0' failed, at file ../../lib/mynewt-nimble/nimble/host/src/ble_hs.c:434
FATAL ERROR:

Ref: https://github.com/apache/mynewt-nimble/blob/97ce3eacaaa79e8ed6cf71717149ced4f5328ee7/nimble/host/src/ble_hs.c#L431

This is caused by the nimble timer expired function ble_hs_timer_exp() being called while the stack is in startup.

Stepping through the startup code for nimble, the flow is basically:
mp_bluetooth_init() -> mp_bluetooth_nimble_port_start() -> ble_hs_start()

int ble_hs_sync(void) {
    /* Set the sync state to "bringup."  This allows the parent task to send
     * the startup sequence to the controller.  No other tasks are allowed to
     * send any commands.
     */
    ble_hs_sync_state = BLE_HS_SYNC_STATE_BRINGUP;

    rc = ble_hs_startup_go();
    if (rc == 0) {
        ble_hs_sync_state = BLE_HS_SYNC_STATE_GOOD;
    } else {
        ble_hs_sync_state = BLE_HS_SYNC_STATE_BAD;
    }
}

It's during ble_hs_startup_go() where the assert is thrown.

The ble_hs_timer_exp() function is actually called by an event run in os_eventq_run_all() in the micropython background nimble poll function:

void mp_bluetooth_hci_poll(void) {
    if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
        return;
    }

    mp_bluetooth_nimble_hci_uart_process();
    os_callout_process();
    os_eventq_run_all();
}

I've been able to fix the problem and get past the assert with this change.

void mp_bluetooth_hci_poll(void) {
if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
return;
}

mp_bluetooth_nimble_hci_uart_process();

if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE) {
    os_callout_process();
    os_eventq_run_all();
}

}

I'm not sure if this is correct, starting the background tasks only when the stack is marked active?

This gets me to the point of the BLE advertising correctly from examples, however I can't connect still - not sure if that's related or a different problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    extmodRelates to extmod/ directory in source

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions