A movie player for the FreeWili 2 handheld. Drop converted movies on a USB thumb drive, plug it in, and watch them on the built-in LCD, on a TV over HDMI — including HDMI audio — or both, driven entirely from a Roku IR remote.
- USB thumb-drive playlists — FAT-formatted drive, hot-pluggable; files stream through a from-scratch USB MSC host driver at ~1.1 MiB/s into an 8 MB PSRAM ring.
- Three-and-a-half outputs — LCD, DVI (TV video with audio on the speaker/headphone jack), both at once, and a full HDMI-audio mode that sends video and audio to the TV. Switch at runtime with the STAR button; the choice persists across power cycles.
- Roku remote control — play/pause, next/prev, volume/mute, and escalating seek (tap FWD/REW repeatedly: ±10 s → 30 s → 60 s → 5 min per tap, committed as one seek).
- Karaoke mode — mix the built-in PDM microphone over the movie audio.
- Home screen — file browser with a button guide, drawn on whichever outputs are live.
The FreeWili 2's display processor: an RP2350B (dual Cortex-M33, overclocked to 252 MHz) with a 480×320 ST7796 LCD, an HSTX DVI/HDMI output, 8 MB QSPI PSRAM, a NAU88C10 audio codec, a PDM microphone, and an IR receiver. No hardware modifications are needed.
- Convert your videos with
wiliplayerconvert —
it produces
.fwmvfiles (480×270 MJPEG at 15 fps + IMA-ADPCM 16 kHz audio, interleaved for single-pass streaming). - Put the
.fwmvfiles in amovies/folder on a FAT-formatted USB drive (files in the drive root also work). - Flash
movieplayer.uf2(see Building below), plug the drive into the FreeWili's USB host port, and pick a movie from the home screen.
Any Roku IR remote (extended-NEC, address 0xEAC7):
| Button | Action |
|---|---|
| OK / Play | Select / play–pause |
| Up / Down | Move selection (karaoke: mic level) |
| Left / Right | Prev / next movie; border style on home |
| FWD / REW | Escalating seek (±10/30/60/300 s per tap) |
| Vol +/− , Mute | Volume (6 dB steps) / mute |
| STAR (*) | Cycle output: BOTH → LCD → DVI → HDMI AUDIO (press OK within 10 s to confirm — the board saves the mode and reboots into it; in HDMI mode, STAR + OK switches back) |
| Sleep | Speaker ↔ headphone |
| Power | Screen on/off |
| Home / Back | Home screen |
Developed on Windows against pico-sdk 2.2.0 with the toolchain the
Raspberry Pi Pico VS Code extension
installs under ~/.pico-sdk (ARM GCC 14.2, CMake 3.31, Ninja):
powershell -File tools/build.ps1 # → C:/buildfiles/movieplayer/movieplayer.uf2On other platforms, configure directly:
cmake -G Ninja -B build -DPICO_SDK_PATH=<sdk> -DPICO_PLATFORM=rp2350 -DPICO_BOARD=pico2.
Host-side unit tests (pure-logic modules compiled with plain gcc, driven by
pytest) run with python -m pytest tests -q.
The FreeWili 2 has no UART wired to the display processor and its USB port runs in host mode, so everything goes over SWD via the on-board CMSIS-DAP debug probe:
powershell -File tools/flash.ps1 # program + verify + reset via OpenOCD
powershell -File tools/rtt.ps1 # live SEGGER RTT console (DIAG logs)Core 0 decodes MJPEG (TJpgDec) into the HSTX scanout framebuffer, blits the
LCD, mixes/decodes audio, and runs the UI. Core 1 is the USB MSC host,
streaming the current file into a 4 MB PSRAM ring. The HSTX peripheral scans
the framebuffer out as 640×480@60 DVI from a baked DMA command list with no
per-pixel CPU work. In HDMI-audio mode the scanout gains TERC4 data islands
carrying 48 kHz stereo audio (upsampled from 16 kHz by a 90-tap polyphase
FIR), the per-frame refresh IRQ moves to core 1, and video pacing locks to
the audio clock. The output mode is persisted in the last 4 KB flash sector
and selected at boot. The design history — specs, plans, and detailed
findings for every stage — lives in docs/superpowers/.
| Component | Origin | License |
|---|---|---|
third_party/usbmsc |
from-scratch RP2350 USB MSC host (same author) | MIT |
third_party/fatfs |
FatFs (ChaN) | BSD-style (see ff.c) |
third_party/tjpgd |
TJpgDec (ChaN) | BSD-style (see tjpgd.c) |
third_party/pico_hdmi |
fliperama86/pico_hdmi | Unlicense |
third_party/pico_pdm |
OpenPDMFilter (STMicroelectronics) | Apache-2.0 |
third_party/segger_rtt |
SEGGER RTT | SEGGER license (see headers) |
MIT — see LICENSE.

