Skip to content
Closed
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
7 changes: 7 additions & 0 deletions .github/actions/deps/ports/zephyr-cp/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ runs:
run: west zephyr-export
shell: bash
working-directory: ports/zephyr-cp
- name: Fetch cyw43-driver submodule
# The CYW43 shared-bus Bluetooth transport needs the georgerobotics
# cyw43-driver headers and the BT controller patchram, which live in a
# submodule of hal_rpi_pico that west does not check out.
run: git -C modules/hal/rpi_pico submodule update --init --depth 1 lib/cyw43-driver
shell: bash
working-directory: ports/zephyr-cp
- name: Install Zephyr protobuf dependency
run: pip install protobuf==6.33.5
shell: bash
19 changes: 18 additions & 1 deletion .github/workflows/build-board-custom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ jobs:
PORT=$(python tools/board_to_port.py "${{ inputs.board }}")
echo "port=$PORT" >> $GITHUB_OUTPUT
shell: bash
- name: Build extensions
id: build-extensions
run: |
EXT=$(python tools/board_build_extensions.py "${{ inputs.board }}")
echo "extensions=$EXT" >> $GITHUB_OUTPUT
shell: bash
- name: Set up port
id: set-up-port
uses: ./.github/actions/deps/ports
Expand Down Expand Up @@ -121,7 +127,18 @@ jobs:
BOARD: ${{ inputs.board }}
FLAGS: ${{ inputs.flags }}
DEBUG: ${{ inputs.debug && '1' || '0' }}
run: make -j$(nproc) $FLAGS BOARD="$BOARD" DEBUG=$DEBUG TRANSLATION="$TRANSLATION"
BUILD: build-${{ inputs.board }}
EXTENSIONS: ${{ steps.build-extensions.outputs.extensions }}
run: |
# Name the firmware.<ext> targets explicitly rather than relying on the
# default goal. The zephyr-cp port's default goal is the Zephyr ELF, so
# the firmware.* copies the artifact upload expects are never made.
ARTIFACTS=""
for ext in $EXTENSIONS; do
ARTIFACTS="$ARTIFACTS $BUILD/firmware.$ext"
done
make -j4 $FLAGS BOARD="$BOARD" BUILD="$BUILD" DEBUG=$DEBUG \
TRANSLATION="$TRANSLATION" $ARTIFACTS
working-directory: ports/${{ steps.board-to-port.outputs.port }}
- name: Upload artifact
uses: actions/upload-artifact@v7
Expand Down
5 changes: 4 additions & 1 deletion ports/zephyr-cp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ else
CP_BOARD_CONF := $(DEBUG_CONF_FILE)
endif
endif
# Quoted: with DEBUG=1 this is a ;-separated list, and an unquoted ; ends the
# shell command, so west built without debug.conf and the shell then tried to
# run debug.conf as a program.
ifneq ($(CP_BOARD_CONF),)
WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(CP_BOARD_CONF)
WEST_CMAKE_ARGS += "-Dzephyr-cp_EXTRA_CONF_FILE=$(CP_BOARD_CONF)"
endif

.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all sim clean-sim test fetch-port-submodules
Expand Down
7 changes: 7 additions & 0 deletions ports/zephyr-cp/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include "py/runtime.h"
#include "supervisor/port.h"

#if CIRCUITPY_BLEIO
#include "common-hal/_bleio/__init__.h"
#endif

#include <zephyr/kernel.h>

void port_start_background_tick(void) {
Expand All @@ -26,4 +30,7 @@ void port_background_task(void) {
#if defined(CONFIG_ARCH_POSIX)
k_busy_wait(100);
#endif
#if CIRCUITPY_BLEIO
bleio_background();
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "Raspberry Pi Foundation Raspberry Pi Pico 2"

[modules]
__future__ = true
_bleio = false
_bleio = true # Zephyr board has _bleio
_eve = false
_pew = false
_pixelmap = false
Expand Down
74 changes: 74 additions & 0 deletions ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_SOCKETS=y

# TCP. Nothing in the port or the SoC defaults turns it on, so until now every
# SOCK_STREAM socket on these boards failed inside net_context_get() with
# EPROTOTYPE -- surfaced by socketpool as "Out of sockets" -- which also means
# the web workflow's listener never opened. HTTP(S) clients and servers need it.
CONFIG_NET_TCP=y

CONFIG_WIFI=y
CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n
CONFIG_NET_L2_WIFI_MGMT=y
Expand All @@ -18,3 +24,71 @@ CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y
CONFIG_MBEDTLS_ENTROPY_C=y
CONFIG_MBEDTLS_CTR_DRBG_C=y

# The collector's captive portal serves HTTPS from a PEM certificate chain
# (fullchain.pem / key.pem via ssl.SSLContext.load_cert_chain); mbedTLS only
# parses DER unless PEM decoding is compiled in.
CONFIG_MBEDTLS_PEM_PARSE_C=y

# TLS 1.2 ECDHE. Zephyr's mbedTLS 4 default serves secp256r1 through the p256-m
# PSA driver and leaves the builtin ECP module out. mbedTLS then defines a dummy
# MBEDTLS_ECP_MAX_BITS of 1, and ssl.h sizes the TLS 1.2 premaster buffer
# (union mbedtls_ssl_premaster_secret._pms_ecdh[MBEDTLS_ECP_MAX_BYTES]) from
# it, so every ECDHE key agreement fails with PSA_ERROR_BUFFER_TOO_SMALL -- a
# 1-byte buffer for a 32-byte shared secret -- and surfaces as OSError 138 on
# the first read of any TLS connection, client or server. Keep the builtin
# ECP module (p256-m off) until the header sizes that buffer from PSA.
CONFIG_MBEDTLS_PSA_P256M_DRIVER_ENABLED=n

# SoftAP. wifi.radio.start_ap() drives the AIROC driver's ap_enable through
# wifi_mgmt (the driver already implements it; this only enables the pieces
# around it). The DHCPv4 server hands joining stations addresses from a pool
# just above the AP's own -- 192.168.4.1 by default, as on ESP32 -- and tells
# them the AP is their DNS server and (RFC 8910 option 114) captive portal, so
# a portal served from CircuitPython is found by phones and laptops without
# the user typing an address.
CONFIG_NET_DHCPV4_SERVER=y
CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT=8
CONFIG_NET_DHCPV4_SERVER_OPTION_DNS_ADDRESS="192.168.4.1"
CONFIG_NET_DHCPV4_SERVER_OPTION_CAPTIVE_PORTAL=y

# Bluetooth over the shared gSPI bus (CONFIG_BT itself comes from the
# zephyr,bt-hci chosen node in the overlay).
#
# The WHD WiFi, cybt BT and coexistence call chains are deeper than the
# defaults in ../prj.conf; the Cortex-M33 MPU catches an overflow cleanly
# instead of silently corrupting neighbouring stacks.
CONFIG_HW_STACK_PROTECTION=y
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096

# The CYW43439's BT controller firmware (CYW4343A2_001.003.016.0065.0000) does
# not implement the Bluetooth 5 extended advertising/scanning commands: it
# rejects LE Set Extended Scan Parameters (0x2041) with status 0x01 "Unknown
# HCI Command", so scanning fails with -EIO. The port defaults BT_EXT_ADV on,
# so turn it off here to make the host use the legacy 0x200B/0x200C scan and
# legacy advertising commands instead.
CONFIG_BT_EXT_ADV=n

# Sockets. Every Zephyr socket -- a listener, each accepted client, each UDP
# socket -- takes one net_context, and the default pool is 6. A CircuitPython
# program serving HTTP over the station link to a browser that opens several
# connections per page, with NTP and a captive/mDNS UDP socket beside it, sits
# at that ceiling, and the 6th socket() or accept() fails with ENOMEM. A
# net_context is ~150 bytes; the RP2350 has the RAM, so double the pool and
# the connection-handler table that goes with it (NET_MAX_CONN, default 8).
CONFIG_NET_MAX_CONTEXTS=12
CONFIG_NET_MAX_CONN=16

# File descriptors. Zephyr sizes the fd table from the subsystems' declared
# needs (ZVFS_OPEN_ADD_SIZE_*), which came to 4 here; the DHCPv4 server takes
# one socket plus the socket-service eventfd, leaving a program two, and
# socketpool.socket() then fails with "Out of sockets" at the first TLS
# listener. Give sockets a real ceiling (each fd entry is ~12 bytes).
CONFIG_ZVFS_OPEN_MAX=16

# Zephyr defaults BT_MAX_CONN to 1, which would limit the hub to a single
# peer and force a connectionless (advertisement-only) node protocol. The
# CYW43439 controller is not the constraint; raise it so nodes can connect
# and sync data. Costs RAM per connection.
CONFIG_BT_MAX_CONN=4

Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@
code_partition: partition@0 {
compatible = "zephyr,mapped-partition";
label = "code-partition";
reg = <0x0 0x17f000>;
reg = <0x0 0x17e000>;
read-only;
};

storage_partition: partition@17f000 {
/*
* The settings partition backs Bluetooth bond keys via NVS, so it
* must be erase-sector aligned and hold at least two of the
* RP2350's 4K sectors: nvs_mount() rejects a single sector with
* -EINVAL, which makes bt_enable() fail before ever opening the HCI
* driver and surfaces as a bare OSError from "import _bleio".
*
* nvm and circuitpy must stay where ports/raspberrypi puts them
* (cptools/check_partitions.py enforces this), so the second sector
* comes out of the code partition, not out of the CIRCUITPY drive.
*/
storage_partition: partition@17e000 {
compatible = "zephyr,mapped-partition";
label = "storage";
reg = <0x17f000 0x1000>;
reg = <0x17e000 0x2000>;
};

nvm_partition: partition@180000 {
Expand All @@ -30,4 +41,25 @@
};
};

/*
* Bluetooth. The CYW43439's HCI is not on a UART here — it shares the WiFi
* gSPI bus — so hang the shared-bus HCI transport off the board's stock
* infineon,airoc-wifi node and point the host at it. CONFIG_BT then turns
* itself on via the zephyr,bt-hci chosen (see ../../../Kconfig).
*/
&pio0_spi0 {
airoc-wifi@0 {
cyw43_bt_hci: cyw43_bt_hci {
compatible = "infineon,cyw43-bt-hci";
status = "okay";
};
};
};

/ {
chosen {
zephyr,bt-hci = &cyw43_bt_hci;
};
};

#include "../../../app.overlay"
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "Raspberry Pi Foundation Raspberry Pi Pico"

[modules]
__future__ = true
_bleio = false
_bleio = true # Zephyr board has _bleio
_eve = false
_pew = false
_pixelmap = false
Expand Down
49 changes: 49 additions & 0 deletions ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_SOCKETS=y

# TCP. Nothing in the port or the SoC defaults turns it on, so until now every
# SOCK_STREAM socket on these boards failed inside net_context_get() with
# EPROTOTYPE -- surfaced by socketpool as "Out of sockets" -- which also means
# the web workflow's listener never opened. HTTP(S) clients and servers need it.
CONFIG_NET_TCP=y

CONFIG_WIFI=y
CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n
CONFIG_NET_L2_WIFI_MGMT=y
Expand All @@ -19,4 +25,47 @@ CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y
CONFIG_MBEDTLS_ENTROPY_C=y
CONFIG_MBEDTLS_CTR_DRBG_C=y

# The collector's captive portal serves HTTPS from a PEM certificate chain
# (fullchain.pem / key.pem via ssl.SSLContext.load_cert_chain); mbedTLS only
# parses DER unless PEM decoding is compiled in.
CONFIG_MBEDTLS_PEM_PARSE_C=y

# TLS 1.2 ECDHE. Zephyr's mbedTLS 4 default serves secp256r1 through the p256-m
# PSA driver and leaves the builtin ECP module out. mbedTLS then defines a dummy
# MBEDTLS_ECP_MAX_BITS of 1, and ssl.h sizes the TLS 1.2 premaster buffer
# (union mbedtls_ssl_premaster_secret._pms_ecdh[MBEDTLS_ECP_MAX_BYTES]) from
# it, so every ECDHE key agreement fails with PSA_ERROR_BUFFER_TOO_SMALL -- a
# 1-byte buffer for a 32-byte shared secret -- and surfaces as OSError 138 on
# the first read of any TLS connection, client or server. Keep the builtin
# ECP module (p256-m off) until the header sizes that buffer from PSA.
CONFIG_MBEDTLS_PSA_P256M_DRIVER_ENABLED=n

# File descriptors. Zephyr sizes the fd table from the subsystems' declared
# needs (ZVFS_OPEN_ADD_SIZE_*), which came to 4 here; the DHCPv4 server takes
# one socket plus the socket-service eventfd, leaving a program two, and
# socketpool.socket() then fails with "Out of sockets" at the first TLS
# listener. Give sockets a real ceiling (each fd entry is ~12 bytes).
CONFIG_ZVFS_OPEN_MAX=16

# SoftAP. wifi.radio.start_ap() drives the AIROC driver's ap_enable through
# wifi_mgmt (the driver already implements it; this only enables the pieces
# around it). The DHCPv4 server hands joining stations addresses from a pool
# just above the AP's own -- 192.168.4.1 by default, as on ESP32 -- and tells
# them the AP is their DNS server and (RFC 8910 option 114) captive portal, so
# a portal served from CircuitPython is found by phones and laptops without
# the user typing an address.
CONFIG_NET_DHCPV4_SERVER=y
CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT=8
CONFIG_NET_DHCPV4_SERVER_OPTION_DNS_ADDRESS="192.168.4.1"
CONFIG_NET_DHCPV4_SERVER_OPTION_CAPTIVE_PORTAL=y

CONFIG_TEST_RANDOM_GENERATOR=y

# Bluetooth over the shared gSPI bus (CONFIG_BT itself comes from the
# zephyr,bt-hci chosen node in the overlay).
#
# The CYW43439's BT controller firmware does not implement the Bluetooth 5
# extended advertising/scanning commands, and the port defaults BT_EXT_ADV on,
# so turn it off here and let the host use the legacy 0x200B/0x200C commands.
CONFIG_BT_EXT_ADV=n
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
38 changes: 35 additions & 3 deletions ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,25 @@
code_partition: partition@100 {
compatible = "zephyr,mapped-partition";
label = "code-partition";
reg = <0x100 (0x17f000 - 0x100)>;
reg = <0x100 (0x17e000 - 0x100)>;
read-only;
};

storage_partition: partition@17f000 {
/*
* The settings partition backs Bluetooth bond keys via NVS, so it
* must be erase-sector aligned and hold at least two of the
* RP2040's 4K sectors: nvs_mount() rejects a single sector with
* -EINVAL, which makes bt_enable() fail before ever opening the HCI
* driver and surfaces as a bare OSError from "import _bleio".
*
* nvm and circuitpy must stay where ports/raspberrypi puts them
* (cptools/check_partitions.py enforces this), so the second sector
* comes out of the code partition, not out of the CIRCUITPY drive.
*/
storage_partition: partition@17e000 {
compatible = "zephyr,mapped-partition";
label = "storage";
reg = <0x17f000 0x1000>;
reg = <0x17e000 0x2000>;
};

nvm_partition: partition@180000 {
Expand All @@ -41,4 +52,25 @@
};
};

/*
* Bluetooth. Same CYW43439 as the Pico 2 W: HCI is not on a UART, it shares
* the WiFi gSPI bus, so hang the shared-bus HCI transport off the board's
* stock infineon,airoc-wifi node and point the host at it. CONFIG_BT then
* enables itself via the zephyr,bt-hci chosen (see ../../../Kconfig).
*/
&pio0_spi0 {
airoc-wifi@0 {
cyw43_bt_hci: cyw43_bt_hci {
compatible = "infineon,cyw43-bt-hci";
status = "okay";
};
};
};

/ {
chosen {
zephyr,bt-hci = &cyw43_bt_hci;
};
};

#include "../../../app.overlay"
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ BLOBS=["hal_infineon"]

# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them.
counterpart = "raspberrypi/raspberry_pi_pico_w"

# Frozen into flash: the Pico W has ~42 KB of heap, and adafruit_ble alone takes
# ~30 KB of it when loaded from CIRCUITPY as .mpy. Freezing keeps the bytecode in
# flash so a BLE node fits.
FROZEN_MPY_DIRS = ["frozen/Adafruit_CircuitPython_BLE"]
Loading
Loading