ArduinoGFX
ArduinoGFX
Arduino_GFX
by
This instructables introduce a color display graphic function (GFX) Library for Arduino.
The content is intended to be updated from time to time, I will add more details if Arduino_GFX added more features.
You can also help me enrich the content by leaving comments below.
Arduino_GFX: Page 1
https://youtu.be/W8oPOXpAtqI
Arduino_GFX: Page 2
Step 2: Software Design
Arduino_GFX start rewrite from Adafruit_GFX and used many features from LovyanGFX and TFT_eSPI, but the high level
design is a little bit like Ucglib. Arduino_GFX decouple display driver and data interface into 2 separate class. It gives
much more exibilities, for example, ILI9341 display can use:
8-bit SPI
9-bit SPI
6-bit parallel
8-bit parallel
9-bit parallel
16-bit parallel
18-bit parallel
Simply feed di erent data bus class to "Arduino_ILI9341" display class can support various type of ILI9341 display
breakout module.
Ref.:
Arduino_GFX: Page 3
https://cdn-shop.adafruit.com/datasheets/ILI9341.p...
1. Open Library Manager in Arduino IDE: Tools menu -> Manage Libraries...
2. Search "color display gfx" or "GFX Library for Arduino"
3. select "GFX Library for Arduino" and Install
Or you can download the latest code from GitHub and import to library folder yourself:
https://github.com/moononournation/Arduino_GFX
Ref.:
https://www.arduino.cc/en/guide/libraries
Simple Declaration
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = new Arduino_HWSPI(16 /* DC */, 5 /* CS */);
Arduino_GFX *gfx = new Arduino_ILI9341(bus, 17 /* RST */);
The declaration only requires 3 lines, using create_default_Arduino_DataBus() or create_default_Arduino_GFX() still can
make it simpler. This 2 functions will mention in later steps.
And Simple Usage
gfx->begin();
gfx->fillScreen(BLACK);
gfx->println("Hello World!");
Arduino_GFX: Page 4
Step 5: Ease of Switching Hardware
Arduino_GFX write as generic as possible to support multi-platform. Switching dev board no need to change any code
related to GFX function. Switching display simply replacing the GFX class, e.g. switching ILI9341 display to ST7789 IPS
display will be:
// Arduino_GFX *gfx = new Arduino_ILI9341(bus, TFT_RST, 0 /* rotation */, false /* IPS */);
Arduino_GFX *gfx = new Arduino_ST7789(bus, TFT_RST, 0 /* rotation */, true /* IPS */);
Every platform de ned the default SPI speed, ESP family is 40 MHz, AVR family is 4 MHz, ...etc. When you initial the gfx
class, "gfx->begin();", you can pass the frequency value in it to override the default value:
gfx->begin(80000000); // 80 MHz
As you can see the the declaration in previous step, there are no need to pass the LED pin to both class. This is because
the LED on or o is not controlled by the display driver, in most case it is direct controlled by the MCU GPIO. Sometimes it
is controlled by a dedicated power control chips; Sometimes there is no LED backlight, e.g. OLED.
So Arduino_GFX leave LED backlight control to the main program.
The most lazy way is just connect the LED pin to Vcc, but it may take a risk of burn out LED if the breakout board not have
enough protection. So it is better using a GPIO:
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
Please note ESP32 not implemented analogWrite(), it have its own LED control function:
ledcSetup(0 /* LEDChannel */, 5000 /* freq */, 8 /* resolution */);
ledcAttachPin(TFT_BL, 0 /* LEDChannel */);
ledcWrite(0 /* LEDChannel */, 127); /* 0-255 */
Step 8: Benchmark
Arduino_GFX is not putting speed at the rst priority, but still paid much e ort to make the display look smooth. Let's
compare the speed with a most well known GFX library and 2 fastest GFX libraries.
Arduino_GFX: Page 5
Arduino IDE: 1.8.15
arduino-esp32: 1.0.6
PSRAM option: disable
Dev Board: TTGO T8 v1.8
Color Display: ILI9341
Interface: SPI
SPI Frequency: 40 MHz
Test Code: https://github.com/moononournation/Arduino_graphicstest_PDQ.git
Test Date: 2021 Jun 16
Yes, if you are using the MCU with limited program space, e.g. Arduino Nano only have 32 KB program space (exclude the
size of boot loader, maximum is 30720 bytes).
In early development stage, once I added the Arcs function to PDQgraphicstest example, I found it cannot t in Arduino
Nano. A display library used up all program space means you cannot do any thing in the project. It is not acceptable, so I
raise an issue in GitHub myself:
https://github.com/moononournation/Arduino_GFX/iss...
After various ne tuning and tradeo , now PDQgraphicstest use 28530 bytes (92%); And HelloWorld example use 11496
bytes (37%), I thing it is good enough for many projects.
When you design your display project, there are 2 variable hardware factors to consider:
Dev board. Di erent dev board (platform) have di erent GPIO pins mapping and di erent interface (data
bus) can be used. Also driving higher resolution color display smooth requires higher processing power.
Display breakout board. Di erent Display have di erent display driver and di erent interface (data bus)
can be used.
First of all, it must have common interface between the dev board and display, most likely it should be 8-bit SPI. And
then you need to allocate other GPIO control pins, e.g. CS, DC, RST and LED. If you do not have preference for using
which GPIOs, Arduino_GFX already de ned some default for ease of use.
Arduino_GFX: Page 7
Since most display using 8-bit SPI, simply use below line to create the default 8-bit SPI data bus class:
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = create_default_Arduino_DataBus();
Below steps illustrate the pins connection with the ILI9341 SPI breakout board for each platform.
Connection summary:
Teensy 4.1 -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 39 -> CS
GPIO 40 -> RESET
GPIO 41 -> D/C
GPIO 11(MOSI) -> SDI(MOSI)
GPIO 13(SCK) -> SCK
GPIO 22 -> LED
Arduino_GFX: Page 8
https://youtu.be/hSFmYXghJo8
Since Arduino Nano is 5V dev board but most display is not 5V I/O tolerant so it require some resistors between GPIOs
and display pins.
Connection summary:
Arduino Nano -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 9 -> 3.3k resistor -> CS
GPIO 7 -> 3.3k resistor -> RESET
GPIO 8 -> 3.3k resistor -> D/C
GPIO 11(MOSI) -> 3.3k resistor -> SDI(MOSI)
GPIO 13(SCK) -> 3.3k resistor -> SCK
GPIO 6 -> LED
Arduino_GFX: Page 9
Arduino_GFX: Page 10
https://youtu.be/QA0jqFOot3E
Connection summary:
Arduino Nano 33 BLE -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 9 -> CS
GPIO 7 -> RESET
GPIO 8 -> D/C
GPIO 11(MOSI) -> SDI(MOSI)
GPIO 13(SCK) -> SCK
GPIO 6 -> LED
Arduino_GFX: Page 11
Arduino_GFX: Page 12
https://youtu.be/Ro4N0_eiOjY
Connection summary:
Black Pill -> ILI9341
Vin -> Vcc
GND -> GND
GPIO A4 -> CS
GPIO A2 -> RESET
GPIO A3 -> D/C
GPIO A7(MOSI) -> SDI(MOSI)
GPIO A5(SCK) -> SCK
GPIO A1 -> LED
Arduino_GFX: Page 13
Arduino_GFX: Page 14
https://youtu.be/9NkApyBmYYY
Connection summary:
ESP8266 -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 15 -> CS
GPIO 2 -> RESET
GPIO 4 -> D/C
GPIO 13(MOSI) -> SDI(MOSI)
GPIO 14(SCK) -> SCK
GPIO 5 -> LED
Arduino_GFX: Page 15
Arduino_GFX: Page 16
https://youtu.be/xLNL666BQB8
Connection summary:
Seeeduino XIAO -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 3 -> CS
GPIO 1 -> RESET
GPIO 2 -> D/C
GPIO 10(MOSI) -> SDI(MOSI)
GPIO 8(SCK) -> SCK
GPIO 0 -> LED
Arduino_GFX: Page 17
Arduino_GFX: Page 18
https://youtu.be/b4k7ZPfL0tA
Connection summary:
RTL8720DN -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 18 -> CS
GPIO 2 -> RESET
GPIO 17 -> D/C
GPIO 21(MOSI) -> SDI(MOSI)
GPIO 19(SCK) -> SCK
GPIO 23 -> LED
Ref.:
https://www.instructables.com/RTL8720DN/
Arduino_GFX: Page 19
Arduino_GFX: Page 20
https://youtu.be/HEIJ-w_rLDU
Connection summary:
ESP32 -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 5 -> CS
GPIO 33 -> RESET
GPIO 27 -> D/C
GPIO 23(MOSI) -> SDI(MOSI)
GPIO 18(SCK) -> SCK
GPIO 22 -> LED
Arduino_GFX: Page 21
Arduino_GFX: Page 22
https://youtu.be/JaB5FTcBxiM
Connection summary:
ESP32-C3 -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 7 -> CS
GPIO 1 -> RESET
GPIO 2 -> D/C
GPIO 6(MOSI) -> SDI(MOSI)
GPIO 4(SCK) -> SCK
GPIO 3 -> LED
https://youtu.be/r92MajazrSw
Arduino_GFX: Page 24
https://youtu.be/Ip3VahOQS9w
Connection summary:
Raspberry Pi Pico -> ILI9341
Vin -> Vcc
GND -> GND
GPIO 17 -> CS
GPIO 26 -> RESET
GPIO 27 -> D/C
GPIO 19(MOSI) -> SDI(MOSI)
GPIO 18(SCK) -> SCK
GPIO 28 -> LED
Arduino_GFX: Page 25
Arduino_GFX: Page 26
Step 23: Data Bus
9-bit SPI is not the most common name for this interface, a more common name is 3-line SPI or 3-wire SPI. But I found
there have 2 di erent meaning for 3-line SPI:
No DC pin, append 1-bit for each 8-bit data to represent it is command or data. 3-line is CLK, MOSI and
MISO
Combined MOSI and MISO pin, data input and output use same GPIO. 3-line is DC, CLK and MOSI+MISO
Arduino_GFX: Page 27
So I will avoid call 9-bit SPI as 3-line SPI.
In digital world, the smallest data size is bit, but the actual smallest data computation and storage size is byte (8 bit). So
many MCU only can support transfer SPI data bit in the factor 8. I found ESP32 SPI can freely control the number of bit
transfer, so I make ESP32SPI Data Bus class support 9-bit SPI.
Software SPI also can support 9-bit SPI, it just slower.
mbedSPI or NRFXSPI
The o cial SPI for Arduino Nano 33 BLE is a little bit slow for color display, it even much slower than Arduino Nano. It is a
well known issue on the web, the reason may caused by a mbedOS in the middle. When I dig into the rmware source
code, I found 9 internal classes related to SPI. I selected implement 2 classes. I think NRFXSPI implementation can meet
the performance of 64 MHz main frequency, mbedSPI is just a backup plan in case NRFXSPI broken something in
mbedOS.
Parallel Interface
AVR family is 8-bit MCU, running in 8 or 16 MHz, maximum SPI speed is 4 MHz. Seems not fast enough for color display, as
show in the rst video. How about 8-bit parallel? MCU can use port operation command direct access all GPIOs under
same port in 1 instruction. So AVR 8-bit parallel interface (AVRPAR8) can run much faster than SPI. However, most AVR
dev board not breakout enough pins for 8-bit port operation. E.g. Arduino UNO only break out port D all 8 GPIOs but use
port D require sacri ce the serial port pins.
Many 32-bit MCU also have port operation, but the port also in 32-bit. It means require some bit operation before setting
only 8-bit data (more than 1 instruction), so it is not as e cient as 8-bit MCU.
RPiPicoPAR16 data bus class utilize Raspberry Pi Pico 32-bit data port rst 16 bits to form a 16-bit parallel interface,
average only requires around 2 instructions to send 16 bits data, so it is very e cient.
ESP32PAR8, RTLPAR8 and ESP32PAR16 are actually a semi-software implementation of parallel interface, so it is not run
very fast.
As mentioned in previous step, many AVR breakout board not breakout all port GPIOs and limited the port parallel
interface usage. If you want challenge your soldering skill, you can breakout the missing pins yourself ;>
The above pictures and video are breakout Arduino Pro Micro 8MHz port B all pins and connect to NT35310 display.
Arduino_GFX: Page 28
Arduino_GFX: Page 29
https://youtu.be/rNAK98xGxOM
This is a round display with 240x240 resolution. Same as ILI9341, this display is not 5V I/O tolerant so it require some
resistors between GPIOs and display pins if using 5V MCU like Arduino Nano.
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = create_default_Arduino_DataBus();
Arduino_GFX *gfx = new Arduino_GC9A01(bus, 7 /* RST */, 0 /* rotation */, true /* IPS */);
HX8357B
This is an IPS display with 320x480 resolution. This display only support 9-bit SPI so it is better connect with ESP32SPI.
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = new Arduino_ESP32SPI(-1 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, -1 /* MISO */);
Arduino_GFX *gfx = new Arduino_HX8357B(bus, 7 /* RST */, 0 /* rotation */, true /* IPS */);
NT35510
This is the highest resolution display I have in hand, it is 480x800. This display support 8-bit or 16-bit parallel interface.
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = new Arduino_RPiPicoPAR8(27 /* DC */, 17 /* CS */, 18 /* WR */, 19 /* RD */);
Arduino_GFX *gfx = new Arduino_NT35510(bus, 7 /* RST */, 0 /* rotation */);
https://youtu.be/-xrbyeakgBQ
https://youtu.be/bwFF9-9kMog
https://youtu.be/C_1ASzUN3bg
Arduino_GFX provide various canvas class, sometimes it call framebu er, for draw bu ering on complicated
presentation:
Canvas (16-bit color, 2 bytes for each pixel)
Canvas_Indexed (half memory space)
Arduino_GFX: Page 31
Canvas_3bit (1/4 memory space framebu er)
Canvas_Mono (1/16 memory space framebu er)
The display only require refresh once after canvas draw nish and call ush(). It can reduce the display icking
substantially but requires more RAM.
First declare a canvas output display:
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = create_default_Arduino_DataBus();
Arduino_GFX *output_display = new Arduino_ST7789(bus, TFT_RST, 0 /* rotation */, true /* IPS */);
Some display support 3-bit color space like ILI9488. It is hard to direct implement 3-bit color space e ciently. But it can
work with a Canvas_3bit class in the middle:
#include <Arduino_GFX_Library.h>
// 3-bit color Canvas, R1G1B1, 8 colors
Arduino_G *output_display = new Arduino_ILI9488_3bit(bus, -1 /* RST */, 0 /* rotation */, false /* IPS */);
Arduino_GFX *gfx = new Arduino_Canvas_3bit(480 /* width */, 320 /* height */, output_display);
https://youtu.be/r7be0WbIBYk
Arduino_GFX support create default display class accordingly to selected built-in display dev device in Board selection
menu. Below are recognizable dev device:
Wio Terminal
M5Stack Core Family (v1)
Odroid Go
TTGO T-Watch
Simple declaration:
#include <Arduino_GFX_Library.h>
Arduino_GFX *gfx = create_default_Arduino_GFX();
Arduino_GFX: Page 32
https://youtu.be/oQQ6uSSbUzQ
https://youtu.be/UoPpIjVSO5Q
https://youtu.be/ZEvc1LkuVuQ
https://youtu.be/9AqsXMB8Qbk
https://youtube.com/shorts/V1MCQ1tQ8PM
https://youtu.be/q7vi-4infE8
https://youtu.be/Zk81_T8c20E
https://youtu.be/NkE-LhtLHBQ
Arduino_GFX: Page 34
https://youtu.be/wlx__QCNrzw
I made it!! thanks for the library, I made the example ImgViewerJpeg pi pico and ST7796S
Arduino_GFX: Page 35
Do your fonts include the degree symbol for rendering temperatures? Like 25°C or 75°F.
try `gfx->println("23""\xF7""C");`
The correct EASCII code for degree should be Hex F8, I have fix it in latest code. So the print
function should look like:
gfx->println("23""\xF8""C");
Thanks for the update. :-)
Hi,
Thanks for this!
When trying to run your Hello World demo for Pico Pi I get:
C:\Users\HOME\Documents\Arduino\libraries\GFX_Library_for_Arduino\src\databus\Arduino_HWSPI.cpp:69:16:
error: 'digitalPinToBitMask' was not declared in this scope
_dcPinMask = digitalPinToBitMask(_dc);
The digitalPinToBitMask does not seem to be defined for Pico Pi. Is there a way around this?
Thanks again,
Bill
I am using this core:
https://github.com/earlephilhower/arduino-pico.git
Ah, OK, thanks.
I have seen dramatic speed ups on LCD graphics when using the Mbed core versus the
Philhower core.
When using Bodmer;s TFT_eSPI graphics library with Earle Philhower's core versus the Arduino
Mbed core (for example Bodmer's bouncing circles INO), the Mbed core runs ~3X faster: 45fps
for the Mbed and 17fps for the Philhower core.
Have you done similar testing with your graphics library? I don't know why this is but it was easy
to reproduce.
Great tutorial. I tried an UNO and ESP32 I have not been successful. I have the round display
GC9A01. Could you post the full code of what I should have for the ESP32 and UNO please?
?
sorry, I did not have that board in hand. but the pin number should be the same.
I can get the pinout. But, I'm having issues with the code. Is it possible to post the complete code
for the ESP32?
You can find all the example code at Arduino IDE -> File -> Examples -> GFX Library for Arduino
Hi fantastic instructable! I have the GC9A01 running on the Arduino Nano and an SD card
(working OK with the example code). It is the 240x240 px round display, but I cannot display
square images larger than 165 pixels. The sketch does not validate it because the image is
square not round (it gives the error "bmpMalloc failed"). How do I use the full 240x240 pixels?
Arduino_GFX: Page 36
Could you post your code?
The malloc error come from the BmpClass.h, Arduino Nano do not have enough RAM allocate 1
row memory i.e. 240 * 16 bit, so throw this error. Please consider use other dev broad that have
more RAM or find other BMP library that no need buffer one row data(but it will draw much
slower).
But the nano still draws the picture if it is completely within the screen (i.e. 165 x 165 pixels). Are
you sure this is just a memory error? This seems like a coincidence.
Hi! Can u explain where i can change MOSI and SCLK pin for my nRF52 module (or other
microcontrollers too) ?
nRF52 module? I have no this type of dev board in hand, but many MCU cannot remap the
hardware SPI pins.
nRF52832-nRF52840 can change SPI pins, Adafruit GFX works good, but i don`t know where i
can remap pin in your Lib
I cannot find how Adafruit GFX change pins, do you have sample code?
I did not have dev board with this MCU, can you name the dev board using it? Or direct give us a
link?
This: https://www.adafruit.com/product/3406
This: https://www.sparkfun.com/products/13990
And Like this: https://www.adafruit.com/product/4062
U can just explain where contain setting about pins in your Lib and i try to check :)
ok, I will buy one to try when I have budget for it.
So can you tell me where I can set the parameters of the MISO and SCLK?
Really awesome Instructables! Certainly one of the best I've ever seen! Congratulations!!
Fantastic. All that information in one place. You have saved a lot of people many hours of search
and find and try.
This is amazing! What a great resource. :)
Arduino_GFX: Page 37