Introduction: Arduino TFT Display and Font Library
I am quite a fan of the Arduino as there is so much software already available on the internet, this makes completing new projects easier!
Recently I bought a few cheap 1.8" TFT displays for a project, initially I could not get them working which was frustrating. Eventually I found that the ones I had bought used the Samsung S6D02A1 driver chip and I had been trying to use the wrong library.
After a brief search on the web I came across the Adafruit_QDTech library which worked really well. This library is used in conjunction with the Adafruit_GFX library. After trying some examples I was a little disappointed that only scaled blocky fonts were available - so I have modified the original libraries to add some new fonts and functions.
Update 2/2/2015:
I have now added a driver library below for the 2.2" TFT QVGA 240x320 pixel display with the ILI9341 driver. This has examples included.
Update 3/2/2015:
I have now added a driver library for the 1.8" TFT display based on the ST7735 driver along with examples.
Update 14/6/2015:
I have added a new library for the 2.2" TFT QVGA 240x320 pixel display with the ILI9341 driver. This library is called TFT_ILI9341 and is a stand alone library that does not need the support of another GFX library. Compatibility with the Adafruit GFX library has been maintained. See Step 8 of this Instructable.
Step 1: Wiring It Up
I used the Arduino UNO and linked it to the 1.8" S6D02A1 based display as follows:
- UNO +5V to display pin 6 (VCC) and pin 7 (BL)
- UNO 0V (GND) to display pin 8 (GND)
- UNO digital pin 7 through a 1K2 resistor to display pin 1 (RST)
- UNO digital pin 8 through a 1K2 resistor to display pin 3 (D/C)
- UNO digital pin 9 through a 1K2 resistor to display pin 2 (CS)
- UNO digital pin 11 through a 1K2 resistor to display pin 4 (DIN)
- UNO digital pin 13 through a 1K2 resistor to display pin 5 (CLK)
The 1K2 resistors are required to protect the display being damaged by the 5V logic levels from the UNO, these limit the current flow. Ideally we could use a level shifter but the resistors work fine.
Update 2/2/2015
You can also now use the 2.2" QVGA TFT SPI display based on the ILI9341 driver. To use this display load the Adatfruit_IL9341_AS and Adafruit_GFX_AS libraries. Connect the display to the UNO as follows:
- UNO +5V to display pin 1 (VCC)
- UNO +5V through a 56 Ohm resistor to display pin 8 (LED)
- UNO 0V (GND) to display pin 2 (GND)
- UNO digital pin 7 through a 1K2 resistor to display pin 4 (RESET), add a 1K8 resistor from display pin 4 to GND
- UNO digital pin 8 through a 1K2 resistor to display pin 5 (DC/RS), add a 1K8 resistor from display pin 5 to GND
- UNO digital pin 9 through a 1K2 resistor to display pin 3 (CS), add a 1K8 resistor from display pin 3 to GND
- UNO digital pin 11 through a 1K2 resistor to display pin 6 (SDI/MOSI), add a 1K8 resistor from display pin 6 to GND
- UNO digital pin 13 through a 1K2 resistor to display pin 7 (SCK), add a 1K8 resistor from display pin 7 to GND
It is important to include the 1K8 resistors to GND with this 2.2" display as otherwise it will not work. The 1K2 and 1K8 resistors are a "potential divider", acting as a logic level shifter so that the logic level at the display is reduced from 5V to around 3V. Pin 9 of the display does not need to be connected up.
Some displays of this type do not have a LED series resistor built in so the 56 Ohm value above is needed to limit the LED current to about 50mA.
Update 3/2/2015
The 1.8" 128x160 pixel display based on the ST7735 driver is now also supported. To use this display load the Adafruit_ST7735_AS and Adafruit_GFX_AS libraries. Connect the UNO to the display as follows:
- UNO +5V to display pin 1 (VCC) and pin 8 (LED)
- UNO 0V (GND) to display pin 2 (GND)
- UNO digital pin 7 through a 1K2 resistor to display pin 4 (RESET)
- UNO digital pin 8 through a 1K2 resistor to display pin 5 (AO)
- UNO digital pin 9 through a 1K2 resistor to display pin 3 (CS)
- UNO digital pin 11 through a 1K2 resistor to display pin 6 (SDI)
- UNO digital pin 13 through a 1K2 resistor to display pin 7 (SCK)
Step 2: Loading the Libraries (updated 3/2/15)
I have modified the Adafruit libraries and added the fonts. The fonts will be stored in FLASH so will use up some program space however a reasonable amount of space is still available, if you run out then use an Arduino Mega board.
I am actually a hardware designer so the software updates could probably be improved, but they are working!
The zip file contains the two libraries you will need. These have have new names (_AS appended) so they will coexist with any libraries you already have. There are 3 example programs included in the Adafruit_QDTech_AS library.
I updated the libraries to version 5 on 2/2/2015, now individual fonts can be disabled to save FLASH memory if they are not all needed. To prevent particular font files being loaded simply edit the "Load_fonts.h" file within the "Adafruit_GFX_AS" library folder. Just comment out the fonts not needed by adding // to the beginning of the respective line. Also, in response to a question from a reader below, I have made the proportional fonts scalable just like the original simple Adafruit, this makes the fonts more blocky but providing the scale factor is not more than 2 the fonts still look reasonable. In the example TFT_Show_Font_ILI9341 I use the commands:
tft.setTextSize(1); // For normal sized fonts
tft.setTextSize(2); // For double sized fonts
Other minor tweaks have been made so that the font background will be drawn as per original Adafruit font. The font drawing speed has also been improved. Minor tweaks have been made to the fonts, Font 4 has been reduced in height slightly to remove superfluous "whitespace" and a full stop "." has been added to the characters available in the large font 6.
Minor tweaks to the fonts have been made and new example sketches have been added to show all font characters.
Attachments
Step 3: Example Programs
The example programs are:
- TFT_Rainbow - gives some examples of drawing the fonts on the display
- TFT_Clock - an analogue clock drawn with the standard Adafruit graphics routines plus a centred line of text in Font 4
- TFT_Clock_Digital - a digital clock using the 7 segment display font and other font drawing examples.
- TFT_Show_Font - draws the different fonts and characters on the screen
Step 4: Library Functions and Fonts
Here are the library functions that can be called:
- int drawUnicode(unsigned int uniCode, int x, int y, int size);
- int drawNumber(long long_num,int poX, int poY, int size);
- int drawChar(char c, int x, int y, int size);
- int drawString(char *string, int poX, int poY, int size);
- int drawCentreString(char *string, int dX, int poY, int size);
- int drawRightString(char *string, int dX, int poY, int size);
- int drawFloat(float floatNumber,int decimal,int poX, int poY, int size);
In summary, the X and Y parameters are the coordinates for the drawing.
Each function returns the X position delta to the end of the printed characters.
"size" is the font size:
- Only font numbers 2,4,6,7 are valid
- Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 - . : a p m
- Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
The fonts are proportionally spaced to give an improved appearance.
The routine for floating point numbers uses a parameter "decimal" which defines the number of decimal places to show, this aids formatting and displaying sensor readings, the number is rounded, so for example if decimal = 3, then 3.14159 will display as 3.142 and 3.14 will display as 3.140
drawCentreString will centre the string around the x position. convenient for tidy display formatting
drawRightString will draw the string right justified to the x position, useful for labels that are followed by sensor readings printed afterwards.
Update 2/2/2015:
Added new library "Adafruit_ILI9341_AS" so a 2.2" TFT 240x320 pixel display can also be used.
All fonts can now be scaled:
tft.setTextSize(1); // For normal sized fonts
tft.setTextSize(2); // For double sized fonts
Also:
drawUnicode(unsigned int uniCode, int x, int y, int size)
is no longer in the latest libraries, please use:
drawChar(char c, int x, int y, int size)
instead.
Step 5: Have Fun!
I hope you find this Instructable useful!
P.S. I am am not connected with Adafruit, but do check out their great products and look for the support on using the standard graphics library functions (these remain within the adapted libraries).
Step 6: Requests...
Here we have some responses to requests:
1. A replacement Font32.c file with the Grave accent being drawn as a degree symbol.
2. A Sketch that has a function to wrap text to next line or back to the top.
A faster drawing ILI9341 library to try with any ATmega328 based Arduino can be found attached to my Instructable here.
Attachments
Step 7: Displaying Images Stored on an SD Card
I have now created a new Instructable for drawing bitmap image files stored on an SD Card on the display:
https://www.instructables.com/id/Arduino-TFT-displa...
This is compatible with the ILI9341 driver based TFT boards.
Step 8: New Fast Library for the ILI9341 Based TFT Display With Run Length Encoded Fonts
This new library is a standalone library that contains the TFT driver as well as the graphics functions and fonts that were in the GFX library. This library has significant performance improvements when used with an UNO (or ATmega328 based Arduino) and MEGA.
Examples are included with the library, including graphics test programs. The example sketch TFT_Rainbow_one shows different ways of using the font support functions. This library now supports the "print" library so the formatting features of the "print" library can be used, for example to print to the TFT in Hexadecimal, for example:
tft.println(57005, HEX);
The larger fonts are now Run Length Encoded (RLE) so that they occupy less FLASH space, this frees up space for the rest of the sketch. A byproduct of the RLE approach is that the font drawing is also speeded up so it is a win-win situation.
A new 72 point large Font 8 has been added that contains [space]1234567890:. characters.
To use the F_AS_T performance option the ILI9341 based display must be connected to an UNO as follows:
- UNO +5V to display pin 1 (VCC) and pin 8 (LED)
- UNO 0V (GND) to display pin 2 (GND)
- UNO digital pin 7 through a 1K2 resistor to display pin 4 (RESET), add a 1K8 resistor from display pin 4 to GND
- UNO digital pin 9 through a 1K2 resistor to display pin 5 (DC/RS), add a 1K8 resistor from display pin 5 to GND
- UNO digital pin 10 through a 1K2 resistor to display pin 3 (CS), add a 1K8 resistor from display pin 3 to GND
- UNO digital pin 11 through a 1K2 resistor to display pin 6 (SDI/MOSI), add a 1K8 resistor from display pin 6 to GND
- UNO digital pin 13 through a 1K2 resistor to display pin 7 (SCK), add a 1K8 resistor from display pin 7 to GND
When using an UNO the CS line must be connected to pin 10 and DC line to pin 9, this is because the optimised code uses direct port access.
When using the UNO comment out the MEGA_TFT_ILI9341 #define in the library Run_faster.h file.
This library only supports hardware SPI, so pins 11 and 13 on the UNO must be used as listed above.
To use the F_AS_T performance option the ILI9341 based display must be connected to an MEGA as follows:
- MEGA +5V to display pin 1 (VCC) and pin 8 (LED) UNO 0V (GND) to display pin 2 (GND)
- MEGA digital pin 44 through a 1K2 resistor to display pin 4 (RESET), add a 1K8 resistor from display pin 4 to GND
- MEGA digital pin 48 through a 1K2 resistor to display pin 5 (DC/RS), add a 1K8 resistor from display pin 5 to GND
- MEGA digital pin 47 through a 1K2 resistor to display pin 3 (CS), add a 1K8 resistor from display pin 3 to GND
- MEGA digital pin 51 through a 1K2 resistor to display pin 6 (SDI/MOSI), add a 1K8 resistor from display pin 6 to GND
- MEGA digital pin 52 through a 1K2 resistor to display pin 7 (SCK), add a 1K8 resistor from display pin 7 to GND
When using a MEGA the CS line must be connected to pin 47 and DC line to pin 48, this is because the optimised code uses direct port access.
When using the MEGA ensure the MEGA_TFT_ILI9341 #define in the library Run_faster.h file in not commented out.
This library only supports hardware SPI, so pins 51 and 52 on the MEGA must be used as listed above.
In the library Font 0 (GLCD font), 2, 4, 6 and 8 are enabled. Edit the Load_fonts.h file within the library folder to enable/disable fonts to save space.
Remember: disabling fonts saves FLASH space, and disabling them means they cannot be displayed!
TFT_ILI9341 library updated on 1st July 2015 to version 12, this latest version is attached here to step 8:
- Minor bug when rendering letter 'T' in font 4 without background fixed
- RLE fonts are now rendered without overlap (improves rendering speed and stops flicker of adjacent character)
Attachments
Step 9: TFT_ILI9341 Library Updated 31/7/15
TFT_ILI9341 library has been updated to version 14 beta, this latest version is attached below.
1. Text algnment, the datum for drawing strings and numbers can be changed with a new function: tft.setTextDatum(datum); See example sketch included "TFT_String_Align"
2. Performance improvements, in particular line drawing is much faster now (thanks Spellbuilder)
3. There is a new "User_Setup.h" file inside the library where all the settings can be controlled, eg. pins used for the TFT interface and the fonts loaded. See the comments in the header file. The pins are defined in this header so to invoke the custom library the pin references must be removed from legacy sketches so it reads: TFT_ILI9341 tft = TFT_ILI9341(); // Invoke custom library
4. The FastPin.h header has been adopted from the FastLED library, this allows any control pins to be used for CS, DC and RST whilst still getting the best pin toggle performance (thanks Marstom)
This v14b is a beta version as there is a minor bug in the drawFloat() function that I need to fix!
This library has been developed for my own hobby use. If you do find a problem with it then please report bugs here. TTFN
Attachments
Step 10: TFT_ILI9341 Library Now on Github
As I have been making minor tweaks to the ILI9341 library (and because it has proved to be popular!) I have put the TFT_ILI9341 library on Github. You can down load the latest here:
https://github.com/Bodmer/TFT_ILI9341
Using the Download Zip button is probably the easiest method if you do not have a GitHub client loaded.
A request has been posted to the Arduino team to have it listed in the IDE Library Manager.
Typically performance is 3 times faster than the standard Adafruit GFX library (see table for speed comparison) and up to 20 times faster than UTFT. So the graphics drawing performance is now about as good as it is going to get on a humble UNO/AVR Arduino!
Full 320 x 240 screens are cleared in 174ms, raw image files can be pulled off an SD Card and drawn in 400ms using the tweaked version of the SdFat library here:
https://github.com/Bodmer/TFT_SdFat
I have also created a touch screen library for the 2.4" ILI9341 TFT display fitted with the XPT2046 touch controller. The touch library can be downloaded here:
https://github.com/Bodmer/TFT_Touch
I will be creating a more comprehensive instructable at a future date to document all the font and formatting features of the graphics library.
Step 11: Update: June 2016 - More Libraries on GitHub
I have improved the performance of the ST7735 and S6D02A1 libraries. Copies are available here:
and here:
292 Comments
8 years ago on Introduction
Hi, nice job ! I have it running now on an UNO now with a 2,2 inch display. Never had a library before that fitted in the UNO and had such nice characters !
I'm now trying to port it to a STM Nucleo board where I have loads of Flash available. In the code I see fonts 1,3, and 5 mentioned but the are not provided. Do you have these fonts available ? Would like to try them when I have the Nucleo up and running. I use the non RLE fonts.
Thanks !
Reply 8 years ago on Introduction
Hi, thanks for your feedback.
The font numbers 1, 3 and 5 were reserved for intermediate sizes of the same font style (aka similar to Helvetica), but I did not need these sizes in the end and never created the required files. If you have a particular need then I may be able to create new files but you will need to be patient as I spend less time tinkering with electronics and software in the summer!
Question 7 months ago
I As a beginner I am having a great deal of trouble getting going. I have down loaded and unzipped TFT_ILI9341, and saved the fonts in Arduino/Libraries/Adafruit_GFX_Library/Fonts but when I include the lines # include <Fonts/Font64rle> and tft.setFont(&Font64rle); in my sketch I get the error <Font64rle not declared in this sketch>
What am I doing wrong or not doing? Where should the files TFT_FastPin & TFT_ILI9341 be saved (after extraction from zip file)?
Help please!
Question 1 year ago on Step 1
Thanks for this tutorial. Do you have a version for ESP32 ?
3 years ago
Just great on ST7735!
I found it fails with some characters, for example "°" (for "°C" or "°F"), did I miss something ?
3 years ago
Hello Mr. Bodmer,
Thank you so much for all the work you have done!! Amazing! Really!
I got your Adafruit_GFX_AS and ILI9341_AS libraries working -- I am reading RAW files from a card reader and displaying them with the drawRAW function. The speed is amazing, around 715 ms to draw an image. Then I read the documentation with this library, and I would love to get that down to the 400 ms you indicated. However, when I swapped out the TFT_ILI9341 library and re-ran my sketch, I got the following error in the drawRAW function...
'void TFT_ILI9341::setAddrWindow(int16_t, int16_t, int16_t, int16_t)' is private within this context
I am wondering if there is anything that you can do to help me out. I searched through the example sketches you included, but I was unable to locate any that contained the drawRAW function specifically for the TFT_ILI9341 library. I am quite a newbie when it comes to Arduino C, and I have no idea what that message means.
Thanks!
Tip 4 years ago
Hi, I made speedometer used st7735 and arduino uno, thank you instructables
Question 4 years ago
Does it have any substitute of drawRGBBitmap from adafruit?
Question 4 years ago on Step 6
Is there a way to use more than one screen with Your library, where should I apply changes?
4 years ago
HI
Thanks a lot for the library.
Wich tool and/or settings did u use to make/modify the fonts? I need some special characters ;) thanks.
5 years ago on Step 9
Hi, and thanks for this great library.
1. Where can I find the command syntax of all the commands used it the library ?
2. Is there anyway to use other fonts ?
Reply 4 years ago
Unfortunately there is no manual. The library uses the same functions as the Adafruit_GFX library plus some new ones associated with the fonts and text handling. It is a case of looking at the examples.
5 years ago
Dear,
again thanks for fentastic codes for ST7735. After a deep check I have successed to run all 03
example......thanks again
5 years ago
Dear,
I just use your good library, first I try "TFT_Clock_ST7735.ino" sketch exmp but I always get an errors " as given.
Arduino: 1.8.3 (Windows XP), Board: "Arduino/Genuino Uno"
TFT_Clock_Digital_ST7735:46: error: 'conv2dec' was not declared in this scope
uint8_t hh=conv2dec(__TIME__), mm=conv2d(__TIME__+3), ss=conv2d(__TIME__+6); // Get H, M, S from compile time
^
C:\DOCUME~1\SANJIV~1\LOCALS~1\Temp\arduino_modified_sketch_510720\TFT_Clock_Digital_ST7735.ino: In function 'void loop()':
TFT_Clock_Digital_ST7735:68: error: 'ss' was not declared in this scope
ss++; // Advance second
^
TFT_Clock_Digital_ST7735:71: error: 'mm' was not declared in this scope
omm = mm;
^
TFT_Clock_Digital_ST7735:98: error: 'mm' was not declared in this scope
if (omm != mm) { // Only redraw every minute to minimise flicker
^
exit status 1
'conv2dec' was not declared in this scope
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
Thanks a lot
5 years ago
Thanks a lot for this great library! It is really fast.
I use a 128x128 pixel ST7735 TFT however there is an offset of two or three pixels left and top. I have read the tutorial, but found nothing about a offset correction. Furthermore, there is a problem with the positioning of the text after an SD card has been initialised.
With following code:
#include // Hardware-specific library
#include
#include
TFT_ST7735 tft = TFT_ST7735(128, 128); // Invoke custom library
#define SD_CS 37
Sd2Card card;
void setup(void) {
Serial.begin(115200);
Serial.print("Hello! ST7735 TFT Test");
// Use this initializer if you're using a 1.8" TFT
tft.init(); // initialize a ST7735S chip
tft.setRotation(1); // landscape
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0, 0);
tft.print("TEST:");
tft.println(" OK");
tft.println("Init SD card");
tft.print("SD:");
boolean initSD = card.init(SPI_HALF_SPEED, SD_CS);
if (!initSD) {
tft.println(" NOK");
} else {
tft.println(" OK");
}
}
void loop() {}}
As you can see on the picture, the text "OK" after the text "Test" is ok. The "OK" to "SD:" is some how under the text "DS:".
I have no idea how to fix that.
Some idea?
THX a lot!
Reply 5 years ago
SD problem fixed be using the SdFat.h lib.
Right now just the OFFSET problem ...
5 years ago
Hi Bodmer,
thank you very much for this work, please check attached pictures, it working fine using tft7735 1.8" and everything alright except, when i use code to read from my sensor: reading= analogRead(A0).
as you can see from the picture first reading is ok but when i change the potentio-meter numbers not clear as the previous numbers seems not updated, i guess its string char conversion but i stuck and i need help if that ok to clear this.
Thank you very much
Reply 5 years ago
Set the foreground and background colors and the test should overwrite old values.
Reply 5 years ago
It looks like you have switched off rendering the font text background?
Use a line like:
tft.setTextColor(TFT_WHITE,TFT_BLACK);
5 years ago
Hi,
Thanks for the nice libraries.
I converted some parts to work on the ILI9163 ,works great!
Draw lines,circles,various colors,write strings...etc.
But i cannot write a variable value on the tft display.
I tried the ''drawChar'' from the library ,I use the ITOA function in Avr Studio to write the ADC value ,,,but cannot get it to work with your library and ARDUINO.
Must I use ITOA or does your library do all the work,I can follow what you do but only up to
a point ,some of your code gets real deep beyond me.
I only started C Programming a few months back....many years of playing with Pic's and Assembler.
Can you please give a small example of how to use this function.
Thanks Great Work!