Skip to main content

Running apps

What an app is

An app is a .uf2 file on the device's SD card that the bootloader loads and hands control to directly — it runs its own code, separate from the firmware's own screens (the panels covered in Screen and buttons). Loading an app is closer to booting a different program than opening a menu item.

Worth knowing if you go looking in the firmware source yourself: the APP_SELECTED_* constants and addApp() calls in fwPanelLibMain.cpp actually register panels, not apps — a naming leftover that has misled more than one writer on this documentation project. This page and Screen and buttons use "app" only for a real .uf2 launched the way described below.

Getting a UF2 onto the card

Apps arrive on the device the same way firmware updates do — as a .uf2 file copied onto the SD card — but they land in a different place and get launched a different way. See Transferring files for the ways to get a file onto the card (swap it to the built-in USB reader, or copy it from the FREE-WILi GUI).

Tracing picker_open() in targets/fw2mainsbl/picker.cpp: the picker only lists .UF2/.uf2 files sitting directly at the SD card's root (1:/) — it skips directories rather than looking inside them (if (fno.fattrib & AM_DIR) continue;), so a UF2 buried in a subfolder won't show up. It shows at most 12 entries, each with its file size, and titles the screen "FW2 Main SBL — 1:/".

This is different from a firmware update: flashing the main or display processor's own firmware image uses the BOOTSEL/mass-storage path covered in Firmware update and Recovery mode. An app UF2 is never flashed — see Launching an app below.

Launching an app

The second-stage bootloader (the "SBL") is what actually launches an app, before the main firmware — and its panel list — ever starts. Tracing targets/fw2mainsbl/stage3.cpp's main loop: once an SD card is present and mounts successfully, the bootloader opens the picker automatically and renders the list of .UF2 files at the card's root. Up/Down move the highlight (picker_on_up/picker_on_down) and Center confirms a selection (picker_on_select).

On selection, load_application_from_uf2() (targets/fw2mainsbl/uf2.c) reads the UF2 file block by block, validates each block (it must target on-chip RAM and match the RP2350's family ID), and copies its contents straight into SRAM — the app is not written to flash. stage3.cpp then calls launch_application_from_ram(), which hands the processor over to whatever was just loaded. If loading fails, the bootloader shows "Load failed" and reopens the picker so you can try again.

The on-screen "Apps" folder

The main menu's Apps folder — see Screen and buttons — lists Skelltris, Wili8, and Doom, and they're meant to be real apps launched this way. Today, though, the launch wiring behind them isn't finished: tracing fwPanelLibDisplay.cpp:262-264, all three entries currently dispatch to APP_SELECTED_TERMINAL — the same identifier the Wi-Li-nux Terminal panel uses — so selecting any of the three just opens the Terminal panel rather than launching a distinct game. This is confirmed directly from the menu-building source; it isn't a case of unclear firmware, the wiring is simply not done yet.

Scripts: a different mechanism again

Scripts are a third thing, distinct from both panels and apps: a script doesn't get handed the processor the way an app does. Instead it runs as a guest program inside an engine that's already part of the running main firmware.

A script is a file in /scripts/ on the SD card, and its extension decides which engine runs it:

  • .wasm — a sandboxed WebAssembly guest, run by the on-device WiliWasm engine (built on wasm3). This is the default if you don't give a script an extension. Write it in C/C++, Rust, or anything else that compiles to WASM, with remote debugging support from FREE-WILi GUI.
  • .r — an rTHON script: a Python-like language that runs directly on the device, no host PC or full Python runtime needed.
  • .z — a ZoomIO program: compiled to native RISC-V and run on the main RP2350's second core, for protocol work and timing precise to the nanosecond.

WiliBLOCKS (.wili files, opened from the separate Wili Blocks panel — see Screen and buttons) is a fourth, point-and-click way to automate the device, distinct from the three script types the Scripts panel runs.

Which to reach for: rTHON and WiliBLOCKS are the fastest way to automate something without leaving the device; WASM is for real software written in a language you already know; ZoomIO is for the narrow slice of work where PIO-level timing precision actually matters.