2.4" TFT SPI (ILI9341 & XPT2046): SPI for LCD+Touch w/ Nano

Hello, I have this TFT which I am trying to run from an Arduino Nano.

I have had success with the Adafruit_ILI9341 library for the screen and the XPT2046_Touchscreen library for the touch interface. I modified an XPT library example to use my project's pins, remove the fonts, and use the adafruit library instead of whatever was default. Here's the code and pin configuration below.

ILI9341test.ino

#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <XPT2046_Touchscreen.h>
#include <SPI.h>

#define CS_PIN  A1
#define TFT_DC  A3
#define TFT_CS A0
// MOSI=11, MISO=12, SCK=13

XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN  2
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, 255);  // Param 2 - 255 - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

void setup() {
  // Backlight
  pinMode( 9, OUTPUT );
  digitalWrite( 9, HIGH );
  
  Serial.begin(38400);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

boolean wastouched = true;

void loop() {
  boolean istouched = ts.touched();
  if (istouched) {
    TS_Point p = ts.getPoint();
    if (!wastouched) {
      tft.fillScreen(ILI9341_BLACK);
      tft.setTextColor(ILI9341_YELLOW);
      tft.setCursor(60, 80);
      tft.print("Touch");
    }
    tft.fillRect(100, 150, 140, 60, ILI9341_BLACK);
    tft.setTextColor(ILI9341_GREEN);
    tft.setCursor(100, 150);
    tft.print("X = ");
    tft.print(p.x);
    tft.setCursor(100, 180);
    tft.print("Y = ");
    tft.print(p.y);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.println(p.y);
  } else {
    if (wastouched) {
      tft.fillScreen(ILI9341_BLACK);
      tft.setTextColor(ILI9341_RED);
      tft.setCursor(120, 50);
      tft.print("No");
      tft.setCursor(80, 120);
      tft.print("Touch");
    }
    Serial.println("no touch");
  }
  wastouched = istouched;
  delay(100);
}

Pin config

 Arduino                                   2.4" TFT
  Nano                                    SPI 240x320
+-------+                               +------------+
|     5V|-------------------------------|VCC         |
|    GND|-------------------------------|GND         |
|     A0|----5v{VOLTAGE_DIVIDER}3.3v----|CS          |
|    3V3|-------------------------------|RESET       |
|     A3|----5v{VOLTAGE_DIVIDER}3.3v----|DC          |
|    D11|-+--5v{VOLTAGE_DIVIDER}3.3v----|SDI(MOSI)   |
|       | `-----------------------------|T_DIN       |
|    D13|-+--5v{VOLTAGE_DIVIDER}3.3v----|SCK         |
|       | `-----------------------------|T_CLK       |
|     D9|-------------------------------|LED         |
|    D12|----------------------------+--|SDO(MISO)   |
|       |                            `--|T_DO        |
|     A1|-------------------------------|T_CS        |
|       |                     unassigned|T_IRQ       |
+-------+                               +------------+

However, I'm not sure if the way it's set up right now is correct. These devices are sharing pins with the Arduino, and while they both seem to work, there are some oddities.

  • Both libraries want the initial SCLK to be two different things (touch interface is 2MHz, LCD is 16MHz). Right now I'm getting some noticeable flickering, so that could be due to a slower clock than usual. I bet if I moved the touchscreen init to happen before the lcd init, the 16MHz would be set last and persist. But then would there be issues with clocking the touch chip too fast?

  • Will sharing MISO or MOSI clash in any way here? For the display, it wouldn't usually send back any data and only needs to receive, and the opposite is true for the touch interface. That said, I couldn't get the touch to work without both T_DO and T_DIN set up, so it's probably not that simple.

Ultimately, how are you supposed to configure this thing?

If the answer involves moving the clashing pins away from SPI, I have another issue - the touch library I'm using currently seems to be SPI-only, and I haven't had success with any other touch libraries. I can post more detail about that if things seem to be moving that way.

Thanks,

1 Like

You need level shifter chip (or voltage divider) on every output signal. MISO does not need a shifter. In theory, T_IRQ does not need a shifter. But the URTouch library abuses this line.
The XPT2046_Touchscreen library works fine.

It all becomes very messy with jumper wires and breadboards.

Invest in a proper 3.3V Arduino e.g. Zero, Due, ...
I use Seeeduino switched to 3.3V logic.
Some of the newer Chinese Uno clones have a 3.3V/5V switch.

The Nano is always 5V. Which means you have to buy a lot of level shifter chips, resistors and wires.
You end up with something bulky, unreliable and expensive. Making you wonder why you were such a cheapskate buying the Nano in the first place.

David.

You need seven 3.3V outputs: RST, DC, MOSI, SCK, TFT_CS, TOUCH_CS, SD_CS
And one input: MISO

You can either use a bidirectional level shifter chip like TSX0108 (8 channel)
Or use voltage divider for RST. And a 74HC4050 (6 channel) for DC, MOSI, SCK, TFT_CS, TOUCH_CS, SD_CS. Use a 2k2 series resistor for MISO.

Okay, I moved T_DIN and T_CLK to after the voltage divider. The updated connections are as follows:

Arduino                                   2.4" TFT
  Nano                                    SPI 240x320
+-------+                               +------------+
|     5V|-------------------------------|VCC         |
|    GND|-------------------------------|GND         |
|     A0|----5v{VOLTAGE_DIVIDER}3.3v----|CS          |
|    3V3|-------------------------------|RESET       |
|     A3|----5v{VOLTAGE_DIVIDER}3.3v----|DC          |
|    D11|-+--5v{VOLTAGE_DIVIDER}3.3v-+--|SDI(MOSI)   |
|       |                            `--|T_DIN       |
|    D13|-+--5v{VOLTAGE_DIVIDER}3.3v-+--|SCK         |
|       |                            `--|T_CLK       |
|     D9|-------------------------------|LED         |
|    D12|----------------------------+--|SDO(MISO)   |
|       |                            `--|T_DO        |
|     A1|-------------------------------|T_CS        |
|       |                     unassigned|T_IRQ       |
+-------+                               +------------+

Everything still works with ILI9341test.ino. I will test with the other library shortly.

After doing a little scoping, it looks like my Nano's MOSI, MISO, and SCLK pins are all curiously outputting at only about 0.5V. The waveforms themselves look fine, but why are they this low? I have several Nanos at my disposal and all of them have this same characteristic. The LCD device is still capable of communication with this voltage, but it makes me wonder if I can scrap the voltage dividers for these pins.

Also, I am still wary about the reuse of pins. Is there truly no issue here with using the same SCLK, MOSI, and MISO? How do I control which SCLK is ultimately being set (the touchscreen's preferred or the TFT's preferred)?

Thanks,

In this recent thread I experimented with voltage dividers, level shifter chips, regular 3.3V logic.

Yes, I would expect to be able to run multiple 3.3V SPI Slave devices with voltage dividers on the Nano.
In practice, I found it unreliable.

However TSX0108 level shifter or straight 3.3V logic works perfectly.

SPI slave devices put all their pins into 3-state when /CS is inactive.
So you can have as many devices on the bus as you want. Only one device can have its /CS active at any one time.

MOSI, SCK are input pins on a Slave. So it should not matter how many Slaves are connected to the bus.
A Slave's MISO is an output. So it is important than inactive devices put MISO into 3-state.

Note that I added a p.s. to my previous message.

David.