← All projects in the gallery

NEON DECK

by jonathan harrocks

A synthwave internet radio for the Cheap Yellow Display, and a worked example of almost everything the designer can do: joining a network, keeping settings across a reboot, playing a stream, and binding widgets straight to hardware. Clone it and take it apart - most of the decisions below are visible in two clicks. WHY THE AUDIO IS WHAT IT IS The board decided this, not taste. A CYD brings out exactly one free pair of general-purpose pins (CN1), and an external I2S DAC needs three - so sound is the chip's own DAC on GPIO 26, where the onboard amplifier and the speaker connector already are. That is 8-bit and mono, which then settles two more things: the codec is MP3 rather than AAC, because the AAC decoder wants about 45 KB of working memory this board has not got, and the stations are 128 kbps because the ceiling is the DAC, not the stream. There is a trap in that pin, and it is worth knowing before you build anything with sound on this board. The internal DAC is driven through I2S, and I2S maps its left channel to GPIO 26 and its right to GPIO 25 - and GPIO 25 is the touch controller's clock. The usual audio library turns on both channels. The export turns on one. WHY THE METERS ARE BOUND TO THE PLAYER, NOT A VARIABLE Open either meter and look at its binding: the source is the player itself, not a variable. A level is a reading - nothing computes with it - so making you declare a variable to show one would be ceremony. The volume slider is the same idea taken one step further: it is a two-way binding, so the slider IS the volume rather than a proxy for it. It sets the level, and follows it when something else does. The levels are taken off the audio samples on their way out, so those bars move with the music rather than on a timer. Press Play in the designer and you will see them move there too - the preview synthesises its own music rather than fetching a station, and taps it with an analyser, so the meters are real in both places. WHY THE TRACK TITLE SCROLLS It is a Text variable bound to the stream metadata, and its label mode is Scroll circular rather than Wrap. An ICY title can be sixty characters and the box is 288 px wide; wrapping would push it out of its panel and clipping would hide the half that matters. Design for the long one - many stations send no title at all, so it also has to look right empty. WHY THERE IS A BUTTON OVER THE STATUS BAR The transparent button at the top left is the way to the network screen. There are swipes too - left for stations, up for the network - but a swipe announces itself to nobody, and on a first boot with no credentials the radio cannot play and there has to be something visible to press. It sits on the network state because that is where somebody looks when there is no network. The WiFi screen has a Back button for the same reason: without one the only way off it is to join something. WHY THE PASSWORD IS NOWHERE IN THIS FILE The whole join is one widget - scan, pick, type, verify - and the password is typed on the device at exactly one of those steps. The setting it goes into is marked secret, which means nothing can read it back, it is never written to the settings file, and it carries no value in the design. That last part is why cloning this is safe: a password typed into a project would travel with every copy of it. The access point password is the exception, and it is in here in plain sight. An access point publishes the password people need in order to reach it, so there is no earlier moment at which somebody could have entered one. Change it before you flash this - and keep it to eight characters or more, because softAP() given a shorter one starts an open network and returns success. WHAT SURVIVES A REBOOT Four settings: the network, its password, the volume and the last station. They live in NVS, which is its own flash partition - so an ordinary firmware upload does not touch them, though "Erase All Flash" does. The volume writes itself shortly after you move the slider; that automatic save is right for a volume and wrong for a calibration, where the point is being able to abandon a bad one by not saving it. THE LOOK RGB565 on a 2.8 inch panel rewards broad flat colour and hard-edged glow, and punishes fine gradients (they band) and 1 px detail (it disappears). Synthwave is almost a specification for those constraints, which is why this reads as clearly on glass as it does on screen. The stations are real and long-running; swap them for your own on the Data tab, and prefer http where a station offers both - TLS wants about 40 KB of heap that the decoder would rather have.
Board
ESP32-2432S028R "Cheap Yellow Display"
MCU
ESP32 (WROOM / WROVER)
Display
ILI9341
Resolution
320 x 240
Touch
XPT2046
LVGL
v9