# st7789_mpy: a MicroPython display driver with its own build chain and firmware images

> st7789_mpy is a C written MicroPython driver for ST7789 based screens, forked from devbis' driver and extended with rotation, scrolling, bitmap and Hershey fonts, PNG and JPEG drawing, and pre-compiled firmware for boards from the Pico to the T-Display. The catch is that you inherit the maintainer's toolchain, including a custom licence and a README that still calls itself a work in progress.

**russhughes/st7789_mpy** — Fast MicroPython driver for  ST7789 display module written in C

- Repository: https://github.com/russhughes/st7789_mpy
- Stars: 728 · Forks: 140
- Language: Python
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/russhughes-st7789-mpy

## What st7789_mpy adds on top of the devbis driver

st7789_mpy is a driver for cheap displays based on the ST7789 chip, written in C and intended for MicroPython. It starts life as a fork of devbis' st7789_mpy driver, and the author states plainly that he modified the original for one of his own projects. That fork history explains both the shape of the project and its gaps: it is a working personal toolkit with features added on demand rather than a general purpose library designed from the requirements of many boards.

The list of additions is specific enough to be useful when choosing. Display rotation and scrolling are there. Text can be written from bitmaps converted from True Type fonts, drawn with 8 and 16 bit wide bitmap fonts, or drawn with Hershey vector fonts. JPEG images can be drawn, including a SLOW mode that handles files larger than the available RAM by decompressing them in pieces through TJpgDec, the Tiny JPEG Decompressor R0.01d. PNG drawing uses the pngle library. Polygons and filled polygons can be drawn and rotated, and the driver tracks bounds. Init is customisable enough to support st7735, ili9341 and ili9342 panels as well, with configuration examples for the M5Stack Core, M5Stack Core2, T-DONGLE-S3 and Wio Terminal.

The package also carries 12 bitmap fonts derived from classic PC text mode fonts and 26 Hershey vector fonts, so a build ships with usable text rather than requiring you to bring your own.

## The repository layout: C sources, frozen fonts and prebuilt firmware

The top level of the repository tells you what kind of project this is. Alongside the expected .gitignore, LICENSE, README.md and VERSION files sit st7789/, which holds the C driver itself, lib/ for the vendored helper code, fonts/ for the frozen font files, firmware/ for the pre-compiled images, examples/ for runnable scripts, docs/, utils/, and two build related files that matter.

The first is micropython.cmake, which is how the driver gets pulled into a MicroPython build rather than being an importable package you pip install. The second is uncrustify.cfg, the formatter configuration, which tells you the project expects its C style to be checked rather than improvised.

Inside examples/ you will find hello.py, scroll.py, paint.py, cfg_helper.py, a st7789.pyi type stub so editors can suggest the API, and directories for specific tasks including jpg/, png/, mono_fonts/, chango/, clock/, proverbs/ and configs/. The configs directory is the one to look at first when you own a particular board, because it holds the init parameters for the supported devices.

The fonts directory carries its own README.md explaining the font files, and the driver can freeze those fonts into the firmware so text drawing does not depend on the filesystem. That is the central design decision of the project: it is a firmware level driver, and the MicroPython build is part of the installation rather than an optional extra.

## Installing the build environment on Ubuntu 20.04.2

The README documents the build environment for Ubuntu 20.04.2, and points readers to the MicroPython ESP32 README for anything that is not directly related to the st7789 driver, warning that the recommended MicroPython build instructions may have changed since the text was written.

The first step is bringing a fresh Ubuntu install up to date, which the README covers for a new install or for the Windows Subsystem for Linux.

```bash
sudo apt-get -y update
sudo apt-get -y upgrade
```

After that, the toolchain packages needed to compile MicroPython and the driver.

```bash
sudo apt-get -y install build-essential libffi-dev git pkg-config cmake virtualenv python3-pip python3-virtualenv
```

Those packages cover the compiler toolchain, Python packaging, CMake and Git, which is what the CMake based MicroPython build expects. If a build fails for a reason that has nothing to do with the display code, the README is explicit about where to look: the MicroPython ESP32 port documentation, rather than the st7789 issues.

The important expectation to set before you start is that this is a source build of MicroPython itself. You are not installing a wheel and importing a module. The driver is compiled into a firmware image that you then flash onto the board, and the pre-compiled images described later in this article exist precisely to save you that work for common targets.

## Fetching esp-idf v4.4 for a MicroPython compatible SDK

MicroPython for ESP32 is built against Espressif's ESP-IDF, and the README quotes the MicroPython documentation noting that the ESP-IDF changes quickly and that MicroPython supports specific versions, currently v4.0.2, v4.1.1 and v4.2, though other v4 versions may also work. The author reports having had good luck with IDF v4.4, and the firmware section confirms the shipped images were compiled with ESP IDF v4.4.4 using CMake.

Cloning the SDK with its submodules takes several minutes, which the README mentions up front.

```bash
git clone -b v4.4 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf/
git pull
```

If you already have a copy of the IDF, the README gives the shortcut for switching a checkout to a compatible version and refreshing the submodules.

```bash
$ cd esp-idf
$ git checkout v4.4
$ git submodule update --init --recursive
```

The version pin is the part to get right. IDF moves quickly, and a newer SDK can produce a build that fails for reasons that look like driver bugs. Pinning to v4.4 keeps you inside the combination the project actually shipped against, which is the difference between a first build that works and an afternoon spent reading linker errors.

## cfg_helper.py and the colstart, rowstart problem

A ST7789 panel is rarely as simple as its resolution suggests. Some use a BGR colour order, some invert colours, and many have a frame buffer larger than the physical matrix, which means the driver must be told where the first visible column and row sit inside that buffer.

The README describes a quick test for colour order: fill the display with st7789.RED and look at what appears. Red means the settings are right, blue means color_order should be st7789.BGR, yellow means inversion_mode should be True, and cyan means both are needed. The cfg_helper.py program in the examples directory is the tool for working out these values along with colstart and rowstart.

The 128x128 st7735 example given in the README shows the shape of the answer.

```python
inversion_mode(False)
color_order = st7789.BGR
for rotation 0 use offset(2, 1)
for rotation 1 use offset(1, 2)
for rotation 2 use offset(2, 3)
for rotation 3 use offset(3, 2)
```

Each rotation can need different offsets, which is why the offsets method has to be called after any rotation calls rather than before. The driver sets colstart and rowstart automatically for common 135x240, 240x240, 170x320 and 240x320 displays, and the offsets method exists for the panels where those defaults are wrong. For a 128x160 st7735 panel the same README entry shows all four rotations using offset(0, 0), which is the easy case.

## Drawing text and images, and the JPEG slow mode

Text rendering is the reason most people pick this driver over the original, and it comes in three flavours. Bitmaps converted from True Type fonts let you use a real typeface. Bitmap fonts at 8 and 16 bits wide cover the classic text mode look. Hershey vector fonts give a third option that scales without the blocky edges of a bitmap. The package includes 12 bitmap fonts derived from classic PC text mode fonts and 26 Hershey vector fonts, and the font files can be frozen into the firmware.

Image drawing is where the memory constraints bite. PNG support comes through the pngle library, so PNG files can be placed on screen directly. JPEG support is built on TJpgDec, the Tiny JPEG Decompressor R0.01d from elm-chan. The addition the author made to the original driver is a SLOW mode, which exists so that JPEG images larger than the available RAM can still be drawn.

That mode is the interesting engineering decision in the project. Display controllers typically hold the frame buffer in the microcontroller's RAM, so a full screen image on a 240 by 320 panel does not fit comfortably alongside the interpreter on a small ESP32. Rather than refuse large images, the SLOW path decompresses them in pieces and paints them as it goes. The cost is time rather than feasibility, which is exactly the trade you want for a splash screen or a logo that must appear on a board with a few hundred kilobytes of free heap.

The examples directory includes a jpg/ folder and a png/ folder, plus mono_fonts/, noto_fonts.py and font_decode.py for working with font data, so the supported paths are visible before you write anything.

## Pre-compiled firmware for the boards people actually own

The firmware directory holds pre-compiled images that already contain the st7789 C driver and frozen Python font files, and it is the fastest way to get started. The README states the images are MicroPython v1.20.0 compiled with ESP IDF v4.4.4 using CMake, which pins the exact combination if you later rebuild from source and want to match.

Coverage is broad enough to cover most hobby boards: GENERIC-7789 for generic ESP32 devices, GENERIC_SPIRAM-7789 for ESP32 boards with SPI RAM, GENERIC_C3 for ESP32-C3 devices, LOLIN_S2_MINI for the Wemos S2 mini, PYBV11 as firmware.dfu for the Pyboard v1.1 (marked as no PNG), RP2 and RP2W as firmware.uf2 for the Raspberry Pi Pico and PicoW, T-DISPLAY for the LILYGO TTGO T-Display, T-Watch-2020 for the LILYGO T-Watch 2020, and WIO_TERMINAL for the Seeed Wio Terminal. Note the file formats differ by upload method, with dfu for the Pyboard and uf2 for the Pico.

Two additional modules are pulled in from outside the repository: axp202c from the AXP202X_Libraries project, and focaltouch from a GitLab repository for T-Watch 2020 with microphone support. Those are separate sources with their own maintenance histories, so a build that depends on them depends on code you did not clone here.

The README also links video walkthroughs for specific scripts, including PYBV11 hello.py and scroll.py, T-DISPLAY fonts.py, hello.py, scroll.py and roids.py, and TWATCH-2020 draw.py, hello.py, bitmap.py and watch.py.

## A custom licence, no releases, and a README that says work in progress

Two facts should shape any adoption decision. The first is the licence. GitHub classifies it as Other, a custom licence that the platform cannot categorise, and the README does not summarise its terms. You need to read the LICENSE file in the repository root yourself before you copy this driver into a product, and this review makes no claim about what those terms allow beyond pointing you there.

The second is the release record. The repository has no GitHub releases, so there is no versioned artefact to pin, no changelog to diff against, and no upgrade path that does not involve rebuilding from a branch. The last push was on 2026-07-21. The README itself closes its feature list with the sentence that this is a work in progress, and the credits list a single maintainer alongside acknowledgements to devbis for the original driver, hklang10 for the new mp_raise_ValueError(), and aleggon for the correct offsets for 240x240 displays and for discovering issues compiling STM32 ports.

Those acknowledgements are informative about how issues are found. Offsets for a given panel size were contributed by a user who owned that panel, and STM32 build problems surfaced the same way. There is no hardware lab behind this project, so a configuration that works for one owner of a 240x240 panel may need your own adjustment, and there is no compatibility matrix to consult. That is the real cost of the project: for boards it has been exercised on, it saves an afternoon of work, and for everything else, you are the test case.

## Conclusion

st7789_mpy suits MicroPython developers who want fast C level drawing on cheap ST7789, ST7735, ILI9341 or ILI9342 panels and who are comfortable compiling MicroPython from source, and it does not suit teams wanting a batteries included library, a tagged release, or a plainly classified licence. Before adopting it, read the LICENSE file yourself, because GitHub cannot classify it, and pick either the pre-compiled firmware.bin, firmware.dfu or firmware.uf2 for your exact board or build the C driver yourself against esp-idf v4.4 with the MicroPython build instructions, which the README warns may have changed.

## FAQ

### What does st7789_mpy add compared with the original devbis ST7789 driver?

The fork adds display rotation, scrolling, text from True Type converted bitmaps, 8 and 16 bit wide bitmap fonts, Hershey vector fonts, JPEG drawing with a SLOW mode for images larger than available RAM, PNG drawing through the pngle library, polygon and filled polygon drawing with rotation, bounds tracking, and a custom init capability for st7735, ili9341 and ili9342 displays.

### How do I install st7789_mpy on an ESP32 board?

The driver is compiled into MicroPython rather than installed as a package, so you either flash one of the pre-compiled images in the firmware directory, which were built with MicroPython v1.20.0 and ESP IDF v4.4.4, or you build MicroPython from source with the C driver included, using an esp-idf v4.4 checkout and the toolchain packages listed in the README.

### Why does my ST7789 screen show the wrong colors or a shifted image?

The driver may need a different colour order or inversion mode, and panels whose frame buffer is larger than the visible matrix need colstart and rowstart offsets, which vary by rotation. The README describes testing with a st7789.RED fill and using the cfg_helper.py example program to determine color_order, inversion_mode, colstart and rowstart, with the offsets method called after rotation calls.

### What licence does st7789_mpy use?

GitHub classifies the licence as Other, a custom licence it cannot categorise, and the terms are in the LICENSE file at the repository root rather than in the README. The repository also has no GitHub releases, so there is no published version to upgrade from.

## Sources

- [Issues](https://github.com/russhughes/st7789_mpy/issues)
- [README](https://github.com/russhughes/st7789_mpy/blob/master/README.md)
- [russhughes/st7789_mpy on GitHub](https://github.com/russhughes/st7789_mpy)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/russhughes-st7789-mpy
