Skip to content

Commit

Permalink
stm32/mpbthciport: Change from systick to soft-timer for BT scheduling.
Browse files Browse the repository at this point in the history
Instead of using systick the BT subsystem is now scheduled using a soft
timer.  This means it is scheduled only when it is enabled.

Signed-off-by: Damien George <damien@micropython.org>
  • Loading branch information
dpgeorge committed Jun 23, 2021
1 parent 60f1f76 commit 74c2c31
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 39 deletions.
4 changes: 2 additions & 2 deletions ports/stm32/main.c
Expand Up @@ -54,6 +54,7 @@
#endif

#include "boardctrl.h"
#include "mpbthciport.h"
#include "mpu.h"
#include "rfcore.h"
#include "systick.h"
Expand Down Expand Up @@ -440,8 +441,7 @@ void stm32_main(uint32_t reset_mode) {
systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
#endif
#if MICROPY_PY_BLUETOOTH
extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
systick_enable_dispatch(SYSTICK_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_systick);
mp_bluetooth_hci_init();
#endif

#if MICROPY_PY_NETWORK_CYW43
Expand Down
85 changes: 53 additions & 32 deletions ports/stm32/mpbthciport.c
Expand Up @@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2018-2020 Damien P. George
* Copyright (c) 2018-2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -28,7 +28,8 @@
#include "py/mphal.h"
#include "extmod/mpbthci.h"
#include "extmod/modbluetooth.h"
#include "systick.h"
#include "mpbthciport.h"
#include "softtimer.h"
#include "pendsv.h"
#include "lib/utils/mpirq.h"

Expand All @@ -38,22 +39,48 @@

uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];

// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
// Request new data from the uart and pass to the stack, and run pending events/callouts.
extern void mp_bluetooth_hci_poll(void);
// Soft timer for scheduling a HCI poll.
STATIC soft_timer_entry_t mp_bluetooth_hci_soft_timer;

// Hook for pendsv poller to run this periodically every 128ms
#define BLUETOOTH_HCI_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
// Prevent double-enqueuing of the scheduled task.
STATIC volatile bool events_task_is_scheduled;
#endif

// This is called by soft_timer and executes at IRQ_PRI_PENDSV.
STATIC void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) {
mp_bluetooth_hci_poll_now();
}

void mp_bluetooth_hci_init(void) {
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
events_task_is_scheduled = false;
#endif
soft_timer_static_init(
&mp_bluetooth_hci_soft_timer,
SOFT_TIMER_MODE_ONE_SHOT,
0,
mp_bluetooth_hci_soft_timer_callback
);
}

STATIC void mp_bluetooth_hci_start_polling(void) {
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
events_task_is_scheduled = false;
#endif
mp_bluetooth_hci_poll_now();
}

void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms);
}

#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS

// For synchronous mode, we run all BLE stack code inside a scheduled task.
// This task is scheduled periodically (every 128ms) via SysTick, or
// This task is scheduled periodically via a soft timer, or
// immediately on HCI UART RXIDLE.

// Prevent double-enqueuing of the scheduled task.
STATIC volatile bool events_task_is_scheduled = false;

STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
(void)none_in;
events_task_is_scheduled = false;
Expand All @@ -65,23 +92,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_sched

// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to
// request that processing happens ASAP in the scheduler.
void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
if (events_task_is_scheduled) {
return;
}

if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
void mp_bluetooth_hci_poll_now(void) {
if (!events_task_is_scheduled) {
events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
if (!events_task_is_scheduled) {
// The schedule queue is full, set callback to try again soon.
mp_bluetooth_hci_poll_in_ms(5);
}
}
}

#else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS

// Called periodically (systick) or directly (e.g. uart irq).
void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
}
void mp_bluetooth_hci_poll_now(void) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
}

#endif
Expand All @@ -104,14 +128,13 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {

DEBUG_printf("mp_bluetooth_hci_uart_init (stm32 rfcore)\n");

#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
events_task_is_scheduled = false;
#endif

rfcore_ble_init();
hci_uart_rx_buf_cur = 0;
hci_uart_rx_buf_len = 0;

// Start the HCI polling to process any initial events/packets.
mp_bluetooth_hci_start_polling();

return 0;
}

Expand Down Expand Up @@ -163,7 +186,6 @@ int mp_bluetooth_hci_uart_readchar(void) {
/******************************************************************************/
// HCI over UART

#include "pendsv.h"
#include "uart.h"

pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
Expand All @@ -173,7 +195,7 @@ static uint8_t hci_uart_rxbuf[768];

mp_obj_t mp_uart_interrupt(mp_obj_t self_in) {
// Queue up the scheduler to run the HCI UART and event processing ASAP.
mp_bluetooth_hci_systick(0);
mp_bluetooth_hci_poll_now();

return mp_const_none;
}
Expand All @@ -182,10 +204,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt);
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
DEBUG_printf("mp_bluetooth_hci_uart_init (stm32)\n");

#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
events_task_is_scheduled = false;
#endif

// bits (8), stop (1), parity (none) and flow (rts/cts) are assumed to match MYNEWT_VAL_BLE_HCI_UART_ constants in syscfg.h.
mp_bluetooth_hci_uart_obj.base.type = &pyb_uart_type;
mp_bluetooth_hci_uart_obj.uart_id = port;
Expand All @@ -208,6 +226,9 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
mp_bluetooth_hci_uart_irq_obj.ishard = true;
uart_irq_config(&mp_bluetooth_hci_uart_obj, true);

// Start the HCI polling to process any initial events/packets.
mp_bluetooth_hci_start_polling();

return 0;
}

Expand Down
42 changes: 42 additions & 0 deletions ports/stm32/mpbthciport.h
@@ -0,0 +1,42 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
#define MICROPY_INCLUDED_STM32_MPBTHCIPORT_H

// Initialise the HCI subsystem (should be called once, early on).
void mp_bluetooth_hci_init(void);

// Poll the HCI now, or after a certain timeout.
void mp_bluetooth_hci_poll_now(void);
void mp_bluetooth_hci_poll_in_ms(uint32_t ms);

// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
// Request new data from the uart and pass to the stack, and run pending events/callouts.
// This is a low-level function and should not be called directly, use
// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead.
void mp_bluetooth_hci_poll(void);

#endif // MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
5 changes: 5 additions & 0 deletions ports/stm32/mpbtstackport.c
Expand Up @@ -38,6 +38,7 @@
#include "extmod/mpbthci.h"
#include "extmod/btstack/btstack_hci_uart.h"
#include "extmod/btstack/modbluetooth_btstack.h"
#include "mpbthciport.h"

// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
// following three functions are empty.
Expand Down Expand Up @@ -75,6 +76,10 @@ void mp_bluetooth_hci_poll(void) {

// Call the BTstack run loop.
btstack_run_loop_embedded_execute_once();

// Call this function again in 128ms to check for new events.
// TODO: improve this by only calling back when needed.
mp_bluetooth_hci_poll_in_ms(128);
}

void mp_bluetooth_btstack_port_init(void) {
Expand Down
7 changes: 7 additions & 0 deletions ports/stm32/mpnimbleport.c
Expand Up @@ -40,6 +40,7 @@
#include "extmod/modbluetooth.h"
#include "extmod/nimble/modbluetooth_nimble.h"
#include "extmod/nimble/hal/hal_uart.h"
#include "mpbthciport.h"

// Get any pending data from the UART and send it to NimBLE's HCI buffers.
// Any further processing by NimBLE will be run via its event queue.
Expand All @@ -56,6 +57,12 @@ void mp_bluetooth_hci_poll(void) {
// Run any remaining events (e.g. if there was no UART data).
mp_bluetooth_nimble_os_eventq_run_all();
}

if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
// Call this function again in 128ms to check for new events.
// TODO: improve this by only calling back when needed.
mp_bluetooth_hci_poll_in_ms(128);
}
}

// --- Port-specific helpers for the generic NimBLE bindings. -----------------
Expand Down
4 changes: 2 additions & 2 deletions ports/stm32/rfcore.c
Expand Up @@ -32,6 +32,7 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "extmod/modbluetooth.h"
#include "mpbthciport.h"
#include "rtc.h"
#include "rfcore.h"

Expand Down Expand Up @@ -714,8 +715,7 @@ void IPCC_C1_RX_IRQHandler(void) {

#if MICROPY_PY_BLUETOOTH
// Queue up the scheduler to process UART data and run events.
extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
mp_bluetooth_hci_systick(0);
mp_bluetooth_hci_poll_now();
#endif
}

Expand Down
3 changes: 0 additions & 3 deletions ports/stm32/systick.h
Expand Up @@ -37,9 +37,6 @@ enum {
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
SYSTICK_DISPATCH_LWIP,
#endif
#if MICROPY_PY_BLUETOOTH
SYSTICK_DISPATCH_BLUETOOTH_HCI,
#endif
SYSTICK_DISPATCH_MAX
};

Expand Down

0 comments on commit 74c2c31

Please sign in to comment.