by Floris Wouterlood The Netherlands – December 4, 2023
Summary
Here we connect two displays to one microcontroller. This makes it easy to monitor two different sensors, for instance temperature and pressure. In the current project a bench is constructed that hosts an ESP32 microcontroller and two 1.6 inch diameter rounded-corner 240*280 TFT displays. The display controller is a ST7789A. ‘Independent’ action of the displays is achieved simply by alternately addressing them. Alternating is done by toggling the CS pins LOW-HIGH between each instruction that sends data to a particular screen. The screens alternately display information, while with a fast ESP32 the interdisplay delay is so short that there is no flicker. The human brain interprets the alternating displays as acting independently.
Introduction
Data display is classically done with a single display. However, in a multisensor environment, for instance in a weather station it can be handy to have two displays available, for instance one that presents temperature and another that shows barometric pressure. Thanks to a trick Bodmer’s TFT_eSPI.h library can be forced to work with two displays. To demonstrate this trick we connect two 240*280 pixel TFT screens with a ST7789 display controller to an ESP32 microcontroller. All pins of the TFT displays are connected in parallel to the microcontroller, except the CS pins. The CS pin of display (0) is connected to pin D21 of the ESP32 while the CS pin of display (1) is wired to pin D22.
Pin mapping
Wiring is as follows. There is a common ‘bus’ for the GND, VCC, SCL, SDA, RES, DC and BLK wires (figure 1). CS is differently wired.
figure 1. Wiring scheme for two 1.69 inch diagonal 240*280 TFT displays and one ESP32 microcontroller
Pin connectivity table
ESP32 pin | ST7789A display 0 | ST7789A display 1 |
GND | GND | GND |
3V3 | VCC | VCC |
D18 | SCL | SCL |
D23 | SDA | SDA |
D4 | RES | RES |
D2 | DC | DC |
D21 | CS | |
D22 | CS | |
3V3 | BLK | BLK |
Bench
Figure 2. Wiring scheme, front view: positioning of pin sockets for one ESP32-WROOM-32 board and two 1.69” 240*280 SPI ST7789A TFT displays. The ESP32 and the displays will be mounted onto the pin sockets.
Creation of sketches is so much faster if one is not continuously distracted by loose wires and poor connections in breadboard assemblies. Thus, one a piece of 26 x 31 holes, double sided prototyping soldering board (7×9 cm) was acquired on which pin sockets were soldered to accommodate two breakout displays and one ESP32 microcontroller (figure 2). The ‘stick ‘em on’ configuration makes it possible to remove displays and microcontroller so that they can be used in other experimental configurations. All wires are carefully soldered to their pins to provide robust connectivity.
Note that the wiring is of a ‘bus type, with parallel wiring of the displays, except the CS pin wires. The CS pin for display 0 is wired to pin D21 of the microcontroller while the CS pin for display 1 is wired to pin D22. Note also that the standard CS pin to D5 is abandoned in favor of D21-D22.
Software
Note that controlling two displays requires Bodmer’s TFT_eSPI.h library. This library a) supports ST7789A driven displays, b) enables soft-switching of CS pins and c) supports multiple displays as long as they have identical controller chips. The User_setup.h file that is needed is Setup24_ST7789.h. This setup contains a line ‘#define TFT_CS 5 . You may comment this line inactive because it sets the default CS pin at D5. Using the default pin in dual-display configurations may cause problems.
Inside a two-display sketch
In the header part:
#define device_A_CS 21 // display 0
#define device_B_CS 22 // display 0
In void setup () the first lines define the CS pins:
pinMode (screen_0_CS, OUTPUT);
pinMode (screen_1_CS, OUTPUT);
next the displays are initialized:
digitalWrite (screen_0_CS, LOW); // we need to ‘init’ both displays
digitalWrite (screen_1_CS, LOW); // at the same time – so set both cs pins low
tft.init ();
digitalWrite (screen_0_CS, HIGH); // set both CS pins HIGH, or ‘inactive’
digitalWrite (screen_1_CS, HIGH);
A CS pin in LOW state instructs the display controller to process and display incoming data. A HIGH state tells the controller to ignore data.
The follow-up is easy:
To let screen 0 display something:
digitalWrite (screen_0_CS, LOW); // this display active
… instructions to display data exclusively on screen 0
digitalWrite (screen_0_CS, HIGH); // inactivate this displays
To let screen 0 then display something:
digitalWrite (screen_1_CS, LOW); // this display active
… instructions to display data exclusively on screen 1
digitalWrite (screen_1_CS, HIGH); // inactivate this display
and so forth.
Figure 3. Operational bench featuring two 20*240 rounded corner TFT displays with ST7789A controller. The sketch running is ESP32_two_240x280_ST7789_displays.ino
The sketch switches data to the proper display all the time. The ESP is so fast and our own eyes/brain so slow that we don’t notice the continuous update! For humans it seems as if two independent displays are at work.
The TFT_eSPI.h library contains an example named ‘Animated_Eyes’. This example can be tweaked to run at full speed on two displays without signaling power shortage.
Display power supply issues
Both displays draw power from the 3.3V pin of the ESP32. We know from previous projects that an ESP32 has no problem supplying power to a single 240*280 rounded-corner display with ST778A controller. In contrast to pins on an ESP32 that source 40 mA, the boards’ 3.3V pin a can provide an overwhelming 600 mA, sufficient to power several of the 240*280 rounded-corner displays (rated at 60 mA power consumption each). An external 3.3V power source is therefore considered redundant.
Figure 4. Operational bench fitted with extra pin sockets (wired to pins D16 and D17) connected to an BMP280-380 i2c breakout sensor (barometric pressure, temperature, relative humidity). The temperature readings are displayed on screen A and the relative humidity readings on screen B.
Working with the bench
To demonstrate the dual display capability a BMP280-380 breakout sensor was wired to the bench. In order to do so the bench was expanded with a two-pin socket with wires soldered to pins D16 and D17 of the ESP32 (figure 4). The sensor works with the i2c protocol that by default is supported by pins D21 and D22 of an ESP32. These pins are already assigned to the CS pin of each display. A workaround was found by soft remapping the i2c pins to different pins through the TwoWire class of the wire.h library.
#include <Wire.h>
#define I2C_SDA 16
#define I2C_SCL 17
TwoWire I2CBME = TwoWire (0);
and in Setup ()
I2CBME.begin (I2C_SDA, I2C_SCL, 100000);
With this configuration the readings from the sensor can be distributed to screen 0 and screen 1, in the case of Figure 4 the temperature and relative humidity values. Temperature is visualized by a modified version of Bodmer’s ‘rainbow scale’.
Sketches
Two sketches are supplied. Both are implementations of Bodmer’s <TFT_eSPI.h> library. In order to work properly TFT_eSPI needs a User_Setup.h file. Here we used User_Setup file nr. 24: Setup24_ST7789.h whose settings direct the compiler to do its job properly. User_Setups must be called in User_Setup_Select.h in the library’s main folder.
Downloadable sketch
[example] sketch: ESP32_two_240x280_ST7789.ino
[application] sketch: ESP32_two_ 240x280_ST7789_BMP280.ino
The two sketches are packed in a zip file: ESP32_two_240x280_ST7789_displays.zip