Skip to content

boards: add Silicon Labs SiWx917-DK2605A (BRD2605A) - #23

Closed
mikeysklar wants to merge 8 commits into
mainfrom
siwx917/board-silabs-siwx917-dk2605a
Closed

boards: add Silicon Labs SiWx917-DK2605A (BRD2605A)#23
mikeysklar wants to merge 8 commits into
mainfrom
siwx917/board-silabs-siwx917-dk2605a

Conversation

@mikeysklar

Copy link
Copy Markdown
Owner

Adds the Silicon Labs SiWx917-DK2605A (BRD2605A), plus one line in boards/board_aliases.cmake.

Four board decisions worth reviewing:

CONFIG_NET_TCP=y and CONFIG_ZVFS_OPEN_MAX=8. The board enabled NET_SOCKETS, NET_IPV4 and NET_DHCPV4 but never TCP, and the siwx91x driver defaults to the native stack. DHCP is UDP, so association and the lease both worked and the board looked healthy while every SOCK_STREAM socket failed. ZVFS_OPEN_MAX also defaulted to 0, leaving no descriptors to hand out. This is what blocked the web workflow, not anything in the workflow itself.

siwx917_dk2605a.overlay exists to override app.overlay, which unconditionally references zephyr_udc0. This SoC has no USB device controller, so there is no CIRCUITPY drive over USB, ever. Precedent: boards/nrf54l15dk_nrf54l15_cpuapp.overlay. The overlay also enables the PSRAM node, which is only safe because of #22.

Console on SEGGER RTT, not the UART. CONFIG_UART_CONSOLE=n, CONFIG_RTT_CONSOLE=y. The board has one UART and CircuitPython wants it for the REPL, so every Zephyr printk interleaved into the Python session and corrupted pasted input.

CIRCUITPY carved out of code_partition, not upper flash. In common flash mode the M4 cannot write flash itself, the NWP does it, and the NWP refuses writes in the OTA swap region. Everything there opens and reads fine and every write returns -EIO. 1 MB partition, 984 KB to CIRCUITPY.

Depends on #15, #16, #18, #20, #21, #22.

mikeysklar and others added 5 commits July 31, 2026 13:51
Wi-Fi 6 + Bluetooth LE 5.4 dev kit built on the SiWG917M111MGTBA:
Cortex-M4F at 180 MHz plus a separate network processor, 8 MB flash and
8 MB memory-mapped PSRAM.

The SoC has no USB device controller, so boards/siwx917_dk2605a.overlay
replaces the port's app.overlay, which unconditionally references
zephyr_udc0. The console falls back to the Zephyr console on ulpuart,
reaching the host over the on-board J-Link VCOM, and file access is via
web workflow. This follows the existing nrf54l15dk precedent.

CIRCUITPY is carved out of code_partition rather than the upper flash.
In common-flash mode the M4 cannot write flash itself; the driver asks
the NWP to do it, and the NWP refuses writes in the OTA-swap region,
which fails as -EIO on the first block. code_partition is shrunk from
2008K to 1M (the image uses ~700K) and 984K given to circuitpy.

The board conf also sets CONFIG_GPIO and a non-zero kernel heap, neither
of which the upstream Zephyr board defconfig enables; without them the
build fails to link.
Enable ulab for this board (CIRCUITPY_ULAB), which fits comfortably in
the 1 MB code partition at ~76% used.

Disable the 8 MB PSRAM node. It works as memory - sparse writes across a
64 KB buffer verify correctly - but using it as the CircuitPython heap
corrupts objects under sustained allocation, and a loop with no buffer
at all is enough to hang the board. Not a timing problem: identical at
fast-freq 144 MHz and 33 MHz. Disabling the node keeps it out of the
generated ram_bounds[] so the heap falls back to the 319 KB internal
SRAM, which is ample and about 20% faster for array work.

Worth re-enabling once the root cause is found; 8 MB of Python heap
would be exceptional.
The board enabled NET_SOCKETS, NET_IPV4 and NET_DHCPV4 but never CONFIG_NET_TCP,
and the siwx91x driver defaults to the native network stack. DHCP is UDP, so
association and the DHCP lease both worked and the board looked healthy while
every SOCK_STREAM socket failed to open. The web workflow listener never came
up and socketpool raised "Out of sockets" from Python.

CONFIG_ZVFS_OPEN_MAX also defaulted to 0, so there were no file descriptors for
Zephyr to hand out to sockets.

With both set, the web workflow serves: PUT returns 201, the bytes land
sha256-exact, and /fs/ returns 401 without credentials.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Wi-Fi path prints on nearly every net event, and those printks shared the
UART with the CircuitPython REPL. A single scan emits dozens of
NET_EVENT_WIFI_SCAN_RESULT lines, which interleave with the raw REPL protocol
and corrupt the handshake:

    Raw REPL did not acknowledge (got b'\x1b]')

so any harness driving the board over serial is flaky.

Route Zephyr's console to RTT over the existing SWD connection. Nothing else
has to change: supervisor/serial.c builds its console from
DEVICE_DT_GET(DT_CHOSEN(zephyr_console)) and drives it with busio directly,
never going through Zephyr's console subsystem, so the REPL keeps ulpuart and
the J-Link VCOM while printk, the boot banner and driver logs move to RTT.

RTT needs no extra pin and works on the debug link already in use. Note the
control block cannot be auto-detected on this SoC: J-Link scans the usual
Cortex-M RAM at 0x20000000 and this part has RAM at 0x400, so the address has
to be passed explicitly. Read it from the ELF and hand it to J-Link:

    arm-none-eabi-nm zephyr.elf | grep _SEGGER_RTT
    JLinkExe ... -autoconnect 1 -RTTTelnetPort 19021   # then: RTTStart <addr>
    JLinkRTTClientExe

Verified: the full Zephyr console including the boot banner appears on RTT, the
serial side is quiet, and a multi-line raw-REPL exec that previously failed
repeatedly now succeeds first try while a scan is running.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Root cause of the corruption is found and fixed in
siwx917/fix-psram-dcache-corruption: an unmaintained 16 KB data cache
dedicated to PSRAM, left enabled and half-configured by the bootloader.

With that in place the heap moves from the 319 KB internal sram0 to the
8 MB PSRAM. gc.mem_free() goes from 72,144 to 8,265,200 bytes.

Depends on siwx917/fix-psram-dcache-corruption. Enabling this node without
it reintroduces the corruption.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mikeysklar added a commit that referenced this pull request Aug 4, 2026
check_suite["workflowRun"] is null for check suites that aren't attached
to a workflow run (e.g. one that was deleted, or belongs to an app
integration), and the "scheduler" job's Get-last-commit-with-checks step
dereferenced it unconditionally:

  TypeError: 'NoneType' object is not subscriptable

That's what was failing CI on PRs #20 and #23 on this fork. Skip check
suites with no workflow run instead of crashing on them.
check_suite["workflowRun"] is null for check suites that aren't attached
to a workflow run (e.g. one that was deleted, or belongs to an app
integration), and the "scheduler" job's Get-last-commit-with-checks step
dereferenced it unconditionally:

  TypeError: 'NoneType' object is not subscriptable

That's what was failing this PR's "scheduler" CI job.
mikeysklar added a commit that referenced this pull request Aug 4, 2026
Same fix as pushed to #20/#23: check_suite["workflowRun"] is null for
check suites with no attached workflow run, and the "scheduler" job
dereferenced it unconditionally. That's what was failing this PR's
scheduler job too.
mikeysklar added a commit that referenced this pull request Aug 4, 2026
Second-eyes review from Hermes (verified independently against this
repo's real lib/tlsf/tlsf.c, probe pack in the review thread):

tlsf_create_with_pool() cannot return NULL for any region that passes
MIN_HEAP_REGION_SIZE on this board. control_construct() sizes the
control block from max_bytes (circuitpy_max_ram_size, a compile-time
8 MiB constant), not from the region being added -- so the control
block is the same fixed size no matter which region hosts it, and both
the 8 KiB guard and TLSF's actual minimum clear it by a wide margin.
The `heap == NULL` branch documented a mechanism that cannot occur;
removed it rather than leave dead code that reads as real handling.

Also corrected the size-guard comment: measured against the real TLSF
sources, a region under the guard doesn't fail to allocate from --
tlsf_create_with_pool() writes its control block past the end of the
region regardless and returns success (a 1 KB region took a 3.7 KB
out-of-bounds write in the measurement). The corruption from that
write, not a clean "cannot allocate" failure, is what the guard
actually prevents.

This branch predates the board definition (added by #23) so it can't
build standalone; the identical change was hardware-verified on
siwx917_dk2605a via siwx917/integration, which carries this branch's
exact commits plus this same fix on top: boots, gc.mem_free() reports
~8 MB free, allocation works, hw test suite 9 passed/1 xfailed
(unchanged).

Not touching the largest-region-first reorder: it's a correct
permutation and the hazard flagged in review (relocating the heap's
control block into the SiWx917's PSRAM, which sits behind an
unmaintained write-back cache per #22) is already mitigated in the
merged tree by disabling that cache before port_heap_init() does
anything else -- and the reorder itself is unmeasured as a live bug,
just a documented risk worth keeping an eye on for other boards.
zephyr_dts_to_cp_board() dereferenced props["label"] unconditionally for
gpio-keys, but label is optional and deprecated there; modern boards
identify keys with zephyr,code instead. Any such board failed board
generation with KeyError: 'label'.

Guard it the same way the gpio-leds handler a few lines above already does.
mikeysklar added a commit that referenced this pull request Aug 4, 2026
Same fix as pushed to #20/#23/#24: check_suite["workflowRun"] is null
for check suites with no attached workflow run, and the "scheduler"
job dereferenced it unconditionally. That's what was failing this PR's
scheduler job too.
mikeysklar added a commit that referenced this pull request Aug 4, 2026
Same fix as pushed to #20/#23/#24: check_suite["workflowRun"] is null
for check suites with no attached workflow run, and the "scheduler"
job dereferenced it unconditionally. That's what was failing this PR's
scheduler job too.
The siwx91x SoC family Kconfig never selects BUILD_OUTPUT_HEX, unlike
Silicon Labs' other SoC families (silabs_s0/s1/s2/sim3, which all
select it). The port's Makefile unconditionally copies zephyr.hex to
firmware.hex for release artifacts, so every release build for this
board failed:

  cp: cannot stat '.../zephyr.hex': No such file or directory
  make: *** [Makefile:37: build-.../firmware.hex] Error 1

even though the .elf and .rps (what's actually flashed) built and
linked fine. Verified locally: zephyr.hex now generates.
@mikeysklar mikeysklar added the port:siwx917 SiWx917 CircuitPython port label Aug 4, 2026
@mikeysklar

Copy link
Copy Markdown
Owner Author

Closing as merged. All commits present in siwx917/integration by patch-id; 1ad9b23 matches integration's 7e6f0d1. Verified read-only; nothing outstanding from this branch.

@mikeysklar mikeysklar closed this Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

port:siwx917 SiWx917 CircuitPython port

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant