Archived from the old WioL1Pro-CVHBuild repository (first published 2026-08-28). These are the Wio Tracker L1 Pro builds from before Cairn; current builds are in the latest Cairn release.
CVHBuild 91 — the GPS Eco freeze
A Seeed Wio Tracker L1 Pro fork of MeshCore
(nRF52840, SH1106 128×64 OLED, 5-way joystick, buzzer, L76K GNSS), on upstream v1.17.1.
One fix, and it is the reason nodes were going dark: a node running GPS Eco froze for good at its
first ten-minute re-wake. Everything else is build 90.
This fork versions by build number — CVHBuild N, shown on the splash screen — so a device can be
matched to a tag from its own display.
Downloads
| File | Target |
|---|---|
MeshCore-WioL1Pro-CVHBuild91-2026-08-25.uf2
| Companion, SH1106 OLED — the main build |
MeshCore-WioL1Eink-CVHBuild91-2026-08-25.uf2
| Companion, Waveshare 2.13" B/W e-ink |
MeshCore-DV1-CVHBuild91-2026-08-25.uf2
| Companion, 2.42" SSD1309 OLED on the Grove connector |
MeshCore-WioL1RoomServer-CVHBuild91-2026-08-25.uf2
| Room server, SH1106 OLED |
All four images carry the fix — it is not specific to one panel.
Flashing: double-tap reset to expose the TRACKER L1 volume and copy the .uf2 onto it. The
"could not copy extended attributes" error is normal, and the volume ejecting itself means the
flash succeeded.
Time the copy. A flash that finishes in about a second with "Device not configured" is a
truncated write and leaves the app bricked — a good flash takes several seconds (≈6 s for the
OLED images, ≈16 s for e-ink). If it was quick, double-tap reset and copy it again.
Fixed
GPS Eco stopped killing the node ten minutes in.
EnvironmentSensorManager::start_gps() opened with an unconditional Serial1.end(), on the
reasoning that closing first is harmless whether or not the port was already open. It is not
harmless. This core's Uart::end() has no _begun guard: it clears EVENTS_TXSTOPPED and
EVENTS_RXTO, fires TASKS_STOPRX/TASKS_STOPTX, then spins on
while ( !(nrfUart->EVENTS_TXSTOPPED && nrfUart->EVENTS_RXTO) ) yield();
A disabled UARTE does not execute tasks, so on an already-closed port neither event ever arrives and
the call never returns. yield() is taskYIELD(), so the loop task spins at its own priority for
ever: display frozen or dark, joystick dead, node off the mesh — while the SoftDevice and TinyUSB
keep running on their own tasks, which is why the USB serial port stays enumerated through it and
the node looks asleep rather than crashed. Nothing recovers it; only a reset does.
Eco mode walks straight into it. stop_gps() closes the port at the end of each fix window, and
GPS_ECO_INTERVAL_MS (10 minutes) later the eco loop calls start_gps() — the first eco re-wake
is the hang. The same path is reachable by hand in any GPS mode: Settings → GPS On → Off → On
freezes on the second On, which is the thirty-second reproduction and the way to confirm the fix on
a flashed device.
Both Serial1.end() calls are now guarded with if (Serial1) — Uart::operator bool() returns
_begun, so the port is only closed when it is actually open.
Present since build 73 (the "GPS UART closes with the GPS" change, 2026-08-13) in every L1
image, not just the SH1106 one. It only fires on a device that is in Eco, or that has had GPS
toggled off and on again — which is why it read as intermittent.
Memory
| Build | Flash | RAM |
|---|---|---|
| Companion (SH1106 OLED) | 466 KB / 692 KB (67.3%) | 150 KB / 230 KB (65.4%) |
| Companion (e-ink) | 486 KB / 692 KB (70.3%) | 154 KB / 230 KB (67.1%) |
| Companion (DV1 / SSD1309) | 473 KB / 692 KB (68.3%) | 150 KB / 230 KB (65.4%) |
| Room server | 417 KB / 792 KB (52.6%) | 37 KB / 230 KB (16.1%) |
Testing
All four environments build and the native suite passes 48/48 (40 core + 8 KISS modem). The
mechanism is certain from the core's source rather than inferred from symptoms, but the fix has
not yet been confirmed on hardware — Settings → GPS On → Off → On is the check to run first.
Full changelog: see CHANGELOG.md, [cvhbuild-v91].