logo elektroda
logo elektroda
X
logo elektroda

How to program SmallTV-Ultra in PlatformIO? Running TFT ST7789 with Adafruit and directly

p.kaczmarek2 4335 3

TL;DR

  • SmallTV-Ultra uses a 2.5-inch 240x240 ST7789 display with an ESP8266 in PlatformIO, aiming at a clock, weather station, or other gadget.
  • The tutorial shows two driving methods: Adafruit_GFX with Adafruit_ST7789, or direct SPI control without external display libraries.
  • The ST7789 requires SPI MODE3, and the code alternates ST77XX_RED and ST77XX_GREEN on the 240x240 panel.
  • Adafruit support adds text, formatted numbers, RGB565 colours, and an NTP-based clock that refreshes only when the minute changes.
  • Bit-banging the display was too slow, so hardware SPI.transfer was used; the direct approach remains mostly a curiosity.
Generated by the language model.
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 Listen (AI):
  • Small display showing time and date. .
    Here is a short tutorial showing how to run a 2.5" 240x240 ST7789 display with an ESP8266. I will present here two separate ways, the first will be based on a library from Adafruit and the second will come down to running the TFT without external libraries. In this way, I am preparing the basis for building my own clock/weather station or any other gadget with a display based on SmallTV-Ultra.

    Let me remind you of the previous topic:
    [Polish] SmallTV-Ultra that is a small display on ESP8266 showing weather forecast, photos, animations .
    [English] SmallTV-Ultra which is a small display on ESP8266 showing weather forecast, pictures, animations .

    In this theme I will use PlatformIO , which is an add-on for Visual Code. I've presented this platform before, and I'll start the adventure with my typical code including ArduinoOTA (batch updates via WiFi) and WiFiManager (WiFi configuration):
    [Polish] How to program a Wemos D1 (ESP8266) board in the shape of an Arduino? ArduinoOTA in PlatformIO .
    [English] How to program the Wemos D1 (ESP8266) shaped Arduino board? ArduinoOTA in PlatformIO .
    [Polish] WiFi Manager in PlatformIO - convenient WiFi configuration for ESP8266 and ESP32 - tutorial
    [English] WiFi Manager in PlatformIO - convenient WiFi configuration for ESP8266 and ESP32 - tutorial

    Startup with Adafruit_ST7789 .
    Adafruit offers an off-the-shelf solution to support this display, but you must first configure it properly.
    Install first Adafruit_GFX (common graphics base) and then Adafruit_ST7798 :
    PlatformIO search window with adafruit gfx query. .
    In the software we define the pins, in the case of this board these are:
    Code: C / C++
    Log in, to see the code
    .
    SPI is hardware based, so we do not need to define these pins. We create a TFT object:
    Code: C / C++
    Log in, to see the code
    .
    We also need to run it - here it is important to set the SPI MODE3 mode, that is, with polarity (CPOL) = 1 and phase (CPHA) = 1. This means that the clock signal starts from a high state and the data is transmitted on a rising edge.
    Code: C / C++
    Log in, to see the code
    .
    I alternate the screen between two colours for demonstration in a loop:
    Code: C / C++
    Log in, to see the code
    .
    ST77XX_RED and ST77XX_GREEN are predefined colour values from the presented library, later I will show how to generate my own RGB.
    Full code:
    Code: C / C++
    Log in, to see the code
    .
    Result:
    Animated display changing colors .

    Text from Adafruit_ST7789 .
    The library from Adafruit, however, offers much more. For example, it already has fonts uploaded, so you can also display text. First position the cursor on the screen, and then display the subtitles one by one. You can also display a number. Everything is done automatically, the cursor also moves itself.
    Code: C / C++
    Log in, to see the code
    .
    Here is an example program displaying some random temperature value on the screen:
    Code: C / C++
    Log in, to see the code
    .
    Result:
    2.5 display showing temperature 25.6°C


    Colours from Adafruit_ST7789 .
    However, let's not forget that this display is in colour. The function tft.colour565 creates a 16-bit colour code for R, G and B data from the ranges [0,255]. For demonstration purposes, I have developed a simple colour loop generation based on sine functions:
    Code: C / C++
    Log in, to see the code
    .
    Result:
    LCD display changing colors from blue to green .


    The clock from Adafruit_ST7789 .
    You can also create a simple clock. We will need a client for the NTP service, or Network Time Protocol. It will retrieve the current date and time from the Internet. We install the NTPClient:
    PlatformIO user interface with a search for the NTPClient library. .
    In addition, we similarly install TimeLib to be able to process time more conveniently and extract a bit more information from the time_t type.
    We include the headers:
    Code: C / C++
    Log in, to see the code
    .
    We create objects:
    Code: C / C++
    Log in, to see the code
    .
    In the constructor, the address of the NTP server from which we retrieve the time is given. It remains to run the client:
    Code: C / C++
    Log in, to see the code
    .
    and updating it:
    Code: C / C++
    Log in, to see the code
    .
    Now the time needs to be displayed. In order to reduce screen flashing, I added a condition in the refresh so that it only executes when the current minute changes. I retrieve the time from the NTP client in epoch form (time_t) and then extract the individual date and time values from it.
    Code: C / C++
    Log in, to see the code
    .
    It is worth noting the use of tft.printf, this function allows you to format the displayed text just like a normal printf. These 02 means that we want two-digit values.
    The result:
    Small display showing time and date. .
    The full downloadable project is at the end of the topic.


    Implementation without external libraries .
    In the previous topic I presented an example code from the display manufacturer itself. Here I have transferred this code to PlatformIO. I changed the port operations to digitalWrite and the SPI data transfer itself I moved to the hardware SPI.transfer. Initially, I also tried sending data fully programmatically, via bit-banging (operations on IO pins), but this was so inefficient that I even had to increase the watchdog time to prevent it from resetting the chip.... I quickly let it go, it's unnecessary fun when we have hardware SPI.
    Code: C / C++
    Log in, to see the code
    .
    The example developed just turns on the backlight and colours the screen alternating between two selected colours.
    The result:
    Green display with connected wires on a breadboard. .

    Summary .
    This makes it easy to run SmallTV-Ultra in PlatformIO. I've actually shown two ways to do this here, although I treat the second one more as a curiosity - in its case we would probably have to implement drawing shapes, lines as well as displaying text ourselves. Much easier is the first way, which is a ready-made library from Adafruit - there is even a built-in font there.
    Now, it would be possible to develop the example shown here and enrich it for example with temperature reading from OpenWeatherMap, so as I once showed , or simply connect DHT11, and maybe some buzzer and buttons?
    Do you have any ideas what could be done with this screen in the next part, what to add, what to make up? Feel free to comment.
    Attachments:
    • TVultra-20250325.zip (2.91 MB) You must be logged in to download this attachment.

    Cool? Ranking DIY
    Helpful post? Buy me a coffee.
    About Author
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    p.kaczmarek2 wrote 14418 posts with rating 12376, helped 650 times. Been with us since 2014 year.
  • ADVERTISEMENT
  • #2 21495513
    viayner
    Level 43  
    Posts: 10558
    Help: 1557
    Rate: 2006
    Hello,
    perhaps a small comment
    "without external libraries" - after all, what you yourself have written in the form of lines of code is just there in the library in question, so there is practically no difference.
    I've done that myself many times and do if either there is no library or it's written sloppily (unfortunately a fair amount is).
    Regards
  • ADVERTISEMENT
  • #3 21496766
    krzbor
    Level 29  
    Posts: 1731
    Help: 40
    Rate: 1044
    Have you tested the TFT_eSPI library?
  • #4 21504707
    EmperorProdigy
    Level 4  
    Posts: 7
    Hi - this was extremely helpful thank you! Just a small note, for me the arduino IDE would not recognize what is pin "D1" in the command #define TFT_BACKLIGHT D1 so to fix that i replaced that with the appropriate GPIO pin, so #define TFT_BACKLIGHT 5
📢 Listen (AI):

FAQ

TL;DR: For ESP8266 users driving a 240x240 ST7789 on the 2.5-inch SmallTV-Ultra, the fastest path is Adafruit_ST7789 in PlatformIO: define 4 pins, initialize with SPI_MODE3, and "set the SPI MODE3 mode" to avoid a black screen. This FAQ shows both the library method and direct SPI writes, plus text, colors, clock code, and common pin-name fixes. [#21494759]

Why it matters: This thread gives a working, repeatable setup for turning a SmallTV-Ultra into a clock, weather display, or other ESP8266 gadget without guessing the ST7789 wiring or SPI mode.

Method Graphics features Setup effort Key requirement Best use
Adafruit_ST7789 + Adafruit_GFX Built-in text, colors, screen fill Lower tft.init(240, 240, SPI_MODE3) Fast project start
Direct hardware SPI writes Raw commands and full-screen color fill Higher Manual init sequence + SPI writes Learning or custom low-level control

Key insight: The most important fix is not the library choice; it is correct ST7789 initialization on ESP8266, especially SPI_MODE3 and the right GPIO mapping. Once those match the board, both approaches work. [#21494759]

Quick Facts

  • The display shown is a 2.5-inch ST7789 panel running at 240x240 pixels on an ESP8266 SmallTV-Ultra board. [#21494759]
  • The working Adafruit pin map is TFT_CS = 4, TFT_RST = 2, TFT_DC = 0, and TFT_BACKLIGHT = D1; one user confirmed replacing D1 with GPIO 5 fixed Arduino IDE pin recognition. [#21504707]
  • The direct SPI example starts a transaction at 1,000,000 Hz, MSBFIRST, SPI_MODE3, then fills the whole 240 x 240 region with 16-bit color values. [#21494759]
  • The clock example updates from pool.ntp.org every 60,000 ms and redraws only when the minute changes to cut visible flashing. [#21494759]

How do I program the SmallTV-Ultra ST7789 display in PlatformIO on an ESP8266 using the Adafruit_GFX and Adafruit_ST7789 libraries?

Use PlatformIO with Adafruit_GFX, Adafruit_ST7789, SPI, ArduinoOTA, and WiFiManager, then initialize the display as a 240x240 ST7789 in SPI mode 3. 1. Define the four display pins. 2. Create Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);. 3. In setup, enable the backlight and call tft.init(240, 240, SPI_MODE3);, tft.setRotation(0);, and tft.fillScreen(ST77XX_BLACK);. After that, you can draw colors, text, or a clock while OTA and Wi-Fi continue running in the loop. [#21494759]

What pin definitions should I use for TFT_CS, TFT_RST, TFT_DC, and TFT_BACKLIGHT on the SmallTV-Ultra board with ESP8266?

Use TFT_CS 4, TFT_RST 2, TFT_DC 0, and TFT_BACKLIGHT D1 on the SmallTV-Ultra example board. In the same thread, a follow-up confirms that replacing D1 with the raw GPIO number also works, so TFT_BACKLIGHT 5 is a practical equivalent when an IDE does not understand board-style pin names. This mapping matches the working Adafruit example for the ESP8266 ST7789 setup. [#21504707]

Why does the ST7789 on SmallTV-Ultra need SPI_MODE3, and what do CPOL and CPHA mean in this setup?

The working setup uses SPI_MODE3 because this ST7789 wiring expects clock polarity and phase both set to 1. In this configuration, "CPOL and CPHA" are SPI timing parameters that define the idle clock level and the edge used for data capture, with MODE3 meaning idle-high clock and rising-edge transfer behavior as described in the thread. If you use the wrong SPI mode, the screen may stay black or show corrupted output even when the wiring is correct. [#21494759]

How can I display text on a 240x240 ST7789 screen with Adafruit_ST7789, including numbers like temperature values?

Set the text color and size once, position the cursor, and print strings and numbers in sequence. The example uses tft.setTextColor(ST77XX_WHITE);, tft.setTextSize(2);, and tft.setCursor(30, 100);, then prints "Temp: ", a floating value, and " C". The sample generates a fake temperature from 20.0°C upward using 20.0 + (rand() % 100) / 10.0, so values change in 0.1°C steps and redraw every 2000 ms. [#21494759]

What is NTPClient, and how is it used with WiFiUDP and TimeLib to show a clock on an ESP8266 TFT display?

NTPClient is used to fetch Internet time so the ESP8266 can draw a live clock without a separate RTC chip. "NTPClient is a time-synchronization library that queries an NTP server over UDP, returns epoch time, and lets an embedded device keep current date and time with periodic network updates." In the example, WiFiUDP ntpUDP; and NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000); are paired with TimeLib to extract hour, minute, day, month, and year from time_t. [#21494759]

How do I reduce screen flicker on an ST7789 clock display by refreshing only when the minute changes?

Store the previous minute and skip drawing until the new minute differs from the last one. The example reads epoch time, extracts minutes, and returns immediately when prev_min == minutes. That prevents unnecessary full-screen clears and redraws during the other 59 seconds of the minute. When the minute changes, it redraws the black background, then prints the time in text size 7 and the date in text size 2. [#21494759]

What's the difference between driving the ST7789 through Adafruit_ST7789 and writing directly to the display over SPI without an external graphics library?

Adafruit_ST7789 gives you ready-made drawing functions, built-in fonts, and easier text output, while direct SPI code gives low-level control but requires manual command and color handling. The author treats the direct method as more of a curiosity because you would still need to implement shapes, lines, and text yourself. A forum reply also notes that handwritten low-level code is functionally similar to what a display library already wraps, so the real difference is convenience and maintenance effort. [#21495513]

How can I generate custom RGB colors on an ST7789 using the Adafruit color565 function?

Generate 8-bit red, green, and blue values, then convert them to the display’s 16-bit format with tft.color565(r, g, b). The example uses three sine waves with a phase offset, such as sin(x * 0.05), to create smoothly changing uint8_t values in the 0-255 range. It then fills the full screen with the converted color on each loop iteration, producing a continuous RGB transition effect. [#21494759]

Why might Arduino IDE not recognize D1 in '#define TFT_BACKLIGHT D1', and how do I replace it with the correct GPIO number?

Arduino IDE may not recognize D1 when the selected board definition does not expose NodeMCU-style aliases. In that case, replace the symbolic pin name with the raw ESP8266 GPIO value used by the board. The working fix reported in the thread is #define TFT_BACKLIGHT 5, which maps the SmallTV-Ultra backlight control from D1 to GPIO 5 directly. That change solved compilation for that user without altering the rest of the display code. [#21504707]

What is PlatformIO, and why would I use it instead of the Arduino IDE for an ESP8266 display project?

PlatformIO is a Visual Studio Code add-on used here to build, manage libraries, and deploy ESP8266 display projects more cleanly than a basic Arduino IDE sketch workflow. The author uses it together with ArduinoOTA for Wi-Fi updates and WiFiManager for network setup, which makes repeated testing easier. For this project, PlatformIO keeps the ST7789 libraries, OTA support, and NTP clock code in one structured environment instead of a single flat sketch. [#21494759]

How do I initialize the ST7789 manually over hardware SPI on ESP8266, including reset, command writes, and setting the display region?

Initialize it by resetting the panel, sending the ST7789 command sequence, and defining the drawing window before writing pixel data. 1. Configure GPIO pins, call SPI.begin(), and start SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));. 2. Pulse RESET_PIN low for 10 ms, then high for 10 ms, and send init commands like 0x36, 0x3A, 0x11, and 0x29. 3. Use Lcd_SetRegion(0, 0, 239, 239) and stream 16-bit colors with LCD_WriteData_16Bit(). This produces a full-screen fill on the 240x240 panel. [#21494759]

Why is bit-banging the ST7789 on ESP8266 so slow compared with hardware SPI, and how does it affect the watchdog timer?

Bit-banging is slow because the ESP8266 must toggle every pin in software for every transferred bit, while hardware SPI shifts bytes automatically. The author says the software-driven version was so inefficient that the watchdog time had to be increased just to stop resets. That is a strong failure case: low-level GPIO toggling can consume enough CPU time to trigger watchdog problems, while SPI.transfer() avoids that overhead and keeps updates practical. [#21494759]

How does the TFT_eSPI library work with SmallTV-Ultra and the ST7789 in PlatformIO compared with Adafruit_ST7789?

The thread does not provide a tested TFT_eSPI configuration for SmallTV-Ultra; it only asks whether that library has been tested. Because no code, pin file, or working result follows, the thread supports Adafruit_ST7789 as the confirmed library path and leaves TFT_eSPI as an unverified alternative. If you need a proven setup from this discussion alone, use the Adafruit method rather than assuming TFT_eSPI compatibility. [#21496766]

What troubleshooting steps help when an ST7789 screen stays black or the backlight behaves incorrectly on a SmallTV-Ultra ESP8266 build?

Check SPI mode, pin mapping, and backlight polarity first. A black screen often means the panel was not initialized with SPI_MODE3, while a backlight issue can come from using D1 instead of GPIO 5 in an IDE that lacks alias support. Also verify that the code actually drives the backlight pin, because the examples use both digitalWrite(TFT_BACKLIGHT, 0) and later explicit backlight toggles. If the direct SPI method shows nothing, confirm the 240x240 region and command sequence ran after reset. [#21504707]

What are some practical next features to add to a SmallTV-Ultra project, such as OpenWeatherMap, DHT11, buttons, or a buzzer?

The next practical upgrades are weather data, local sensors, and simple user input or alerts. The author explicitly suggests extending the display with OpenWeatherMap temperature readings, attaching a DHT11, and adding buttons or a buzzer. Those features fit the demonstrated base well because the thread already shows Wi-Fi setup, OTA updates, NTP time, text rendering, and full-screen color changes on the same ESP8266 platform. [#21494759]
Generated by the language model.
ADVERTISEMENT