Small Microcontroller Displays
I found myself wanting several small displays connected to a microcontroller, so was doing a bit of a trade-off between various options, and was starting to lose track, so this post collects some of those thoughts together.
It is not meant to be a comprehensive discussion of choosing small displays for projects, but more of a reflection on the displays I already have kicking around in my parts boxes!
Most displays tend to be categorised by the driver chip they use. And then by the bus type used for their connection. So that is how I’ve grouped them here.
A really good reference for many of the displays shown here is: https://www.lcdwiki.com/Main_Page
I2C SSD1306 OLED
This is usually my “go to” set of small displays. They are generally well supported and pretty easy to use.
I generally have two variants to choose from:
On the left is the 0.91″ 128×32 OLED SSD1306 and on the right is the 0.96″ 128×54 OLED SSD1306. Common properties of both displays:
- Monochrome – white or blue.
- I2C interface.
- Usually 5V powered, but some include level shifters to allow 3V3 logic.
- Usually includes I2C pull-ups. Might be to VCC level so be wary if using a 3V3 MCU but powering from 5V – always check the voltage level prior to connecting.
- 128×32 usually a fixed I2C address (0x3C). 128×64 usually allows selection between 0x3C and 0x3D.
- There are variants with VCC and GND swapped, and other variants with SDA and SCL swapped.
Software support:
- The “go to” library for Arduino is the Adafruit_SSD1306 library, which assumes the use of the Adafruit_GFX library too.
- But there are lots of alternative libraries too, for example u8glib.
- Well supported in Circuitpython or Micropython.
- More here: Arduino Nano Every I2C and SPI Displays.
Typical Connections:
- VCC/GND (see note below re VCC vs logic levels).
- SCL/SDA – I2C pins on the MCU.
Known “gotchas”:
- Requires a chunk of memory allocated on start-up on Arduino, which can fail if there isn’t enough dynamic memory left and make a sketch hang.
- Can’t be written to from an interrupt routine (e.g. a timer).
- Low-level I2C Wire library on Arduino is blocking.
- Can sometimes be a little slow compared to alternatives.
- Limited I2C address options, so multiple display use is limited (and also increase the memory issues).
- As already mentioned, any I2C pull-ups may be pulled up to the VCC level or might be level shifted, so it is always worth checking if planning to use with a 3V3 microcontroller.
Summary:
- Cheap, pretty easy to use, and fairly universal if you want a single, small, monochrome display for simple outputs.
Other I2C Variants
There are some variants of the SSD1306 that sometimes pops up too for slightly larger displays:
- SSD1315 – apparently can simply be treated as a SSD1306 and mostly it works ok.
- SH1106 – very similar niche to SSD1306 but requires it owns driver support.
SPI ST7735/89/96 TFT
Whereas the SSD1306 I2C is pretty ubiquitous for monochrome displays, I’ve tended to find that SPI ST77xx displays fill a similar niche for small, full colour, non-touch, TFT displays. And there are loads of variations on the theme when it comes to these displays.
The 7735 supports lower resolution, smaller displays, typically up to 170×320, with the 7789 for those of 240×240 or 240×320 and similar. There is also a ST7796 which I believe uses the same driver libraries for a higher 320×480 display.
Two 7735 Displays:
These two ST7735 displays that I have are labelled:
- TFT 0.96″ 80×160 SPI ST7735
- TFT 1.8″ 128×160 SPI ST7735
These ST7789 display I have is labelled:
- TFT 1.3″ 240×240 SPI ST7789
I also have a display that was bought as a ST7789 labelled “TFT 2.8″ 240×320 SPI” which comes with a touch screen, but I can’t get this to work.
Common properties:
- SPI interface: data (SDA/MOSI/COPI), clock (SCK/SCLK), chip select (CS), data/command (SR/DC), possibly a reset.
- Typically 65536 colours, usually encoded as 5-6-5 bit RGB patterns.
- Have to check for 3V3 or 5V operation depending on the datasheet of the driver chip and design of the module.
Software support:
- Adafruit SST77x Library supports ST7735 and ST7789, once again also requiring Adafruit_GFX.
- Arduino_GFX Library supports a whole range of displays and microcontrollers, including the ST77xx devices.
- TFT_eSPI for Raspberry Pi Pico, ESP32 and others.
- MCUFRIEND_kbv for Arduino and “MCUFRIEND” type displays. Wide range of TFT display drivers supported.
- Tiny TFT Library for ATTiny85 and Compact TFT Library for a range of MCUs by David Johnson-Davies (technoblogy)
- https://github.com/bitbank2/bb_spi_lcd. Standalone library for ST7735, ST7789 and others, with a set of pre-configured “named” displays.
- More here: Arduino and a Cheap TFT Display.
Typical Connections:
- VCC/GND
- CLK/SDA – SPI Clock and Data (Data OUT from MCU – i.e. MOSI/COPI)
- RES – Reset
- DC, RS – Data/Command Register Select
- CS – Chip Select
Known Gotchas:
- Working out if RS means reset of the data/command pin; and not mixing up SCL/SDA with I2C!
- Some might include a backlight control pin too for dimming or turning it off. With this not connected the display was a maximum brightness.
- I’ve also seen talk that many of these modules themselves run at 3V3, so whilst they may include a regulator for 5V to 3V3 for power, they don’t always include level shifting for the signal pins. It seems unclear (to me at least at the moment) if it is ok to use these with a 5V microcontroller (although I have done…).
- Some of these displays are “inverted” colour wise. The use 16-bit 5-6-5 format colours, but some are RGB, some are BGR and there might be other variants too.
- Sometimes the initialiser for the library requires a SPI_MODE setting. My ST7789 240×240 required the Adafruit ST7789 initialisation as follows:
#include <Adafruit_ST7789.h>
#include <SPI.h>
#define TFT_CS 10 // (not used)
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
void setup() {
tft.init(240, 240, SPI_MODE2);
}
Note, unlike the monochrome displays, these have their own pixel framebuffer so memory use is much more efficient, even when used as a full colour display.
Summary:
- Cheap, pretty easy to use once the voltage levels and the pin labelling are worked out. Well supported by a number of libraries; but does require more pins for 4-wire SPI. Might need some messing around to get the right colour definitions. Otherwise a good choice if you just want a cheap, colour display with no touch.
OLED SH1122 SPI
There are actually both I2C and SPI versions of SH1122 displays, but I’m considering the SPI version here. The display I have is a 256×64, monochrome OLED display.
Software Support:
- U8G2 library:https://github.com/olikraus/u8g2
- Use the SH1122 constructors: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp#sh1122-256×64
Example:
U8G2_SH1122_256X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);Typical Connections:
- VCC/GND – mine states it can support either 3V or 5V power
- CLK/SDA – SPI Clock and Data (Data OUT from MCU – i.e. MOSI/COPI)
- RES – Reset
- DC, RS – Data/Command Register Select
- CS – Chip Select
The _F_ constructor requires a full frame-buffer so is unlikely to work on resource constrained devices (e.g. the Arduino Uno/Nano). The _1_ constructor provides a pageable interface which allows for the updating of the display in pages, which takes longer but allows it to be used with more devices.
There are also software SPI versions that allow the use of any GPIO pins.
Summary:
- A pretty neat board if these physical dimensions match what is required.
- There are a whole pile of example sketches in the U8G2/page_buffer directory.
ILI9341/9488 TFT
Cheap larger displays are often driven by one of the ILI9341 or ILI9488 chips. The former supports 240×320 in full (16-bit) colour whereas the 9488 tends to support larger displays of up to 320×480 in full (24-bit) colour. Both support either a parallel (at least 8, 9, 16-bit) or serial (3 or 4 wire SPI) bus interface.
I don’t have a lot of detailed information for this post yet, but instead will refer to:
The ILI9341 is well supported by the Adafruit graphic libraries, but the ILI9488 is likely to require something else, as described in the above post.
These displays are often used with touch support and will often expect to run at 3V3 logic levels.
LCD 1602 HD44780
This is another very common monochrome, but text only, display. They have a 4 or 8-bit parallel interface, but it is also quite common to use the with an I2C “backpack” based on the PCF8574 I2C IO expander. Boards can be cheaply bought with or without a backpack, and the backpacks are available separately too for retro fitting to displays without them.
They are often called “1602” displays as they are two rows of 16 characters. By using custom blocks it is possible to have some simple graphics. There are LCD2004 modules too with four rows of 20 characters.
They often come with a choice of backlight colours. White or red are particularly striking! There are some variants that come with an additional I2C controller chip built in to control the backlight and some even come with a full RGB backlight capability.
Typical Connections:
- VCC/GND
- Data – either 4 or 8 bit modes support
- E, RW, RS – enable, read/write, register select.
- Backlight V+/GND – level is often fixed using a resistor.
There are core Arduino libraries to support the most basic versions of these displays:
- LiquidCrystal
- LiquidCrystal_I2C
Typical Gotchas:
- The I2C backpacks often include pull-ups to VCC, yet many of these displays require 5V even if used with a 3V3 microcontroller. One option is to remove the pull-ups and add external pull-ups to 3V3.
- If there are only blocks on the display then the communications isn’t working properly – check SDA/SCL or the control lines.
- If there is nothing on the display or the text is obscured by blocks behind it, then the contrast is either too low or too high. I2C backpacks have a potentiometer to adjust the contrast.
- More complex versions require an additional I2C setup phase, e.g. to turn on the backlight, which isn’t supported by the standard libraries.
Summary:
- Very useful if a large, high/adjustable contrast, text-only display is required.
Others
So I don’t forget when considering the above, I also have:
- GC9A01 based 240×240 1.28″ circular SPI display like this one: https://www.waveshare.com/wiki/1.28inch_LCD_Module. Note: cheaper versions of this won’t include level shifting and will expect to run at 3V3.
- ESP32 boards with built-in displays: ESP32-C3 0.42 OLED
- ESP32 “Cheap Yellow Display” boards, details here: https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display
- Range of small displays from Pimoroni, Waveshare and others for use with the Raspberry Pi Pico.
- Waveshare small HDMI displays for use with a Raspberry Pi.
I’ll add to the list for my own reference as I remember other odds and ends.
Kevin
#hd44780 #ili9341 #ili9488 #include #lcd1602 #oled #ssd1306 #st7735 #st7789 #tft











