From 0835b336bd3de5c89a25b328d48da811b4db9ebf Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 27 Jun 2017 17:41:12 +0200 Subject: [PATCH] Very first step, talking successfully to ST7787 --- TFT_Drivers/ST7787_Defines.h | 116 ++++++++++++++++++++++++ TFT_Drivers/ST7787_Init.h | 37 ++++++++ TFT_Drivers/ST7787_Rotation.h | 28 ++++++ TFT_eSPI.cpp | 161 +++++++++++++++++++++++++++++++--- TFT_eSPI.h | 15 ++++ User_Setup.h | 11 ++- User_Setup_Select.h | 2 + 7 files changed, 354 insertions(+), 16 deletions(-) create mode 100644 TFT_Drivers/ST7787_Defines.h create mode 100644 TFT_Drivers/ST7787_Init.h create mode 100644 TFT_Drivers/ST7787_Rotation.h diff --git a/TFT_Drivers/ST7787_Defines.h b/TFT_Drivers/ST7787_Defines.h new file mode 100644 index 0000000..715173b --- /dev/null +++ b/TFT_Drivers/ST7787_Defines.h @@ -0,0 +1,116 @@ +// Change the width and height if required (defined in portrait mode) +// or use the constructor to over-ride defaults +#ifndef TFT_WIDTH + #define TFT_WIDTH 240 +#endif +#ifndef TFT_HEIGHT + #define TFT_HEIGHT 320 +#endif + + +// Color definitions for backwards compatibility with old sketches +// use colour definitions like TFT_BLACK to make sketches more portable +#define ST7735_BLACK 0x0000 /* 0, 0, 0 */ +#define ST7735_NAVY 0x000F /* 0, 0, 128 */ +#define ST7735_DARKGREEN 0x03E0 /* 0, 128, 0 */ +#define ST7735_DARKCYAN 0x03EF /* 0, 128, 128 */ +#define ST7735_MAROON 0x7800 /* 128, 0, 0 */ +#define ST7735_PURPLE 0x780F /* 128, 0, 128 */ +#define ST7735_OLIVE 0x7BE0 /* 128, 128, 0 */ +#define ST7735_LIGHTGREY 0xC618 /* 192, 192, 192 */ +#define ST7735_DARKGREY 0x7BEF /* 128, 128, 128 */ +#define ST7735_BLUE 0x001F /* 0, 0, 255 */ +#define ST7735_GREEN 0x07E0 /* 0, 255, 0 */ +#define ST7735_CYAN 0x07FF /* 0, 255, 255 */ +#define ST7735_RED 0xF800 /* 255, 0, 0 */ +#define ST7735_MAGENTA 0xF81F /* 255, 0, 255 */ +#define ST7735_YELLOW 0xFFE0 /* 255, 255, 0 */ +#define ST7735_WHITE 0xFFFF /* 255, 255, 255 */ +#define ST7735_ORANGE 0xFD20 /* 255, 165, 0 */ +#define ST7735_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ +#define ST7735_PINK 0xF81F + +#define ILI9341_BLACK ST7735_BLACK + + +// Delay between some initialisation commands +#define TFT_INIT_DELAY 0x80 + + +// Generic commands used by TFT_eSPI.cpp +#define TFT_NOP 0x00 +#define TFT_SWRST 0x01 + +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C + +#define TFT_RAMRD 0x2E +#define TFT_IDXRD 0x00 //0xDD // ILI9341 only, indexed control register read + +#define TFT_MADCTL 0x36 +#define TFT_MAD_MY 0x80 +#define TFT_MAD_MX 0x40 +#define TFT_MAD_MV 0x20 +#define TFT_MAD_ML 0x10 +#define TFT_MAD_BGR 0x08 +#define TFT_MAD_MH 0x04 +#define TFT_MAD_RGB 0x00 + +#define TFT_INVOFF 0x20 +#define TFT_INVON 0x21 + +// ST7787 specific commands used in init +#define ST7787_NOP 0x00 +#define ST7787_SWRESET 0x01 +#define ST7787_RDDID 0x04 +#define ST7787_RDDST 0x09 + +#define ST7787_SLPIN 0x10 +#define ST7787_SLPOUT 0x11 +#define ST7787_PTLON 0x12 +#define ST7787_NORON 0x13 + +#define ST7787_INVOFF 0x20 +#define ST7787_INVON 0x21 +#define ST7787_DISPOFF 0x28 +#define ST7787_DISPON 0x29 +#define ST7787_CASET 0x2A +#define ST7787_RASET 0x2B // PASET +#define ST7787_RAMWR 0x2C +#define ST7787_RAMRD 0x2E + +#define ST7787_PTLAR 0x30 +#define ST7787_MADCTL 0x36 +#define ST7787_COLMOD 0x3A + +#define ST7787_FRMCTR1 0xB1 +#define ST7787_FRMCTR2 0xB2 +#define ST7787_FRMCTR3 0xB3 +#define ST7787_INVCTR 0xB4 +#define ST7787_DISSET5 0xB6 +#define ST7787_VSYNCOUT 0xBC +#define ST7787_VSYNCIN 0xBD + +#define ST7787_PWCTR1 0xC0 +#define ST7787_PWCTR2 0xC1 +#define ST7787_PWCTR3 0xC2 +#define ST7787_PWCTR4 0xC3 +#define ST7787_PWCTR5 0xC4 +#define ST7787_VMCTR1 0xC5 + +#define ST7787_RDID1 0xDA +#define ST7787_RDID2 0xDB +#define ST7787_RDID3 0xDC + +#define ST7787_GMCTRP1 0xE0 +#define ST7787_GMCTRN1 0xE1 + +/* Timing delays from ST7787 datasheet (in nanoseconds). */ +#define ST7787_T_CSS 60 +#define ST7787_T_SCC 20 +#define ST7787_T_CHW 40 +#define ST7787_T_SHW 20 +#define ST7787_T_SLW 20 +#define ST7787_T_SHR 60 +#define ST7787_T_SLR 60 diff --git a/TFT_Drivers/ST7787_Init.h b/TFT_Drivers/ST7787_Init.h new file mode 100644 index 0000000..3ef08ce --- /dev/null +++ b/TFT_Drivers/ST7787_Init.h @@ -0,0 +1,37 @@ + +// This is the command sequence that initialises the ST7787 driver +// +// This setup information uses simple 8 bit SPI writecommand() and writedata() functions +// +// See ST7735_Setup.h file for an alternative format + +{ + /* Take the display out of sleep mode. */ + writecommand(ST7787_SLPOUT); + /* + Wait for sleep-out command to complete. + Datasheet says 5 msec is enough before next command, but 120 msec is + needed before the display is fully out of sleep mode. + */ + delay(120); + /* + Select 16-bit 565 RGB pixel format (mode 5). + Same for RGB mode (but we don't use it). + */ + writecommand(ST7787_COLMOD); + writedata((13 << 4) | 5); + /* Disable external vsync. */ + writecommand(ST7787_VSYNCOUT); + /* Turn on the display */ + writecommand(ST7787_DISPON); + + { + /* Debug: Read ID and status, to see if the basics are working. */ + uint8_t buf[4]; + docommand(ST7787_RDDID, NULL, 0, buf, 3); + Serial.print("RDDID: "); Serial.print(buf[0], HEX); Serial.print(" "); Serial.print(buf[1], HEX); Serial.print(" "); Serial.print(buf[2], HEX); Serial.print("\r\n"); + docommand(ST7787_RDDST, NULL, 0, buf, 4); + Serial.print("RDDST: "); Serial.print(buf[0], HEX); Serial.print(" "); Serial.print(buf[1], HEX); Serial.print(" "); Serial.print(buf[2], HEX); Serial.print(" "); Serial.print(buf[3], HEX); Serial.print("\r\n"); + for (;;) { } + } +} diff --git a/TFT_Drivers/ST7787_Rotation.h b/TFT_Drivers/ST7787_Rotation.h new file mode 100644 index 0000000..13a0ebe --- /dev/null +++ b/TFT_Drivers/ST7787_Rotation.h @@ -0,0 +1,28 @@ + +// This is the command sequence that rotates the ST7735 driver coordinate frame + + rotation = m % 4; // Limit the range of values to 0-3 + + writecommand(TFT_MADCTL); + switch (rotation) { + case 0: + writedata(TFT_MAD_RGB); + _width = TFT_WIDTH; + _height = TFT_HEIGHT; + break; + case 1: + writedata(TFT_MAD_MX | TFT_MAD_MV | TFT_MAD_RGB); + _width = TFT_HEIGHT; + _height = TFT_WIDTH; + break; + case 2: + writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_RGB); + _width = TFT_WIDTH; + _height = TFT_HEIGHT; + break; + case 3: + writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_RGB); + _width = TFT_HEIGHT; + _height = TFT_WIDTH; + break; + } diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 0189854..5a2d940 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -24,7 +24,9 @@ //#include //#include "pins_arduino.h" //#include "wiring_private.h" +#ifndef ST7787_DRIVER #include +#endif // If it is a 16bit serial display we must transfer 16 bits every time #ifdef RPI_ILI9486_DRIVER @@ -90,6 +92,16 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) } #endif +#ifdef TFT_DAT + digitalWrite(TFT_DAT, HIGH); + pinMode(TFT_DAT, OUTPUT); +#endif + +#ifdef TFT_SCK + digitalWrite(TFT_SCK, LOW); + pinMode(TFT_SCK, OUTPUT); +#endif + _width = w; // Set by specific xxxxx_Defines.h file or by users sketch _height = h; // Set by specific xxxxx_Defines.h file or by users sketch rotation = 0; @@ -172,7 +184,17 @@ void TFT_eSPI::init(void) SPI.pins(6, 7, 8, 0); #endif + #ifdef TFT_DAT + cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); + #endif + + #ifdef TFT_SCK + cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); + #endif + +#ifndef ST7787_DRIVER SPI.begin(); // This will set HMISO to input +#endif #else #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); @@ -185,6 +207,7 @@ void TFT_eSPI::init(void) inTransaction = false; locked = true; +#ifdef ST7787_DRIVER #ifndef SUPPORT_TRANSACTIONS SPI.setBitOrder(MSBFIRST); @@ -197,6 +220,7 @@ void TFT_eSPI::init(void) locked = false; // Flag to stop repeat beginTransaction calls #endif +#endif #endif // Set to output once again in case D6 (MISO) is used for CS @@ -249,6 +273,9 @@ void TFT_eSPI::init(void) #elif defined (RPI_ILI9486_DRIVER) #include "TFT_Drivers/RPI_ILI9486_Init.h" +#elif defined(ST7787_DRIVER) + #include "TFT_Drivers/ST7787_Init.h" + #endif spi_end(); @@ -281,6 +308,9 @@ void TFT_eSPI::setRotation(uint8_t m) #elif defined (RPI_ILI9486_DRIVER) #include "TFT_Drivers/RPI_ILI9486_Rotation.h" +#elif defined (ST7787_DRIVER) + #include "TFT_Drivers/ST7787_Rotation.h" + #endif delayMicroseconds(10); @@ -338,20 +368,101 @@ void TFT_eSPI::spiwrite(uint8_t c) } +void TFT_eSPI::docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len) +{ + uint32_t i; + uint32_t val; + + DAT_O; + CS_L; + delay_ns(ST7787_T_CSS); + + /* Write the command byte. */ + /* First shift out the data/command bit ('0' for command). */ + SCK_L; + DAT_L; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + /* Then shift out the bits, MSB-to-LSB. */ + val = c; + for (i = 8; i; --i) { + SCK_L; + if ((val>>7) & 1) + DAT_H; + else + DAT_L; + val <<= 1; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + } + + /* Write any command data. */ + if (in_len) { + do { + val = *in++; + + /* Data/command bit ('1' for data). */ + SCK_L; + DAT_H; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + + for (i = 8; i; --i) { + SCK_L; + if ((val>>7) & 1) + DAT_H; + else + DAT_L; + val <<= 1; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + } + } while (--in_len > 0); + } + + DAT_I; + + /* Read reply. */ + if (out_len) { + /* Dummy bit (according to data sheet, data/command placeholder?). */ + SCK_L; + delay_ns(ST7787_T_SLR); + SCK_H; + delay_ns(ST7787_T_SHR); + + do { + val = 0; + for (i = 8; i; --i) { + SCK_L; + delay_ns(ST7787_T_SLR); + val = (val << 1); + if (DAT_V) + val = val | 1; + SCK_H; + delay_ns(ST7787_T_SHR); + } + *out++ = val; + } while (--out_len > 0); + } + + SCK_L; + delay_ns(ST7787_T_SCC); + CS_H; + delay_ns(ST7787_T_CHW); +} + + /*************************************************************************************** ** Function name: writecommand ** Description: Send an 8 bit command to the TFT ***************************************************************************************/ void TFT_eSPI::writecommand(uint8_t c) { - DC_C; - CS_L; - #ifdef SEND_16_BITS - SPI.transfer(0); - #endif - SPI.transfer(c); - CS_H; - DC_D; + docommand(c, NULL, 0, NULL, 0); } @@ -361,12 +472,38 @@ void TFT_eSPI::writecommand(uint8_t c) ***************************************************************************************/ void TFT_eSPI::writedata(uint8_t c) { + uint32_t i; + uint32_t val; + + DAT_O; CS_L; - #ifdef SEND_16_BITS - SPI.transfer(0); - #endif - SPI.transfer(c); + delay_ns(ST7787_T_CSS); + + /* Data/command bit ('1' for data). */ + val = c; + SCK_L; + DAT_H; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + + for (i = 8; i; --i) { + SCK_L; + if ((val>>7) & 1) + DAT_H; + else + DAT_L; + val <<= 1; + delay_ns(ST7787_T_SLW); + SCK_H; + delay_ns(ST7787_T_SHW); + } + + DAT_I; + + delay_ns(ST7787_T_SCC); CS_H; + delay_ns(ST7787_T_CHW); } diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 25c86b6..e6d7719 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -120,6 +120,19 @@ #endif #endif +#ifdef TFT_DAT +#define DAT_I pinMode(TFT_DAT, INPUT) +#define DAT_O pinMode(TFT_DAT, OUTPUT) +#define DAT_L digitalWrite(TFT_DAT, LOW) +#define DAT_H digitalWrite(TFT_DAT, HIGH) +#define DAT_V digitalRead(TFT_DAT) +#endif + +#ifdef TFT_SCK +#define SCK_L digitalWrite(TFT_SCK, LOW) +#define SCK_H digitalWrite(TFT_SCK, HIGH) +#endif + #ifdef LOAD_GFXFF // We can include all the free fonts and they will only be built into // the sketch if they are used @@ -361,6 +374,7 @@ class TFT_eSPI : public Print { setTextFont(uint8_t font), #endif spiwrite(uint8_t), + docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len), writecommand(uint8_t c), writedata(uint8_t d), commandList(const uint8_t *addr); @@ -458,6 +472,7 @@ inline void spi_end() __attribute__((always_inline)); *gfxFont; #endif + void delay_ns(uint32_t d) { delayMicroseconds(1); /* ToDo */ } }; #endif diff --git a/User_Setup.h b/User_Setup.h index a106fd9..67d178b 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -14,15 +14,16 @@ // ################################################################################## // Only define one driver, the other ones must be commented out -#define ILI9341_DRIVER +//#define ILI9341_DRIVER //#define ST7735_DRIVER //#define ILI9163_DRIVER //#define S6D02A1_DRIVER //#define RPI_ILI9486_DRIVER // 20MHz maximum SPI +#define ST7787_DRIVER // For ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation -//#define TFT_WIDTH 128 -//#define TFT_HEIGHT 160 +#define TFT_WIDTH 240 +#define TFT_HEIGHT 320 //#define TFT_HEIGHT 128 // For ST7735 ONLY, define the type of display, originally this was based on the @@ -81,9 +82,11 @@ // For ModeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation #define TFT_CS PIN_D8 // Chip select control pin D8 -#define TFT_DC PIN_D3 // Data Command control pin +//#define TFT_DC PIN_D3 // Data Command control pin #define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line) //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V +#define TFT_SCK PIN_D5 +#define TFT_DAT PIN_D7 //#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only diff --git a/User_Setup_Select.h b/User_Setup_Select.h index 3d8c600..16a9478 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -51,6 +51,8 @@ #include #elif defined (RPI_ILI9486_DRIVER) #include +#elif defined (ST7787_DRIVER) + #include #endif // These are the pins for all ESP8266 boards