diff --git a/Processors/TFT_eSPI_ESP32_S3.c b/Processors/TFT_eSPI_ESP32_S3.c index 2958b52..9d23a7c 100644 --- a/Processors/TFT_eSPI_ESP32_S3.c +++ b/Processors/TFT_eSPI_ESP32_S3.c @@ -43,11 +43,11 @@ #endif #else #ifdef USE_HSPI_PORT - #define DMA_CHANNEL 2 - spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes + #define DMA_CHANNEL SPI_DMA_CH_AUTO + spi_host_device_t spi_host = SPI3_HOST; #else // use FSPI port - #define DMA_CHANNEL 1 - spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes + #define DMA_CHANNEL SPI_DMA_CH_AUTO + spi_host_device_t spi_host = SPI2_HOST; #endif #endif #endif @@ -643,6 +643,15 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); } + // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint + // small transfers are performed using a blocking call until DMA capacity is reached. + // User sketch can prevent blocking by managing pixel count and splitting into blocks + // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) + while(len>0x4000) { // Transfer 16 bit pixels in blocks if len*2 over 65536 bytes + pushPixels(image, 0x400); + len -= 0x400; image+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) + } + esp_err_t ret; static spi_transaction_t trans; @@ -669,11 +678,20 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t { if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; + uint16_t *buffer = (uint16_t*)image; uint32_t len = w*h; dmaWait(); setAddrWindow(x, y, w, h); + // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint + // small transfers are performed using a blocking call until DMA capacity is reached. + // User sketch can prevent blocking by managing pixel count and splitting into blocks + // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) + while(len>0x4000) { // Transfer 16 bit pixels in blocks if len*2 over 65536 bytes + pushPixels(buffer, 0x400); + len -= 0x400; buffer+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) + } esp_err_t ret; static spi_transaction_t trans; @@ -681,7 +699,7 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t memset(&trans, 0, sizeof(spi_transaction_t)); trans.user = (void *)1; - trans.tx_buffer = image; //Data pointer + trans.tx_buffer = buffer; //Data pointer trans.length = len * 16; //Data length, in bits trans.flags = 0; //SPI_TRANS_USE_TXDATA flag @@ -751,6 +769,15 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t setAddrWindow(x, y, dw, dh); + // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint + // small transfers are performed using a blocking call until DMA capacity is reached. + // User sketch can prevent blocking by managing pixel count and splitting into blocks + // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) + while(len>0x4000) { // Transfer 16 bit pixels in blocks if len*2 over 65536 bytes + pushPixels(buffer, 0x400); + len -= 0x400; buffer+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) + } + esp_err_t ret; static spi_transaction_t trans; @@ -774,7 +801,7 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t // The DMA functions here work with SPI only (not parallel) /*************************************************************************************** ** Function name: dc_callback -** Description: Toggles DC line during transaction +** Description: Toggles DC line during transaction (not used) ***************************************************************************************/ extern "C" void dc_callback(); @@ -784,6 +811,17 @@ void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) else {DC_C;} } +/*************************************************************************************** +** Function name: dma_end_callback +** Description: Clear DMA run flag to stop retransmission loop +***************************************************************************************/ +extern "C" void dma_end_callback(); + +void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) +{ + WRITE_PERI_REG(SPI_DMA_CONF_REG(spi_host), 0); +} + /*************************************************************************************** ** Function name: initDMA ** Description: Initialise the DMA engine - returns true if init OK @@ -799,7 +837,7 @@ bool TFT_eSPI::initDMA(bool ctrl_cs) .sclk_io_num = TFT_SCLK, .quadwp_io_num = -1, .quadhd_io_num = -1, - .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size + .max_transfer_sz = 65536, // ESP32 S3 max size is 64Kbytes .flags = 0, .intr_flags = 0 }; @@ -819,9 +857,9 @@ bool TFT_eSPI::initDMA(bool ctrl_cs) .input_delay_ns = 0, .spics_io_num = pin, .flags = SPI_DEVICE_NO_DUMMY, //0, - .queue_size = 1, - .pre_cb = 0, //dc_callback, //Callback to handle D/C line - .post_cb = 0 + .queue_size = 1, // Not using queues + .pre_cb = 0, //dc_callback, //Callback to handle D/C line (not used) + .post_cb = dma_end_callback //Callback to end transmission }; ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); ESP_ERROR_CHECK(ret); diff --git a/Processors/TFT_eSPI_ESP32_S3.h b/Processors/TFT_eSPI_ESP32_S3.h index 197ebc5..2c366df 100644 --- a/Processors/TFT_eSPI_ESP32_S3.h +++ b/Processors/TFT_eSPI_ESP32_S3.h @@ -134,7 +134,7 @@ SPI3_HOST = 2 #if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) #define ESP32_DMA // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK //dmaWait() + #define DMA_BUSY_CHECK dmaWait() #else #define DMA_BUSY_CHECK #endif @@ -366,7 +366,7 @@ SPI3_HOST = 2 #define PARALLEL_INIT_TFT_DATA_BUS \ for (int32_t c = 0; c<256; c++) \ { \ - xset_mask[c] = 0; \ + xset_mask[c] = 0; \ if ( c & 0x01 ) xset_mask[c] |= (1 << (TFT_D0-MASK_OFFSET)); \ if ( c & 0x02 ) xset_mask[c] |= (1 << (TFT_D1-MASK_OFFSET)); \ if ( c & 0x04 ) xset_mask[c] |= (1 << (TFT_D2-MASK_OFFSET)); \ @@ -374,8 +374,8 @@ SPI3_HOST = 2 if ( c & 0x10 ) xset_mask[c] |= (1 << (TFT_D4-MASK_OFFSET)); \ if ( c & 0x20 ) xset_mask[c] |= (1 << (TFT_D5-MASK_OFFSET)); \ if ( c & 0x40 ) xset_mask[c] |= (1 << (TFT_D6-MASK_OFFSET)); \ - if ( c & 0x80 ) xset_mask[c] |= (1 << (TFT_D7-MASK_OFFSET)); \ - } \ + if ( c & 0x80 ) xset_mask[c] |= (1 << (TFT_D7-MASK_OFFSET)); \ + } \ // Mask for the 8 data bits to set pin directions #define GPIO_DIR_MASK ((1 << (TFT_D0-MASK_OFFSET)) | (1 << (TFT_D1-MASK_OFFSET)) | (1 << (TFT_D2-MASK_OFFSET)) | (1 << (TFT_D3-MASK_OFFSET)) | (1 << (TFT_D4-MASK_OFFSET)) | (1 << (TFT_D5-MASK_OFFSET)) | (1 << (TFT_D6-MASK_OFFSET)) | (1 << (TFT_D7-MASK_OFFSET))) diff --git a/TFT_eSPI.h b/TFT_eSPI.h index d0de6a5..fac79a8 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.5.1" +#define TFT_ESPI_VERSION "2.5.2" // Bit level feature flags // Bit 0 set: viewport capability diff --git a/library.json b/library.json index 4746287..bac8f01 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.5.1", + "version": "2.5.2", "keywords": "Arduino, tft, display, ttgo, LilyPi, WT32-SC01, ePaper, display, Pico, RP2040 Nano Connect, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, ST7796, RM68140, SSD1351, SSD1963, ILI9225, HX8357D, GC9A01, R61581", "description": "A TFT and ePaper (SPI or parallel interface) graphics library with optimisation for Raspberry Pi Pico, RP2040, ESP8266, ESP32 and STM32 processors", "repository": diff --git a/library.properties b/library.properties index d0c6448..2006074 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.5.1 +version=2.5.2 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32