Breathing new life into an old LCD shield

Background

The latest generation of inexpensive microcontrollers have some capabilities that can be utilized in a variety of ways. One of them is the ability to quickly write parallel data with optional DMA (direct memory access) to drive the operation. The Raspberry Pi Pico not only has lots of exposed IO, but it contains a very flexible IO state machine that can run simple 'PIO' programs to manipulate IO with precise timing. The good folks at Pimoroni reminded me of this recently with the release of their Tufty2040 product. The board features a RP2040 MCU along with a lovely ST7789 IPS 240x320 color LCD. The bold move they made was to take the extra effort to connect it on an 8-bit parallel bus instead of the usual 1-bit SPI. This change allows the LCD to rewrite its entire content more than 60 times per second. To clarify, the RP2040 has no video output, but inexpensive LCDs like the ST7789 have their own internal video RAM and can be told what to display with a series of 'move cursor' and 'write pixel' commands. Send those commands fast enough and you can produce smooth animation and even video.

Taking it further

I bought a Tufty2040 as soon as it became available and think it's a great product. Two things got me thinking about doing some additional experimentation with the idea of parallel displays:

- Pimoroni's software for the Tufty2040 is focused on MicroPython and I prefer to work in native code (Arduino)
- I have an old Arduino UNO display shield with a parallel LCD (ILI9486 320x480):



I wrote my own display library (bb_spi_lcd) that already supports a lot of display controllers, but 8-bit parallel support is something new. Using the RP2040 to drive the ILI9486 sounded like a worthwhile challenge.

RP2040 PIO

Setting up the state machine of the RP2040 and writing code for it is a non-trivial exercise that's not the focus of this post. For my use case, I 'borrowed' the 2-line PIO program from Pimoroni (with full attribution) and wrote my own support around it. Here's the entire PIO program for driving a parallel LCD:

            //     .wrap_target
    0x6008, //  0: out    pins, 8         side 0
    0xb042, //  1: nop                    side 1
            //     .wrap

The code simply writes 8 bits of data to sequential GPIO pins and then toggles the "side" pin which is the write clock (LCD_WR) input.

There's additional code needed to configure the pins, set up DMA etc., but that's the heart of writing data 8-bits at a time on the RP2040.

Wiring

To make use of the UNO display shield, I created a tinned protoboard adapter. I used the same wiring scheme as the Tufty2040, but you can use almost any GPIO pins as long as the 8 data pins are sequential numbers.


The pins for the LCD are connect as follows:
LCD_CS = GPIO10
LCD_RS = GPIO11
LCD_WR = GPIO12
LCD_RD = GPIO13
LCD_D0..D7 = GPIO14...21
(and connect GND, 5V and 3V to the appropriate pins on the Pico)

Putting it to the test

My personal favorite way of testing MCUs and displays is to throw a good GIF animation at them. Here's the code to set up the display. I created a 'named display' feature in bb_spi_lcd which makes it easier to initialize popular devices. In this case, I made one for this setup called "DISPLAY_KUMAN_35". It assumes that the GPIO pins are wired as above.


The code is located in the parallel_shield_demo sketch on the display library repo: bb_spi_lcd
If I haven't done a new release of the library yet (so that it shows up in the Arduino library manager), it's because it's still in development, but you can do a clone of the repo and use it in its pre-release state.

Here's the video of it in action:



Comments

Popular posts from this blog

Surprise! ESP32-S3 has (a few) SIMD instructions

How much current do OLED displays use?

Fast SSD1306 OLED drawing with I2C bit banging