Display is slow to update, how can improve?

Hi lovely people.

New to Arduino and this is my first project.

I am trying to create a very simple log display using an Arduino Mega2560 and a DFRobot DFR0669 (3.5”480x320 TFT LCD Capacitive Touchscreen Breakout Wiki - DFRobot).

It's using SPI to communicate, and I am using the DFR provided libraries to interface with the display.

I have a simple sketch to output an event log to a new line every 200ms, and keep an uptime timer updated every 1000ms. I am not using delay().

Problem is it seems to be closer to 800-1000ms between the lines updating on the display, it seems the Arduino is waiting for the display to draw the line of text, which it does character by character, before it moves on.

So to fill the 480x320 display with text should take about 3 seconds, at which point it should refresh and keep rolling. However it takes more like 30 seconds. Also the wipe of the screen takes a second to process.

I was expecting the screen refresh would be instant, and I though the text would just display immediately. As it stands, the project is not fit for purpose.

Am I just pushing the limits of what's possible with the tool here, or am I missing a trick?!

#include "DFRobot_GDL.h"
#include "uptime.h"

#define TFT_DC  8
#define TFT_CS  53
#define TFT_RST 9

/**
 * @brief Constructor Constructor of hardware SPI communication
 * @param dc Command/data line pin for SPI communication
 * @param cs Chip select pin for SPI communication
 * @param rst reset pin of the screen
 */

DFRobot_ILI9488_320x480_HW_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);
//DFRobot_ILI9488_320x480_DMA_SPI screen(/*dc=*/TFT_DC,/*cs=*/TFT_CS,/*rst=*/TFT_RST);

/*
 *User-selectable macro definition color
 *COLOR_RGB565_BLACK   COLOR_RGB565_NAVY    COLOR_RGB565_DGREEN   COLOR_RGB565_DCYAN 
 *COLOR_RGB565_MAROON  COLOR_RGB565_PURPLE  COLOR_RGB565_OLIVE    COLOR_RGB565_LGRAY     
 *COLOR_RGB565_DGRAY   COLOR_RGB565_BLUE    COLOR_RGB565_GREEN    COLOR_RGB565_CYAN  
 *COLOR_RGB565_RED     COLOR_RGB565_MAGENTA COLOR_RGB565_YELLOW   COLOR_RGB565_ORANGE           
 *COLOR_RGB565_WHITE   
 */

unsigned long timer1 =0;
unsigned long timer2 =0;
int refresh1 = 1000;
int refresh2 = 100;
int16_t cursor_x = 0;
int16_t cursor_y = 0;

void setup() {
  Serial.begin(115200);
  screen.begin();

   // Set text wrapping mode
   // true = Text word wrap, false = No word wrap
  screen.setTextWrap(false);
  screen.setTextColor(COLOR_RGB565_BLACK, COLOR_RGB565_WHITE);
  //Set text size to 0
  screen.setTextSize(0);
  //Fill color, RGB color with 565 structure
  screen.fillScreen(COLOR_RGB565_WHITE);
}

void loop(){
if (millis()>timer1+refresh1){//do this every 1000 ms
  timer1+=refresh1;
  printStatus();
}
if (millis()>timer2+refresh2){//do this every 300 ms
  timer2+=refresh2;
  printLog("Here is a message to be displayed");
}


}

void printStatus(){
//Set the coordinate position x = 0, y = 50
  screen.setCursor(0, 470);
  
    //First call calculate_uptime() to calculate the uptime
  //and then read the uptime variables.
  uptime::calculateUptime();

  //Output text
  screen.print("Ross2D2 uptime ");
  screen.print(uptime::getHours());
  screen.print(":");
  screen.print(uptime::getMinutes());
  screen.print(":");
  screen.print(uptime::getSeconds());
}

void printLog(char *eventLog) {

if(cursor_y>=460){
  cursor_y = 0; //go back to the top
   screen.fillScreen(COLOR_RGB565_WHITE); //wipe the screen
}

    screen.setCursor(cursor_x, cursor_y);    
  screen.print(millis());
  screen.print(": ");
        screen.println(eventLog);
        cursor_x = screen.getCursorX();
        cursor_y = screen.getCursorY();
}

*I know the above is using 100ms as a timer. Also I should say if I disable the uptime timer, the refresh is marginally faster, more like 600ms between lines drawing, but still far from instant as I had hoped.

I have used the method where I saved a copy of the item saved to the screen in a variable. Then setting the screen text to black and writing to the location the saved text, clearing the screen text then reposition the cursor for a new text write.

like as in the below code.

void fDoTheDisplayThing( void * parameter )
{
  tft.init( 240, 320 ); // Init ST7789 320x240
  tft.setRotation( 3 );
  tft.setTextSize( 3 );
  tft.fillScreen( ST77XX_BLACK );
  tft.setTextWrap( false );
  struct stu_eData px_eData;
  const int brightness = 250;
  ledcWrite( 4, brightness ); //backlight set
  const int MaxString      = 20;
  String oldTempString     = "";
  String oldHumidityString = "";
  String oldAQIString      = "";
  String oldRainfall       = "";
  String oldWindDirection  = "";
  String oldAirPressure    = "";
  String oldRMO            = "";
  String oldPM2            = "";
  //String oldPower          = "";
  String oldC02 = "";
  oldHumidityString.reserve( MaxString );
  oldWindDirection.reserve( MaxString );
  oldAirPressure.reserve( MaxString );
  oldTempString.reserve( MaxString );
  oldAQIString.reserve( MaxString );
  oldRainfall.reserve( MaxString );
  //oldPower.reserve( MaxString );
  oldRMO.reserve( MaxString );
  oldPM2.reserve( MaxString );
  oldC02.reserve( MaxString );
  bool Tick = true;
  const int numOfColors = 40;
  /* https://chrishewett.com/blog/true-rgb565-colour-picker/#:~:text=A%20true%20RGB565%20colour%20picker%2021st%20Oct%202017,in%205%20bits%20and%20green%20in%206%20bits. */
  int colors[numOfColors] = { ST77XX_BLACK, ST77XX_RED, ST77XX_WHITE, ST77XX_BLUE, ST77XX_GREEN, ST77XX_CYAN, ST77XX_MAGENTA, ST77XX_YELLOW, 0xd55b, 0xee09,
                              0x2e15, 0xcb43, 0x6bad, 0x126f, 0x1264, 0xe264, 0xe7e4, 0x87e4, 0x87fe, 0x876a,
                              0xe304, 0x1cc4, 0xf4c4, 0xf4da, 0xcf66, 0xa879, 0x7f28, 0x4f37, 0xfa97, 0x6195,
                              0X8162, 0xc962, 0x517b, 0x325b, 0xea5b, 0x179b, 0xff80, 0xf960, 0x416d, 0x7bd1
                            };
  int colorCounter = 1;
  for (;;)
  {
    if ( xQueueReceive(xQ_eData, &px_eData, portMAX_DELAY) == pdTRUE )
    {
      tft.setCursor( 0, 0 );
      tft.setTextColor( colors[0] );
      tft.print( oldTempString );
      tft.setCursor( 0, 0 );
      tft.setTextColor( colors[colorCounter] );
      oldTempString = "";
      if ( Tick )
      {
        oldTempString.concat( "iTemp " + String(px_eData.Temperature) + "F" );
      } else {
        oldTempString.concat( "Wind Chill " + String(px_eData.WindChill) + "F" );
      }
      tft.println( oldTempString );
      tft.setCursor( 0, 30 );
      tft.setTextColor( colors[0] );
      tft.print( oldHumidityString );
      tft.setCursor( 0, 30 );
      tft.setTextColor( colors[colorCounter] );
      oldHumidityString = "";
      if ( Tick )
      {
        oldHumidityString.concat( "iHum  " + String(px_eData.Humidity) + "%" );
      } else {
        if ( (px_eData.SunRiseHr < 10) & (px_eData.SunRiseMin < 10) )
        {
          oldHumidityString.concat( "sRise 0" + String(px_eData.SunRiseHr) + "0" + String(px_eData.SunRiseMin) );
        }
        if ( (px_eData.SunRiseHr >= 10) & (px_eData.SunRiseMin < 10) )
        {
          oldHumidityString.concat( "sRise " + String(px_eData.SunRiseHr) + "0" + String(px_eData.SunRiseMin) );
        }
        if ( (px_eData.SunRiseHr < 10) & (px_eData.SunRiseMin >= 10) )
        {
          oldHumidityString.concat( "sRise 0" + String(px_eData.SunRiseHr) + String(px_eData.SunRiseMin) );
        }
        if ( (px_eData.SunRiseHr >= 10) & (px_eData.SunRiseMin >= 10) )
        {
          oldHumidityString.concat( "sRise " + String(px_eData.SunRiseHr) + String(px_eData.SunRiseMin) );
        }
      }
      tft.println( oldHumidityString );
      tft.setCursor( 0, 60 );
      tft.setTextColor( colors[0] );
      tft.print( oldAirPressure );
      tft.setCursor( 0, 60 );
      tft.setTextColor( colors[colorCounter] );
      oldAirPressure = "";
      if ( Tick )
      {
        //oldAirPressure.concat( "Pres " + String(px_eData.Pressure) + "mmHg" );
        oldAirPressure.concat( "Dew Pt. " + String(px_eData.DewPoint) + "F" );
      } else {
        if ( px_eData.SunSetMin < 10 )
        {
          oldAirPressure.concat( "sSet " + String(px_eData.SunSetHr) + "0" + String(px_eData.SunSetMin) );
        }
        if ( px_eData.SunRiseMin >= 10 )
        {
          oldAirPressure.concat( "sSet " + String(px_eData.SunSetHr) + String(px_eData.SunSetMin) );
        }
      }
      tft.println( oldAirPressure );
      tft.setCursor( 0, 90 );
      tft.setTextColor( colors[0] );
      tft.print( oldAQIString );
      tft.setCursor( 0, 90 );
      tft.setTextColor( colors[colorCounter] );
      oldAQIString = "";
      oldAQIString.concat( "iAQI " + String(px_eData.IAQ) + "%" );
      tft.println( oldAQIString );
      tft.setCursor( 0, 120 );
      tft.setTextColor( colors[0] );
      tft.print( oldRMO );
      tft.setCursor( 0, 120 );
      tft.setTextColor( colors[colorCounter] );
      oldRMO = "";
      //if ( Tick )
      //{
        oldRMO.concat( "iRM0 " + String(px_eData.RM0) + "%" );
      //} else {
      //  oldRMO.concat( "iCO2 " + String(CO2) + "ppm" );
      //}
      tft.println( oldRMO );
      tft.setCursor( 0, 150 );
      tft.setTextColor( colors[0] );
      tft.print( oldPM2 );
      tft.setCursor( 0, 150 );
      tft.setTextColor( colors[colorCounter] );
      oldPM2 = "";
      oldPM2.concat( "PM2 " + String(px_eData.PM2) + "ug/m3" );
      tft.println( oldPM2 );
      tft.setCursor( 0, 180 );
      tft.setTextColor( colors[0] );
      //tft.print( oldPower );
      tft.print( oldC02 );
      tft.setCursor( 0, 180 );
      tft.setTextColor( colors[colorCounter] );
      //oldPower = "";
      oldC02 = "";
      //oldPower.concat(  String(px_eData.WSV) + " Volts" );
      oldC02.concat(  "iCO2 " + String(x_eData.CO2) + "ppm" );
      //oldPower.concat(  String(px_eData.WSV) + "V " + String(int(px_eData.WSC * 1000.0f)) + "mA " + String((int(px_eData.WSP * 1000.0f))) + "mW" );
      //tft.println( oldPower );
      tft.println( oldC02 );
      colorCounter++;
      if ( colorCounter > (numOfColors - 1) )
      {
        colorCounter = 1;
      }
      Tick = !Tick;
      //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
    } //if ( xQueueReceive(xQ_eData, &px_eData, portMAX_DELAY) == pdTRUE )
  } //for (;;)
  vTaskDelete( NULL );
} //void fDoTheDisplayTHing( void * parameter )