Sending multiple commands to ST7789 display

Hi! I have two ST7789 displays with SPI interface. I want to make a speedometer for my e-bike and display some info on them like speed, time, distance, throttle gauge, etc. When composing all this data I was executing functions one by one like:

tft.fillScreen(ST77XX_BLACK);
tft.drawCircle(220, 220, 175, ST77XX_BLUE);
tft.drawCircle(220, 220, 176, ST77XX_BLUE);
tft.drawCircle(220, 220, 177, ST77XX_BLUE);
tft.setCursor(20, 220);
tft.print("0");
tft.setCursor(200, 20);
tft.print("100");
tft.setCursor(75, 75);
tft.print("50");
tft.setCursor(75, 180);
tft.print("Bat: "); lcd.print(Vbatt);
drawGauge();

But it's causing a lot of flickering display is updating after each function and adding text/figures one at a time. Is there any way to "pre-make" a 128x160 canvas (like, make an image of everything above) on arduino, and then send it as a bitmap to display? I have UNO, Nano, ESP32-CAM, ESP32-WROVER, ESP8266

As I understand it, that display supports 1-bit, 8-bit, and 16-bit interfaces. Consider using the 16-bit interface for better performance. Check this link for more information: PJRC Forum - Fastest Possible SPI Speed/Refresh Rate on a ST7789.

Sorry, I made a mistake: flickering because display is updating after each function. I wonder if it's possible to make it work like SSD1306 when you call everything you want to display and then send the whole buffer with display.display()

I’m not familiar with that part, but it sounds like it will solve your flickering problem. You didn’t mention which Arduino you’re using, so I assume you may be low on RAM. There are 32K x 8 FRAM modules available for just a few dollars, and they operate at processor speed. Both SPI and I2C versions are available.

I can use UNO (2Kb RAM), ESP32-WROOM (520Kb RAM) or ESP8266 (82Kb)

Framebuffer will be around 21Kb (128*160, uint8_t)

The UNO does not have enough ram internally so you would have to add it externally, that will slow it down. The other two appear to have enough.

Sorry, there is not enough information here to give a complete answer, like
what libraries are you using? The Adafruit one? Guessing... Did you set a font or are
you using the default font or set a specific one, etc... How many colors are you using?

Also would help to see an image of your actual output.

But will mention a few approaches.

Anytime you redraw a display, that starts off with:
tft.fillScreen(ST77XX_BLACK);
It will typically flicker a lot...

Approaches:

  1. Using some form of Framebuffer - with the Adafruit libraries you can use their
    Canvas objects. If you are only two colors, you could use the GFXcanvas1, which
    only uses 1 bit per pixel. But even that would take about 2.5K for the buffer so UNO
    with 2k would not work. The Adafruit GFX library has a demo app for using Canvas.

  2. Do smarter updates of the screen. That is, if all you are wanting to do is
    to output updated speed, and lets say that is your value at 75, 75.
    You could simply just update that portion of the display.
    a) if Adafruit and default font and things not overly packed on screen, you could
    use Opaque text output, where the bits of the character being output that are not
    in the actual character they will be drawn in the background color. Only caveat, is
    if the new output is shorter than previous output... But if enough room and
    output is still left justified you can do something like:

void update_speed(int speed) {
    tft.setTextColor(ST77XX_BLUE, ST77XX_BLACK); // assuming text in blue and background black.
    tft.setCursor(75, 75);
    tft.print(speed);  // output new speed.
    tft.print("  "); // print a couple of blanks to cover any previous data.
}

Warning typed on fly so could have issues.
You also have lots of options on how these numbers are output. I showed quick and
dirty left justified. You could instead do right justified, by computing how many
characters will be output, and proceed by the number of blanks needed. ...

b) if you are not using system font, and don't have opaque capability, you could eiath
b1) do a fillRect of an area sufficient to take care of your previous output number. note: don't need to output blank characters.
b2) like b1) except use something like tft.getTextBounds to know exact area your previous
output was drawn and only clear that amount.
b3) use a Canvas object just big enough for one text field, and do your output for that updated value into canvas and then draw the canvas data to the screen at the position
of the value.

Hope this gives you a few ideas
Good luck

Thanks everyone for ideas! I ended up using ESP32 and TFT_eSPI library. It supports framebuffer and DMA

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.