Anyway to stop flickering during update on ILI9341 display ?

Status
Not open for further replies.

skpang

Well-known member
I'm using a 2.8" ILI9341 LCD on Teensy 4.0
To update a counter I first fill a rectangle with the background colour to erase the old number the print the new number.
There is alway a small annoying flicker on the screen. I think is the fill then redraw.

Is there any way to remove the flicker ?

Code:
#include "SPI.h"
#include "ILI9341_t3.h"
#include <font_liberationSansBold.h>

#define TFT_DC  9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

int i;

void setup() {

  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLUE);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setFont(LiberationSans_60_Bold);
    
  i = 1234;
}

void loop() {
  
      tft.fillRect(0,0,185, 80,ILI9341_BLUE);  // Remove the old text
      tft.setCursor(0,16);
      tft.println(i++);

      delay(1000);
}
 
Not with the ILI9341_t3 lib. You can try the ILI9341_t3n lib and use framebuffer. That helps big time to stop flickering. You basically do a tft.useFrameBuffer(1) //turnon then do a tft.updateScreen() before your delay(1000) and the flickering should disappear.
 
As @mjs513 mentioned, the library ili9341_t3n does provide a few different ways to handle this.

The easiest is to use frame buffer.

I am trying to remember if some of the stuff I did earlier made it back into ili9341_t3 library. In particular support for opaque fonts. ili9341_t3 does have support for opaque system font, just don't think it does for some of these other fonts.

Assuming it does, what you can do, is to do something like:
Code:
#include "SPI.h"
#include "ILI9341_t3.h"
#include <font_liberationSansBold.h>

#define TFT_DC  9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

int i;

void setup() {

  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLUE);
[COLOR="#FF0000"]  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLUE);[/COLOR]
  tft.setFont(LiberationSans_60_Bold);
    
  i = 1234;
}

void loop() {
  
     [COLOR="#FF0000"] //tft.fillRect(0,0,185, 80,ILI9341_BLUE);  // Remove the old text[/COLOR]
      tft.setCursor(0,16);
      [COLOR="#FF0000"]tft.print(i++);[/COLOR]  // was println
     [COLOR="#FF0000"] tft.fillrect(tft.getCursorX(), 0, 185, 80, ILI9341_BLUE);  // blank out from end of what was drawn to end of field[/COLOR]   

      delay(1000);
}
Again I don't know if the transparent font works here.

Also depending on what else you may draw, the opaque will draw blue through to the next logical line spacing in Y direction, which can be large. If not desired, ili9341_t3n, then has the ability to set a clip rectangle to limit how much of the display will be updated.

Also this can be semi optimized some, with the last fillRect to blank out any remaining previous text. You could remember the text cursor at the end of the previous drawing and only if the new text cursor X is < than the previous one do you do any blanking and only from the current cursor X to previous ending cursor x. Hope that makes sense.
 
@mjs513 Using frame buffer works. No flicker on screen now.

@KurtE Using opaque fonts also works.

Now I have choice of which one to use. I will continue with my project.

Thanks for everyone's help.
 
My guess is using the TE (Tear effect) signal is to solve a very specific issue.

The one at the start of this thread was for how to write the code as to avoid the flicker.

They were getting a flicker as it was doing exactly what they asked it to do:
Code:
      tft.fillRect(0,0,185, 80,ILI9341_BLUE);  // Remove the old text
      tft.setCursor(0,16);
      tft.println(i++);
First write blue pixels over everything and then write the new text, so you will see pixels going from yellow to blue back to yellow and as such flicker.

Looks like there are a few different solutions that work given in this thread, which is great.

KrisKasprzak - Your library looks interesting, especially for those who don't have code setup...
What I have done in the past, is to not necessarily keep the previous text string, but sometimes simply keep bounding rectangle of the last time I output a logical field.
Note: with some of our libraries there will be issues with you intercepting the string character by character.
That is some libraries have the ability now to center the text.

Example our current ST7735_t3 code has stuff in it that allows you to do:
setCursor(x, y, true);
And the optional true says to center the text at the x, y position.
We also have the ability to set the x and/or y to center at center of screen setCursor(ST7735_T3::CENTER, y)
Will center the text in the x direction with starting y of the given y...

And the underlying code uses this for the next text output...

But that is probably beyond the scope of this issue.
 
Maybe I am too stupid, but for me it is simple. Set TE to operate as mode 1, vsync.
Prepare a frame buffer in RAM to operate on. Write whatever to the buffer. If TE flank high, copy the changed part of buffer to the screen. And write whatever to framebuffer, if TE high write changes to screen,....
 
@kurtE, yea...i had a heck of a time trying to determine when to update, and i could only get compairing to the old value to be reliable. Saving the old val, i can check each character. My challenge was painting, the lib did not have a width given an array of chars, hence the cursorX deal. I'm guessing this lib will not be portable to other display drivers.

@radius. I guess I'm the stupid one, i can't figure out what you are suggesting. code and a diagram would help.
 
On my cellphone, I had to do complete screen rewrites and some those would take over a couple seconds. Looked horrible. So I just, between refreshes, turned off the backlight, then brought it back up slowly after the redraw. Then it "looked" great!

-jim lee
 
Status
Not open for further replies.
Back
Top