cyd_playground #
A simple dashboard generated by an LLM for a CYD. Rest of the read me is what the LLM wrote.
Bare-metal Rust (esp-hal + Embassy) for the ESP32-2432S028R "Cheap Yellow Display",
2-USB revision. Boots to a loading screen until WiFi joins over DHCP (or, with no
network configured, to a WiFi picker with an on-screen keyboard), then shows a
portrait tile dashboard: the clock (set from timeapi.io, with a WiFi status dot)
and current weather from Open-Meteo (refreshed every 15 minutes): the temperature tile
carries the day's high and low below the current reading. While music plays,
the weather folds into one row and a now-playing tile shows the track (scrolling if
long) with a progress bar; it comes from the teal.fm status record in ATPROTO_REPO,
read through the Slingshot cache at SLINGSHOT_URL every 15 seconds. Three touch
buttons along the bottom: Refresh (fetch weather and now playing, and re-sync the
clock now), Light
(backlight off; tap anywhere to turn it back on), and Info (IP, SSID, signal,
heap, uptime, plus settings: accent, theme, WiFi picker, touch calibration, power off).
One-time setup #
cargo install espup esp-generate espflash --locked
espup install --targets esp32 # installs the Xtensa `esp` toolchain
cp .env.example .env # then edit with your WiFi credentials
Keep the single quotes in .env; a password containing $, a backtick, or \ is
otherwise altered by the shell before it reaches the firmware. A single quote inside
the password is written as '\''.
Build, flash, monitor #
source ~/export-esp.sh # every new terminal
source .env
cargo run --release # flashes over /dev/cu.usbserial-* and opens the monitor
Ctrl-C leaves the monitor. ESP_LOG in .cargo/esp-config.toml sets the log level.
The CH340 USB bridge on this board is only reliable at the default 115200 baud, so a
full flash takes about a minute.
If the screen looks wrong #
The background must be black, the clock orange, and text must read normally. If not,
see the tuning table at the top of src/board.rs. A blank or noisy screen usually
means the other panel controller: cargo run --release --features ili9341.
Touch calibration #
Info → Calibrate shows four crosses; tap each. The fitted values are saved to
flash and used at once. Every tap is still logged as touch raw (x, y) -> (px, py)
if you want to check them. The defaults live at the top of src/touch.rs.
Joining WiFi from the device #
With SSID empty at build time, or after Info → WiFi, the device scans and lists
networks strongest first (* marks a secured one). Tap one, type the password on the
keyboard, tap Done. The choice is saved to flash and wins over the env on later
boots. On the loading screen a tap anywhere reopens the picker.
Pinout used #
| Signal | GPIO |
|---|---|
| Display SCLK / MOSI / MISO | 14 / 13 / 12 |
| Display CS / DC | 15 / 2 |
| Backlight | 21 |
| Touch CLK / MOSI / MISO / CS / IRQ | 25 / 32 / 39 / 33 / 36 |
SD card, RGB LED (4/16/17) and the light sensor (34) are not used yet.
Layout #
src/board.rspin map, display and touch bus bring-upsrc/ui/mod.rsloading screen, tiles, button bar, off-screen canvas, themesrc/ui/keyboard.rson-screen keyboard componentsrc/ui/wifi_list.rsnetwork pickersrc/ui/calibrate.rstouch calibration screen and fitsrc/touch.rsXPT2046 sampling, runtime calibrationsrc/settings.rsflash-saved settings: colors, WiFi credentials, calibrationsrc/clock.rstime sync, counted on the crystal between fetchessrc/weather.rsOpen-Meteo current conditions and today's high / lowsrc/now_playing.rsteal.fm now-playing status recordsrc/wifi.rscommand-driven station task: connect, scan, DHCP, statussrc/bin/main.rsinit, then the screen state machine: dashboard, info, picker, keyboard, calibration
- Rust 100%