stm32/mpbthciport: Change from systick to soft-timer for BT scheduling.
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>
This commit is contained in:
parent
60f1f76984
commit
74c2c31811
@ -54,6 +54,7 @@
|
||||
#endif
|
||||
|
||||
#include "boardctrl.h"
|
||||
#include "mpbthciport.h"
|
||||
#include "mpu.h"
|
||||
#include "rfcore.h"
|
||||
#include "systick.h"
|
||||
@ -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
|
||||
|
@ -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
|
||||
@ -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"
|
||||
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
42
ports/stm32/mpbthciport.h
Normal file
42
ports/stm32/mpbthciport.h
Normal file
@ -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
|
@ -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.
|
||||
@ -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) {
|
||||
|
@ -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.
|
||||
@ -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. -----------------
|
||||
|
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user