diff --git a/Processors/TFT_eSPI_RP2040.c b/Processors/TFT_eSPI_RP2040.c new file mode 100644 index 0000000..bfe0907 --- /dev/null +++ b/Processors/TFT_eSPI_RP2040.c @@ -0,0 +1,278 @@ + //////////////////////////////////////////////////// + // TFT_eSPI generic driver functions // + //////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////// +// Global variables +//////////////////////////////////////////////////////////////////////////////////////// + +// Select the SPI port to use +SPIClass& spi = SPI; + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: tft_Read_8 +** Description: Bit bashed SPI to read bidirectional SDA line +***************************************************************************************/ +uint8_t TFT_eSPI::tft_Read_8(void) +{ + uint8_t ret = 0; + + for (uint8_t i = 0; i < 8; i++) { // read results + ret <<= 1; + SCLK_L; + if (digitalRead(TFT_MOSI)) ret |= 1; + SCLK_H; + } + + return ret; +} + +/*************************************************************************************** +** Function name: beginSDA +** Description: Detach SPI from pin to permit software SPI +***************************************************************************************/ +void TFT_eSPI::begin_SDA_Read(void) +{ + // Release configured SPI port for SDA read + spi.end(); +} + +/*************************************************************************************** +** Function name: endSDA +** Description: Attach SPI pins after software SPI +***************************************************************************************/ +void TFT_eSPI::end_SDA_Read(void) +{ + // Configure SPI port ready for next TFT access + spi.begin(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // #if defined (TFT_SDA_READ) +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_PARALLEL_8_BIT) // Code for generic (i.e. any) processor +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for generic processor and parallel display +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + while (len>1) {tft_Write_32D(color); len-=2;} + if (len) {tft_Write_16(color);} +} + +/*************************************************************************************** +** Function name: pushPixels - for gereric processor and parallel display +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + if(_swapBytes) { + while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;} + if (len) {tft_Write_16(*data);} + return; + } + + while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;} + if (len) {tft_Write_16S(*data);} +} + +/*************************************************************************************** +** Function name: GPIO direction control - supports class functions +** Description: Set parallel bus to INPUT or OUTPUT +***************************************************************************************/ +void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) +{ + // mask is unused for generic processor + // Arduino native functions suited well to a generic driver + pinMode(TFT_D0, mode); + pinMode(TFT_D1, mode); + pinMode(TFT_D2, mode); + pinMode(TFT_D3, mode); + pinMode(TFT_D4, mode); + pinMode(TFT_D5, mode); + pinMode(TFT_D6, mode); + pinMode(TFT_D7, mode); + return; +} + +/*************************************************************************************** +** Function name: GPIO direction control - supports class functions +** Description: Faster GPIO pin input/output switch +***************************************************************************************/ +void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode) +{ + // No fast port based generic approach available +} + +/*************************************************************************************** +** Function name: read byte - supports class functions +** Description: Read a byte - parallel bus only +***************************************************************************************/ +uint8_t TFT_eSPI::readByte(void) +{ + uint8_t b = 0; + + busDir(0, INPUT); + digitalWrite(TFT_RD, LOW); + + b |= digitalRead(TFT_D0) << 0; + b |= digitalRead(TFT_D1) << 1; + b |= digitalRead(TFT_D2) << 2; + b |= digitalRead(TFT_D3) << 3; + b |= digitalRead(TFT_D4) << 4; + b |= digitalRead(TFT_D5) << 5; + b |= digitalRead(TFT_D6) << 6; + b |= digitalRead(TFT_D7) << 7; + + digitalWrite(TFT_RD, HIGH); + busDir(0, OUTPUT); + + return b; +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for ESP32 or RP2040 RPi TFT +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + if(len) { tft_Write_16(color); len--; } + while(len--) {WR_L; WR_H;} +} + +/*************************************************************************************** +** Function name: pushPixels - for ESP32 or RP2040 RPi TFT +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) +{ + uint16_t *data = (uint16_t*)data_in; + + if (_swapBytes) while ( len-- ) {tft_Write_16S(*data); data++;} + else while ( len-- ) {tft_Write_16(*data); data++;} +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for RP2040 and 3 byte RGB display +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) +{ + // Split out the colours + uint8_t r = (color & 0xF800)>>8; + uint8_t g = (color & 0x07E0)>>3; + uint8_t b = (color & 0x001F)<<3; + + while ( len-- ) {tft_Write_8(r); tft_Write_8(g); tft_Write_8(b);} +} + +/*************************************************************************************** +** Function name: pushPixels - for RP2040 and 3 byte RGB display +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + if (_swapBytes) { + while ( len-- ) { + uint16_t color = *data >> 8 | *data << 8; + tft_Write_8((color & 0xF800)>>8); + tft_Write_8((color & 0x07E0)>>3); + tft_Write_8((color & 0x001F)<<3); + data++; + } + } + else { + while ( len-- ) { + tft_Write_8((*data & 0xF800)>>8); + tft_Write_8((*data & 0x07E0)>>3); + tft_Write_8((*data & 0x001F)<<3); + data++; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +#else // Standard SPI 16 bit colour TFT +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for RP2040 +** 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); + } +} + +/*************************************************************************************** +** Function name: pushPixels - for RP2040 +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + if (_swapBytes) { + spi_write16_blocking(spi0, (const uint16_t*)data_in, len); + } + 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); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // End of display interface specific functions +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +// DMA FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////// + +// Placeholder for DMA functions + +/* +Minimal function set to support DMA: + +bool TFT_eSPI::initDMA(void) +void TFT_eSPI::deInitDMA(void) +bool TFT_eSPI::dmaBusy(void) +void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) +void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image) + +*/ diff --git a/Processors/TFT_eSPI_RP2040.h b/Processors/TFT_eSPI_RP2040.h new file mode 100644 index 0000000..1d3ef7c --- /dev/null +++ b/Processors/TFT_eSPI_RP2040.h @@ -0,0 +1,183 @@ + //////////////////////////////////////////////////// + // TFT_eSPI generic driver functions // + //////////////////////////////////////////////////// + +// This is a generic driver for Arduino boards, it supports SPI interface displays +// 8 bit parallel interface to TFT is not supported for generic processors + +#ifndef _TFT_eSPI_RP2040H_ +#define _TFT_eSPI_RP2040H_ + +// Processor ID reported by getSetup() +#define PROCESSOR_ID 0x0000 + +// 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 + +// 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 + +// To be safe, SUPPORT_TRANSACTIONS is assumed mandatory +#if !defined (SUPPORT_TRANSACTIONS) + #define SUPPORT_TRANSACTIONS +#endif + +// Initialise processor specific SPI functions, used by init() +#define INIT_TFT_DATA_BUS + +// If smooth fonts are enabled the filing system may need to be loaded +#ifdef SMOOTH_FONT + // Call up the filing system for the anti-aliased fonts + //#define FS_NO_GLOBALS + //#include +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the DC (TFT Data/Command or Register Select (RS))pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_DC + #define DC_C // No macro allocated so it generates no code + #define DC_D // No macro allocated so it generates no code +#else + #define DC_C sio_hw->gpio_clr = (1ul << TFT_DC) + #define DC_D sio_hw->gpio_set = (1ul << TFT_DC) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the CS (TFT chip select) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_CS + #define CS_L // No macro allocated so it generates no code + #define CS_H // No macro allocated so it generates no code +#else + #define CS_L sio_hw->gpio_clr = (1ul << TFT_CS) + #define CS_H sio_hw->gpio_set = (1ul << TFT_CS) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Make sure TFT_RD is defined if not used to avoid an error message +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_RD + #define TFT_RD -1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the WR (TFT Write) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifdef TFT_WR + #define WR_L digitalWrite(TFT_WR, LOW) + #define WR_H digitalWrite(TFT_WR, HIGH) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the touch screen chip select pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined TOUCH_CS || (TOUCH_CS < 0) + #define T_CS_L // No macro allocated so it generates no code + #define T_CS_H // No macro allocated so it generates no code +#else + #define T_CS_L digitalWrite(TOUCH_CS, LOW) + #define T_CS_H digitalWrite(TOUCH_CS, HIGH) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Make sure TFT_MISO is defined if not used to avoid an error message +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_MISO + #define TFT_MISO -1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to a SPI ILI948x TFT +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour + + // Write 8 bits to TFT + #define tft_Write_8(C) spi.transfer(C) + + // Convert 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16(C) spi.transfer(((C) & 0xF800)>>8); \ + spi.transfer(((C) & 0x07E0)>>3); \ + spi.transfer(((C) & 0x001F)<<3) + + // Convert 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16N(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) & 0xE000)>>11 | ((C) & 0x07)<<5); \ + spi.transfer(((C) & 0x1F00)>>5) + // Write 32 bits to TFT + #define tft_Write_32(C) spi.transfer16((C)>>16); spi.transfer16((uint16_t)(C)) + + // Write two address coordinates + #define tft_Write_32C(C,D) spi.transfer16(C); spi.transfer16(D) + + // Write same value twice + #define tft_Write_32D(C) spi.transfer16(C); spi.transfer16(C) + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to other displays +//////////////////////////////////////////////////////////////////////////////////////// +#else + #if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers + #define tft_Write_8(C) spi.transfer(C); spi.transfer(C) + #define tft_Write_16(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0)) + #define tft_Write_16N(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0)) + #define tft_Write_16S(C) spi.transfer((uint8_t)((C)>>0));spi.transfer((uint8_t)((C)>>8)) + + #define tft_Write_32(C) \ + tft_Write_16((uint16_t) ((C)>>16)); \ + tft_Write_16((uint16_t) ((C)>>0)) + + #define tft_Write_32C(C,D) \ + spi.transfer(0); spi.transfer((C)>>8); \ + spi.transfer(0); spi.transfer((C)>>0); \ + spi.transfer(0); spi.transfer((D)>>8); \ + spi.transfer(0); spi.transfer((D)>>0) + + #define tft_Write_32D(C) \ + spi.transfer(0); spi.transfer((C)>>8); \ + spi.transfer(0); spi.transfer((C)>>0); \ + spi.transfer(0); spi.transfer((C)>>8); \ + 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) + + #define tft_Write_32C(C,D) _Cbuf = (C) | (D) << 16; spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 2) + + #define tft_Write_32D(C) _Cbuf = (C) | (C) << 16; spi_write16_blocking(spi0, (const uint16_t*)&(_Cbuf), 2) + + #endif // RPI_DISPLAY_TYPE +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to read from display using SPI or software SPI +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) + // Use a bit banged function call for STM32 and bi-directional SDA pin + #define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(void); + #define SCLK_L digitalWrite(TFT_SCLK, LOW) + #define SCLK_H digitalWrite(TFT_SCLK, LOW) +#else + // Use a SPI read transfer + #define tft_Read_8() spi.transfer(0) +#endif + + +#endif // Header end diff --git a/README.md b/README.md index 59d3213..df3c5fc 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,21 @@ A [Beta test branch](https://github.com/Bodmer/TFT_eSPI/tree/2.4.0-Beta) has bee A new ["Discussions"](https://github.com/Bodmer/TFT_eSPI/discussions) facility has been added for Q&A etc. Use the ["Issues"](https://github.com/Bodmer/TFT_eSPI/issues) tab only for problems with the library. Thanks! # News -1. Viewports can now be applied to sprites e.g. spr.setViewport(5, 5, 20, 20); so graphics can be restricted to a particular area of the sprite. This operates in the same way as the TFT viewports, see 2. below. +1. The library now supports the Raspberry Pi Pico with the [Arduino core provided by Earle Philhower](https://github.com/earlephilhower/arduino-pico). The setup file "Setup60_RP2040_ILI9341.h" has been used for tests with and ILI9341 display. At the moment only SPI interface displays have been tested. -2. The library now provides a "viewport" capability. See "Viewport_Demo" and "Viewport_graphicstest" examples. When a viewport is defined graphics will only appear within that window. The coordinate datum by default moves to the top left corner of the viewport, but can optionally remain at top left corner of TFT. The GUIslice library will make use of this feature to speed up the rendering of GUI objects ([see #769](https://github.com/Bodmer/TFT_eSPI/issues/769)). +2. Viewports can now be applied to sprites e.g. spr.setViewport(5, 5, 20, 20); so graphics can be restricted to a particular area of the sprite. This operates in the same way as the TFT viewports, see 2. below. -3. The library now supports SSD1963 based screen, this has been tested on a [480x800 screen](https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu) with an ESP32. The interface is 8 bit parallel only as that controller does not support a SPI interface. +3. The library now provides a "viewport" capability. See "Viewport_Demo" and "Viewport_graphicstest" examples. When a viewport is defined graphics will only appear within that window. The coordinate datum by default moves to the top left corner of the viewport, but can optionally remain at top left corner of TFT. The GUIslice library will make use of this feature to speed up the rendering of GUI objects ([see #769](https://github.com/Bodmer/TFT_eSPI/issues/769)). -4. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI. +4. The library now supports SSD1963 based screen, this has been tested on a [480x800 screen](https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu) with an ESP32. The interface is 8 bit parallel only as that controller does not support a SPI interface. -5. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488). +5. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI. -6. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h". +6. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488). -7. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program. +7. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h". + +8. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program. ![Animated_dial](https://i.imgur.com/S736Rg6.png) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index ca049e6..154e4dd 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -22,6 +22,8 @@ #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 + #include "Processors/TFT_eSPI_RP2040.c" #else #include "Processors/TFT_eSPI_Generic.c" #endif @@ -513,7 +515,7 @@ void TFT_eSPI::init(uint8_t tc) { if (_booted) { -#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) +#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040) #if defined (TFT_CS) && (TFT_CS >= 0) cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); #endif @@ -541,7 +543,7 @@ void TFT_eSPI::init(uint8_t tc) #else #if !defined(TFT_PARALLEL_8_BIT) - #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) + #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) && !defined(RP2040) spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); #else spi.begin(); @@ -1806,46 +1808,62 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_ // Optimised midpoint circle algorithm void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) { - int32_t x = 1; - int32_t dx = 1; - int32_t dy = r+r; - int32_t p = -(r>>1); + if ( r <= 0 ) return; //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() inTransaction = true; - // These are ordered to minimise coordinate changes in x or y - // drawPixel can then send fewer bounding box commands - drawPixel(x0 + r, y0, color); - drawPixel(x0 - r, y0, color); - drawPixel(x0, y0 - r, color); - drawPixel(x0, y0 + r, color); + int32_t f = 1 - r; + int32_t ddF_y = -2 * r; + int32_t ddF_x = 1; + int32_t xs = -1; + int32_t xe = 0; + int32_t len = 0; + + bool first = true; + do { + while (f < 0) { + ++xe; + f += (ddF_x += 2); + } + f += (ddF_y += 2); - while(x1) { + if (first) { + len = 2*(xe - xs)-1; + drawFastHLine(x0 - xe, y0 + r, len, color); + drawFastHLine(x0 - xe, y0 - r, len, color); + drawFastVLine(x0 + r, y0 - xe, len, color); + drawFastVLine(x0 - r, y0 - xe, len, color); + first = false; + } + else { + len = xe - xs++; + drawFastHLine(x0 - xe, y0 + r, len, color); + drawFastHLine(x0 - xe, y0 - r, len, color); + drawFastHLine(x0 + xs, y0 - r, len, color); + drawFastHLine(x0 + xs, y0 + r, len, color); - if(p>=0) { - dy-=2; - p-=dy; - r--; - } + drawFastVLine(x0 + r, y0 + xs, len, color); + drawFastVLine(x0 + r, y0 - xe, len, color); + drawFastVLine(x0 - r, y0 - xe, len, color); + drawFastVLine(x0 - r, y0 + xs, len, color); + } + } + else { + ++xs; + drawPixel(x0 - xe, y0 + r, color); + drawPixel(x0 - xe, y0 - r, color); + drawPixel(x0 + xs, y0 - r, color); + drawPixel(x0 + xs, y0 + r, color); - dx+=2; - p+=dx; - - // These are ordered to minimise coordinate changes in x or y - // drawPixel can then send fewer bounding box commands - drawPixel(x0 + x, y0 + r, color); - drawPixel(x0 - x, y0 + r, color); - drawPixel(x0 - x, y0 - r, color); - drawPixel(x0 + x, y0 - r, color); - if (r != x) { - drawPixel(x0 + r, y0 + x, color); - drawPixel(x0 - r, y0 + x, color); - drawPixel(x0 - r, y0 - x, color); - drawPixel(x0 + r, y0 - x, color); - } - x++; - } + drawPixel(x0 + r, y0 + xs, color); + drawPixel(x0 + r, y0 - xe, color); + drawPixel(x0 - r, y0 - xe, color); + drawPixel(x0 - r, y0 + xs, color); + } + xs = xe; + } while (xe < --r); inTransaction = false; end_tft_write(); // Does nothing if Sprite class uses this function @@ -1856,42 +1874,70 @@ void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) ** Function name: drawCircleHelper ** Description: Support function for drawRoundRect() ***************************************************************************************/ -void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t r, uint8_t cornername, uint32_t color) +void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t rr, uint8_t cornername, uint32_t color) { - int32_t f = 1 - r; + if (rr <= 0) return; + int32_t f = 1 - rr; int32_t ddF_x = 1; - int32_t ddF_y = -2 * r; - int32_t x = 0; + int32_t ddF_y = -2 * rr; + int32_t xe = 0; + int32_t xs = 0; + int32_t len = 0; - while (x < r) { - if (f >= 0) { - r--; - ddF_y += 2; - f += ddF_y; + //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() + inTransaction = true; + + while (xe < rr--) + { + while (f < 0) { + ++xe; + f += (ddF_x += 2); } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) { - drawPixel(x0 + x, y0 + r, color); - drawPixel(x0 + r, y0 + x, color); + f += (ddF_y += 2); + + if (xe-xs==1) { + if (cornername & 0x1) { // left top + drawPixel(x0 - xe, y0 - rr, color); + drawPixel(x0 - rr, y0 - xe, color); + } + if (cornername & 0x2) { // right top + drawPixel(x0 + rr , y0 - xe, color); + drawPixel(x0 + xs + 1, y0 - rr, color); + } + if (cornername & 0x4) { // right bottom + drawPixel(x0 + xs + 1, y0 + rr , color); + drawPixel(x0 + rr, y0 + xs + 1, color); + } + if (cornername & 0x8) { // left bottom + drawPixel(x0 - rr, y0 + xs + 1, color); + drawPixel(x0 - xe, y0 + rr , color); + } } - if (cornername & 0x2) { - drawPixel(x0 + x, y0 - r, color); - drawPixel(x0 + r, y0 - x, color); - } - if (cornername & 0x8) { - drawPixel(x0 - r, y0 + x, color); - drawPixel(x0 - x, y0 + r, color); - } - if (cornername & 0x1) { - drawPixel(x0 - r, y0 - x, color); - drawPixel(x0 - x, y0 - r, color); + else { + len = xe - xs++; + if (cornername & 0x1) { // left top + drawFastHLine(x0 - xe, y0 - rr, len, color); + drawFastVLine(x0 - rr, y0 - xe, len, color); + } + if (cornername & 0x2) { // right top + drawFastVLine(x0 + rr, y0 - xe, len, color); + drawFastHLine(x0 + xs, y0 - rr, len, color); + } + if (cornername & 0x4) { // right bottom + drawFastHLine(x0 + xs, y0 + rr, len, color); + drawFastVLine(x0 + rr, y0 + xs, len, color); + } + if (cornername & 0x8) { // left bottom + drawFastVLine(x0 - rr, y0 + xs, len, color); + drawFastHLine(x0 - xe, y0 + rr, len, color); + } } + xs = xe; } + inTransaction = false; + end_tft_write(); // Does nothing if Sprite class uses this function } - /*************************************************************************************** ** Function name: fillCircle ** Description: draw a filled circle diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 293a4ff..d101555 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.3.61" +#define TFT_ESPI_VERSION "2.3.62" // Bit level feature flags // Bit 0 set: viewport capability @@ -54,6 +54,8 @@ #include "Processors/TFT_eSPI_ESP8266.h" #elif defined (STM32) #include "Processors/TFT_eSPI_STM32.h" +#elif defined (RP2040) + #include "Processors/TFT_eSPI_RP2040.h" #else #include "Processors/TFT_eSPI_Generic.h" #endif @@ -773,6 +775,7 @@ 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 ff9b58d..9ba3582 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -15,6 +15,9 @@ // // ################################################################################## +// 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_Setup_Select.h b/User_Setup_Select.h index 7961804..7ce07eb 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -76,7 +76,9 @@ //#include // Setup file for ESP32 and SSD1963 TFT display -//#include // Setup file for LilyGo LilyPi with ILI9481 display +//#include // Setup file for LilyGo LilyPi with ILI9481 display + +//#include // Setup file for Raspberry Pi Pico with SPI ILI9341 //#include // Setup file for ESP8266 and ST7789 135 x 240 TFT diff --git a/User_Setups/Setup60_RP2040_ILI9341.h b/User_Setups/Setup60_RP2040_ILI9341.h new file mode 100644 index 0000000..a0052e8 --- /dev/null +++ b/User_Setups/Setup60_RP2040_ILI9341.h @@ -0,0 +1,195 @@ +// USER DEFINED SETTINGS +// Set driver type, fonts to be loaded, pins used and SPI control method etc +// +// See the User_Setup_Select.h file if you wish to be able to define multiple +// setups and then easily select which setup file is used by the compiler. +// +// If this file is edited correctly then all the library example sketches should +// run without the need to make any more changes for a particular hardware setup! +// Note that some sketches are designed for a particular TFT pixel width/height + + +// ################################################################################## +// +// Section 1. Call up the right driver file and any options for it +// +// ################################################################################## + +// 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 + +// Display type - only define if RPi display +//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI + +// Only define one driver, the other ones must be commented out +#define ILI9341_DRIVER +//#define ST7735_DRIVER // Define additional parameters below for this display +//#define ILI9163_DRIVER // Define additional parameters below for this display +//#define S6D02A1_DRIVER +//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI +//#define HX8357D_DRIVER +//#define ILI9481_DRIVER +//#define ILI9486_DRIVER +//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high) +//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display +//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display +//#define R61581_DRIVER +//#define RM68140_DRIVER +//#define ST7796_DRIVER +//#define SSD1963_480_DRIVER +//#define SSD1963_800_DRIVER +//#define SSD1963_800ALT_DRIVER +//#define ILI9225_DRIVER + +// Some displays support SPI reads via the MISO pin, other displays have a single +// bi-directional SDA pin and the library will try to read this via the MOSI line. +// To use the SDA line for reading data from the TFT uncomment the following line: + +// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 display only + +// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display +// Try ONE option at a time to find the correct colour order for your display + +// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue +// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red + +// For ST7789, ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation +// #define TFT_WIDTH 80 +// #define TFT_WIDTH 128 +// #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320 +// #define TFT_HEIGHT 160 +// #define TFT_HEIGHT 128 +// #define TFT_HEIGHT 240 // ST7789 240 x 240 +// #define TFT_HEIGHT 320 // ST7789 240 x 320 + +// For ST7735 ONLY, define the type of display, originally this was based on the +// colour of the tab on the screen protector film but this is not always true, so try +// out the different options below if the screen does not display graphics correctly, +// e.g. colours wrong, mirror images, or tray pixels at the edges. +// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this +// this User_Setup file, then rebuild and upload the sketch to the board again: + +// #define ST7735_INITB +// #define ST7735_GREENTAB +// #define ST7735_GREENTAB2 +// #define ST7735_GREENTAB3 +// #define ST7735_GREENTAB128 // For 128 x 128 display +// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset) +// #define ST7735_REDTAB +// #define ST7735_BLACKTAB +// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset + +// If colours are inverted (white shows as black) then uncomment one of the next +// 2 lines try both options, one of the options should correct the inversion. + +// #define TFT_INVERSION_ON +// #define TFT_INVERSION_OFF + + +// ################################################################################## +// +// Section 2. Define the pins that are used to interface with the display here +// +// ################################################################################## + +// If a backlight control signal is available then define the TFT_BL pin in Section 2 +// below. The backlight will be turned ON when tft.begin() is called, but the library +// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be +// driven with a PWM signal or turned OFF/ON then this must be handled by the user +// sketch. e.g. with digitalWrite(TFT_BL, LOW); + +// #define TFT_BL 32 // LED back-light control pin +// #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) + +// We must use hardware SPI, a minimum of 3 GPIO pins is needed. +// Typical setup for the RP2040 is : +// +// Display SDO/MISO to RP2040 pin D8 (or leave disconnected if not reading TFT) +// Display LED to RP2040 pin 3V3 or 5V +// Display SCK to RP2040 pin D10 +// Display SDI/MOSI to RP2040 pin D11 +// Display DC (RS/AO)to RP2040 pin D18 +// Display RESET to RP2040 pin D19 +// Display CS to RP2040 pin D20 (or GND, see below) +// Display GND to RP2040 pin GND (0V) +// Display VCC to RP2040 5V or 3.3V (5v if display has a 5V to 3.3V regulator fitted) +// +// The DC (Data Command) pin may be labelled AO or RS (Register Select) +// +// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more +// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS +// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin +// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected. + +// For the Pico use these #define lines +#define TFT_MISO D8 +#define TFT_MOSI D11 +#define TFT_SCLK D10 +#define TFT_CS D20 // Chip select control pin +#define TFT_DC D18 // Data Command control pin +#define TFT_RST D19 // Reset pin (could connect to Arduino RESET pin) +//#define TFT_BL // LED back-light + +//#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen + +// ################################################################################## +// +// Section 3. Define the fonts that are to be used here +// +// ################################################################################## + +// Comment out the #defines below with // to stop that font being loaded +// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not +// normally necessary. If all fonts are loaded the extra FLASH space required is +// about 17Kbytes. To save FLASH space only enable the fonts you need! + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded +// this will save ~20kbytes of FLASH +#define SMOOTH_FONT + + +// ################################################################################## +// +// Section 4. Other options +// +// ################################################################################## + +// Define the SPI clock frequency, this affects the graphics rendering speed. Too +// fast and the TFT driver will not keep up and display corruption appears. +// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails +// With a ST7735 display more than 27MHz may not work (spurious pixels and lines) +// With an ILI9163 display 27 MHz works OK. + +// #define SPI_FREQUENCY 1000000 +// #define SPI_FREQUENCY 5000000 +// #define SPI_FREQUENCY 10000000 +// #define SPI_FREQUENCY 20000000 +// #define SPI_FREQUENCY 32000000 + #define SPI_FREQUENCY 63000000 + +// Optional reduced SPI frequency for reading TFT +#define SPI_READ_FREQUENCY 20000000 + +// 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/library.json b/library.json index 575f9e9..d4a0eb9 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "TFT_eSPI", - "version": "2.3.61", - "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, RM68140, SSD1963, ILI9225, HX8357D", - "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", + "version": "2.3.62", + "keywords": "Arduino, tft, ePaper, display, Pico, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, RM68140, SSD1963, ILI9225, HX8357D", + "description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32", "repository": { "type": "git", @@ -17,5 +17,5 @@ } ], "frameworks": "arduino", - "platforms": "espressif8266, espressif32, ststm32" + "platforms": "rp2040, espressif8266, espressif32, ststm32" } diff --git a/library.properties b/library.properties index f4a4560..4284fe1 100644 --- a/library.properties +++ b/library.properties @@ -1,8 +1,8 @@ name=TFT_eSPI -version=2.3.61 +version=2.3.62 author=Bodmer maintainer=Bodmer -sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 +sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32 paragraph=Supports TFT displays using drivers (ILI9341 etc) that operate with hardware SPI or 8 bit parallel. category=Display url=https://github.com/Bodmer/TFT_eSPI