Improve RPi Pico (RP2040) rendering performance

This commit is contained in:
Bodmer
2021-04-05 16:39:33 +01:00
parent 356095bdf3
commit fce86c0f2e
7 changed files with 296 additions and 118 deletions

View File

@@ -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 ** Description: Write a block of pixels of the same colour
***************************************************************************************/ ***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
while(len--)
bool loaded = false; {
uint16_t colorBuf[64]; while (!spi_is_writable(spi0)){};
const uint16_t* colorPtr = colorBuf; spi_get_hw(spi0)->dr = (uint32_t)color;
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);
} }
} }
@@ -244,14 +232,23 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
** Description: Write a sequence of pixels ** Description: Write a sequence of pixels
***************************************************************************************/ ***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if (_swapBytes) { 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 { 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); while(len--)
spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); {
uint16_t color = *data++;
color = color >> 8 | color << 8;
while (!spi_is_writable(spi0)){};
spi_get_hw(spi0)->dr = (uint32_t)color;
}
} }
} }

View File

@@ -14,13 +14,17 @@
// Include processor specific header // Include processor specific header
// None // None
// Processor specific code used by SPI bus transaction startWrite and endWrite functions // Processor specific code used by SPI bus transaction begin/end_tft_write functions
#define SET_BUS_WRITE_MODE // Not used #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 // Not used #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 // 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 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 // To be safe, SUPPORT_TRANSACTIONS is assumed mandatory
#if !defined (SUPPORT_TRANSACTIONS) #if !defined (SUPPORT_TRANSACTIONS)
@@ -28,7 +32,7 @@
#endif #endif
// Initialise processor specific SPI functions, used by init() // 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 // If smooth fonts are enabled the filing system may need to be loaded
#ifdef SMOOTH_FONT #ifdef SMOOTH_FONT
@@ -150,18 +154,27 @@
spi.transfer(0); spi.transfer((C)>>0) spi.transfer(0); spi.transfer((C)>>0)
#else #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 // RPI_DISPLAY_TYPE
#endif #endif

View File

@@ -2,7 +2,7 @@
Arduino TFT graphics library targeted at 32 bit Arduino TFT graphics library targeted at 32 bit
processors such as ESP32, ESP8266 and STM32. 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 hardware driver, the graphics functions and the
proportional fonts. proportional fonts.
@@ -22,7 +22,7 @@
#include "Processors/TFT_eSPI_ESP8266.c" #include "Processors/TFT_eSPI_ESP8266.c"
#elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h #elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h
#include "Processors/TFT_eSPI_STM32.c" #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" #include "Processors/TFT_eSPI_RP2040.c"
#else #else
#include "Processors/TFT_eSPI_Generic.c" #include "Processors/TFT_eSPI_Generic.c"
@@ -56,10 +56,10 @@
inline void TFT_eSPI::begin_tft_write(void){ inline void TFT_eSPI::begin_tft_write(void){
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
if (locked) { if (locked) {
locked = false; locked = false; // Flag to show SPI access now unlocked
spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); // RP2040 SDK -> 68us delay!
CS_L; 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 #else
CS_L; CS_L;
@@ -74,16 +74,17 @@ inline void TFT_eSPI::begin_tft_write(void){
***************************************************************************************/ ***************************************************************************************/
inline void TFT_eSPI::end_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 defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
if(!inTransaction) { if(!inTransaction) { // Flag to stop ending tranaction during multiple graphics calls
if (!locked) { if (!locked) { // Locked when beginTransaction has been called
locked = true; locked = true; // Flag to show SPI access now locked
SPI_BUSY_CHECK; // Check send complete and clean out unused rx data
CS_H; 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 #else
if(!inTransaction) {CS_H; SET_BUS_READ_MODE;} if(!inTransaction) {SPI_BUSY_CHECK; CS_H; SET_BUS_READ_MODE;}
#endif #endif
} }
@@ -435,12 +436,13 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
_swapBytes = false; // Do not swap colour bytes by default _swapBytes = false; // Do not swap colour bytes by default
locked = true; // Transaction mutex lock flags locked = true; // Transaction mutex lock flag to ensure begin/endTranaction pairing
inTransaction = false; 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 _booted = true; // Default attributes
_cp437 = true; _cp437 = true; // Legacy GLCD font bug fix
_utf8 = true; _utf8 = true; // UTF8 decoding enabled
#ifdef FONT_FS_AVAILABLE #ifdef FONT_FS_AVAILABLE
fs_font = true; // Smooth font filing system or array (fs_font = false) flag 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 #endif
_psram_enable = false; _psram_enable = false;
addr_row = 0xFFFF; addr_row = 0xFFFF; // drawPixel command length optimiser
addr_col = 0xFFFF; addr_col = 0xFFFF; // drawPixel command length optimiser
_xPivot = 0; _xPivot = 0;
_yPivot = 0; _yPivot = 0;
// Legacy support for bit GPIO masks
cspinmask = 0; cspinmask = 0;
dcpinmask = 0; dcpinmask = 0;
wrpinmask = 0; wrpinmask = 0;
sclkpinmask = 0; sclkpinmask = 0;
// Flags for which fonts are loaded
#ifdef LOAD_GLCD #ifdef LOAD_GLCD
fontsloaded = 0x0002; // Bit 1 set fontsloaded = 0x0002; // Bit 1 set
#endif #endif
@@ -515,7 +519,8 @@ void TFT_eSPI::init(uint8_t tc)
{ {
if (_booted) 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) #if defined (TFT_CS) && (TFT_CS >= 0)
cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS);
#endif #endif
@@ -543,14 +548,14 @@ void TFT_eSPI::init(uint8_t tc)
#else #else
#if !defined(TFT_PARALLEL_8_BIT) #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); spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
#else #else
spi.begin(); spi.begin();
#endif #endif
#endif #endif
#endif #endif
lockTransaction = false;
inTransaction = false; inTransaction = false;
locked = true; locked = true;
@@ -559,7 +564,7 @@ void TFT_eSPI::init(uint8_t tc)
#ifdef TFT_CS #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); pinMode(TFT_CS, OUTPUT);
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
#elif defined (ESP8266) && !defined (TFT_PARALLEL_8_BIT) #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 #ifdef TFT_DC
pinMode(TFT_DC, OUTPUT); pinMode(TFT_DC, OUTPUT);
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode 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 #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; uint16_t color = 0;
begin_tft_read(); 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(); end_tft_read();
// Reinstate the transaction if one was in progress
if(wasInTransaction) { begin_tft_write(); inTransaction = true; }
#endif #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(); 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; data += w;
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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); pushPixels(buffer, dw);
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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; data += w;
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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 _swapBytes = swap; // Restore old value
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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 _swapBytes = swap; // Restore old value
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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; xs = xe;
} while (xe < --r); } while (xe < --r);
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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; xs = xe;
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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 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); s += rx2 * ((4 * y) + 6);
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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); s += rx2 * ((4 * y) + 6);
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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, y+1, h-2, color);
drawFastVLine(x + w - 1, 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 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 + w - r - 1, y + h - r - 1, r, 4, color);
drawCircleHelper(x + r , y + h - r - 1, r, 8, 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 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 + h - r - 1, r, 1, w - r - r - 1, color);
fillCircleHelper(x + r , y + r, r, 2, 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 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(x1, y1, x2, y2, color);
drawLine(x2, y2, x0, y0, color); drawLine(x2, y2, x0, y0, color);
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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); drawFastHLine(a, y, b - a + 1, color);
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function 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 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 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 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 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 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 end_tft_write(); // Does nothing if Sprite class uses this function
} }
#endif #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_C; tft_Write_8(TFT_RAMWR);
DC_D; DC_D;
#else #else // Not ILI9225
#if defined (SSD1963_DRIVER) #if defined (SSD1963_DRIVER)
if ((rotation & 0x1) == 0) { swap_coord(x0, y0); swap_coord(x1, y1); } 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; y1+=rowstart;
#endif #endif
DC_C; tft_Write_8(TFT_CASET); // Temporary solution is to include the RP2040 optimised code here
DC_D; tft_Write_32C(x0, x1); #if defined(ARDUINO_ARCH_RP2040) && !defined(TFT_PARALLEL_8BIT)
DC_C; tft_Write_8(TFT_PASET); while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D; tft_Write_32C(y0, y1); DC_C;
DC_C; tft_Write_8(TFT_RAMWR); spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
DC_D; 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 #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); } if ((rotation & 0x1) == 0) { swap_coord(xs, ys); swap_coord(xe, ye); }
#endif #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 // Column addr set
DC_C; tft_Write_8(TFT_CASET); DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_32C(xs, xe); 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_C; tft_Write_8(TFT_RAMRD);
DC_D; DC_D;
#endif // RP2040 SPI
//end_tft_write(); // Must be called after readAddrWindow or CS set high //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_C; tft_Write_8(TFT_RAMWR);
DC_D; tft_Write_16(color); 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 #else
#if defined (SSD1963_DRIVER) #if defined (SSD1963_DRIVER)
@@ -3058,7 +3202,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
} }
#endif #endif
DC_C; tft_Write_8(TFT_RAMWR); DC_C; tft_Write_8(TFT_RAMWR);
DC_D; tft_Write_16(color); DC_D; tft_Write_16(color);
#endif #endif
end_tft_write(); end_tft_write();
@@ -3098,6 +3242,7 @@ void TFT_eSPI::pushColor(uint16_t color, uint32_t len)
void TFT_eSPI::startWrite(void) void TFT_eSPI::startWrite(void)
{ {
begin_tft_write(); begin_tft_write();
lockTransaction = true; // Lock transaction for all sequentially run sketch functions
inTransaction = true; inTransaction = true;
} }
@@ -3107,9 +3252,10 @@ void TFT_eSPI::startWrite(void)
***************************************************************************************/ ***************************************************************************************/
void TFT_eSPI::endWrite(void) void TFT_eSPI::endWrite(void)
{ {
lockTransaction = false; // Release sketch induced transaction lock
inTransaction = false; inTransaction = false;
DMA_BUSY_CHECK; // Safety check - user code should have checked this! DMA_BUSY_CHECK; // Safety check - user code should have checked this!
end_tft_write(); 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); if (dlen) drawFastHLine(xs, y0, dlen, color);
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); 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; pY += textsize;
} }
inTransaction = false; inTransaction = lockTransaction;
end_tft_write(); end_tft_write();
} }
else { // Faster drawing of characters and background using block 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_tft_write();
} }
// End of RLE font rendering // End of RLE font rendering

View File

@@ -2,7 +2,7 @@
Arduino TFT graphics library targeted at ESP8266 Arduino TFT graphics library targeted at ESP8266
and ESP32 based boards. 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 hardware driver, the graphics functions and the
proportional fonts. proportional fonts.
@@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_ #ifndef _TFT_eSPIH_
#define _TFT_eSPIH_ #define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.3.62" #define TFT_ESPI_VERSION "2.3.63"
// Bit level feature flags // Bit level feature flags
// Bit 0 set: viewport capability // Bit 0 set: viewport capability
@@ -54,7 +54,7 @@
#include "Processors/TFT_eSPI_ESP8266.h" #include "Processors/TFT_eSPI_ESP8266.h"
#elif defined (STM32) #elif defined (STM32)
#include "Processors/TFT_eSPI_STM32.h" #include "Processors/TFT_eSPI_STM32.h"
#elif defined (RP2040) #elif defined(ARDUINO_ARCH_RP2040)
#include "Processors/TFT_eSPI_RP2040.h" #include "Processors/TFT_eSPI_RP2040.h"
#else #else
#include "Processors/TFT_eSPI_Generic.h" #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 // New begin and end prototypes
// begin/end a TFT write transaction // begin/end a TFT write transaction
// For SPI bus the transmit clock rate is set // For SPI bus the transmit clock rate is set
inline void begin_tft_write() __attribute__((always_inline)); inline void begin_tft_write() __attribute__((always_inline));
inline void end_tft_write() __attribute__((always_inline)); inline void end_tft_write() __attribute__((always_inline));
// begin/end a TFT read transaction // begin/end a TFT read transaction
// For SPI bus: begin lowers SPI clock rate, end reinstates transmit clock rate // For SPI bus: begin lowers SPI clock rate, end reinstates transmit clock rate
inline void begin_tft_read() __attribute__((always_inline)); inline void begin_tft_read() __attribute__((always_inline));
inline void end_tft_read() __attribute__((always_inline)); inline void end_tft_read() __attribute__((always_inline));
// Temporary library development function TODO: remove need for this // Temporary library development function TODO: remove need for this
void pushSwapBytePixels(const void* data_in, uint32_t len); 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 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 textwrapX, textwrapY; // If set, 'wrap' text at right and optionally bottom edge of display
bool _swapBytes; // Swap the byte order for TFT pushImage() 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 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 bool _psram_enable; // Enable PSRAM use for library functions (TBD) and Sprites
uint32_t _lastColor; // Buffered value of last colour used uint32_t _lastColor; // Buffered value of last colour used
uint32_t _Cbuf; // SPI buffer for RP2040
#ifdef LOAD_GFXFF #ifdef LOAD_GFXFF
GFXfont *gfxFont; GFXfont *gfxFont;

View File

@@ -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 to invoke optimised processor support (only for STM32)
//#define STM32 //#define STM32

View File

@@ -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) // Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
//#define TFT_PARALLEL_8_BIT //#define TFT_PARALLEL_8_BIT
@@ -177,7 +174,7 @@
// #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 10000000
// #define SPI_FREQUENCY 20000000 // #define SPI_FREQUENCY 20000000
// #define SPI_FREQUENCY 32000000 // #define SPI_FREQUENCY 32000000
#define SPI_FREQUENCY 63000000 #define SPI_FREQUENCY 70000000
// Optional reduced SPI frequency for reading TFT // Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY 20000000 #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: // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY 2500000 #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

View File

@@ -0,0 +1,37 @@
// Walking 1 write and read pixel test
#include <TFT_eSPI.h>
#include <SPI.h>
#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;
}