Skip to content

Add Silicon Labs EFM32GG11 chip family + WF200 Wi-Fi backend + dual-bank OTA (WGM160P)#387

Draft
RAR wants to merge 35 commits into
libretiny-eu:masterfrom
RAR:feature/silabs-efm32gg11-wf200
Draft

Add Silicon Labs EFM32GG11 chip family + WF200 Wi-Fi backend + dual-bank OTA (WGM160P)#387
RAR wants to merge 35 commits into
libretiny-eu:masterfrom
RAR:feature/silabs-efm32gg11-wf200

Conversation

@RAR

@RAR RAR commented Jun 12, 2026

Copy link
Copy Markdown

Add Silicon Labs EFM32GG11 chip family + WF200 Wi-Fi backend + dual-bank OTA (WGM160P)

Summary

Adds a new chip family, silabs-efm32gg11, for the Silicon Labs
EFM32GG11B820 (Cortex-M4F) — together with a Wi-Fi backend for the on-package
WF200 radio (including softAP) and a dual-bank OTA scheme behind the
standard Arduino Update API. The target is the WGM160P SiP (EFM32GG11
host + WF200), e.g. as used in the Enel X JuiceBox 40.

What's in it

Grouped into six logical pieces (~34 commits):

  1. EFM32GG11 chip familyfamilies.json / platform.json
    (framework-silabs-gecko-sdk package), WGM160P board def, SCons family
    builder, EFM32GG11B820 linker script, LibreTiny base API
    (cpu/device/flash/mem/ota/sleep/wdt/init/fault), FreeRTOS, printf, FlashDB
    FAL port, syscalls, and the Arduino core (wiring/GPIO/EXTI/HardwareSerial).
  2. WF200 Wi-Fi backend — from-scratch Arasan-SDHCI PIO SDIO host driver,
    the sl_wfx FMAC host port (reset/PDS/firmware feed, bus + event tasks,
    cmd52/53), WF200↔lwIP netif glue, lwIP config, and a LibreTiny-style WiFi
    library (STA/Scan/Generic/Events + HTTPClient).
  3. WF200 Secure Link — the WGM160P's WF200 is OTP-provisioned in enforced
    Secure Link mode, so plaintext is rejected. Adds the host crypto hooks
    (curve25519 ECDH + AES-CCM via software mbedtls 3.5.0), a GG11 TRNG0 entropy
    source, and the FreeRTOS renegotiation task.
  4. WF200 softAP — concurrent AP + STA on the single WF200 radio: a second
    lwIP netif beside the STA one, interface-demuxed RX / per-interface TX,
    modePriv AP enable/disable, the full WiFiAP API, and AP client-event
    plumbing. AP clients get DHCP from the GSDK's own Apache-2.0 dhcp_server.c
    (consumed unmodified from the framework package via thin MIT glue).
  5. Dual-bank OTA — jump-based A/B OTA behind the Arduino Update API,
    with a custom MIT first-stage bootloader and auto-rollback:
    • A custom first-stage bootloader (bootloader/, original MIT) selects the
      boot bank from ping-pong metadata, validates the image CRC, and reverts to
      the last-good bank if a trial image fails to confirm within N boots.
    • Shared ping-pong OTA metadata (lt_ota_meta.{c,h}, common) with CRC32,
      plus a real FAL flash driver over emlib MSC (erase/write/read), run
      from RAM (EM_MSC_RUN_FROM_RAM) so the metadata write survives.
    • Dual-link app build (bank A @ 0x008000, bank B @ 0x100000) and
      a dual-bank .uf2 artifact; Update.begin/write/end stages the inactive
      bank and arms it as a TRIAL.
    • lt_ota_confirm() (common weak no-op + silabs impl, idempotent) commits a
      trial image; the watchdog (now functional — ULFRCO + WDOG bus clock)
      backstops a hung trial boot. Host unit tests cover CRC32 + metadata
      ping-pong.
  6. Board/doc cleanup — drop the untested generic wgm160p-slwstk6121a board
    (see below); README reflects the working Wi-Fi + softAP + OTA.

Boards

  • wgm160p-juicebox-40 — Enel X JuiceBox 40 variant (RGB/pinmap). All bench
    testing below was done on this board
    — the only WGM160P hardware I have.

(An earlier revision carried a generic wgm160p-slwstk6121a Starter-Kit board,
but it's removed: its WF200 host bus is SPI-strapped while this backend is
SDIO-only, and I can't verify it without the hardware. Happy to add a generic
board back once someone with a Starter Kit can confirm the strap + pinout.)

The OTA flash map (in boards/_base/silabs-efm32gg11.json):

boot  0x000000 +0x008000   32 KB   MIT first-stage bootloader
ota1  0x008000 +0x0F0000  960 KB   bank A
ota2  0x100000 +0x0F0000  960 KB   bank B
kvs   0x1F0000 +0x008000   32 KB   FlashDB (survives OTA)
meta  0x1F8000 +0x008000   32 KB   ping-pong OTA metadata

Framework packages

Two SDK packages are referenced via platform.json, following the existing
framework-* pattern (separate repos, not vendored into this tree):

  • framework-silabs-gecko-sdk (Gecko SDK 4.5.0 — emlib, lwIP, FreeRTOS port,
    mbedtls).
  • framework-wfx-fmac-driver (SiliconLabs wfx-fullMAC-driver 3.7.0, Apache-2.0,
    incl. the WF200 firmware blob — Silicon Labs limited-redistribution license).

Testing (bench, real WGM160P in a JuiceBox 40 — the only board I have)

  • framework=base compiles; Arduino blink + Serial run.
  • GPIO, EXTI/attachInterrupt, multi-task FreeRTOS verified.
  • STA: WiFi.begin()WL_CONNECTED → DHCP lease; HTTPClient GET
    completes (full response body) over enforced Secure Link.
  • softAP: AP beacon visible → client associates (AP_CLIENT_CONNECTED_IND,
    station count) → client gets a DHCP lease (192.168.4.x, gw 192.168.4.1).
  • Concurrent AP + STA (the softAP done-state): with the device joined to a
    home network as STA, a client on the device's AP loaded a page served by the
    on-device lwIP httpd — and the same page was reachable from the home LAN on
    the STA address at the same time (httpd served on both netifs concurrently).
  • OTA (end-to-end, 2026-06-16): Update streamed a dual-bank .uf2
    inactive bank written byte-exact (CRC matched the source image) → first-stage
    bootloader switched banks → new image booted → lt_ota_confirm() committed
    the trial → choice persisted across reset. Auto-rollback verified by skipping
    the confirm (bootloader reverts to the previous bank). Host CRC32 + metadata
    ping-pong unit tests pass.

Notes / known limitations

  • OTA UF2 packing needs a ltchiptool SoC module
    (libretiny-eu/ltchiptool#93,
    pending). Until it ships, the build emits a raw firmware.uf2 (not
    OTA-applicable) and prints a fallback notice; SWD/Commander flashing of
    firmware.bin is unaffected. With the patched ltchiptool the build emits a
    real dual-bank .uf2.
  • OTA requires the app to confirm. A freshly applied image boots as a TRIAL
    and auto-reverts unless lt_ota_confirm() is called once the app is healthy.
    This is by design (auto-rollback), documented in the OTA API.
  • mbedtls is software-only (no PSA/CRYPTOACC plugin — those need SLC-generated
    init); sufficient for the Secure Link key exchange and OTA image hashing.
  • softAP rides the STA channel (single radio). The common case (STA up first,
    AP follows its channel) is bench-proven; the late-connect edge (AP up before
    STA joins on a different channel) is a documented limitation, with a
    restart-AP-on-CONNECT_IND fallback designed but not yet implemented.
  • Reconfiguring a running AP needs softAPdisconnect() first (documented in
    WiFiAP.cpp).

Heads-up for reviewers (deliberate deviations)

  • Board variants are hand-written, not boardgen output. boardgen 0.12.0
    can't model EFM32 port-aware pins (PA4/PB4/PD4 all collapse to "4") and drops
    non-D0/A0 Arduino labels, so it emits a degenerate variant. The hand-written
    variant header documents this; happy to file/track the upstream boardgen gap.
  • FreeRTOS and lwIP are compiled from the GSDK tree (single vendored source)
    rather than the library-freertos / library-freertos-port split — cleaner
    for a SiP that already vendors the whole GSDK, but a deviation from the guide.
  • OTA flashing/packing is SWD + ltchiptool, not the usual UART flow. There
    is no Silabs SoC module in ltchiptool yet, so initial provisioning goes
    through SWD (OpenOCD/J-Link/Commander) and the dual-bank .uf2 packer is the
    new ltchiptool SoC plugin (PR Unable to Flash to Certain Modules #93 above). firmware.bin stays the raw SWD
    image; firmware.uf2 is the OTA artifact.

Provenance / licensing

This PR contains no vendored SDK source — every file in the tree is original
work under LibreTiny's MIT license. The SDK proper (driver, mbedtls, lwIP,
FreeRTOS, emlib, the WF200 firmware blob, the board PDS, and the AP DHCP server)
is not in this PR — it is consumed from the framework-* packages above. In
particular:

  • The host port (sl_wfx_host.c, lt_sdio.c, lwIP glue, WiFi library) is
    original work written against the Apache-2.0 driver API. lt_sdio.c is
    from-scratch; only hardware register values (facts) were referenced from any
    SiLabs material, no code.
  • sl_wfx_host_crypto.c (the Secure Link hooks) is an independent mbedtls
    implementation
    written from the public Apache-2.0 hook API and the wire
    protocol — not derived from the Gecko SDK's MSLA-licensed example code.
  • The OTA first-stage bootloader, ping-pong metadata, FAL flash port, and
    dual-bank lt_ota
    are all original MIT work; no Gecko Bootloader code is
    used or vendored.
  • The AP DHCP server is the GSDK's own Apache-2.0 dhcp_server.c, compiled
    unmodified from the framework-silabs-gecko-sdk package; LibreTiny adds
    only MIT glue (lt_dhcpserver.c) and a small compat shim. No DHCP-server
    source is vendored into this tree.
  • The board PDS (sl_wfx_pds.h, brd4321a) is pulled from the
    framework-silabs-gecko-sdk package via an include path, not copied here.

Checklist

  • clang-format (v19) clean
  • autoflake / black / isort --profile black clean
  • Builds and runs on hardware (STA + softAP concurrent, OTA end-to-end)

RAR added 3 commits June 12, 2026 09:32
New LibreTiny chip family for the Silicon Labs EFM32GG11B820 (Cortex-M4F),
targeting the WGM160P SiP. Adds the family to families.json/platform.json
(framework-silabs-gecko-sdk package), generic + WGM160P board definitions,
the SCons family builder, EFM32GG11B820 linker script, LibreTiny base API
(lt_cpu/device/flash/mem/ota/sleep/wdt/init/fault), FreeRTOS config, printf
backend, FlashDB FAL port, syscalls, and the Arduino core (wiring, GPIO,
EXTI, HardwareSerial). framework=base compiles and Arduino blink + Serial
run on a WGM160P (bench-verified on a JuiceBox 40).
Wi-Fi support for the WGM160P's on-package WF200 over internal SDIO.
Adds a from-scratch Arasan SDHCI PIO host driver (lt_sdio), the sl_wfx
FMAC host port (reset/PDS/firmware feed, bus + event tasks, cmd52/53),
the WF200<->lwIP netif glue, lwIP config, and the LibreTiny-style WiFi
library (WiFiSTA/Scan/Generic/Events + HTTPClient). The board PDS is pulled
from the GSDK package (brd4321a), not vendored into the tree. WiFi.begin()
-> WL_CONNECTED -> DHCP and an HTTPClient GET work on a bench JuiceBox 40.
The WGM160P's WF200 is OTP-provisioned in enforced Secure Link mode, so
plaintext host messages are rejected. Adds the host crypto hooks
(sl_wfx_host_crypto.c) as an independent mbedtls implementation written from
the public Apache-2.0 hook API (sl_wfx_host_api.h) and the SecureLink wire
protocol — X25519 ECDH, HMAC-SHA512 public-key authentication, a SHA-256
session key, and AES-128-CCM records. A GG11 TRNG0 entropy source backs
mbedtls, and a FreeRTOS task drives session-key renegotiation.

The pub-key exchange indication is stashed when it arrives before the driver
arms its wait, without which sl_wfx_init() intermittently times out. Bench:
WiFi.begin() -> WL_CONNECTED -> DHCP and HTTPClient GET work deterministically
over enforced Secure Link.
@RAR RAR marked this pull request as ready for review June 12, 2026 13:45
@RAR RAR marked this pull request as draft June 12, 2026 14:47
RAR added 25 commits June 12, 2026 13:15
…CP server)

Second lwIP netif (AP) beside STA on the single WF200 radio: interface-demuxed RX, per-interface TX, modePriv AP enable/disable, full WiFiAP API, AP client-event plumbing. DHCP for AP clients reuses the GSDK's Apache-2.0 dhcp_server.c (consumed unmodified from framework-silabs-gecko-sdk) via thin MIT glue + a compat shim. lwIP httpd enabled for the concurrent-server demo. Bench-confirmed on a JuiceBox 40: client on the AP gets a 192.168.4.x lease and loads an on-device page while STA is online (served on both netifs at once).
…lects working WiFi+softAP

The generic SLWSTK6121A board mapped WF200 to SPI but the backend is SDIO-only and the board is untested (no hardware), so it's removed for now; wgm160p-juicebox-40 (bench-proven) is the sole board. README updated: WiFi STA + softAP are working; WF200 SDIO pin map corrected to PE8-PE13 LOC0 to match lt_sdio.c and the board JSON.
With LT_REMALLOC, __wrap_realloc passed new_size straight to
pvPortMalloc(). realloc(ptr, 0) (e.g. Mongoose's mbuf_trim of an
emptied recv buffer) then requests 0 bytes; heap_4 returns NULL, and
with configUSE_MALLOC_FAILED_HOOK any NULL return fires the hook — on
ports whose hook resets the SoC, a legal shrink-to-zero becomes a
reboot loop. Factor the malloc+copy+free path into lt_remalloc():
free and return NULL when new_size==0, and skip the memcpy when the
old pointer is NULL (realloc-as-malloc was reading from address 0).

Affects every LT_REMALLOC family, not just silabs-efm32gg11.
AddCoreSources() only globs a fixed subdir set (api/, common/, port/,
wiring/, ...) — base/ota/ is not among them, so lt_ota_meta.c and
lt_crc32.c never reached the family core. lt_ota.c's references to
lt_ota_meta_bank_valid only linked while every caller was gc-sections'd
out; the first sketch to actually call lt_ota_switch() failed to link.
Register base/ota/ explicitly (excluding the host-only lt_meta_hostshim.c).
…section)

EFM32GG11 is Series 1, which emlib's em_msc.h does NOT include in its
RAMFUNC allowlist (only Series 0/2 or an explicit EM_MSC_RUN_FROM_RAM).
So MSC_LoadWriteData ran from flash, and a sustained flash write (e.g.
staging a multi-KB OTA image into the inactive bank) hung mid-transfer
inside the write loop — bench-confirmed the CPU halted in
MSC_LoadWriteData at ~3s into an 85 KB FAL write.

Define EM_MSC_RUN_FROM_RAM and add a .ram output section (VMA in RAM,
LMA in flash) with a startup copy-table entry so the MSC routines are
copied to and executed from RAM. _lt_image_size now spans .ram (the last
flash-LMA section) so the OTA image-length symbol stays exact. Single
4-byte writes (Task 3 bench) worked from flash by luck of prefetch; this
makes all flash writes robust.
The FSBL rewrites the OTA metadata page on every trial boot (attempt
countdown / revert). Like the app, its emlib MSC write must execute from
RAM on this Series-1 part or risk hanging mid-write. Add a .ram section +
copy-table entry to bootloader.ld and define EM_MSC_RUN_FROM_RAM in the
bootloader's standalone compile, so rollback can't stall on a flash-resident
write loop.
…clock)

lt_wdt_enable() armed the WDOG peripheral but never gave it a running
clock: WDOG_INIT_DEFAULT selects LFRCO (32 kHz), which lt_init never
enables, and the WDOG register clock (cmuClock_WDOG0) was never gated on
— so WDOGn_Init writes were dropped and the counter never ticked. The
watchdog therefore never reset the chip, which silently breaks OTA
auto-rollback (an unhealthy trial image is supposed to hang and let the
watchdog reset it so the bootloader can revert). Enable cmuClock_WDOG0
and select the always-on ULFRCO (~1 kHz), which also matches the existing
ms->period mapping. Bench-found while testing OTA T8 rollback.
Add ltWifiStatusLedEnable(bool) so an application can take the RGB
status LED away from the WiFi backend at runtime — needed by the
openevse port, where LED_R/G/B are the charge-state indicator. When
disabled, ltWifiStatusLed() touches no GPIO, leaving the pins for the
app to drive; re-enabling re-inits them as outputs. No-op on boards
without LED_R/LED_G/LED_B.
Add ltWifiStatusLedEnable(bool) so an application can take the RGB
status LED away from the WiFi backend at runtime — needed by the
openevse port, where LED_R/G/B are the charge-state indicator. When
disabled, ltWifiStatusLed() touches no GPIO, leaving the pins for the
app to drive; re-enabling re-inits them as outputs. No-op on boards
without LED_R/LED_G/LED_B.
Shrink both OTA banks from 0x0F8000 to 0x0F0000 (960 KB) and add a 32 KB
`kvs` partition at 0x1F0000+0x8000, between bank B and the OTA metadata.
It sits outside both banks so it survives an OTA, and the matching FAL
partition (FAL_PART_TABLE_ITEM(kvs, KVS) + FLASH_KVS_OFFSET/LENGTH) is
generated from the board flash map by builder/utils/flash.py.

Keeps the OTA bank constants, both linker defaults, and the bank-B
re-link defsym in sync. Backs FlashDB (the LibreTiny-native KV store);
LibreTiny ships only the IPreferences interface, no concrete Preferences.

Flash map: boot 0x0/32K, ota1 0x008000/960K, ota2 0x100000/960K,
kvs 0x1F0000/32K, meta 0x1F8000/32K (8K used). Bank A's freed tail
0x0F8000..0x100000 is left unused to keep both banks equal size.

Build-verified: KVDB inits on the kvs partition; both banks link at the
correct bases (entry delta 0xF8000); 91 KB app fits the 960 KB bank.
Bench-found: with the kvs partition in place, FlashDB formatted and wrote
KVs but they never survived a reboot — the partition reformatted every
boot. Root cause: FDB_WRITE_GRAN defaulted to 8 (STM32F2/F4 byte
granularity), which packs KV status markers as sub-word bytes. EFM32GG11
internal flash is word-only (emlib MSC writes 4-byte words; the FAL port
rejects sub-word offsets), so the markers corrupted.

Make FDB_WRITE_GRAN overridable in the common fdb_cfg.h (#ifndef guard,
default 8 unchanged for byte-writable SPI-flash families) and set 32 in
the silabs builder — the stm32f1-class word-write value the comment names.

Bench-verified on the JuiceBox WGM160P: a boot counter in the kvs
partition now persists across power cycles (0->1->2->3 over 3 reboots).
WiFiGeneric::modePriv hardcoded WFM_MGMT_FRAME_PROTECTION_OPTIONAL in the
START_AP command. PMF (802.11w) has no key hierarchy to protect on an OPEN
BSS, so the WF200 rejects START_AP with 0x21 (INVALID_PARAMETER) and the AP
never starts. Gate it on the security mode: OPTIONAL on a WPA2 AP, DISABLED
on an open one.

Bench-validated on the JuiceBox WGM160P: open softAP() now returns success
(START_AP 0x00, IP 192.168.4.1) where it previously failed 0x21.
…e-free

Bug-2 diagnostic, gated behind -DLT_WFX_RX_TRACE=1 (stock build byte-identical).
The 'pbuf_free: p->ref > 0' double-free only reproduces with a client associated
to the softAP generating RX traffic concurrent with scanNetworks() (bench-proven:
scan + softAP with no client is crash-free, STA-only scan is crash-free).

Two probes:
 - wf200_netif.c lt_wf200_netif_input(): bound frame_length to a max Ethernet
   frame; record + drop a bogus length instead of letting pbuf_take() write OOB
   and corrupt a neighbour pbuf's ref (hypothesis 2). Per-interface RX counters.
 - WiFiScan.cpp scanNetworks(): log the calling task + RX counters. task='tcpip'
   means the scan is driven from the lwIP thread (hypothesis 1).

Probe validated on the JuiceBox bench (emits 'scan: ctx task=... rx_ap=...').
Hand to the openevse bench (which has a client) to settle the root cause.
The WF200 FMAC has no autonomous rejoin, so the backend now supervises it: a
STA link that reached GOT_IP and then drops is rejoined automatically, instead
of requiring the app to poll WiFi.status() and call reconnect() itself.
setAutoReconnect()/getAutoReconnect() are now functional (was a no-op returning
false); default ON to match the ESP32 Arduino core.

Implementation (no new task, no new RAM): the existing WiFi event task gets a
1 s receive timeout and runs a supervisor tick on idle. When armed + enabled +
the link is lost (CONNECTION_LOST / CONNECT_FAILED / DISCONNECTED), it fires a
rate-limited (2 s -> 30 s backoff) NON-blocking join and lets the normal
CONNECT -> GOT_IP ladder update status. Armed on GOT_IP (and static-IP link-up);
disarmed on a fresh begin(), intentional disconnect(), or STA disable -- so a
never-succeeded join (e.g. wrong password) is never looped; that stays the
caller's to handle via begin()'s return.

Fills a real gap for the openevse-lite consumer, which has no dropped-link
watcher once STA-connected (its only retry path is softAP-mode-only).
…lags

__wrap_malloc routes ALL allocations (Arduino String, ArduinoJson, mongoose
mbufs, lwIP pbufs) to the single heap_4 ucHeap[], so a heap-hungry app (e.g.
serving a ~21-26 KB gzipped web UI) exhausts the 64 KB default and crashes
(malloc-failed hook / lwIP OOM -> corrupted callback in ucHeap -> HardFault)
while ~350 KB of the part's 512 KB SRAM sits idle. Wrap the define in #ifndef so
firmware can size it via -DconfigTOTAL_HEAP_SIZE=N. ucHeap is a static BSS
array, so a larger value just grows BSS (no linker change). Default unchanged
(64 KB). Verified: -DconfigTOTAL_HEAP_SIZE=262144 links at RAM 68.7% (360 KB),
~164 KB clearance below the top-of-RAM stack; no linker overflow.
Opt-in SNTP for firmware that drives it (sntp_init/setservername/
setoperatingmode) and provides the time-set hook. lwipopts.h: SNTP_SUPPORT +
SNTP_SERVER_DNS (LWIP_DNS already on) + SNTP_SET_SYSTEM_TIME -> a firmware hook
(lite_sntp_set_system_time, declared here). Builder: add
lwip/src/apps/sntp/sntp.c to the lwIP source list (header was already on the
include path).

No behaviour change for apps that don't use it: sntp.c.o is built into liblwip.a
but only linked when something references sntp_*. Verified: a sketch that defines
the hook + calls sntp_init() links clean with sntp.c.o produced; a non-SNTP
example links unchanged (no undefined lite_sntp_set_system_time).
RAR added 6 commits June 16, 2026 08:05
…rollback)

Brings the bench-verified OTA core onto the libretiny-eu#387 family branch:
custom first-stage bootloader, ping-pong metadata, dual-bank app
linker layout, real FAL/MSC flash driver, and lt_ota_confirm().

OTA core verified on the real JuiceBox WGM160P over SWD (FAL flash,
bank-A boot, A/B switch, auto-rollback, healthy-confirm).
erase() returned (end - start) with start page-aligned DOWN, so a
page-aligned 256-byte first write reported only 256 B erased when the
whole 4 KB page was blank. uf2ota records {erased_offset=offset,
erased_length=ret} and skips re-erase only inside that window, so every
later 256 B block in the same page failed the check and re-erased the
page -- wiping the blocks already written. Net effect: a staged OTA bank
ended up mostly 0xFF (only the final page survived), the metadata CRC was
computed over that garbage, and the bootloader jumped into an empty bank
and hard-faulted.

Round the erased extent up to a full page and return (end_pages - offset),
matching the realtek/beken/ln882h ports (ceil(size/page)*page). Bench:
on-device Update OTA now writes bank B byte-exact (CRC matches the source
image) and boots it. Found via the first end-to-end on-device OTA test.
The dual-bank OTA engine (lt_ota + uf2ota + FAL + bootloader switch) was
proven, but the standard Arduino Update path was never wired for this
family:
 - LT_HAS_OTA was undefined, so Update::begin() short-circuited with
   'OTA is not yet supported on this chip!'. Define it 1.
 - Update.cpp references MD5Init/Update/Final unconditionally, but neither
   LT_ARD_MD5_MBEDTLS nor _HOSTAPD was set, so they were undefined at link.
   Enable MD5 via the GSDK mbedtls already compiled for the WFX Secure Link:
   MBEDTLS_MD5_C + library/md5.c + LT_ARD_MD5_MBEDTLS=1. Independent of
   LT_HAS_MBEDTLS (no full TLS stack).
 - Replace the Phase-1 firmware.uf2 stub with a real dual-bank packer that
   drives 'ltchiptool uf2 write' (EFM32GG11 SocInterface, OTAType.DUAL):
   DUAL_1 -> ota1 (bank A), DUAL_2 -> ota2 (bank B, diff32 binpatch). Emits
   only firmware.uf2 so the raw firmware.bin stays the SWD/commander image.
   The SocInterface lives in ltchiptool; until a release carrying it is
   installed, 'uf2 write' raises NotImplementedError, so fall back to the
   raw-image stub (build stays green; OTA needs the SoC-enabled ltchiptool).

Bench: full on-device OTA verified -- applier (bank A) applies an embedded
.uf2 via Update.begin/write/end, bootloader switches to bank B, the new
image runs and lt_ota_confirm()s; bank B persists across reset.
…F2 enablement)

Brings the two follow-up commits from the OTA branch onto libretiny-eu#387:
 - FAL erase() return-value fix (uf2ota multi-block data loss)
 - Arduino Update/OTA UF2 path (LT_HAS_OTA, mbedtls MD5, dual-bank UF2
   packer with stub fallback when ltchiptool lacks the EFM32GG11 SoC)

Bench-verified end-to-end on the JuiceBox WGM160P.
lt_ota_confirm() unconditionally rewrote the metadata page (a 4 KB MSC
erase+write) on every call, including boots where there is nothing to
confirm -- e.g. just after an SWD flash that erased the meta region, where
the metadata is blank and the bootloader already defaults to bank A. That
stray erase+write can stall the core long enough to disrupt the live WF200
SDIO link (observed downstream: an OTA build with a self-confirm hook never
came up on WiFi after a fresh flash; removing the confirm call fixed it).

Bail out without touching flash unless the running bank is genuinely an
unconfirmed TRIAL: skip when metadata is blank/invalid, and skip when the
bank is already CONFIRMED. Confirm now writes flash at most once -- on the
actual post-OTA trial boot -- so apps can call it unconditionally on every
boot (after a health check) without perturbing WiFi on normal boots.
Carries the confirm fix from the OTA branch onto libretiny-eu#387: lt_ota_confirm()
now no-ops without touching flash unless the running bank is an
unconfirmed TRIAL, so calling it on every boot no longer does a stray
metadata erase+write that can disrupt the WF200 link. Bench-verified:
confirm on blank meta (post-SWD-flash) leaves the metadata untouched.
@RAR RAR changed the title Add Silicon Labs EFM32GG11 chip family + WF200 Wi-Fi backend (WGM160P) Add Silicon Labs EFM32GG11 chip family + WF200 Wi-Fi backend + dual-bank OTA (WGM160P) Jun 16, 2026
The WGM160P host drives the ATmega328P EVSE-controller RESET (active-low,
continuity-confirmed 2026-06-13) on PF11 — nominally USB_DP (module pin 42),
repurposed on the JuiceBox since USB is unused. Add it to the board JSON
pinout and expose an EVSE_RESET macro (encoded 0x5B) in the variant; raise
PINS_GPIO_MAX to 0x5B so it is addressable via pinMode/digitalWrite.

Also drop the PB3 pinout entry: bench-verified to drive nothing visible, so
it is not a meaningful board pin.
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.

1 participant