Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 10 additions & 3 deletions extmod/zephyr_ble/hal/zephyr_ble_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
#include <stdint.h>
#include <stdbool.h>

#ifdef __ZEPHYR__
// Native Zephyr: use real kernel types
#include <zephyr/kernel.h>
#else

// Zephyr k_timer abstraction layer for MicroPython
// Uses polling-based timer mechanism (cooperative scheduling)

Expand Down Expand Up @@ -61,12 +66,14 @@ void k_timer_stop(struct k_timer *timer);
// Note: K_MSEC, K_NO_WAIT, K_FOREVER are defined in zephyr_ble_work.h
// Note: k_yield() is defined in zephyr_ble_kernel.h

// Called by MicroPython scheduler to process timer callbacks
void mp_bluetooth_zephyr_timer_process(void);

// Check if two timeouts are equal
static inline bool K_TIMEOUT_EQ(k_timeout_t a, k_timeout_t b) {
return a.ticks == b.ticks;
}

#endif // __ZEPHYR__

// Called by MicroPython scheduler to process timer callbacks
void mp_bluetooth_zephyr_timer_process(void);

#endif // MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_HAL_ZEPHYR_BLE_TIMER_H
105 changes: 102 additions & 3 deletions ports/rp2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ endif()
list(APPEND GIT_SUBMODULES lib/mbedtls)
list(APPEND GIT_SUBMODULES lib/tinyusb)

# Workaround for pico-sdk host toolchain issue, see directory for details
list(APPEND CMAKE_MODULE_PATH "${MICROPY_PORT_DIR}/tools_patch")

# Include component cmake fragments
include(${MICROPY_DIR}/py/py.cmake)
include(${MICROPY_DIR}/extmod/extmod.cmake)
Expand Down Expand Up @@ -259,6 +262,13 @@ elseif(PICO_RISCV)
)
endif()

# When a board variant explicitly disables threading, override mpconfigport.h default
if(DEFINED MICROPY_PY_THREAD AND NOT MICROPY_PY_THREAD)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_THREAD=0
)
endif()

# Use our custom pico_float_micropython float implementation. This is needed for two reasons:
# - to fix inf handling in pico-sdk's __wrap___aeabi_fadd();
# - so we can use our own libm functions, to fix inaccuracies in the pico-sdk versions.
Expand Down Expand Up @@ -325,25 +335,47 @@ if (MICROPY_PY_LWIP)
endif()

if(MICROPY_PY_BLUETOOTH)
# Add shared HCI infrastructure for all BLE stacks (BTstack, NimBLE, Zephyr)
# Provides common polling, scheduling, and controller interface (WEAK overrides)
list(APPEND MICROPY_SOURCE_PORT mpbthciport.c)

target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_BLUETOOTH=1
MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1
)
# Interlock requires threading support for mp_thread_get_state/set_state
if(NOT DEFINED MICROPY_PY_THREAD OR MICROPY_PY_THREAD)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK=1
MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE=2048
)
endif()
endif()

if (MICROPY_PY_BLUETOOTH_CYW43)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
CYW43_ENABLE_BLUETOOTH=1
MICROPY_PY_BLUETOOTH_CYW43=1
CYW43_INCLUDE_LEGACY_F1_OVERFLOW_WORKAROUND_VARIABLES=1
)

# Add CYW43 external pin support (needed for LED and other CYW43 GPIO pins)
list(APPEND MICROPY_SOURCE_PORT
machine_pin_cyw43.c
)

if (MICROPY_BLUETOOTH_BTSTACK)
# BTstack uses SPI/SDIO BT transport
target_link_libraries(${MICROPY_TARGET}
pico_btstack_hci_transport_cyw43
)
endif()

if (MICROPY_BLUETOOTH_ZEPHYR)
# Zephyr BLE uses CYW43 SPI btbus (same as BTstack)
# HCI transport files added in MICROPY_BLUETOOTH_ZEPHYR section above
endif()
endif()

if (MICROPY_BLUETOOTH_BTSTACK)
Expand Down Expand Up @@ -387,6 +419,53 @@ if(MICROPY_BLUETOOTH_NIMBLE)
list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE})
endif()

if(MICROPY_BLUETOOTH_ZEPHYR)
list(APPEND GIT_SUBMODULES lib/zephyr)
if(NOT UPDATE_SUBMODULES AND NOT EXISTS ${MICROPY_DIR}/lib/zephyr/subsys/bluetooth/host/hci_core.c)
message(FATAL_ERROR " zephyr not initialized.\n Run 'make BOARD=${MICROPY_BOARD} submodules'")
endif()

# CYW43 controller functions provided by pico-sdk via WEAK overrides
if (MICROPY_PY_NETWORK_CYW43)
list(APPEND MICROPY_SOURCE_PORT mpzephyrport_rp2.c) # Full CYW43 HCI transport
else()
list(APPEND MICROPY_SOURCE_PORT mpzephyrport_rp2_stub.c) # Minimal HCI stub
endif()

include(${MICROPY_DIR}/extmod/zephyr_ble/zephyr_ble.cmake)
target_link_libraries(${MICROPY_TARGET} micropy_extmod_zephyr_ble)

# Link CMSIS headers to Zephyr BLE (provides __enable_irq, __disable_irq, __ISB, __get_PRIMASK)
# These intrinsics are required by Zephyr's arch/arm/asm_inline_gcc.h
if(TARGET cmsis_core_headers)
target_link_libraries(micropy_extmod_zephyr_ble INTERFACE cmsis_core_headers)
endif()

# Define port-specific macro for cmsis_core.h stub header
target_compile_definitions(micropy_extmod_zephyr_ble INTERFACE __ZEPHYR_BLE_RP2_PORT__)

get_target_property(ZEPHYR_INCLUDE micropy_extmod_zephyr_ble INTERFACE_INCLUDE_DIRECTORIES)
list(APPEND MICROPY_INC_CORE ${ZEPHYR_INCLUDE})

# Add Zephyr BLE sources for QSTR/root pointer scanning
get_target_property(ZEPHYR_BLE_SOURCES micropy_extmod_zephyr_ble INTERFACE_SOURCES)
list(APPEND MICROPY_SOURCE_QSTR ${ZEPHYR_BLE_SOURCES})

target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_BLUETOOTH_ZEPHYR=1
MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
)

# MICROPY_PY_BLUETOOTH_USE_ZEPHYR_HCI calls mp_bluetooth_hci_controller_init()
# before bt_enable(). For CYW43, HCI transport is initialized via
# bt_hci_transport_setup() which is called by bt_enable().
if (NOT MICROPY_PY_NETWORK_CYW43)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_BLUETOOTH_USE_ZEPHYR_HCI=1
)
endif()
endif()

# tinyusb helper
target_include_directories(${MICROPY_TARGET} PRIVATE
${MICROPY_DIR}/shared/tinyusb/
Expand All @@ -408,15 +487,35 @@ if (MICROPY_PY_NETWORK_CYW43)
)
endif()

list(APPEND MICROPY_SOURCE_PORT
machine_pin_cyw43.c
)
# Override cyw43_malloc/free to use MicroPython's tracked allocator.
# This is critical because the pico-sdk's default uses C malloc which
# panics with "Out of memory" during BT firmware download.
# The compile definitions are set on cyw43_driver which is an INTERFACE
# library, so they propagate to all targets that link it.
if(TARGET cyw43_driver)
target_compile_definitions(cyw43_driver INTERFACE
cyw43_malloc=m_tracked_calloc_wrapper
cyw43_free=m_tracked_free
)
# Force-include header with function declarations for the above.
# Use generator expression to only apply to C files, not assembly.
target_compile_options(cyw43_driver INTERFACE
$<$<COMPILE_LANGUAGE:C>:-include${MICROPY_PORT_DIR}/cyw43_mp_malloc.h>
)
endif()

# Link CYW43 WiFi driver (for both BTstack and Zephyr BLE)
target_link_libraries(${MICROPY_TARGET}
cyw43_driver_picow
)

# Port dir must come before pico_cyw43_driver/include so MicroPython's
# cyw43_configport.h is found first (the pico-SDK version defines
# CYW43_THREAD_ENTER as a function call requiring cyw43_arch linkage).
target_include_directories(${MICROPY_TARGET} PRIVATE
"${MICROPY_PORT_DIR}"
${MICROPY_DIR}/lib/cyw43-driver/
${PICO_SDK_PATH}/src/rp2_common/pico_cyw43_driver/include
)

endif()
Expand Down
4 changes: 4 additions & 0 deletions ports/rp2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ ifdef MICROPY_C_HEAP_SIZE
CMAKE_ARGS += -DMICROPY_C_HEAP_SIZE=$(MICROPY_C_HEAP_SIZE)
endif

ifdef MICROPY_BLUETOOTH_ZEPHYR
CMAKE_ARGS += -DMICROPY_BLUETOOTH_ZEPHYR=1
endif

HELP_PICO_SDK_SUBMODULE ?= "\033[1;31mError: pico-sdk submodule is not initialized.\033[0m Run 'make submodules'"
HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m"

Expand Down
13 changes: 13 additions & 0 deletions ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,28 @@
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico2W"

// CYW43 driver configuration.
// Use #ifndef guards as pico-SDK also defines these
#ifndef CYW43_USE_SPI
#define CYW43_USE_SPI (1)
#endif
#ifndef CYW43_LWIP
#define CYW43_LWIP (1)
#endif
#ifndef CYW43_GPIO
#define CYW43_GPIO (1)
#endif
#ifndef CYW43_SPI_PIO
#define CYW43_SPI_PIO (1)
#endif

// For debugging mbedtls - also set
// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose
// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1

// BLE UART for CYW43 Bluetooth controller (UART0)
#define MICROPY_HW_BLE_UART_ID (0)
#define MICROPY_HW_BLE_UART_BAUDRATE (115200)

#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT

int mp_hal_is_pin_reserved(int n);
Expand Down
18 changes: 18 additions & 0 deletions ports/rp2/boards/RPI_PICO2_W/mpconfigvariant_zephyr_ble.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Zephyr BLE variant for Pico 2 W (cooperative polling, no FreeRTOS)
# Build with: make BOARD=RPI_PICO2_W BOARD_VARIANT=zephyr_ble

# RP2350 platform (normally set by the default mpconfigvariant.cmake)
set(PICO_PLATFORM "rp2350")

# Disable threading - use cooperative polling instead of FreeRTOS tasks
set(MICROPY_PY_THREAD OFF)

# Allocate 16KB C heap for GATT service/UUID allocations
set(MICROPY_C_HEAP_SIZE 16384)

# Override bluetooth stack selection
set(MICROPY_BLUETOOTH_BTSTACK OFF)
set(MICROPY_BLUETOOTH_ZEPHYR ON)

# Force fetch picotool from git (version mismatch workaround)
set(PICOTOOL_FORCE_FETCH_FROM_GIT ON)
16 changes: 16 additions & 0 deletions ports/rp2/boards/RPI_PICO_W/mpconfigvariant_zephyr_ble.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Zephyr BLE variant for Pico W (cooperative polling, no FreeRTOS)
# Build with: make BOARD=RPI_PICO_W BOARD_VARIANT=zephyr_ble
message(STATUS "Loading Zephyr BLE polling variant for Pico W")

# Disable threading - use cooperative polling instead of FreeRTOS tasks
set(MICROPY_PY_THREAD OFF)

# Allocate 16KB C heap for GATT service/UUID allocations
set(MICROPY_C_HEAP_SIZE 16384)

# Override bluetooth stack selection
set(MICROPY_BLUETOOTH_BTSTACK OFF)
set(MICROPY_BLUETOOTH_ZEPHYR ON)

# Force fetch picotool from git (version mismatch workaround)
set(PICOTOOL_FORCE_FETCH_FROM_GIT ON)
8 changes: 8 additions & 0 deletions ports/rp2/cyw43_btfw_43439_extern.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Stub header to declare BT firmware data as extern
// (actual definition is in cybt_shared_bus.c)
extern const unsigned char cyw43_btfw_43439[];
extern const unsigned int cyw43_btfw_43439_len;

// Alias names used in cyw43_bthci_uart.c
#define btfw_data cyw43_btfw_43439
#define btfw_len cyw43_btfw_43439_len
68 changes: 68 additions & 0 deletions ports/rp2/cyw43_bthci_uart_wrapper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2025 MicroPython Contributors
*
* 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.
*/

// Wrapper to include cyw43_bthci_uart.c with proper CYW43 BT configuration
//
// NOTE: The BT firmware data is defined in cybt_shared_bus.c (part of
// cyw43_driver_picow library). To avoid duplicate definitions, we declare
// the firmware data as extern here and skip including the firmware header.

// Include MicroPython HAL
#include "py/mphal.h"

// Force-define CYW43 BT UART transport before any CYW43 includes
#ifdef CYW43_ENABLE_BLUETOOTH_OVER_UART
#undef CYW43_ENABLE_BLUETOOTH_OVER_UART
#endif
#define CYW43_ENABLE_BLUETOOTH_OVER_UART 1

// Use stub firmware header that declares data as extern
#define CYW43_BT_FIRMWARE_INCLUDE_FILE "cyw43_btfw_43439_extern.h"

// Define MAC address index for BDADDR
#ifndef CYW43_HAL_MAC_BDADDR
#define CYW43_HAL_MAC_BDADDR MP_HAL_MAC_BDADDR
#endif

// Define other BT config that should come from cyw43_configport.h
#ifndef CYW43_PIN_BT_REG_ON
#define CYW43_PIN_BT_REG_ON (0)
#endif
#ifndef CYW43_PIN_BT_CTS
#define CYW43_PIN_BT_CTS (2)
#endif
#ifndef CYW43_PIN_BT_HOST_WAKE
#define CYW43_PIN_BT_HOST_WAKE (3)
#endif
#ifndef CYW43_PIN_BT_DEV_WAKE
#define CYW43_PIN_BT_DEV_WAKE (4)
#endif
#ifndef CYW43_HAL_UART_READCHAR_BLOCKING_WAIT
#define CYW43_HAL_UART_READCHAR_BLOCKING_WAIT mp_event_handle_nowait()
#endif

// Include the actual implementation
#include "../../lib/cyw43-driver/src/cyw43_bthci_uart.c"
Loading
Loading