diff --git a/Processors/TFT_eSPI_ESP32_S3.c b/Processors/TFT_eSPI_ESP32_S3.c new file mode 100644 index 0000000..29df68e --- /dev/null +++ b/Processors/TFT_eSPI_ESP32_S3.c @@ -0,0 +1,859 @@ + //////////////////////////////////////////////////// + // TFT_eSPI driver functions for ESP32 processors // + //////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////// +// Global variables +//////////////////////////////////////////////////////////////////////////////////////// + +// Select the SPI port to use, ESP32 has 2 options +#if !defined (TFT_PARALLEL_8_BIT) + #ifdef CONFIG_IDF_TARGET_ESP32 + #ifdef USE_HSPI_PORT + SPIClass spi = SPIClass(HSPI); + #elif defined(USE_FSPI_PORT) + SPIClass spi = SPIClass(FSPI); + #else // use default VSPI port + SPIClass spi = SPIClass(VSPI); + #endif + #else + #ifdef USE_HSPI_PORT + SPIClass spi = SPIClass(HSPI); + #elif defined(USE_FSPI_PORT) + SPIClass spi = SPIClass(FSPI); + #else // use FSPI port + SPIClass& spi = SPI; + #endif + #endif +#endif + +#ifdef ESP32_DMA + // DMA SPA handle + spi_device_handle_t dmaHAL; + #ifdef CONFIG_IDF_TARGET_ESP32 + #define DMA_CHANNEL 1 + #ifdef USE_HSPI_PORT + spi_host_device_t spi_host = HSPI_HOST; + #elif defined(USE_FSPI_PORT) + spi_host_device_t spi_host = SPI_HOST; + #else // use VSPI port + spi_host_device_t spi_host = VSPI_HOST; + #endif + #else + #ifdef USE_HSPI_PORT + #define DMA_CHANNEL 2 + spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes + #else // use FSPI port + #define DMA_CHANNEL 1 + spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes + #endif + #endif +#endif + +#if !defined (TFT_PARALLEL_8_BIT) + // Volatile for register reads: + volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); + volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); + // Register writes only: + volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); + volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: beginSDA +** Description: Detach SPI from pin to permit software SPI +***************************************************************************************/ +void TFT_eSPI::begin_SDA_Read(void) +{ + pinMatrixOutDetach(TFT_MOSI, false, false); + pinMode(TFT_MOSI, INPUT); + pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false); + SET_BUS_READ_MODE; +} + +/*************************************************************************************** +** Function name: endSDA +** Description: Attach SPI pins after software SPI +***************************************************************************************/ +void TFT_eSPI::end_SDA_Read(void) +{ + pinMode(TFT_MOSI, OUTPUT); + pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false); + pinMode(TFT_MISO, INPUT); + pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false); + SET_BUS_WRITE_MODE; +} +//////////////////////////////////////////////////////////////////////////////////////// +#endif // #if defined (TFT_SDA_READ) +//////////////////////////////////////////////////////////////////////////////////////// + + +/*************************************************************************************** +** Function name: read byte - supports class functions +** Description: Read a byte from ESP32 8 bit data port +***************************************************************************************/ +// Parallel bus MUST be set to input before calling this function! +uint8_t TFT_eSPI::readByte(void) +{ + uint8_t b = 0xAA; + +#if defined (TFT_PARALLEL_8_BIT) + RD_L; + uint32_t reg; // Read all GPIO pins 0-31 + reg = gpio_input_get(); // Read three times to allow for bus access time + reg = gpio_input_get(); + reg = gpio_input_get(); // Data should be stable now + RD_H; + + // Check GPIO bits used and build value + b = (((reg>>TFT_D0)&1) << 0); + b |= (((reg>>TFT_D1)&1) << 1); + b |= (((reg>>TFT_D2)&1) << 2); + b |= (((reg>>TFT_D3)&1) << 3); + b |= (((reg>>TFT_D4)&1) << 4); + b |= (((reg>>TFT_D5)&1) << 5); + b |= (((reg>>TFT_D6)&1) << 6); + b |= (((reg>>TFT_D7)&1) << 7); +#endif + + return b; +} + +//////////////////////////////////////////////////////////////////////////////////////// +#ifdef TFT_PARALLEL_8_BIT +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: GPIO direction control - supports class functions +** Description: Set parallel bus to INPUT or OUTPUT +***************************************************************************************/ +void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) +{ + // Arduino generic native function + pinMode(TFT_D0, mode); + pinMode(TFT_D1, mode); + pinMode(TFT_D2, mode); + pinMode(TFT_D3, mode); + pinMode(TFT_D4, mode); + pinMode(TFT_D5, mode); + pinMode(TFT_D6, mode); + pinMode(TFT_D7, mode); + return; +} + +/*************************************************************************************** +** Function name: GPIO direction control - supports class functions +** Description: Set ESP32 GPIO pin to input or output (set high) ASAP +***************************************************************************************/ +void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode) +{ + pinMode(pin, mode); + digitalWrite(pin, HIGH); +} +//////////////////////////////////////////////////////////////////////////////////////// +#endif // #ifdef TFT_PARALLEL_8_BIT +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (RPI_WRITE_STROBE) && !defined (TFT_PARALLEL_8_BIT) // Code for RPi TFT +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for ESP32 or ESP8266 RPi TFT +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) +{ + uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color }; + if(len) spi.writePattern(&colorBin[0], 2, 1); len--; + while(len--) {WR_L; WR_H;} +} + +/*************************************************************************************** +** Function name: pushPixels - for ESP32 or ESP8266 RPi TFT +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) +{ + uint8_t *data = (uint8_t*)data_in; + + if(_swapBytes) { + while ( len-- ) {tft_Write_16(*data); data++;} + return; + } + + while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; } + if (len) spi.writePattern(data, len, 1); +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif !defined (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI displays +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for ESP32 +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +/* +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); + bool empty = true; + volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; + if (len > 31) + { + *_spi_mosi_dlen = 511; + spi_w[0] = color32; + spi_w[1] = color32; + spi_w[2] = color32; + spi_w[3] = color32; + spi_w[4] = color32; + spi_w[5] = color32; + spi_w[6] = color32; + spi_w[7] = color32; + spi_w[8] = color32; + spi_w[9] = color32; + spi_w[10] = color32; + spi_w[11] = color32; + spi_w[12] = color32; + spi_w[13] = color32; + spi_w[14] = color32; + spi_w[15] = color32; + while(len>31) + { + while ((*_spi_cmd)&SPI_USR); + *_spi_cmd = SPI_USR; + len -= 32; + } + empty = false; + } + + if (len) + { + if(empty) { + for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; + } + len = (len << 4) - 1; + while (*_spi_cmd&SPI_USR); + *_spi_mosi_dlen = len; + *_spi_cmd = SPI_USR; + } + while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? +} +//*/ +//* +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + volatile uint32_t* spi_w = _spi_w; + uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); + uint32_t i = 0; + uint32_t rem = len & 0x1F; + len = len - rem; + + // Start with partial buffer pixels + if (rem) + { + while (*_spi_cmd&SPI_USR); + for (i=0; i < rem; i+=2) *spi_w++ = color32; + *_spi_mosi_dlen = (rem << 4) - 1; +#if CONFIG_IDF_TARGET_ESP32S3 + *_spi_cmd = SPI_UPDATE; + while (*_spi_cmd & SPI_UPDATE); +#endif + *_spi_cmd = SPI_USR; + if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } + i = i>>1; while(i++<16) *spi_w++ = color32; + } + + while (*_spi_cmd&SPI_USR); + if (!rem) while (i++<16) *spi_w++ = color32; + *_spi_mosi_dlen = 511; + + // End with full buffer to maximise useful time for downstream code + while(len) + { + while (*_spi_cmd&SPI_USR); +#if CONFIG_IDF_TARGET_ESP32S3 + *_spi_cmd = SPI_UPDATE; + while (*_spi_cmd & SPI_UPDATE); +#endif + *_spi_cmd = SPI_USR; + len -= 32; + } + + // Do not wait here + //while (*_spi_cmd&SPI_USR); +} +//*/ +/*************************************************************************************** +** Function name: pushSwapBytePixels - for ESP32 +** Description: Write a sequence of pixels with swapped bytes +***************************************************************************************/ +void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ + + uint8_t* data = (uint8_t*)data_in; + uint32_t color[16]; + + if (len > 31) + { + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); + while(len>31) + { + uint32_t i = 0; + while(i<16) + { + color[i++] = DAT8TO32(data); + data+=4; + } + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]); + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]); + WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color[8]); + WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color[9]); + WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), color[10]); + WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), color[11]); + WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), color[12]); + WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), color[13]); + WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), color[14]); + WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), color[15]); +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + len -= 32; + } + } + + if (len > 15) + { + uint32_t i = 0; + while(i<8) + { + color[i++] = DAT8TO32(data); + data+=4; + } + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 255); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]); + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]); +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + len -= 16; + } + + if (len) + { + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1); + for (uint32_t i=0; i <= (len<<1); i+=4) { + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT)+i, DAT8TO32(data)); data+=4; + } +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + } + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + +} + +/*************************************************************************************** +** Function name: pushPixels - for ESP32 +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + if(_swapBytes) { + pushSwapBytePixels(data_in, len); + return; + } + + uint32_t *data = (uint32_t*)data_in; + + if (len > 31) + { + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); + while(len>31) + { + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), *data++); + WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), *data++); +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + len -= 32; + } + } + + if (len) + { + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1); + for (uint32_t i=0; i <= (len<<1); i+=4) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + i), *data++); +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + } + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for ESP32 and 3 byte RGB display +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) +{ + // Split out the colours + uint32_t r = (color & 0xF800)>>8; + uint32_t g = (color & 0x07E0)<<5; + uint32_t b = (color & 0x001F)<<19; + // Concatenate 4 pixels into three 32 bit blocks + uint32_t r0 = r<<24 | b | g | r; + uint32_t r1 = r0>>8 | g<<16; + uint32_t r2 = r1>>8 | b<<8; + + if (len > 19) + { + SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); + + while(len>19) + { + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2); +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + len -= 20; + } + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + } + + if (len) + { + SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (len * 24) - 1, SPI_USR_MOSI_DBITLEN_S); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2); + if (len > 8 ) + { + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2); + WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0); + WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1); + WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2); + } +#if CONFIG_IDF_TARGET_ESP32S3 + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); +#endif + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + } +} + +/*************************************************************************************** +** Function name: pushPixels - for ESP32 and 3 byte RGB display +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + // ILI9488 write macro is not endianess dependant, hence !_swapBytes + if(!_swapBytes) { while ( len-- ) {tft_Write_16S(*data); data++;} } + else { while ( len-- ) {tft_Write_16(*data); data++;} } +} + +/*************************************************************************************** +** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display +** Description: Write a sequence of pixels with swapped bytes +***************************************************************************************/ +void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + // ILI9488 write macro is not endianess dependant, so swap byte macro not used here + while ( len-- ) {tft_Write_16(*data); data++;} +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8 bit parallel +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for ESP32 and parallel display +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + if ( (color >> 8) == (color & 0x00FF) ) + { if (!len) return; + tft_Write_16(color); + #if defined (SSD1963_DRIVER) + while (--len) {WR_L; WR_H; WR_L; WR_H; WR_L; WR_H;} + #else + #ifdef PSEUDO_16_BIT + while (--len) {WR_L; WR_H;} + #else + while (--len) {WR_L; WR_H; WR_L; WR_H;} + #endif + #endif + } + else while (len--) {tft_Write_16(color);} +} + +/*************************************************************************************** +** Function name: pushSwapBytePixels - for ESP32 and parallel display +** Description: Write a sequence of pixels with swapped bytes +***************************************************************************************/ +void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + while ( len-- ) {tft_Write_16(*data); data++;} +} + +/*************************************************************************************** +** Function name: pushPixels - for ESP32 and parallel display +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + if(_swapBytes) { while ( len-- ) {tft_Write_16(*data); data++; } } + else { while ( len-- ) {tft_Write_16S(*data); data++;} } +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // End of display interface specific functions +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: dmaBusy +** Description: Check if DMA is busy +***************************************************************************************/ +bool TFT_eSPI::dmaBusy(void) +{ + if (!DMA_Enabled || !spiBusyCheck) return false; + + spi_transaction_t *rtrans; + esp_err_t ret; + uint8_t checks = spiBusyCheck; + for (int i = 0; i < checks; ++i) + { + ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0); + if (ret == ESP_OK) spiBusyCheck--; + } + + //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); + if (spiBusyCheck ==0) return false; + return true; +} + + +/*************************************************************************************** +** Function name: dmaWait +** Description: Wait until DMA is over (blocking!) +***************************************************************************************/ +void TFT_eSPI::dmaWait(void) +{ + if (!DMA_Enabled || !spiBusyCheck) return; + spi_transaction_t *rtrans; + esp_err_t ret; + for (int i = 0; i < spiBusyCheck; ++i) + { + ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); + assert(ret == ESP_OK); + } + spiBusyCheck = 0; +} + + +/*************************************************************************************** +** Function name: pushPixelsDMA +** Description: Push pixels to TFT (len must be less than 32767) +***************************************************************************************/ +// This will byte swap the original image if setSwapBytes(true) was called by sketch. +void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) +{ + if ((len == 0) || (!DMA_Enabled)) return; + + dmaWait(); + + if(_swapBytes) { + for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); + } + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = image; //finally send the line data + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + + +/*************************************************************************************** +** Function name: pushImageDMA +** Description: Push image to a window (w*h must be less than 65536) +***************************************************************************************/ +// Fixed const data assumed, will NOT clip or swap bytes +void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) +{ + if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; + + uint32_t len = w*h; + + dmaWait(); + + setAddrWindow(x, y, w, h); + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = image; //Data pointer + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + + +/*************************************************************************************** +** Function name: pushImageDMA +** Description: Push image to a window (w*h must be less than 65536) +***************************************************************************************/ +// This will clip and also swap bytes if setSwapBytes(true) was called by sketch +void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) +{ + if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; + + int32_t dx = 0; + int32_t dy = 0; + int32_t dw = w; + int32_t dh = h; + + if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } + if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } + + if ((x + dw) > _vpW ) dw = _vpW - x; + if ((y + dh) > _vpH ) dh = _vpH - y; + + if (dw < 1 || dh < 1) return; + + uint32_t len = dw*dh; + + if (buffer == nullptr) { + buffer = image; + dmaWait(); + } + + // If image is clipped, copy pixels into a contiguous block + if ( (dw != w) || (dh != h) ) { + if(_swapBytes) { + for (int32_t yb = 0; yb < dh; yb++) { + for (int32_t xb = 0; xb < dw; xb++) { + uint32_t src = xb + dx + w * (yb + dy); + (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); + } + } + } + else { + for (int32_t yb = 0; yb < dh; yb++) { + memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); + } + } + } + // else, if a buffer pointer has been provided copy whole image to the buffer + else if (buffer != image || _swapBytes) { + if(_swapBytes) { + for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); + } + else { + memcpy(buffer, image, len*2); + } + } + + if (spiBusyCheck) dmaWait(); // In case we did not wait earlier + + setAddrWindow(x, y, dw, dh); + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = buffer; //finally send the line data + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Processor specific DMA initialisation +//////////////////////////////////////////////////////////////////////////////////////// + +// The DMA functions here work with SPI only (not parallel) +/*************************************************************************************** +** Function name: dc_callback +** Description: Toggles DC line during transaction +***************************************************************************************/ +extern "C" void dc_callback(); + +void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) +{ + if ((bool)spi_tx->user) {DC_D;} + else {DC_C;} +} + +/*************************************************************************************** +** Function name: initDMA +** Description: Initialise the DMA engine - returns true if init OK +***************************************************************************************/ +bool TFT_eSPI::initDMA(bool ctrl_cs) +{ + if (DMA_Enabled) return false; + + esp_err_t ret; + spi_bus_config_t buscfg = { + .mosi_io_num = TFT_MOSI, + .miso_io_num = TFT_MISO, + .sclk_io_num = TFT_SCLK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size + .flags = 0, + .intr_flags = 0 + }; + + int8_t pin = -1; + if (ctrl_cs) pin = TFT_CS; + + spi_device_interface_config_t devcfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = TFT_SPI_MODE, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .clock_speed_hz = SPI_FREQUENCY, + .input_delay_ns = 0, + .spics_io_num = pin, + .flags = SPI_DEVICE_NO_DUMMY, //0, + .queue_size = 1, + .pre_cb = 0, //dc_callback, //Callback to handle D/C line + .post_cb = 0 + }; + ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); + ESP_ERROR_CHECK(ret); + ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); + ESP_ERROR_CHECK(ret); + + DMA_Enabled = true; + spiBusyCheck = 0; + return true; +} + +/*************************************************************************************** +** Function name: deInitDMA +** Description: Disconnect the DMA engine from SPI +***************************************************************************************/ +void TFT_eSPI::deInitDMA(void) +{ + if (!DMA_Enabled) return; + spi_bus_remove_device(dmaHAL); + spi_bus_free(spi_host); + DMA_Enabled = false; +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // End of DMA FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP32_S3.h b/Processors/TFT_eSPI_ESP32_S3.h new file mode 100644 index 0000000..392be1d --- /dev/null +++ b/Processors/TFT_eSPI_ESP32_S3.h @@ -0,0 +1,608 @@ + //////////////////////////////////////////////////// + // TFT_eSPI driver functions for ESP32 processors // + //////////////////////////////////////////////////// + +#ifndef _TFT_eSPI_ESP32H_ +#define _TFT_eSPI_ESP32H_ + +// Processor ID reported by getSetup() +#define PROCESSOR_ID 0x32 + +// Include processor specific header +#include "soc/spi_reg.h" +#include "driver/spi_master.h" + +#if !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) + #define CONFIG_IDF_TARGET_ESP32 +#endif + +#ifndef VSPI + #define VSPI FSPI +#endif + +// Fix IDF problems with ESP32S3 VSPI=FSPI_HOST=SPI2_HOST=1 HSPI_HOST=SPI3_HOST=2 +#if CONFIG_IDF_TARGET_ESP32S3 + // Fix ESP32C3 IDF bug for missing definition (VSPI/FSPI only tested at the moment) + #ifndef REG_SPI_BASE + #define REG_SPI_BASE(i) (((i)>1) ? (DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE)) + #endif + + // Fix ESP32S3 IDF bug for name change + #ifndef SPI_MOSI_DLEN_REG + #define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) + #endif + + // Fix ESP32C3 specific register reference + //#define out_w1tc out_w1tc.val + //#define out_w1ts out_w1ts.val +#endif + +// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled +#if !defined (SUPPORT_TRANSACTIONS) + #define SUPPORT_TRANSACTIONS +#endif + +/* +ESP32: +FSPI not defined +HSPI = 2, uses SPI2 +VSPI = 3, uses SPI3 + +ESP32-S2: +FSPI = 1, uses SPI2 +HSPI = 2, uses SPI3 +VSPI not defined + +ESP32 C3: +FSPI = 0, uses SPI2 ???? To be checked +HSPI = 1, uses SPI3 ???? To be checked +VSPI not defined + +For ESP32/S2/C3: +SPI1_HOST = 0 +SPI2_HOST = 1 +SPI3_HOST = 2 +*/ + +// ESP32 specific SPI port selection +#ifdef USE_HSPI_PORT + #ifdef CONFIG_IDF_TARGET_ESP32 + #define SPI_PORT HSPI //HSPI is port 2 on ESP32 + #else + #define SPI_PORT 3 //HSPI is port 3 on ESP32 S2 + #endif +#elif defined(USE_FSPI_PORT) + #define SPI_PORT 2 //FSPI(ESP32 S2) +#else + #ifdef CONFIG_IDF_TARGET_ESP32 + #define SPI_PORT VSPI + #elif CONFIG_IDF_TARGET_ESP32S2 + #define SPI_PORT 2 //FSPI(ESP32 S2) + #elif CONFIG_IDF_TARGET_ESP32S3 + #define SPI_PORT FSPI + #endif +#endif + +#ifdef RPI_DISPLAY_TYPE + #define CMD_BITS (16-1) +#else + #define CMD_BITS (8-1) +#endif + +// Initialise processor specific SPI functions, used by init() +#define INIT_TFT_DATA_BUS // Not used + +// Define a generic flag for 8 bit parallel +#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility + #if !defined (TFT_PARALLEL_8_BIT) + #define TFT_PARALLEL_8_BIT // Generic parallel flag + #endif +#endif + +// Ensure ESP32 specific flag is defined for 8 bit parallel +#if defined (TFT_PARALLEL_8_BIT) + #if !defined (ESP32_PARALLEL) + #define ESP32_PARALLEL + #endif +#endif + +// Processor specific code used by SPI bus transaction startWrite and endWrite functions +#if !defined (ESP32_PARALLEL) + #if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) + #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE + #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE + #else + #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI + #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN + #endif +#else + // Not applicable to parallel bus + #define SET_BUS_WRITE_MODE + #define SET_BUS_READ_MODE +#endif + +// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions +#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) + #define ESP32_DMA + // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions + #define DMA_BUSY_CHECK dmaWait() +#else + #define DMA_BUSY_CHECK +#endif + +#if defined(TFT_PARALLEL_8_BIT) + #define SPI_BUSY_CHECK +#else + #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) +#endif + +// If smooth font is used then it is likely SPIFFS will be needed +#ifdef SMOOTH_FONT + // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts + #define FS_NO_GLOBALS + #include + #include "SPIFFS.h" // ESP32 only + #define FONT_FS_AVAILABLE +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the DC (TFT Data/Command or Register Select (RS))pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_DC + #define DC_C // No macro allocated so it generates no code + #define DC_D // No macro allocated so it generates no code +#else + #if defined (TFT_PARALLEL_8_BIT) + // TFT_DC, by design, must be in range 0-31 for single register parallel write + #if (TFT_DC >= 0) && (TFT_DC < 32) + #define DC_C GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1ts = (1 << TFT_DC) + #else + #define DC_C + #define DC_D + #endif + #else + #if (TFT_DC >= 32) + #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change + #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ + GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) + #define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \ + GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) + #else + #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) + #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) + #endif + #elif (TFT_DC >= 0) + #if defined (RPI_DISPLAY_TYPE) + #if defined (ILI9486_DRIVER) + // RPi ILI9486 display needs a slower DC change + #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1ts = (1 << TFT_DC) + #else + // Other RPi displays need a slower C->D change + #define DC_C GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1ts = (1 << TFT_DC) + #endif + #else + #define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (1 << TFT_DC) + #endif + #else + #define DC_C + #define DC_D + #endif + #endif +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the CS (TFT chip select) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_CS + #define TFT_CS -1 // Keep DMA code happy + #define CS_L // No macro allocated so it generates no code + #define CS_H // No macro allocated so it generates no code +#else + #if defined (TFT_PARALLEL_8_BIT) + #if TFT_CS >= 32 + #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) + #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) + #elif TFT_CS >= 0 + #define CS_L GPIO.out_w1tc = (1 << TFT_CS) + #define CS_H GPIO.out_w1ts = (1 << TFT_CS) + #else + #define CS_L + #define CS_H + #endif + #else + #if (TFT_CS >= 32) + #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change + #define CS_L GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)); \ + GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) + #define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \ + GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) + #else + #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) + #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) + #endif + #elif (TFT_CS >= 0) + #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change + #define CS_L GPIO.out_w1ts = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) + #define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS) + #else + #define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) + #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) + #endif + #else + #define CS_L + #define CS_H + #endif + #endif +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the WR (TFT Write) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_WR) + #if (TFT_WR >= 32) + // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 + #define WR_L GPIO.out1_w1tc.val = (1 << (TFT_WR - 32)) + #define WR_H GPIO.out1_w1ts.val = (1 << (TFT_WR - 32)) + #elif (TFT_WR >= 0) + // TFT_WR, for best performance, should be in range 0-31 for single register parallel write + #define WR_L GPIO.out_w1tc = (1 << TFT_WR) + #define WR_H GPIO.out_w1ts = (1 << TFT_WR) + #else + #define WR_L + #define WR_H + #endif +#else + #define WR_L + #define WR_H +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the touch screen chip select pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TOUCH_CS + #define T_CS_L // No macro allocated so it generates no code + #define T_CS_H // No macro allocated so it generates no code +#else // XPT2046 is slow, so use slower digitalWrite here + #define T_CS_L digitalWrite(TOUCH_CS, LOW) + #define T_CS_H digitalWrite(TOUCH_CS, HIGH) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Make sure SPI default pins are assigned if not specified by user or set to -1 +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined (TFT_PARALLEL_8_BIT) + + #ifdef USE_HSPI_PORT + + #ifndef TFT_MISO + #define TFT_MISO -1 + #endif + + #ifndef TFT_MOSI + #define TFT_MOSI 13 + #endif + #if (TFT_MOSI == -1) + #undef TFT_MOSI + #define TFT_MOSI 13 + #endif + + #ifndef TFT_SCLK + #define TFT_SCLK 14 + #endif + #if (TFT_SCLK == -1) + #undef TFT_SCLK + #define TFT_SCLK 14 + #endif + + #else // VSPI port + + #ifndef TFT_MISO + #define TFT_MISO -1 + #endif + + #ifndef TFT_MOSI + #define TFT_MOSI 23 + #endif + #if (TFT_MOSI == -1) + #undef TFT_MOSI + #define TFT_MOSI 23 + #endif + + #ifndef TFT_SCLK + #define TFT_SCLK 18 + #endif + #if (TFT_SCLK == -1) + #undef TFT_SCLK + #define TFT_SCLK 18 + #endif + + #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) + #if (TFT_MISO == -1) + #undef TFT_MISO + #define TFT_MISO TFT_MOSI + #endif + #endif + + #endif + +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the parallel bus interface chip pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_PARALLEL_8_BIT) + + // Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically + // can then use e.g. GPIO.out_w1ts = set_mask(0xFF); to set data bus to 0xFF + #define PARALLEL_INIT_TFT_DATA_BUS \ + for (int32_t c = 0; c<256; c++) \ + { \ + xset_mask[c] = 0; \ + if ( c & 0x01 ) xset_mask[c] |= (1 << TFT_D0); \ + if ( c & 0x02 ) xset_mask[c] |= (1 << TFT_D1); \ + if ( c & 0x04 ) xset_mask[c] |= (1 << TFT_D2); \ + if ( c & 0x08 ) xset_mask[c] |= (1 << TFT_D3); \ + if ( c & 0x10 ) xset_mask[c] |= (1 << TFT_D4); \ + if ( c & 0x20 ) xset_mask[c] |= (1 << TFT_D5); \ + if ( c & 0x40 ) xset_mask[c] |= (1 << TFT_D6); \ + if ( c & 0x80 ) xset_mask[c] |= (1 << TFT_D7); \ + } \ + + // Mask for the 8 data bits to set pin directions + #define dir_mask ((1 << TFT_D0) | (1 << TFT_D1) | (1 << TFT_D2) | (1 << TFT_D3) | (1 << TFT_D4) | (1 << TFT_D5) | (1 << TFT_D6) | (1 << TFT_D7)) + + #if (TFT_WR >= 32) + // Data bits and the write line are cleared sequentially + #define clr_mask (dir_mask); WR_L + #elif (TFT_WR >= 0) + // Data bits and the write line are cleared to 0 in one step (1.25x faster) + #define clr_mask (dir_mask | (1 << TFT_WR)) + #else + #define clr_mask + #endif + + // A lookup table is used to set the different bit patterns, this uses 1kByte of RAM + #define set_mask(C) xset_mask[C] // 63fps Sprite rendering test 33% faster, graphicstest only 1.8% faster than shifting in real time + + // Real-time shifting alternative to above to save 1KByte RAM, 47 fps Sprite rendering test + /*#define set_mask(C) (((C)&0x80)>>7)<>6)<>5)<>4)<>3)<>2)<>1)<>0)<> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + + #ifdef PSEUDO_16_BIT + // One write strobe for both bytes + #define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H + #define tft_Write_16S(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H + #else + // Write 16 bits to TFT + #define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H + + // 16 bit write with swapped bytes + #define tft_Write_16S(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H + #endif + + #endif + + // Write 32 bits to TFT + #define tft_Write_32(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 16)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H + + // Write two concatenated 16 bit values to TFT + #define tft_Write_32C(C,D) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 0)); WR_H + + // Write 16 bit value twice to TFT - used by drawPixel() + #define tft_Write_32D(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H + + // Read pin + #ifdef TFT_RD + #if (TFT_RD >= 32) + #define RD_L GPIO.out1_w1tc.val = (1 << (TFT_RD - 32)) + #define RD_H GPIO.out1_w1ts.val = (1 << (TFT_RD - 32)) + #elif (TFT_RD >= 0) + #define RD_L GPIO.out_w1tc = (1 << TFT_RD) + //#define RD_L digitalWrite(TFT_WR, LOW) + #define RD_H GPIO.out_w1ts = (1 << TFT_RD) + //#define RD_H digitalWrite(TFT_WR, HIGH) + #else + #define RD_L + #define RD_H + #endif + #else + #define TFT_RD -1 + #define RD_L + #define RD_H + #endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to a SPI ILI948x TFT +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour + + // Write 8 bits to TFT + #define tft_Write_8(C) spi.transfer(C) + + // Convert 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16(C) spi.transfer(((C) & 0xF800)>>8); \ + spi.transfer(((C) & 0x07E0)>>3); \ + spi.transfer(((C) & 0x001F)<<3) + + // Future option for transfer without wait + #define tft_Write_16N(C) tft_Write_16(C) + + // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ + spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ + spi.transfer(((C) & 0x1F00)>>5) + + // Write 32 bits to TFT + #define tft_Write_32(C) spi.write32(C) + + // Write two concatenated 16 bit values to TFT + #define tft_Write_32C(C,D) spi.write32((C)<<16 | (D)) + + // Write 16 bit value twice to TFT + #define tft_Write_32D(C) spi.write32((C)<<16 | (C)) + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to an Raspberry Pi TFT +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (RPI_DISPLAY_TYPE) + + // ESP32 low level SPI writes for 8, 16 and 32 bit values + // to avoid the function call overhead + #define TFT_WRITE_BITS(D, B) \ + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + + // Write 8 bits + #define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16) + + // Write 16 bits with corrected endianness for 16 bit colours + #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + + // Future option for transfer without wait + #define tft_Write_16N(C) tft_Write_16(C) + + // Write 16 bits + #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) + + // Write 32 bits + #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) + + // Write two address coordinates + #define tft_Write_32C(C,D) TFT_WRITE_BITS((C)<<24 | (C), 32); \ + TFT_WRITE_BITS((D)<<24 | (D), 32) + + // Write same value twice + #define tft_Write_32D(C) tft_Write_32C(C,C) + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros for all other SPI displays +//////////////////////////////////////////////////////////////////////////////////////// +#else +/* Old macros + // ESP32 low level SPI writes for 8, 16 and 32 bit values + // to avoid the function call overhead + #define TFT_WRITE_BITS(D, B) \ + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + + // Write 8 bits + #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) + + // Write 16 bits with corrected endianness for 16 bit colours + #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + + // Write 16 bits + #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) + + // Write 32 bits + #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) + + // Write two address coordinates + #define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + + // Write same value twice + #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) +//*/ +//* Replacement slimmer macros + #if !defined(CONFIG_IDF_TARGET_ESP32S3) + #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ + *_spi_w = D; \ + *_spi_cmd = SPI_USR; \ + while (*_spi_cmd & SPI_USR); + #else + #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ + *_spi_w = D; \ + *_spi_cmd = SPI_UPDATE; \ + while (*_spi_cmd & SPI_UPDATE); \ + *_spi_cmd = SPI_USR; \ + while (*_spi_cmd & SPI_USR); + #endif + // Write 8 bits + #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) + + // Write 16 bits with corrected endianness for 16 bit colours + #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + + // Future option for transfer without wait + #if !defined(CONFIG_IDF_TARGET_ESP32S3) + #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ + *_spi_w = ((C)<<8 | (C)>>8); \ + *_spi_cmd = SPI_USR; +#else + #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ + *_spi_w = ((C)<<8 | (C)>>8); \ + *_spi_cmd = SPI_UPDATE; \ + while (*_spi_cmd & SPI_UPDATE); \ + *_spi_cmd = SPI_USR; +#endif + + // Write 16 bits + #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) + + // Write 32 bits + #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) + + // Write two address coordinates + #define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + + // Write same value twice + #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + +//*/ +#endif + +#ifndef tft_Write_16N + #define tft_Write_16N tft_Write_16 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to read from display using SPI or software SPI +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined (TFT_PARALLEL_8_BIT) + // Read from display using SPI or software SPI + // Use a SPI read transfer + #define tft_Read_8() spi.transfer(0) +#endif + +// Concatenate a byte sequence A,B,C,D to CDAB, P is a uint8_t pointer +#define DAT8TO32(P) ( (uint32_t)P[0]<<8 | P[1] | P[2]<<24 | P[3]<<16 ) + +#endif // Header end diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 9ec4312..bfc41b5 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -17,7 +17,11 @@ #include "TFT_eSPI.h" #if defined (ESP32) - #include "Processors/TFT_eSPI_ESP32.c" + #if defined(CONFIG_IDF_TARGET_ESP32S3) + #include "Processors/TFT_eSPI_ESP32_S3.c" + #else + #include "Processors/TFT_eSPI_ESP32.c" + #endif #elif defined (ESP8266) #include "Processors/TFT_eSPI_ESP8266.c" #elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h @@ -743,6 +747,12 @@ void TFT_eSPI::init(uint8_t tc) #elif defined (RM68120_DRIVER) #include "TFT_Drivers/RM68120_Init.h" +#elif defined (HX8357B_DRIVER) + #include "TFT_Drivers/HX8357B_Init.h" + +#elif defined (HX8357C_DRIVER) + #include "TFT_Drivers/HX8357C_Init.h" + #endif #ifdef TFT_INVERSION_ON @@ -834,6 +844,12 @@ void TFT_eSPI::setRotation(uint8_t m) #elif defined (RM68120_DRIVER) #include "TFT_Drivers/RM68120_Rotation.h" +#elif defined (HX8357B_DRIVER) + #include "TFT_Drivers/HX8357B_Rotation.h" + +#elif defined (HX8357C_DRIVER) + #include "TFT_Drivers/HX8357C_Rotation.h" + #endif delayMicroseconds(10); @@ -3418,7 +3434,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) // write to RAM DC_C; tft_Write_8(TFT_RAMWR); - #if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32) + #if defined(TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) || !defined(ESP32) DC_D; tft_Write_16(color); #else DC_D; tft_Write_16N(color); @@ -3546,7 +3562,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_C; tft_Write_8(TFT_RAMWR); - #if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32) + #if defined(TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) || !defined(ESP32) DC_D; tft_Write_16(color); #else DC_D; tft_Write_16N(color); @@ -5371,7 +5387,7 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.trans = false; #endif -#if defined (TFT_PARALLEL_8_BIT) +#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) tft_settings.serial = false; tft_settings.tft_spi_freq = 0; #else @@ -5470,7 +5486,7 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.pin_tft_rst = -1; #endif -#if defined (TFT_PARALLEL_8_BIT) +#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) tft_settings.pin_tft_d0 = TFT_D0; tft_settings.pin_tft_d1 = TFT_D1; tft_settings.pin_tft_d2 = TFT_D2; diff --git a/TFT_eSPI.h b/TFT_eSPI.h deleted file mode 100644 index 06df531..0000000 --- a/TFT_eSPI.h +++ /dev/null @@ -1,894 +0,0 @@ -/*************************************************** - Arduino TFT graphics library targeted at ESP8266 - and ESP32 based boards. - - This is a stand-alone library that contains the - hardware driver, the graphics functions and the - proportional fonts. - - The built-in fonts 4, 6, 7 and 8 are Run Length - Encoded (RLE) to reduce the FLASH footprint. - - Last review/edit by Bodmer: 04/02/22 - ****************************************************/ - -// Stop fonts etc being loaded multiple times -#ifndef _TFT_eSPIH_ -#define _TFT_eSPIH_ - -#define TFT_ESPI_VERSION "2.4.50" - -// Bit level feature flags -// Bit 0 set: viewport capability -#define TFT_ESPI_FEATURES 1 - -/*************************************************************************************** -** Section 1: Load required header files -***************************************************************************************/ - -//Standard support -#include -#include -#include - -/*************************************************************************************** -** Section 2: Load library and processor specific header files -***************************************************************************************/ -// Include header file that defines the fonts loaded, the TFT drivers -// available and the pins to be used, etc, etc -#ifdef CONFIG_TFT_eSPI_ESPIDF -#include "TFT_config.h" -#endif -#include - -// Handle FLASH based storage e.g. PROGMEM -#if defined(ARDUINO_ARCH_RP2040) - #undef pgm_read_byte - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #undef pgm_read_word - #define pgm_read_word(addr) ({ \ - typeof(addr) _addr = (addr); \ - *(const unsigned short *)(_addr); \ - }) - #undef pgm_read_dword - #define pgm_read_dword(addr) ({ \ - typeof(addr) _addr = (addr); \ - *(const unsigned long *)(_addr); \ - }) -#elif defined(__AVR__) - #include -#elif defined(ESP8266) || defined(ESP32) - #include -#else - #define PROGMEM -#endif - -// Include the processor specific drivers -#if defined (ESP32) - #include "Processors/TFT_eSPI_ESP32.h" -#elif defined (ESP8266) - #include "Processors/TFT_eSPI_ESP8266.h" -#elif defined (STM32) - #include "Processors/TFT_eSPI_STM32.h" -#elif defined(ARDUINO_ARCH_RP2040) - #include "Processors/TFT_eSPI_RP2040.h" -#else - #include "Processors/TFT_eSPI_Generic.h" -#endif - -/*************************************************************************************** -** Section 3: Interface setup -***************************************************************************************/ -#ifndef TAB_COLOUR - #define TAB_COLOUR 0 -#endif - -// If the SPI frequency is not defined, set a default -#ifndef SPI_FREQUENCY - #define SPI_FREQUENCY 20000000 -#endif - -// If the SPI read frequency is not defined, set a default -#ifndef SPI_READ_FREQUENCY - #define SPI_READ_FREQUENCY 10000000 -#endif - -// Some ST7789 boards do not work with Mode 0 -#ifndef TFT_SPI_MODE - #if defined(ST7789_DRIVER) || defined(ST7789_2_DRIVER) - #define TFT_SPI_MODE SPI_MODE3 - #else - #define TFT_SPI_MODE SPI_MODE0 - #endif -#endif - -// If the XPT2046 SPI frequency is not defined, set a default -#ifndef SPI_TOUCH_FREQUENCY - #define SPI_TOUCH_FREQUENCY 2500000 -#endif - -#ifndef SPI_BUSY_CHECK - #define SPI_BUSY_CHECK -#endif - -/*************************************************************************************** -** Section 4: Setup fonts -***************************************************************************************/ -// Use GLCD font in error case where user requests a smooth font file -// that does not exist (this is a temporary fix to stop ESP32 reboot) -#ifdef SMOOTH_FONT - #ifndef LOAD_GLCD - #define LOAD_GLCD - #endif -#endif - -// Only load the fonts defined in User_Setup.h (to save space) -// Set flag so RLE rendering code is optionally compiled -#ifdef LOAD_GLCD - #include -#endif - -#ifdef LOAD_FONT2 - #include -#endif - -#ifdef LOAD_FONT4 - #include - #define LOAD_RLE -#endif - -#ifdef LOAD_FONT6 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif -#endif - -#ifdef LOAD_FONT7 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif -#endif - -#ifdef LOAD_FONT8 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif -#elif defined LOAD_FONT8N // Optional narrower version - #define LOAD_FONT8 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif -#endif - -#ifdef LOAD_GFXFF - // We can include all the free fonts and they will only be built into - // the sketch if they are used - #include - // Call up any user custom fonts - #include -#endif // #ifdef LOAD_GFXFF - -// Create a null default font in case some fonts not used (to prevent crash) -const uint8_t widtbl_null[1] = {0}; -PROGMEM const uint8_t chr_null[1] = {0}; -PROGMEM const uint8_t* const chrtbl_null[1] = {chr_null}; - -// This is a structure to conveniently hold information on the default fonts -// Stores pointer to font character image address table, width table and height -typedef struct { - const uint8_t *chartbl; - const uint8_t *widthtbl; - uint8_t height; - uint8_t baseline; - } fontinfo; - -// Now fill the structure -const PROGMEM fontinfo fontdata [] = { - #ifdef LOAD_GLCD - { (const uint8_t *)font, widtbl_null, 0, 0 }, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - // GLCD font (Font 1) does not have all parameters - { (const uint8_t *)chrtbl_null, widtbl_null, 8, 7 }, - - #ifdef LOAD_FONT2 - { (const uint8_t *)chrtbl_f16, widtbl_f16, chr_hgt_f16, baseline_f16}, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - // Font 3 current unused - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - - #ifdef LOAD_FONT4 - { (const uint8_t *)chrtbl_f32, widtbl_f32, chr_hgt_f32, baseline_f32}, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - // Font 5 current unused - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - - #ifdef LOAD_FONT6 - { (const uint8_t *)chrtbl_f64, widtbl_f64, chr_hgt_f64, baseline_f64}, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - #ifdef LOAD_FONT7 - { (const uint8_t *)chrtbl_f7s, widtbl_f7s, chr_hgt_f7s, baseline_f7s}, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - #ifdef LOAD_FONT8 - { (const uint8_t *)chrtbl_f72, widtbl_f72, chr_hgt_f72, baseline_f72} - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 } - #endif -}; - -/*************************************************************************************** -** Section 5: Font datum enumeration -***************************************************************************************/ -//These enumerate the text plotting alignment (reference datum point) -#define TL_DATUM 0 // Top left (default) -#define TC_DATUM 1 // Top centre -#define TR_DATUM 2 // Top right -#define ML_DATUM 3 // Middle left -#define CL_DATUM 3 // Centre left, same as above -#define MC_DATUM 4 // Middle centre -#define CC_DATUM 4 // Centre centre, same as above -#define MR_DATUM 5 // Middle right -#define CR_DATUM 5 // Centre right, same as above -#define BL_DATUM 6 // Bottom left -#define BC_DATUM 7 // Bottom centre -#define BR_DATUM 8 // Bottom right -#define L_BASELINE 9 // Left character baseline (Line the 'A' character would sit on) -#define C_BASELINE 10 // Centre character baseline -#define R_BASELINE 11 // Right character baseline - -/*************************************************************************************** -** Section 6: Colour enumeration -***************************************************************************************/ -// Default color definitions -#define TFT_BLACK 0x0000 /* 0, 0, 0 */ -#define TFT_NAVY 0x000F /* 0, 0, 128 */ -#define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define TFT_MAROON 0x7800 /* 128, 0, 0 */ -#define TFT_PURPLE 0x780F /* 128, 0, 128 */ -#define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define TFT_LIGHTGREY 0xD69A /* 211, 211, 211 */ -#define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define TFT_BLUE 0x001F /* 0, 0, 255 */ -#define TFT_GREEN 0x07E0 /* 0, 255, 0 */ -#define TFT_CYAN 0x07FF /* 0, 255, 255 */ -#define TFT_RED 0xF800 /* 255, 0, 0 */ -#define TFT_MAGENTA 0xF81F /* 255, 0, 255 */ -#define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define TFT_WHITE 0xFFFF /* 255, 255, 255 */ -#define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */ -#define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */ -#define TFT_PINK 0xFE19 /* 255, 192, 203 */ //Lighter pink, was 0xFC9F -#define TFT_BROWN 0x9A60 /* 150, 75, 0 */ -#define TFT_GOLD 0xFEA0 /* 255, 215, 0 */ -#define TFT_SILVER 0xC618 /* 192, 192, 192 */ -#define TFT_SKYBLUE 0x867D /* 135, 206, 235 */ -#define TFT_VIOLET 0x915C /* 180, 46, 226 */ - -// Next is a special 16 bit colour value that encodes to 8 bits -// and will then decode back to the same 16 bit value. -// Convenient for 8 bit and 16 bit transparent sprites. -#define TFT_TRANSPARENT 0x0120 // This is actually a dark green - -// Default palette for 4 bit colour sprites -static const uint16_t default_4bit_palette[] PROGMEM = { - TFT_BLACK, // 0 ^ - TFT_BROWN, // 1 | - TFT_RED, // 2 | - TFT_ORANGE, // 3 | - TFT_YELLOW, // 4 Colours 0-9 follow the resistor colour code! - TFT_GREEN, // 5 | - TFT_BLUE, // 6 | - TFT_PURPLE, // 7 | - TFT_DARKGREY, // 8 | - TFT_WHITE, // 9 v - TFT_CYAN, // 10 Blue+green mix - TFT_MAGENTA, // 11 Blue+red mix - TFT_MAROON, // 12 Darker red colour - TFT_DARKGREEN,// 13 Darker green colour - TFT_NAVY, // 14 Darker blue colour - TFT_PINK // 15 -}; - -/*************************************************************************************** -** Section 7: Diagnostic support -***************************************************************************************/ -// #define TFT_eSPI_DEBUG // Switch on debug support serial messages (not used yet) -// #define TFT_eSPI_FNx_DEBUG // Switch on debug support for function "x" (not used yet) - -// This structure allows sketches to retrieve the user setup parameters at runtime -// by calling getSetup(), zero impact on code size unless used, mainly for diagnostics -typedef struct -{ -String version = TFT_ESPI_VERSION; -String setup_info; // Setup reference name available to use in a user setup -uint32_t setup_id; // ID available to use in a user setup -int32_t esp; // Processor code -uint8_t trans; // SPI transaction support -uint8_t serial; // Serial (SPI) or parallel -uint8_t port; // SPI port -uint8_t overlap; // ESP8266 overlap mode -uint8_t interface; // Interface type - -uint16_t tft_driver; // Hexadecimal code -uint16_t tft_width; // Rotation 0 width and height -uint16_t tft_height; - -uint8_t r0_x_offset; // Display offsets, not all used yet -uint8_t r0_y_offset; -uint8_t r1_x_offset; -uint8_t r1_y_offset; -uint8_t r2_x_offset; -uint8_t r2_y_offset; -uint8_t r3_x_offset; -uint8_t r3_y_offset; - -int8_t pin_tft_mosi; // SPI pins -int8_t pin_tft_miso; -int8_t pin_tft_clk; -int8_t pin_tft_cs; - -int8_t pin_tft_dc; // Control pins -int8_t pin_tft_rd; -int8_t pin_tft_wr; -int8_t pin_tft_rst; - -int8_t pin_tft_d0; // Parallel port pins -int8_t pin_tft_d1; -int8_t pin_tft_d2; -int8_t pin_tft_d3; -int8_t pin_tft_d4; -int8_t pin_tft_d5; -int8_t pin_tft_d6; -int8_t pin_tft_d7; - -int8_t pin_tft_led; -int8_t pin_tft_led_on; - -int8_t pin_tch_cs; // Touch chip select pin - -int16_t tft_spi_freq;// TFT write SPI frequency -int16_t tft_rd_freq; // TFT read SPI frequency -int16_t tch_spi_freq;// Touch controller read/write SPI frequency -} setup_t; - -/*************************************************************************************** -** Section 8: Class member and support functions -***************************************************************************************/ -// Swap any type -template static inline void -swap_coord(T& a, T& b) { T t = a; a = b; b = t; } - -// Callback prototype for smooth font pixel colour read -typedef uint16_t (*getColorCallback)(uint16_t x, uint16_t y); - -// Class functions and variables -class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has access to protected members - - //--------------------------------------- public ------------------------------------// - public: - - TFT_eSPI(int16_t _W = TFT_WIDTH, int16_t _H = TFT_HEIGHT); - - // init() and begin() are equivalent, begin() included for backwards compatibility - // Sketch defined tab colour option is for ST7735 displays only - void init(uint8_t tc = TAB_COLOUR), begin(uint8_t tc = TAB_COLOUR); - - // These are virtual so the TFT_eSprite class can override them with sprite specific functions - virtual void drawPixel(int32_t x, int32_t y, uint32_t color), - drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), - drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color), - drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), - drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), - fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); - - virtual int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), - drawChar(uint16_t uniCode, int32_t x, int32_t y), - height(void), - width(void); - - // Read the colour of a pixel at x,y and return value in 565 format - virtual uint16_t readPixel(int32_t x, int32_t y); - - virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates - - // Push (aka write pixel) colours to the set window - virtual void pushColor(uint16_t color); - - // These are non-inlined to enable override - virtual void begin_nin_write(); - virtual void end_nin_write(); - - void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3 - uint8_t getRotation(void); // Read the current rotation - - void invertDisplay(bool i); // Tell TFT to invert all displayed colours - - - // The TFT_eSprite class inherits the following functions (not all are useful to Sprite class - void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); // Note: start coordinates + width and height - - // Viewport commands, see "Viewport_Demo" sketch - void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); - bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h); - int32_t getViewportX(void); - int32_t getViewportY(void); - int32_t getViewportWidth(void); - int32_t getViewportHeight(void); - bool getViewportDatum(void); - void frameViewport(uint16_t color, int32_t w); - void resetViewport(void); - - // Clip input window to viewport bounds, return false if whole area is out of bounds - bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h); - // Clip input window area to viewport bounds, return false if whole area is out of bounds - bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye); - - // Push (aka write pixel) colours to the TFT (use setAddrWindow() first) - void pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock() - pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option - pushColors(uint8_t *data, uint32_t len); // Deprecated, use pushPixels() - - // Write a solid block of a single colour - void pushBlock(uint16_t color, uint32_t len); - - // Write a set of pixels stored in memory, use setSwapBytes(true/false) function to correct endianess - void pushPixels(const void * data_in, uint32_t len); - - // Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input - #ifdef TFT_SDA_READ - #if defined (TFT_eSPI_ENABLE_8_BIT_READ) - uint8_t tft_Read_8(void); // Read 8 bit value from TFT command register - #endif - void begin_SDA_Read(void); // Begin a read on a half duplex (bi-directional SDA) SPI bus - sets MOSI to input - void end_SDA_Read(void); // Restore MOSI to output - #endif - - // Graphics drawing - void fillScreen(uint32_t color), - drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color), - drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color), - fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color); - - void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2); - void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2); - - // Draw a pixel blended with the pixel colour on the TFT or sprite, return blended colour - // If bg_color is not included the background pixel colour will be read from TFT or sprite - uint16_t drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color = 0x00FFFFFF); - - // Draw a small anti-aliased filled circle at ax,ay with radius r (uses drawWideLine) - // If bg_color is not included the background pixel colour will be read from TFT or sprite - void drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased filled circle at x, y with radius r - // If bg_color is not included the background pixel colour will be read from TFT or sprite - void fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color = 0x00FFFFFF); - - void fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2) - // If bg_color is not included the background pixel colour will be read from TFT or sprite - void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends - // If bg_color is not included the background pixel colour will be read from TFT or sprite - void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color), - drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color), - fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color), - fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color), - - drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color), - fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color), - - // Corner 1 Corner 2 Corner 3 - drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color), - fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color); - - // Image rendering - // Swap the byte order for pushImage() and pushPixels() - corrects endianness - void setSwapBytes(bool swap); - bool getSwapBytes(void); - - // Draw bitmap - void drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), - drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), - drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), - drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), - setBitmapColor(uint16_t fgcolor, uint16_t bgcolor); // Define the 2 colours for 1bpp sprites - - // Set TFT pivot point (use when rendering rotated sprites) - void setPivot(int16_t x, int16_t y); - int16_t getPivotX(void), // Get pivot x - getPivotY(void); // Get pivot y - - // The next functions can be used as a pair to copy screen blocks (or horizontal/vertical lines) to another location - // Read a block of pixels to a data buffer, buffer is 16 bit and the size must be at least w * h - void readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); - // Write a block of pixels to the screen which have been read by readRect() - void pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); - - // These are used to render images or sprites stored in RAM arrays (used by Sprite class for 16bpp Sprites) - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transparent); - - // These are used to render images stored in FLASH (PROGMEM) - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent); - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data); - - // These are used by Sprite class pushSprite() member function for 1, 4 and 8 bits per pixel (bpp) colours - // They are not intended to be used with user sketches (but could be) - // Set bpp8 true for 8bpp sprites, false otherwise. The cmap pointer must be specified for 4bpp - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true, uint16_t *cmap = nullptr); - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true, uint16_t *cmap = nullptr); - // FLASH version - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *data, bool bpp8, uint16_t *cmap = nullptr); - // This next function has been used successfully to dump the TFT screen to a PC for documentation purposes - // It reads a screen area and returns the 3 RGB 8 bit colour values of each pixel in the buffer - // Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes - void readRectRGB(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data); - - // Text rendering - value returned is the pixel width of the rendered text - int16_t drawNumber(long intNumber, int32_t x, int32_t y, uint8_t font), // Draw integer using specified font number - drawNumber(long intNumber, int32_t x, int32_t y), // Draw integer using current font - - // Decimal is the number of decimal places to render - // Use with setTextDatum() to position values on TFT, and setTextPadding() to blank old displayed values - drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y, uint8_t font), // Draw float using specified font number - drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y), // Draw float using current font - - // Handle char arrays - // Use with setTextDatum() to position string on TFT, and setTextPadding() to blank old displayed strings - drawString(const char *string, int32_t x, int32_t y, uint8_t font), // Draw string using specified font number - drawString(const char *string, int32_t x, int32_t y), // Draw string using current font - drawString(const String& string, int32_t x, int32_t y, uint8_t font),// Draw string using specified font number - drawString(const String& string, int32_t x, int32_t y), // Draw string using current font - - drawCentreString(const char *string, int32_t x, int32_t y, uint8_t font), // Deprecated, use setTextDatum() and drawString() - drawRightString(const char *string, int32_t x, int32_t y, uint8_t font), // Deprecated, use setTextDatum() and drawString() - drawCentreString(const String& string, int32_t x, int32_t y, uint8_t font),// Deprecated, use setTextDatum() and drawString() - drawRightString(const String& string, int32_t x, int32_t y, uint8_t font); // Deprecated, use setTextDatum() and drawString() - - // Text rendering and font handling support funtions - void setCursor(int16_t x, int16_t y), // Set cursor for tft.print() - setCursor(int16_t x, int16_t y, uint8_t font); // Set cursor and font number for tft.print() - - int16_t getCursorX(void), // Read current cursor x position (moves with tft.print()) - getCursorY(void); // Read current cursor y position - - void setTextColor(uint16_t color), // Set character (glyph) color only (background not over-written) - setTextColor(uint16_t fgcolor, uint16_t bgcolor, bool bgfill = false), // Set character (glyph) foreground and background colour, optional background fill for smooth fonts - setTextSize(uint8_t size); // Set character size multiplier (this increases pixel size) - - void setTextWrap(bool wrapX, bool wrapY = false); // Turn on/off wrapping of text in TFT width and/or height - - void setTextDatum(uint8_t datum); // Set text datum position (default is top left), see Section 6 above - uint8_t getTextDatum(void); - - void setTextPadding(uint16_t x_width); // Set text padding (background blanking/over-write) width in pixels - uint16_t getTextPadding(void); // Get text padding - -#ifdef LOAD_GFXFF - void setFreeFont(const GFXfont *f = NULL), // Select the GFX Free Font - setTextFont(uint8_t font); // Set the font number to use in future -#else - void setFreeFont(uint8_t font), // Not used, historical fix to prevent an error - setTextFont(uint8_t font); // Set the font number to use in future -#endif - - int16_t textWidth(const char *string, uint8_t font), // Returns pixel width of string in specified font - textWidth(const char *string), // Returns pixel width of string in current font - textWidth(const String& string, uint8_t font), // As above for String types - textWidth(const String& string), - fontHeight(int16_t font), // Returns pixel height of string in specified font - fontHeight(void); // Returns pixel width of string in current font - - // Used by library and Smooth font class to extract Unicode point codes from a UTF8 encoded string - uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining), - decodeUTF8(uint8_t c); - - // Support function to UTF8 decode and draw characters piped through print stream - size_t write(uint8_t); - // size_t write(const uint8_t *buf, size_t len); - - // Used by Smooth font class to fetch a pixel colour for the anti-aliasing - void setCallback(getColorCallback getCol); - - uint16_t fontsLoaded(void); // Each bit in returned value represents a font type that is loaded - used for debug/error handling only - - // Low level read/write - void spiwrite(uint8_t); // legacy support only -#ifndef RM68120_DRIVER - void writecommand(uint8_t c); // Send a command, function resets DC/RS high ready for data -#else - void writecommand(uint16_t c); // Send a command, function resets DC/RS high ready for data - void writeRegister(uint16_t c, uint8_t d); // Write data to 16 bit command register -#endif - void writedata(uint8_t d); // Send data with DC/RS set high - - void commandList(const uint8_t *addr); // Send a initialisation sequence to TFT stored in FLASH - - uint8_t readcommand8( uint8_t cmd_function, uint8_t index = 0); // read 8 bits from TFT - uint16_t readcommand16(uint8_t cmd_function, uint8_t index = 0); // read 16 bits from TFT - uint32_t readcommand32(uint8_t cmd_function, uint8_t index = 0); // read 32 bits from TFT - - - // Colour conversion - // Convert 8 bit red, green and blue to 16 bits - uint16_t color565(uint8_t red, uint8_t green, uint8_t blue); - - // Convert 8 bit colour to 16 bits - uint16_t color8to16(uint8_t color332); - // Convert 16 bit colour to 8 bits - uint8_t color16to8(uint16_t color565); - - // Convert 16 bit colour to/from 24 bit, R+G+B concatenated into LS 24 bits - uint32_t color16to24(uint16_t color565); - uint32_t color24to16(uint32_t color888); - - // Alpha blend 2 colours, see generic "alphaBlend_Test" example - // alpha = 0 = 100% background colour - // alpha = 255 = 100% foreground colour - uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc); - // 16 bit colour alphaBlend with alpha dither (dither reduces colour banding) - uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t dither); - // 24 bit colour alphaBlend with optional alpha dither - uint32_t alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8_t dither = 0); - - - // DMA support functions - these are currently just for SPI writes when using the ESP32 or STM32 processors - // Bear in mind DMA will only be of benefit in particular circumstances and can be tricky - // to manage by noobs. The functions have however been designed to be noob friendly and - // avoid a few DMA behaviour "gotchas". - // - // At best you will get a 2x TFT rendering performance improvement when using DMA because - // this library handles the SPI bus so efficiently during normal (non DMA) transfers. The best - // performance improvement scenario is the DMA transfer time is exactly the same as the time it - // takes for the processor to prepare the next image buffer and initiate another DMA transfer. - // - // DMA transfer to the TFT is done while the processor moves on to handle other tasks. Bear - // this in mind and watch out for "gotchas" like the image buffer going out of scope as the - // processor leaves a function or its content being changed while the DMA engine is reading it. - // - // The compiler MAY change the implied scope of a buffer which has been set aside by creating - // an array. For example a buffer defined before a "for-next" loop may get de-allocated when - // the loop ends. To avoid this use, for example, malloc() and free() to take control of when - // the buffer space is available and ensure it is not released until DMA is complete. - // - // Clearly you should not modify a buffer that is being DMA'ed to the TFT until the DMA is over. - // Use the dmaBusy() function to check this. Use tft.startWrite() before invoking DMA so the - // TFT chip select stays low. If you use tft.endWrite() before DMA is complete then the endWrite - // function will wait for the DMA to complete, so this may defeat any DMA performance benefit. - // - - bool initDMA(bool ctrl_cs = false); // Initialise the DMA engine and attach to SPI bus - typically used in setup() - // Parameter "true" enables DMA engine control of TFT chip select (ESP32 only) - // For ESP32 only, TFT reads will not work if parameter is true - void deInitDMA(void); // De-initialise the DMA engine and detach from SPI bus - typically not used - - // Push an image to the TFT using DMA, buffer is optional and grabs (double buffers) a copy of the image - // Use the buffer if the image data will get over-written or destroyed while DMA is in progress - // If swapping colour bytes is defined, and the double buffer option is NOT used, then the bytes - // in the original data image will be swapped by the function before DMA is initiated. - // The function will wait for the last DMA to complete if it is called while a previous DMA is still - // in progress, this simplifies the sketch and helps avoid "gotchas". - void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* data, uint16_t* buffer = nullptr); - -#if defined (ESP32) // ESP32 only at the moment - // For case where pointer is a const and the image data must not be modified (clipped or byte swapped) - void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* data); -#endif - // Push a block of pixels into a window set up using setAddrWindow() - void pushPixelsDMA(uint16_t* image, uint32_t len); - - // Check if the DMA is complete - use while(tft.dmaBusy); for a blocking wait - bool dmaBusy(void); // returns true if DMA is still in progress - void dmaWait(void); // wait until DMA is complete - - bool DMA_Enabled = false; // Flag for DMA enabled state - uint8_t spiBusyCheck = 0; // Number of ESP32 transfer buffers to check - - // Bare metal functions - void startWrite(void); // Begin SPI transaction - void writeColor(uint16_t color, uint32_t len); // Deprecated, use pushBlock() - void endWrite(void); // End SPI transaction - - // Set/get an arbitrary library configuration attribute or option - // Use to switch ON/OFF capabilities such as UTF8 decoding - each attribute has a unique ID - // id = 0: reserved - may be used in future to reset all attributes to a default state - // id = 1: Turn on (a=true) or off (a=false) GLCD cp437 font character error correction - // id = 2: Turn on (a=true) or off (a=false) UTF8 decoding - // id = 3: Enable or disable use of ESP32 PSRAM (if available) - #define CP437_SWITCH 1 - #define UTF8_SWITCH 2 - #define PSRAM_ENABLE 3 - void setAttribute(uint8_t id = 0, uint8_t a = 0); // Set attribute value - uint8_t getAttribute(uint8_t id = 0); // Get attribute value - - // Used for diagnostic sketch to see library setup adopted by compiler, see Section 7 above - void getSetup(setup_t& tft_settings); // Sketch provides the instance to populate - bool verifySetupID(uint32_t id); - - // Global variables - static SPIClass& getSPIinstance(void); // Get SPI class handle - - uint32_t textcolor, textbgcolor; // Text foreground and background colours - - uint32_t bitmap_fg, bitmap_bg; // Bitmap foreground (bit=1) and background (bit=0) colours - - uint8_t textfont, // Current selected font number - textsize, // Current font size multiplier - textdatum, // Text reference datum - rotation; // Display rotation (0-3) - - uint8_t decoderState = 0; // UTF8 decoder state - not for user access - uint16_t decoderBuffer; // Unicode code-point buffer - not for user access - - //--------------------------------------- private ------------------------------------// - private: - // Legacy begin and end prototypes - deprecated TODO: delete - void spi_begin(); - void spi_end(); - - void spi_begin_read(); - void spi_end_read(); - - // New begin and end prototypes - // begin/end a TFT write transaction - // For SPI bus the transmit clock rate is set - inline void begin_tft_write() __attribute__((always_inline)); - inline void end_tft_write() __attribute__((always_inline)); - - // begin/end a TFT read transaction - // For SPI bus: begin lowers SPI clock rate, end reinstates transmit clock rate - inline void begin_tft_read() __attribute__((always_inline)); - inline void end_tft_read() __attribute__((always_inline)); - - // Initialise the data bus GPIO and hardware interfaces - void initBus(void); - - // Temporary library development function TODO: remove need for this - void pushSwapBytePixels(const void* data_in, uint32_t len); - - // Same as setAddrWindow but exits with CGRAM in read mode - void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); - - // Byte read prototype - uint8_t readByte(void); - - // GPIO parallel bus input/output direction control - void busDir(uint32_t mask, uint8_t mode); - - // Single GPIO input/output direction control - void gpioMode(uint8_t gpio, uint8_t mode); - - // Helper function: calculate distance of a point from a finite length line between two points - float wedgeLineDistance(float pax, float pay, float bax, float bay, float dr); - - // Display variant settings - uint8_t tabcolor, // ST7735 screen protector "tab" colour (now invalid) - colstart = 0, rowstart = 0; // Screen display area to CGRAM area coordinate offsets - - // Port and pin masks for control signals (ESP826 only) - TODO: remove need for this - volatile uint32_t *dcport, *csport; - uint32_t cspinmask, dcpinmask, wrpinmask, sclkpinmask; - - #if defined(ESP32_PARALLEL) - // Bit masks for ESP32 parallel bus interface - uint32_t xclr_mask, xdir_mask; // Port set/clear and direction control masks - - // Lookup table for ESP32 parallel bus interface uses 1kbyte RAM, - uint32_t xset_mask[256]; // Makes Sprite rendering test 33% faster, for slower macro equivalent - // see commented out #define set_mask(C) within TFT_eSPI_ESP32.h - #endif - - //uint32_t lastColor = 0xFFFF; // Last colour - used to minimise bit shifting overhead - - getColorCallback getColor = nullptr; // Smooth font callback function pointer - - bool locked, inTransaction, lockTransaction; // SPI transaction and mutex lock flags - - //-------------------------------------- protected ----------------------------------// - protected: - - //int32_t win_xe, win_ye; // Window end coords - not needed - - int32_t _init_width, _init_height; // Display w/h as input, used by setRotation() - int32_t _width, _height; // Display w/h as modified by current rotation - int32_t addr_row, addr_col; // Window position - used to minimise window commands - - int16_t _xPivot; // TFT x pivot point coordinate for rotated Sprites - int16_t _yPivot; // TFT x pivot point coordinate for rotated Sprites - - // Viewport variables - int32_t _vpX, _vpY, _vpW, _vpH; // Note: x start, y start, x end + 1, y end + 1 - int32_t _xDatum; - int32_t _yDatum; - int32_t _xWidth; - int32_t _yHeight; - bool _vpDatum; - bool _vpOoB; - - int32_t cursor_x, cursor_y, padX; // Text cursor x,y and padding setting - int32_t bg_cursor_x; // Background fill cursor - int32_t last_cursor_x; // Previous text cursor position when fill used - - uint32_t fontsloaded; // Bit field of fonts loaded - - uint8_t glyph_ab, // Smooth font glyph delta Y (height) above baseline - glyph_bb; // Smooth font glyph delta Y (height) below baseline - - bool isDigits; // adjust bounding box for numbers to reduce visual jiggling - bool textwrapX, textwrapY; // If set, 'wrap' text at right and optionally bottom edge of display - bool _swapBytes; // Swap the byte order for TFT pushImage() - - bool _booted; // init() or begin() has already run once - - // User sketch manages these via set/getAttribute() - bool _cp437; // If set, use correct CP437 charset (default is ON) - bool _utf8; // If set, use UTF-8 decoder in print stream 'write()' function (default ON) - bool _psram_enable; // Enable PSRAM use for library functions (TBD) and Sprites - - uint32_t _lastColor; // Buffered value of last colour used - - bool _fillbg; // Fill background flag (just for for smooth fonts at the moment) - -#if defined (SSD1963_DRIVER) - uint16_t Cswap; // Swap buffer for SSD1963 - uint8_t r6, g6, b6; // RGB buffer for SSD1963 -#endif - -#ifdef LOAD_GFXFF - GFXfont *gfxFont; -#endif - -/*************************************************************************************** -** Section 9: TFT_eSPI class conditional extensions -***************************************************************************************/ -// Load the Touch extension -#ifdef TOUCH_CS - #if defined (TFT_PARALLEL_8_BIT) || defined (RP2040_PIO_INTERFACE) - #error >>>>------>> Touch functions not supported in 8 bit parallel mode or with RP2040 PIO. - #else - #include "Extensions/Touch.h" // Loaded if TOUCH_CS is defined by user - #endif -#else - #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available! -#endif - -// Load the Anti-aliased font extension -#ifdef SMOOTH_FONT - #include "Extensions/Smooth_font.h" // Loaded if SMOOTH_FONT is defined by user -#endif - -}; // End of class TFT_eSPI - -/*************************************************************************************** -** Section 10: Additional extension classes -***************************************************************************************/ -// Load the Button Class -#include "Extensions/Button.h" - -// Load the Sprite Class -#include "Extensions/Sprite.h" - -#endif // ends #ifndef _TFT_eSPIH_ diff --git a/User_Setups/Setup70b_ESP32_S3_ILI9341.h b/User_Setups/Setup70b_ESP32_S3_ILI9341.h new file mode 100644 index 0000000..9ee735a --- /dev/null +++ b/User_Setups/Setup70b_ESP32_S3_ILI9341.h @@ -0,0 +1,38 @@ +// Setup for the ESP32 S2 with ILI9341 display +// Note SPI DMA with ESP32 S2 is not currently supported +#define USER_SETUP_ID 70 +// See SetupX_Template.h for all options available +#define ILI9341_DRIVER + + // Typical board default pins +#define TFT_CS 34 // 10 or 34 + +#define TFT_MOSI 35 // 11 or 35 +#define TFT_SCLK 36 // 12 or 36 +#define TFT_MISO 37 // 13 or 37 + +// Use pins in range 0-31 +#define TFT_DC 7 +#define TFT_RST 6 + +//#define TOUCH_CS 16 // Optional for touch screen + +#define LOAD_GLCD +#define LOAD_FONT2 +#define LOAD_FONT4 +#define LOAD_FONT6 +#define LOAD_FONT7 +#define LOAD_FONT8 +#define LOAD_GFXFF + +#define SMOOTH_FONT + +// HSPI port NOT TESTED YET +//#define USE_HSPI_PORT + +//#define SPI_FREQUENCY 27000000 +#define SPI_FREQUENCY 80000000 // Maximum for ILI9341 + +#define SPI_READ_FREQUENCY 6000000 // 6 MHz is the maximum SPI read speed for the ST7789V + +#define SPI_TOUCH_FREQUENCY 2500000 diff --git a/library.json b/library.json deleted file mode 100644 index bae9906..0000000 --- a/library.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "TFT_eSPI", - "version": "2.4.50", - "keywords": "Arduino, tft, display, ttgo, LilyPi, WT32-SC01, ePaper, display, Pico, RP2040 Nano Connect, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, ST7796, RM68140, SSD1351, SSD1963, ILI9225, HX8357D, GC9A01, R61581", - "description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, RP2040, ESP8266, ESP32 and STM32", - "repository": - { - "type": "git", - "url": "https://github.com/Bodmer/TFT_eSPI" - }, - "authors": - [ - { - "name": "Bodmer", - "email": "bodmer@anola.net", - "maintainer": true - } - ], - "frameworks": "arduino", - "platforms": "rp2040, espressif8266, espressif32, ststm32", - "headers": "TFT_eSPI.h" -} diff --git a/library.properties b/library.properties deleted file mode 100644 index 0143f09..0000000 --- a/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=TFT_eSPI -version=2.4.50 -author=Bodmer -maintainer=Bodmer -sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32 -paragraph=Supports TFT displays using drivers (ILI9341 etc) that operate with hardware SPI or 8 bit parallel. -category=Display -url=https://github.com/Bodmer/TFT_eSPI -architectures=* -includes=TFT_eSPI.h -