Code on GitHub →

The problem

Display drivers for hobbyist MCU projects usually get written once, hardcoded to whatever bus and MCU HAL was on hand, and rewritten from scratch the next time the interface changes. This driver separates the ST7789VW’s actual behaviour (initialization sequence, window addressing, RGB565/RGB666 pixel writes) from the hardware-specific glue (SPI vs. serial, which MCU’s HAL) needed to talk to it.

Technical approach

The core exposes a small struct of function pointers the caller fills in — reset_assert/reset_release, delay_ms, write_cmd/write_cmd1/write_cmdN, write_data — and everything else (orientation, window addressing, fill_rect, draw_pixels, RGB565/RGB888 conversion) is written once against that interface, independent of which bus is underneath. Adding a new host interface means implementing that one struct, not forking the driver.

The build reflects the same separation: ST7789_ENABLE_SPI_PORT and ST7789_ENABLE_SERIAL_PORT are independent CMake options (SPI on by default), the library installs as a proper CMake package with an exported st7789::st7789 target, and CI builds a small configuration matrix so both port combinations are actually checked, not just the default.

Status, honestly

A complete, working v1.0.0: initialization, drawing primitives, both port backends, CI, and CMake packaging. Small in scope by design — a display driver, not a graphics library — and a good example of designing the hardware-abstraction boundary before writing the second port, not after.