Using 16 bit parallel displays in pseudo 8 bit mode

Pin constrained processors such as the ESP32 do not have enough pins to drive a 16 bit parallel display, so if you have bought one of those displays it may end up getting unused.

There is however a "trick" with these displays to make them usable as 8 bit parallel displays, providing you are content to use a limited set of colours.

The "trick" is possible because typically all commands only use data bits D0-7 and that is 8 bits, when writing commands the bits D8-15 are "don't care" so could be set to any value. Colours on the other hand do use the full 16 bit width.

This means the display can be driven as 16 bits by a 16 bit library but the data bits D8-17 at the display can wired to D0-7 thus:

Connect D0 to D8
Connect D1 to D9
Connect D2 to D10
Connect D3 to D11
Connect D4 to D12
Connect D5 to D13
Connect D6 to D14
Connect D7 to D15

The control pins DC, CS and WR are wired normally and RD (if available) tied high.

You can now use a limited set of "byte matched" colours to draw graphics on the screen such as these:

// These are byte matched colours
#define BM_BLACK   0x0000
#define BM_BLUE    0x1818
#define BM_RED     0xE0E0
#define BM_GREEN   0x0707
#define BM_CYAN    0x7777
#define BM_MAGENTA 0xF8F8
#define BM_YELLOW  0xE7E7
#define BM_WHITE   0xFFFF
#define BM_LIGHT_GREY  0xB5B5
#define BM_DARK_GREY   0x6B6B
#define BM_PINK    0xF4F4
#define BM_ORANGE  0xE4E4

The library used must support 16 bit displays but you do have to assign the pins for D8-15 in the library to a single unused processor pin or set the pin number to -1 if the library can accept that. That will keep the library thinking it is driving a true 16 bit display.

If you try this then do post back!

The image below shows all the 256 matching byte hexadecimal colour codes that can be displayed on a “pseudo 8bit” display.

The columns are numerically ordered but the rows are not, this is deliberate so that the colours end up being grouped into 4 colour coordinated sets. Black is at top left and white at bottom right.

This is the main code section that generated the image on a 480x320 TFT is:

  tft.fillScreen(TFT_BLACK);
  tft.setTextDatum(MC_DATUM); // Text datum is middle centre
  uint16_t color = 0;
  for ( int y = 0; y < 16; y++)
  {
    for ( int x = 0; x < 16; x++)
    {
      tft.fillRect(x*30,y*20,30,20, color<<8 | color);
      String hex =  "";
      if (color < 16) hex = "0";
      hex = hex + String(color, HEX);
      hex = hex + hex;
      if ((color<<8 | color)>0xC000) tft.setTextColor(0);
      else   tft.setTextColor(TFT_WHITE);
      tft.drawString(hex, x*30+15,y*20+10,1);

      color++;
      if (color%16 == 0) color+=16;
      if (color == 256) color = 16;

    }
  }

Interesting hack. There are other approaches, such as using a couple of '595's to hold the
16 bit value, but my preference is just go for the SPI version of a display, its not that slow if run at the
full 8MHz the ATmega328 is capable of.