mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-07-30 18:57:30 +02:00
Patch for ESP32 C3 - may or may not work!
I do NOT have and ESP32 C3 to test with!
This commit is contained in:
859
Processors/TFT_eSPI_ESP32_C3.c
Normal file
859
Processors/TFT_eSPI_ESP32_C3.c
Normal file
@ -0,0 +1,859 @@
|
|||||||
|
////////////////////////////////////////////////////
|
||||||
|
// TFT_eSPI driver functions for ESP32 processors //
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Global variables
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Select the SPI port to use, ESP32 has 2 options
|
||||||
|
#if !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#ifdef USE_HSPI_PORT
|
||||||
|
SPIClass spi = SPIClass(HSPI);
|
||||||
|
#elif defined(USE_FSPI_PORT)
|
||||||
|
SPIClass spi = SPIClass(FSPI);
|
||||||
|
#else // use default VSPI port
|
||||||
|
SPIClass spi = SPIClass(VSPI);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef USE_HSPI_PORT
|
||||||
|
SPIClass spi = SPIClass(HSPI);
|
||||||
|
#elif defined(USE_FSPI_PORT)
|
||||||
|
SPIClass spi = SPIClass(FSPI);
|
||||||
|
#else // use FSPI port
|
||||||
|
SPIClass& spi = SPI;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP32_DMA
|
||||||
|
// DMA SPA handle
|
||||||
|
spi_device_handle_t dmaHAL;
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define DMA_CHANNEL 1
|
||||||
|
#ifdef USE_HSPI_PORT
|
||||||
|
spi_host_device_t spi_host = HSPI_HOST;
|
||||||
|
#elif defined(USE_FSPI_PORT)
|
||||||
|
spi_host_device_t spi_host = SPI_HOST;
|
||||||
|
#else // use VSPI port
|
||||||
|
spi_host_device_t spi_host = VSPI_HOST;
|
||||||
|
#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
|
||||||
|
#else // use FSPI port
|
||||||
|
#define DMA_CHANNEL 1
|
||||||
|
spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
// Volatile for register reads:
|
||||||
|
volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT));
|
||||||
|
volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT));
|
||||||
|
// Register writes only:
|
||||||
|
volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT));
|
||||||
|
volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: beginSDA
|
||||||
|
** Description: Detach SPI from pin to permit software SPI
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::begin_SDA_Read(void)
|
||||||
|
{
|
||||||
|
pinMatrixOutDetach(TFT_MOSI, false, false);
|
||||||
|
pinMode(TFT_MOSI, INPUT);
|
||||||
|
pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false);
|
||||||
|
SET_BUS_READ_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: endSDA
|
||||||
|
** Description: Attach SPI pins after software SPI
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::end_SDA_Read(void)
|
||||||
|
{
|
||||||
|
pinMode(TFT_MOSI, OUTPUT);
|
||||||
|
pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false);
|
||||||
|
pinMode(TFT_MISO, INPUT);
|
||||||
|
pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false);
|
||||||
|
SET_BUS_WRITE_MODE;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // #if defined (TFT_SDA_READ)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: read byte - supports class functions
|
||||||
|
** Description: Read a byte from ESP32 8 bit data port
|
||||||
|
***************************************************************************************/
|
||||||
|
// Parallel bus MUST be set to input before calling this function!
|
||||||
|
uint8_t TFT_eSPI::readByte(void)
|
||||||
|
{
|
||||||
|
uint8_t b = 0xAA;
|
||||||
|
|
||||||
|
#if defined (TFT_PARALLEL_8_BIT)
|
||||||
|
RD_L;
|
||||||
|
uint32_t reg; // Read all GPIO pins 0-31
|
||||||
|
reg = gpio_input_get(); // Read three times to allow for bus access time
|
||||||
|
reg = gpio_input_get();
|
||||||
|
reg = gpio_input_get(); // Data should be stable now
|
||||||
|
RD_H;
|
||||||
|
|
||||||
|
// Check GPIO bits used and build value
|
||||||
|
b = (((reg>>TFT_D0)&1) << 0);
|
||||||
|
b |= (((reg>>TFT_D1)&1) << 1);
|
||||||
|
b |= (((reg>>TFT_D2)&1) << 2);
|
||||||
|
b |= (((reg>>TFT_D3)&1) << 3);
|
||||||
|
b |= (((reg>>TFT_D4)&1) << 4);
|
||||||
|
b |= (((reg>>TFT_D5)&1) << 5);
|
||||||
|
b |= (((reg>>TFT_D6)&1) << 6);
|
||||||
|
b |= (((reg>>TFT_D7)&1) << 7);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef TFT_PARALLEL_8_BIT
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** 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)
|
||||||
|
{
|
||||||
|
// Arduino generic native function
|
||||||
|
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: Set ESP32 GPIO pin to input or output (set high) ASAP
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
|
||||||
|
{
|
||||||
|
pinMode(gpio, mode);
|
||||||
|
digitalWrite(gpio, HIGH);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // #ifdef TFT_PARALLEL_8_BIT
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined (RPI_WRITE_STROBE) && !defined (TFT_PARALLEL_8_BIT) // Code for RPi TFT
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushBlock - for ESP32 or ESP8266 RPi TFT
|
||||||
|
** Description: Write a block of pixels of the same colour
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||||
|
{
|
||||||
|
uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color };
|
||||||
|
if(len) spi.writePattern(&colorBin[0], 2, 1); len--;
|
||||||
|
while(len--) {WR_L; WR_H;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushPixels - for ESP32 or ESP8266 RPi TFT
|
||||||
|
** Description: Write a sequence of pixels
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
|
||||||
|
{
|
||||||
|
uint8_t *data = (uint8_t*)data_in;
|
||||||
|
|
||||||
|
if(_swapBytes) {
|
||||||
|
while ( len-- ) {tft_Write_16(*data); data++;}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; }
|
||||||
|
if (len) spi.writePattern(data, len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#elif !defined (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI displays
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushBlock - for ESP32
|
||||||
|
** Description: Write a block of pixels of the same colour
|
||||||
|
***************************************************************************************/
|
||||||
|
/*
|
||||||
|
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||||
|
|
||||||
|
uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8);
|
||||||
|
bool empty = true;
|
||||||
|
volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w;
|
||||||
|
if (len > 31)
|
||||||
|
{
|
||||||
|
*_spi_mosi_dlen = 511;
|
||||||
|
spi_w[0] = color32;
|
||||||
|
spi_w[1] = color32;
|
||||||
|
spi_w[2] = color32;
|
||||||
|
spi_w[3] = color32;
|
||||||
|
spi_w[4] = color32;
|
||||||
|
spi_w[5] = color32;
|
||||||
|
spi_w[6] = color32;
|
||||||
|
spi_w[7] = color32;
|
||||||
|
spi_w[8] = color32;
|
||||||
|
spi_w[9] = color32;
|
||||||
|
spi_w[10] = color32;
|
||||||
|
spi_w[11] = color32;
|
||||||
|
spi_w[12] = color32;
|
||||||
|
spi_w[13] = color32;
|
||||||
|
spi_w[14] = color32;
|
||||||
|
spi_w[15] = color32;
|
||||||
|
while(len>31)
|
||||||
|
{
|
||||||
|
while ((*_spi_cmd)&SPI_USR);
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
len -= 32;
|
||||||
|
}
|
||||||
|
empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
if(empty) {
|
||||||
|
for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32;
|
||||||
|
}
|
||||||
|
len = (len << 4) - 1;
|
||||||
|
while (*_spi_cmd&SPI_USR);
|
||||||
|
*_spi_mosi_dlen = len;
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
}
|
||||||
|
while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully?
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
//*
|
||||||
|
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||||
|
|
||||||
|
volatile uint32_t* spi_w = _spi_w;
|
||||||
|
uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8);
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t rem = len & 0x1F;
|
||||||
|
len = len - rem;
|
||||||
|
|
||||||
|
// Start with partial buffer pixels
|
||||||
|
if (rem)
|
||||||
|
{
|
||||||
|
while (*_spi_cmd&SPI_USR);
|
||||||
|
for (i=0; i < rem; i+=2) *spi_w++ = color32;
|
||||||
|
*_spi_mosi_dlen = (rem << 4) - 1;
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
*_spi_cmd = SPI_UPDATE;
|
||||||
|
while (*_spi_cmd & SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
if (!len) return; //{while (*_spi_cmd&SPI_USR); return; }
|
||||||
|
i = i>>1; while(i++<16) *spi_w++ = color32;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*_spi_cmd&SPI_USR);
|
||||||
|
if (!rem) while (i++<16) *spi_w++ = color32;
|
||||||
|
*_spi_mosi_dlen = 511;
|
||||||
|
|
||||||
|
// End with full buffer to maximise useful time for downstream code
|
||||||
|
while(len)
|
||||||
|
{
|
||||||
|
while (*_spi_cmd&SPI_USR);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
*_spi_cmd = SPI_UPDATE;
|
||||||
|
while (*_spi_cmd & SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
len -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not wait here
|
||||||
|
//while (*_spi_cmd&SPI_USR);
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushSwapBytePixels - for ESP32
|
||||||
|
** Description: Write a sequence of pixels with swapped bytes
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
|
||||||
|
|
||||||
|
uint8_t* data = (uint8_t*)data_in;
|
||||||
|
uint32_t color[16];
|
||||||
|
|
||||||
|
if (len > 31)
|
||||||
|
{
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511);
|
||||||
|
while(len>31)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(i<16)
|
||||||
|
{
|
||||||
|
color[i++] = DAT8TO32(data);
|
||||||
|
data+=4;
|
||||||
|
}
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]);
|
||||||
|
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]);
|
||||||
|
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]);
|
||||||
|
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]);
|
||||||
|
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]);
|
||||||
|
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]);
|
||||||
|
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]);
|
||||||
|
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]);
|
||||||
|
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color[8]);
|
||||||
|
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color[9]);
|
||||||
|
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), color[10]);
|
||||||
|
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), color[11]);
|
||||||
|
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), color[12]);
|
||||||
|
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), color[13]);
|
||||||
|
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), color[14]);
|
||||||
|
WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), color[15]);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
len -= 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 15)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(i<8)
|
||||||
|
{
|
||||||
|
color[i++] = DAT8TO32(data);
|
||||||
|
data+=4;
|
||||||
|
}
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 255);
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]);
|
||||||
|
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]);
|
||||||
|
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]);
|
||||||
|
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]);
|
||||||
|
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]);
|
||||||
|
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]);
|
||||||
|
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]);
|
||||||
|
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
len -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1);
|
||||||
|
for (uint32_t i=0; i <= (len<<1); i+=4) {
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT)+i, DAT8TO32(data)); data+=4;
|
||||||
|
}
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
}
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushPixels - for ESP32
|
||||||
|
** Description: Write a sequence of pixels
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
|
||||||
|
|
||||||
|
if(_swapBytes) {
|
||||||
|
pushSwapBytePixels(data_in, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t *data = (uint32_t*)data_in;
|
||||||
|
|
||||||
|
if (len > 31)
|
||||||
|
{
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511);
|
||||||
|
while(len>31)
|
||||||
|
{
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), *data++);
|
||||||
|
WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), *data++);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
len -= 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1);
|
||||||
|
for (uint32_t i=0; i <= (len<<1); i+=4) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + i), *data++);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
}
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushBlock - for ESP32 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
|
||||||
|
uint32_t r = (color & 0xF800)>>8;
|
||||||
|
uint32_t g = (color & 0x07E0)<<5;
|
||||||
|
uint32_t b = (color & 0x001F)<<19;
|
||||||
|
// Concatenate 4 pixels into three 32 bit blocks
|
||||||
|
uint32_t r0 = r<<24 | b | g | r;
|
||||||
|
uint32_t r1 = r0>>8 | g<<16;
|
||||||
|
uint32_t r2 = r1>>8 | b<<8;
|
||||||
|
|
||||||
|
if (len > 19)
|
||||||
|
{
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 479);
|
||||||
|
|
||||||
|
while(len>19)
|
||||||
|
{
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2);
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
len -= 20;
|
||||||
|
}
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len * 24) - 1);
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2);
|
||||||
|
if (len > 8 )
|
||||||
|
{
|
||||||
|
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2);
|
||||||
|
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0);
|
||||||
|
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1);
|
||||||
|
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2);
|
||||||
|
}
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE);
|
||||||
|
#endif
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushPixels - for ESP32 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;
|
||||||
|
// ILI9488 write macro is not endianess dependant, hence !_swapBytes
|
||||||
|
if(!_swapBytes) { while ( len-- ) {tft_Write_16S(*data); data++;} }
|
||||||
|
else { while ( len-- ) {tft_Write_16(*data); data++;} }
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display
|
||||||
|
** Description: Write a sequence of pixels with swapped bytes
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
|
||||||
|
|
||||||
|
uint16_t *data = (uint16_t*)data_in;
|
||||||
|
// ILI9488 write macro is not endianess dependant, so swap byte macro not used here
|
||||||
|
while ( len-- ) {tft_Write_16(*data); data++;}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8 bit parallel
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushBlock - for ESP32 and parallel display
|
||||||
|
** Description: Write a block of pixels of the same colour
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||||
|
if ( (color >> 8) == (color & 0x00FF) )
|
||||||
|
{ if (!len) return;
|
||||||
|
tft_Write_16(color);
|
||||||
|
#if defined (SSD1963_DRIVER)
|
||||||
|
while (--len) {WR_L; WR_H; WR_L; WR_H; WR_L; WR_H;}
|
||||||
|
#else
|
||||||
|
#ifdef PSEUDO_16_BIT
|
||||||
|
while (--len) {WR_L; WR_H;}
|
||||||
|
#else
|
||||||
|
while (--len) {WR_L; WR_H; WR_L; WR_H;}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else while (len--) {tft_Write_16(color);}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushSwapBytePixels - for ESP32 and parallel display
|
||||||
|
** Description: Write a sequence of pixels with swapped bytes
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
|
||||||
|
|
||||||
|
uint16_t *data = (uint16_t*)data_in;
|
||||||
|
while ( len-- ) {tft_Write_16(*data); data++;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushPixels - for ESP32 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-- ) {tft_Write_16(*data); data++; } }
|
||||||
|
else { while ( len-- ) {tft_Write_16S(*data); data++;} }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // End of display interface specific functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: dmaBusy
|
||||||
|
** Description: Check if DMA is busy
|
||||||
|
***************************************************************************************/
|
||||||
|
bool TFT_eSPI::dmaBusy(void)
|
||||||
|
{
|
||||||
|
if (!DMA_Enabled || !spiBusyCheck) return false;
|
||||||
|
|
||||||
|
spi_transaction_t *rtrans;
|
||||||
|
esp_err_t ret;
|
||||||
|
uint8_t checks = spiBusyCheck;
|
||||||
|
for (int i = 0; i < checks; ++i)
|
||||||
|
{
|
||||||
|
ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0);
|
||||||
|
if (ret == ESP_OK) spiBusyCheck--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck);
|
||||||
|
if (spiBusyCheck ==0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: dmaWait
|
||||||
|
** Description: Wait until DMA is over (blocking!)
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::dmaWait(void)
|
||||||
|
{
|
||||||
|
if (!DMA_Enabled || !spiBusyCheck) return;
|
||||||
|
spi_transaction_t *rtrans;
|
||||||
|
esp_err_t ret;
|
||||||
|
for (int i = 0; i < spiBusyCheck; ++i)
|
||||||
|
{
|
||||||
|
ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
}
|
||||||
|
spiBusyCheck = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushPixelsDMA
|
||||||
|
** Description: Push pixels to TFT (len must be less than 32767)
|
||||||
|
***************************************************************************************/
|
||||||
|
// This will byte swap the original image if setSwapBytes(true) was called by sketch.
|
||||||
|
void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
|
||||||
|
{
|
||||||
|
if ((len == 0) || (!DMA_Enabled)) return;
|
||||||
|
|
||||||
|
dmaWait();
|
||||||
|
|
||||||
|
if(_swapBytes) {
|
||||||
|
for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
static spi_transaction_t trans;
|
||||||
|
|
||||||
|
memset(&trans, 0, sizeof(spi_transaction_t));
|
||||||
|
|
||||||
|
trans.user = (void *)1;
|
||||||
|
trans.tx_buffer = image; //finally send the line data
|
||||||
|
trans.length = len * 16; //Data length, in bits
|
||||||
|
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
|
||||||
|
|
||||||
|
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
|
||||||
|
spiBusyCheck++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushImageDMA
|
||||||
|
** Description: Push image to a window (w*h must be less than 65536)
|
||||||
|
***************************************************************************************/
|
||||||
|
// Fixed const data assumed, will NOT clip or swap bytes
|
||||||
|
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image)
|
||||||
|
{
|
||||||
|
if ((w == 0) || (h == 0) || (!DMA_Enabled)) return;
|
||||||
|
|
||||||
|
uint32_t len = w*h;
|
||||||
|
|
||||||
|
dmaWait();
|
||||||
|
|
||||||
|
setAddrWindow(x, y, w, h);
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
static spi_transaction_t trans;
|
||||||
|
|
||||||
|
memset(&trans, 0, sizeof(spi_transaction_t));
|
||||||
|
|
||||||
|
trans.user = (void *)1;
|
||||||
|
trans.tx_buffer = image; //Data pointer
|
||||||
|
trans.length = len * 16; //Data length, in bits
|
||||||
|
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
|
||||||
|
|
||||||
|
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
|
||||||
|
spiBusyCheck++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushImageDMA
|
||||||
|
** Description: Push image to a window (w*h must be less than 65536)
|
||||||
|
***************************************************************************************/
|
||||||
|
// This will clip and also swap bytes if setSwapBytes(true) was called by sketch
|
||||||
|
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer)
|
||||||
|
{
|
||||||
|
if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return;
|
||||||
|
|
||||||
|
int32_t dx = 0;
|
||||||
|
int32_t dy = 0;
|
||||||
|
int32_t dw = w;
|
||||||
|
int32_t dh = h;
|
||||||
|
|
||||||
|
if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; }
|
||||||
|
if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; }
|
||||||
|
|
||||||
|
if ((x + dw) > _vpW ) dw = _vpW - x;
|
||||||
|
if ((y + dh) > _vpH ) dh = _vpH - y;
|
||||||
|
|
||||||
|
if (dw < 1 || dh < 1) return;
|
||||||
|
|
||||||
|
uint32_t len = dw*dh;
|
||||||
|
|
||||||
|
if (buffer == nullptr) {
|
||||||
|
buffer = image;
|
||||||
|
dmaWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If image is clipped, copy pixels into a contiguous block
|
||||||
|
if ( (dw != w) || (dh != h) ) {
|
||||||
|
if(_swapBytes) {
|
||||||
|
for (int32_t yb = 0; yb < dh; yb++) {
|
||||||
|
for (int32_t xb = 0; xb < dw; xb++) {
|
||||||
|
uint32_t src = xb + dx + w * (yb + dy);
|
||||||
|
(buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int32_t yb = 0; yb < dh; yb++) {
|
||||||
|
memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else, if a buffer pointer has been provided copy whole image to the buffer
|
||||||
|
else if (buffer != image || _swapBytes) {
|
||||||
|
if(_swapBytes) {
|
||||||
|
for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(buffer, image, len*2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spiBusyCheck) dmaWait(); // In case we did not wait earlier
|
||||||
|
|
||||||
|
setAddrWindow(x, y, dw, dh);
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
static spi_transaction_t trans;
|
||||||
|
|
||||||
|
memset(&trans, 0, sizeof(spi_transaction_t));
|
||||||
|
|
||||||
|
trans.user = (void *)1;
|
||||||
|
trans.tx_buffer = buffer; //finally send the line data
|
||||||
|
trans.length = len * 16; //Data length, in bits
|
||||||
|
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
|
||||||
|
|
||||||
|
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
|
||||||
|
spiBusyCheck++;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Processor specific DMA initialisation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// The DMA functions here work with SPI only (not parallel)
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: dc_callback
|
||||||
|
** Description: Toggles DC line during transaction
|
||||||
|
***************************************************************************************/
|
||||||
|
extern "C" void dc_callback();
|
||||||
|
|
||||||
|
void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx)
|
||||||
|
{
|
||||||
|
if ((bool)spi_tx->user) {DC_D;}
|
||||||
|
else {DC_C;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: initDMA
|
||||||
|
** Description: Initialise the DMA engine - returns true if init OK
|
||||||
|
***************************************************************************************/
|
||||||
|
bool TFT_eSPI::initDMA(bool ctrl_cs)
|
||||||
|
{
|
||||||
|
if (DMA_Enabled) return false;
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
spi_bus_config_t buscfg = {
|
||||||
|
.mosi_io_num = TFT_MOSI,
|
||||||
|
.miso_io_num = TFT_MISO,
|
||||||
|
.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
|
||||||
|
.flags = 0,
|
||||||
|
.intr_flags = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
int8_t pin = -1;
|
||||||
|
if (ctrl_cs) pin = TFT_CS;
|
||||||
|
|
||||||
|
spi_device_interface_config_t devcfg = {
|
||||||
|
.command_bits = 0,
|
||||||
|
.address_bits = 0,
|
||||||
|
.dummy_bits = 0,
|
||||||
|
.mode = TFT_SPI_MODE,
|
||||||
|
.duty_cycle_pos = 0,
|
||||||
|
.cs_ena_pretrans = 0,
|
||||||
|
.cs_ena_posttrans = 0,
|
||||||
|
.clock_speed_hz = SPI_FREQUENCY,
|
||||||
|
.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
|
||||||
|
};
|
||||||
|
ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL);
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL);
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
DMA_Enabled = true;
|
||||||
|
spiBusyCheck = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: deInitDMA
|
||||||
|
** Description: Disconnect the DMA engine from SPI
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::deInitDMA(void)
|
||||||
|
{
|
||||||
|
if (!DMA_Enabled) return;
|
||||||
|
spi_bus_remove_device(dmaHAL);
|
||||||
|
spi_bus_free(spi_host);
|
||||||
|
DMA_Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // End of DMA FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
608
Processors/TFT_eSPI_ESP32_C3.h
Normal file
608
Processors/TFT_eSPI_ESP32_C3.h
Normal file
@ -0,0 +1,608 @@
|
|||||||
|
////////////////////////////////////////////////////
|
||||||
|
// TFT_eSPI driver functions for ESP32 processors //
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _TFT_eSPI_ESP32H_
|
||||||
|
#define _TFT_eSPI_ESP32H_
|
||||||
|
|
||||||
|
// Processor ID reported by getSetup()
|
||||||
|
#define PROCESSOR_ID 0x32
|
||||||
|
|
||||||
|
// Include processor specific header
|
||||||
|
#include "soc/spi_reg.h"
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
|
||||||
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32)
|
||||||
|
#define CONFIG_IDF_TARGET_ESP32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VSPI
|
||||||
|
#define VSPI FSPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fix IDF problems with ESP32C3
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
// Fix ESP32C3 IDF bug for missing definition (VSPI/FSPI only tested at the moment)
|
||||||
|
#ifndef REG_SPI_BASE
|
||||||
|
//Will this work as per S3? #define REG_SPI_BASE(i) (((i)>1) ? (DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE))
|
||||||
|
#define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Fix ESP32C3 IDF bug for name change
|
||||||
|
#ifndef SPI_MOSI_DLEN_REG
|
||||||
|
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
|
||||||
|
#if !defined (SUPPORT_TRANSACTIONS)
|
||||||
|
#define SUPPORT_TRANSACTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
ESP32:
|
||||||
|
FSPI not defined
|
||||||
|
HSPI = 2, uses SPI2
|
||||||
|
VSPI = 3, uses SPI3
|
||||||
|
|
||||||
|
ESP32-S2:
|
||||||
|
FSPI = 1, uses SPI2
|
||||||
|
HSPI = 2, uses SPI3
|
||||||
|
VSPI not defined
|
||||||
|
|
||||||
|
ESP32 C3:
|
||||||
|
FSPI = 0, uses SPI2 ???? To be checked
|
||||||
|
HSPI = 1, uses SPI3 ???? To be checked
|
||||||
|
VSPI not defined
|
||||||
|
|
||||||
|
For ESP32/S2/C3:
|
||||||
|
SPI1_HOST = 0
|
||||||
|
SPI2_HOST = 1
|
||||||
|
SPI3_HOST = 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ESP32 specific SPI port selection
|
||||||
|
#ifdef USE_HSPI_PORT
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SPI_PORT HSPI //HSPI is port 2 on ESP32
|
||||||
|
#else
|
||||||
|
#define SPI_PORT 3 //HSPI is port 3 on ESP32 S2
|
||||||
|
#endif
|
||||||
|
#elif defined(USE_FSPI_PORT)
|
||||||
|
#define SPI_PORT 2 //FSPI(ESP32 S2)
|
||||||
|
#else
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SPI_PORT VSPI
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#define SPI_PORT 2 //FSPI(ESP32 S2)
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#define SPI_PORT FSPI
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RPI_DISPLAY_TYPE
|
||||||
|
#define CMD_BITS (16-1)
|
||||||
|
#else
|
||||||
|
#define CMD_BITS (8-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialise processor specific SPI functions, used by init()
|
||||||
|
#define INIT_TFT_DATA_BUS // Not used
|
||||||
|
|
||||||
|
// Define a generic flag for 8 bit parallel
|
||||||
|
#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility
|
||||||
|
#if !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
#define TFT_PARALLEL_8_BIT // Generic parallel flag
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Ensure ESP32 specific flag is defined for 8 bit parallel
|
||||||
|
#if defined (TFT_PARALLEL_8_BIT)
|
||||||
|
#if !defined (ESP32_PARALLEL)
|
||||||
|
#define ESP32_PARALLEL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Processor specific code used by SPI bus transaction startWrite and endWrite functions
|
||||||
|
#if !defined (ESP32_PARALLEL)
|
||||||
|
#if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2)
|
||||||
|
#define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE
|
||||||
|
#define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE
|
||||||
|
#else
|
||||||
|
#define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI
|
||||||
|
#define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Not applicable to parallel bus
|
||||||
|
#define SET_BUS_WRITE_MODE
|
||||||
|
#define SET_BUS_READ_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions
|
||||||
|
#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()
|
||||||
|
#else
|
||||||
|
#define DMA_BUSY_CHECK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TFT_PARALLEL_8_BIT)
|
||||||
|
#define SPI_BUSY_CHECK
|
||||||
|
#else
|
||||||
|
#define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If smooth font is used then it is likely SPIFFS will be needed
|
||||||
|
#ifdef SMOOTH_FONT
|
||||||
|
// Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts
|
||||||
|
#define FS_NO_GLOBALS
|
||||||
|
#include <FS.h>
|
||||||
|
#include "SPIFFS.h" // ESP32 only
|
||||||
|
#define FONT_FS_AVAILABLE
|
||||||
|
#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
|
||||||
|
#if defined (TFT_PARALLEL_8_BIT)
|
||||||
|
// TFT_DC, by design, must be in range 0-31 for single register parallel write
|
||||||
|
#if (TFT_DC >= 0) && (TFT_DC < 32)
|
||||||
|
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)
|
||||||
|
#define DC_D GPIO.out_w1ts.val = (1 << TFT_DC)
|
||||||
|
#else
|
||||||
|
#define DC_C
|
||||||
|
#define DC_D
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if (TFT_DC >= 32)
|
||||||
|
#ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change
|
||||||
|
#define DC_C GPIO.out_w1ts.val = (1 << (TFT_DC - 32)); \
|
||||||
|
GPIO.out_w1tc.val = (1 << (TFT_DC - 32))
|
||||||
|
#define DC_D GPIO.out_w1tc.val = (1 << (TFT_DC - 32)); \
|
||||||
|
GPIO.out_w1ts.val = (1 << (TFT_DC - 32))
|
||||||
|
#else
|
||||||
|
#define DC_C GPIO.out_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out_w1tc.val = (1 << (TFT_DC - 32))
|
||||||
|
#define DC_D GPIO.out_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out_w1ts.val = (1 << (TFT_DC - 32))
|
||||||
|
#endif
|
||||||
|
#elif (TFT_DC >= 0)
|
||||||
|
#if defined (RPI_DISPLAY_TYPE)
|
||||||
|
#if defined (ILI9486_DRIVER)
|
||||||
|
// RPi ILI9486 display needs a slower DC change
|
||||||
|
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC); \
|
||||||
|
GPIO.out_w1tc.val = (1 << TFT_DC)
|
||||||
|
#define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \
|
||||||
|
GPIO.out_w1ts.val = (1 << TFT_DC)
|
||||||
|
#else
|
||||||
|
// Other RPi displays need a slower C->D change
|
||||||
|
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)
|
||||||
|
#define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \
|
||||||
|
GPIO.out_w1ts.val = (1 << TFT_DC)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)//;GPIO.out_w1tc.val = (1 << TFT_DC)
|
||||||
|
#define DC_D GPIO.out_w1ts.val = (1 << TFT_DC)//;GPIO.out_w1ts.val = (1 << TFT_DC)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DC_C
|
||||||
|
#define DC_D
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define the CS (TFT chip select) pin drive code
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifndef TFT_CS
|
||||||
|
#define TFT_CS -1 // Keep DMA code happy
|
||||||
|
#define CS_L // No macro allocated so it generates no code
|
||||||
|
#define CS_H // No macro allocated so it generates no code
|
||||||
|
#else
|
||||||
|
#if defined (TFT_PARALLEL_8_BIT)
|
||||||
|
#if TFT_CS >= 32
|
||||||
|
#define CS_L GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
|
||||||
|
#define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
|
||||||
|
#elif TFT_CS >= 0
|
||||||
|
#define CS_L GPIO.out_w1tc.val = (1 << TFT_CS)
|
||||||
|
#define CS_H GPIO.out_w1ts.val = (1 << TFT_CS)
|
||||||
|
#else
|
||||||
|
#define CS_L
|
||||||
|
#define CS_H
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if (TFT_CS >= 32)
|
||||||
|
#ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change
|
||||||
|
#define CS_L GPIO.out_w1ts.val = (1 << (TFT_CS - 32)); \
|
||||||
|
GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
|
||||||
|
#define CS_H GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); \
|
||||||
|
GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
|
||||||
|
#else
|
||||||
|
#define CS_L GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
|
||||||
|
#define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
|
||||||
|
#endif
|
||||||
|
#elif (TFT_CS >= 0)
|
||||||
|
#ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change
|
||||||
|
#define CS_L GPIO.out_w1ts.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS)
|
||||||
|
#define CS_H GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1ts.val = (1 << TFT_CS)
|
||||||
|
#else
|
||||||
|
#define CS_L GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS)
|
||||||
|
#define CS_H GPIO.out_w1ts.val = (1 << TFT_CS)//;GPIO.out_w1ts.val = (1 << TFT_CS)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define CS_L
|
||||||
|
#define CS_H
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define the WR (TFT Write) pin drive code
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined (TFT_WR)
|
||||||
|
#if (TFT_WR >= 32)
|
||||||
|
// Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32
|
||||||
|
#define WR_L GPIO.out_w1tc.val = (1 << (TFT_WR - 32))
|
||||||
|
#define WR_H GPIO.out_w1ts.val = (1 << (TFT_WR - 32))
|
||||||
|
#elif (TFT_WR >= 0)
|
||||||
|
// TFT_WR, for best performance, should be in range 0-31 for single register parallel write
|
||||||
|
#define WR_L GPIO.out_w1tc.val = (1 << TFT_WR)
|
||||||
|
#define WR_H GPIO.out_w1ts.val = (1 << TFT_WR)
|
||||||
|
#else
|
||||||
|
#define WR_L
|
||||||
|
#define WR_H
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define WR_L
|
||||||
|
#define WR_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define the touch screen chip select pin drive code
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifndef TOUCH_CS
|
||||||
|
#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 // XPT2046 is slow, so use slower digitalWrite here
|
||||||
|
#define T_CS_L digitalWrite(TOUCH_CS, LOW)
|
||||||
|
#define T_CS_H digitalWrite(TOUCH_CS, HIGH)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Make sure SPI default pins are assigned if not specified by user or set to -1
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
|
||||||
|
#ifdef USE_HSPI_PORT
|
||||||
|
|
||||||
|
#ifndef TFT_MISO
|
||||||
|
#define TFT_MISO -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TFT_MOSI
|
||||||
|
#define TFT_MOSI 13
|
||||||
|
#endif
|
||||||
|
#if (TFT_MOSI == -1)
|
||||||
|
#undef TFT_MOSI
|
||||||
|
#define TFT_MOSI 13
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TFT_SCLK
|
||||||
|
#define TFT_SCLK 14
|
||||||
|
#endif
|
||||||
|
#if (TFT_SCLK == -1)
|
||||||
|
#undef TFT_SCLK
|
||||||
|
#define TFT_SCLK 14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else // VSPI port
|
||||||
|
|
||||||
|
#ifndef TFT_MISO
|
||||||
|
#define TFT_MISO -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TFT_MOSI
|
||||||
|
#define TFT_MOSI 23
|
||||||
|
#endif
|
||||||
|
#if (TFT_MOSI == -1)
|
||||||
|
#undef TFT_MOSI
|
||||||
|
#define TFT_MOSI 23
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TFT_SCLK
|
||||||
|
#define TFT_SCLK 18
|
||||||
|
#endif
|
||||||
|
#if (TFT_SCLK == -1)
|
||||||
|
#undef TFT_SCLK
|
||||||
|
#define TFT_SCLK 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
#if (TFT_MISO == -1)
|
||||||
|
#undef TFT_MISO
|
||||||
|
#define TFT_MISO TFT_MOSI
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define the parallel bus interface chip pin drive code
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined (TFT_PARALLEL_8_BIT)
|
||||||
|
|
||||||
|
// Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically
|
||||||
|
// can then use e.g. GPIO.out_w1ts.val = set_mask(0xFF); to set data bus to 0xFF
|
||||||
|
#define PARALLEL_INIT_TFT_DATA_BUS \
|
||||||
|
for (int32_t c = 0; c<256; c++) \
|
||||||
|
{ \
|
||||||
|
xset_mask[c] = 0; \
|
||||||
|
if ( c & 0x01 ) xset_mask[c] |= (1 << TFT_D0); \
|
||||||
|
if ( c & 0x02 ) xset_mask[c] |= (1 << TFT_D1); \
|
||||||
|
if ( c & 0x04 ) xset_mask[c] |= (1 << TFT_D2); \
|
||||||
|
if ( c & 0x08 ) xset_mask[c] |= (1 << TFT_D3); \
|
||||||
|
if ( c & 0x10 ) xset_mask[c] |= (1 << TFT_D4); \
|
||||||
|
if ( c & 0x20 ) xset_mask[c] |= (1 << TFT_D5); \
|
||||||
|
if ( c & 0x40 ) xset_mask[c] |= (1 << TFT_D6); \
|
||||||
|
if ( c & 0x80 ) xset_mask[c] |= (1 << TFT_D7); \
|
||||||
|
} \
|
||||||
|
|
||||||
|
// Mask for the 8 data bits to set pin directions
|
||||||
|
#define dir_mask ((1 << TFT_D0) | (1 << TFT_D1) | (1 << TFT_D2) | (1 << TFT_D3) | (1 << TFT_D4) | (1 << TFT_D5) | (1 << TFT_D6) | (1 << TFT_D7))
|
||||||
|
|
||||||
|
#if (TFT_WR >= 32)
|
||||||
|
// Data bits and the write line are cleared sequentially
|
||||||
|
#define clr_mask (dir_mask); WR_L
|
||||||
|
#elif (TFT_WR >= 0)
|
||||||
|
// Data bits and the write line are cleared to 0 in one step (1.25x faster)
|
||||||
|
#define clr_mask (dir_mask | (1 << TFT_WR))
|
||||||
|
#else
|
||||||
|
#define clr_mask
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A lookup table is used to set the different bit patterns, this uses 1kByte of RAM
|
||||||
|
#define set_mask(C) xset_mask[C] // 63fps Sprite rendering test 33% faster, graphicstest only 1.8% faster than shifting in real time
|
||||||
|
|
||||||
|
// Real-time shifting alternative to above to save 1KByte RAM, 47 fps Sprite rendering test
|
||||||
|
/*#define set_mask(C) (((C)&0x80)>>7)<<TFT_D7 | (((C)&0x40)>>6)<<TFT_D6 | (((C)&0x20)>>5)<<TFT_D5 | (((C)&0x10)>>4)<<TFT_D4 | \
|
||||||
|
(((C)&0x08)>>3)<<TFT_D3 | (((C)&0x04)>>2)<<TFT_D2 | (((C)&0x02)>>1)<<TFT_D1 | (((C)&0x01)>>0)<<TFT_D0
|
||||||
|
//*/
|
||||||
|
|
||||||
|
// Write 8 bits to TFT
|
||||||
|
#define tft_Write_8(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t)(C)); WR_H
|
||||||
|
|
||||||
|
#if defined (SSD1963_DRIVER)
|
||||||
|
|
||||||
|
// Write 18 bit color to TFT
|
||||||
|
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H
|
||||||
|
|
||||||
|
// 18 bit color write with swapped bytes
|
||||||
|
#define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef PSEUDO_16_BIT
|
||||||
|
// One write strobe for both bytes
|
||||||
|
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||||
|
#define tft_Write_16S(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||||
|
#else
|
||||||
|
// Write 16 bits to TFT
|
||||||
|
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||||
|
|
||||||
|
// 16 bit write with swapped bytes
|
||||||
|
#define tft_Write_16S(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Write 32 bits to TFT
|
||||||
|
#define tft_Write_32(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 24)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 16)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||||
|
|
||||||
|
// Write two concatenated 16 bit values to TFT
|
||||||
|
#define tft_Write_32C(C,D) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 0)); WR_H
|
||||||
|
|
||||||
|
// Write 16 bit value twice to TFT - used by drawPixel()
|
||||||
|
#define tft_Write_32D(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||||
|
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||||
|
|
||||||
|
// Read pin
|
||||||
|
#ifdef TFT_RD
|
||||||
|
#if (TFT_RD >= 32)
|
||||||
|
#define RD_L GPIO.out_w1tc.val = (1 << (TFT_RD - 32))
|
||||||
|
#define RD_H GPIO.out_w1ts.val = (1 << (TFT_RD - 32))
|
||||||
|
#elif (TFT_RD >= 0)
|
||||||
|
#define RD_L GPIO.out_w1tc.val = (1 << TFT_RD)
|
||||||
|
//#define RD_L digitalWrite(TFT_WR, LOW)
|
||||||
|
#define RD_H GPIO.out_w1ts.val = (1 << TFT_RD)
|
||||||
|
//#define RD_H digitalWrite(TFT_WR, HIGH)
|
||||||
|
#else
|
||||||
|
#define RD_L
|
||||||
|
#define RD_H
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define TFT_RD -1
|
||||||
|
#define RD_L
|
||||||
|
#define RD_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Macros to write commands/pixel colour data to a SPI ILI948x TFT
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#elif 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)
|
||||||
|
|
||||||
|
// Future option for transfer without wait
|
||||||
|
#define tft_Write_16N(C) tft_Write_16(C)
|
||||||
|
|
||||||
|
// 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.write32(C)
|
||||||
|
|
||||||
|
// Write two concatenated 16 bit values to TFT
|
||||||
|
#define tft_Write_32C(C,D) spi.write32((C)<<16 | (D))
|
||||||
|
|
||||||
|
// Write 16 bit value twice to TFT
|
||||||
|
#define tft_Write_32D(C) spi.write32((C)<<16 | (C))
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Macros to write commands/pixel colour data to an Raspberry Pi TFT
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#elif defined (RPI_DISPLAY_TYPE)
|
||||||
|
|
||||||
|
// ESP32 low level SPI writes for 8, 16 and 32 bit values
|
||||||
|
// to avoid the function call overhead
|
||||||
|
#define TFT_WRITE_BITS(D, B) \
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
|
||||||
|
// Write 8 bits
|
||||||
|
#define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16)
|
||||||
|
|
||||||
|
// Write 16 bits with corrected endianness for 16 bit colours
|
||||||
|
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
|
||||||
|
|
||||||
|
// Future option for transfer without wait
|
||||||
|
#define tft_Write_16N(C) tft_Write_16(C)
|
||||||
|
|
||||||
|
// Write 16 bits
|
||||||
|
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
|
||||||
|
|
||||||
|
// Write 32 bits
|
||||||
|
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
|
||||||
|
|
||||||
|
// Write two address coordinates
|
||||||
|
#define tft_Write_32C(C,D) TFT_WRITE_BITS((C)<<24 | (C), 32); \
|
||||||
|
TFT_WRITE_BITS((D)<<24 | (D), 32)
|
||||||
|
|
||||||
|
// Write same value twice
|
||||||
|
#define tft_Write_32D(C) tft_Write_32C(C,C)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Macros for all other SPI displays
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#else
|
||||||
|
/* Old macros
|
||||||
|
// ESP32 low level SPI writes for 8, 16 and 32 bit values
|
||||||
|
// to avoid the function call overhead
|
||||||
|
#define TFT_WRITE_BITS(D, B) \
|
||||||
|
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \
|
||||||
|
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \
|
||||||
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \
|
||||||
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
|
||||||
|
|
||||||
|
// Write 8 bits
|
||||||
|
#define tft_Write_8(C) TFT_WRITE_BITS(C, 8)
|
||||||
|
|
||||||
|
// Write 16 bits with corrected endianness for 16 bit colours
|
||||||
|
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
|
||||||
|
|
||||||
|
// Write 16 bits
|
||||||
|
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
|
||||||
|
|
||||||
|
// Write 32 bits
|
||||||
|
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
|
||||||
|
|
||||||
|
// Write two address coordinates
|
||||||
|
#define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
|
||||||
|
|
||||||
|
// Write same value twice
|
||||||
|
#define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
|
||||||
|
//*/
|
||||||
|
//* Replacement slimmer macros
|
||||||
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
|
||||||
|
*_spi_w = D; \
|
||||||
|
*_spi_cmd = SPI_USR; \
|
||||||
|
while (*_spi_cmd & SPI_USR);
|
||||||
|
#else
|
||||||
|
#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
|
||||||
|
*_spi_w = D; \
|
||||||
|
*_spi_cmd = SPI_UPDATE; \
|
||||||
|
while (*_spi_cmd & SPI_UPDATE); \
|
||||||
|
*_spi_cmd = SPI_USR; \
|
||||||
|
while (*_spi_cmd & SPI_USR);
|
||||||
|
#endif
|
||||||
|
// Write 8 bits
|
||||||
|
#define tft_Write_8(C) TFT_WRITE_BITS(C, 8)
|
||||||
|
|
||||||
|
// Write 16 bits with corrected endianness for 16 bit colours
|
||||||
|
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
|
||||||
|
|
||||||
|
// Future option for transfer without wait
|
||||||
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
|
||||||
|
*_spi_w = ((C)<<8 | (C)>>8); \
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
#else
|
||||||
|
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
|
||||||
|
*_spi_w = ((C)<<8 | (C)>>8); \
|
||||||
|
*_spi_cmd = SPI_UPDATE; \
|
||||||
|
while (*_spi_cmd & SPI_UPDATE); \
|
||||||
|
*_spi_cmd = SPI_USR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Write 16 bits
|
||||||
|
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
|
||||||
|
|
||||||
|
// Write 32 bits
|
||||||
|
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
|
||||||
|
|
||||||
|
// Write two address coordinates
|
||||||
|
#define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
|
||||||
|
|
||||||
|
// Write same value twice
|
||||||
|
#define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
|
||||||
|
|
||||||
|
//*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef tft_Write_16N
|
||||||
|
#define tft_Write_16N tft_Write_16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Macros to read from display using SPI or software SPI
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined (TFT_PARALLEL_8_BIT)
|
||||||
|
// Read from display using SPI or software SPI
|
||||||
|
// Use a SPI read transfer
|
||||||
|
#define tft_Read_8() spi.transfer(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Concatenate a byte sequence A,B,C,D to CDAB, P is a uint8_t pointer
|
||||||
|
#define DAT8TO32(P) ( (uint32_t)P[0]<<8 | P[1] | P[2]<<24 | P[3]<<16 )
|
||||||
|
|
||||||
|
#endif // Header end
|
@ -19,6 +19,8 @@
|
|||||||
#if defined (ESP32)
|
#if defined (ESP32)
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#include "Processors/TFT_eSPI_ESP32_S3.c"
|
#include "Processors/TFT_eSPI_ESP32_S3.c"
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#include "Processors/TFT_eSPI_ESP32_C3.c"
|
||||||
#else
|
#else
|
||||||
#include "Processors/TFT_eSPI_ESP32.c"
|
#include "Processors/TFT_eSPI_ESP32.c"
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,6 +67,8 @@
|
|||||||
// Include the processor specific drivers
|
// Include the processor specific drivers
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#include "Processors/TFT_eSPI_ESP32_S3.h"
|
#include "Processors/TFT_eSPI_ESP32_S3.h"
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#include "Processors/TFT_eSPI_ESP32_C3.h"
|
||||||
#elif defined (ESP32)
|
#elif defined (ESP32)
|
||||||
#include "Processors/TFT_eSPI_ESP32.h"
|
#include "Processors/TFT_eSPI_ESP32.h"
|
||||||
#elif defined (ESP8266)
|
#elif defined (ESP8266)
|
||||||
|
Reference in New Issue
Block a user