[EN] ST7735s 0.96″ 80×160 TFT LCD

This article introduces 0.96 “IPS TFT LCD with a resolution of 80×160 dots, providing RGB565 or 16-bit color by controlling the operation of the LCD module with the ST7735s chip via the SPI bus. The examples use TTGO T8 ESP32 and ST7735 library with python language.

(Figure. 1)

TFT LCD

The TFT LCD is small at only 0.96 “, but has a display resolution of 80×160 dots. IPS lighting allowed us to view from multiple angles. Besides, this LCD can displays 16-bit color according to the color characteristics of RGB565 which can display 216 or 65,536 colors. The TFT LCD is working at 2.5VDC-4.8VDC voltages.

(Figure. 2) The front of the TFT LCD
(Figure. 3) The back of the TFT LCD
(Figure. 4) The block diagram of the ST7735s.
Credit
(Figure. 5) Pins of the TFT LCD

The LCD’s display controller IC is a ST7735s chip with a block diagram inside as shown in Figure 4 and has the model name used in programming which is GRENTAB80x160 that operates through the SPI bus and has a display area size (Width and height of the display) 0.108 x 0.21696 centimeters with 8 external pins as shown in Figure 5 which uses 4 pins to control the operation, 4 pins are SCL (SCK), SDA (MOSI), DC and CS (as shown in figure 6 and 7) and details of all 8 pins are as follows.

  1. GND for connecting to the ground of the working circuit.
  2. VCC for connecting 3.3V DC voltage (3V3)
  3. SCL for connecting to the SCK pin of the SPI bus, used as a clock pin for communication between the microcontroller and the display module.
  4. SDA for connecting with SPI bus’s MOSI pin, it is used to send data from microcontroller to ST7735s.
  5. RES for connecting a reset signal to allow the display module to reset itself.
  6. DC used to indicate the type of data being sent in SDA, 1 for display data or parameters, and 0 for command data.
  7. CS for connecting with the control pin to determine the module to work or not.
  8. BLK for connecting to back light.
(Figure. 6) 4-line Serial Interface Timing (credit)
(Figure. 7) Attribute of 4-line Serial Interface (credit)

Connect to TTGO T8 ESP32

The connection between the display module and the TTGO T8 ESP32 board can be made according to the following table.

TFT LCD ModuleTTGO T8 ESP32
GNDGND
VCC3V3
SCL14
SDA13
RSTRST
DC2
CS15
BLK3V3
(Figure. 8)
(Figure. 9)
(Figure. 10)
(Figure. 11)
(Figure. 12)
(Figure. 13)

Library and example

The library we chose is a library written by Billy Cheung (accessed 2020-10-13) published on github, which is an improved library from Guy Caver to support ST7735s. The required libraries must include st7735.py and sysfont.py by uploading both files into TTGO T8 ESP32.

Example program code9-1 is an example that updates test80x160.py to be usable with the TTGO T8 ESP32 board and choose to use the operating clock frequency of 240MHz, together with setting the SPI bus communication speed to 20MHz to achieve the highest speed possible.

# code9-1
from st7735 import TFT
from sysfont import sysfont
from machine import SPI,Pin
import machine as mc
import time
import math
mc.freq(240000000)
spi = SPI(1, baudrate=20000000,
          sck=Pin(14), mosi=Pin(13),
          polarity=0, phase=0)
# dc, rst, cs
tft=TFT(spi,2,None,15)
tft.init_7735(tft.GREENTAB80x160)

def testlines(color):
    tft.fill(TFT.BLACK)
    for x in range(0, tft.size()[0], 6):
        tft.line((0,0),(x, tft.size()[1] - 1), color)
    for y in range(0, tft.size()[1], 6):
        tft.line((0,0),(tft.size()[0] - 1, y), color)

    tft.fill(TFT.BLACK)
    for x in range(0, tft.size()[0], 6):
        tft.line((tft.size()[0] - 1, 0), (x, tft.size()[1] - 1), color)
    for y in range(0, tft.size()[1], 6):
        tft.line((tft.size()[0] - 1, 0), (0, y), color)

    tft.fill(TFT.BLACK)
    for x in range(0, tft.size()[0], 6):
        tft.line((0, tft.size()[1] - 1), (x, 0), color)
    for y in range(0, tft.size()[1], 6):
        tft.line((0, tft.size()[1] - 1), (tft.size()[0] - 1,y), color)

    tft.fill(TFT.BLACK)
    for x in range(0, tft.size()[0], 6):
        tft.line((tft.size()[0] - 1, tft.size()[1] - 1), (x, 0), color)
    for y in range(0, tft.size()[1], 6):
        tft.line((tft.size()[0] - 1, tft.size()[1] - 1), (0, y), color)

def testfastlines(color1, color2):
    tft.fill(TFT.BLACK)
    for y in range(0, tft.size()[1], 5):
        tft.hline((0,y), tft.size()[0], color1)
    for x in range(0, tft.size()[0], 5):
        tft.vline((x,0), tft.size()[1], color2)

def testdrawrects(color):
    tft.fill(TFT.BLACK);
    for x in range(0,tft.size()[0],6):
        tft.rect((tft.size()[0]//2 - x//2, tft.size()[1]//2 - x/2), (x, x), color)

def testfillrects(color1, color2):
    tft.fill(TFT.BLACK);
    for x in range(tft.size()[0],0,-6):
        tft.fillrect((tft.size()[0]//2 - x//2, tft.size()[1]//2 - x/2), (x, x), color1)
        tft.rect((tft.size()[0]//2 - x//2, tft.size()[1]//2 - x/2), (x, x), color2)


def testfillcircles(radius, color):
    for x in range(radius, tft.size()[0], radius * 2):
        for y in range(radius, tft.size()[1], radius * 2):
            tft.fillcircle((x, y), radius, color)

def testdrawcircles(radius, color):
    for x in range(0, tft.size()[0] + radius, radius * 2):
        for y in range(0, tft.size()[1] + radius, radius * 2):
            tft.circle((x, y), radius, color)

def testtriangles():
    tft.fill(TFT.BLACK);
    color = 0xF800
    w = tft.size()[0] // 2
    x = tft.size()[1] - 1
    y = 0
    z = tft.size()[0]
    for t in range(0, 15):
        tft.line((w, y), (y, x), color)
        tft.line((y, x), (z, x), color)
        tft.line((z, x), (w, y), color)
        x -= 4
        y += 4
        z -= 4
        color += 100

def testroundrects():
    tft.fill(TFT.BLACK);
    color = 100
    for t in range(5):
        x = 0
        y = 0
        w = tft.size()[0] - 2
        h = tft.size()[1] - 2
        for i in range(17):
            tft.rect((x, y), (w, h), color)
            x += 2
            y += 3
            w -= 4
            h -= 6
            color += 1100
        color += 100

def tftprinttest():
    tft.fill(TFT.BLACK);
    v = 30
    tft.text((0, v), "Hello World!", TFT.RED, sysfont, 1, nowrap=True)
    v += sysfont["Height"]
    tft.text((0, v), "Hello World!", TFT.YELLOW, sysfont, 2, nowrap=True)
    v += sysfont["Height"] * 2
    tft.text((0, v), "Hello World!", TFT.GREEN, sysfont, 3, nowrap=True)
    v += sysfont["Height"] * 3
    tft.text((0, v), str(1234.567), TFT.BLUE, sysfont, 4, nowrap=True)
    time.sleep_ms(1500)
    tft.fill(TFT.BLACK);
    v = 0
    tft.text((0, v), "Hello World!", TFT.RED, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), str(math.pi), TFT.GREEN, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), " Want pi?", TFT.GREEN, sysfont)
    v += sysfont["Height"] * 2
    tft.text((0, v), hex(8675309), TFT.GREEN, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), " Print HEX!", TFT.GREEN, sysfont)
    v += sysfont["Height"] * 2
    tft.text((0, v), "Sketch has been", TFT.WHITE, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), "running for: ", TFT.WHITE, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), str(time.ticks_ms() / 1000), TFT.PURPLE, sysfont)
    v += sysfont["Height"]
    tft.text((0, v), " seconds.", TFT.WHITE, sysfont)

def testMain() :
  while True :
    tft.fill(TFT.BLACK)

    while True :
        tft.fill(TFT.BLACK)
        tft.text((0, 0), "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", TFT.WHITE, sysfont, 1)
        time.sleep_ms(1000)

        tftprinttest()
        time.sleep_ms(2000)

        testlines(TFT.YELLOW)
        time.sleep_ms(500)

        testfastlines(TFT.RED, TFT.BLUE)
        time.sleep_ms(500)

        testdrawrects(TFT.GREEN)
        time.sleep_ms(500)

        testfillrects(TFT.YELLOW, TFT.PURPLE)
        time.sleep_ms(500)

        tft.fill(TFT.BLACK)
        testfillcircles(10, TFT.BLUE)
        testdrawcircles(10, TFT.WHITE)
        time.sleep_ms(500)

        testroundrects()
        time.sleep_ms(500)

        testtriangles()
        time.sleep_ms(500)

def testRotation () :
    i = tft.rotate
    for x in range (0, 4) :
        tft.rotation(i)
        tft.fill(TFT.BLACK)
        tft.rect((0,0),tft.size(), TFT.WHITE)
        tft.rect((2,2),(tft.size()[0]-4, tft.size()[1]-4), TFT.YELLOW)
        tft.rect((4,4),(tft.size()[0]-8, tft.size()[1]-8), TFT.RED)
        tft.fillrect((0,0),(8,8),TFT.GREEN)
        tft.text((20, 20), "TEST", TFT.RED, sysfont, 2)
        print ('{} {}x{} {}:{}'.format(i, tft.size()[0],tft.size()[1] , tft.offset()[0],tft.offset()[1]))
        time.sleep_ms(3000)
        i = i + 1 if i < 3 else 0
    tft.rotation(1)
testRotation()
testMain()

Conclusion

From this article, found that we can implement SPI bus communication through ESP32 hardware with Python. The speed of work may not be the same as writing in C/C++ via the Arduino Framework or ESP-IDF, but for the convenience of writing and managing code. And as before, if readers are interested in TFT LCD 0.96″ ISP 80×160, we still have enough spare. (As described earlier, experiments often have to order in case) Thus, you can contact us or wait for us to finish the shop section, then support us to continue writing articles.

Lastly, have fun with programming.

(C) 2020, Danai Jedsadathitikul and Jarut Busarathid
Updated 2020-10-22