Skip to content

zephyr-cp: add the Silicon Labs SiWx917-DK2605A - #11218

Open
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:board/siwx917-dk2605a
Open

zephyr-cp: add the Silicon Labs SiWx917-DK2605A#11218
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:board/siwx917-dk2605a

Conversation

@mikeysklar

@mikeysklar mikeysklar commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Depends on #11220. #11210 has merged, so this builds against main as it stands. #11220 keeps autogen_board_info.toml correct across a rebuild; without it the generator rewrites the board's name to "Dev Kits and Thunderboards SiWx917 ...". Worth merging that one first.

What

Adds the CircuitPython board definition for the Silicon Labs SiWx917-DK2605A (SiWx917 Wi-Fi 6 and Bluetooth LE Dev Kit), Zephyr board siwx917_dk2605a, SoC SiWG917M111MGTBA.

The Zephyr board already exists upstream at boards/silabs/dev_kits/siwx917_dk2605a, so this is only the CircuitPython side: the board .conf and .overlay fragments, autogen_board_info.toml, circuitpython.toml, and one alias line.

The .rps artifact

This SoC boots from a .rps container that the bootloader installs, not from a raw image written to an address. Zephyr's soc/silabs/silabs_siwx91x handles that by leaving BUILD_OUTPUT_HEX unset and pointing the runner's bin_file at zephyr.rps:

# runners_yaml_props_target controls the file used by "west flash"
set_target_properties(runners_yaml_props_target PROPERTIES bin_file ${PROJECT_BINARY_DIR}/${KERNEL_NAME}.rps)

The port's Makefile only knew .elf, .hex, .exe and .uf2, so a build with no .hex failed the release-artifact copy. This adds a firmware.rps rule and has the board declare ["elf", "rps"].

That matters beyond tidiness: if the board forces CONFIG_BUILD_OUTPUT_HEX=y to satisfy the old Makefile, west flash then prefers the .hex, reports success, and leaves a board that does not boot.

Testing

Two SiWx917-DK2605A boards, on separate hosts, both flashed with the image built from this branch.

Artifacts produced, confirming the .hex is correctly absent:

zephyr.hex → No such file or directory
zephyr.bin
zephyr.elf
zephyr.rps

Both boards boot:

Adafruit CircuitPython 10.3.0-alpha.4-48-gb9d03f12f-dirty on 2026-08-20; SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A) with siwg917m111mgtba
>>>

The banner reports BRD2605A, the radio board number, for the same kit.

Board-generated pin names come from zephyr,code via #11210, and the pins work:

>>> import board, digitalio
>>> [n for n in dir(board) if n.startswith("KEY")]
['KEY_0', 'KEY_1']
>>> d = digitalio.DigitalInOut(board.KEY_0)
>>> d.switch_to_input(pull=digitalio.Pull.UP)
>>> d.value
True

west flash selects the right artifact on its own, with no arguments beyond the debugger id my bench needs because several probes are attached:

-- west flash: using runner silabs_commander
Flashing file: .../build-silabs_siwx917_dk2605a/zephyr-cp/zephyr/zephyr.rps
Flashing completed successfully!

and the board comes up afterwards. make flash passes no runner arguments, so on a host with a single debugger attached it is the same path.

Wi-Fi is deliberately not in this PR. The board boots, exposes its pins and runs code without it. An implementation exists on a branch, roughly 800 lines across ports/zephyr-cp/common-hal/wifi/, and I am holding it back rather than attaching it to a board PR: it is a behaviour change that deserves its own review, and some of it currently compensates in common-hal for driver behaviour, which may not be the shape you want. Happy to send it next, split however you prefer.

Scope

One new board plus the firmware.rps rule the port needs to support it. No behavior change for existing boards.

AI assistance

Written with Claude Code. I ran the hardware myself. The banners, artifact listing and REPL output above are from the boards, not from a model.

@tannewt

tannewt commented Aug 20, 2026

Copy link
Copy Markdown
Member

The port's Makefile only knew .elf, .hex, .exe and .uf2, so a build with no .hex failed the release-artifact copy. This adds a firmware.rps rule and has the board declare ["elf", "rps"].

I doubt we actually need the "elf" portion here if rps is used for loading.

@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 2e70556 to 4fcfd9c Compare August 20, 2026 17:49
@mikeysklar

Copy link
Copy Markdown
Collaborator Author

Agreed, dropped it. CIRCUITPY_BUILD_EXTENSIONS = ["rps"] now, which also matches what the other zephyr-cp boards do: each declares exactly the one artifact it loads from.

Checked that this does not cost debugging. zephyr.elf is still linked into the build tree either way, 21 MB with symbols, since the .rps is generated from it. Publishing an elf as a release artifact would not help anyone anyway, since you would want the one matching your own build.

Rebuilt clean with ["rps"] and the firmware.rps rule still produces the artifact.

Separate thing I should flag on this PR, since it is not ready yet and it is why this is still a draft. autogen_board_info.toml here is hand-edited, but its own header says not to edit it. When the board is built, the generator rewrites it to:

name = "Dev Kits and Thunderboards SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A)"

because zephyr2cp.py derives the vendor from the board directory's parent:

vendor_index = zephyr_board_dir.parent / "index.rst"

That holds for boards/<vendor>/<board>, but Silicon Labs nests a level deeper, boards/silabs/dev_kits/<board>, so the parent is a category rather than the vendor. Four of their category directories are affected: dev_kits, explorer_kits, radio_boards, starter_kits. board_yaml["vendor"] is already silabs, so walking up to the ancestor matching it would fix all of them.

I would rather fix that generically than hand-edit a generated file. Happy to send it as its own PR like the gpio-keys one, unless you would rather it rode along here.

@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 4fcfd9c to 3fd8073 Compare August 20, 2026 19:29
@mikeysklar

Copy link
Copy Markdown
Collaborator Author

Rebuilt with the mdns hand edit dropped, so autogen_board_info.toml is now byte-identical to what the build generates. import mdns reports not available on the board, so the generated mdns = false is right and the committed true was wrong.

The name in that file needs #11220 to stay correct across a rebuild, otherwise the generator rewrites it to "Dev Kits and Thunderboards SiWx917 ...".

Built once from b9d03f12f with #11210, #11220 and this branch applied together, then flashed to two SiWx917-DK2605A boards on separate hosts. Both boot and both expose the generated pin names:

Adafruit CircuitPython 10.3.0-alpha.4-48-gb9d03f12f-dirty on 2026-08-20; SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A) with siwg917m111mgtba
>>> import board
>>> [n for n in dir(board) if n.startswith("KEY")]
['KEY_0', 'KEY_1']

So this now waits on two: #11210 to build at all, and #11220 for the board's published name.

@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 3fd8073 to 841a135 Compare August 20, 2026 21:39
@mikeysklar

Copy link
Copy Markdown
Collaborator Author

Rebased onto 069144c66 now that #11210 is merged, and rebuilt rather than assuming the earlier result carried over.

Built from merged upstream with only this branch and #11220 applied, then flashed to two SiWx917-DK2605A boards on separate hosts:

Adafruit CircuitPython 10.3.0-alpha.4-49-g069144c66-dirty on 2026-08-20; SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A) with siwg917m111mgtba
>>> import board
>>> [n for n in dir(board) if n.startswith("KEY")]
['KEY_0', 'KEY_1']

autogen_board_info.toml now shows no diff after a build, so the committed file is exactly what the generator produces. That needs #11220; without it the name is rewritten to "Dev Kits and Thunderboards SiWx917 ...".

@mikeysklar
mikeysklar marked this pull request as ready for review August 21, 2026 00:51

@tannewt tannewt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple suggestions to make this more concise.

Comment on lines +146 to +157
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_BROADCASTER=y
CONFIG_BT_OBSERVER=y
CONFIG_BT_EXT_ADV=y

CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_BT_DEVICE_NAME_MAX=28
CONFIG_BT_L2CAP_TX_MTU=253

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe these settings have been factored out. Maybe into Kconfig. I don't think you need them here.

Comment on lines +43 to +71
// The 8 MB PSRAM at 0xa000000 works as memory: sparse writes across a 64 KB
// buffer verify correctly and a 64 KB allocation succeeds. But using it as the
// Python heap corrupts objects under sustained allocation, and the failure is
// not about large buffers - a plain `for i in range(200000): s = s + i` with no
// buffer at all hangs the board. Symptoms are corrupted objects: an int that
// became a function, a bytearray with a wrong length, and an MPU fault calling
// a garbage pointer read from PSRAM:
//
// ***** MPU FAULT ***** Instruction Access Violation
// r0/a1: 0x0a0012c0 r12/ip: 0x0a0031ac <- PSRAM pointers
// PC: 0x410e29c8 <- called through r3, garbage
//
// Not a timing problem: identical at fast-freq 144 MHz and 33 MHz. Not the
// NWP-reserved/DMA pools either; excluding those (supervisor/port.c minimum
// region size) did not help.
//
// ROOT CAUSE FOUND 2026-08-01, and the node is enabled again.
//
// The SoC has a 16 KB data cache dedicated to PSRAM (family RM rev 1.2 section
// 5.4.5) at 0x44040000, on the QSPI2 path. The bootloader leaves it enabled and
// half-configured, and nothing in this build maintains it - see the long
// comment in supervisor/port.c, which disables it in port_heap_init() before
// any TLSF pool exists.
//
// Note what did NOT work, so it is not retried: setting ATTR_MPU_RAM_NOCACHE on
// this node changes nothing. That is an MPU attribute governing the Cortex-M
// architectural cache, and CPU_HAS_DCACHE is never selected, so there is
// nothing there for it to govern. The cache that matters is a separate
// peripheral and an MPU attribute does not reach it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this here.

@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 841a135 to 9831dc5 Compare August 21, 2026 21:41
@mikeysklar

mikeysklar commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Both done, and I took your two comments as the general rule rather than the specific instances, so this went further than the lines you marked. Rebased onto current main, so #11220 is in.

before now
.conf 193 lines, 138 comment 93, 43
.overlay 111 lines, 69 comment 69, 22
PR total +508 +296

nrf7002dk_nrf5340_cpuapp.conf is the closest analogue at 10 lines, so this was several times the size of anything else in the port and no longer is.

Settings the port already provides. 23 of them, not just the BT block: the CONFIG_BT_* group from ports/zephyr-cp/Kconfig, NET_HOSTNAME* and MBEDTLS from prj.conf, plus SPI and SPI_ASYNC. CONFIG_BT=y went too, since the board DT has zephyr,bt-hci and config BT defaults from dt_chosen_enabled. Also dropped CONFIG_SPI_SILABS_SIWX91X_GSPI=y, whose own comment admitted it was redundant. I checked each removal against the generated .config rather than assuming: CONFIG_BT and the GSPI symbol are both still y without the lines, and board.SPI still works.

Two real overrides remain, each with a reason: BT_BUF_ACL_TX_COUNT=15 and the peripheral preferred connection parameters.

Comments. Removed the .overlay narrative you flagged and four more like it, plus seven links to my fork's issue tracker, a reference to a test file that is not in this PR, timing measurements and trial counts, Zephyr source line numbers that would rot at the next manifest bump, and a pasted flash error transcript. Also deleted # CONFIG_ICM40627=y and an eight line note about an IMU that cannot work yet.

&psram stays. The Python heap measures 7936 bytes with it and without it, so nothing here depends on it, but the node does feed ram_bounds so removing it is a real change rather than dead config. Making the heap actually use the 8 MB needs port_heap_init() to build the pool in the largest region instead of the first, which is not this PR.

Testing

Two DK2605A boards on separate hosts, same image, flashed with commander.

Adafruit CircuitPython 10.3.0-alpha.4-52-g3113c1d785 on 2026-08-21; SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A) with siwg917m111mgtba
440353787 440353836
board key names ['KEY_0', 'KEY_1'] ['KEY_0', 'KEY_1']
board.SPI True True
filesystem mount CIRCUITPY CIRCUITPY
heap total 7936 7936
200k allocations 12800000 12800000

autogen_board_info.toml is byte-identical to what the build regenerates. The banner prints BRD2605A because that is the radio board number in the firmware; the board and Zephyr target are siwx917_dk2605a.

Not tested here: web workflow, since neither board has credentials in this build. Wi-Fi scanning returns 0 networks, which is #11223 and not specific to this board.

AI assistance was used. The hardware runs are mine, and I verified the config removals against the built .config myself rather than trusting the diff.

@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 9831dc5 to 5822c01 Compare August 21, 2026 23:49
The SiWx917 SoC pairs a Cortex-M4 application core with a separate network
processor that owns the Wi-Fi and BLE radios. Firmware is loaded as an .rps
container rather than a hex image, so the port's release-artifact rule gains a
firmware.rps target and the board declares CIRCUITPY_BUILD_EXTENSIONS = ["rps"].
@mikeysklar
mikeysklar force-pushed the board/siwx917-dk2605a branch from 5822c01 to 422467e Compare August 22, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants