mirror of
https://github.com/jaksatomovic/esp32-clickwheel.git
synced 2025-08-29 15:48:29 -04:00
first commit
This commit is contained in:
commit
868b14f8c8
286 changed files with 59925 additions and 0 deletions
827
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.c
Normal file
827
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.c
Normal file
|
@ -0,0 +1,827 @@
|
|||
////////////////////////////////////////////////////
|
||||
// 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);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
*_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);
|
||||
*_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]);
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
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++);
|
||||
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++);
|
||||
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)
|
||||
{
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S);
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (len * 24) - 1, SPI_USR_MOSI_DBITLEN_S);
|
||||
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);
|
||||
}
|
||||
|
||||
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 defined (SSD1963_DRIVER)
|
||||
if ( ((color & 0xF800)>> 8) == ((color & 0x07E0)>> 3) && ((color & 0xF800)>> 8)== ((color & 0x001F)<< 3) )
|
||||
#else
|
||||
if ( (color >> 8) == (color & 0x00FF) )
|
||||
#endif
|
||||
{ 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
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
596
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.h
Normal file
596
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.h
Normal file
|
@ -0,0 +1,596 @@
|
|||
////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
// Fix IDF problems with ESP32C3
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
// Fix ESP32C3 IDF bug for missing definition
|
||||
#ifndef REG_SPI_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
|
||||
|
||||
// Fix ESP32C3 specific register reference
|
||||
#define out_w1tc out_w1tc.val
|
||||
#define out_w1ts out_w1ts.val
|
||||
#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
|
||||
#else
|
||||
#define SPI_PORT 2 //FSPI(ESP32 S2)
|
||||
#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>
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
#include "SPIFFS.h" // ESP32 only
|
||||
#else
|
||||
#ifndef SPIFFS
|
||||
#include <LittleFS.h>
|
||||
#define SPIFFS LittleFS
|
||||
#endif
|
||||
#endif
|
||||
#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 = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#elif (TFT_DC >= 32)
|
||||
#define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC- 32))
|
||||
#define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC- 32))
|
||||
#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.out1_w1ts.val = (1 << (TFT_DC - 32)); \
|
||||
GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))
|
||||
#define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \
|
||||
GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))
|
||||
#else
|
||||
#define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))
|
||||
#define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_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 = (1 << TFT_DC); \
|
||||
GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1tc = (1 << TFT_DC); \
|
||||
GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#else
|
||||
// Other RPi displays need a slower C->D change
|
||||
#define DC_C GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1tc = (1 << TFT_DC); \
|
||||
GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#endif
|
||||
#else
|
||||
#define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (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.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))
|
||||
#elif TFT_CS >= 0
|
||||
#define CS_L GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1ts = (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.out1_w1ts.val = (1 << (TFT_CS - 32)); \
|
||||
GPIO.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \
|
||||
GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))
|
||||
#else
|
||||
#define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_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 = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS)
|
||||
#else
|
||||
#define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (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.out1_w1tc.val = (1 << (TFT_WR - 32))
|
||||
#define WR_H GPIO.out1_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 = (1 << TFT_WR)
|
||||
#define WR_H GPIO.out_w1ts = (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 = 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 GPIO_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 GPIO_OUT_CLR_MASK (GPIO_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 GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR))
|
||||
#else
|
||||
#define GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
#define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||
#else
|
||||
// Write 16 bits to TFT
|
||||
#define tft_Write_16(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
|
||||
// 16 bit write with swapped bytes
|
||||
#define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Write 32 bits to TFT
|
||||
#define tft_Write_32(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 16)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
|
||||
// Read pin
|
||||
#ifdef TFT_RD
|
||||
#if (TFT_RD >= 32)
|
||||
#define RD_L GPIO.out1_w1tc.val = (1 << (TFT_RD - 32))
|
||||
#define RD_H GPIO.out1_w1ts.val = (1 << (TFT_RD - 32))
|
||||
#elif (TFT_RD >= 0)
|
||||
#define RD_L GPIO.out_w1tc = (1 << TFT_RD)
|
||||
//#define RD_L digitalWrite(TFT_WR, LOW)
|
||||
#define RD_H GPIO.out_w1ts = (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
|
||||
#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
|
||||
*_spi_w = D; \
|
||||
*_spi_cmd = SPI_USR; \
|
||||
while (*_spi_cmd & 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)
|
||||
|
||||
// Future option for transfer without wait
|
||||
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
|
||||
*_spi_w = ((C)<<8 | (C)>>8); \
|
||||
*_spi_cmd = SPI_USR;
|
||||
|
||||
// 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
|
860
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.c
Normal file
860
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.c
Normal file
|
@ -0,0 +1,860 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP32 processors //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// Temporarily a separate file to TFT_eSPI_ESP32.c until board package low level API stabilises
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
597
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h
Normal file
597
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h
Normal file
|
@ -0,0 +1,597 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP32 processors //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// Temporarily a separate file to TFT_eSPI_ESP32.h until board package low level API stabilises
|
||||
|
||||
#ifndef _TFT_eSPI_ESP32H_
|
||||
#define _TFT_eSPI_ESP32H_
|
||||
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#warning >>>>------>> DMA is not supported on the ESP32 C3 (possible future update)
|
||||
#endif
|
||||
|
||||
// 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
|
||||
#define REG_SPI_BASE(i) DR_REG_SPI2_BASE
|
||||
#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 so have made VSPI = HSPI
|
||||
|
||||
ESP32 C3: Only 1 SPI port available
|
||||
FSPI = 1, uses SPI2
|
||||
HSPI = 1, uses SPI2
|
||||
VSPI not defined so have made VSPI = HSPI
|
||||
|
||||
For ESP32/S2/C3:
|
||||
SPI1_HOST = 0
|
||||
SPI2_HOST = 1
|
||||
SPI3_HOST = 2
|
||||
*/
|
||||
|
||||
// ESP32 specific SPI port selection - only SPI2_HOST available on C3
|
||||
#define SPI_PORT SPI2_HOST
|
||||
|
||||
#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)
|
||||
#elif (TFT_DC >= 32)
|
||||
#define DC_C GPIO.out_w1tc.val = (1 << (TFT_DC- 32))
|
||||
#define DC_D GPIO.out_w1ts.val = (1 << (TFT_DC- 32))
|
||||
#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 GPIO_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 GPIO_OUT_CLR_MASK (GPIO_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 GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR))
|
||||
#else
|
||||
#define GPIO_OUT_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 = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
#define tft_Write_16S(C) GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 24)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 16)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc.val = GPIO_OUT_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
|
851
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.c
Normal file
851
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.c
Normal file
|
@ -0,0 +1,851 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP32 processors //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// Temporarily a separate file to TFT_eSPI_ESP32.c until board package low level API stabilises
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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_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);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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_ESP32S3
|
||||
*_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_ESP32S3
|
||||
*_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_ESP32S3
|
||||
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_ESP32S3
|
||||
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_ESP32S3
|
||||
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_ESP32S3
|
||||
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_ESP32S3
|
||||
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_ESP32S3
|
||||
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_ESP32S3
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
620
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.h
Normal file
620
lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.h
Normal file
|
@ -0,0 +1,620 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP32 processors //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// Temporarily a separate file to TFT_eSPI_ESP32.h until board package low level API stabilises
|
||||
|
||||
#ifndef _TFT_eSPI_ESP32H_
|
||||
#define _TFT_eSPI_ESP32H_
|
||||
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#warning >>>>------>> DMA is not supported on the ESP32 S3 (possible future update)
|
||||
#endif
|
||||
|
||||
// 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_ESP32S3) && !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 ESP32S3
|
||||
// Note illogical enumerations: FSPI_HOST=SPI2_HOST=1 HSPI_HOST=SPI3_HOST=2
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
// Fix ESP32C3 IDF bug for missing definition (FSPI only tested at the moment)
|
||||
#ifndef REG_SPI_BASE // HSPI FSPI/VSPI
|
||||
#define REG_SPI_BASE(i) (((i)>1) ? (DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE))
|
||||
#endif
|
||||
|
||||
// Fix ESP32S3 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/S3:
|
||||
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_ESP32S3
|
||||
#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)
|
||||
#define _spi_cmd (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT))
|
||||
#define _spi_user (volatile uint32_t*)(SPI_USER_REG(SPI_PORT))
|
||||
#define _spi_mosi_dlen (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT))
|
||||
#define _spi_w (volatile uint32_t*)(SPI_W0_REG(SPI_PORT))
|
||||
|
||||
#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 = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#elif (TFT_DC >= 32)
|
||||
#define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC- 32))
|
||||
#define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC- 32))
|
||||
#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.out1_w1ts.val = (1 << (TFT_DC - 32)); \
|
||||
GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))
|
||||
#define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \
|
||||
GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))
|
||||
#else
|
||||
#define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))
|
||||
#define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_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 = (1 << TFT_DC); \
|
||||
GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1tc = (1 << TFT_DC); \
|
||||
GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#else
|
||||
// Other RPi displays need a slower C->D change
|
||||
#define DC_C GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1tc = (1 << TFT_DC); \
|
||||
GPIO.out_w1ts = (1 << TFT_DC)
|
||||
#endif
|
||||
#else
|
||||
#define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC)
|
||||
#define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (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.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))
|
||||
#elif TFT_CS >= 0
|
||||
#define CS_L GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1ts = (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.out1_w1ts.val = (1 << (TFT_CS - 32)); \
|
||||
GPIO.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \
|
||||
GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))
|
||||
#else
|
||||
#define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32))
|
||||
#define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_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 = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS)
|
||||
#else
|
||||
#define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS)
|
||||
#define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (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.out1_w1tc.val = (1 << (TFT_WR - 32))
|
||||
#define WR_H GPIO.out1_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 = (1 << TFT_WR)
|
||||
#define WR_H GPIO.out_w1ts = (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_ESP32S3) || 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 = 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 GPIO_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 GPIO_OUT_CLR_MASK (GPIO_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 GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR))
|
||||
#else
|
||||
#define GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
#define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||
#else
|
||||
// Write 16 bits to TFT
|
||||
#define tft_Write_16(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
|
||||
// 16 bit write with swapped bytes
|
||||
#define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Write 32 bits to TFT
|
||||
#define tft_Write_32(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 16)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
|
||||
GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
|
||||
|
||||
// Read pin
|
||||
#ifdef TFT_RD
|
||||
#if (TFT_RD >= 32)
|
||||
#define RD_L GPIO.out1_w1tc.val = (1 << (TFT_RD - 32))
|
||||
#define RD_H GPIO.out1_w1ts.val = (1 << (TFT_RD - 32))
|
||||
#elif (TFT_RD >= 0)
|
||||
#define RD_L GPIO.out_w1tc = (1 << TFT_RD)
|
||||
//#define RD_L digitalWrite(TFT_WR, LOW)
|
||||
#define RD_H GPIO.out_w1ts = (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_ESP32S3)
|
||||
#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_ESP32S3)
|
||||
#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
|
447
lib/TFT_eSPI/Processors/TFT_eSPI_ESP8266.c
Normal file
447
lib/TFT_eSPI/Processors/TFT_eSPI_ESP8266.c
Normal file
|
@ -0,0 +1,447 @@
|
|||
|
||||
//////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP8266 processors //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// Select the SPI port to use
|
||||
// ESP8266 default (FLASH port also available via overlap mode)
|
||||
SPIClass& spi = SPI;
|
||||
|
||||
// Buffer for SPI transmit byte padding and byte order manipulation
|
||||
uint8_t spiBuffer[8] = {0,0,0,0,0,0,0,0};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: tft_Read_8
|
||||
** Description: ESP8266 software SPI to read bidirectional SDA line
|
||||
***************************************************************************************/
|
||||
uint8_t TFT_eSPI::tft_Read_8(void)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
uint32_t reg = 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)
|
||||
{
|
||||
#ifdef TFT_SPI_OVERLAP
|
||||
// Reads in overlap mode not supported
|
||||
#else
|
||||
spi.end();
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: endSDA
|
||||
** Description: Attach SPI pins after software SPI
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::end_SDA_Read(void)
|
||||
{
|
||||
#ifdef TFT_SPI_OVERLAP
|
||||
spi.pins(6, 7, 8, 0);
|
||||
#else
|
||||
spi.begin();
|
||||
#endif
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // #if defined (TFT_SDA_READ)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: read byte - supports class functions
|
||||
** Description: Parallel bus only - dummy function - not used
|
||||
***************************************************************************************/
|
||||
uint8_t TFT_eSPI::readByte(void)
|
||||
{
|
||||
uint8_t b = 0xAA;
|
||||
return b;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (RPI_WRITE_STROBE)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; }
|
||||
if (len) spi.writePattern(data, len, 1);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushSwapBytePixels - for ESP32 or ESP8266 RPi TFT
|
||||
** 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++;}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for ESP8266 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;
|
||||
// Concatenate 4 pixels into three 32 bit blocks
|
||||
uint32_t r0 = r<<24 | b<<16 | g<<8 | r;
|
||||
uint32_t r1 = g<<24 | r<<16 | b<<8 | g;
|
||||
uint32_t r2 = b<<24 | g<<16 | r<<8 | b;
|
||||
|
||||
SPI1W0 = r0;
|
||||
SPI1W1 = r1;
|
||||
SPI1W2 = r2;
|
||||
|
||||
if (len > 4)
|
||||
{
|
||||
SPI1W3 = r0;
|
||||
SPI1W4 = r1;
|
||||
SPI1W5 = r2;
|
||||
}
|
||||
if (len > 8)
|
||||
{
|
||||
SPI1W6 = r0;
|
||||
SPI1W7 = r1;
|
||||
SPI1W8 = r2;
|
||||
}
|
||||
if (len > 12)
|
||||
{
|
||||
SPI1W9 = r0;
|
||||
SPI1W10 = r1;
|
||||
SPI1W11 = r2;
|
||||
SPI1W12 = r0;
|
||||
SPI1W13 = r1;
|
||||
SPI1W14 = r2;
|
||||
SPI1W15 = r0;
|
||||
}
|
||||
|
||||
if (len > 20)
|
||||
{
|
||||
SPI1U1 = (503 << SPILMOSI);
|
||||
while(len>20)
|
||||
{
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1CMD |= SPIBUSY;
|
||||
len -= 21;
|
||||
}
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
len = (len * 24) - 1;
|
||||
SPI1U1 = (len << SPILMOSI);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for ESP8266 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;
|
||||
|
||||
// Send groups of 4 concatenated pixels
|
||||
if (len > 3) {
|
||||
SPI1U1 = ((4 * 24 - 1) << SPILMOSI);
|
||||
while (len > 3) {
|
||||
|
||||
uint8_t r[4];
|
||||
uint8_t g[4];
|
||||
uint8_t b[4];
|
||||
|
||||
if (!_swapBytes) {
|
||||
// Split out the colours
|
||||
for (uint16_t i = 0; i < 4; i++) {
|
||||
uint16_t col = *data++;
|
||||
r[i] = (col & 0xF8);
|
||||
g[i] = (col & 0xE000)>>11 | (col & 0x07)<<5;
|
||||
b[i] = (col & 0x1F00)>>5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (uint16_t i = 0; i < 4; i++) {
|
||||
uint16_t col = *data++;
|
||||
r[i] = (col & 0xF800)>>8;
|
||||
g[i] = (col & 0x07E0)>>3;
|
||||
b[i] = (col & 0x001F)<<3;
|
||||
}
|
||||
}
|
||||
uint32_t r0 = r[1]<<24 | b[0]<<16 | g[0]<<8 | r[0];
|
||||
uint32_t r1 = g[2]<<24 | r[2]<<16 | b[1]<<8 | g[1];
|
||||
uint32_t r2 = b[3]<<24 | g[3]<<16 | r[3]<<8 | b[2];
|
||||
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = r0;
|
||||
SPI1W1 = r1;
|
||||
SPI1W2 = r2;
|
||||
|
||||
SPI1CMD |= SPIBUSY;
|
||||
len -= 4;
|
||||
}
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
|
||||
// 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 ESP8266 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++;}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#else
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for ESP8266
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
//Clear screen test 76.8ms theoretical. 81.5ms TFT_eSPI, 967ms Adafruit_ILI9341
|
||||
//Performance 26.15Mbps@26.66MHz, 39.04Mbps@40MHz, 75.4Mbps@80MHz SPI clock
|
||||
//Efficiency:
|
||||
// TFT_eSPI 98.06% 97.59% 94.24%
|
||||
// Adafruit_GFX 19.62% 14.31% 7.94%
|
||||
//
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||
{
|
||||
/*
|
||||
while (len>1) { tft_Write_32(color<<16 | color); len-=2;}
|
||||
if (len) tft_Write_16(color);
|
||||
return;
|
||||
//*/
|
||||
uint16_t color16 = (color >> 8) | (color << 8);
|
||||
uint32_t color32 = color16 | color16 << 16;
|
||||
/*
|
||||
while(len--) {
|
||||
SPI1U1 = ((16-1) << SPILMOSI) | ((16-1) << SPILMISO);
|
||||
SPI1W0 = color16;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
return;
|
||||
//*/
|
||||
|
||||
SPI1W0 = color32;
|
||||
SPI1W1 = color32;
|
||||
SPI1W2 = color32;
|
||||
SPI1W3 = color32;
|
||||
if (len > 8)
|
||||
{
|
||||
SPI1W4 = color32;
|
||||
SPI1W5 = color32;
|
||||
SPI1W6 = color32;
|
||||
SPI1W7 = color32;
|
||||
}
|
||||
if (len > 16)
|
||||
{
|
||||
SPI1W8 = color32;
|
||||
SPI1W9 = color32;
|
||||
SPI1W10 = color32;
|
||||
SPI1W11 = color32;
|
||||
}
|
||||
if (len > 24)
|
||||
{
|
||||
SPI1W12 = color32;
|
||||
SPI1W13 = color32;
|
||||
SPI1W14 = color32;
|
||||
SPI1W15 = color32;
|
||||
}
|
||||
if (len > 31)
|
||||
{
|
||||
SPI1U1 = (511 << SPILMOSI);
|
||||
while(len>31)
|
||||
{
|
||||
#if (defined (SPI_FREQUENCY) && (SPI_FREQUENCY == 80000000))
|
||||
if(SPI1CMD & SPIBUSY) // added to sync with flag change
|
||||
#endif
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1CMD |= SPIBUSY;
|
||||
len -= 32;
|
||||
}
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
len = (len << 4) - 1;
|
||||
SPI1U1 = (len << SPILMOSI);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for ESP8266
|
||||
** Description: Write a sequence of pixels
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
|
||||
|
||||
if(_swapBytes) {
|
||||
pushSwapBytePixels(data_in, len);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *data = (uint16_t*) data_in;
|
||||
|
||||
uint32_t color[8];
|
||||
|
||||
SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO);
|
||||
|
||||
|
||||
while(len>15)
|
||||
{
|
||||
memcpy(color,data,32);
|
||||
data+=16;
|
||||
|
||||
len -= 16;
|
||||
|
||||
// ESP8266 wait time here at 40MHz SPI is ~5.45us
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = color[0];
|
||||
SPI1W1 = color[1];
|
||||
SPI1W2 = color[2];
|
||||
SPI1W3 = color[3];
|
||||
SPI1W4 = color[4];
|
||||
SPI1W5 = color[5];
|
||||
SPI1W6 = color[6];
|
||||
SPI1W7 = color[7];
|
||||
SPI1CMD |= SPIBUSY;
|
||||
}
|
||||
|
||||
if(len)
|
||||
{
|
||||
uint32_t bits = (len*16-1); // bits left to shift - 1
|
||||
|
||||
memcpy(color,data,len<<1);
|
||||
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1U1 = (bits << SPILMOSI) | (bits << SPILMISO);
|
||||
SPI1W0 = color[0];
|
||||
SPI1W1 = color[1];
|
||||
SPI1W2 = color[2];
|
||||
SPI1W3 = color[3];
|
||||
SPI1W4 = color[4];
|
||||
SPI1W5 = color[5];
|
||||
SPI1W6 = color[6];
|
||||
SPI1W7 = color[7];
|
||||
SPI1CMD |= SPIBUSY;
|
||||
}
|
||||
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushSwapBytePixels - for ESP8266
|
||||
** 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;
|
||||
//uint16_t* data = (uint16_t*)data_in;
|
||||
|
||||
uint32_t color[8];
|
||||
|
||||
SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO);
|
||||
|
||||
while(len>15)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
while(i<8) { color[i++] = DAT8TO32(data); data+=4; }
|
||||
|
||||
len -= 16;
|
||||
|
||||
// ESP8266 wait time here at 40MHz SPI is ~5.45us
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = color[0];
|
||||
SPI1W1 = color[1];
|
||||
SPI1W2 = color[2];
|
||||
SPI1W3 = color[3];
|
||||
SPI1W4 = color[4];
|
||||
SPI1W5 = color[5];
|
||||
SPI1W6 = color[6];
|
||||
SPI1W7 = color[7];
|
||||
SPI1CMD |= SPIBUSY;
|
||||
}
|
||||
|
||||
if(len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t bits = (len*16-1); // bits left to shift - 1
|
||||
len = (len+1)>>1;
|
||||
while(len--) { color[i++] = DAT8TO32(data); data+=4; }
|
||||
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
SPI1U1 = (bits << SPILMOSI) | (bits << SPILMISO);
|
||||
SPI1W0 = color[0];
|
||||
SPI1W1 = color[1];
|
||||
SPI1W2 = color[2];
|
||||
SPI1W3 = color[3];
|
||||
SPI1W4 = color[4];
|
||||
SPI1W5 = color[5];
|
||||
SPI1W6 = color[6];
|
||||
SPI1W7 = color[7];
|
||||
SPI1CMD |= SPIBUSY;
|
||||
}
|
||||
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
245
lib/TFT_eSPI/Processors/TFT_eSPI_ESP8266.h
Normal file
245
lib/TFT_eSPI/Processors/TFT_eSPI_ESP8266.h
Normal file
|
@ -0,0 +1,245 @@
|
|||
//////////////////////////////////////////////////////
|
||||
// TFT_eSPI driver functions for ESP8266 processors //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _TFT_eSPI_ESP8266H_
|
||||
#define _TFT_eSPI_ESP8266H_
|
||||
|
||||
// Processor ID reported by getSetup()
|
||||
#define PROCESSOR_ID 0x8266
|
||||
|
||||
// Include processor specific header
|
||||
// None
|
||||
|
||||
// Processor specific code used by SPI bus transaction startWrite and endWrite functions
|
||||
#define SET_BUS_WRITE_MODE SPI1U=SPI1U_WRITE
|
||||
#define SET_BUS_READ_MODE SPI1U=SPI1U_READ
|
||||
|
||||
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions
|
||||
#define DMA_BUSY_CHECK // DMA not available, leave blank
|
||||
|
||||
// Initialise processor specific SPI functions, used by init()
|
||||
#if (!defined (SUPPORT_TRANSACTIONS) && defined (ESP8266))
|
||||
#define INIT_TFT_DATA_BUS \
|
||||
spi.setBitOrder(MSBFIRST); \
|
||||
spi.setDataMode(TFT_SPI_MODE); \
|
||||
spi.setFrequency(SPI_FREQUENCY);
|
||||
#else
|
||||
#define INIT_TFT_DATA_BUS
|
||||
#endif
|
||||
|
||||
// If smooth fonts are enabled the filing system may need to be loaded
|
||||
#ifdef SMOOTH_FONT
|
||||
// Call up the SPIFFS FLASH filing system for the anti-aliased fonts
|
||||
#define FS_NO_GLOBALS
|
||||
#include <FS.h>
|
||||
#define FONT_FS_AVAILABLE
|
||||
#endif
|
||||
|
||||
// Do not allow parallel mode for ESP8266
|
||||
#ifdef ESP32_PARALLEL
|
||||
#undef ESP32_PARALLEL
|
||||
#endif
|
||||
#ifdef TFT_PARALLEL_8_BIT
|
||||
#undef TFT_PARALLEL_8_BIT
|
||||
#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 (TFT_DC == 16)
|
||||
#define DC_C digitalWrite(TFT_DC, LOW)
|
||||
#define DC_D digitalWrite(TFT_DC, HIGH)
|
||||
#else
|
||||
#define DC_C GPOC=dcpinmask
|
||||
#define DC_D GPOS=dcpinmask
|
||||
#endif
|
||||
#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
|
||||
#if (TFT_CS == 16)
|
||||
#define CS_L digitalWrite(TFT_CS, LOW)
|
||||
#define CS_H digitalWrite(TFT_CS, HIGH)
|
||||
#else
|
||||
#define CS_L GPOC=cspinmask
|
||||
#define CS_H GPOS=cspinmask
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define the WR (TFT Write) pin drive code
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef TFT_WR
|
||||
#define WR_L GPOC=wrpinmask
|
||||
#define WR_H GPOS=wrpinmask
|
||||
#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
|
||||
#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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ESP8266 specific SPI macros
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_SPI_OVERLAP)
|
||||
#undef TFT_CS
|
||||
#define SPI1U_WRITE (SPIUMOSI | SPIUSSE | SPIUCSSETUP | SPIUCSHOLD)
|
||||
#define SPI1U_READ (SPIUMOSI | SPIUSSE | SPIUCSSETUP | SPIUCSHOLD | SPIUDUPLEX)
|
||||
#else
|
||||
#define SPI1U_WRITE (SPIUMOSI | SPIUSSE)
|
||||
#define SPI1U_READ (SPIUMOSI | SPIUSSE | SPIUDUPLEX)
|
||||
#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 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 address coordinates
|
||||
#define tft_Write_32C(C,D) spi.write32((C)<<16 | (D))
|
||||
|
||||
// Write same value twice
|
||||
#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)
|
||||
// Command is 16 bits
|
||||
#define CMD_BITS 16
|
||||
|
||||
// ESP8266 low level SPI writes for 8, 16 and 32 bit values
|
||||
// to avoid the function call overhead
|
||||
#define TFT_WRITE_BITS(D, B) \
|
||||
SPI1U1 = ((B-1) << SPILMOSI); \
|
||||
SPI1W0 = D; \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {}
|
||||
|
||||
#define tft_Write_8(C) TFT_WRITE_BITS((uint16_t)(C)<<8, CMD_BITS)
|
||||
|
||||
#define tft_Write_16(C) TFT_WRITE_BITS((C)>>8 | (C)<<8, 16)
|
||||
|
||||
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
|
||||
|
||||
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
|
||||
|
||||
#define tft_Write_32C(C,D) SPI1U1 = ((64-1) << SPILMOSI); \
|
||||
SPI1W0 = ((C)<<24) | (C); \
|
||||
SPI1W1 = ((D)<<24) | (D); \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_32D(C) tft_Write_32C(C,C)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Macros for all other SPI displays
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#else
|
||||
// Command is 8 bits
|
||||
#define CMD_BITS 8
|
||||
|
||||
#define tft_Write_8(C) \
|
||||
SPI1U1 = ((CMD_BITS-1) << SPILMOSI) | ((CMD_BITS-1) << SPILMISO); \
|
||||
SPI1W0 = (C)<<(CMD_BITS - 8); \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_16(C) \
|
||||
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
||||
SPI1W0 = ((C)<<8 | (C)>>8); \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_16N(C) \
|
||||
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
||||
SPI1W0 = ((C)<<8 | (C)>>8); \
|
||||
SPI1CMD |= SPIBUSY
|
||||
|
||||
#define tft_Write_16S(C) \
|
||||
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
||||
SPI1W0 = C; \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_32(C) \
|
||||
SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); \
|
||||
SPI1W0 = C; \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_32C(C,D) \
|
||||
SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); \
|
||||
SPI1W0 = ((D)>>8 | (D)<<8)<<16 | ((C)>>8 | (C)<<8); \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#define tft_Write_32D(C) \
|
||||
SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); \
|
||||
SPI1W0 = ((C)>>8 | (C)<<8)<<16 | ((C)>>8 | (C)<<8); \
|
||||
SPI1CMD |= SPIBUSY; \
|
||||
while(SPI1CMD & SPIBUSY) {;}
|
||||
|
||||
#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_SDA_READ)
|
||||
// Use a bit banged function call for ESP8266 and bi-directional SDA pin
|
||||
#define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(void);
|
||||
#define SCLK_L GPOC=sclkpinmask
|
||||
#define SCLK_H GPOS=sclkpinmask
|
||||
#else
|
||||
// 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
|
263
lib/TFT_eSPI/Processors/TFT_eSPI_Generic.c
Normal file
263
lib/TFT_eSPI/Processors/TFT_eSPI_Generic.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI generic driver functions //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Global variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Select the SPI port to use
|
||||
#ifdef TFT_SPI_PORT
|
||||
SPIClass& spi = TFT_SPI_PORT;
|
||||
#else
|
||||
SPIClass& spi = SPI;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#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 STM32 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 STM32 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 STM32 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 STM32 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 STM32
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||
|
||||
while ( len-- ) {tft_Write_16(color);}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for STM32
|
||||
** 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
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
|
||||
*/
|
188
lib/TFT_eSPI/Processors/TFT_eSPI_Generic.h
Normal file
188
lib/TFT_eSPI/Processors/TFT_eSPI_Generic.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
////////////////////////////////////////////////////
|
||||
// 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_GENERICH_
|
||||
#define _TFT_eSPI_GENERICH_
|
||||
|
||||
// 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 DMA is busy, used by SPI bus transaction startWrite and endWrite functions
|
||||
#define DMA_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 <FS.h>
|
||||
#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 digitalWrite(TFT_DC, LOW)
|
||||
#define DC_D digitalWrite(TFT_DC, HIGH)
|
||||
#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 digitalWrite(TFT_CS, LOW)
|
||||
#define CS_H digitalWrite(TFT_CS, HIGH)
|
||||
#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 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_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
|
||||
#ifdef __AVR__ // AVR processors do not have 16 bit transfer
|
||||
#define tft_Write_8(C) {SPDR=(C); while (!(SPSR&_BV(SPIF)));}
|
||||
#define tft_Write_16(C) tft_Write_8((uint8_t)((C)>>8));tft_Write_8((uint8_t)((C)>>0))
|
||||
#define tft_Write_16S(C) tft_Write_8((uint8_t)((C)>>0));tft_Write_8((uint8_t)((C)>>8))
|
||||
#else
|
||||
#define tft_Write_8(C) spi.transfer(C)
|
||||
#define tft_Write_16(C) spi.transfer16(C)
|
||||
#define tft_Write_16S(C) spi.transfer16(((C)>>8) | ((C)<<8))
|
||||
#endif // AVR
|
||||
|
||||
#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) \
|
||||
tft_Write_16((uint16_t) (C)); \
|
||||
tft_Write_16((uint16_t) (D))
|
||||
|
||||
#define tft_Write_32D(C) \
|
||||
tft_Write_16((uint16_t) (C)); \
|
||||
tft_Write_16((uint16_t) (C))
|
||||
#endif // RPI_DISPLAY_TYPE
|
||||
#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_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
|
733
lib/TFT_eSPI/Processors/TFT_eSPI_RP2040.c
Normal file
733
lib/TFT_eSPI/Processors/TFT_eSPI_RP2040.c
Normal file
|
@ -0,0 +1,733 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI generic driver functions //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Global variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
|
||||
// Select the SPI port and board package to use
|
||||
#ifdef ARDUINO_ARCH_MBED
|
||||
// Arduino RP2040 board package
|
||||
MbedSPI spi = MbedSPI(TFT_MISO, TFT_MOSI, TFT_SCLK);
|
||||
#else
|
||||
// Community RP2040 board package by Earle Philhower
|
||||
//SPIClass& spi = SPI; // will use board package default pins
|
||||
SPIClassRP2040 spi = SPIClassRP2040(SPI_X, TFT_MISO, -1, TFT_SCLK, TFT_MOSI);
|
||||
#endif
|
||||
|
||||
#else // PIO interface used (8 bit parallel or SPI)
|
||||
|
||||
#ifdef RP2040_PIO_SPI
|
||||
#if defined (SPI_18BIT_DRIVER)
|
||||
// SPI PIO code for 18 bit colour transmit
|
||||
#include "pio_SPI_18bit.pio.h"
|
||||
#else
|
||||
// SPI PIO code for 16 bit colour transmit
|
||||
#include "pio_SPI.pio.h"
|
||||
#endif
|
||||
#elif defined (TFT_PARALLEL_8_BIT)
|
||||
// SPI PIO code for 8 bit parallel interface (16 bit colour)
|
||||
#include "pio_8bit_parallel.pio.h"
|
||||
#else // must be TFT_PARALLEL_16_BIT
|
||||
// SPI PIO code for 16 bit parallel interface (16 bit colour)
|
||||
#include "pio_16bit_parallel.pio.h"
|
||||
#endif
|
||||
|
||||
// Board package specific differences
|
||||
#ifdef ARDUINO_ARCH_MBED
|
||||
// Not supported at the moment
|
||||
#error The Arduino RP2040 MBED board package is not supported when PIO is used. Use the community package by Earle Philhower.
|
||||
#endif
|
||||
|
||||
// Community RP2040 board package by Earle Philhower
|
||||
PIO tft_pio = pio0; // Code will try both pio's to find a free SM
|
||||
int8_t pio_sm = 0; // pioinit will claim a free one
|
||||
// Updated later with the loading offset of the PIO program.
|
||||
uint32_t program_offset = 0;
|
||||
|
||||
// SM stalled mask
|
||||
uint32_t pull_stall_mask = 0;
|
||||
|
||||
// SM jump instructions to change SM behaviour
|
||||
uint32_t pio_instr_jmp8 = 0;
|
||||
uint32_t pio_instr_fill = 0;
|
||||
uint32_t pio_instr_addr = 0;
|
||||
|
||||
// SM "set" instructions to control DC control signal
|
||||
uint32_t pio_instr_set_dc = 0;
|
||||
uint32_t pio_instr_clr_dc = 0;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RP2040_DMA
|
||||
int32_t dma_tx_channel;
|
||||
dma_channel_config dma_tx_config;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_SDA_READ) && !defined (RP2040_PIO_INTERFACE)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
}
|
||||
*/
|
||||
|
||||
ret = spi.transfer(0x00);
|
||||
|
||||
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 (RP2040_PIO_INTERFACE)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef RP2040_PIO_SPI
|
||||
void pioinit(uint32_t clock_freq) {
|
||||
|
||||
// Find a free SM on one of the PIO's
|
||||
tft_pio = pio0;
|
||||
|
||||
/*
|
||||
pio_sm = pio_claim_unused_sm(tft_pio, false); // false means don't panic
|
||||
// Try pio1 if SM not found
|
||||
if (pio_sm < 0) {
|
||||
tft_pio = pio1;
|
||||
pio_sm = pio_claim_unused_sm(tft_pio, true); // panic this time if no SM is free
|
||||
}
|
||||
*/
|
||||
|
||||
// Find enough free space on one of the PIO's
|
||||
tft_pio = pio0;
|
||||
if (!pio_can_add_program(tft_pio, &tft_io_program)) {
|
||||
tft_pio = pio1;
|
||||
if (!pio_can_add_program(tft_pio, &tft_io_program)) {
|
||||
Serial.println("No room for PIO program!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pio_sm = pio_claim_unused_sm(tft_pio, false);
|
||||
|
||||
// Load the PIO program
|
||||
program_offset = pio_add_program(tft_pio, &tft_io_program);
|
||||
|
||||
// Associate pins with the PIO
|
||||
pio_gpio_init(tft_pio, TFT_DC);
|
||||
pio_gpio_init(tft_pio, TFT_SCLK);
|
||||
pio_gpio_init(tft_pio, TFT_MOSI);
|
||||
|
||||
// Configure the pins to be outputs
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_SCLK, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_MOSI, 1, true);
|
||||
|
||||
// Configure the state machine
|
||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||
|
||||
sm_config_set_set_pins(&c, TFT_DC, 1);
|
||||
// Define the single side-set pin
|
||||
sm_config_set_sideset_pins(&c, TFT_SCLK);
|
||||
// Define the pin used for data output
|
||||
sm_config_set_out_pins(&c, TFT_MOSI, 1);
|
||||
// Set clock divider, frequency is set up to 2% faster than specified, or next division down
|
||||
uint16_t clock_div = 0.98 + clock_get_hz(clk_sys) / (clock_freq * 2.0); // 2 cycles per bit
|
||||
sm_config_set_clkdiv(&c, clock_div);
|
||||
// Make a single 8 words FIFO from the 4 words TX and RX FIFOs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first, autopull off
|
||||
sm_config_set_out_shift(&c, false, false, 0);
|
||||
// Now load the configuration
|
||||
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_tx, &c);
|
||||
|
||||
// Start the state machine.
|
||||
pio_sm_set_enabled(tft_pio, pio_sm, true);
|
||||
|
||||
// Create the pull stall bit mask
|
||||
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
||||
|
||||
// Create the assembler instruction for the jump to byte send routine
|
||||
pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8);
|
||||
pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill);
|
||||
pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window);
|
||||
|
||||
pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1);
|
||||
pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0);
|
||||
}
|
||||
#else // 8 or 16 bit parallel
|
||||
void pioinit(uint16_t clock_div, uint16_t fract_div) {
|
||||
|
||||
// Find a free SM on one of the PIO's
|
||||
tft_pio = pio0;
|
||||
pio_sm = pio_claim_unused_sm(tft_pio, false); // false means don't panic
|
||||
// Try pio1 if SM not found
|
||||
if (pio_sm < 0) {
|
||||
tft_pio = pio1;
|
||||
pio_sm = pio_claim_unused_sm(tft_pio, true); // panic this time if no SM is free
|
||||
}
|
||||
/*
|
||||
// Find enough free space on one of the PIO's
|
||||
tft_pio = pio0;
|
||||
if (!pio_can_add_program(tft_pio, &tft_io_program) {
|
||||
tft_pio = pio1;
|
||||
if (!pio_can_add_program(tft_pio, &tft_io_program) {
|
||||
Serial.println("No room for PIO program!");
|
||||
while(1) delay(100);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
uint8_t bits = 8;
|
||||
#else // must be TFT_PARALLEL_16_BIT
|
||||
uint8_t bits = 16;
|
||||
#endif
|
||||
|
||||
// Load the PIO program
|
||||
program_offset = pio_add_program(tft_pio, &tft_io_program);
|
||||
|
||||
// Associate pins with the PIO
|
||||
pio_gpio_init(tft_pio, TFT_DC);
|
||||
pio_gpio_init(tft_pio, TFT_WR);
|
||||
|
||||
for (int i = 0; i < bits; i++) {
|
||||
pio_gpio_init(tft_pio, TFT_D0 + i);
|
||||
}
|
||||
|
||||
// Configure the pins to be outputs
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_WR, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_D0, bits, true);
|
||||
|
||||
// Configure the state machine
|
||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||
// Define the set pin
|
||||
sm_config_set_set_pins(&c, TFT_DC, 1);
|
||||
// Define the single side-set pin
|
||||
sm_config_set_sideset_pins(&c, TFT_WR);
|
||||
// Define the consecutive pins that are used for data output
|
||||
sm_config_set_out_pins(&c, TFT_D0, bits);
|
||||
// Set clock divider and fractional divider
|
||||
sm_config_set_clkdiv_int_frac(&c, clock_div, fract_div);
|
||||
// Make a single 8 words FIFO from the 4 words TX and RX FIFOs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first
|
||||
sm_config_set_out_shift(&c, false, false, 0);
|
||||
// Now load the configuration
|
||||
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_tx, &c);
|
||||
|
||||
// Start the state machine.
|
||||
pio_sm_set_enabled(tft_pio, pio_sm, true);
|
||||
|
||||
// Create the pull stall bit mask
|
||||
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
||||
|
||||
// Create the instructions for the jumps to send routines
|
||||
pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8);
|
||||
pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill);
|
||||
pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window);
|
||||
|
||||
// Create the instructions to set and clear the DC signal
|
||||
pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1);
|
||||
pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for generic processor and parallel display
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
#ifdef RP2040_PIO_PUSHBLOCK
|
||||
// PIO handles pixel block fill writes
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||
{
|
||||
#if defined (SPI_18BIT_DRIVER)
|
||||
uint32_t col = ((color & 0xF800)<<8) | ((color & 0x07E0)<<5) | ((color & 0x001F)<<3);
|
||||
if (len) {
|
||||
WAIT_FOR_STALL;
|
||||
tft_pio->sm[pio_sm].instr = pio_instr_fill;
|
||||
|
||||
TX_FIFO = col;
|
||||
TX_FIFO = --len; // Decrement first as PIO sends n+1
|
||||
}
|
||||
#else
|
||||
if (len) {
|
||||
WAIT_FOR_STALL;
|
||||
tft_pio->sm[pio_sm].instr = pio_instr_fill;
|
||||
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = --len; // Decrement first as PIO sends n+1
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||
|
||||
while (len > 4) {
|
||||
// 5 seems to be the optimum for maximum transfer rate
|
||||
WAIT_FOR_FIFO_FREE(5);
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = color;
|
||||
|
||||
len -= 5;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
// There could be a maximum of 4 words left to send
|
||||
WAIT_FOR_FIFO_FREE(4);
|
||||
while (len--) TX_FIFO = color;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for generic processor and parallel display
|
||||
** Description: Write a sequence of pixels
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
|
||||
#if defined (SPI_18BIT_DRIVER)
|
||||
uint16_t *data = (uint16_t*)data_in;
|
||||
if (_swapBytes) {
|
||||
while ( len-- ) {
|
||||
uint32_t col = *data++;
|
||||
tft_Write_16(col);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ( len-- ) {
|
||||
uint32_t col = *data++;
|
||||
tft_Write_16S(col);
|
||||
}
|
||||
}
|
||||
#else
|
||||
const uint16_t *data = (uint16_t*)data_in;
|
||||
|
||||
// PIO sends MS byte first, so bytes are already swapped on transmit
|
||||
if(_swapBytes) {
|
||||
while (len > 4) {
|
||||
WAIT_FOR_FIFO_FREE(5);
|
||||
TX_FIFO = data[0];
|
||||
TX_FIFO = data[1];
|
||||
TX_FIFO = data[2];
|
||||
TX_FIFO = data[3];
|
||||
TX_FIFO = data[4];
|
||||
data += 5;
|
||||
len -= 5;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
WAIT_FOR_FIFO_FREE(4);
|
||||
while(len--) TX_FIFO = *data++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (len > 4) {
|
||||
WAIT_FOR_FIFO_FREE(5);
|
||||
TX_FIFO = data[0] << 8 | data[0] >> 8;
|
||||
TX_FIFO = data[1] << 8 | data[1] >> 8;
|
||||
TX_FIFO = data[2] << 8 | data[2] >> 8;
|
||||
TX_FIFO = data[3] << 8 | data[3] >> 8;
|
||||
TX_FIFO = data[4] << 8 | data[4] >> 8;
|
||||
data += 5;
|
||||
len -= 5;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
WAIT_FOR_FIFO_FREE(4);
|
||||
while(len--) {
|
||||
TX_FIFO = *data << 8 | *data >> 8;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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)
|
||||
{
|
||||
// Avoid warnings
|
||||
mask = mask;
|
||||
mode = 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);
|
||||
*/
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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)
|
||||
{
|
||||
// Avoid warnings
|
||||
gpio = gpio;
|
||||
mode = mode;
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: read byte - supports class functions
|
||||
** Description: Read a byte - parallel bus only - not supported yet
|
||||
***************************************************************************************/
|
||||
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)
|
||||
{
|
||||
uint16_t r = (color & 0xF800)>>8;
|
||||
uint16_t g = (color & 0x07E0)>>3;
|
||||
uint16_t b = (color & 0x001F)<<3;
|
||||
|
||||
// If more than 32 pixels then change to 16 bit transfers with concatenated pixels
|
||||
if (len > 32) {
|
||||
uint32_t rg = r<<8 | g;
|
||||
uint32_t br = b<<8 | r;
|
||||
uint32_t gb = g<<8 | b;
|
||||
// Must wait before changing to 16 bit
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
|
||||
while ( len > 1 ) {
|
||||
while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = rg;
|
||||
while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = br;
|
||||
while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = gb;
|
||||
len -= 2;
|
||||
}
|
||||
// Must wait before changing back to 8 bit
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
|
||||
}
|
||||
|
||||
// Mop up the remaining pixels
|
||||
while ( len-- ) {tft_Write_8N(r);tft_Write_8N(g);tft_Write_8N(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-- ) {
|
||||
uint32_t col = *data++;
|
||||
tft_Write_16(col);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ( len-- ) {
|
||||
uint32_t col = *data++;
|
||||
tft_Write_16S(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#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){
|
||||
while(len--)
|
||||
{
|
||||
while (!spi_is_writable(SPI_X)){};
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for RP2040
|
||||
** 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--)
|
||||
{
|
||||
while (!spi_is_writable(SPI_X)){};
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)(*data++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(len--)
|
||||
{
|
||||
uint16_t color = *data++;
|
||||
color = color >> 8 | color << 8;
|
||||
while (!spi_is_writable(SPI_X)){};
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // End of display interface specific functions
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef RP2040_DMA // DMA functions for 16 bit SPI and 8 bit parallel displays
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
These are created in header file:
|
||||
uint32_t dma_tx_channel;
|
||||
dma_channel_config dma_tx_config;
|
||||
*/
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: dmaBusy
|
||||
** Description: Check if DMA is busy
|
||||
***************************************************************************************/
|
||||
bool TFT_eSPI::dmaBusy(void) {
|
||||
if (!DMA_Enabled) return false;
|
||||
|
||||
if (dma_channel_is_busy(dma_tx_channel)) return true;
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
// For SPI must also wait for FIFO to flush and reset format
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: dmaWait
|
||||
** Description: Wait until DMA is over (blocking!)
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::dmaWait(void)
|
||||
{
|
||||
while (dma_channel_is_busy(dma_tx_channel));
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
// For SPI must also wait for FIFO to flush and reset format
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixelsDMA
|
||||
** Description: Push pixels to TFT
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
|
||||
{
|
||||
if ((len == 0) || (!DMA_Enabled)) return;
|
||||
|
||||
dmaWait();
|
||||
|
||||
channel_config_set_bswap(&dma_tx_config, !_swapBytes);
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)image, len, true);
|
||||
#else
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)image, len, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushImageDMA
|
||||
** Description: Push image to a window
|
||||
***************************************************************************************/
|
||||
// This will clip to the viewport
|
||||
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) ) {
|
||||
for (int32_t yb = 0; yb < dh; yb++) {
|
||||
memmove((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) {
|
||||
memcpy(buffer, image, len*2);
|
||||
}
|
||||
|
||||
dmaWait(); // In case we did not wait earlier
|
||||
|
||||
setAddrWindow(x, y, dw, dh);
|
||||
|
||||
channel_config_set_bswap(&dma_tx_config, !_swapBytes);
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)buffer, len, true);
|
||||
#else
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)buffer, len, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
|
||||
ctrl_cs = ctrl_cs; // stop unused parameter warning
|
||||
|
||||
dma_tx_channel = dma_claim_unused_channel(false);
|
||||
|
||||
if (dma_tx_channel < 0) return false;
|
||||
|
||||
dma_tx_config = dma_channel_get_default_config(dma_tx_channel);
|
||||
|
||||
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
||||
#else
|
||||
channel_config_set_dreq(&dma_tx_config, pio_get_dreq(tft_pio, pio_sm, true));
|
||||
#endif
|
||||
|
||||
DMA_Enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: deInitDMA
|
||||
** Description: Disconnect the DMA engine from SPI
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::deInitDMA(void)
|
||||
{
|
||||
if (!DMA_Enabled) return;
|
||||
dma_channel_unclaim(dma_tx_channel);
|
||||
DMA_Enabled = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // End of DMA FUNCTIONS
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
458
lib/TFT_eSPI/Processors/TFT_eSPI_RP2040.h
Normal file
458
lib/TFT_eSPI/Processors/TFT_eSPI_RP2040.h
Normal file
|
@ -0,0 +1,458 @@
|
|||
////////////////////////////////////////////////////
|
||||
// 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_
|
||||
|
||||
#ifndef ARDUINO_ARCH_MBED
|
||||
#include <LittleFS.h>
|
||||
#define FONT_FS_AVAILABLE
|
||||
#define SPIFFS LittleFS
|
||||
#endif
|
||||
|
||||
// Required for both the official and community board packages
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
// Processor ID reported by getSetup()
|
||||
#define PROCESSOR_ID 0x2040
|
||||
|
||||
// Transactions always supported
|
||||
#ifndef SUPPORT_TRANSACTIONS
|
||||
#define SUPPORT_TRANSACTIONS
|
||||
#endif
|
||||
|
||||
// Include processor specific header
|
||||
// None
|
||||
|
||||
#if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RP2040_PIO_SPI)
|
||||
#define RP2040_PIO_INTERFACE
|
||||
#define RP2040_PIO_PUSHBLOCK
|
||||
#endif
|
||||
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
// Use SPI0 as default if not defined
|
||||
#ifndef TFT_SPI_PORT
|
||||
#define TFT_SPI_PORT 0
|
||||
#endif
|
||||
|
||||
#if (TFT_SPI_PORT == 0)
|
||||
#define SPI_X spi0
|
||||
#else
|
||||
#define SPI_X spi1
|
||||
#endif
|
||||
|
||||
// Processor specific code used by SPI bus transaction begin/end_tft_write functions
|
||||
#define SET_BUS_WRITE_MODE spi_set_format(SPI_X, 8, (spi_cpol_t)(TFT_SPI_MODE >> 1), (spi_cpha_t)(TFT_SPI_MODE & 0x1), SPI_MSB_FIRST)
|
||||
#define SET_BUS_READ_MODE // spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST)
|
||||
#else
|
||||
// Processor specific code used by SPI bus transaction begin/end_tft_write functions
|
||||
#define SET_BUS_WRITE_MODE
|
||||
#define SET_BUS_READ_MODE
|
||||
#endif
|
||||
|
||||
// Code to check if SPI or DMA is busy, used by SPI bus transaction startWrite and/or endWrite functions
|
||||
#if !defined(SPI_18BIT_DRIVER)
|
||||
#define RP2040_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 (RP2040_PIO_INTERFACE) // SPI
|
||||
// Initialise processor specific SPI functions, used by init()
|
||||
#define INIT_TFT_DATA_BUS // Not used
|
||||
|
||||
// Wait for tx to end, flush rx FIFO, clear rx overrun
|
||||
#define SPI_BUSY_CHECK while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; \
|
||||
while (spi_is_readable(SPI_X)) (void)spi_get_hw(SPI_X)->dr; \
|
||||
spi_get_hw(SPI_X)->icr = SPI_SSPICR_RORIC_BITS
|
||||
|
||||
// To be safe, SUPPORT_TRANSACTIONS is assumed mandatory
|
||||
#if !defined (SUPPORT_TRANSACTIONS)
|
||||
#define SUPPORT_TRANSACTIONS
|
||||
#endif
|
||||
#else
|
||||
|
||||
// Different controllers have different minimum write cycle periods, so the PIO clock is changed accordingly
|
||||
// The PIO clock is a division of the CPU clock so scales when the processor is overclocked
|
||||
// PIO write frequency = (CPU clock/(4 * DIV_UNITS))
|
||||
#if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RP2040_PIO_SPI)
|
||||
#if defined (TFT_PARALLEL_16_BIT)
|
||||
// Different display drivers have different minimum write cycle times
|
||||
#if defined (HX8357C_DRIVER) || defined (SSD1963_DRIVER)
|
||||
#define DIV_UNITS 1 // 32ns write cycle time SSD1963, HX8357C (maybe HX8357D?)
|
||||
#elif defined (ILI9486_DRIVER) || defined (HX8357B_DRIVER) || defined (HX8357D_DRIVER)
|
||||
#define DIV_UNITS 2 // 64ns write cycle time ILI9486, HX8357D, HX8357B
|
||||
#else // ILI9481 needs a slower cycle time
|
||||
#define DIV_UNITS 3 // 96ns write cycle time
|
||||
#endif
|
||||
#define DIV_FRACT 0
|
||||
#else // 8 bit parallel mode
|
||||
#ifdef ILI9481_DRIVER
|
||||
#define DIV_UNITS 1
|
||||
#define DIV_FRACT 160 // Note: Fractional values done with clock period dithering
|
||||
#else
|
||||
#define DIV_UNITS 1
|
||||
#define DIV_FRACT 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialise TFT data bus
|
||||
#if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT)
|
||||
#define INIT_TFT_DATA_BUS pioinit(DIV_UNITS, DIV_FRACT);
|
||||
#elif defined (RP2040_PIO_SPI)
|
||||
#define INIT_TFT_DATA_BUS pioinit(SPI_FREQUENCY);
|
||||
#endif
|
||||
|
||||
#define SPI_BUSY_CHECK
|
||||
|
||||
// Set the state machine clock divider (from integer and fractional parts - 16:8)
|
||||
#define PARALLEL_INIT_TFT_DATA_BUS // Not used
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// If smooth fonts are enabled the filing system may need to be loaded
|
||||
#if defined (SMOOTH_FONT) && !defined (ARDUINO_ARCH_MBED)
|
||||
// Call up the filing system for the anti-aliased fonts
|
||||
//#define FS_NO_GLOBALS
|
||||
#include <FS.h>
|
||||
#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 (RP2040_PIO_INTERFACE)// SPI
|
||||
//#define DC_C sio_hw->gpio_clr = (1ul << TFT_DC)
|
||||
//#define DC_D sio_hw->gpio_set = (1ul << TFT_DC)
|
||||
#if defined (RPI_DISPLAY_TYPE)
|
||||
#define DC_C digitalWrite(TFT_DC, LOW);
|
||||
#define DC_D digitalWrite(TFT_DC, HIGH);
|
||||
#else
|
||||
#define DC_C sio_hw->gpio_clr = (1ul << TFT_DC)
|
||||
#define DC_D sio_hw->gpio_set = (1ul << TFT_DC)
|
||||
#endif
|
||||
#else
|
||||
// PIO takes control of TFT_DC
|
||||
// Must wait for data to flush through before changing DC line
|
||||
#define DC_C WAIT_FOR_STALL; \
|
||||
tft_pio->sm[pio_sm].instr = pio_instr_clr_dc
|
||||
|
||||
// Flush has happened before this and mode changed back to 16 bit
|
||||
#define DC_D tft_pio->sm[pio_sm].instr = pio_instr_set_dc
|
||||
#endif
|
||||
#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
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
#if defined (RPI_DISPLAY_TYPE)
|
||||
#define CS_L digitalWrite(TFT_CS, LOW);
|
||||
#define CS_H digitalWrite(TFT_CS, HIGH);
|
||||
#else
|
||||
#define CS_L sio_hw->gpio_clr = (1ul << TFT_CS)
|
||||
#define CS_H sio_hw->gpio_set = (1ul << TFT_CS)
|
||||
#endif
|
||||
#else // PIO interface display
|
||||
#define CS_L sio_hw->gpio_clr = (1ul << TFT_CS)
|
||||
#define CS_H WAIT_FOR_STALL; sio_hw->gpio_set = (1ul << TFT_CS)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Make sure TFT_RD is defined if not used to avoid an error message
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// At the moment read is not supported for parallel mode, tie TFT signal high
|
||||
#ifdef TFT_RD
|
||||
#if (TFT_RD >= 0)
|
||||
#define RD_L sio_hw->gpio_clr = (1ul << TFT_RD)
|
||||
//#define RD_L digitalWrite(TFT_WR, LOW)
|
||||
#define RD_H sio_hw->gpio_set = (1ul << 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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define the WR (TFT Write) pin drive code
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) // SPI
|
||||
#ifdef TFT_WR
|
||||
#define WR_L digitalWrite(TFT_WR, LOW)
|
||||
#define WR_H digitalWrite(TFT_WR, HIGH)
|
||||
#endif
|
||||
#else
|
||||
// The PIO manages the write line
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define the touch screen chip select pin drive code
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
#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
|
||||
#else
|
||||
#ifdef TOUCH_CS
|
||||
#error Touch screen not supported in parallel or SPI PIO mode, use a separate library.
|
||||
#endif
|
||||
#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 (RP2040_PIO_INTERFACE) // SPI
|
||||
|
||||
#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
|
||||
// Write 8 bits to TFT
|
||||
#define tft_Write_8(C) spi_get_hw(SPI_X)->dr = (uint32_t)(C); \
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; \
|
||||
|
||||
//#define tft_Write_8(C) spi.transfer(C);
|
||||
#define tft_Write_8N(B) while (!spi_is_writable(SPI_X)){}; \
|
||||
spi_get_hw(SPI_X)->dr = (uint8_t)(B)
|
||||
|
||||
// Convert 16 bit colour to 18 bit and write in 3 bytes
|
||||
#define tft_Write_16(C) tft_Write_8N(((C) & 0xF800)>>8); \
|
||||
tft_Write_8N(((C) & 0x07E0)>>3); \
|
||||
tft_Write_8N(((C) & 0x001F)<<3)
|
||||
|
||||
// Convert 16 bit colour to 18 bit and write in 3 bytes
|
||||
#define tft_Write_16N(C) tft_Write_8N(((C) & 0xF800)>>8); \
|
||||
tft_Write_8N(((C) & 0x07E0)>>3); \
|
||||
tft_Write_8N(((C) & 0x001F)<<3)
|
||||
|
||||
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
|
||||
#define tft_Write_16S(C) tft_Write_8N((C) & 0xF8); \
|
||||
tft_Write_8N(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
|
||||
tft_Write_8N(((C) & 0x1F00)>>5)
|
||||
// Write 32 bits to TFT
|
||||
#define tft_Write_32(C) tft_Write_8N(C>>24); \
|
||||
tft_Write_8N(C>>16); \
|
||||
tft_Write_8N(C>>8); \
|
||||
tft_Write_8N(C)
|
||||
|
||||
// Write two address coordinates
|
||||
#define tft_Write_32C(C,D) tft_Write_8N(C>>8); \
|
||||
tft_Write_8N(C); \
|
||||
tft_Write_8N(D>>8); \
|
||||
tft_Write_8N(D)
|
||||
|
||||
// Write same value twice
|
||||
#define tft_Write_32D(C) tft_Write_8N(C>>8); \
|
||||
tft_Write_8N(C); \
|
||||
tft_Write_8N(C>>8); \
|
||||
tft_Write_8N(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)
|
||||
|
||||
#elif defined (ILI9225_DRIVER) // Needs gaps between commands + data bytes, so use slower transfer functions
|
||||
|
||||
// Warning: these all end in 8 bit SPI mode!
|
||||
#define tft_Write_8(C) spi.transfer(C);
|
||||
|
||||
#define tft_Write_16(C) spi.transfer16(C)
|
||||
|
||||
#define tft_Write_16N(C) spi.transfer16(C)
|
||||
|
||||
#define tft_Write_16S(C) spi.transfer16((C)<<8 | (C)>>8)
|
||||
|
||||
#define tft_Write_32(C) spi.transfer16((C)>>16); spi.transfer16(C)
|
||||
|
||||
#define tft_Write_32C(C,D) spi.transfer16(C); spi.transfer16(D)
|
||||
|
||||
#define tft_Write_32D(C) spi.transfer16(C); spi.transfer16(C)
|
||||
|
||||
#else
|
||||
|
||||
// This swaps to 8 bit mode, then back to 16 bit mode
|
||||
#define tft_Write_8(C) while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; \
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); \
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)(C); \
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; \
|
||||
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS)
|
||||
|
||||
// Note: the following macros do not wait for the end of transmission
|
||||
|
||||
#define tft_Write_16(C) while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = (uint32_t)(C)
|
||||
|
||||
#define tft_Write_16N(C) while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = (uint32_t)(C)
|
||||
|
||||
#define tft_Write_16S(C) while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = (uint32_t)(C)<<8 | (C)>>8
|
||||
|
||||
#define tft_Write_32(C) spi_get_hw(SPI_X)->dr = (uint32_t)((C)>>16); spi_get_hw(SPI_X)->dr = (uint32_t)(C)
|
||||
|
||||
#define tft_Write_32C(C,D) spi_get_hw(SPI_X)->dr = (uint32_t)(C); spi_get_hw(SPI_X)->dr = (uint32_t)(D)
|
||||
|
||||
#define tft_Write_32D(C) spi_get_hw(SPI_X)->dr = (uint32_t)(C); spi_get_hw(SPI_X)->dr = (uint32_t)(C)
|
||||
|
||||
#endif // RPI_DISPLAY_TYPE
|
||||
#endif
|
||||
|
||||
#else // Parallel 8 bit or PIO SPI
|
||||
|
||||
// Wait for the PIO to stall (SM pull request finds no data in TX FIFO)
|
||||
// This is used to detect when the SM is idle and hence ready for a jump instruction
|
||||
#define WAIT_FOR_STALL tft_pio->fdebug = pull_stall_mask; while (!(tft_pio->fdebug & pull_stall_mask))
|
||||
|
||||
// Wait until at least "S" locations free
|
||||
#define WAIT_FOR_FIFO_FREE(S) while (((tft_pio->flevel >> (pio_sm * 8)) & 0x000F) > (8-S)){}
|
||||
|
||||
// Wait until at least 5 locations free
|
||||
#define WAIT_FOR_FIFO_5_FREE while ((tft_pio->flevel) & (0x000c << (pio_sm * 8))){}
|
||||
|
||||
// Wait until at least 1 location free
|
||||
#define WAIT_FOR_FIFO_1_FREE while ((tft_pio->flevel) & (0x0008 << (pio_sm * 8))){}
|
||||
|
||||
// Wait for FIFO to empty (use before swapping to 8 bits)
|
||||
#define WAIT_FOR_FIFO_EMPTY while(!(tft_pio->fstat & (1u << (PIO_FSTAT_TXEMPTY_LSB + pio_sm))))
|
||||
|
||||
// The write register of the TX FIFO.
|
||||
#define TX_FIFO tft_pio->txf[pio_sm]
|
||||
|
||||
// Temporary - to be deleted
|
||||
#define GPIO_DIR_MASK 0
|
||||
|
||||
#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
// This writes 8 bits, then switches back to 16 bit mode automatically
|
||||
// Have already waited for pio stalled (last data write complete) when DC switched to command mode
|
||||
// The wait for stall allows DC to be changed immediately afterwards
|
||||
#define tft_Write_8(C) tft_pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
||||
TX_FIFO = (C); \
|
||||
WAIT_FOR_STALL
|
||||
|
||||
// Used to send last byte for 32 bit macros below since PIO sends 24 bits
|
||||
#define tft_Write_8L(C) WAIT_FOR_STALL; \
|
||||
tft_pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
||||
TX_FIFO = (C)
|
||||
|
||||
// Note: the following macros do not wait for the end of transmission
|
||||
|
||||
#define tft_Write_16(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = ((((uint32_t)(C) & 0xF800)<<8) | (((C) & 0x07E0)<<5) | (((C) & 0x001F)<<3))
|
||||
|
||||
#define tft_Write_16N(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = ((((uint32_t)(C) & 0xF800)<<8) | (((C) & 0x07E0)<<5) | (((C) & 0x001F)<<3))
|
||||
|
||||
#define tft_Write_16S(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = ((((uint32_t)(C) & 0xF8) << 16) | (((C) & 0xE000)>>3) | (((C) & 0x07)<<13) | (((C) & 0x1F00)>>5))
|
||||
|
||||
#define tft_Write_32(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = ((C)>>8); WAIT_FOR_STALL; tft_Write_8(C)
|
||||
|
||||
#define tft_Write_32C(C,D) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (((C)<<8) | ((D)>>8)); tft_Write_8L(D)
|
||||
|
||||
#define tft_Write_32D(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (((C)<<8) | ((C)>>8)); tft_Write_8L(C)
|
||||
|
||||
#else // PIO interface, SPI or parallel
|
||||
// This writes 8 bits, then switches back to 16 bit mode automatically
|
||||
// Have already waited for pio stalled (last data write complete) when DC switched to command mode
|
||||
// The wait for stall allows DC to be changed immediately afterwards
|
||||
#if defined (TFT_PARALLEL_8_BIT) || defined (RP2040_PIO_SPI)
|
||||
#define tft_Write_8(C) tft_pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
||||
TX_FIFO = (C); \
|
||||
WAIT_FOR_STALL
|
||||
#else // For 16 bit parallel 16 bits are always sent
|
||||
#define tft_Write_8(C) TX_FIFO = (C); \
|
||||
WAIT_FOR_STALL
|
||||
#endif
|
||||
|
||||
// Note: the following macros do not wait for the end of transmission
|
||||
|
||||
#define tft_Write_16(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = (C)
|
||||
|
||||
#define tft_Write_16N(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = (C)
|
||||
|
||||
#define tft_Write_16S(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = ((C)<<8) | ((C)>>8)
|
||||
|
||||
#define tft_Write_32(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = ((C)>>16); TX_FIFO = (C)
|
||||
|
||||
#define tft_Write_32C(C,D) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (C); TX_FIFO = (D)
|
||||
|
||||
#define tft_Write_32D(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (C); TX_FIFO = (C)
|
||||
#endif
|
||||
#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 (RP2040_PIO_INTERFACE)// 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
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Temporary to keep the "Arduino Mbed OS RP2040 Boards" support package happy
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
|
||||
#define ltoa itoa
|
||||
|
||||
#endif
|
||||
|
||||
#endif // Header end
|
675
lib/TFT_eSPI/Processors/TFT_eSPI_STM32.c
Normal file
675
lib/TFT_eSPI/Processors/TFT_eSPI_STM32.c
Normal file
|
@ -0,0 +1,675 @@
|
|||
////////////////////////////////////////////////////
|
||||
// TFT_eSPI Driver functions for STM32 processors //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Global variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
// No globals
|
||||
#else
|
||||
// Use STM32 default SPI port
|
||||
#if !defined (TFT_MOSI) || !defined (TFT_MISO) || !defined (TFT_SCLK)
|
||||
SPIClass& spi = SPI;
|
||||
#else
|
||||
SPIClass spi(TFT_MOSI, TFT_MISO, TFT_SCLK);
|
||||
#endif
|
||||
// SPI HAL peripheral handle
|
||||
SPI_HandleTypeDef spiHal;
|
||||
#endif
|
||||
|
||||
#ifdef STM32_DMA
|
||||
// DMA HAL handle
|
||||
DMA_HandleTypeDef dmaHal;
|
||||
#endif
|
||||
|
||||
// Buffer for SPI transmit byte padding and byte order manipulation
|
||||
uint8_t spiBuffer[8];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************############# UNTESTED ###################
|
||||
** Function name: tft_Read_8
|
||||
** Description: STM32 software SPI to read bidirectional SDA line
|
||||
***************************************************************************************/
|
||||
uint8_t TFT_eSPI::tft_Read_8(void)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
uint32_t reg = 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;
|
||||
}
|
||||
|
||||
/***************************************************************************************############# UNTESTED ###################
|
||||
** 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();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<<
|
||||
}
|
||||
|
||||
/***************************************************************************************############# UNTESTED ###################
|
||||
** 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();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<<
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // #if defined (TFT_SDA_READ)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_PARALLEL_8_BIT) // Code for STM32 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){
|
||||
// Loop unrolling improves speed dramatically graphics test 0.634s => 0.374s
|
||||
while (len>31) {
|
||||
#if !defined (SSD1963_DRIVER)
|
||||
// 32D macro writes 16 bits twice
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
#else
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
#endif
|
||||
len-=32;
|
||||
}
|
||||
|
||||
while (len>7) {
|
||||
#if !defined (SSD1963_DRIVER)
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
tft_Write_32D(color); tft_Write_32D(color);
|
||||
#else
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
|
||||
#endif
|
||||
len-=8;
|
||||
}
|
||||
|
||||
while (len--) {tft_Write_16(color);}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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>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)
|
||||
{
|
||||
#if defined (STM_PORTA_DATA_BUS)
|
||||
#if defined (STM32F1xx)
|
||||
if (mode == OUTPUT) GPIOA->CRL = 0x33333333;
|
||||
else GPIOA->CRL = 0x88888888;
|
||||
#else
|
||||
if (mode == OUTPUT) GPIOA->MODER = (GPIOA->MODER & 0xFFFF0000) | 0x00005555;
|
||||
else GPIOA->MODER &= 0xFFFF0000;
|
||||
#endif
|
||||
#elif defined (STM_PORTB_DATA_BUS)
|
||||
#if defined (STM32F1xx)
|
||||
if (mode == OUTPUT) GPIOB->CRL = 0x33333333;
|
||||
else GPIOB->CRL = 0x88888888;
|
||||
#else
|
||||
if (mode == OUTPUT) GPIOB->MODER = (GPIOB->MODER & 0xFFFF0000) | 0x00005555;
|
||||
else GPIOB->MODER &= 0xFFFF0000;
|
||||
#endif
|
||||
#elif defined (STM_PORTC_DATA_BUS)
|
||||
#if defined (STM32F1xx)
|
||||
if (mode == OUTPUT) GPIOC->CRL = 0x33333333;
|
||||
else GPIOC->CRL = 0x88888888;
|
||||
#else
|
||||
if (mode == OUTPUT) GPIOC->MODER = (GPIOC->MODER & 0xFFFF0000) | 0x00005555;
|
||||
else GPIOC->MODER &= 0xFFFF0000;
|
||||
#endif
|
||||
#elif defined (STM_PORTD_DATA_BUS)
|
||||
#if defined (STM32F1xx)
|
||||
if (mode == OUTPUT) GPIOD->CRL = 0x33333333;
|
||||
else GPIOD->CRL = 0x88888888;
|
||||
#else
|
||||
if (mode == OUTPUT) GPIOD->MODER = (GPIOD->MODER & 0xFFFF0000) | 0x00005555;
|
||||
else GPIOD->MODER &= 0xFFFF0000;
|
||||
#endif
|
||||
#else
|
||||
if (mode == OUTPUT) {
|
||||
LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_MASK, LL_GPIO_MODE_OUTPUT);
|
||||
}
|
||||
else {
|
||||
LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_MASK, LL_GPIO_MODE_INPUT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: GPIO direction control - supports class functions
|
||||
** Description: Set STM32 GPIO pin to input or output (set high) ASAP
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
|
||||
{
|
||||
PinName pn = digitalPinToPinName(gpio);
|
||||
// Push-pull output with no pullup
|
||||
if (mode == OUTPUT) pin_function(pn, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0));
|
||||
// Input with pullup
|
||||
else pin_function(pn, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0));
|
||||
}
|
||||
|
||||
/***************************************************************************************############# UNTESTED ###################
|
||||
** Function name: read byte - supports class functions
|
||||
** Description: Read a byte - parallel bus only
|
||||
***************************************************************************************/
|
||||
uint8_t TFT_eSPI::readByte(void)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
|
||||
RD_L;
|
||||
#if defined (STM_PORTA_DATA_BUS)
|
||||
b = GPIOA->IDR;
|
||||
b = GPIOA->IDR;
|
||||
b = GPIOA->IDR;
|
||||
b = (GPIOA->IDR) & 0xFF;
|
||||
#elif defined (STM_PORTB_DATA_BUS)
|
||||
b = GPIOB->IDR;
|
||||
b = GPIOB->IDR;
|
||||
b = GPIOB->IDR;
|
||||
b = (GPIOB->IDR) & 0xFF;
|
||||
#elif defined (STM_PORTC_DATA_BUS)
|
||||
b = GPIOC->IDR;
|
||||
b = GPIOC->IDR;
|
||||
b = GPIOC->IDR;
|
||||
b = (GPIOC->IDR) & 0xFF;
|
||||
#elif defined (STM_PORTD_DATA_BUS)
|
||||
b = GPIOD->IDR;
|
||||
b = GPIOD->IDR;
|
||||
b = GPIOD->IDR;
|
||||
b = (GPIOD->IDR) & 0xFF;
|
||||
#else
|
||||
b = RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0; //Delay for bits to settle
|
||||
|
||||
b = RD_TFT_D0 | RD_TFT_D1 | RD_TFT_D2 | RD_TFT_D3;
|
||||
b |= RD_TFT_D4 | RD_TFT_D5 | RD_TFT_D6 | RD_TFT_D7;
|
||||
#endif
|
||||
RD_H;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe ############# UNTESTED ###################
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for ESP32 or STM32 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 STM32 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 STM32 and 3 byte RGB display
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
#define BUF_SIZE 240*3
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||
{
|
||||
uint8_t col[BUF_SIZE];
|
||||
// Always using swapped bytes is a peculiarity of this function...
|
||||
//color = color>>8 | color<<8;
|
||||
uint8_t r = (color & 0xF800)>>8; // Red
|
||||
uint8_t g = (color & 0x07E0)>>3; // Green
|
||||
uint8_t b = (color & 0x001F)<<3; // Blue
|
||||
|
||||
if (len<BUF_SIZE/3) {
|
||||
for (uint32_t i = 0; i < len*3; i++) {
|
||||
col[i] = r;
|
||||
col[++i] = g;
|
||||
col[++i] = b;
|
||||
}
|
||||
HAL_SPI_Transmit(&spiHal, col, len*3, HAL_MAX_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < BUF_SIZE; i++) {
|
||||
col[i] = r;
|
||||
col[++i] = g;
|
||||
col[++i] = b;
|
||||
}
|
||||
do {
|
||||
HAL_SPI_Transmit(&spiHal, col, BUF_SIZE, HAL_MAX_DELAY);
|
||||
len -= BUF_SIZE/3;
|
||||
} while ( len>=BUF_SIZE/3 ) ;
|
||||
// Send remaining pixels
|
||||
if (len) HAL_SPI_Transmit(&spiHal, col, len*3, HAL_MAX_DELAY); //*/
|
||||
}
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for STM32 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-- ) {
|
||||
// Split out the colours
|
||||
spiBuffer[0] = (*data & 0xF8); // Red
|
||||
spiBuffer[1] = (*data & 0xE000)>>11 | (*data & 0x07)<<5; // Green
|
||||
spiBuffer[2] = (*data & 0x1F00)>>5; // Blue
|
||||
data++;
|
||||
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ( len-- ) {
|
||||
// Split out the colours
|
||||
spiBuffer[0] = (*data & 0xF800)>>8; // Red
|
||||
spiBuffer[1] = (*data & 0x07E0)>>3; // Green
|
||||
spiBuffer[2] = (*data & 0x001F)<<3; // Blue
|
||||
data++;
|
||||
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#else // Standard SPI 16 bit colour TFT All Tested
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for STM32
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
#define BUF_SIZE 480
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||
{
|
||||
uint16_t col[BUF_SIZE];
|
||||
// Always using swapped bytes is a peculiarity of this function...
|
||||
uint16_t swapColor = color>>8 | color<<8;
|
||||
if (len<BUF_SIZE) {
|
||||
for (uint32_t i = 0; i < len; i++) col[i] = swapColor;
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < BUF_SIZE; i++) col[i] = swapColor;
|
||||
do {
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY);
|
||||
len -= BUF_SIZE;
|
||||
} while ( len>=BUF_SIZE ) ;
|
||||
// Send remaining pixels
|
||||
if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for STM32
|
||||
** 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) {
|
||||
uint16_t col[BUF_SIZE]; // Buffer for swapped bytes
|
||||
while ( len>=BUF_SIZE ) {
|
||||
for (uint32_t i = 0; i < BUF_SIZE; i++) { col[i] = (*data>>8) | (*data<<8); data++; }
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY);
|
||||
len -= BUF_SIZE;
|
||||
}
|
||||
for (uint32_t i = 0; i < len; i++) { col[i] = (*data>>8) | (*data<<8); data++; }
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY);
|
||||
}
|
||||
else {
|
||||
// HAL byte count for transmit is only 16 bits maximum so to avoid this constraint
|
||||
// transfers of small blocks are performed until HAL capacity is reached.
|
||||
while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)data, 0x800<<1, HAL_MAX_DELAY);
|
||||
len -= 0x800; data+= 0x800; // Arbitrarily use 2KByte blocks
|
||||
}
|
||||
// Send remaining pixels (max 65534 bytes)
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)data, len<<1, HAL_MAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // End of display interface specific functions
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined STM32_DMA && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: dmaBusy
|
||||
** Description: Check if DMA is busy (usefully non-blocking!)
|
||||
***************************************************************************************/
|
||||
// Use while( tft.dmaBusy() ) {Do-something-useful;}"
|
||||
bool TFT_eSPI::dmaBusy(void)
|
||||
{
|
||||
//return (dmaHal.State == HAL_DMA_STATE_BUSY); // Do not use, SPI may still be busy
|
||||
return (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: dmaWait
|
||||
** Description: Wait until DMA is over (blocking!)
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::dmaWait(void)
|
||||
{
|
||||
//return (dmaHal.State == HAL_DMA_STATE_BUSY); // Do not use, SPI may still be busy
|
||||
while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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) return;
|
||||
|
||||
// Wait for any current DMA transaction to end
|
||||
while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy
|
||||
|
||||
if(_swapBytes) {
|
||||
for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8);
|
||||
}
|
||||
|
||||
HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)image, len << 1);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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)) 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;
|
||||
while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
setWindow(x, y, x + dw - 1, y + dh - 1);
|
||||
|
||||
// DMA byte count for transmit is only 16 bits 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 32767 pixels maximum. (equivalent to an area of ~320 x 100 pixels)
|
||||
while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes
|
||||
HAL_SPI_Transmit(&spiHal, (uint8_t*)buffer, 0x800<<1, HAL_MAX_DELAY);
|
||||
len -= 0x800; buffer+= 0x800; // Arbitrarily send 1K pixel blocks (2Kbytes)
|
||||
}
|
||||
// Send remaining pixels using DMA (max 65534 bytes)
|
||||
HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)buffer, len << 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Processor specific DMA initialisation
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The DMA functions here work with SPI only (not parallel)
|
||||
#if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx)
|
||||
/***************************************************************************************
|
||||
** Function name: DMAX_StreamX_IRQHandler
|
||||
** Description: Override the default HAL stream X interrupt handler
|
||||
***************************************************************************************/
|
||||
#if (TFT_SPI_PORT == 1)
|
||||
extern "C" void DMA2_Stream3_IRQHandler();
|
||||
void DMA2_Stream3_IRQHandler(void)
|
||||
#elif (TFT_SPI_PORT == 2)
|
||||
extern "C" void DMA1_Stream4_IRQHandler();
|
||||
void DMA1_Stream4_IRQHandler(void)
|
||||
#elif (TFT_SPI_PORT == 3)
|
||||
extern "C" void DMA1_Stream5_IRQHandler();
|
||||
void DMA1_Stream5_IRQHandler(void)
|
||||
#endif
|
||||
{
|
||||
// Call the default end of buffer handler
|
||||
HAL_DMA_IRQHandler(&dmaHal);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: initDMA
|
||||
** Description: Initialise the DMA engine - returns true if init OK
|
||||
***************************************************************************************/
|
||||
// This initialisation is for STM32F2xx/4xx/7xx processors and may not work on others
|
||||
// Dual core H7xx series not supported yet, they are different and have a DMA MUX:
|
||||
// https://electronics.stackexchange.com/questions/379813/configuring-the-dma-request-multiplexer-on-a-stm32h7-mcu
|
||||
bool TFT_eSPI::initDMA(bool ctrl_cs)
|
||||
{
|
||||
ctrl_cs = ctrl_cs; // Not used for STM32, so stop compiler warning
|
||||
|
||||
#if (TFT_SPI_PORT == 1)
|
||||
__HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock
|
||||
dmaHal.Init.Channel = DMA_CHANNEL_3; // DMA channel 3 is for SPI1 TX
|
||||
#elif (TFT_SPI_PORT == 2)
|
||||
__HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock
|
||||
dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI2 TX
|
||||
#elif (TFT_SPI_PORT == 3)
|
||||
__HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock
|
||||
dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI3 TX
|
||||
|
||||
#endif
|
||||
|
||||
dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once
|
||||
dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral
|
||||
dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address
|
||||
dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned
|
||||
dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address
|
||||
dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned
|
||||
|
||||
if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings
|
||||
// Insert error message here?
|
||||
return DMA_Enabled = false;
|
||||
};
|
||||
#if (TFT_SPI_PORT == 1)
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); // Enable DMA end interrupt handler
|
||||
#elif (TFT_SPI_PORT == 2)
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); // Enable DMA end interrupt handler
|
||||
#endif
|
||||
|
||||
__HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral
|
||||
|
||||
return DMA_Enabled = true;
|
||||
}
|
||||
|
||||
#elif defined (STM32F1xx) // Supports "Blue Pill" boards
|
||||
/***************************************************************************************
|
||||
** Function name: DMA1_ChannelX_IRQHandler
|
||||
** Description: Override the default HAL stream 3 interrupt handler
|
||||
***************************************************************************************/
|
||||
#if (TFT_SPI_PORT == 1)
|
||||
extern "C" void DMA1_Channel3_IRQHandler();
|
||||
void DMA1_Channel3_IRQHandler(void)
|
||||
#elif (TFT_SPI_PORT == 2)
|
||||
extern "C" void DMA1_Channel5_IRQHandler();
|
||||
void DMA1_Channel5_IRQHandler(void)
|
||||
#endif
|
||||
{
|
||||
// Call the default end of buffer handler
|
||||
HAL_DMA_IRQHandler(&dmaHal);
|
||||
}
|
||||
|
||||
//*/
|
||||
/***************************************************************************************
|
||||
** Function name: initDMA
|
||||
** Description: Initialise the DMA engine - returns true if init OK
|
||||
***************************************************************************************/
|
||||
bool TFT_eSPI::initDMA(bool ctrl_cs)
|
||||
{
|
||||
ctrl_cs = ctrl_cs; // Not used for STM32, so stop compiler warning
|
||||
|
||||
__HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock
|
||||
|
||||
dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once
|
||||
dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral
|
||||
dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address
|
||||
dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned
|
||||
dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address
|
||||
dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned
|
||||
dmaHal.Init.Priority = DMA_PRIORITY_LOW; // Added this line - needed ?
|
||||
|
||||
__HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral
|
||||
|
||||
if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings
|
||||
// Insert error message here?
|
||||
return DMA_Enabled = false;
|
||||
};
|
||||
|
||||
#if (TFT_SPI_PORT == 1)
|
||||
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); // Enable DMA end interrupt handler
|
||||
#elif (TFT_SPI_PORT == 2)
|
||||
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); // Enable DMA end interrupt handler
|
||||
#endif
|
||||
|
||||
return DMA_Enabled = true;
|
||||
}
|
||||
#endif // End of STM32F1/2/4/7xx
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: deInitDMA
|
||||
** Description: Disconnect the DMA engine from SPI
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::deInitDMA(void)
|
||||
{
|
||||
HAL_DMA_DeInit(&dmaHal);
|
||||
DMA_Enabled = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // End of DMA FUNCTIONS
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
1078
lib/TFT_eSPI/Processors/TFT_eSPI_STM32.h
Normal file
1078
lib/TFT_eSPI/Processors/TFT_eSPI_STM32.h
Normal file
File diff suppressed because it is too large
Load diff
62
lib/TFT_eSPI/Processors/pio_16bit_parallel.pio.h
Normal file
62
lib/TFT_eSPI/Processors/pio_16bit_parallel.pio.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// 16 bit parallel //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 7
|
||||
#define tft_io_wrap 20
|
||||
#define tft_io_offset_block_fill 0u
|
||||
#define tft_io_offset_start_8 7u
|
||||
#define tft_io_offset_start_tx 7u
|
||||
#define tft_io_offset_set_addr_window 10u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
0x98a0, // 0: pull block side 1
|
||||
0xa027, // 1: mov x, osr
|
||||
0x80a0, // 2: pull block
|
||||
0xa047, // 3: mov y, osr
|
||||
0xb8e1, // 4: mov osr, x side 1
|
||||
0x7100, // 5: out pins, 32 side 0 [1]
|
||||
0x1884, // 6: jmp y--, 4 side 1
|
||||
// .wrap_target
|
||||
0x98a0, // 7: pull block side 1
|
||||
0x7100, // 8: out pins, 32 side 0 [1]
|
||||
0x1807, // 9: jmp 7 side 1
|
||||
0xf822, // 10: set x, 2 side 1
|
||||
0xe000, // 11: set pins, 0
|
||||
0x80a0, // 12: pull block
|
||||
0x7000, // 13: out pins, 32 side 0
|
||||
0x0033, // 14: jmp !x, 19
|
||||
0x98a0, // 15: pull block side 1
|
||||
0xe001, // 16: set pins, 1
|
||||
0x7108, // 17: out pins, 8 side 0 [1]
|
||||
0x19f1, // 18: jmp !osre, 17 side 1 [1]
|
||||
0x184b, // 19: jmp x--, 11 side 1
|
||||
0xe001, // 20: set pins, 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 21,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config tft_io_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
70
lib/TFT_eSPI/Processors/pio_8bit_parallel.pio.h
Normal file
70
lib/TFT_eSPI/Processors/pio_8bit_parallel.pio.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// 8 bit parallel //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 9
|
||||
#define tft_io_wrap 27
|
||||
|
||||
#define tft_io_offset_block_fill 0u
|
||||
#define tft_io_offset_start_tx 9u
|
||||
#define tft_io_offset_start_8 14u
|
||||
#define tft_io_offset_set_addr_window 17u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
0x98a0, // 0: pull block side 1
|
||||
0xa027, // 1: mov x, osr
|
||||
0x80a0, // 2: pull block
|
||||
0xa047, // 3: mov y, osr
|
||||
0xb8e1, // 4: mov osr, x side 1
|
||||
0x7118, // 5: out pins, 24 side 0 [1]
|
||||
0xb942, // 6: nop side 1 [1]
|
||||
0x7108, // 7: out pins, 8 side 0 [1]
|
||||
0x1884, // 8: jmp y--, 4 side 1
|
||||
// .wrap_target
|
||||
0x98a0, // 9: pull block side 1
|
||||
0x7118, // 10: out pins, 24 side 0 [1]
|
||||
0xb942, // 11: nop side 1 [1]
|
||||
0x7108, // 12: out pins, 8 side 0 [1]
|
||||
0x1809, // 13: jmp 9 side 1
|
||||
0x98a0, // 14: pull block side 1
|
||||
0x7100, // 15: out pins, 32 side 0 [1]
|
||||
0x1809, // 16: jmp 9 side 1
|
||||
0xf822, // 17: set x, 2 side 1
|
||||
0xe000, // 18: set pins, 0
|
||||
0x80a0, // 19: pull block
|
||||
0x7000, // 20: out pins, 32 side 0
|
||||
0x003a, // 21: jmp !x, 26
|
||||
0x98a0, // 22: pull block side 1
|
||||
0xe001, // 23: set pins, 1
|
||||
0x7108, // 24: out pins, 8 side 0 [1]
|
||||
0x19f8, // 25: jmp !osre, 24 side 1 [1]
|
||||
0x1852, // 26: jmp x--, 18 side 1
|
||||
0xe001, // 27: set pins, 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 28,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config tft_io_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
74
lib/TFT_eSPI/Processors/pio_SPI.pio.h
Normal file
74
lib/TFT_eSPI/Processors/pio_SPI.pio.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// 8 + 16 bit SPI - no auto colour conversion //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 27
|
||||
#define tft_io_wrap 31
|
||||
|
||||
#define tft_io_offset_start_8 0u
|
||||
#define tft_io_offset_set_addr_window 3u
|
||||
#define tft_io_offset_block_fill 17u
|
||||
#define tft_io_offset_start_tx 27u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
0x90a0, // 0: pull block side 0
|
||||
0x6019, // 1: out pins, 25
|
||||
0x181e, // 2: jmp 30 side 1
|
||||
0xf022, // 3: set x, 2 side 0
|
||||
0xe000, // 4: set pins, 0
|
||||
0x90a0, // 5: pull block side 0
|
||||
0x6019, // 6: out pins, 25
|
||||
0xb842, // 7: nop side 1
|
||||
0x7001, // 8: out pins, 1 side 0
|
||||
0x18e8, // 9: jmp !osre, 8 side 1
|
||||
0xf001, // 10: set pins, 1 side 0
|
||||
0x003b, // 11: jmp !x, 27
|
||||
0x80a0, // 12: pull block
|
||||
0x7001, // 13: out pins, 1 side 0
|
||||
0x18ed, // 14: jmp !osre, 13 side 1
|
||||
0x1044, // 15: jmp x--, 4 side 0
|
||||
0x001b, // 16: jmp 27
|
||||
0x90a0, // 17: pull block side 0
|
||||
0xa027, // 18: mov x, osr
|
||||
0x80a0, // 19: pull block
|
||||
0xa047, // 20: mov y, osr
|
||||
0xb0e1, // 21: mov osr, x side 0
|
||||
0x7011, // 22: out pins, 17 side 0
|
||||
0xb842, // 23: nop side 1
|
||||
0x7001, // 24: out pins, 1 side 0
|
||||
0x18f8, // 25: jmp !osre, 24 side 1
|
||||
0x1095, // 26: jmp y--, 21 side 0
|
||||
// .wrap_target
|
||||
0x90a0, // 27: pull block side 0
|
||||
0x7011, // 28: out pins, 17 side 0
|
||||
0xb842, // 29: nop side 1
|
||||
0x7001, // 30: out pins, 1 side 0
|
||||
0x18fe, // 31: jmp !osre, 30 side 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 32,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config tft_io_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
74
lib/TFT_eSPI/Processors/pio_SPI_18bit.pio.h
Normal file
74
lib/TFT_eSPI/Processors/pio_SPI_18bit.pio.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// 8 + 18 bit SPI - no auto colour conversion //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 27
|
||||
#define tft_io_wrap 31
|
||||
|
||||
#define tft_io_offset_start_8 0u
|
||||
#define tft_io_offset_set_addr_window 3u
|
||||
#define tft_io_offset_block_fill 17u
|
||||
#define tft_io_offset_start_tx 27u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
0x90a0, // 0: pull block side 0
|
||||
0x6019, // 1: out pins, 25
|
||||
0x181e, // 2: jmp 30 side 1
|
||||
0xf022, // 3: set x, 2 side 0
|
||||
0xe000, // 4: set pins, 0
|
||||
0x90a0, // 5: pull block side 0
|
||||
0x6019, // 6: out pins, 25
|
||||
0xb842, // 7: nop side 1
|
||||
0x7001, // 8: out pins, 1 side 0
|
||||
0x18e8, // 9: jmp !osre, 8 side 1
|
||||
0xf001, // 10: set pins, 1 side 0
|
||||
0x003b, // 11: jmp !x, 27
|
||||
0x80a0, // 12: pull block
|
||||
0x7001, // 13: out pins, 1 side 0
|
||||
0x18ed, // 14: jmp !osre, 13 side 1
|
||||
0x1044, // 15: jmp x--, 4 side 0
|
||||
0x001b, // 16: jmp 27
|
||||
0x90a0, // 17: pull block side 0
|
||||
0xa027, // 18: mov x, osr
|
||||
0x80a0, // 19: pull block
|
||||
0xa047, // 20: mov y, osr
|
||||
0xb0e1, // 21: mov osr, x side 0
|
||||
0x7009, // 22: out pins, 9 side 0
|
||||
0xb842, // 23: nop side 1
|
||||
0x7001, // 24: out pins, 1 side 0
|
||||
0x18f8, // 25: jmp !osre, 24 side 1
|
||||
0x1095, // 26: jmp y--, 21 side 0
|
||||
// .wrap_target
|
||||
0x90a0, // 27: pull block side 0
|
||||
0x7009, // 28: out pins, 9 side 0
|
||||
0xb842, // 29: nop side 1
|
||||
0x7001, // 30: out pins, 1 side 0
|
||||
0x18fe, // 31: jmp !osre, 30 side 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 32,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config tft_io_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue