Arduino Due library for interfacing with ILI9341 SPI TFTs


A library for interfacing with ILI9341-based TFT’s in SPI, Extended SPI and DMA SPI mode optimized for Arduino Due.

ILI9341 with Arduino Due

The library can also be used with Arduino AVR boards like Uno, Mega, Pro Mini, Nano, etc. It is faster than the original Adafruit one but do not expect DMA-like speed increase. It is comparable to some other tweaked Adafruit libraries out there and in addition you get things like custom fonts, arcs, images or ability to take screenshots. Btw. Not all library examples will work because of smaller ROM/RAM space available on AVRs.

ILI9341 with Arduino Pro Mini

This library is based on 3 libraries:

ili9341_t3 library where various optimizations for Adafruit’s ili9341 and GFX libraries were implemented was used as a base for ili9341_due.
One class from SdFat library is used for utilizing Due’s DMA in SPI transfers which provides the main speed boost.
gText class from GLCD library was used as a base for rendering custom fonts.

As for the wiring, use Due’s and AVR’s HW SPI pins (e.g. described here). The pin for CS on Due depends on the SPI mode you choose (see SPI Mode section below for details).


Some of the default settings can be set in ILI9341_due_config.h file.

SPI Mode

Uncomment the line depending on the SPI mode you want to use. DMA mode is the default. For AVR, it does not matter which mode you use, ILI9341_SPI_MODE_NORMAL is always going to be used since there is no Extended SPI or DMA available on AVRs.

SPI_MODE_NORMAL is the standard SPI mode where you can use any digital pin for CS. In this mode the library will drive the CS pin ‘manually’.
SPI_MODE_EXTENDED is the extended SPI mode available in Due the CS pin is handled by the chip (which is faster than handling it in code ‘manually’). You are restricted to these 3 pins for CS — 4, 10 and 52 (as described here).
SPI_MODE_DMA is utilizing D(irect) M(emory) A(ddress) to do SPI transfers. You can use use any digital pin for CS.

Here is a video where you can see the speed difference between the modes (v0.x version):

SPI clock divider

This is used to set the SPI clock frequency on Due, which for example when set to 10 will set the SPI clock frequency to 84MHz/10=8.4MHz. The minimum divider is 1 (84MHz) and maximum is 255 (329kHz). If you are getting glitches on the screen or it just does not work try to use a higher divider to bring the frequency down (e.g. 11 to run it at 8-ish MHz). I was using 20cm dupont cables to connect TFT with Due and haven’t had any issues running it with the divider set to 2.

  • SPI_CLOCK_DIV2 — divider of 2
  • SPI_CLOCK_DIV4 — divider of 4
  • SPI_CLOCK_DIV8 — divider of 8
  • SPI_CLOCK_DIV16 — divider of 16
  • SPI_CLOCK_DIV32 — divider of 32
  • SPI_CLOCK_DIV64 — divider of 64
  • SPI_CLOCK_DIV128 — divider of 128

You can change the clock divider at runtime by calling the setSPIClockDivider function.

If you do not need scaled fonts (setTextScale function) then you can comment out the define to disable support for text scaling. Text will render a bit faster. Text scaling is enabled by default.

Set the default spacing between letters in pixels.

Different letter spacings:

Set the default spacing between lines in pixels.

Different line spacings:

If uncommented, the space between lines (defined by DEFAULT_LINE_SPACING) is filled with text background color. By default it is commented out/disabled.

This number represents the maximum equal to 360 degrees (full circle). The default is 360 so if you pass in start=25 and end=75 you’ll get an arc going from 25 degrees to 75 degrees. If you set ARC_ANGLE_MAX 100 and you pass in start=0 and end=50 then you get a half circle (that can represent percentages). If you set ARC_ANGLE_MAX 2*PI, you can pass in angles in radians etc. You can change the default at runtime by calling the setArcParams function.

This number is an offset in degrees from the default position where the arc starts (representing value of 0). If you imagine a compass, then the default starting position is at the East point. Setting the value to -90 will move the starting point 90 degress counter-clockwise (so to the North point).

You can change the offset at runtime by calling the setAngleOffset function. The value provided in setAngleOffset argument is *in addition* to ARC_ANGLE_OFFSET value. So the total angle offset from the default East point is ARC_ANGLE_OFFSET+setAngleOffset value.

Creating Custom Fonts

Custom fonts on AVR (important!)

If you do not change anything the compiler will complain with:

error: variable ‘Arial_14’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’

In order to fix it you need to add "const" so it will look like this:
Here is a video of rendering a 255px-high font:


Loading images from an SD card

This is the SdFatTftBitmap example sketch demonstrating loading images from an SD card. The images were converted to RGB565 format using BMP24toILI565 tool (see the Tools folder). One image loads and displays in around 160ms using half speed for SD card SPI and half speed for Due SPI. I was getting distorted images when I tried to use the full speed for either of the SPIs.

This is the Arcs demo from the examples folder:

UTFT demo speed comparison

All the credits (and blame 🙂 goes to TFTLCDCyg who ported the UTFT demo to ILI9341_due library. Both demos were run on Due at the max speed.

Here is a video of the demo powered by the UTFT library:

And here is the demo powered by the ILI9341_due library:

The source code for the ILI9341_due-fied demo can be found in the library’s examples folder. Done with ILI9431_due v0.x version. The demo completes in around 1080ms with ILI9341_due v1.x version.

ILI9341_due_Buttons add-on library

Created by Graham Lawrence (aka ghlawrence2000). It’s an add-on library which allows to easily add buttons to the UI. See his GitHub page for more information.

Here are videos of two of his example sketches:

ILI9341 functions

Functions summary (in alphabetical order)

Functions details


If you want to ask me a question or just contact me, feel free to do so in the Arduino Forum.