Skip to content

Commit 61d1e4b

Browse files
jimmodpgeorge
authored andcommitted
extmod/nimble: Make stm32 and unix NimBLE ports use synchronous events.
This changes stm32 from using PENDSV to run NimBLE to use the MicroPython scheduler instead. This allows Python BLE callbacks to be invoked directly (and therefore synchronously) rather than via the ringbuffer. The NimBLE UART HCI and event processing now happens in a scheduled task every 128ms. When RX IRQ idle events arrive, it will also schedule this task to improve latency. There is a similar change for the unix port where the background thread now queues the scheduled task. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent 81e92d3 commit 61d1e4b

File tree

15 files changed

+279
-156
lines changed

15 files changed

+279
-156
lines changed

extmod/modbluetooth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#endif
5151

5252
// This is used to protect the ringbuffer.
53+
// A port may no-op this if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS is enabled.
5354
#ifndef MICROPY_PY_BLUETOOTH_ENTER
5455
#define MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
5556
#define MICROPY_PY_BLUETOOTH_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state);

extmod/nimble/hal/hal_uart.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@
2828
#include "py/mphal.h"
2929
#include "nimble/ble.h"
3030
#include "extmod/nimble/hal/hal_uart.h"
31+
#include "extmod/nimble/nimble/nimble_npl_os.h"
3132
#include "extmod/mpbthci.h"
3233

3334
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
3435

36+
#define HCI_TRACE (0)
37+
3538
static hal_uart_tx_cb_t hal_uart_tx_cb;
3639
static void *hal_uart_tx_arg;
3740
static hal_uart_rx_cb_t hal_uart_rx_cb;
@@ -62,10 +65,10 @@ void hal_uart_start_tx(uint32_t port) {
6265
mp_bluetooth_hci_cmd_buf[len++] = data;
6366
}
6467

65-
#if 0
66-
printf("[% 8d] BTUTX: %02x", mp_hal_ticks_ms(), hci_cmd_buf[0]);
67-
for (int i = 1; i < len; ++i) {
68-
printf(":%02x", hci_cmd_buf[i]);
68+
#if HCI_TRACE
69+
printf("< [% 8d] %02x", mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]);
70+
for (size_t i = 1; i < len; ++i) {
71+
printf(":%02x", mp_bluetooth_hci_cmd_buf[i]);
6972
}
7073
printf("\n");
7174
#endif
@@ -77,13 +80,21 @@ int hal_uart_close(uint32_t port) {
7780
return 0; // success
7881
}
7982

80-
void mp_bluetooth_nimble_hci_uart_process(void) {
83+
void mp_bluetooth_nimble_hci_uart_process(bool run_events) {
8184
bool host_wake = mp_bluetooth_hci_controller_woken();
8285

8386
int chr;
8487
while ((chr = mp_bluetooth_hci_uart_readchar()) >= 0) {
85-
// printf("UART RX: %02x\n", data);
88+
#if HCI_TRACE
89+
printf("> %02x (%d)\n", chr);
90+
#endif
8691
hal_uart_rx_cb(hal_uart_rx_arg, chr);
92+
93+
// Incoming data may result in events being enqueued. If we're in
94+
// scheduler context then we can run those events immediately.
95+
if (run_events) {
96+
mp_bluetooth_nimble_os_eventq_run_all();
97+
}
8798
}
8899

89100
if (host_wake) {

extmod/nimble/hal/hal_uart.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ void hal_uart_start_tx(uint32_t port);
4343
int hal_uart_close(uint32_t port);
4444

4545
// --- Called by the MicroPython port when UART data is available -------------
46-
void mp_bluetooth_nimble_hci_uart_process(void);
46+
void mp_bluetooth_nimble_hci_uart_process(bool run_events);
4747

4848
#endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_HAL_HAL_UART_H

extmod/nimble/modbluetooth_nimble.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ int mp_bluetooth_init(void) {
382382
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC;
383383

384384
// Initialise NimBLE memory and data structures.
385+
DEBUG_printf("mp_bluetooth_init: nimble_port_init\n");
385386
nimble_port_init();
386387

387388
// Make sure that the HCI UART and event handling task is running.
@@ -402,6 +403,8 @@ int mp_bluetooth_init(void) {
402403
return MP_ETIMEDOUT;
403404
}
404405

406+
DEBUG_printf("mp_bluetooth_init: starting services\n");
407+
405408
// By default, just register the default gap/gatt service.
406409
ble_svc_gap_init();
407410
ble_svc_gatt_init();
@@ -417,7 +420,7 @@ int mp_bluetooth_init(void) {
417420
}
418421

419422
void mp_bluetooth_deinit(void) {
420-
DEBUG_printf("mp_bluetooth_deinit\n");
423+
DEBUG_printf("mp_bluetooth_deinit %d\n", mp_bluetooth_nimble_ble_state);
421424
if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
422425
return;
423426
}

extmod/nimble/nimble.mk

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ CFLAGS_MOD += -DMICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY=$(MICROPY_BLUETOOTH_NIMBL
1717

1818
ifeq ($(MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY),0)
1919

20+
# On all ports where we provide the full implementation (i.e. not just
21+
# bindings like on ESP32), then we don't need to use the ringbuffer. In this
22+
# case, all NimBLE events are run by the MicroPython scheduler. On Unix, the
23+
# scheduler is also responsible for polling the UART, whereas on STM32 the
24+
# UART is also polled by the RX IRQ.
25+
CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
26+
2027
NIMBLE_LIB_DIR = lib/mynewt-nimble
2128

2229
LIB_SRC_C += $(addprefix $(NIMBLE_LIB_DIR)/, \

0 commit comments

Comments
 (0)