Two TFT Graphics Libraries
29th March 2026
This article describes two alternative graphics libraries that support a range of different colour TFT displays, and combine fast performance with minimal memory usage:

The Sampler example running on an ATtiny85 and
driving an Adafruit 1.28" round 240x240 colour TFT display.
Introduction
- The Tiny TFT Graphics Library is specifically aimed at ATtiny microcontrollers. It supports both the classic ATtiny processors, such as the ATtiny85, and the new 0-Series, 1-Series, and 2-Series ATtiny processors, such as the ATtiny402. It uses direct I/O pin manipulations, which means that you can use any assignment of pins to the four I/O lines needed by the display.
- The Compact TFT Graphics Library uses standard Arduino SPI calls to interface with the display, so it will work with any board or processor that supports SPI.
Both libraries support the same range of TFT displays from a variety of suppliers including Adafruit and AliExpress, from resolutions of 128x128 and 160x80 up to 320x240. These latest versions of the libraries add support for round 240x240 TFT displays based on the GC9A01A display driver.
The libraries each provide the same graphics functions, allowing you to plot points, draw lines, draw outline and filled rectangles, draw outline and filled circles, and plot characters and text with an optional scale factor, all in 16-bit colour. These updated versions of the libraries also add functions to draw outline and filled triangles and quadrilaterals, and to allow plotting using relative coordinates rather than absolute coordinates, which can be more intuitive for some applications.
These updated versions have evolved from libraries I published on earlier occasions: Tiny TFT Graphics Library 2 and Compact TFT Graphics Library.
Performance and memory
Originally the bit manipulations used by the Tiny TFT Graphics Library made it substantially faster than the SPI interface used by the Compact TFT Graphics Library, but I've made improvements to the latter that now makes them close in performance.
Depending on which drawing functions you use, the libraries will often fit in 4K bytes and so will run on microcontrollers with as little as 4K bytes of flash, such as the ATtiny45, ATtiny402, and ATtiny412.
The following table shows the difference in performance and memory usage for clearing the display, and running the three example programs, on a 20MHz ATtiny814 driving an Adafruit 1.3" 240x240 TFT display:
| Compact TFT Graphics Library | Tiny TFT Graphics Library | |||||
| Time | RAM | Flash | Time | RAM | Flash | |
| ClearDisplay() | 350ms | 29 bytes | 2362 bytes | 277ms | 16 bytes | 1866 bytes |
| Sampler() | 162ms | 35 bytes | 5948 bytes | 216ms | 22 bytes | 5406 bytes |
| BarChart() | 261ms | 35 bytes | 3890 bytes | 390ms | 22 bytes | 3378 bytes |
| Waterfall() | 488ms | 31 bytes | 3532 bytes | 561ms | 18 bytes | 2980 bytes |
For all figures, lower is better.
Supported displays
The libraries will work with displays based on the ST7735 which supports a maximum display size of 162x132, the ST7789 and ILI9340/1 which support a maximum display size of 320x240, and the GC9A01/A which supports 240x240. They include settings for the following colour TFT displays:
| Supplier | Size | Width | Height | Voltage | Driver | Link |
| Adafruit | 1.44" | 128 | 128 | 3.3 - 5V | ST7735R | Adafruit 1.44" Color TFT LCD Display * |
| AliExpress | 1.44" | 128 | 128 | 3.3 - 5V | ST7735R | 1.44" 128x128 SPI TFT display † |
| Adafruit | 0.96" | 160 | 80 | 3.3 - 5V | ST7735 | Adafruit 0.96" 160x80 Color TFT Display * |
| AliExpress | 0.96" | 160 | 80 | 3.3V | ST7735 | TFT Display 0.96 inch 80x160 † |
| Adafruit | 1.8" | 160 | 128 | 3.3 - 5V | ST7735R | Adafruit 1.8" Color TFT LCD display |
| AliExpress | 1.8" | 160 | 128 | 3.3V | ST7735R | 1.8 inch TFT LCD Module 128x160 Red PCB |
| AliExpress | 1.8" | 160 | 128 | 3.3V | ST7735R | 1.8" 128x160 SPI TFT Display Blue PCB † |
| Adafruit | 1.14" | 240 | 135 | 3.3 - 5V | ST7789 | Adafruit 1.14" 240x135 Color TFT Display * |
| AliExpress | 1.14" | 240 | 135 | 3.3V | ST7789 | 1.14in SPI 240x135 RGB TFT display † |
| Adafruit | 1.28" round | 240 | 240 | 3.3 - 5V | GC9A01A | Adafruit 1.28" 240x240 Round TFT Display * |
| AliExpress | 1.28" round | 240 | 240 | 3.3V | GC9A01 | 1.28" 240x240 Round TFT Display Octagonal PCB † |
| AliExpress | 1.28" round | 240 | 240 | 3.3V | GC9A01 | 1.28" 240x240 Round TFT Display Round PCB |
| Adafruit | 1.3" | 240 | 240 | 3.3 - 5V | ST7789 | Adafruit 1.3" 240x240 Wide Angle TFT LCD Display * |
| Adafruit | 1.54" | 240 | 240 | 3.3 - 5V | ST7789 | Adafruit 1.54" 240x240 TFT LCD Display * |
| AliExpress | 1.54" | 240 | 240 | 3.3V | ST7789 | 1.54" 240x240 TFT LCD Display † |
| Adafruit | 1.9" | 320 | 170 | 3.3 - 5V | ST7789 | Adafruit 1.9" 320x170 Color IPS TFT Display * |
| AliExpress | 1.9" | 320 | 170 | 3.3V | ST7789 | 1.9" 170x320 TFT LCD Display † |
| Adafruit | 1.47" | 320 | 172 | 3.3 - 5V | ST7789 | Adafruit 1.47" 320x172 Rounded TFT Display * |
| AliExpress | 1.47" | 320 | 172 | 3.3V | ST7789 | 1.47" 172x320 Rounded TFT LCD Display † |
| Adafruit | 2.0" | 320 | 240 | 3.3 - 5V | ST7789 | Adafruit 2.0" 320x240 Color TFT Display * |
| AliExpress | 2.0" | 320 | 240 | 3.3V | ST7789V | 2.0" TFT 240x320 LCD Display |
| Adafruit | 2.2" | 320 | 240 | 3.3 - 5V | ILI9340C | Adafruit 2.2" 320x240 Color TFT Display |
| AliExpress | 2.4" | 320 | 240 | 3.3V | ILI9341 | 2.4" 320x240 TFT Display Module Blue PCB † |
* These Adafruit displays conveniently all have the same 11-way edge-connector layout, so you can make a prototyping board or PCB that will take any of them, such as my Universal TFT Display Backpack.
† Likewise, these AliExpress displays have the same 8-way edge-connector layout, and are also compatible with my Universal TFT Display Backpack.
Options
The AliExpress displays sometimes include a LDO 3.3V regulator, but not logic-level translation, so I recommend only interfacing them to a processor running from 3.3V.
The Adafruit displays all include an LDO 3.3V regulator and logic-level translation, so can be safely interfaced to processors powered from either 5V or 3.3V.
On some AliExpress displays, such as the red 160x128 display, the backlight isn't on by default and you need to connect the backlight pin to Vcc to turn it on.
The libraries allow you to choose the orientation of the display image, to cater for different mounting choices.
The libraries will probably support other TFT displays that use the same ST7735, ST7789, ILI9340/1, or GC9A01/A driver chips, but you may need to experiment with the parameters to get the image scaled and centered correctly. You can use the included TestChart() function to help with this; see Test chart.
Using the graphics libraries
To use the graphics libraries you need to connect up the display correctly, and then select the correct parameters for the display you are using.
The display needs to be connected to the microcontroller via four I/O lines. Note that on different display boards the pins are labelled in a variety of ways:
| Pin | Labelled |
| Vcc | Vin |
| Ground | GND |
| Clock | SCK, SCL |
| Data In | MOSI, SI, SDA |
| Chip Select | CS, TCS |
| Data/Command | DC, D/C, A0 |
| Backlight | LITE, LIT, BLK, BL |
Don't be confused by pins labelled SCL and SDA on some displays; these are all definitely SPI displays!
Tiny TFT Graphics Library
With the Tiny TFT Graphics Library you can use any pins for the four I/O lines MOSI, SCK, CS, and DC, but they should all be in the same port. You need to specify the port pin numbers of the pins you are using at the start of the Tiny TFT Graphics Library listing.
For the ATtiny402/412:
// ATtiny 0, 1, or 2-Series PORTA positions. Change these for your circuit const int dc = 7; const int mosi = 1; const int sck = 3; const int cs = 6;
For the ATtiny45/85:
// ATtiny45/85 PORTB positions. Change these for your circuit const int dc = 4; const int mosi = 1; const int sck = 2; const int cs = 3;
Note that in this case these are PORT bit numbers, not Arduino pin numbers.
The default pin connections shown above are correct for the two circuits shown below.
Compact TFT Graphics Library
With the Compact TFT Graphics Library two of the I/O lines, Data In and Clock, are dictated by the SPI interface on the processor you are using. They are usually called MOSI and SCK on the pinout diagram, and they connect to the appropriate two pins on the display.
For the other two signals, Chip Select and Data/Command, you can use any two spare I/O lines on the processor, on any port. You need to specify the Arduino pin numbers of the two pins you are using at the start of the Compact TFT Graphics Library listing.
For the ATtiny402/412:
// Arduino pin numbers. Change these for your circuit const int cs = PIN_PA6; // TFT display SPI chip select pin const int dc = PIN_PA7; // TFT display data/command pin
For the ATtiny45/85:
// Arduino pin numbers. Change these for your circuit const int cs = PIN_PB3; // TFT display SPI chip select pin const int dc = PIN_PB4; // TFT display data/command pin
Note that in this case these are Arduino pin numbers or PIN #defines, not PORT bit numbers.
The default pin connections shown above are correct for the two circuits shown below.
Typical circuits
The following circuits can be used with either library.
ATtiny402/412
This circuit is based on an 8-pin ATtiny402 or ATtiny412:

Circuit of the TFT colour graphics display interface using an ATtiny402.
You can omit the 10kΩ pullup if you're using an Adafruit display, as these include a pullup on the board.
ATtiny85/45
This circuit is based on a classic ATtiny45 or ATtiny85:

Circuit of the TFT colour graphics display interface using an ATtiny85.
The 33kΩ pullup resistor from the display's CS pin is optional; it is only needed on the AliExpress displays, and holds the chip select high to prevent the display from flickering while programming the ATtiny85.
You can omit the 10kΩ pullup if you're using an Adafruit display, as these include a pullup on the board.
Specifying the display
In both libraries the different displays are catered for by seven constants which specify the size of the display, the offsets relative to the area supported by the display driver, whether the display is inverted, the rotation value, and the order of the colours; for example:
// Adafruit 1.44" 128x128 display int const xsize=128, ysize=128, xoff=2, yoff=1, invert=0, rotate=3, bgr=1;
Uncomment the parameters for the display you're using. In addition for the GC9A01/A displays you need to uncomment the line:
// #define GC9A01A
By default the parameters orient the image assuming you're using the display with the board in its natural orientation, except in the case of the larger displays which have the header pins along the shorter edge, in which case the header pins are assumed to be on the left.
However, you can choose to have the image in any orientation, specified by the value of the constant rotate:

Test Chart test pattern.
The other possible values of rotate, 1, 2, 4, or 7, should be selected if the image appears mirrored.
Note that on some displays you may also have to change the xoff or yoff value when rotating the image.
Test chart
To check or adjust the values for each display you can run the TestChart() function, which draws a one-pixel border around the display area, and plots a red "F" to show the orientation:
For example:

The Test Chart running on an ATtiny402 and driving
an AliExpress 1.14" 240x135 colour TFT display.
If the 'F' is blue you need to change the value of bgr.
The library will probably support other TFT displays that use the same driver chips, but you may need to experiment with the parameters to get the image scaled and centered correctly.
Graphics commands
Here is a summary of the graphics commands provided by this library:
Colour
The library uses a 16-bit colour mode, which assigns 5 bits to red, 6 bits to green, and 5 bits to blue.
Colour() lets you create a colour value by specifying its red, green, and blue components as numbers from 0 to 255:
unsigned int Colour (int r, int g, int b)
Foreground and background
The foreground and background colours are defined by the two global variables fore and back. Initially these are set to White (0xFFFF) and Black (0) respectively.
Clearing the display
ClearDisplay() clears the display to black:
void ClearDisplay ()
Current drawing position
The graphics functions use a conventional coordinate system with the origin at lower left. For example, on the 80x160 display:

Unlike some other graphics libraries, such as Adafruit's GFX library, this library uses a current drawing position to reduce the number of parameters that have to be supplied to each function. The current drawing position is stored in the global variables xpos and ypos, and you can change this with MoveTo():
void MoveTo (int x, int y)
Alternatively the command MoveBy() moves the drawing position relative to its previous position:
void MoveBy (int x, int y)
Plotting points
PlotPoint() plots a single point in the current foreground colour:
void PlotPoint (int x, int y)
Drawing lines
DrawTo() draws a line in the foreground colour from the current drawing position to x,y, and updates the drawing position to this:
void DrawTo (int x, int y)
Alternatively the command DrawBy() draws a line relative to the drawing position:
void DrawBy (int x, int y)
Drawing rectangles
DrawRect() draws an outline rectangle and FillRect() draws a filled rectangle in the foreground colour with width w and height h, and the bottom left corner at the current drawing position:
void DrawRect (int w, int h) void FillRect (int w, int h)
The drawing position doesn't change.
Drawing circles
DrawCircle() draws an outline circle and FillCircle() draws a filled circle in the foreground colour with radius radius, and the centre at the current drawing position:
void DrawCircle (int radius)
void FillCircle (int radius)
The drawing position doesn't change.
Drawing triangles
DrawTriangle() draws an outline triangle from the drawing position to two other points, and FillTriangle() draws a filled triangle:
void DrawTriangle (int x1, int y1, int x2, int y2) void FillTriangle (int x1, int y1, int x2, int y2)
The drawing position doesn't change.
Alternatively, DrawTriangleBy() and FillTriangleBy() allow you to specify each point relative to the previous point:
void DrawTriangleBy (int x1, int y1, int x2, int y2)
void FillTriangleBy (int x1, int y1, int x2, int y2)
Drawing quadrilaterals
DrawTriangle() draws an outline triangle from the drawing position to three other points, and FillQuad() draws a filled quadrilateral.
void DrawQuad (int x1, int y1, int x2, int y2, int x3, int y3)
void FillQuad (int x1, int y1, int x2, int y2, int x3, int y3)
The drawing position doesn't change.
Alternatively, DrawQuadBy() and FillQuadBy() allow you to specify each point relative to the previous point:
void DrawQuadBy (int x1, int y1, int x2, int y2, int x3, int y3)
void FillQuadBy (int x1, int y1, int x2, int y2, int x3, int y3)
So, for example, to draw a filled diamond with its leftmost vertex at the drawing position:
FillQuadBy(50, 50, 50, -50, -50, -50);
Note that FillQuad() and FillQuadBy() don't handle concave quadrilaterals, such as:

These can instead be drawn as two filled triangles.
For more information about the triangle and quadrilateral functions see my article Drawing Filled Quadrilaterals and Triangles.
Characters and text
The library includes a character set based on a 5x7 dot matrix.
PlotChar() plots a specified character at the current plot position, and in the current foreground colour:
void PlotChar (char c)
You can plot larger characters by setting the global variable scale, default value 1. After plotting a character PlotChar() moves the drawing position to the start of the next character to make it easy to plot several characters in a row without needing to call MoveTo().
PlotText() plots text from a constant string in program memory:
void PlotText (PGM_P p)
For example:
PlotText(PSTR("Temperature"));
PlotChars() plots text from a char array:
void PlotChars (char *s)
For example, to display a floating-point value:
float Sensorval = 5.23; char buff[10]; dtostrf(sensorVal, 4, 2, buff); PlotChars(buff);
PlotInt() plots a positive or negative integer:
void PlotInt (int i)
Reading from the display
I chose not to include my routine to read from the display in these libraries because it only supports a subset of the TFT displays listed here. For an explanation, and details of the routine if you want to add it, see Reading from a TFT Display.
Examples
Both libraries include the following examples to demonstrate the drawing functions.
Bar chart
The BarChart() example draws a random bar chart, with axes, that automatically scales to fit the dimensions of the display:

The Bar chart example running on an ATtiny402 and driving
an Adafruit 2.2" 320x240 colour TFT display.
Waterfall plot
The Waterfall() example plots a three-dimensional curve; again, it automatically scales to fit the display:

The Waterfall example running on an ATtiny85 and driving
an Adafruit 2.0" 320x240 colour TFT display.
Sampler
The Sampler() example demonstrates most of the graphics commands in a table, designed to fit on a round 240x240 display, or any display 240x240 or larger. Here it is running on a round 240x240 display, using my Universal TFT Display Backpack:

The Sampler example running on an ATtiny814 and
driving an AliExpress 1.28" round 240x240 colour TFT display.
Compiling the graphics library
ATtiny402/412
Compile the program using Spence Konde's megaTinyCore [1]. Choose the ATtiny412/402/212/202 option under the megaTinyCore heading on the Board menu.
- Check that the subsequent options are set as follows (ignore any other options):
Chip: "ATtiny402" or "ATtiny412"
Clock: "20 MHz internal"
To program the processor the recommended option is to use a 3.3V USB to Serial board, such as the SparkFun FTDI Basic board [2], or a USB to Serial cable [3], connected with a Schottky diode as follows. You can substitute a 4.7kΩ resistor for the Schottky diode:

- Set the Programmer option to "SerialUPDI - 230400 baud".
- Upload the program.
ATtiny85/45
Compile the program using Spence Konde's ATTiny Core [4]. Choose the ATtiny25/45/85 (No bootloader) option under the ATTinyCore heading on the Board menu.
- Check that the subsequent options are set as follows (ignore any other options):
Chip: "ATtiny85" or "ATtiny45"
Clock Source: "8 MHz (internal)"
Use an ISP (in-system programming) programmer to program the chip. If your display is a 5V board you could use Sparkfun's Tiny AVR Programmer Board [5]. If your display only supports a 3.3V supply make sure your programmer has a 3.3V option, such as USBasp [6], widely available on eBay.
- Set the Programmer option to "USBtinyISP" or "USBasp" as appropriate.
- Choose Burn Bootloader to set the fuses for 8MHz operation
- Upload the program.
Other boards
The Compact TFT Graphics Library will also work on other processor boards. Use the appropriate Arduino core to upload the program to those boards.
Resources
Tiny TFT Graphics Library
Here's the Tiny TFT Graphics Library and examples: Tiny TFT Graphics Library Program.
Or get it from GitHub here: https://github.com/technoblogy/tiny-tft-graphics-library.
Compact TFT Graphics Library
Here's the Compact TFT Graphics Library and examples: Compact TFT Graphics Library Program.
Or get it from GitHub here: https://github.com/technoblogy/compact-tft-graphics-library.
- ^ megaTinyCore on GitHub.
- ^ SparkFun FTDI Basic Breakout - 5V on Sparkfun.
- ^ FTDI Serial TTL-232 USB Cable on Adafruit.
- ^ ATTinyCore on GitHub.
- ^ Tiny AVR Programmer on SparkFun.
- ^ USBasp - USP programmer for Atmel AVR controllers on www.fischl.de.
blog comments powered by Disqus
