Graphics library for cheap KMR-1.8 SPI (S6D02A1 and ILI9163) TFT displays

The new library supports low cost S6D02A1 based displays connected to an UNO, Leonardo or Mega via SPI, it is based on the Adafruit GFX library with encoded fonts to save space. The library is highly optimised for AVR processors to boost performance and is 3 to 10 times faster than the basic Adafruit library.

The library can be found on Github.

These are pictures of my display.

Some similar looking displays have the ST7735 driver fitted so a different library is needed.

This display does not tolerate 5V logic signals. A series resistor works but the contrast flickers, so a resistor divider is needed. Connect as follows:

  • UNO +5V to display pin 2 (VCC)
  • UNO 0V (GND) to display pin 1 (GND)
  • UNO +5V through a 22 Ohm resistor to display pin 15 (LED+)
  • UNO 0V (GND) to display pin 16 (LED-)
  • UNO digital pin 7 through a 1K2 resistor to display pin 6 (RESET), add a 2K2 resistor from display pin 6 to GND
  • UNO digital pin 8 through a 1K2 resistor to display pin 7 (A0), add a 2K2 resistor from display pin 7 to GND
  • UNO digital pin 11 through a 1K2 resistor to display pin 8 (SDA), add a 2K2 resistor from display pin 8 to GND
  • UNO digital pin 13 through a 1K2 resistor to display pin 9 (SCL), add a 2K2 resistor from display pin 9 to GND
  • UNO digital pin 9 through a 1K2 resistor to display pin 10 (CS), add a 2K2 resistor from display pin 10 to GND

The 22R resistor is needed to limit the LED current to about 55mA.

Please report any bugs here.

Update: It appears this display is fitted with a ILI9163 driver but just happens to work with the S6D02A1 based library. So I have created a new library specifically for the ILI9163 driver. It is exxentially the same library as the link above but has initialisation code specifically for the ILI9163 driver. This library can be found here:

TFT_ILI9163 library

Note: This library "almost" works with ST7735S based displays but the blue and red colours will be swapped, rotations will not work and the colours will be dull because the Gamma registers will not be setup.

I've updated updated the library on GitHub to improve performance by reducing the number of SPI transactions needed to plot single pixels and lines, this also speeds up other graphics functions like plotting text characters and drawing circle+triangle outlines.

Two new examples "TFT_3d_engine" and "TFT_Starfield" have been added that benefit significantly from this approach.

All this extra effort was just to get a game of "Space Invaders" running smoothly on the UNO... :slight_smile:

This is a really good library, I have been waiting for something like this. I am only playing with code at the moment, but it seems very fast.

Hi Richard,

Thanks for the feedback. I have done some tests and it is significantly faster than the equivalent stock Adafruit library, for example running this 1000 times:

tft.drawLine(0, 0, 100, 20, 0xFFFF);

shows it is 24x faster.

drawPixel is the most fundamental graphics operation and is more than 7x faster. In cases where the new fastPixel function can be used, it is at least 10x faster.

Hello Everyone,

I got the same display from Aliexpress and still unable to have it working on my Mega.
I wired it like suggested.
I first tried with the library for a ST7735 and a got something like Fantawttw from this thread : Help Please: KMR-1.8 SPI can't get it working - Displays - Arduino Forum
I had a loop that had "invertDisplay" called every second and it did change the display, although I'm not sure it was really inverting but at least showed me that kind of talk to the module...

Then I tried with the library for the S6D02A1. We are never sure which driver they put in these Chinese builds!
I got really no sign of life with this one.
I tried with a second display, new out of box, same thing.

I've seen people getting good results from these displays but after a lot of attemps I am still stuck.
Am I missing something? Where should I start looking?

Thanks!

Which pins on the Mega have you wired up to the display?

I have wired this way

  • RESET to 49
  • A0 to 47
  • SDA to 51
  • SCK to 52
  • CS to 45

All these with 1K in series. I also tried a voltage divider with a 1.5K that gave me 3V at the pin (should be enough for the logic 1 CMOS level).

Thanks for your help!

@slessard

Can you post pictures of the front and back of the display. I may be able to match it to one of the displays I have. Though it might look the same as the one I posted on this thread are subtle differences on the PCB, the display white plastic frame and the ribbon cable that comes off the display that may help narrow down the coice of driver.

If you use the library linked in the original post you do need to configure the pins in the User_Setup.h file within the library folder.

I also have a sketch that reads back the ID so I will see if I can find where I saved it (!) and test it on some of my displays.

Hello Bodmer,

Thanks for your reply. Here is a photo of front and back in attachment.

Yes, I have noticed the instruction in the example and I modified the User_Setup.h according to my IO configuration.

Thanks again!
Simon

slessard:
I have wired this way

  • RESET to 49
  • A0 to 47
  • SDA to 51
  • SCK to 52
  • CS to 45

All these with 1K in series. I also tried a voltage divider with a 1.5K that gave me 3V at the pin (should be enough for the logic 1 CMOS level).

Thanks for your help!

It may be a typo error but you should use SCL not SCK (which is the clock line for the SD Card slot).

The white plastic frame and ribbon cable off the display is different to mine. I will check if that corresponds to one of my displays later today and post a display ID reader. You may have a ST7735 driver or a Hynix driver.

What Hynix controllers are there?
I googled and found that Hynix sold (or were trying to sell) their TFT business in 2001.
Did 128x160 singlechip controllers exist in 2001?

There seem to be several 128x160 controllers from different manufacturers e.g.
ILI9163C Ilitek
ST7735S Sitronix
S6D02A1 Samsung

I presume that Renesas, Himax, SolomonSystech, ... have parts too.

David.

Hello Bodmer,

Yes it was a typo. I use the SCL pin on the TFT side, wired to the SCK on the Mega side. Thanks for pointing out.

David, I tried with library for ST7735S and S6D02A1.
A got at least some basic responding with the ST7735S (I looped over the function InvertDisplay every second and I saw the screen flashing at same frequency. I'm not sure it was actually inverting but it did something).
The call to fill with a solid color didn't filled the entire screen but about 2/3 with some large areas in the middle being unaffected by the command (tried on two different parts).
I got no result with the driver from Samsung so unless drivers have similar command register or I got lucky and the InvertDisplay function was recognized by my display even if I was using the wrong library, I guess that mine is ST7735S.
I can still try with the libs for ILI9163C just in case!

Thanks,
Simon

My comments / questions were directed to Bodmer. He knows a lot about this class of controller.

If you can diagnose which make of controller is present, you can use the correct library. Or configure a universal library to suit your display.

These controllers are readable if you use 3.3V logic. And readable with 5V logic if you use series resistors. I have published a sketch before now. I can't remember which thread(s) that I posted in.

David.

@david_prentice: I meant Himax, well spotted! I remember seeing a 1.8" display with a HX---- driver advertised, but I am not sure where I saw it. Yes you are right, ILI9163/S6D02A1/ST7735 are all options often advertised for 1.8" displays.

@slessard: Your PCB has different track routing to mine.

Below is a sketch that might help identify the driver. I have used the ID's from the data sheets for the ILI9163/S6D02A1/ST7735S drivers.

// Read the ID from the TFT controller
// The sketch only supports displays with a bi-directional SPI data line (often labelled SDA)

// Bit bashes SPI so it does NOT assume hardware SPI wired up
// No other libraries are needed

// Original author unknown
// Adapted by Bodmer 22/5/16, updated 16/9/16

// Change the pin settings to suit your hardware

// UNO etc
//#define TFT_MOSI  11
//#define TFT_SCK 13
//#define TFT_CS 9
//#define TFT_DC  8
//#define TFT_RESET 7

//Mega
#define TFT_MOSI  51
#define TFT_SCK 52
#define TFT_CS 47
#define TFT_DC  48
#define TFT_RESET 44

/* Example Serial Monitor output:

TFT driver register values:
===========================
Register 0x01: 0x00
Register 0x04: 0x548066
Register 0x09: 0x610000
Register 0x0A: 0x08
Register 0x0B: 0x00
Register 0x0C: 0x06
Register 0x0D: 0x00
Register 0x0E: 0x00
Register 0x0F: 0x00
Register 0x2E: 0x1834B4
Register 0xDA: 0x54
Register 0xDB: 0x80
Register 0xDC: 0x66
===========================

Looks like driver chip is: ILI9163 (based on datasheet ID)

*/

char *chip = "Unknown                                                                                           ";


uint32_t readwrite8(uint8_t cmd, uint8_t bits, uint8_t dummy)
{
    uint32_t ret = 0;
    uint8_t val = cmd;
    int cnt = 8;
    digitalWrite(TFT_CS, LOW);
    digitalWrite(TFT_DC, LOW);
    pinMode(TFT_MOSI, OUTPUT);
    for (int i = 0; i < 8; i++) {   //send command
        digitalWrite(TFT_MOSI, (val & 0x80) != 0);
        digitalWrite(TFT_SCK, HIGH);
        digitalWrite(TFT_SCK, LOW);
        val <<= 1;
    }
    if (bits == 0) {
        digitalWrite(TFT_CS, HIGH);
        return 0;
    }
    pinMode(TFT_MOSI, INPUT_PULLUP);
    digitalWrite(TFT_DC, HIGH);
    for (int i = 0; i < dummy; i++) {  //any dummy clocks
        digitalWrite(TFT_SCK, HIGH);
        digitalWrite(TFT_SCK, LOW);
    }
    for (int i = 0; i < bits; i++) {  // read results
        ret <<= 1;
        if (digitalRead(TFT_MOSI)) ret |= 1;;
        digitalWrite(TFT_SCK, HIGH);
        digitalWrite(TFT_SCK, LOW);
    }
    digitalWrite(TFT_CS, HIGH);
    return ret;
}

void showreg(uint8_t reg, uint8_t bits, uint8_t dummy)
{
    uint32_t val;
    val = readwrite8(reg, bits, dummy);

    Serial.print("Register 0x");
    if (reg < 0x10) Serial.print("0");
    Serial.print(reg , HEX);
    Serial.print(": 0x");
    if (val < 0x10) Serial.print("0");
    Serial.println(val, HEX);
}

void setup() {
    // put your setup code here, to run once:
    uint32_t ID = 0;
    Serial.begin(9600);
    Serial.println("TFT driver register values:");
    Serial.println("===========================");
    digitalWrite(TFT_CS, HIGH);
    //    digitalWrite(TFT_SCK, HIGH);
    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_SCK, OUTPUT);
    pinMode(TFT_MOSI, OUTPUT);
    pinMode(MISO, INPUT_PULLUP);
    pinMode(TFT_DC, OUTPUT);
    pinMode(TFT_RESET, OUTPUT);
    digitalWrite(TFT_RESET, HIGH);
    digitalWrite(TFT_RESET, LOW);   //Hardware Reset
    delay(50);
    digitalWrite(TFT_RESET, HIGH);
    showreg(0x01, 0, 0);            //Software Reset
    delay(100);
    ID = readwrite8(0x04, 24, 1);

    if ((ID & 0xFF8000) == 0x5C8000uL) chip = "ST7735 (based on datasheet ID)";
    if (ID == 0x7C89F0uL) chip = "ST7735 (empirical value)";
    if (ID == 0x548066uL) chip = "ILI9163 (based on datasheet ID)";
    if (ID == 0x5C0000uL) chip = "S6D02A1 (based on datasheet ID)";
 
    showreg(0x04, 24, 1);   //RDDID
    showreg(0x09, 32, 1);   //RDSTATUS
    showreg(0x0A, 8, 0);
    showreg(0x0B, 8, 0);
    showreg(0x0C, 8, 0);
    showreg(0x0D, 8, 0);
    showreg(0x0E, 8, 0);
    showreg(0x0F, 8, 0);
    showreg(0x2E, 24, 8);   //readGRAM
    showreg(0xDA, 8, 0);
    showreg(0xDB, 8, 0);
    showreg(0xDC, 8, 0);

    Serial.println("===========================");
    Serial.println();
    Serial.print("Looks like driver chip is: " );Serial.println(chip);
}

void loop() {

}

Interestingly it reports my display as having an ILI9163 but I am using initialisation code from this library for a S6D02A1 and it works OK but that may just be by luck and a degree of initialisation address compatibility.

Can you tell me where you got your display and what the ID reading sketch reports in the Serial Monitor window (9600 baud)?

The ID reader code in post #13 above indicates I have a ILI9163 driver on my display but this just happens to work OK with the S6D02A1 library!

So I have created a specific library for the ILI9163 and it is working fine. It retains the high plotting performance and is suited to AVR processors only (UNO, Mega, Leonardo etc) because of the way the performance enhancements have been done.

Report any bugs here.

Hello Bodmer,

Yes it was a typo. I use the SCL pin on the TFT side, wired to the SCK on the Mega side. Thanks for pointing out.

David, I tried with library for ST7735S and S6D02A1.
A got at least some basic responding with the ST7735S (I looped over the function InvertDisplay every second and I saw the screen flashing at same frequency. I'm not sure it was actually inverting but it did something).
The call to fill with a solid color didn't filled the entire screen but about 2/3 with some large areas in the middle being unaffected by the command (tried on two different parts).
I got no result with the driver from Samsung so unless drivers have similar command register or I got lucky and the InvertDisplay function was recognized by my display even if I was using the wrong library, I guess that mine is ST7735S.
I can still try with the libs for ILI9163C just in case!

Thanks,
Simon

Hello bodmer,

Thanks for the script! Pretty effective... I just ran it and here is the output :

TFT driver register values:
===========================
Register 0x01: 0x00
Register 0x04: 0x548066
Register 0x09: 0x610000
Register 0x0A: 0x08
Register 0x0B: 0x00
Register 0x0C: 0x06
Register 0x0D: 0x00
Register 0x0E: 0x00
Register 0x0F: 0x00
Register 0x2E: 0x482020
Register 0xDA: 0x54
Register 0xDB: 0x80
Register 0xDC: 0x66
===========================

Looks like driver chip is: ILI9163 (based on datasheet ID)

The one I haven't tried yet, so there is hope!
I also went back to the description of the TFT part I bought and it says ST7735... we always have surprises with these products from China!
I will try your lib and give you some news.

Thanks again!

@slessard

OK, it looks like you have an ILI9163 based display then. The results indicate you have got the connections right.

You will need a resistor divider on the logic lines with that driver to avoid brightness modulation (happens when the display is being updated), I use 1k2 and 2k2 as I have lots of those values. Power the display from 5V, I notice that my display is fitted with a 3.0V regulator.

I intend to make a minor tweak to the library later today to add a "belt and braces" software reset at the start of initialisation.

I tested another display that I thought had a S6D02A1 and this does indeed seem to be the case as it only works with the TFT_S6D02A1 library and no others. Whereas the ILI9163 based display works fine with either the TFT_ILI9163 or the S6D02A1 library!

PS The TFT_ILI9163 library has been updated to add a software reset at the start of initialisation. This will help in cases where a display does not have a hardware reset pin.

It's starting to give some results!
Apparently my TFT that was identified to be built with driver ST7735 by the vendor was finally made from ILI9163...
Although it is not perfect, I have a good start see attached.
The background is weird and the two bright stripes we can see is like those I got when I was using the library for the ST7735 but at this time it was two solid color areas, not pixelized like that and obviously without the text.