From 054a824eb824771a5836dcd56499002eadaee6b2 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Tue, 22 Jan 2019 18:41:31 +0000 Subject: [PATCH] Add ESP32 VSPI or HSPI port option + others If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) then add or uncomment the following line in the setup header file: //#define USE_HSPI_PORT Minor performance tweaks for ESP32 to minimise the occurence of the slow transaction overhead. setAddrWindow now takes xstart, ystart, width and height as inputs Multi-sample raw touch x and y for noisy displays Example update for setAddrWindow change compatibility --- Extensions/Smooth_font.cpp | 5 +- Extensions/Sprite.cpp | 24 +- Extensions/Touch.cpp | 34 +- TFT_eSPI.cpp | 386 ++++++++++-------- TFT_eSPI.h | 84 ++-- User_Setup.h | 4 + User_Setups/SetupX_Template.h | 4 + examples/160 x 128/Pong_v3/Pong_v3.ino | 6 +- .../TFT_graphicstest_PDQ3.ino | 10 +- .../TFT_Mandlebrot/TFT_Mandlebrot.ino | 11 +- examples/320 x 240/TFT_Pong/TFT_Pong.ino | 6 +- .../TFT_graphicstest_PDQ.ino | 6 +- .../480 x 320/TFT_flash_jpg/TFT_flash_jpg.ino | 7 +- .../TFT_ring_meter/TFT_ring_meter.ino | 6 +- library.json | 2 +- library.properties | 2 +- 16 files changed, 355 insertions(+), 242 deletions(-) diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index 3dc2cb0..1952add 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -441,6 +441,8 @@ void TFT_eSPI::drawGlyph(uint16_t code) int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; int16_t cx = cursor_x + gdX[gNum]; + startWrite(); // Avoid slow ESP32 transaction overhead for every pixel + for (int y = 0; y < gHeight[gNum]; y++) { fontFile.read(pbuffer, gWidth[gNum]); // _tft->width()) max_x = _tft->width(); if (max_y > _tft->height()) max_y = _tft->height(); - _tft->startWrite(); + _tft->startWrite(); // ESP32: avoid transaction overhead for every tft pixel + // Scan destination bounding box and fetch transformed pixels from source Sprite for (int32_t x = min_x; x <= max_x; x++) { int32_t xt = x - _tft->_xpivot; @@ -325,7 +326,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) else if (column_drawn) y = max_y; // Skip remaining column pixels } } - _tft->endWrite(); + + _tft->endWrite(); // ESP32: end transaction return true; } @@ -465,7 +467,6 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y) if (_bpp == 16) _tft->pushImage(x, y, _iwidth, _iheight, _img ); else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8)); - } @@ -562,7 +563,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1 if (xs + w >= _iwidth) ws = _iwidth - xs; if (ys + h >= _iheight) hs = _iheight - ys; - if (_bpp == 16) + if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite { for (uint32_t yp = yo; yp < yo + hs; yp++) { @@ -577,7 +578,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1 ys++; } } - else if (_bpp == 8) + else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite { for (uint32_t yp = yo; yp < yo + hs; yp++) { @@ -613,7 +614,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1 x = y; y = _dheight - tx - 1; } - + // Plot a 1bpp image into a 1bpp Sprite uint8_t* pdata = (uint8_t* ) data; uint32_t ww = (w+7) & 0xFFF8; for (int32_t yp = 0; yp= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0) || !_created) return; if ((x + (int32_t)w < 0) || (y + (int32_t)h < 0)) return; @@ -654,7 +659,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const if (xs + w >= _iwidth) ws = _iwidth - xs; if (ys + h >= _iheight) hs = _iheight - ys; - if (_bpp == 16) + if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite { for (uint32_t yp = yo; yp < yo + hs; yp++) { @@ -670,7 +675,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const } } - else if (_bpp == 8) + else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite { for (uint32_t yp = yo; yp < yo + hs; yp++) { @@ -706,7 +711,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const x = y; y = _dheight - tx - 1; } - + // Plot a 1bpp image into a 1bpp Sprite const uint8_t* pdata = (const uint8_t* ) data; uint32_t ww = (w+7) & 0xFFF8; for (int32_t yp = 0; yp>3); // Read last 8 bits and start new XP conversion + tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion *x = tmp; - // Start XP sample request for y position - tmp = SPI.transfer(0); // Read first 8 bits + // Start XP sample request for y position, read 4 times and keep last sample + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + + tmp = spi.transfer(0); // Read first 8 bits tmp = tmp <<5; - tmp |= 0x1f & (SPI.transfer(0)>>3); // Read last 8 bits + tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits *y = tmp; @@ -57,9 +71,9 @@ uint16_t TFT_eSPI::getTouchRawZ(void){ // Calculate Z int16_t tz = 0xFFF; - SPI.transfer(0xb0); // Start new Z1 conversion - tz += SPI.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion - tz -= SPI.transfer16(0x00) >> 3; // Read Z2 + spi.transfer(0xb0); // Start new Z1 conversion + tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion + tz -= spi.transfer16(0x00) >> 3; // Read Z2 T_CS_H; diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index f1fb2c4..4df354b 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -15,10 +15,16 @@ #include "TFT_eSPI.h" -#include - -#ifndef ESP32_PARALLEL - #include +#if defined (ESP32) + #if !defined (ESP32_PARALLEL) + #ifdef USE_HSPI_PORT + SPIClass spi = SPIClass(HSPI); + #else // use default VSPI port + SPIClass spi = SPIClass(VSPI); + #endif + #endif +#else // ESP8266 + SPIClass spi = SPIClass(); #endif // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled @@ -48,32 +54,32 @@ void busDir(uint32_t mask, uint8_t mode); inline void TFT_eSPI::spi_begin(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));} + if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));} #endif } inline void TFT_eSPI::spi_end(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}} + if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} #endif } inline void TFT_eSPI::spi_begin_read(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE));} + if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE));} #else #if !defined(ESP32_PARALLEL) - SPI.setFrequency(SPI_READ_FREQUENCY); + spi.setFrequency(SPI_READ_FREQUENCY); #endif #endif } inline void TFT_eSPI::spi_end_read(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}} + if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} #else #if !defined(ESP32_PARALLEL) - SPI.setFrequency(SPI_FREQUENCY); + spi.setFrequency(SPI_FREQUENCY); #endif #endif } @@ -82,17 +88,17 @@ inline void TFT_eSPI::spi_end_read(void){ inline void TFT_eSPI::spi_begin_touch(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) - if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} + if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} #else - SPI.setFrequency(SPI_TOUCH_FREQUENCY); + spi.setFrequency(SPI_TOUCH_FREQUENCY); #endif } inline void TFT_eSPI::spi_end_touch(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) - if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}} + if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} #else - SPI.setFrequency(SPI_FREQUENCY); + spi.setFrequency(SPI_FREQUENCY); #endif } @@ -263,17 +269,17 @@ void TFT_eSPI::init(uint8_t tc) #ifdef TFT_SPI_OVERLAP // Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS // pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss); - //SPI.pins( 6, 7, 8, 0); - SPI.pins(6, 7, 8, 0); + //spi.pins( 6, 7, 8, 0); + spi.pins(6, 7, 8, 0); #endif - SPI.begin(); // This will set HMISO to input + spi.begin(); // This will set HMISO to input #else #if !defined(ESP32_PARALLEL) #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) - SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); + spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); #else - SPI.begin(); + spi.begin(); #endif #endif #endif @@ -284,9 +290,9 @@ void TFT_eSPI::init(uint8_t tc) // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled // so the code here is for ESP8266 only #if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(TFT_SPI_MODE); - SPI.setFrequency(SPI_FREQUENCY); + spi.setBitOrder(MSBFIRST); + spi.setDataMode(TFT_SPI_MODE); + spi.setFrequency(SPI_FREQUENCY); #endif #if defined(ESP32_PARALLEL) @@ -298,7 +304,7 @@ void TFT_eSPI::init(uint8_t tc) digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) pinMode(TFT_CS, OUTPUT); #else - SPI.setHwCs(1); // Use hardware SS toggling + spi.setHwCs(1); // Use hardware SS toggling #endif #endif @@ -611,7 +617,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) { #if defined(ESP32_PARALLEL) - readAddrWindow(x0, y0, x0, y0); // Sets CS low + readAddrWindow(x0, y0, 1, 1); // Sets CS low // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); @@ -652,7 +658,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) spi_begin_read(); - readAddrWindow(x0, y0, x0, y0); // Sets CS low + readAddrWindow(x0, y0, 1, 1); // Sets CS low #ifdef TFT_SDA_READ begin_SDA_Read(); @@ -757,7 +763,7 @@ void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t #if defined(ESP32_PARALLEL) - readAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low + readAddrWindow(x, y, w, h); // Sets CS low // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); @@ -799,7 +805,7 @@ void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t spi_begin_read(); - readAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low + readAddrWindow(x, y, w, h); // Sets CS low #ifdef TFT_SDA_READ begin_SDA_Read(); @@ -881,7 +887,7 @@ void TFT_eSPI::begin_SDA_Read(void) #ifdef TFT_SPI_OVERLAP // Reads in overlap mode not supported #else - SPI.end(); + spi.end(); #endif #endif } @@ -901,9 +907,9 @@ void TFT_eSPI::end_SDA_Read(void) pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false); #else #ifdef TFT_SPI_OVERLAP - SPI.pins(6, 7, 8, 0); + spi.pins(6, 7, 8, 0); #else - SPI.begin(); + spi.begin(); #endif #endif } @@ -946,7 +952,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t spi_begin(); inTransaction = true; - setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR + setWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR data += dx + dy * w; @@ -1007,7 +1013,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t { if (transp != *ptr) { - if (move) { move = false; setAddrWindow(px, y, xe, ye); } + if (move) { move = false; setWindow(px, y, xe, ye); } lineBuf[np] = *ptr; np++; } @@ -1042,7 +1048,10 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uint16_t *data) { - +#ifdef ESP32 + pushImage(x, y, w, h, (uint16_t*)data); +#else + // Partitioned memory FLASH processor if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return; int32_t dx = 0; @@ -1066,7 +1075,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin uint16_t buffer[64]; uint16_t* pix_buffer = buffer; - setAddrWindow(x, y, x + dw - 1, y + dh - 1); + setWindow(x, y, x + dw - 1, y + dh - 1); // Work out the number whole buffers to send uint16_t nb = (dw * dh) / 64; @@ -1095,6 +1104,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin inTransaction = false; spi_end(); +#endif // if ESP32 else ESP8266 check } @@ -1104,7 +1114,10 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uint16_t *data, uint16_t transp) { - +#ifdef ESP32 + pushImage(x, y, w, h, (uint16_t*) data, transp); +#else + // Partitioned memory FLASH processor if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return; int32_t dx = 0; @@ -1145,7 +1158,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin uint16_t color = pgm_read_word(ptr); if (transp != color) { - if (move) { move = false; setAddrWindow(px, y, xe, ye); } + if (move) { move = false; setWindow(px, y, xe, ye); } lineBuf[np] = color; np++; } @@ -1171,6 +1184,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin inTransaction = false; spi_end(); +#endif // if ESP32 else ESP8266 check } @@ -1198,7 +1212,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t * spi_begin(); inTransaction = true; - setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR + setWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR // Line buffer makes plotting faster uint16_t lineBuf[dw]; @@ -1339,7 +1353,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t * { if (transp != *ptr) { - if (move) { move = false; setAddrWindow(px, y, xe, ye);} + if (move) { move = false; setWindow(px, y, xe, ye);} uint8_t color = *ptr; // Shifts are slow so check if colour has changed first @@ -1398,7 +1412,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t * if (move) { move = false; - setAddrWindow(px, y, xe, ye); + setWindow(px, y, xe, ye); } np++; } @@ -1464,7 +1478,7 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_ spi_begin_read(); - readAddrWindow(x0, y0, x0 + w - 1, y0 + h - 1); // Sets CS low + readAddrWindow(x0, y0, w, h); // Sets CS low #ifdef TFT_SDA_READ begin_SDA_Read(); @@ -2397,7 +2411,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, u uint8_t mask = 0x1; spi_begin(); //inTransaction = true; - setAddrWindow(x, y, x+5, y+8); + setWindow(x, y, x+5, y+8); for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); column[5] = 0; @@ -2620,27 +2634,26 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, u /*************************************************************************************** -** Function name: setWindow +** Function name: setAddrWindow ** Description: define an area to receive a stream of pixels ***************************************************************************************/ // Chip select is high at the end of this function -void TFT_eSPI::setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1) +void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t w, int32_t h) { spi_begin(); - setAddrWindow(x0, y0, x1, y1); + setWindow(x0, y0, x0 + w - 1, y0 + h - 1); CS_H; spi_end(); } /*************************************************************************************** -** Function name: setAddrWindow +** Function name: setWindow ** Description: define an area to receive a stream of pixels ***************************************************************************************/ -// Chip select stays low, use setWindow() from sketches - +// Chip select stays low, call spi_begin first. Use setAddrWindow() from sketches #if defined (ESP8266) && !defined (RPI_WRITE_STROBE) && !defined (RPI_ILI9486_DRIVER) -void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) +void TFT_eSPI::setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) { //spi_begin(); @@ -2708,7 +2721,7 @@ void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) #elif defined (ESP8266) && !defined (RPI_WRITE_STROBE) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits -void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) +void TFT_eSPI::setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) { //spi_begin(); @@ -2731,7 +2744,7 @@ void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) DC_D; uint8_t xb[] = { 0, (uint8_t) (xs>>8), 0, (uint8_t) (xs>>0), 0, (uint8_t) (xe>>8), 0, (uint8_t) (xe>>0), }; - SPI.writePattern(&xb[0], 8, 1); + spi.writePattern(&xb[0], 8, 1); // Row addr set DC_C; @@ -2745,7 +2758,7 @@ void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) DC_D; uint8_t yb[] = { 0, (uint8_t) (ys>>8), 0, (uint8_t) (ys>>0), 0, (uint8_t) (ye>>8), 0, (uint8_t) (ye>>0), }; - SPI.writePattern(&yb[0], 8, 1); + spi.writePattern(&yb[0], 8, 1); // write to RAM DC_C; @@ -2763,7 +2776,7 @@ void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) #else #if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits -void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) +void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //spi_begin(); @@ -2840,7 +2853,7 @@ void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) #else // This is for the ESP32 -void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) +void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //spi_begin(); @@ -2862,7 +2875,7 @@ void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) #if defined (RPI_ILI9486_DRIVER) uint8_t xb[] = { 0, (uint8_t) (x0>>8), 0, (uint8_t) (x0>>0), 0, (uint8_t) (x1>>8), 0, (uint8_t) (x1>>0), }; - SPI.writePattern(&xb[0], 8, 1); + spi.writePattern(&xb[0], 8, 1); #else tft_Write_32(SPI_32(x0, x1)); #endif @@ -2876,7 +2889,7 @@ void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) #if defined (RPI_ILI9486_DRIVER) uint8_t yb[] = { 0, (uint8_t) (y0>>8), 0, (uint8_t) (y0>>0), 0, (uint8_t) (y1>>8), 0, (uint8_t) (y1>>0), }; - SPI.writePattern(&yb[0], 8, 1); + spi.writePattern(&yb[0], 8, 1); #else tft_Write_32(SPI_32(y0, y1)); #endif @@ -2900,10 +2913,13 @@ void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) ***************************************************************************************/ // Chip select stays low #if defined (ESP8266) && !defined (RPI_WRITE_STROBE) -void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) +void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) { //spi_begin(); + int32_t xe = xs + w - 1; + int32_t ye = ys + h - 1; + addr_col = 0xFFFF; addr_row = 0xFFFF; @@ -2966,10 +2982,13 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) #else //ESP32 -void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) +void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) { //spi_begin(); + int32_t xe = xs + w - 1; + int32_t ye = ys + h - 1; + addr_col = 0xFFFF; addr_row = 0xFFFF; @@ -2987,7 +3006,7 @@ void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) DC_D; - tft_Write_32(SPI_32(x0, x1)); + tft_Write_32(SPI_32(xs, xe)); // Row addr set DC_C; @@ -2996,7 +3015,7 @@ void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) DC_D; - tft_Write_32(SPI_32(y0, y1)); + tft_Write_32(SPI_32(ys, ye)); DC_C; @@ -3044,7 +3063,7 @@ void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color) #if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte uint8_t cBin[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0)}; - SPI.writePattern(&cBin[0], 4, 2); + spi.writePattern(&cBin[0], 4, 2); #else SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO); // Load the two coords as a 32 bit value and shift in one go @@ -3072,7 +3091,7 @@ void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color) #if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte uint8_t cBin[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0)}; - SPI.writePattern(&cBin[0], 4, 2); + spi.writePattern(&cBin[0], 4, 2); #else SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO); // Load the two coords as a 32 bit value and shift in one go @@ -3221,7 +3240,7 @@ void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color) #if defined (RPI_ILI9486_DRIVER) uint8_t xb[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), }; - SPI.writePattern(&xb[0], 8, 1); + spi.writePattern(&xb[0], 8, 1); #else tft_Write_32(SPI_32(x, x)); #endif @@ -3240,7 +3259,7 @@ void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color) #if defined (RPI_ILI9486_DRIVER) uint8_t yb[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), }; - SPI.writePattern(&yb[0], 8, 1); + spi.writePattern(&yb[0], 8, 1); #else tft_Write_32(SPI_32(y, y)); #endif @@ -3295,7 +3314,7 @@ void TFT_eSPI::pushColor(uint16_t color, uint32_t len) #ifdef RPI_WRITE_STROBE uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color }; - if(len) SPI.writePattern(&colorBin[0], 2, 1); len--; + if(len) spi.writePattern(&colorBin[0], 2, 1); len--; while(len--) {WR_L; WR_H;} #else #if defined (ESP32_PARALLEL) @@ -3340,7 +3359,7 @@ void TFT_eSPI::writeColor(uint16_t color, uint32_t len) { #ifdef RPI_WRITE_STROBE uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color }; - if(len) SPI.writePattern(&colorBin[0], 2, 1); len--; + if(len) spi.writePattern(&colorBin[0], 2, 1); len--; while(len--) {WR_L; WR_H;} #else #if defined (ESP32_PARALLEL) @@ -3355,7 +3374,7 @@ void TFT_eSPI::writeColor(uint16_t color, uint32_t len) ** Function name: pushColors ** Description: push an array of pixels for 16 bit raw image drawing ***************************************************************************************/ -// Assumed that setWindow() has previously been called +// Assumed that setAddrWindow() has previously been called void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) { @@ -3364,8 +3383,8 @@ void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) CS_L; #if defined (RPI_WRITE_STROBE) - while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; } - if (len) SPI.writePattern(data, len, 1); + while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; } + if (len) spi.writePattern(data, len, 1); #else #ifdef ESP32_PARALLEL while (len--) {tft_Write_8(*data); data++;} @@ -3374,10 +3393,10 @@ void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) while (len>1) {color = (*data++) | ((*data++)<<8); tft_Write_16(color); len-=2;} #else #if (SPI_FREQUENCY == 80000000) - while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; } - if (len) SPI.writePattern(data, len, 1); + while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; } + if (len) spi.writePattern(data, len, 1); #else - SPI.writeBytes(data, len); + spi.writeBytes(data, len); #endif #endif #endif @@ -3403,8 +3422,8 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap) if (swap) while ( len-- ) {tft_Write_16(*data); data++;} else while ( len-- ) {tft_Write_16S(*data); data++;} #else - if (swap) SPI.writePixels(data,len<<1); - else SPI.writeBytes((uint8_t*)data,len<<1); + if (swap) spi.writePixels(data,len<<1); + else spi.writeBytes((uint8_t*)data,len<<1); #endif #else @@ -3600,7 +3619,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t if (x0 > x1) {spi_end(); return;} - setAddrWindow(y0, x0, y0, _height); + setWindow(y0, x0, y0, _height); SPI1U1 = mask; SPI1W0 = swapped_color; for (; x0 <= x1; x0++) { @@ -3613,7 +3632,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t if ((y0 < 0) || (y0 >= _width)) break; err += dx; while(SPI1CMD & SPIBUSY) {} - setAddrWindow(y0, x0+1, y0, _height); + setWindow(y0, x0+1, y0, _height); SPI1U1 = mask; SPI1W0 = swapped_color; } @@ -3634,7 +3653,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t if (x0 > x1) {spi_end(); return;} - setAddrWindow(x0, y0, _width, y0); + setWindow(x0, y0, _width, y0); SPI1U1 = mask; SPI1W0 = swapped_color; for (; x0 <= x1; x0++) { @@ -3647,7 +3666,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t if ((y0 < 0) || (y0 >= _height)) break; err += dx; while(SPI1CMD & SPIBUSY) {} - setAddrWindow(x0+1, y0, _width, y0); + setWindow(x0+1, y0, _width, y0); SPI1U1 = mask; SPI1W0 = swapped_color; } @@ -3670,13 +3689,18 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t #if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { - // Rudimentary clipping - if ((x >= _width) || (y >= _height) || (h < 1)) return; - if ((y + h - 1) >= _height) h = _height - y; + // Clipping + if ((x < 0) || (x >= _width) || (y >= _height)) return; + + if (y < 0) { h += y; y = 0; } + + if ((y + h) > _height) h = _height - y; + + if (h < 1) return; spi_begin(); - setAddrWindow(x, y, x, y + h - 1); + setWindow(x, y, x, y + h - 1); writeBlock(color, h); @@ -3689,17 +3713,22 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { - // Rudimentary clipping - if ((x >= _width) || (y >= _height) || (h < 1)) return; - if ((y + h - 1) >= _height) h = _height - y; + // Clipping + if ((x < 0) || (x >= _width) || (y >= _height)) return; + + if (y < 0) { h += y; y = 0; } + + if ((y + h) > _height) h = _height - y; + + if (h < 1) return; spi_begin(); - setAddrWindow(x, y, x, y + h - 1); + setWindow(x, y, x, y + h - 1); #ifdef RPI_WRITE_STROBE #if defined (ESP8266) - // SPI1U1 will already be set to transfer 16 bits by setAddrWindow() + // SPI1U1 will already be set to transfer 16 bits by setWindow() SPI1W0 = (color >> 8) | (color << 8); SPI1CMD |= SPIBUSY; while(SPI1CMD & SPIBUSY) {} @@ -3729,13 +3758,18 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) #if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) { - // Rudimentary clipping - if ((x >= _width) || (y >= _height) || (w < 1)) return; - if ((x + w - 1) >= _width) w = _width - x; + // Clipping + if ((y < 0) || (x >= _width) || (y >= _height)) return; + + if (x < 0) { w += x; x = 0; } + + if ((x + w) > _width) w = _width - x; + + if (w < 1) return; spi_begin(); - setAddrWindow(x, y, x + w - 1, y); + setWindow(x, y, x + w - 1, y); writeBlock(color, w); @@ -3753,11 +3787,11 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) if ((x + w - 1) >= _width) w = _width - x; spi_begin(); - setAddrWindow(x, y, x + w - 1, y); + setWindow(x, y, x + w - 1, y); #ifdef RPI_WRITE_STROBE #if defined (ESP8266) - // SPI1U1 will already be set to transfer 16 bits by setAddrWindow() + // SPI1U1 will already be set to transfer 16 bits by setWindow() SPI1W0 = (color >> 8) | (color << 8); SPI1CMD |= SPIBUSY; while(SPI1CMD & SPIBUSY) {} @@ -3787,13 +3821,19 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) #if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { - // rudimentary clipping (drawChar w/big text requires this) - if ((x > _width) || (y > _height) || (w < 1) || (h < 1)) return; - if ((x + w - 1) > _width) w = _width - x; - if ((y + h - 1) > _height) h = _height - y; + // Clipping + if ((x >= _width) || (y >= _height)) return; + + if (x < 0) { w += x; x = 0; } + if (y < 0) { h += y; y = 0; } + + if ((x + w) > _width) w = _width - x; + if ((y + h) > _height) h = _height - y; + + if ((w < 1) || (h < 1)) return; spi_begin(); - setAddrWindow(x, y, x + w - 1, y + h - 1); + setWindow(x, y, x + w - 1, y + h - 1); writeBlock(color, w * h); @@ -3806,13 +3846,19 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { - // rudimentary clipping (drawChar w/big text requires this) - if ((x > _width) || (y > _height) || (w < 1) || (h < 1)) return; - if ((x + w - 1) > _width) w = _width - x; - if ((y + h - 1) > _height) h = _height - y; + // Clipping + if ((x >= _width) || (y >= _height)) return; + + if (x < 0) { w += x; x = 0; } + if (y < 0) { h += y; y = 0; } + + if ((x + w) > _width) w = _width - x; + if ((y + h) > _height) h = _height - y; + + if ((w < 1) || (h < 1)) return; spi_begin(); - setAddrWindow(x, y, x + w - 1, y + h - 1); + setWindow(x, y, x + w - 1, y + h - 1); uint32_t n = (uint32_t)w * (uint32_t)h; @@ -3906,6 +3952,10 @@ size_t TFT_eSPI::write(uint8_t utf8) if(fontLoaded) { uint16_t unicode = decodeUTF8(utf8); + + //Serial.print("UniCode="); Serial.println(unicode); + //Serial.print("UTF8 ="); Serial.println(utf8); + if (!unicode) return 1; //fontFile = SPIFFS.open( _gFontFilename, "r" ); @@ -4176,7 +4226,7 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font) // Faster drawing of characters and background using block write { spi_begin(); - setAddrWindow(x, y, (x + w * 8) - 1, y + height - 1); + setWindow(x, y, (x + w * 8) - 1, y + height - 1); uint8_t mask; for (int i = 0; i < height; i++) @@ -4238,7 +4288,7 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font) } while (line--) { // In this case the while(line--) is faster pc++; // This is faster than putting pc+=line before while()? - setAddrWindow(px, py, px + ts, py + ts); + setWindow(px, py, px + ts, py + ts); if (ts) { tnp = np; @@ -4267,7 +4317,7 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font) // so use faster drawing of characters and background using block write { //spi_begin(); - setAddrWindow(x, y, x + width - 1, y + height - 1); + setWindow(x, y, x + width - 1, y + height - 1); #ifdef RPI_WRITE_STROBE uint8_t textcolorBin[] = { (uint8_t) (textcolor >> 8), (uint8_t) textcolor }; @@ -4282,7 +4332,7 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font) line &= 0x7F; line++; w -= line; #ifdef RPI_WRITE_STROBE - SPI.writePattern(&textcolorBin[0], 2, 1); line--; + spi.writePattern(&textcolorBin[0], 2, 1); line--; while(line--) {WR_L; WR_H;} #else #ifdef ESP32_PARALLEL @@ -4295,7 +4345,7 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font) else { line++; w -= line; #ifdef RPI_WRITE_STROBE - SPI.writePattern(&textbgcolorBin[0], 2, 1); line--; + spi.writePattern(&textbgcolorBin[0], 2, 1); line--; while(line--) {WR_L; WR_H;} #else #ifdef ESP32_PARALLEL @@ -4927,56 +4977,56 @@ void writeBlock(uint16_t color, uint32_t repeat) if (repeat > 19) { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); + SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); while(repeat>19) { - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W1_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W2_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W3_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W4_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W5_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W6_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W7_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W8_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W9_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W10_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W11_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W12_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W13_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W14_REG(SPI_NUM), r2); - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); + 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); + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); repeat -= 20; } - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); } if (repeat) { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, (repeat * 24) - 1, SPI_USR_MOSI_DBITLEN_S); - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W1_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W2_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W3_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W4_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W5_REG(SPI_NUM), r2); + SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (repeat * 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 (repeat > 8 ) { - WRITE_PERI_REG(SPI_W6_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W7_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W8_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W9_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W10_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W11_REG(SPI_NUM), r2); - WRITE_PERI_REG(SPI_W12_REG(SPI_NUM), r0); - WRITE_PERI_REG(SPI_W13_REG(SPI_NUM), r1); - WRITE_PERI_REG(SPI_W14_REG(SPI_NUM), 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); } - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); } } @@ -4990,39 +5040,39 @@ void writeBlock(uint16_t color, uint32_t repeat) if (repeat > 31) // Revert legacy toggle buffer change { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), 511); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); while(repeat>31) { - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W1_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W2_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W3_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W4_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W5_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W6_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W7_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W8_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W9_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W10_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W11_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W12_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W13_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W14_REG(SPI_NUM), color32); - WRITE_PERI_REG(SPI_W15_REG(SPI_NUM), color32); - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), color32); + WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), color32); + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); repeat -= 32; } - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); } if (repeat) { // Revert toggle buffer change - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), (repeat << 4) - 1); - for (uint32_t i=0; i <= (repeat>>1); i++) WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + (i << 2)), color32); - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (repeat << 4) - 1); + for (uint32_t i=0; i <= (repeat>>1); i++) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + (i << 2)), color32); + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); } } #endif diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 1422fb4..5e471e9 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -105,7 +105,11 @@ #ifdef ESP32 #include "soc/spi_reg.h" - #define SPI_NUM 0x3 + #ifdef USE_HSPI_PORT + #define SPI_PORT HSPI + #else + #define SPI_PORT VSPI + #endif #endif #ifdef SMOOTH_FONT @@ -312,32 +316,32 @@ #elif defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB // Write 8 bits to TFT - #define tft_Write_8(C) SPI.transfer(C) + #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) + #define tft_Write_16(C) spi.transfer((C & 0xF800)>>8); \ + spi.transfer((C & 0x07E0)>>3); \ + spi.transfer((C & 0x001F)<<3) // 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 & 0xE0)>>11 | (C & 0x07)<<5); \ - SPI.transfer((C & 0x1F00)>>5) + #define tft_Write_16S(C) spi.transfer(C & 0xF8); \ + spi.transfer((C & 0xE0)>>11 | (C & 0x07)<<5); \ + spi.transfer((C & 0x1F00)>>5) // Write 32 bits to TFT - #define tft_Write_32(C) SPI.write32(C) + #define tft_Write_32(C) spi.write32(C) #elif defined (RPI_ILI9486_DRIVER) - #define tft_Write_8(C) SPI.transfer(0); SPI.transfer(C) - #define tft_Write_16(C) SPI.write16(C) - #define tft_Write_16S(C) SPI.write16(C<<8 | C>>8) - #define tft_Write_32(C) SPI.write32(C) + #define tft_Write_8(C) spi.transfer(0); spi.transfer(C) + #define tft_Write_16(C) spi.write16(C) + #define tft_Write_16S(C) spi.write16(C<<8 | C>>8) + #define tft_Write_32(C) spi.write32(C) #elif defined ESP8266 - #define tft_Write_8(C) SPI.write(C) - #define tft_Write_16(C) SPI.write16(C) - #define tft_Write_32(C) SPI.write32(C) + #define tft_Write_8(C) spi.write(C) + #define tft_Write_16(C) spi.write16(C) + #define tft_Write_32(C) spi.write32(C) #else // ESP32 using SPI with 16 bit color display @@ -346,31 +350,31 @@ // Write 8 bits #define tft_Write_8(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), 8-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 8-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); // Write 16 bits with corrected endianess for 16 bit colours #define tft_Write_16(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), 16-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), C<<8 | C>>8); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 16-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C<<8 | C>>8); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); // Write 16 bits #define tft_Write_16S(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), 16-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 16-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); // Write 32 bits #define tft_Write_32(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_NUM), 32-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_NUM), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR); + WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 32-1); \ + WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ + SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ + while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); #endif @@ -383,7 +387,7 @@ #define SCLK_H GPOS=sclkpinmask #else // Use a SPI read transfer - #define tft_Read_8() SPI.transfer(0) + #define tft_Read_8() spi.transfer(0) #endif #endif @@ -650,7 +654,7 @@ class TFT_eSPI : public Print { width(void); // The TFT_eSprite class inherits the following functions - void setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1), + void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye), pushColor(uint16_t color), pushColor(uint16_t color, uint32_t len), pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option @@ -776,12 +780,12 @@ class TFT_eSPI : public Print { fontHeight(int16_t font), fontHeight(void); - void setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); + void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); - // These 3 functions are used together, for every startWrite() there must be an endWrite() - void startWrite(void); // Begin SPI transaction - void writeColor(uint16_t color, uint32_t len); // Write a colour without transaction overhead - void endWrite(void); // End SPI transaction + // Compatibility additions (non-essential) + void startWrite(void); // Begin SPI transaction (not normally needed) + void writeColor(uint16_t color, uint32_t len); // Write colours without transaction overhead + void endWrite(void); // End SPI transaction size_t write(uint8_t); @@ -816,7 +820,7 @@ class TFT_eSPI : public Print { inline void spi_begin_read() __attribute__((always_inline)); inline void spi_end_read() __attribute__((always_inline)); - void readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); + void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); uint8_t tabcolor, colstart = 0, rowstart = 0; // some ST7735 displays need this changed diff --git a/User_Setup.h b/User_Setup.h index 6a5531e..b581333 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -262,6 +262,10 @@ // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: #define SPI_TOUCH_FREQUENCY 2500000 +// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. +// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) +// then uncomment the following line: +//#define USE_HSPI_PORT // Comment out the following #define if "SPI Transactions" do not need to be // supported. When commented out the code size will be smaller and sketches will diff --git a/User_Setups/SetupX_Template.h b/User_Setups/SetupX_Template.h index 6a5531e..36a2372 100644 --- a/User_Setups/SetupX_Template.h +++ b/User_Setups/SetupX_Template.h @@ -262,6 +262,10 @@ // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: #define SPI_TOUCH_FREQUENCY 2500000 +// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. +// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) +// then uncomment the following line to use the HSPI port: +//#define USE_HSPI_PORT // Comment out the following #define if "SPI Transactions" do not need to be // supported. When commented out the code size will be smaller and sketches will diff --git a/examples/160 x 128/Pong_v3/Pong_v3.ino b/examples/160 x 128/Pong_v3/Pong_v3.ino index 7c51299..318c851 100644 --- a/examples/160 x 128/Pong_v3/Pong_v3.ino +++ b/examples/160 x 128/Pong_v3/Pong_v3.ino @@ -107,13 +107,17 @@ void midline() { // If the ball is not on the line then don't redraw the line if ((ball_x dashline_x+dashline_w)) return; + tft.startWrite(); + // Quick way to draw a dashed line - tft.setAddrWindow(dashline_x,0,dashline_x+dashline_w-1,h); + tft.setAddrWindow(dashline_x, 0, dashline_w, h); for(int16_t i = 0; i < dashline_n; i+=2) { tft.pushColor(WHITE, dashline_w*dashline_h); // push dash pixels tft.pushColor(BLACK, dashline_w*dashline_h); // push gap pixels } + + tft.endWrite(); } void lpaddle() { diff --git a/examples/160 x 128/TFT_graphicstest_PDQ3/TFT_graphicstest_PDQ3.ino b/examples/160 x 128/TFT_graphicstest_PDQ3/TFT_graphicstest_PDQ3.ino index 325b9a4..148499e 100644 --- a/examples/160 x 128/TFT_graphicstest_PDQ3/TFT_graphicstest_PDQ3.ino +++ b/examples/160 x 128/TFT_graphicstest_PDQ3/TFT_graphicstest_PDQ3.ino @@ -308,14 +308,16 @@ uint32_t testHaD() 0x0a, 0x2b, 0x0b, 0x41, 0x0a, 0x29, 0x0b, 0x43, 0x0a, 0x27, 0x0a, 0x46, 0x0a, 0x25, 0x0a, 0x49, 0x09, 0x23, 0x08, 0x4e, 0x08, 0x96, 0x12 }; - + tft.fillScreen(TFT_BLACK); uint32_t start = micros_start(); - + + tft.startWrite(); + for (int i = 0; i < 0x10; i++) { - tft.setAddrWindow(0, 0, tft.width()-1, tft.height()-1); + tft.setAddrWindow(0, 0, tft.width(), tft.height()); uint16_t cnt = 0; uint16_t color = tft.color565((i << 4) | i, (i << 4) | i, (i << 4) | i); @@ -335,6 +337,8 @@ uint32_t testHaD() } } + tft.endWrite(); + uint32_t t = micros() - start; tft.setTextColor(TFT_YELLOW); diff --git a/examples/320 x 240/TFT_Mandlebrot/TFT_Mandlebrot.ino b/examples/320 x 240/TFT_Mandlebrot/TFT_Mandlebrot.ino index 73e0afc..2a04556 100644 --- a/examples/320 x 240/TFT_Mandlebrot/TFT_Mandlebrot.ino +++ b/examples/320 x 240/TFT_Mandlebrot/TFT_Mandlebrot.ino @@ -7,7 +7,7 @@ TFT_eSPI tft = TFT_eSPI(); // Invoke custom library -#define ILI9341_GREY 0x7BEF +#define TFT_GREY 0x7BEF unsigned long runTime = 0; @@ -16,8 +16,9 @@ uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0; void setup() { + Serial.begin(250000); //randomSeed(analogRead(A0)); - + Serial.println(); // Setup the LCD tft.init(); tft.setRotation(3); @@ -27,7 +28,8 @@ void loop() { runTime = millis(); - tft.fillScreen(ILI9341_BLACK); + tft.fillScreen(TFT_BLACK); + tft.startWrite(); for (int px = 1; px < 320; px++) { for (int py = 0; py < 240; py++) @@ -49,6 +51,9 @@ void loop() yield();tft.drawPixel(px, py, color); } } + tft.endWrite(); + + Serial.println(millis()-runTime); while(1) yield(); } diff --git a/examples/320 x 240/TFT_Pong/TFT_Pong.ino b/examples/320 x 240/TFT_Pong/TFT_Pong.ino index 6cf91f2..5bcd880 100644 --- a/examples/320 x 240/TFT_Pong/TFT_Pong.ino +++ b/examples/320 x 240/TFT_Pong/TFT_Pong.ino @@ -108,13 +108,17 @@ void midline() { // If the ball is not on the line then don't redraw the line if ((ball_x dashline_x+dashline_w)) return; + tft.startWrite(); + // Quick way to draw a dashed line - tft.setWindow(dashline_x,0,dashline_x+dashline_w-1,h); + tft.setAddrWindow(dashline_x, 0, dashline_w, h); for(int16_t i = 0; i < dashline_n; i+=2) { tft.pushColor(WHITE, dashline_w*dashline_h); // push dash pixels tft.pushColor(BLACK, dashline_w*dashline_h); // push gap pixels } + + tft.endWrite(); } void lpaddle() { diff --git a/examples/320 x 240/TFT_graphicstest_PDQ/TFT_graphicstest_PDQ.ino b/examples/320 x 240/TFT_graphicstest_PDQ/TFT_graphicstest_PDQ.ino index 7db002e..8e03ef5 100644 --- a/examples/320 x 240/TFT_graphicstest_PDQ/TFT_graphicstest_PDQ.ino +++ b/examples/320 x 240/TFT_graphicstest_PDQ/TFT_graphicstest_PDQ.ino @@ -336,10 +336,10 @@ uint32_t testHaD() tft.fillScreen(TFT_BLACK); uint32_t start = micros_start(); - + for (int i = 0; i < 0x10; i++) { - tft.setWindow(0, 0, 240-1, 320-1); + tft.setAddrWindow(0, 0, 240, 320); uint16_t cnt = 0; uint16_t color = tft.color565((i << 4) | i, (i << 4) | i, (i << 4) | i); @@ -347,6 +347,7 @@ uint32_t testHaD() const uint8_t *cmp = &HaD_240x320[0]; + tft.startWrite(); while (cmp < &HaD_240x320[sizeof(HaD_240x320)]) { cnt = pgm_read_byte(cmp++); @@ -354,6 +355,7 @@ uint32_t testHaD() tft.pushColor(curcolor, cnt); // PDQ_GFX has count curcolor ^= color; } + tft.endWrite(); } uint32_t t = micros() - start; diff --git a/examples/480 x 320/TFT_flash_jpg/TFT_flash_jpg.ino b/examples/480 x 320/TFT_flash_jpg/TFT_flash_jpg.ino index 5af0f13..f8ebcb1 100644 --- a/examples/480 x 320/TFT_flash_jpg/TFT_flash_jpg.ino +++ b/examples/480 x 320/TFT_flash_jpg/TFT_flash_jpg.ino @@ -171,11 +171,14 @@ void renderJPEG(int xpos, int ypos) { // calculate how many pixels must be drawn uint32_t mcu_pixels = win_w * win_h; + tft.startWrite(); + // draw image MCU block only if it will fit on the screen if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()) { + // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) - tft.setWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); + tft.setAddrWindow(mcu_x, mcu_y, win_w, win_h); // Write all MCU pixels to the TFT window while (mcu_pixels--) { @@ -185,6 +188,8 @@ void renderJPEG(int xpos, int ypos) { } else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding + + tft.endWrite(); } // calculate how long it took to draw the image diff --git a/examples/480 x 320/TFT_ring_meter/TFT_ring_meter.ino b/examples/480 x 320/TFT_ring_meter/TFT_ring_meter.ino index ebed42b..d4d8c2f 100644 --- a/examples/480 x 320/TFT_ring_meter/TFT_ring_meter.ino +++ b/examples/480 x 320/TFT_ring_meter/TFT_ring_meter.ino @@ -251,8 +251,10 @@ void drawIcon(const unsigned short* icon, int16_t x, int16_t y, int8_t width, in uint16_t pix_buffer[BUFF_SIZE]; // Pixel buffer (16 bits per pixel) + tft.startWrite(); + // Set up a window the right size to stream pixels into - tft.setWindow(x, y, x + width - 1, y + height - 1); + tft.setAddrWindow(x, y, width, height); // Work out the number whole buffers to send uint16_t nb = ((uint16_t)height * width) / BUFF_SIZE; @@ -273,5 +275,7 @@ void drawIcon(const unsigned short* icon, int16_t x, int16_t y, int8_t width, in for (int i = 0; i < np; i++) pix_buffer[i] = pgm_read_word(&icon[nb * BUFF_SIZE + i]); tft.pushColors(pix_buffer, np); } + + tft.endWrite(); } diff --git a/library.json b/library.json index 640cef0..d32cf0c 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "1.3.13", + "version": "1.4.0", "keywords": "tft, ePaper, display, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789", "description": "A TFT and ePaper SPI graphics library for ESP8266 and ESP32", "repository": diff --git a/library.properties b/library.properties index 7f4f52c..834703f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=1.3.13 +version=1.4.0 author=Bodmer maintainer=Bodmer sentence=A fast TFT graphics library for ESP8266 and ESP32 processors for the Arduino IDE