From 3fb9bc5cbd134fdb7aec5ba86453ac0dbd683620 Mon Sep 17 00:00:00 2001 From: Haroldo M Murata Date: Sat, 8 May 2021 15:27:07 -0300 Subject: [PATCH 1/5] ST7781_driver All fixes and examples with comments. --- Processors/TFT_eSPI_ESP32.c | 5 + Processors/TFT_eSPI_ESP8266.c | 4 + Processors/TFT_eSPI_Generic.c | 3 + Processors/TFT_eSPI_RP2040.c | 3 + Processors/TFT_eSPI_STM32.c | 3 + TFT_Drivers/ST7781_Defines.h | 104 ++++++++ TFT_Drivers/ST7781_Init.h | 46 ++++ TFT_Drivers/ST7781_Rotation.h | 51 ++++ TFT_eSPI.cpp | 66 ++++- User_Setup_Select.h | 4 + User_Setups/Setup37_ST7781.h | 37 +++ .../TFT_Resistive_Touch_MCU_ST7781.ino | 229 ++++++++++++++++++ 12 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 TFT_Drivers/ST7781_Defines.h create mode 100644 TFT_Drivers/ST7781_Init.h create mode 100644 TFT_Drivers/ST7781_Rotation.h create mode 100644 User_Setups/Setup37_ST7781.h create mode 100644 examples/320 x 240/TFT_Resistive_Touch_MCU_ST7781/TFT_Resistive_Touch_MCU_ST7781.ino diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 62150cc..0bcaa3b 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -235,6 +235,11 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ *_spi_cmd = SPI_USR; } while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? + +#if defined(NO_MIPI_DCS_REV1) + setWindow(0, 0, _width - 1, _height - 1); +#endif + } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_ESP8266.c b/Processors/TFT_eSPI_ESP8266.c index 83939f9..545befc 100644 --- a/Processors/TFT_eSPI_ESP8266.c +++ b/Processors/TFT_eSPI_ESP8266.c @@ -322,6 +322,10 @@ return; while(SPI1CMD & SPIBUSY) {} } +#if defined(NO_MIPI_DCS_REV1) + setWindow(0, 0, _width - 1, _height - 1); +#endif + } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_Generic.c b/Processors/TFT_eSPI_Generic.c index 82c6027..f6c8b21 100644 --- a/Processors/TFT_eSPI_Generic.c +++ b/Processors/TFT_eSPI_Generic.c @@ -68,6 +68,9 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ while (len>1) {tft_Write_32D(color); len-=2;} if (len) {tft_Write_16(color);} +#if defined(NO_MIPI_DCS_REV1) + setWindow(0, 0, _width - 1, _height - 1); +#endif } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_RP2040.c b/Processors/TFT_eSPI_RP2040.c index fbcbfe2..1614ee1 100644 --- a/Processors/TFT_eSPI_RP2040.c +++ b/Processors/TFT_eSPI_RP2040.c @@ -233,6 +233,9 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)color; } +#if defined(NO_MIPI_DCS_REV1) + setWindow(0, 0, _width - 1, _height - 1); +#endif } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index 1584d4b..7c365a7 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -382,6 +382,9 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) } while ( len>=BUF_SIZE ) ; // Send remaining pixels if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/ +#if defined(NO_MIPI_DCS_REV1) + setWindow(0, 0, _width - 1, _height - 1); +#endif } diff --git a/TFT_Drivers/ST7781_Defines.h b/TFT_Drivers/ST7781_Defines.h new file mode 100644 index 0000000..b1332ed --- /dev/null +++ b/TFT_Drivers/ST7781_Defines.h @@ -0,0 +1,104 @@ +// Change the width and height if required (defined in portrait mode) +// or use the constructor to over-ride defaults +// Based ON: ILI9225_Defines.h for ST7781 / SPFD5408 (MCUFRIEND UNO/Mega Display Shield) +// https://www.crystalfontz.com/controllers/Sitronix/ST7781/ +// https://www.rhydolabz.com/documents/SPFD5408A.pdf + + +#define WRITE_COMMAND_16 // Change TFT_eSPI::writecommand(); to use tft_Write_16(c); +#define NO_MIPI_DCS_REV1 // Add setWindow(0, 0, _width - 1, _height - 1); after TFT_eSPI::pushBlock() + +#define TFT_WIDTH 240 +#define TFT_HEIGHT 320 + +// Generic commands used by TFT_eSPI.cpp +#define TFT_NOP 0x00 +#define TFT_SWRST 0x00 // NO Software Reset ? + +#define TFT_CASET 0 +#define TFT_PASET 0 + +#define TFT_CASET1 ST7781_HORIZONTAL_WINDOW_ADDR1 +#define TFT_CASET2 ST7781_HORIZONTAL_WINDOW_ADDR2 + +#define TFT_PASET1 ST7781_VERTICAL_WINDOW_ADDR1 +#define TFT_PASET2 ST7781_VERTICAL_WINDOW_ADDR2 + +#define TFT_RAM_ADDR1 ST7781_RAM_ADDR_SET1 +#define TFT_RAM_ADDR2 ST7781_RAM_ADDR_SET2 + +#define TFT_RAMWR ST7781_RAM_DATA_REG + +#define TFT_MAD_BGR 0x10 +#define TFT_MAD_RGB 0x00 + +#ifdef TFT_RGB_ORDER + #if (TFT_RGB_ORDER == 1) + #define TFT_MAD_COLOR_ORDER TFT_MAD_RGB + #else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR + #endif +#else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR +#endif + +// Not used +#define TFT_INVOFF 0x00 +#define TFT_INVON 0x00 +#define TFT_RAMRD 0x00 +#define TFT_IDXRD 0x00 + +/* ST7781 Registers */ +#define ST7781_DRIVER_OUTPUT_CTRL 0x01 // Driver Output Control +#define ST7781_LCD_AC_DRIVING_CTRL 0x02 // LCD AC Driving Control +#define ST7781_ENTRY_MODE 0x03 // Entry Mode +#define ST7781_RESIZE_CTRL 0x04 // Resize Control +#define ST7781_DISP_CTRL1 0x07 // Display Control 1 +#define ST7781_DISP_CTRL2 0x08 // Display Control 2 +#define ST7781_DISP_CTRL3 0x09 // Display Control 3 +#define ST7781_DISP_CTRL4 0x0A // Display Control 4 +#define ST7781_FRAME_MAKER_POS 0x0D // Frame Maker Position +#define ST7781_POWER_CTRL1 0x10 // Power Control 1 +#define ST7781_POWER_CTRL2 0x11 // Power Control 2 +#define ST7781_POWER_CTRL3 0x12 // Power Control 3 +#define ST7781_POWER_CTRL4 0x13 // Power Control 4 +#define ST7781_RAM_ADDR_SET1 0x20 // Horizontal GRAM Address Set +#define ST7781_RAM_ADDR_SET2 0x21 // Vertical GRAM Address Set +#define ST7781_RAM_DATA_REG 0x22 // Read/Write to RAM Data Register +#define ST7781_VCOMH_CTRL 0x29 // VCOMH Control +#define ST7781_FRAME_COLOR_CTRL 0x2B // Frame Rate and Color Control +#define ST7781_GAMMA_CTRL1 0x30 // Gamma Control 1 +#define ST7781_GAMMA_CTRL2 0x31 // Gamma Control 2 +#define ST7781_GAMMA_CTRL3 0x32 // Gamma Control 3 +#define ST7781_GAMMA_CTRL4 0x35 // Gamma Control 4 +#define ST7781_GAMMA_CTRL5 0x36 // Gamma Control 5 +#define ST7781_GAMMA_CTRL6 0x37 // Gamma Control 6 +#define ST7781_GAMMA_CTRL7 0x38 // Gamma Control 7 +#define ST7781_GAMMA_CTRL8 0x39 // Gamma Control 8 +#define ST7781_GAMMA_CTRL9 0x3C // Gamma Control 9 +#define ST7781_GAMMA_CTRL10 0x3D // Gamma Control 10 +#define ST7781_HORIZONTAL_WINDOW_ADDR1 0x50 // Horizontal Address Start Position +#define ST7781_HORIZONTAL_WINDOW_ADDR2 0x51 // Horizontal Address End Position +#define ST7781_VERTICAL_WINDOW_ADDR1 0x52 // Vertical Address Start Position +#define ST7781_VERTICAL_WINDOW_ADDR2 0x53 // Vertical Address End Position +#define ST7781_GATE_SCAN_CTRL1 0x60 // Gate Scan Control 1 +#define ST7781_GATE_SCAN_CTRL2 0x61 // Gate Scan Control 2 +#define ST7781_PARTIAL_POS_IMG1 0x80 // Partial Image 1 Display Position +#define ST7781_PARTIAL_START_ADDR_IMG1 0x81 // Partial Image 1 Start Address +#define ST7781_PARTIAL_END_ADDR_IMG1 0x82 // Partial Image 1 End Address +#define ST7781_PARTIAL_POS_IMG2 0x83 // Partial Image 2 Display Position +#define ST7781_PARTIAL_START_ADDR_IMG2 0x84 // Partial Image 2 Start Address +#define ST7781_PARTIAL_END_ADDR_IMG2 0x85 // Partial Image 2 End Address +#define ST7781_PANEL_IFACE_CTRL1 0x90 // Panel Interface Control 1 +#define ST7781_PANEL_IFACE_CTRL2 0x92 // Panel Interface Control 2 +#define ST7781_EEPROM_ID_CODE 0xD2 // EEPROM ID Code +#define ST7781_EEPROM_CTRL_STATUS 0xD9 // EEPROM Control Status +#define ST7781_EEPROM_WRITE_COMMAND 0xDF // EEPROM Wite Command +#define ST7781_EEPROM_ENABLE 0xFA // EEPROM Enable +#define ST7781_EEPROM_VCOM_OFFSET 0xFE // EEPROM VCOM Offset +#define ST7781_FA_FE_ENABLE 0xFF // FAh/FEh Enable + + +// Delay between some initialisation commands +//#define TFT_INIT_DELAY 0x00 // Not used unless commandlist invoked +#define TFT_INIT_DELAY 0x00 diff --git a/TFT_Drivers/ST7781_Init.h b/TFT_Drivers/ST7781_Init.h new file mode 100644 index 0000000..9d22583 --- /dev/null +++ b/TFT_Drivers/ST7781_Init.h @@ -0,0 +1,46 @@ + // + // This is the command sequence that initialises the ST7781 / SPFD5408 driver + // References: + // - https://github.com/compihu/SWIFT-Shield + // - https://github.com/prenticedavid/MCUFRIEND_kbv + // SUPPORT_7781 / ST7781_regValues_CPT24 + // + // This want full 16 bit command, so writecommand() is changed with define WRITE_COMMAND_16 +{ + writecommand(ST7781_DRIVER_OUTPUT_CTRL); writedata(0x01);writedata(0x00); // Driver Output Control Register (R01h) + writecommand(ST7781_LCD_AC_DRIVING_CTRL); writedata(0x07);writedata(0x00); // LCD Driving Waveform Control (R02h) + writecommand(ST7781_ENTRY_MODE); writedata(0x10);writedata(0x30); // Entry Mode (R03h) + writecommand(ST7781_DISP_CTRL2); writedata(0x03);writedata(0x02); // Porch + writecommand(ST7781_DISP_CTRL3); writedata(0x00);writedata(0x00); // Scan + writecommand(ST7781_DISP_CTRL4); writedata(0x00);writedata(0x08); // Fmark Off + writecommand(ST7781_POWER_CTRL1); writedata(0x00);writedata(0x08); // Power Control 1 (R10h) + writecommand(ST7781_POWER_CTRL2); writedata(0x00);writedata(0x05); // Power Control 2 (R11h) + writecommand(ST7781_POWER_CTRL3); writedata(0x00);writedata(0x00); // Power Control 3 (R12h) + writecommand(ST7781_POWER_CTRL4); writedata(0x00);writedata(0x00); // Power Control 4 (R13h) + delay(100); + writecommand(ST7781_POWER_CTRL1); writedata(0x12);writedata(0xB0); // Power Control 1 SAP=1, BT=2, APE=1, AP=3 + delay(50); + writecommand(ST7781_POWER_CTRL2); writedata(0x00);writedata(0x07); // Power Control 2 VC=7 + delay(50); + writecommand(ST7781_POWER_CTRL3); writedata(0x00);writedata(0x8C); // Power Control 3 VCIRE=1, VRH=12 + writecommand(ST7781_POWER_CTRL4); writedata(0x17);writedata(0x00); // Power Control 4 VDV=23 + writecommand(ST7781_VCOMH_CTRL); writedata(0x00);writedata(0x20); // NVM read data 2 VCM=32 + delay(50); + writecommand(ST7781_GAMMA_CTRL1); writedata(0x00);writedata(0x00); // Gamma Control 1 App Note CPT 2.4 + writecommand(ST7781_GAMMA_CTRL2); writedata(0x01);writedata(0x06); // Gamma Control 2 + writecommand(ST7781_GAMMA_CTRL3); writedata(0x01);writedata(0x01); // Gamma Control 3 + writecommand(ST7781_GAMMA_CTRL4); writedata(0x01);writedata(0x06); // Gamma Control 4 + writecommand(ST7781_GAMMA_CTRL5); writedata(0x02);writedata(0x03); // Gamma Control 5 + writecommand(ST7781_GAMMA_CTRL6); writedata(0x00);writedata(0x00); // Gamma Control 6 + writecommand(ST7781_GAMMA_CTRL7); writedata(0x07);writedata(0x07); // Gamma Control 7 + writecommand(ST7781_GAMMA_CTRL8); writedata(0x02);writedata(0x04); // Gamma Control 8 + writecommand(ST7781_GAMMA_CTRL9); writedata(0x01);writedata(0x06); // Gamma Control 9 + writecommand(ST7781_GAMMA_CTRL10); writedata(0x01);writedata(0x03); // Gamma Control 10 + writecommand(ST7781_GATE_SCAN_CTRL1); writedata(0xA7);writedata(0x00); // Driver Output Control (R60h) .kbv was 0xa700 + writecommand(ST7781_GATE_SCAN_CTRL2); writedata(0x00);writedata(0x01); // Driver Output Control (R61h) + writecommand(ST7781_PANEL_IFACE_CTRL1); writedata(0x00);writedata(0x30); // Panel Interface Control 1 (R90h) + // Display On + writecommand(ST7781_DISP_CTRL1); writedata(0x01);writedata(0x33); // Display Control (R07h) + delay(50); + +} \ No newline at end of file diff --git a/TFT_Drivers/ST7781_Rotation.h b/TFT_Drivers/ST7781_Rotation.h new file mode 100644 index 0000000..7c352ec --- /dev/null +++ b/TFT_Drivers/ST7781_Rotation.h @@ -0,0 +1,51 @@ + +// This is the command sequence that rotates the ST7781 driver coordinate frame +// Based on ILI9225_Rotation.h and MCUFRIEND_kbv = MCUFRIEND_kbv::setRotation() + + rotation = m % 4; // Limit the range of values to 0-3 + + switch (rotation) { + case 0: + writecommand(ST7781_GATE_SCAN_CTRL1); + writedata(0xA7);writedata(0x00); + writecommand(ST7781_DRIVER_OUTPUT_CTRL); + writedata(0x01);writedata(0x00); + writecommand(ST7781_ENTRY_MODE); + writedata(TFT_MAD_COLOR_ORDER);writedata(0x30); + _width = _init_width; + _height = _init_height; + break; + case 1: + writecommand(ST7781_GATE_SCAN_CTRL1); + writedata(0xA7);writedata(0x00); + writecommand(ST7781_DRIVER_OUTPUT_CTRL); + writedata(0x00);writedata(0x00); + writecommand(ST7781_ENTRY_MODE); + writedata(TFT_MAD_COLOR_ORDER);writedata(0x38); + _width = _init_height; + _height = _init_width; + break; + case 2: + writecommand(ST7781_GATE_SCAN_CTRL1); + writedata(0x27);writedata(0x00); + writecommand(ST7781_DRIVER_OUTPUT_CTRL); + writedata(0x00);writedata(0x00); + writecommand(ST7781_ENTRY_MODE); + writedata(TFT_MAD_COLOR_ORDER);writedata(0x30); + _width = _init_width; + _height = _init_height; + break; + case 3: + writecommand(ST7781_GATE_SCAN_CTRL1); + writedata(0x27);writedata(0x00); + writecommand(ST7781_DRIVER_OUTPUT_CTRL); + writedata(0x01);writedata(0x00); + writecommand(ST7781_ENTRY_MODE); + writedata(TFT_MAD_COLOR_ORDER);writedata(0x38); + _width = _init_height; + _height = _init_width; + break; + } + + // Finish Window + setWindow(0, 0, _width - 1, _height - 1); diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 0f9e784..24fc600 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -656,6 +656,9 @@ void TFT_eSPI::init(uint8_t tc) #elif defined (ILI9225_DRIVER) #include "TFT_Drivers/ILI9225_Init.h" +#elif defined (ST7781_DRIVER) + #include "TFT_Drivers/ST7781_Init.h" + #endif #ifdef TFT_INVERSION_ON @@ -744,6 +747,9 @@ void TFT_eSPI::setRotation(uint8_t m) #elif defined (ILI9225_DRIVER) #include "TFT_Drivers/ILI9225_Rotation.h" +#elif defined (ST7781_DRIVER) + #include "TFT_Drivers/ST7781_Rotation.h" + #endif delayMicroseconds(10); @@ -814,7 +820,11 @@ void TFT_eSPI::writecommand(uint8_t c) DC_C; - tft_Write_8(c); +#if defined(WRITE_COMMAND_16) + tft_Write_16(c); +#else + tft_Write_8(c); +#endif DC_D; @@ -3060,6 +3070,32 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) // write to RAM DC_C; tft_Write_8(TFT_RAMWR); DC_D; + +#elif defined (ST7781_DRIVER) // Like ILI9225_DRIVER, but 16 bits + if (rotation & 0x01) { swap_coord(x0, y0); swap_coord(x1, y1); } + + addr_row = 0xFFFF; + addr_col = 0xFFFF; + + DC_C; tft_Write_16(TFT_CASET1); + DC_D; tft_Write_16(x0); + DC_C; tft_Write_16(TFT_CASET2); + DC_D; tft_Write_16(x1); + + DC_C; tft_Write_16(TFT_PASET1); + DC_D; tft_Write_16(y0); + DC_C; tft_Write_16(TFT_PASET2); + DC_D; tft_Write_16(y1); + + DC_C; tft_Write_16(TFT_RAM_ADDR1); + DC_D; tft_Write_16(x0); + DC_C; tft_Write_16(TFT_RAM_ADDR2); + DC_D; tft_Write_16(y0); + + // write to RAM + DC_C; tft_Write_16(TFT_RAMWR); + DC_D; + #elif defined (SSD1351_DRIVER) if (rotation & 1) { swap_coord(x0, y0); @@ -3260,6 +3296,34 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_C; tft_Write_8(TFT_RAMWR); DC_D; tft_Write_16(color); +#elif defined (ST7781_DRIVER) // Like ILI9225_DRIVER, but commands 16 Bits + + if (rotation & 0x01) { swap_coord(x, y); } + + // Set window to full screen to optimise sequential pixel rendering + if (addr_row != TFT_DRIVER) { + addr_row = TFT_DRIVER; // addr_row used for flag + DC_C; tft_Write_16(TFT_CASET1); + DC_D; tft_Write_16(0); + DC_C; tft_Write_16(TFT_CASET2); + DC_D; tft_Write_16(TFT_WIDTH - 1); + + DC_C; tft_Write_16(TFT_PASET1); + DC_D; tft_Write_16(0); + DC_C; tft_Write_16(TFT_PASET2); + DC_D; tft_Write_16(TFT_HEIGHT - 1); + } + + // Define pixel coordinate + DC_C; tft_Write_16(TFT_RAM_ADDR1); + DC_D; tft_Write_16(x); + DC_C; tft_Write_16(TFT_RAM_ADDR2); + DC_D; tft_Write_16(y); + + // write to RAM + DC_C; tft_Write_16(TFT_RAMWR); + DC_D; tft_Write_16(color); + // Temporary solution is to include the RP2040 optimised code here #elif defined (ARDUINO_ARCH_RP2040) diff --git a/User_Setup_Select.h b/User_Setup_Select.h index 08a58da..71f2528 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -67,6 +67,7 @@ //#include // Setup for STM32 port A parallel display //#include // Setup file configured for ESP32 and RPi ST7796 TFT with touch +//#include // Setup for ST7781 parallel display //#include // Setup file configured for my ST7735S 80x160 //#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 @@ -198,6 +199,9 @@ #elif defined (ILI9225_DRIVER) #include "TFT_Drivers/ILI9225_Defines.h" #define TFT_DRIVER 0x9225 +#elif defined (ST7781_DRIVER) + #include "TFT_Drivers/ST7781_Defines.h" + #define TFT_DRIVER 0x7781 // <<<<<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVER HERE // XYZZY_init.h and XYZZY_rotation.h must also be added in TFT_eSPI.cpp #elif defined (XYZZY_DRIVER) diff --git a/User_Setups/Setup37_ST7781.h b/User_Setups/Setup37_ST7781.h new file mode 100644 index 0000000..39f809e --- /dev/null +++ b/User_Setups/Setup37_ST7781.h @@ -0,0 +1,37 @@ +// Setup for ESP32 and ST7781/SPFD5408 240 x 320 TFT + +// See SetupX_Template.h for all options available +#define ST7781_DRIVER +#define TFT_PARALLEL_8_BIT // MCUFRIEND Shields is Parallel + +// ESP32 pins used for the parallel interface TFT +#define TFT_CS 27 // Chip select control pin +#define TFT_DC 14 // Data Command control pin - must use a pin in the range 0-31 +#define TFT_RST 26 // Reset pin + +#define TFT_WR 12 // Write strobe control pin - must use a pin in the range 0-31 +#define TFT_RD 13 + +#define TFT_D0 16 // Must use pins in the range 0-31 for the data bus +#define TFT_D1 4 // so a single register write sets/clears all bits +#define TFT_D2 23 +#define TFT_D3 22 +#define TFT_D4 21 +#define TFT_D5 19 +#define TFT_D6 18 +#define TFT_D7 17 + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +#define SMOOTH_FONT + + +//#define SPI_FREQUENCY 20000000 +#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3 diff --git a/examples/320 x 240/TFT_Resistive_Touch_MCU_ST7781/TFT_Resistive_Touch_MCU_ST7781.ino b/examples/320 x 240/TFT_Resistive_Touch_MCU_ST7781/TFT_Resistive_Touch_MCU_ST7781.ino new file mode 100644 index 0000000..fe5a409 --- /dev/null +++ b/examples/320 x 240/TFT_Resistive_Touch_MCU_ST7781/TFT_Resistive_Touch_MCU_ST7781.ino @@ -0,0 +1,229 @@ +/* + Common Paint Example + Is adapted to work with Resistive touch from TFT 2.4" MCUFRIEND Shield + with chipset ST7781 / SPFD5408. This uses shared pins to touch analogic + values. + Tested with ESP32-Dev Board. + + Need connect pin SD_SCK and set in PIN_SD_SCK + Need download Adafruit Resistive Touch Library: Adafruit_TouchScreen + On different boards maybe need adjust isValidPressure() + + Make sure all the display driver and pin connections are correct by + editing the User_Setup.h file in the TFT_eSPI library folder. + + ######################################################################### + ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ###### + ######################################################################### + */ + + +#include // Hardware-specific library +#include +#include // Adafruit_TouchScreen + +// If User_Setup.h is OK, just need setup this option. +// On Display, Touch Screen shares PIN with SD Card +// Just select one free pin, this example use GPIO 32 on ESP32 +#define PIN_SD_SCK 32 + + +#define YP TFT_WR // On Uno is pin A1, just use User_Setup.h +#define XM TFT_DC // On Uno is pin A2, just use User_Setup.h +#define YM TFT_D7 // On Uno is pin D7, just use User_Setup.h +#define XP TFT_D6 // On Uno is pin D6, just use User_Setup.h + +// For better pressure precision, we need to know the resistance +// between X+ and X- Use any multimeter to read it +// For the one we're using, its 300 ohms across the X plate +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); +TSPoint p; + +TFT_eSPI tft = TFT_eSPI(); + +#define BOXSIZE 40 +#define PENRADIUS 3 +int oldcolor, currentcolor; +int calibration = 0; + +int16_t calibMinX = 0; +int16_t calibMinY = 0; +int16_t calibMaxX = 0; +int16_t calibMaxY = 0; +int16_t userX = 0; +int16_t userY = 0; + +void setup(void) { + Serial.begin(115200); + Serial.println(F("Paint Time!")); + // + uint16_t identifier = tft.readcommand16(0x00, 2); // 16 Bits + Serial.print(F("LCD driver chip: ")); + Serial.println(identifier, HEX); + // + Serial.print("Screen Width: "); Serial.println(tft.width()); + Serial.print("Screen Height: "); Serial.println(tft.height()); + // + pinMode(PIN_SD_SCK, OUTPUT); + + tft.begin(); + tft.fillScreen(TFT_BLACK); +} + +void loop() { + if (calibration < 30) { + doCalibration(); + return; + } + // + if (isValidPressure()) { +// Serial.print("X = "); Serial.print(p.x); +// Serial.print("\tY = "); Serial.print(p.y); +// Serial.print("\tPressure = "); Serial.println(p.z); + + // Calculate correct user touch + userX = map(p.x, calibMinX, calibMaxX, 0, tft.width()); + userY = map(p.y, calibMinY, calibMaxY, 0, tft.height()); + // Fix limits + if (userX < 0) userX = 0; + if (userY < 0) userY = 0; + if (userX > tft.width()) userX = tft.width(); + if (userY > tft.height()) userY = tft.height(); +// Serial.print("User X: "); Serial.print(userX); +// Serial.print("\tUser Y: "); Serial.println(userY); + + if (userY > (tft.height()-5)) { + // Serial.println("Erase"); + // press the bottom of the screen to erase + tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, TFT_BLACK); + } + + // Select colors + if (userY < BOXSIZE) { + oldcolor = currentcolor; + + if (userX < BOXSIZE) { + currentcolor = TFT_RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } else if (userX < BOXSIZE*2) { + currentcolor = TFT_YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } else if (userX < BOXSIZE*3) { + currentcolor = TFT_GREEN; + tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } else if (userX < BOXSIZE*4) { + currentcolor = TFT_CYAN; + tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } else if (userX < BOXSIZE*5) { + currentcolor = TFT_BLUE; + tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } else if (userX < BOXSIZE*6) { + currentcolor = TFT_MAGENTA; + tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + } + if (oldcolor != currentcolor) { + if (oldcolor == TFT_RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, TFT_RED); + if (oldcolor == TFT_YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, TFT_YELLOW); + if (oldcolor == TFT_GREEN) tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, TFT_GREEN); + if (oldcolor == TFT_CYAN) tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, TFT_CYAN); + if (oldcolor == TFT_BLUE) tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, TFT_BLUE); + if (oldcolor == TFT_MAGENTA) tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, TFT_MAGENTA); + } + } + if (((userY-PENRADIUS) > BOXSIZE) && ((userY+PENRADIUS) < tft.height())) { + tft.fillCircle(userX, userY, PENRADIUS, currentcolor); + } + } +} + +void drawnPalette() { + + tft.fillRect(0 , 0, BOXSIZE, BOXSIZE, TFT_RED); + tft.fillRect(BOXSIZE , 0, BOXSIZE, BOXSIZE, TFT_YELLOW); + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, TFT_GREEN); + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, TFT_CYAN); + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, TFT_BLUE); + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, TFT_MAGENTA); + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, TFT_WHITE); + currentcolor = TFT_RED; +} + +void readTouchPoint() { + // Switch SD CLK to read touch data + digitalWrite(PIN_SD_SCK, HIGH); + p = ts.getPoint(); // read to global + digitalWrite(PIN_SD_SCK, LOW); + + // if sharing pins, you'll need to fix the directions of the touchscreen pins + //pinMode(XP, OUTPUT); + pinMode(XM, OUTPUT); + pinMode(YP, OUTPUT); + //pinMode(YM, OUTPUT); +} + +bool isValidPressure() +{ + readTouchPoint(); + // I using ESP 32, and reading on Z is 0 (zero) no touch (normally), + // and Adafruit library return negative values or positive.. + //if (p.z > 10 && p.z < 1000) { // Original + if (p.z > 1 || p.z < -1) { + return true; + } + return false; +} + +// Simple calibration steps +void doCalibration() { + + if (calibration == 0) { + // Draw 0,0 circle + tft.fillCircle(10, 10, 10, TFT_WHITE); + tft.setCursor(5, 30); + tft.setTextColor(TFT_WHITE); + tft.println("1: TOUCH ON CIRCLE TO CALIBRATE"); + calibration = 1; + return; + } + if (calibration == 1) { + if (isValidPressure()) { + calibMinX = p.x; + calibMinY = p.y; + //Serial.print("Z:"); Serial.print(p.z); + Serial.print("[minX:"); + Serial.print(calibMinX); + Serial.print("][minY:"); + Serial.print(calibMinY); + Serial.println("]"); + calibration = 2; + tft.fillScreen(TFT_BLACK); + } + return; + } + if (calibration == 2) { + // Draw 0,0 circle + tft.fillCircle(tft.width() - 10, tft.height() - 10, 10, TFT_WHITE); + tft.setCursor(5, 30); + tft.setTextColor(TFT_WHITE); + tft.println("2: TOUCH ON CIRCLE TO CALIBRATE"); + calibration = 3; + delay(3000);// Wait to not get multiple touch on last location, users will press a lot the second point ;P + return; + } + if (calibration == 3) { + if (isValidPressure()) { + calibMaxX = p.x; + calibMaxY = p.y; + Serial.print("[maxX:"); + Serial.print(calibMaxX); + Serial.print("][maxY:"); + Serial.print(calibMaxY); + Serial.println("]"); + Serial.println("Calibration Ended."); + calibration = 33; // end + tft.fillScreen(TFT_BLACK); + drawnPalette(); + } + return; + } +} From cad65ff53569aee42b8c762ee08eb5c9a073d3bb Mon Sep 17 00:00:00 2001 From: Haroldo M Murata Date: Sat, 15 May 2021 14:54:08 -0300 Subject: [PATCH 2/5] ST7781_driver Remove setWindows() --- Processors/TFT_eSPI_ESP32.c | 5 ----- Processors/TFT_eSPI_ESP8266.c | 4 ---- Processors/TFT_eSPI_Generic.c | 3 --- Processors/TFT_eSPI_RP2040.c | 3 --- Processors/TFT_eSPI_STM32.c | 3 --- TFT_Drivers/ST7781_Defines.h | 1 - TFT_Drivers/ST7781_Rotation.h | 3 --- 7 files changed, 22 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 0bcaa3b..62150cc 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -235,11 +235,6 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ *_spi_cmd = SPI_USR; } while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? - -#if defined(NO_MIPI_DCS_REV1) - setWindow(0, 0, _width - 1, _height - 1); -#endif - } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_ESP8266.c b/Processors/TFT_eSPI_ESP8266.c index 545befc..83939f9 100644 --- a/Processors/TFT_eSPI_ESP8266.c +++ b/Processors/TFT_eSPI_ESP8266.c @@ -322,10 +322,6 @@ return; while(SPI1CMD & SPIBUSY) {} } -#if defined(NO_MIPI_DCS_REV1) - setWindow(0, 0, _width - 1, _height - 1); -#endif - } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_Generic.c b/Processors/TFT_eSPI_Generic.c index f6c8b21..82c6027 100644 --- a/Processors/TFT_eSPI_Generic.c +++ b/Processors/TFT_eSPI_Generic.c @@ -68,9 +68,6 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ while (len>1) {tft_Write_32D(color); len-=2;} if (len) {tft_Write_16(color);} -#if defined(NO_MIPI_DCS_REV1) - setWindow(0, 0, _width - 1, _height - 1); -#endif } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_RP2040.c b/Processors/TFT_eSPI_RP2040.c index 1614ee1..fbcbfe2 100644 --- a/Processors/TFT_eSPI_RP2040.c +++ b/Processors/TFT_eSPI_RP2040.c @@ -233,9 +233,6 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)color; } -#if defined(NO_MIPI_DCS_REV1) - setWindow(0, 0, _width - 1, _height - 1); -#endif } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index 7c365a7..1584d4b 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -382,9 +382,6 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) } while ( len>=BUF_SIZE ) ; // Send remaining pixels if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/ -#if defined(NO_MIPI_DCS_REV1) - setWindow(0, 0, _width - 1, _height - 1); -#endif } diff --git a/TFT_Drivers/ST7781_Defines.h b/TFT_Drivers/ST7781_Defines.h index b1332ed..1d32193 100644 --- a/TFT_Drivers/ST7781_Defines.h +++ b/TFT_Drivers/ST7781_Defines.h @@ -6,7 +6,6 @@ #define WRITE_COMMAND_16 // Change TFT_eSPI::writecommand(); to use tft_Write_16(c); -#define NO_MIPI_DCS_REV1 // Add setWindow(0, 0, _width - 1, _height - 1); after TFT_eSPI::pushBlock() #define TFT_WIDTH 240 #define TFT_HEIGHT 320 diff --git a/TFT_Drivers/ST7781_Rotation.h b/TFT_Drivers/ST7781_Rotation.h index 7c352ec..753fee9 100644 --- a/TFT_Drivers/ST7781_Rotation.h +++ b/TFT_Drivers/ST7781_Rotation.h @@ -46,6 +46,3 @@ _height = _init_width; break; } - - // Finish Window - setWindow(0, 0, _width - 1, _height - 1); From 029069db9eb897b4e0fb08487b5fd161dd9bdcfd Mon Sep 17 00:00:00 2001 From: Haroldo M Murata Date: Sat, 15 May 2021 14:55:38 -0300 Subject: [PATCH 3/5] ST7781_driver Fix setAddrWindow(), readPixel(), readRect(). --- TFT_eSPI.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 24fc600..9b09a9c 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -953,6 +953,10 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) // Dummy read to throw away don't care value readByte(); #endif +// Some drives need throw 16 bits +#if defined (ST7781_DRIVER) + readByte(); +#endif // Fetch the 16 bit BRG pixel //uint16_t rgb = (readByte() << 8) | readByte(); @@ -979,7 +983,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) // Set masked pins D0- D7 to output busDir(dir_mask, OUTPUT); - #ifdef ILI9486_DRIVER + #if defined(ILI9486_DRIVER) | defined(ST7781_DRIVER) return bgr; #else // Swap Red and Blue (could check MADCTL setting to see if this is needed) @@ -1113,13 +1117,17 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da #else // ILI9481 reads as 16 bits // Dummy read to throw away don't care value readByte(); + // Some drives need throw 16 bits + #if defined (ST7781_DRIVER) + readByte(); + #endif // Fetch the 16 bit BRG pixels while (dh--) { int32_t lw = dw; uint16_t* line = data; while (lw--) { - #ifdef ILI9486_DRIVER + #if defined (ILI9486_DRIVER) | defined (ST7781_DRIVER) // Read the RGB 16 bit colour *line++ = readByte() | (readByte() << 8); #else @@ -3228,6 +3236,32 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) while (spi_is_readable(spi0)) (void)spi_get_hw(spi0)->dr; spi_get_hw(spi0)->icr = SPI_SSPICR_RORIC_BITS; +#elif defined (ST7781_DRIVER) + // Is Like setWindow() + if (rotation & 0x01) { swap_coord(xs, ys); swap_coord(xe, ye); } + + // Horizontal Range + DC_C; tft_Write_16(TFT_CASET1); + DC_D; tft_Write_16(xs); + DC_C; tft_Write_16(TFT_CASET2); + DC_D; tft_Write_16(xe); + + // Vertical Range + DC_C; tft_Write_16(TFT_PASET1); + DC_D; tft_Write_16(ys); + DC_C; tft_Write_16(TFT_PASET2); + DC_D; tft_Write_16(ye); + + // Start Address Pointer + DC_C; tft_Write_16(TFT_RAM_ADDR1); + DC_D; tft_Write_16(xs); + DC_C; tft_Write_16(TFT_RAM_ADDR2); + DC_D; tft_Write_16(ys); + + // write to RAM + DC_C; tft_Write_16(TFT_RAMWR); + DC_D; + #else // Column addr set DC_C; tft_Write_8(TFT_CASET); From 43c6cad403e9111285f727ac6647ae0e40171bc0 Mon Sep 17 00:00:00 2001 From: Haroldo M Murata Date: Sat, 15 May 2021 15:09:30 -0300 Subject: [PATCH 4/5] ST7781_driver Fix setAddrWindow(), readPixel(), readRect(). --- TFT_eSPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index a9639b7..8100e70 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -1079,7 +1079,7 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); - #if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9488_DRIVER) // Read 3 bytes + #if defined (ILI9341_DRIVER) | defined(ILI9341_2_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes // Dummy read to throw away don't care value readByte(); From 0a8964696e7be1e7647872d8fc1b7288be0ad2a4 Mon Sep 17 00:00:00 2001 From: Haroldo M Murata Date: Sat, 15 May 2021 15:11:32 -0300 Subject: [PATCH 5/5] ST7781_driver Fix setAddrWindow(), readPixel(), readRect(). --- TFT_eSPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 8100e70..a9639b7 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -1079,7 +1079,7 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); - #if defined (ILI9341_DRIVER) | defined(ILI9341_2_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes + #if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9488_DRIVER) // Read 3 bytes // Dummy read to throw away don't care value readByte();