[solved]Flickering TFT screens using ESP32

Flickering TFT screens using ESP32

ESP32: https://www.aliexpress.com/item/1005005972312714.html?spm=a2g0o.order_list.order_list_main.40.37151802nWHxEy
TFT screens : https://www.aliexpress.com/item/1005007522838485.html?spm=a2g0o.order_list.order_list_main.22.37151802nWHxEy

The 3 screens are connected in this way:
First screen CS - pin 15
Second screen CS - pin 21
Third screen CS - pin 22

And all 3 have this common pins:
VCC - 3V3
GND - GND
SCL - pin 18
SDA - pin 23
DC - pin 2
RST - pin 4

The User_Setup.h is like this:


//                            USER DEFINED SETTINGS

#define GC9A01_DRIVER

// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation

#define TFT_DC   2  // Data Command control pin
#define TFT_RST  4  // Reset pin (could connect to NodeMCU RST, see next line)

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT


// #define SPI_FREQUENCY   1000000
// #define SPI_FREQUENCY   5000000
// #define SPI_FREQUENCY  10000000
// #define SPI_FREQUENCY  20000000
#define SPI_FREQUENCY  27000000 // Actually sets it to 26.67MHz = 80/3
// #define SPI_FREQUENCY  40000000
// #define SPI_FREQUENCY  80000000

// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY  20000000

// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY  2500000

The problem is that all 3 screens flicker constantly and I don't know what the cause would be.

Code: Untitled (wg0jvmko) - PasteCode.io

Hi misterdanny,

I have three GC9A01 circular 240*240 displays working, flicker free, driven by an ESP32WROOM-32.
My questions to you:

  1. do you compile under the TFT_eSPI library ?
  2. What flickers? Do you run animations?
  3. Can you post your entire sketch? That may lead to some suggestions to get rid of your flicker experience.
    regards, photoncatcher
1 Like
  1. Yes
  2. I don't run animations, only some text that is updated every 3 seconds. Video: Unique Download Link | WeTransfer
  3. All my code is here : Untitled (wg0jvmko) - PasteCode.io and all my connections are in the main post.
    Do you need more info?

Code:

#include <WiFi.h>

#include <HTTPClient.h>
#include <TFT_eSPI.h>
#include <SPI.h>        // Include SPI library
#include <ArduinoJson.h>
#include <time.h>
#include "icons.h"  // Include the file that contains the cloud icon

// TFT screen settings
#define TFT_WIDTH 240
#define TFT_HEIGHT 240

#define firstScreenCS 15
#define secondScreenCS 21
#define thirdScreenCS 22

TFT_eSPI tft = TFT_eSPI();

const char* ssid = "";   // Wi-Fi SSID
const char* password = "";  // Wi-Fi password

// WeatherAPI details
const String apiKey = "";  // Replace with your WeatherAPI key
const String city = "Brasov";                             // City name (Brasov)
const String weatherUrl = "http://api.weatherapi.com/v1/current.json?key=" + apiKey + "&q=" + city + "&aqi=no";
const char* stockURL = "https://bvb-prices.ro/stock/TVBETETF";

// Time zone offset (in seconds)
// Adjust according to your local time zone. Example: GMT+1 (Europe) is 3600 seconds.
const long gmtOffset_sec = 7200;
// Daylight saving time offset in seconds (0 if not applicable)
const int daylightOffset_sec = 3600;

// Text sizes
const int cityTextSize = 5;
const int tempTextSize = 6;
const int timeTextSize = 6;
const int dateTextSize = 2;
const int stockNameSize = 4;
const int stockPriceSize = 3;
// Cloud icon dimensions
const int CLOUD_ICON_WIDTH = 36;
const int CLOUD_ICON_HEIGHT = 36;
// Clock icon dimensions
const int CLOCK_ICON_WIDTH = 36;
const int CLOCK_ICON_HEIGHT = 36;
// Stock icon dimensions
const int STOCK_ICON_WIDTH = 36;
const int STOCK_ICON_HEIGHT = 36;

// Static Y positions for city and temperature
int cityYPos = 0;
int tempYPos = 0;
int cloudIconYPos = 0;  // Y position for the cloud icon
int timeYPos = 0;
int dateYPos = 0;
int clockIconYPos = 0;  // Y position for the clock icon
int stockNameYPos = 0;
int stockPriceYPos = 0;
int stockIconYPos = 0;  // Y position for the stock icon


void setup() {

  Serial.begin(115200);
  pinMode(firstScreenCS, OUTPUT);
  digitalWrite(firstScreenCS, HIGH);
  
  pinMode(secondScreenCS, OUTPUT);
  digitalWrite(secondScreenCS, HIGH);

  pinMode(thirdScreenCS, OUTPUT);
  digitalWrite(thirdScreenCS, HIGH);

    // We need to 'init' both displays
  // at the same time. so set both cs pins low
  digitalWrite(firstScreenCS, LOW);
  digitalWrite(secondScreenCS, LOW);
  digitalWrite(thirdScreenCS, LOW);
  delay(500);
  tft.init();

  digitalWrite(firstScreenCS, HIGH);
  digitalWrite(secondScreenCS, HIGH);
  digitalWrite(thirdScreenCS, HIGH);

  delay(500);

  digitalWrite(firstScreenCS, LOW);
  tft.setRotation(0);
  tft.fillScreen(TFT_WHITE);  // Set background to white
  delay(500);
  digitalWrite(firstScreenCS, HIGH);

  digitalWrite(secondScreenCS, LOW);
  tft.setRotation(0);
  tft.fillScreen(TFT_WHITE);  // Set background to white
  delay(500);
  digitalWrite(secondScreenCS, HIGH);

  digitalWrite(thirdScreenCS, LOW);
  tft.setRotation(0);
  tft.fillScreen(TFT_WHITE);  // Set background to white
  delay(500);
  digitalWrite(thirdScreenCS, HIGH);

  // Connect to Wi-Fi
  connectToWiFi();

  // Initialize and configure time
  configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");

  // Wait for time to be set
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }

  // Calculate the center position for the text and icon
  calculateTextPosition();
}

void loop() {
  String temperature = fetchWeatherData();  // Fetch weather data
  String stockPrice = fetchStockData();

  digitalWrite(firstScreenCS, LOW);
  // If data is fetched, display city name and temperature
  if (temperature != "") {
    tft.fillScreen(TFT_WHITE);  // Only clear the screen for error message
    // Display the cloud icon
    displayCloudIcon();

    // Display city name and temperature
    displayText(tft,"Brasov", cityTextSize, cityYPos);
    displayText(tft,temperature.c_str(), tempTextSize, tempYPos);
  } else {
    // Clear the screen and display error message if data fetch failed
    tft.fillScreen(TFT_WHITE);  // Only clear the screen for error message
    displayText(tft,"Error Fetching Data", 2, cityYPos);
  }
  delay(500);
  digitalWrite(firstScreenCS, HIGH);

   delay(1000);

  digitalWrite(secondScreenCS, LOW);
  displayClockIcon();
  displayTime(timeTextSize, dateTextSize);  // Display time and date
  delay(500);
  digitalWrite(secondScreenCS, HIGH);

  delay(1000);

  digitalWrite(thirdScreenCS, LOW);
  if(stockPrice !=""){
    tft.fillScreen(TFT_WHITE);  // Only clear the screen for error message
    displayStockIcon();
    displayText(tft,"TVBETETF", stockNameSize, stockNameYPos);
    displayText(tft,stockPrice.c_str(), stockPriceSize, stockPriceYPos);
  }else {
    // Clear the screen and display error message if data fetch failed
    tft.fillScreen(TFT_WHITE);  // Only clear the screen for error message
    displayText(tft,"Error Fetching Data", 2, stockNameYPos);
  }
  delay(500);
  digitalWrite(thirdScreenCS, HIGH);

  delay(3000);  // Update every 3 seconds
}

void connectToWiFi() {
  WiFi.begin(ssid, password);
  Serial.print("Connecting to Wi-Fi");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected to Wi-Fi");
}

String fetchWeatherData() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(weatherUrl);  // API endpoint for fetching weather data

    int httpResponseCode = http.GET();
    String payload;

    if (httpResponseCode > 0) {  // Check if the GET request was successful
      payload = http.getString();
      Serial.println("Weather data fetched successfully");

      // Parse the JSON response
      DynamicJsonDocument doc(1024);
      deserializeJson(doc, payload);

      // Extract the temperature from the JSON object
      float temp = doc["current"]["temp_c"];  // Current temperature in Celsius
      String temperature = String(temp, 1);   // Convert temperature to string with 1 decimal place
      http.end();
      return temperature;
    } else {
      Serial.print("Error on HTTP request: ");
      Serial.println(httpResponseCode);
    }
    http.end();
  } else {
    Serial.println("Wi-Fi not connected.");
  }

  return "";  // Return empty string if there's an error
}

// Function to calculate the center positions for city and temperature with a gap of 5 pixels
void calculateTextPosition() {
  int16_t cityTextWidth = tft.textWidth("Brasov") * cityTextSize;
  int16_t cityTextHeight = cityTextSize * 8;  // Estimated height based on text size

  int16_t tempTextWidth = tft.textWidth("00.0") * tempTextSize;  // Assuming max temp length like "00.0"
  int16_t tempTextHeight = tempTextSize * 8;                     // Estimated height based on text size'

   int16_t timeTextWidth = tft.textWidth("00:00") * timeTextSize;  // Assuming "00:00" format for time
  int16_t timeTextHeight = timeTextSize * 8;                      // Estimated height based on text size'

  int16_t dateTextWidth = tft.textWidth("00.00.0000") * dateTextSize;  // Assuming "00.00.0000" format for date
  int16_t dateTextHeight = dateTextSize * 8;                           // Estimated height based on text size'

  int16_t stockTextWidth = tft.textWidth("TVBETETF") * stockNameSize;
  int16_t stockTextHeight = stockNameSize * 8;  // Estimated height based on text size

  int16_t stockPriceTextWidth = tft.textWidth("00.0") * stockPriceSize;  
  int16_t stockPriceTextHeight = stockPriceSize * 8;                     

  // Calculate center Y positions with a 5px gap between elements
  cloudIconYPos = (TFT_HEIGHT - (CLOUD_ICON_HEIGHT + cityTextHeight + tempTextHeight + 10)) / 2;  // Top of cloud icon
  cityYPos = cloudIconYPos + CLOUD_ICON_HEIGHT + 5;                                               // 5px gap below the cloud icon
  tempYPos = cityYPos + cityTextHeight + 5;                                                       // 5px gap between city name and temperature

  // Calculate center Y positions with a 5px gap between elements
  clockIconYPos = (TFT_HEIGHT - (CLOCK_ICON_HEIGHT + timeTextHeight + dateTextHeight + 15)) / 2;  // Top of clock icon
  timeYPos = clockIconYPos + CLOCK_ICON_HEIGHT + 10;                                               // 5px gap below the clock icon
  dateYPos = timeYPos + timeTextHeight + 5;                                                       // 5px gap between time and date

  // Calculate center Y positions with a 5px gap between elements
  stockIconYPos = (TFT_HEIGHT - (STOCK_ICON_HEIGHT + stockTextHeight + stockPriceTextHeight + 15)) / 2;  // Top of clock icon
  stockNameYPos = stockIconYPos + STOCK_ICON_HEIGHT + 10;
  stockPriceYPos = stockNameYPos + stockTextHeight + 5; 

}

// Function to display the cloud icon on the screen
void displayCloudIcon() {
  // Display the cloud icon at the top of the city name
  tft.drawBitmap((TFT_WIDTH - CLOUD_ICON_WIDTH) / 2, cloudIconYPos, cloudIcon, CLOUD_ICON_WIDTH, CLOUD_ICON_HEIGHT, TFT_BLACK);
}

// Function to display the clock icon on the screen
void displayClockIcon() {
  tft.drawBitmap((TFT_WIDTH - CLOCK_ICON_WIDTH) / 2, clockIconYPos, clockIcon, CLOCK_ICON_WIDTH, CLOCK_ICON_HEIGHT, TFT_BLACK);
}

// Function to display the cloud icon on the screen
void displayStockIcon() {
  // Display the cloud icon at the top of the city name
  tft.drawBitmap((TFT_WIDTH - STOCK_ICON_WIDTH) / 2, stockIconYPos, stockIcon, STOCK_ICON_WIDTH, STOCK_ICON_HEIGHT, TFT_BLACK);
}

// Function to display text at a specific position
void displayText(TFT_eSPI &tft,const char* text, int textSize, int yPos) {
  tft.setTextSize(textSize);
  int16_t textWidth = tft.textWidth(text);
  int16_t textHeight = textSize * 8;

  // Calculate the X position to center the text horizontally
  int16_t x = (TFT_WIDTH - textWidth) / 2;

  // Set cursor at the calculated position
  tft.setCursor(x, yPos);
  tft.setTextColor(TFT_BLACK, TFT_WHITE);  // Set text color to black with transparent background
  tft.print(text);
}

// Function to display the time and date using calculated positions
void displayTime(int timeSize, int dateSize) {
  struct tm timeinfo;
  if (getLocalTime(&timeinfo)) {
    // Format and display the time using the calculated position
    char timeStr[6];
    snprintf(timeStr, sizeof(timeStr), "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
    displayText(tft,timeStr, timeSize, timeYPos);

    // Format and display the date using the calculated position
    char dateStr[11];
    snprintf(dateStr, sizeof(dateStr), "%02d.%02d.%04d", timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
    displayText(tft,dateStr, dateSize, dateYPos);
  } else {
    displayText(tft,"Time Error", 2, dateYPos);
  }
}

String fetchStockData() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(stockURL);
    int httpResponseCode = http.GET();

    if (httpResponseCode > 0) {
      String payload = http.getString();
      Serial.println("Raw HTML data received:");
      Serial.println(payload); // Initial HTML for debugging

      return payload;
    } else {
      Serial.println("HTTP request error: " + String(httpResponseCode));
    }
    http.end();
  } else {
    Serial.println("WiFi Disconnected");
  }
  return "";
}```
1 Like

The problem was with the alimentation cable.

JHi, misterdanny,
Yes! Your sketch is working immediately here in The Netherlands on a three circular GC9A01 display constellation driven by and ESP32. (CS_00 = 5, CS_01 = 21, CS_02 = 23). resulta: One hour time difference, and 9.9 degrees Celsius temperature difference. Cold in Brasov, brrr.
There is slight flicker on my displays (these are soldered - so no power supply issue). Will experiment to solve this issue.
Thanks! photoncatcher

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