Round GC9A01 display from a Volos Project struggling to get a Gauge displayed?

Hello everyone,

Before posting this I had a browse for something familiar and read up on “TFT Display works in Arduino IDE, but doesnt in PlatformIO” posted by leemanio in Apr 2023. Unfortunately I don’t see a solution there.

I am following this eample by Volos Projects Round GC9A01 240x240 display and gauges

and I can see he uses Arduino IDE.

I have copied the provided code from his well documented web page and put all the header files in >lib > All_Gauges and the project compiles without errors.

I know the code with espi by Bodmer is working up to a point as I am able in setup() to change the tft.fillScreen(TFT_ORANGE) to (TFT_SILVER) so I’m assuming that my pin configuration for the ESP32 is correct in the User_Setup_Select.h file.

What it does not appear to execute in the loop() is to generate the gauge code (presumably not reading the <gauge1.h> file and compiling it) ?

I have tried over the last few days using different versions of TFT_eSPI by Bodmer (ranging from 2.4.79 to 2.5.43) but still have the same result of a non displayed gauge?

To test my wiring and choice of User_Setup_Select.h settings I have successfully run the Animated_dial example found in TFT_eSPI > examples > Sprite > Animated_dial and even played around to correct that version of the needle overwriting the numeric background as it moves.

I’m now at a loss to find a solution?

Here is my platformio configuration code

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed = 115200
lib_deps = 
	bodmer/TJpg_Decoder@^1.1.0
	bodmer/TFT_eSPI@^2.5.43

Here is my main.cpp code

#include <Arduino.h>
#include <SPI.h>

#include <TFT_eSPI.h> 
#include <gauge1.h>
#include <gauge2.h>
#include <gauge3.h>
#include <gauge4.h>
#include <gauge5.h>
#include <gauge6.h>
#include <font.h>

// Include the jpeg decoder library
////#include <TJpg_Decoder.h>

TFT_eSPI tft = TFT_eSPI(); 
TFT_eSprite img = TFT_eSprite(&tft);
TFT_eSprite ln = TFT_eSprite(&tft);

double rad=0.01745;
int angle;

int sx=120;
int sy=120;
int r=76;

float x[360];
float y[360];
float x2[360];
float y2[360];

const int pwmFreq = 5000;
const int pwmResolution = 8;
const int pwmLedChannelTFT = 0;

int chosenOne=0;
int minValue[6]={0,20,0,0,0,80};
int maxValue[6]={40,100,60,80,70,160};
int dbounce=0;

int a1,a2;
int result=0;
/*
// =======================================================================================
// This function will be called during decoding of the jpeg file
// =======================================================================================
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  // Stop further decoding as image is running off bottom of screen
  if ( y >= tft.height() ) return 0;

  // This function will clip the image block rendering automatically at the TFT boundaries
  tft.pushImage(x, y, w, h, bitmap);

  // Return 1 to decode next block
  return 1;
}
*/

void setup() {

  // For code checking
  Serial.begin(115200); // Debug only

  // The byte order can be swapped (set true for TFT_eSPI)
  ////TJpgDec.setSwapBytes(true);
  // The jpeg decoder must be given the exact name of the rendering function above
  ////TJpgDec.setCallback(tft_output);

  ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
  ledcAttachPin(5, pwmLedChannelTFT);
  ledcWrite(pwmLedChannelTFT, 90);

  pinMode(12,INPUT_PULLUP);
   
  tft.init();
  tft.setRotation(0);
  tft.setSwapBytes(true);
  img.setSwapBytes(true);
  ////tft.fillScreen(TFT_ORANGE);
  tft.fillScreen(TFT_SILVER);
  img.createSprite(240, 240);    

  tft.setPivot(60,60);
  img.setTextDatum(4);
  img.setTextColor(TFT_BLACK,0xAD55);
  img.setFreeFont(&Orbitron_Medium_28);

  int i=0;
  int a=136;

  while(a!=44)
  {
   x[i]=r*cos(rad*a)+sx;
   y[i]=r*sin(rad*a)+sy;
   x2[i]=(r-20)*cos(rad*a)+sx;
   y2[i]=(r-20)*sin(rad*a)+sy;
   i++;
   a++;
   if(a==360)
   a=0;
  }
  ////Serial.print("Exiting setup()");
}

//min angle 136 or 137
//max angle 43

void loop() {

  //// Not using a PushButton so commented out.
  //// Just want to see Gauge 1 displayed!
  /*
  if(digitalRead(12)==0)
  {
    if(dbounce==0)
       {
        dbounce=1;
        chosenOne++;
        if(chosenOne>=6)
        chosenOne=0;
        }
    }else dbounce=0;
  result=map(analogRead(14),0,4095,minValue[chosenOne],maxValue[chosenOne]);
  angle=map(result,minValue[chosenOne],maxValue[chosenOne],0,267);
  */ 

  chosenOne=0;

 if(chosenOne==0)
 img.pushImage(0,0,240,240,gauge1);
  if(chosenOne==1)
 img.pushImage(0,0,240,240,gauge2);
  if(chosenOne==2)
 img.pushImage(0,0,240,240,gauge3);
  if(chosenOne==3)
 img.pushImage(0,0,240,240,gauge4);
  if(chosenOne==4)
 img.pushImage(0,0,240,240,gauge5);
  if(chosenOne==5)
 img.pushImage(0,0,240,240,gauge6);

 if(chosenOne==5)
  img.drawFloat(result/10.00,2,120,114);
 else if(chosenOne==4)
 img.drawString(String(result*100),120,114);
 else
 img.drawString(String(result),120,114);
 //img.drawString(String(analogRead(22)), 30,10,2);

 a1=angle-4;
 a2=angle+4;

 if(a1<0)
 a1=angle-4+359;
  if(a2>=359)
 a2=angle+4-359;

 if(result<=minValue[chosenOne]+4)
 img.fillTriangle(x[angle],y[angle],x2[angle],y2[angle],x2[a2+2],y2[a2+2],TFT_RED);
 else if(result>=maxValue[chosenOne]-4)
 img.fillTriangle(x[angle],y[angle],x2[a1-2],y2[a1-2],x2[angle],y2[angle],TFT_RED);
 else
 img.fillTriangle(x[angle],y[angle],x2[a1],y2[a1],x2[a2],y2[a2],TFT_RED);
 
 img.pushSprite(0, 0);
 Serial.print("Value of chosenOne: ");
 Serial.println(chosenOne); //Debug purpose only
}

Thank you for any help/advice gratefully received as I really want to solve this for future use.

Kind Regards,

Degs

I can’t see any build_flags in your platformio.ini to configure the TFT_eSPI library. Did you read the instructions for PlatformIO?

Thank you Sivar for this, I think I understand what you are saying so I’ll give it a go. I did read it but didn’t conclude as it was it required. ‘It is possible’ in my understanding means it isn’t mandatory, and ‘rather than modify the library’ means it’s an alternative option to myself?

In the TFT_eSPI folder I have used the User_Setup_Select.h as follows:

#ifndef USER_SETUP_LOADED // Lets PlatformIO users define settings in

                      //  platformio.ini, see notes in "Tools" folder.

#include <User_Setups/Setup46_GC9A01_ESP32.h>

which works as the Setup46 option settings I have displays some example text and I can change background colour, so I know my wiring is correct, but I cannot get the gauge1.h file to load?

So I’ve changed the platformio.ini file to include the following:

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed = 115200
lib_deps = 
	bodmer/TFT_eSPI@^2.5.43
	bodmer/TJpg_Decoder@^1.1.0

build_flags =
	;###############################################################
  	; TFT_eSPI library setting here (no need to edit library files):
  	;###############################################################

  -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
  -D USER_SETUP_LOADED=1 ; Set this settings as valid
  -include $PROJECT_LIBDEPS_DIR/$PIOENV/TFT_eSPI/User_Setups/Setup46_GC9A01_ESP32.h
  
  ; Define the TFT driver, pins etc. here:
  -D GC9A01_DRIVER=1 	; Select the GC9A01 driver for round 240x240 display
  -D TFT_WIDTH=240		; Set TFT size		
  -D TFT_HEIGHT=240
  ;-DTFT_MISO=19
  -D TFT_MOSI=23		; Define the SPI pins
  -D TFT_SCLK=18
  -D TFT_CS=22			; Chip Select
  -D TFT_DC=16			; Data/Command
  -D TFT_RST=4			; Reset pin
  ;-DTFT_BL=21
  ;-DTOUCH_CS=22
  -D LOAD_GLCD=1
  -D LOAD_FONT2=1
  -D LOAD_FONT4=1
  -D LOAD_FONT6=1
  -D LOAD_FONT7=1
  -D LOAD_FONT8=1
  -D LOAD_GFXFF=1
  -D SMOOTH_FONT=1
  -D SPI_FREQUENCY=27000000	;Set SPI frequency

But I still cannot display the gauge1.h information?

I don’t think I’m barking up the wrong tree here, but I’d like advice please from the more experienced learned code users.

What I’ve come across this morning by implementing the <TJpg_Decoder.h> which TFT_eSPI requires for creating an image from a data file like gauge1.h is that <TJpg_Decoder.h> requires data (build error notification) in the format of:

JRESULT drawJpg(int32_t x, int32_t y, const uint8_t array[], uint32_t array_size);

But the original data for gauge1.h was in the form of:

const unsigned short gauge1[57600] PROGMEM = {

When I change gauge1.h to what TJpg_Decoder.h requires I get the following build error:

lib/Gauge_Image/gauge1.h:3614:1: error: narrowing conversion of ‘10565’ from ‘int’ to ‘uint8_t’ {aka ‘unsigned char’} inside { } [-Wnarrowing]

Does this imply that bitmap data in gauge1.h is incorrect for TJpg_Decoder.h to use, and this is why no image is created?

If I use the TJpg_Decoder.h platformio constantly creates build errors, yet in the TFT_eSPI>Sprite>Animated_dial example I have it working perfect?

I hope I’ve correctly described what I’m dealing with to get gauge1.h loaded and working in my code.

I can take a look on Volos Example in a few days. I am currently on vacation.

Thank you Sivar, enjoy your vacation and put away the laptop!!!

In the meantime… What exact espressif32 platform version do you use?

ArduinoIDE is using 3.x. To get this in PlatformIO you have to use pioarduino espresif32 platform. This is also supported by TFT_eSPI since a few months.

I’m pretty sure I’ve narrowed down what the issue is……but it’s a bit beyond my coding skils (though it’s not stopping me trying)!

In the example I have working the image data takes the form of:

const uint8_t dial[] PROGMEM = {

0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60, 

0x00, 0x60, 0x00, 0x00, 0xFF, 0xE1, 0x00, 0x5A, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D, 

which of course is 8bit…..

The gauge1.h header data I want to use takes the form of:

//const unsigned short gauge1[57600]

const uint16_t gauge1[57600] PROGMEM = {

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0010 (16) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0020 (32) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0030 (48) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0040 (64) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0050 (80) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0060 (96) pixels

0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x18E4, 0x2945, 0x39E8, 0x52AA, 0x5AEC, 0x7BF0, 0x7BF0, 0x7BF0,   // 0x0070 (112) pixels

0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55, 0xAD55,

Which is clearly 16 bit so I modified the TJpg_Decoder.h file to:

//JRESULT drawJpg(int32_t x, int32_t y, const uint8_t array[], uint32_t  array_size);

  JRESULT drawJpg(int32_t x, int32_t y, const uint16_t array[], uint32_t  array_size);

  //JRESULT getJpgSize(uint16_t *w, uint16_t *h, const uint8_t array[], uint32_t  array_size);

  JRESULT getJpgSize(uint16_t *w, uint16_t *h, const uint16_t array[], uint32_t  array_size); 

But now I get build errors in the TJpg_Decoder.cpp file which I’m trying to resolve:

a value of type “const uint16_t *” cannot be assigned to an entity of type “const uint8_t *”

cannot convert ‘const uint16_t*’ {aka ‘const short unsigned int*’} to ‘const uint8_t*’ {aka ‘const unsigned char*’} in assignment

in this piece of coding in file TJpg_Decoder.cpp:

/***************************************************************************************

** Function name:           drawJpg

** Description:             Draw a jpg saved in a FLASH memory array

***************************************************************************************/

JRESULT TJpg_Decoder::drawJpg(int32_t x, int32_t y, const uint16_t jpeg_data[], uint32_t  data_size) {

  JDEC jdec;

  JRESULT jresult = JDR_OK;

  jpg_source = TJPG_ARRAY;

  array_index = 0;

  array_data  = jpeg_data;

  array_size  = data_size;

You cannot just change the function deckaration in the headerfile without implementing a matching function! You simply need to pass the correct data into the function! You have to change your data, not the function declaration!

So how would you change 0xAD55 for example to two 8bits? like 0xAD and 0x55 in the correct order? The whole bitmap image data would be a nightmare to resolve?

There must be something I am totally missing from the example Volos YouTube video, because in there he only uses TFT_eSPI in Arduino ID and it works!

Unfortunately, my internet connection is poor right now (I’m on vacation). What exactly isn’t working? You mentioned that Volos’s example compiles without errors. Does the example work for you, and does anything actually show up on the display?

As far as I can tell, Volos’s example project doesn’t require a JPEG decoder.

As I mentioned earlier, the TFT_eSPI library was updated a few months ago. I’m not yet familiar with the updates, since I haven’t used the library in quite some time…

Hi Sivar, this is from my first post comment - what exactly isn’t working?

What it does not appear to execute in the loop() is to generate the gauge code (presumably not reading the <gauge1.h> file and compiling it) ?

I have tried over the last few days using different versions of TFT_eSPI by Bodmer (ranging from 2.4.79 to 2.5.43) but still have the same result of a non displayed gauge?

To test my wiring and choice of User_Setup_Select.h settings I have successfully run the Animated_dial example found in TFT_eSPI > examples > Sprite > Animated_dial and even played around to correct that version of the needle overwriting the numeric background as it moves.

I’m now at a loss to find a solution?

The example from Volos does not work for me when using platformio IDE. Volos is using Arduino IDE.

Thank you for taking time out from your vacation and helping me, I’ve learned a lot today and broke a lot today!! :slight_smile:

Unfortunately, I still don’t quite understand what the problem is. On the one hand, you say the project compiles without errors, but on the other hand, you say that Gauge1.h doesn’t compile? That’s confusing me.

Please post the exact error message.
Also, please specify the exact version of the Espressif32 platform you’re using.

It also seems that this isn’t just one project, but several different ones? Please name an exact project your’re trying to build. Currently I’m assuming you’re going to build the Volos Example from GitHub - VolosR/BoatGauges · GitHub

Sidenote: This example is 4 years old. Therefore, you must also use the Espressif32 Arduino platform and the TFT_eSPI version from 4 years ago to ensure that everything is compatible. Otherwise, modifications may be necessary.

Hi Sivar,

Yes, it’s the Volos boat gauge example. Build compiles without errors, but Gauge1.h image does not appear on my Waveshare round GC9A01 display. That’s the problem.

This is the top of the report from build showing what configuration I am using:

CONFIGURATION: 

PLATFORM: Espressif 32 (6.12.0) > DOIT ESP32 DEVKIT V1
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:

framework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b

tool-esptoolpy @ 2.40900.250804 (4.9.0)

toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
LDF: Library Dependency Finder → 

LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 36 compatible libraries
Scanning dependencies…
Dependency Graph
|-- TFT_eSPI @ 2.5.43
|-- TJpg_Decoder @ 1.1.0
|-- Gauge_Image
|-- SPI @ 2.0.0
Building in release mode
Compiling .pio\build\esp32doit-devkit-v1\src\main.cpp.o

At the end of build:

#warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available!
^~~~~~~
Linking .pio\build\esp32doit-devkit-v1\firmware.elf
Retrieving maximum program size .pio\build\esp32doit-devkit-v1\firmware.elf
Checking size .pio\build\esp32doit-devkit-v1\firmware.elf
Advanced Memory Usage is available via “PlatformIO Home > Project Inspect”
RAM: [= ] 8.7% (used 28644 bytes from 327680 bytes)
Flash: [=== ] 26.6% (used 348977 bytes from 1310720 bytes)
Building .pio\build\esp32doit-devkit-v1\firmware.bin
esptool.py v4.9.0
Creating esp32 image…
Merged 2 ELF sections
Successfully created esp32 image.

I have the same thoughts that as the example is 4yrs old I need to use an older version, but I’m definitely not skilled enough to know how to set platform.ini platform =, framework =, to older versions. I know how to install TFT_eSPI using the library to choose an older version.

Many thanks Sivar.

The reason the gauges aren’t displaying is likely due to the amount of available free memory.

A 240x240, 16-bit image takes up 2x240x240 = 115,200 bytes. Under Espressif Arduino 2.0.17 (platform=espressif32 @ 6.12.0), the largest contiguous block of free heap memory is approximately 114,676 bytes, which is insufficient.

I suspect that at the time, Espressif32 Arduino 1.0.6 was the current version, which had different memory usage.

Newer Espressif ESP32 Arduino models require more RAM (due to additional features).

If you want to work with displays and images, be sure to use an ESP32 chip with PSRAM! For example, an ESP32-S3 N16R8. This chip has 16 MB of flash (ROM) and 8 MB of PSRAM.

To make the example work, you have to use Espressif32 Arduino 1.0.6 (platform = espressif32 @ 3.0.5)and TFT_eSPI 2.4.79 (see the platformio.ini below). This brings a largest contiguous memory block of 125,716 bytes, which is sufficient for a bitmap of that size.

platformio.ini:

[env:esp32dev]
platform = espressif32 @ 3.0.5
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
   bodmer/TFT_eSPI @ 2.4.79
build_flags = 
  -DUSER_SETUP_LOADED=1
  -DGC9A01_DRIVER
  -DTFT_WIDTH=240
  -DTFT_HEIGHT=240
  -DTFT_MISO=5
  -DTFT_MOSI=2
  -DTFT_SCLK=15
  -DTFT_CS=17
  -DTFT_DC=16
  -DTFT_RST=4
  -DTOUCH_CS=-1
  -DLOAD_GLCD
  -DLOAD_FONT2
  -DLOAD_FONT4
  -DLOAD_FONT6
  -DLOAD_FONT7
  -DLOAD_FONT8
  -DLOAD_GFXFF
  -DSMOOTH_FONT
  -DUSE_HSPI_PORT
  -DSPI_FREQUENCY=80000000

Hi Sivar, I suspected the old ESP32 DevKit V1 boards might be the issue.

When I copied and pasted your code into the platformio for my project, I get the following error on build:

Resolving esp32dev dependencies...

Platform Manager: Installing espressif32 @ 3.0.5

UnknownPackageError: Could not find the package with 'espressif32 @ 3.0.5' requirements

Many thanks for your time and effort on this, guess I’ll search your board recommendations.

Sorry, that was a typo.
Correct is
platform = espressif32 @ 3.5.0:

[env:esp32dev]
platform = espressif32 @ 3.5.0
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
   bodmer/TFT_eSPI @ 2.4.79
build_flags = 
  -DUSER_SETUP_LOADED=1
  -DGC9A01_DRIVER
  -DTFT_WIDTH=240
  -DTFT_HEIGHT=240
  -DTFT_MISO=5
  -DTFT_MOSI=2
  -DTFT_SCLK=15
  -DTFT_CS=17
  -DTFT_DC=16
  -DTFT_RST=4
  -DTOUCH_CS=-1
  -DLOAD_GLCD
  -DLOAD_FONT2
  -DLOAD_FONT4
  -DLOAD_FONT6
  -DLOAD_FONT7
  -DLOAD_FONT8
  -DLOAD_GFXFF
  -DSMOOTH_FONT
  -DUSE_HSPI_PORT
  -DSPI_FREQUENCY=80000000

Hi Sivar,

FINALLY! All working as expected, even my (Build_A_Gaugefrom scratch) project is working once I’d done the image conversion using image2cpp to use only Horizontal - 1 bit per pixel. instead of the 2 bytes per pixel (565) option.

Many many thanks Sivar for all your help.

I’ve already been on Amazon for the more modern updated ESP32.

1 Like

I recommend the TZT ESP32-S3-DevKitC-1 ESP32-S3 WiFi Bluetooth-compatible BLE 5.0 Mesh Development Board ESP32 Wireless Module N16R8. Make sure it is the YD model (YD-ESP32-S3 2022-V1.3). Other similar ESP32 DevKits may have ESP32 modules of inferior quality and have a grounding issue with the antenna.