Two or more different TFTs with one Arduino Nano and one SD Card Reader

Hello everyone,

I am using an Arduino Nano to control a 0.96" TFT display. I use it to generate advertisements for the model railroad. The sketch currently only controls one display with an Arduino Nano and an SD card reader. I can also connect two copies of the display with the same picture to the circuit board.

On Arduino, pins (D0, D1), D2, D3 and D5, D6 and D7 are still unassigned.

Now to my questions:

  • Is it possible to control two ore more different displays with one Arduino Nano and just one SD card reader?
  • Do I have to define the CS, RST and DC pins twice for another display with different content? Once for display 1 and once for display 2?
  • Do all three pins CS, DC and RST have to be connected to other Arduino pins if the content of the display has to be different?
  • How can I define that the Nano alternately outputs an image on display 1 and then on display 2?
  • Can I use D0/D1 to connect a third display?
  • What about SDA/SCL?

Perhaps one or the other has an idea of how to get even more out of one Nano and one card reader. Thank you very much for supporting my project.

Here is the sketch that was kindly made available to me.



// TFT Display farbig 80 x 160 Pixel ACHTUNG Bilder müssen evtl. invertiert werden um richtig angezeigt zu werden.

#include <SPI.h>
#include <SD.h>
#include <TFT.h> 

#define PIN_SD_CS 4
#define PIN_TFT_CS 10
#define PIN_DC 9
#define PIN_RST 8

// #define PIN_TFT_CS2 7   // Is this correct?
// #define PIN_DC2 6
// #define PIN_RST2 5

#define VERTICAL 0
#define HORIZONTAL 3    //Bildlauf bei 3 = rechts nach links 

// Jenachdem wie der Bilderrahmen aufgestellt wird, ob wagerecht oder senkrecht müssen die Auflösungen engepasst werden, damit die Zentrierung richtig funktioniert
#define XRES 160
#define YRES 128

#define DELAY_IMAGE_SWAP 5000 // Anzeigedauer in Millisekunden

TFT TFTscreen = TFT(PIN_TFT_CS, PIN_DC, PIN_RST);
// TFT TFTscreen2 = TFT2(PIN_TFT_CS2, PIN_DC2, PIN_RST2);  // Second Display?

void setup() {
  
  // Serielle Verbindung erstellen für Standardausgabe
  Serial.begin(9600);
  while (!Serial) {
  }
  
  //Folgende Zeilen eventuell durch  "TFTscreen.begin();" ersetzen falls es Farbfehler gibt
  TFTscreen.initR(INITR_GREENTAB);
  //TFTscreen.initR(T_INITR_GREENTAB);
  TFTscreen.setRotation(HORIZONTAL);
  TFTscreen.invertDisplay(1);                   //"TFT Farben invertieren, wenn 0 dann "normal" wenn 1 dann "negativ"
  
  
  TFTscreen.background(255, 255, 255);          // Mit weiß den Bildschirm löschen, für andere Farbe einfach die entprechenden (R , G , B) Werte setzen  
  init_SD();                                    // SD-Kartenleser initialisieren
}

void init_SD() {
  // try to init SD card
  // Übernommen vom Basis-Sketch
  
  Serial.print(F("SD card init..."));
  if (!SD.begin(PIN_SD_CS)) {
    Serial.println(F("ERROR")); // failed
    return;
  }
  Serial.println(F("SUCCESS")); // ok
}

void loop() {

 
  File dir = SD.open("/");                       // Willst Du ein Unterverzeichnis nutzen einfach nach dem Slash eintragen und noch einen Slash ans Ende
  File entry;
  char name[16];
  bool worked_once = false;
  int xpos;
  int ypos;

  while (entry = dir.openNextFile()) {
    Serial.print(F("Opened File: "));
    Serial.println(entry.name());
    strcpy(name, entry.name());
    entry.close();
    int filename_len = strlen(name);
    if ((filename_len >= 4 && strcmp(name + filename_len - 4, ".BMP") == 0)) {
      PImage image = TFTscreen.loadImage(name); 
      if (image.isValid()) {
        Serial.println(F("Bild darstellen."));
    // TFTscreen.background(255, 255, 255);       // Bildschirm mit weiß löschen bevor ein neues Bild gerendert wird

        // Zentrierung
        xpos = (XRES - image.width()) / 2;
        ypos = (YRES - image.height()) / 2;
        TFTscreen.image(image, xpos, ypos);
        worked_once = true;
        delay(DELAY_IMAGE_SWAP);
      } else {
        Serial.println(F("Bild ungueltig"));  
      }  
      image.close();
    } else {
      Serial.println(F("Keine BMP-Grafik!"));  
    }
  }
  dir.close();


  if (worked_once == false) { 
    Serial.println(F("Es konnte kein Bild dargestellt werden. SD-Karte wird versucht neu zu initialiseren"));        
    SD.end();
    init_SD();
  }

}

If they are the same model of display and they show the same image, it should be very easy. The code won't need to be changed because the Nano won't even know it is connected to more than one display.

Probably only the CS pins of the displays need to connect to different Arduino pins. The RST and DC pins can be shared, like the CLK and COPI/MOSI pins.

1 Like

Yes and once you understand that SPI is a bus where Clk, MISO and MOSI go to each of the SPI peripherals. The only thing different is the CS (chip select) pin for each device.

Sorry I cannot follow your schematic as I do not have the pinouts of the parts you memorized. It is normal practice to label them on the schematic.

1 Like

By changing your code to do that.

No, these are used for uploading your code and debugging with serial monitor on Nano.

That's assuming you mean a classic Nano V3 (ATMEGA328). There are many Arduino models called "Nano" these days, with different specifications and features.

1 Like

Classic Nano has no pins labelled as SDA or SCL.

Uno, Mega, Leonardo have separate SDA & SCL pins, but in practice they are connected internally to other pins on the main chip.

On Nano, SDA & SCL are alternative functions of the A4 & A5 analog input pins.

On Nano, A0 to A5 analog input pins can be alternatively used as digital input/output pins. A6 and A7 have only a single function as analog inputs.

1 Like

Sorry, my mistake.
I have changed the components and re-uploaded the image in the initial post.

Now I think more about it, I'm am not certain this is true.

There is a danger that if the RST pins of two or more displays are connected to the same Arduino pin, it may not be possible to initialise each display. The first display may get initialised correctly, but then when the second display is initialised, this might reset the first display again.

It may be possible to solve that problem by giving the library dummy pin numbers for the reset pins of each display, and having your code reset all the displays once in setup(), before any of the displays are initialised.

1 Like

I spotted a problem with your schematic.

The Nano's 3V3 pin can only supply a small current, maybe 50mA or less. Not enough for even 1 TFT display, certainly not more than one.

Do your displays have built-in regulators so that they can be supplied with 5V? If so, just do that.

If not, you will need to use an additional 3.3V regulator such as AMS1117.

Also, are your displays 5V tolerant? If not, they could be damaged by connecting to 5V Nano pins. You can use voltage dividers to reduce the Nano's 5V signals to 3.3V.

1 Like

Hi Paul,

That would not be a problem.

I could therefore use pins D2, D3, D5, D6, D7 and D10 for six times CS and A0 to A5 for six times RST.

If the other pins can be used in parallel, this means that I can display six different pictures on six displays.

Now I just have to find out how to set up the sketch so that the six displays are addressed one after the other. I'll put together a test setup later.

Yes, they can be supplied with 5V alternatively. So I have to shut down the 3V3 line.

Don't copy/paste any of the the code 6 times over, that would be dumb. Arrays can be used to avoid that, the forum can help you with it.

However, it remains to be seen if the Nano has sufficient resources to handle 6 displays!

If it cannot handle 6, maybe it can handle 3 or 4 and you can make some of the displays as duplicates of the others?

1 Like

This is good to know. Paul said, RST also needs a pin for each device for initialising.

I said I was not sure. I also suggested a way to avoid this, if it is a problem.

It's no problem. I know, you said, you're not sure.
I think, 3 or 4 different displays would be great, so there are a lot of pins to use for.
There will be eight displays on each station platform. If four different advertisements are randomly displayed on them, that would be very cool, by using one Arduino Nano and one SD Card Reader.

The TFT library inherits from the Adafruit_ST7735 library, with which you can use a common RST pin for multiple displays by specifying the pin in the first display constructor, then using -1 for the pin number in all subsequent display constructors. That triggers the reset on all displays when the first display is initialized, which is the only time it will be needed.

2 Likes

Problem solved, only one Arduino pin needed for RST.

I'll get you started

// TFT Display farbig 80 x 160 Pixel ACHTUNG Bilder müssen evtl. invertiert werden um richtig angezeigt zu werden.

#include <SPI.h>
#include <SD.h>
#include <TFT.h> 

#define PIN_SD_CS 4
#define PIN_TFT_CS 10
#define PIN_DC 9
#define PIN_RST 8

#define PIN_TFT_CS2 7
#define PIN_TFT_CS3 6
// #define PIN_DC2 6
// #define PIN_RST2 5

#define VERTICAL 0
#define HORIZONTAL 3    //Bildlauf bei 3 = rechts nach links 

// Jenachdem wie der Bilderrahmen aufgestellt wird, ob wagerecht oder senkrecht müssen die Auflösungen engepasst werden, damit die Zentrierung richtig funktioniert
#define XRES 160
#define YRES 128
#define SCREENS 3

#define DELAY_IMAGE_SWAP 5000 // Anzeigedauer in Millisekunden

TFT TFTscreen[SCREENS] = {
  TFT(PIN_TFT_CS, PIN_DC, PIN_RST),
  TFT(PIN_TFT_CS2, PIN_DC, -1),  // Second Display
  TFT(PIN_TFT_CS3, PIN_DC, -1)  // Third Display
};

void setup() {
  
  // Serielle Verbindung erstellen für Standardausgabe
  Serial.begin(9600);
  while (!Serial) {
  }
  
  for(byte s = 0; s < SCREENS; s++) {
    //Folgende Zeilen eventuell durch  "TFTscreen.begin();" ersetzen falls es Farbfehler gibt
    TFTscreen[s].initR(INITR_GREENTAB);
    //TFTscreen.initR(T_INITR_GREENTAB);
    TFTscreen[s].setRotation(HORIZONTAL);
    TFTscreen[s].invertDisplay(1);                   //"TFT Farben invertieren, wenn 0 dann "normal" wenn 1 dann "negativ"
  
  
    TFTscreen[s].background(255, 255, 255);          // Mit weiß den Bildschirm löschen, für andere Farbe einfach die entprechenden (R , G , B) Werte setzen  
  }

  init_SD();                                    // SD-Kartenleser initialisieren
}

void init_SD() {
  // try to init SD card
  // Übernommen vom Basis-Sketch
  
  Serial.print(F("SD card init..."));
  if (!SD.begin(PIN_SD_CS)) {
    Serial.println(F("ERROR")); // failed
    return;
  }
  Serial.println(F("SUCCESS")); // ok
}

void loop() {
  static byte s = 0; 
 
  File dir = SD.open("/");                       // Willst Du ein Unterverzeichnis nutzen einfach nach dem Slash eintragen und noch einen Slash ans Ende
  File entry;
  char name[16];
  bool worked_once = false;
  int xpos;
  int ypos;

  while (entry = dir.openNextFile()) {
    Serial.print(F("Opened File: "));
    Serial.println(entry.name());
    strcpy(name, entry.name());
    entry.close();
    int filename_len = strlen(name);
    if ((filename_len >= 4 && strcmp(name + filename_len - 4, ".BMP") == 0)) {
      PImage image = TFTscreen[s].loadImage(name); 
      if (image.isValid()) {
        Serial.println(F("Bild darstellen."));
    // TFTscreen.background(255, 255, 255);       // Bildschirm mit weiß löschen bevor ein neues Bild gerendert wird

        // Zentrierung
        xpos = (XRES - image.width()) / 2;
        ypos = (YRES - image.height()) / 2;
        TFTscreen[s].image(image, xpos, ypos);
        worked_once = true;
        delay(DELAY_IMAGE_SWAP);
        s++;
        if (s >= SCREENS) s = 0;
      } else {
        Serial.println(F("Bild ungueltig"));  
      }  
      image.close();
    } else {
      Serial.println(F("Keine BMP-Grafik!"));  
    }
  }
  dir.close();


  if (worked_once == false) { 
    Serial.println(F("Es konnte kein Bild dargestellt werden. SD-Karte wird versucht neu zu initialiseren"));        
    SD.end();
    init_SD();
  }

}
1 Like

Hello Paul,

I was just about to present my solution, which I have been working on in vain for the last hour. I had already defined an array, integrated it into the setup, but had no idea how to integrate it into the loop. I just wanted to present this partial solution and found your approach. I will test it right away and thank you for the nice suggestion.