diff --git a/Processors/TFT_eSPI_RP2040.c b/Processors/TFT_eSPI_RP2040.c index bfe0907..0e942cd 100644 --- a/Processors/TFT_eSPI_RP2040.c +++ b/Processors/TFT_eSPI_RP2040.c @@ -220,22 +220,10 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ ** Description: Write a block of pixels of the same colour ***************************************************************************************/ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - bool loaded = false; - uint16_t colorBuf[64]; - const uint16_t* colorPtr = colorBuf; - if (len>63) { - loaded = true; - for (uint32_t i = 0; i < 64; i++) colorBuf[i] = color; - while(len>63) { - spi_write16_blocking(spi0, (const uint16_t*)colorPtr, 64); - len -=64; - } - } - - if (len) { - if (!loaded) for (uint32_t i = 0; i < len; i++) colorBuf[i] = color; - spi_write16_blocking(spi0, (const uint16_t*)colorPtr, len); + while(len--) + { + while (!spi_is_writable(spi0)){}; + spi_get_hw(spi0)->dr = (uint32_t)color; } } @@ -244,14 +232,23 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ ** 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) { - spi_write16_blocking(spi0, (const uint16_t*)data_in, len); + while(len--) + { + while (!spi_is_writable(spi0)){}; + spi_get_hw(spi0)->dr = (uint32_t)(*data++); + } } - else { - spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); - spi_write_blocking(spi0, (const uint8_t*)data_in, len * 2); - spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + else + { + while(len--) + { + uint16_t color = *data++; + color = color >> 8 | color << 8; + while (!spi_is_writable(spi0)){}; + spi_get_hw(spi0)->dr = (uint32_t)color; + } } } diff --git a/Processors/TFT_eSPI_RP2040.h b/Processors/TFT_eSPI_RP2040.h index 3282b68..f1c8908 100644 --- a/Processors/TFT_eSPI_RP2040.h +++ b/Processors/TFT_eSPI_RP2040.h @@ -14,13 +14,17 @@ // Include processor specific header // None -// Processor specific code used by SPI bus transaction startWrite and endWrite functions -#define SET_BUS_WRITE_MODE // Not used -#define SET_BUS_READ_MODE // Not used +// Processor specific code used by SPI bus transaction begin/end_tft_write functions +#define SET_BUS_WRITE_MODE spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) +#define SET_BUS_READ_MODE // spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) // Code to check if SPI or DMA is busy, used by SPI bus transaction startWrite and/or endWrite functions #define DMA_BUSY_CHECK // Not used so leave blank -#define SPI_BUSY_CHECK // Not used so leave blank + +// Wait for tx to end, flush rx FIFO, clear rx overrun +#define SPI_BUSY_CHECK while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; \ + while (spi_is_readable(spi0)) (void)spi_get_hw(spi0)->dr; \ + spi_get_hw(spi0)->icr = SPI_SSPICR_RORIC_BITS // To be safe, SUPPORT_TRANSACTIONS is assumed mandatory #if !defined (SUPPORT_TRANSACTIONS) @@ -28,7 +32,7 @@ #endif // Initialise processor specific SPI functions, used by init() -#define INIT_TFT_DATA_BUS +#define INIT_TFT_DATA_BUS // Not used // If smooth fonts are enabled the filing system may need to be loaded #ifdef SMOOTH_FONT @@ -150,18 +154,27 @@ spi.transfer(0); spi.transfer((C)>>0) #else - #define tft_Write_8(C) spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); \ - _Cbuf = (C); spi_write_blocking(spi0, (const uint8_t*)&(_Cbuf), 1); \ - spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) - #define tft_Write_16(C) _Cbuf = (C); spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 1) - #define tft_Write_16N(C) _Cbuf = (C); spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 1) - #define tft_Write_16S(C) _Cbuf = (C)<<8 | (C)>>8; spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 1) - #define tft_Write_32(C) _Cbuf = (C); spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 2) + // This swaps to 8 bit mode, then back to 16 bit mode + #define tft_Write_8(C) while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; \ + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); \ + spi_get_hw(spi0)->dr = (uint32_t)(C); \ + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; \ + spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) - #define tft_Write_32C(C,D) _Cbuf = (C) | (D) << 16; spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 2) + // Note: the following macros do not wait for the end of transmission - #define tft_Write_32D(C) _Cbuf = (C) | (C) << 16; spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 2) + #define tft_Write_16(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C) + + #define tft_Write_16N(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C) + + #define tft_Write_16S(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C)<<8 | (C)>>8 + + #define tft_Write_32(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)((C)>>8);spi_get_hw(spi0)->dr = (uint32_t)(C) + + #define tft_Write_32C(C,D) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C);spi_get_hw(spi0)->dr = (uint32_t)(D) + + #define tft_Write_32D(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C);spi_get_hw(spi0)->dr = (uint32_t)(C) #endif // RPI_DISPLAY_TYPE #endif diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 154e4dd..1ddd9b3 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2,7 +2,7 @@ Arduino TFT graphics library targeted at 32 bit processors such as ESP32, ESP8266 and STM32. - This is a standalone library that contains the + This is a stand-alone library that contains the hardware driver, the graphics functions and the proportional fonts. @@ -22,7 +22,7 @@ #include "Processors/TFT_eSPI_ESP8266.c" #elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h #include "Processors/TFT_eSPI_STM32.c" -#elif defined (RP2040) // Raspberry Pi Pico +#elif defined (ARDUINO_ARCH_RP2040) // Raspberry Pi Pico #include "Processors/TFT_eSPI_RP2040.c" #else #include "Processors/TFT_eSPI_Generic.c" @@ -56,10 +56,10 @@ inline void TFT_eSPI::begin_tft_write(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) if (locked) { - locked = false; - spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); + locked = false; // Flag to show SPI access now unlocked + spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); // RP2040 SDK -> 68us delay! CS_L; - SET_BUS_WRITE_MODE; + SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used } #else CS_L; @@ -74,16 +74,17 @@ inline void TFT_eSPI::begin_tft_write(void){ ***************************************************************************************/ inline void TFT_eSPI::end_tft_write(void){ #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) - if(!inTransaction) { - if (!locked) { - locked = true; + if(!inTransaction) { // Flag to stop ending tranaction during multiple graphics calls + if (!locked) { // Locked when beginTransaction has been called + locked = true; // Flag to show SPI access now locked + SPI_BUSY_CHECK; // Check send complete and clean out unused rx data CS_H; - spi.endTransaction(); + spi.endTransaction(); // RP2040 SDK -> 0.7us delay } - SET_BUS_READ_MODE; + SET_BUS_READ_MODE; // In case SPI has been configured for tx only } #else - if(!inTransaction) {CS_H; SET_BUS_READ_MODE;} + if(!inTransaction) {SPI_BUSY_CHECK; CS_H; SET_BUS_READ_MODE;} #endif } @@ -435,12 +436,13 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _swapBytes = false; // Do not swap colour bytes by default - locked = true; // Transaction mutex lock flags - inTransaction = false; + locked = true; // Transaction mutex lock flag to ensure begin/endTranaction pairing + inTransaction = false; // Flag to prevent multiple sequential functions to keep bus access open + lockTransaction = false; // start/endWrite lock flag to allow sketch to keep SPI bus access open _booted = true; // Default attributes - _cp437 = true; - _utf8 = true; + _cp437 = true; // Legacy GLCD font bug fix + _utf8 = true; // UTF8 decoding enabled #ifdef FONT_FS_AVAILABLE fs_font = true; // Smooth font filing system or array (fs_font = false) flag @@ -452,17 +454,19 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) #endif _psram_enable = false; - addr_row = 0xFFFF; - addr_col = 0xFFFF; + addr_row = 0xFFFF; // drawPixel command length optimiser + addr_col = 0xFFFF; // drawPixel command length optimiser _xPivot = 0; _yPivot = 0; +// Legacy support for bit GPIO masks cspinmask = 0; dcpinmask = 0; wrpinmask = 0; sclkpinmask = 0; +// Flags for which fonts are loaded #ifdef LOAD_GLCD fontsloaded = 0x0002; // Bit 1 set #endif @@ -515,7 +519,8 @@ void TFT_eSPI::init(uint8_t tc) { if (_booted) { -#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040) +#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) && !defined(ARDUINO_ARCH_RP2040) + // Legacy bitmasks for GPIO #if defined (TFT_CS) && (TFT_CS >= 0) cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); #endif @@ -543,14 +548,14 @@ void TFT_eSPI::init(uint8_t tc) #else #if !defined(TFT_PARALLEL_8_BIT) - #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) && !defined(RP2040) + #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) && !defined(ARDUINO_ARCH_RP2040) spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); #else spi.begin(); #endif #endif #endif - + lockTransaction = false; inTransaction = false; locked = true; @@ -559,7 +564,7 @@ void TFT_eSPI::init(uint8_t tc) #ifdef TFT_CS - // Set to output once again in case D6 (MISO) is used for CS + // Set to output once again in case ESP8266 D6 (MISO) is used for CS pinMode(TFT_CS, OUTPUT); digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) #elif defined (ESP8266) && !defined (TFT_PARALLEL_8_BIT) @@ -568,7 +573,7 @@ void TFT_eSPI::init(uint8_t tc) - // Set to output once again in case D6 (MISO) is used for DC + // Set to output once again in case ESP8266 D6 (MISO) is used for DC #ifdef TFT_DC pinMode(TFT_DC, OUTPUT); digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode @@ -1121,6 +1126,11 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da #else // SPI interface + // This function can get called after a begin_tft_write + // so a transaction may be in progress + bool wasInTransaction = inTransaction; + if (inTransaction) { inTransaction= false; end_tft_write();} + uint16_t color = 0; begin_tft_read(); @@ -1180,6 +1190,8 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da end_tft_read(); + // Reinstate the transaction if one was in progress + if(wasInTransaction) { begin_tft_write(); inTransaction = true; } #endif } @@ -1222,7 +1234,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1280,7 +1292,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d data += w; } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1311,7 +1323,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 pushPixels(buffer, dw); } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1367,7 +1379,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 data += w; } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1500,7 +1512,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da } _swapBytes = swap; // Restore old value - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1702,7 +1714,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da } } _swapBytes = swap; // Restore old value - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -1865,7 +1877,7 @@ void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) xs = xe; } while (xe < --r); - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -1934,7 +1946,7 @@ void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t rr, uint8_t cor } xs = xe; } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -1975,7 +1987,7 @@ void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2059,7 +2071,7 @@ void TFT_eSPI::drawEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint1 s += rx2 * ((4 * y) + 6); } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2104,7 +2116,7 @@ void TFT_eSPI::fillEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint1 s += rx2 * ((4 * y) + 6); } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2135,7 +2147,7 @@ void TFT_eSPI::drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col drawFastVLine(x, y+1, h-2, color); drawFastVLine(x + w - 1, y+1, h-2, color); - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2161,7 +2173,7 @@ void TFT_eSPI::drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); drawCircleHelper(x + r , y + h - r - 1, r, 8, color); - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2183,7 +2195,7 @@ void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color); fillCircleHelper(x + r , y + r, r, 2, w - r - r - 1, color); - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2202,7 +2214,7 @@ void TFT_eSPI::drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int3 drawLine(x1, y1, x2, y2, color); drawLine(x2, y2, x0, y0, color); - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2283,7 +2295,7 @@ void TFT_eSPI::fillTriangle ( int32_t x0, int32_t y0, int32_t x1, int32_t y1, in drawFastHLine(a, y, b - a + 1, color); } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2307,7 +2319,7 @@ void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2331,7 +2343,7 @@ void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2354,7 +2366,7 @@ void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2378,7 +2390,7 @@ void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2787,7 +2799,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 } } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } @@ -2849,7 +2861,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } #endif @@ -2911,7 +2923,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) DC_C; tft_Write_8(TFT_RAMWR); DC_D; -#else +#else // Not ILI9225 #if defined (SSD1963_DRIVER) if ((rotation & 0x1) == 0) { swap_coord(x0, y0); swap_coord(x1, y1); } @@ -2927,14 +2939,50 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) y1+=rowstart; #endif - DC_C; tft_Write_8(TFT_CASET); - DC_D; tft_Write_32C(x0, x1); - DC_C; tft_Write_8(TFT_PASET); - DC_D; tft_Write_32C(y0, y1); - DC_C; tft_Write_8(TFT_RAMWR); - DC_D; + // Temporary solution is to include the RP2040 optimised code here + #if defined(ARDUINO_ARCH_RP2040) && !defined(TFT_PARALLEL_8BIT) + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + spi_get_hw(spi0)->dr = (uint32_t)TFT_CASET; - //end_tft_write(); // Must be called after setWindow + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)x0>>8; + spi_get_hw(spi0)->dr = (uint32_t)x0; + spi_get_hw(spi0)->dr = (uint32_t)x1>>8; + spi_get_hw(spi0)->dr = (uint32_t)x1; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_PASET; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)y0>>8; + spi_get_hw(spi0)->dr = (uint32_t)y0; + spi_get_hw(spi0)->dr = (uint32_t)y1>>8; + spi_get_hw(spi0)->dr = (uint32_t)y1; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_RAMWR; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + DC_D; + + #else + + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32C(x0, x1); + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32C(y0, y1); + DC_C; tft_Write_8(TFT_RAMWR); + DC_D; + //end_tft_write(); // Must be called after setWindow + + #endif // RP2040 SPI #endif } @@ -2964,6 +3012,44 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) if ((rotation & 0x1) == 0) { swap_coord(xs, ys); swap_coord(xe, ye); } #endif + // Temporary solution is to include the RP2040 optimised code here +#if defined(ARDUINO_ARCH_RP2040) && !defined(TFT_PARALLEL_8BIT) + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + spi_get_hw(spi0)->dr = (uint32_t)TFT_CASET; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)xs>>8; + spi_get_hw(spi0)->dr = (uint32_t)xs; + spi_get_hw(spi0)->dr = (uint32_t)xe>>8; + spi_get_hw(spi0)->dr = (uint32_t)xe; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_PASET; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)ys>>8; + spi_get_hw(spi0)->dr = (uint32_t)ys; + spi_get_hw(spi0)->dr = (uint32_t)ye>>8; + spi_get_hw(spi0)->dr = (uint32_t)ye; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_RAMRD; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + //spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + DC_D; + + // Flush the rx buffer and reset overflow flag + while (spi_is_readable(spi0)) (void)spi_get_hw(spi0)->dr; + spi_get_hw(spi0)->icr = SPI_SSPICR_RORIC_BITS; + +#else // Column addr set DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(xs, xe); @@ -2976,6 +3062,7 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) DC_C; tft_Write_8(TFT_RAMRD); DC_D; +#endif // RP2040 SPI //end_tft_write(); // Must be called after readAddrWindow or CS set high } @@ -3030,6 +3117,63 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_C; tft_Write_8(TFT_RAMWR); DC_D; tft_Write_16(color); + // Temporary solution is to include the RP2040 optimised code here +#elif defined (ARDUINO_ARCH_RP2040) + + // Since the SPI functions do not terminate until transmission is complete + // a busy check is not needed. + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + spi_get_hw(spi0)->dr = (uint32_t)TFT_CASET; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS){}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)x>>8; + spi_get_hw(spi0)->dr = (uint32_t)x; + spi_get_hw(spi0)->dr = (uint32_t)x>>8; + spi_get_hw(spi0)->dr = (uint32_t)x; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_PASET; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)y>>8; + spi_get_hw(spi0)->dr = (uint32_t)y; + spi_get_hw(spi0)->dr = (uint32_t)y>>8; + spi_get_hw(spi0)->dr = (uint32_t)y; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_C; + spi_get_hw(spi0)->dr = (uint32_t)TFT_RAMWR; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)color>>8; + spi_get_hw(spi0)->dr = (uint32_t)color; + +/* + // Subsequent pixel reads work OK without draining the FIFO... + // Drain RX FIFO, then wait for shifting to finish (which may be *after* + // TX FIFO drains), then drain RX FIFO again + while (spi_is_readable(spi0)) + (void)spi_get_hw(spi0)->dr; + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) + tight_loop_contents(); + while (spi_is_readable(spi0)) + (void)spi_get_hw(spi0)->dr; +//*/ + +// Subsequent pixel reads work without this +// spi_get_hw(spi0)->icr = SPI_SSPICR_RORIC_BITS; + + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + + // Next call will start with 8 bit command so changing to 16 bit not needed here + //spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + #else #if defined (SSD1963_DRIVER) @@ -3058,7 +3202,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) } #endif DC_C; tft_Write_8(TFT_RAMWR); - DC_D; tft_Write_16(color); + DC_D; tft_Write_16(color); #endif end_tft_write(); @@ -3098,6 +3242,7 @@ void TFT_eSPI::pushColor(uint16_t color, uint32_t len) void TFT_eSPI::startWrite(void) { begin_tft_write(); + lockTransaction = true; // Lock transaction for all sequentially run sketch functions inTransaction = true; } @@ -3107,9 +3252,10 @@ void TFT_eSPI::startWrite(void) ***************************************************************************************/ void TFT_eSPI::endWrite(void) { + lockTransaction = false; // Release sketch induced transaction lock inTransaction = false; - DMA_BUSY_CHECK; // Safety check - user code should have checked this! - end_tft_write(); + DMA_BUSY_CHECK; // Safety check - user code should have checked this! + end_tft_write(); // Release SPI bus } /*************************************************************************************** @@ -3217,7 +3363,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t if (dlen) drawFastHLine(xs, y0, dlen, color); } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } @@ -3861,7 +4007,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) pY += textsize; } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } else { // Faster drawing of characters and background using block write @@ -4006,7 +4152,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } } } - inTransaction = false; + inTransaction = lockTransaction; end_tft_write(); } // End of RLE font rendering diff --git a/TFT_eSPI.h b/TFT_eSPI.h index d101555..be7cfcc 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -2,7 +2,7 @@ Arduino TFT graphics library targeted at ESP8266 and ESP32 based boards. - This is a standalone library that contains the + This is a stand-alone library that contains the hardware driver, the graphics functions and the proportional fonts. @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.3.62" +#define TFT_ESPI_VERSION "2.3.63" // Bit level feature flags // Bit 0 set: viewport capability @@ -54,7 +54,7 @@ #include "Processors/TFT_eSPI_ESP8266.h" #elif defined (STM32) #include "Processors/TFT_eSPI_STM32.h" -#elif defined (RP2040) +#elif defined(ARDUINO_ARCH_RP2040) #include "Processors/TFT_eSPI_RP2040.h" #else #include "Processors/TFT_eSPI_Generic.h" @@ -690,13 +690,13 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // 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)); + 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)); + inline void begin_tft_read() __attribute__((always_inline)); + inline void end_tft_read() __attribute__((always_inline)); // Temporary library development function TODO: remove need for this void pushSwapBytePixels(const void* data_in, uint32_t len); @@ -765,7 +765,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac 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 locked, inTransaction; // SPI transaction and mutex lock flags + bool locked, inTransaction, lockTransaction; // SPI transaction and mutex lock flags bool _booted; // init() or begin() has already run once @@ -775,7 +775,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac bool _psram_enable; // Enable PSRAM use for library functions (TBD) and Sprites uint32_t _lastColor; // Buffered value of last colour used - uint32_t _Cbuf; // SPI buffer for RP2040 #ifdef LOAD_GFXFF GFXfont *gfxFont; diff --git a/User_Setup.h b/User_Setup.h index ae9343b..cb5bda3 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -15,9 +15,6 @@ // // ################################################################################## -// Define RP2040 to invoke optimised processor support (only for RP2040) -//#define RP2040 - // Define STM32 to invoke optimised processor support (only for STM32) //#define STM32 diff --git a/User_Setups/Setup60_RP2040_ILI9341.h b/User_Setups/Setup60_RP2040_ILI9341.h index fa5fc25..42402cb 100644 --- a/User_Setups/Setup60_RP2040_ILI9341.h +++ b/User_Setups/Setup60_RP2040_ILI9341.h @@ -15,9 +15,6 @@ // // ################################################################################## -// Define RP2040 to invoke optimised processor support (only for RP2040) -#define RP2040 - // Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) //#define TFT_PARALLEL_8_BIT @@ -177,7 +174,7 @@ // #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 20000000 // #define SPI_FREQUENCY 32000000 - #define SPI_FREQUENCY 63000000 + #define SPI_FREQUENCY 70000000 // Optional reduced SPI frequency for reading TFT #define SPI_READ_FREQUENCY 20000000 @@ -185,11 +182,3 @@ // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: #define SPI_TOUCH_FREQUENCY 2500000 -// 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 -// run slightly faster, so leave it commented out unless you need it! - -// Transaction support is needed to work with SD library but not needed with TFT_SdFat -// Transaction support is required if other SPI devices are connected. - -// #define SUPPORT_TRANSACTIONS diff --git a/examples/Test and diagnostics/TFT_ReadWrite_Test/TFT_ReadWrite_Test.ino b/examples/Test and diagnostics/TFT_ReadWrite_Test/TFT_ReadWrite_Test.ino new file mode 100644 index 0000000..b5be8da --- /dev/null +++ b/examples/Test and diagnostics/TFT_ReadWrite_Test/TFT_ReadWrite_Test.ino @@ -0,0 +1,37 @@ +// Walking 1 write and read pixel test + +#include +#include + +#define TDELAY 500 + +TFT_eSPI tft = TFT_eSPI(); + +void setup() { + Serial.begin(115200); + + tft.init(); + tft.fillScreen(0xF81F); +} + +void loop() { + static uint32_t wr = 1; + static uint32_t rd = 0xFFFFFFFF; + + delay(TDELAY); + + tft.drawPixel(30,30,wr); + Serial.print(" Pixel value written = ");Serial.println(wr,HEX); + + rd = tft.readPixel(30,30); + Serial.print(" Pixel value read = ");Serial.println(rd,HEX); + + if (rd!=wr) { + Serial.println(" ERROR ^^^^"); + //while(1) yield(); + } + else Serial.println(" PASS "); + // Walking 1 test + wr = wr<<1; + if (wr >= 0x10000) wr = 1; +}