Getting a real, touchable user interface onto the DK2's 4-inch MIPI DSI panel from Elixir on Nerves, with no GPU — the display stack, host previewing, a drift-free timer, and the Scenic gotchas that compile cleanly and fail on the device.
The ST STM32MP157F-DK2 ships with a 4-inch 480×800 MIPI DSI panel and a Goodix capacitive touch controller bolted to the front of it. On my board they sat there doing nothing for four releases of my Nerves system — the kernel drivers were enabled, and nothing ever drew a pixel.
This series is about fixing that, from Elixir, with Scenic, and — as it turns out — without the Vivante GPU at all.
The demo is a Pomodoro timer: start, pause, reset, plus or minus a minute, a big countdown and a progress ring. Small enough to finish, real enough to prove the stack — touch in, timed redraw out, visible state change.
| Board | ST STM32MP157F-DK2 (the STM32MP157D-DK1 is the same idea with one core variant down) |
| CPU | Dual Cortex-A7 @ 800 MHz, plus a Cortex-M4 @ 209 MHz |
| RAM | 512 MB DDR3L |
| Display | 4″ 480×800, MIPI DSI, Orisetech OTM8009A, backlight over DCS |
| Touch | Goodix capacitive, on I²C, on the panel |
| GPU | Vivante GC NanoUltra — unused, as it turns out |
It picks up where the first STM32MP1 series left off. That one was about building the Nerves system: the boot chain, device trees, TF-A, U-Boot and twenty-five build errors. This one is about the thing left switched off at the end of it.
Between an Elixir process and a lit pixel on the DK2 there is an LTDC, a MIPI DSI host, an OTM8009A panel and a Goodix touch controller. I spent a day preparing to enable the Vivante GC NanoUltra, then read scenic_driver_local's source and found it renders in software to /dev/fb0.
An hour spent trying to open a window that was never going to be drawn, then the realisation that a Scenic graph is just data. Walking it and rendering to SVG found two layout bugs in a minute that had survived 49 tests and a review.
Counting down by subtracting the tick interval drifts on an embedded board. Deriving the remaining time from a monotonic deadline instead makes it drift-free by construction — and injecting the clock turns a 25-minute test into a map update. It also caught a real race.
Scenes, graphs, components and drivers on an STM32MP157F-DK2 — then the four gotchas that compile cleanly and fail on the device: the required assets module, the child spec that is a plain list, the missing input: style that made every button inert, and text_align: :center not working.
An afternoon spent finding where a Nerves target's Erlang version is really decided — and discovering it is encoded in the filename of a patch inside a dependency I had never opened. Plus the Kconfig default that will silently move you to OTP 29 the moment you bump.