Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bc3dab8
extmod/zephyr_ble: Add on-core controller support to HAL shims.
pi-anl Feb 22, 2026
afef405
extmod/zephyr_ble: Add controller build system and config.
pi-anl Feb 22, 2026
a6c1090
nrf: Add SysTick, soft timer, and PendSV dispatch.
pi-anl Feb 22, 2026
1c95ca3
nrf: Add Zephyr BLE build integration and board variants.
pi-anl Mar 3, 2026
ec90fd3
nrf: Add Zephyr BLE port integration and controller polling.
pi-anl Mar 4, 2026
17710db
extmod/zephyr_ble: Replace SUSPENDED deinit with bt_disable [nrf].
pi-anl Mar 4, 2026
4484b38
extmod/zephyr_ble: Interleave work processing between HCI events [nrf].
pi-anl Mar 4, 2026
a40f98e
extmod/zephyr_ble: Remove last two Zephyr submodule patches.
pi-anl Mar 3, 2026
522e49e
nrf: Add L2CAP flush, re-entrancy guard, and LLL preempt fix.
pi-anl Mar 12, 2026
879d6c8
nrf: Use shared poll interval define and enable DLE.
pi-anl Mar 13, 2026
1e1e21f
nrf: Remove redundant DLE config from board variants.
pi-anl Apr 19, 2026
9be0165
nrf: Add L2CAP flush to port_run_task.
pi-anl Apr 19, 2026
324041b
unix: Add Zephyr BLE variant with HCI socket transport.
pi-anl Mar 26, 2026
d24d0a2
unix: Fix soft timer, L2CAP defaults, and BLE variant issues.
pi-anl Mar 26, 2026
ebe3a20
stm32: Add Zephyr BLE HCI driver and IPCC integration.
pi-anl Mar 6, 2026
aeefee1
stm32: Add Zephyr BLE build variant for PYBD_SF6.
pi-anl Mar 3, 2026
04b24e3
stm32: Fix mp_handle_pending signature and add L2CAP flush.
pi-anl Mar 12, 2026
180905e
stm32: Use shared poll interval define and enable DLE.
pi-anl Mar 13, 2026
57914ec
stm32: Use IPCC flag for ACL flow control in rfcore.
pi-anl Mar 14, 2026
1bf7a95
stm32: Remove redundant DLE config from board variant.
pi-anl Apr 19, 2026
bc161f6
stm32: Add L2CAP poll_now flush to port_run_task.
pi-anl Apr 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions extmod/btstack/btstack.mk
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ INC += -I$(TOP)/$(BTSTACK_EXTMOD_DIR)
CFLAGS_EXTMOD += -DMICROPY_BLUETOOTH_BTSTACK=1
CFLAGS_EXTMOD += -DMICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE=$(MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE)
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
# Pairing/bonding and L2CAP channels are enabled by default in modbluetooth.h.
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1

BTSTACK_DIR = $(TOP)/lib/btstack
Expand Down
10 changes: 6 additions & 4 deletions extmod/modbluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (0)
#endif

// A port can optionally enable support for L2CAP "Connection Oriented Channels".
// Enable support for L2CAP "Connection Oriented Channels".
// All BLE stacks support this -- enabled by default.
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (0)
#define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (1)
#endif

// A port can optionally enable support for pairing and bonding.
// Enable support for pairing and bonding.
// Requires MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS.
// All BLE stacks support this -- enabled by default.
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (0)
#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (1)
#endif

// Optionally enable support for the `hci_cmd` function allowing
Expand Down
5 changes: 2 additions & 3 deletions extmod/nimble/nimble.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ GIT_SUBMODULES += lib/mynewt-nimble
# UART is also polled by the RX IRQ.
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1

# Without the ringbuffer, and with the full implementation, we can also
# enable pairing and bonding. This requires both synchronous events and
# some customisation of the key store.
# Pairing/bonding and L2CAP channels are enabled by default in modbluetooth.h.
# Explicit -D flags kept for clarity in build logs.
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1

NIMBLE_LIB_DIR = lib/mynewt-nimble
Expand Down
17 changes: 16 additions & 1 deletion extmod/zephyr_ble/hal/zephyr_ble_atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,16 +283,31 @@ static inline void *atomic_ptr_clear(atomic_ptr_t *target) {

typedef unsigned int irq_lock_key_t;

// Lock IRQs and return key
// Lock IRQs and return key.
// When the controller runs on-core, ISRs access shared data structures so
// irq_lock must actually disable hardware interrupts via PRIMASK.
// For host-only builds (CYW43, IPCC) the no-op MICROPY_PY_BLUETOOTH_ENTER
// is sufficient since there are no local BLE ISRs.
static inline irq_lock_key_t irq_lock(void) {
#if MICROPY_BLUETOOTH_ZEPHYR_CONTROLLER && (defined(__arm__) || defined(__thumb__))
unsigned int key;
__asm volatile ("mrs %0, primask" : "=r" (key));
__asm volatile ("cpsid i" ::: "memory");
return key;
#else
MICROPY_PY_BLUETOOTH_ENTER
return atomic_state;
#endif
}

// Unlock IRQs with key
static inline void irq_unlock(irq_lock_key_t key) {
#if MICROPY_BLUETOOTH_ZEPHYR_CONTROLLER && (defined(__arm__) || defined(__thumb__))
__asm volatile ("msr primask, %0" :: "r" (key) : "memory");
#else
uint32_t atomic_state = key;
MICROPY_PY_BLUETOOTH_EXIT
#endif
}

#endif // MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_HAL_ZEPHYR_BLE_ATOMIC_H
149 changes: 149 additions & 0 deletions extmod/zephyr_ble/hal/zephyr_ble_clock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* SPDX-License-Identifier: Apache-2.0
*
* nRF52840 clock control for Zephyr BLE controller without full Zephyr OS.
*
* Replaces Zephyr's lll_clock.c which depends on the onoff_manager and
* nrf_clock_control driver. We drive the nRF52840 HFXO and LFXO directly
* via hardware registers.
*/

#include <stdint.h>
#include <stdbool.h>
#include <errno.h>

#if MICROPY_BLUETOOTH_ZEPHYR_CONTROLLER

#include <nrf.h>

#include "hal/debug.h"

// SCA (Sleep Clock Accuracy) lookup table — PPM values for each SCA index
// SCA 0 = 500ppm, SCA 7 = 20ppm (BT Core Spec Vol 6, Part B, 4.2.2)
static uint16_t const sca_ppm_lut[] = {500, 250, 150, 100, 75, 50, 30, 20};

static atomic_t hf_refcnt;

// nRF52840 DK uses a 32.768 kHz LFXO with ±20ppm accuracy (SCA 7)
// This may need to be made configurable per-board.
#ifndef CLOCK_CONTROL_NRF_K32SRC_ACCURACY
#define CLOCK_CONTROL_NRF_K32SRC_ACCURACY 7
#endif

int lll_clock_init(void)
{
// The BLE controller requires LFXO (external 32.768kHz crystal) for
// accurate radio timing. The nRF port's mp_nrf_start_lfclk() may have
// already started LFCLK with the default source (LFRC internal RC,
// ±2% = 20000ppm uncalibrated). If so, stop and restart with LFXO.
// The SCA config claims 20ppm accuracy which is only valid for LFXO.

bool running = (NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk) != 0;
bool is_xtal = (NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_SRC_Msk) ==
(CLOCK_LFCLKSTAT_SRC_Xtal << CLOCK_LFCLKSTAT_SRC_Pos);

if (running && is_xtal) {
return 0; // Already running on LFXO
}

if (running) {
// Running on LFRC — must stop before changing source
NRF_CLOCK->TASKS_LFCLKSTOP = 1;
// Per nRF52840 PS v1.1 §6.4.4: wait for clock to stop
while (NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk) {
}
}

// Select LFXO as source and start
NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;

return 0;
}

int lll_clock_deinit(void)
{
// Don't stop LFCLK — it's shared with other subsystems (RTC)
return 0;
}

int lll_clock_wait(void)
{
// Wait for LFXO to be running and stable.
// Cannot use a static "done" flag because lll_clock_init() may have
// restarted LFCLK with LFXO after the nRF port started it on LFRC.
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
__WFE();
}

return 0;
}

int lll_hfclock_on(void)
{
if (__atomic_fetch_add(&hf_refcnt, 1, __ATOMIC_SEQ_CST) > 0) {
return 0;
}

NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
DEBUG_RADIO_XTAL(1);

return 0;
}

int lll_hfclock_on_wait(void)
{
__atomic_fetch_add(&hf_refcnt, 1, __ATOMIC_SEQ_CST);

NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;

while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
__WFE();
}

DEBUG_RADIO_XTAL(1);

return 0;
}

int lll_hfclock_off(void)
{
int prev = __atomic_fetch_add(&hf_refcnt, -1, __ATOMIC_SEQ_CST);

if (prev < 1) {
// Correct the underflow
__atomic_fetch_add(&hf_refcnt, 1, __ATOMIC_SEQ_CST);
return -EALREADY;
}

if (prev > 1) {
return 0;
}

NRF_CLOCK->TASKS_HFCLKSTOP = 1;
DEBUG_RADIO_XTAL(0);

return 0;
}

uint8_t lll_clock_sca_local_get(void)
{
return CLOCK_CONTROL_NRF_K32SRC_ACCURACY;
}

uint32_t lll_clock_ppm_local_get(void)
{
return sca_ppm_lut[CLOCK_CONTROL_NRF_K32SRC_ACCURACY];
}

uint32_t lll_clock_ppm_get(uint8_t sca)
{
return sca_ppm_lut[sca];
}

#endif // MICROPY_BLUETOOTH_ZEPHYR_CONTROLLER
Loading
Loading