daily_automated

This commit is contained in:
topicchi
2023-03-17 11:59:21 +00:00
parent 252ecca9cf
commit e2f276193e
4496 changed files with 1178007 additions and 0 deletions

View File

@@ -0,0 +1,715 @@
////////////////////////////////////////////////////
// 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 USE_HSPI_PORT
SPIClass spi = SPIClass(HSPI);
#else // use default VSPI port
//SPIClass& spi = SPI;
SPIClass spi = SPIClass(VSPI);
#endif
#endif
#ifdef ESP32_DMA
// DMA SPA handle
spi_device_handle_t dmaHAL;
#ifdef USE_HSPI_PORT
spi_host_device_t spi_host = HSPI_HOST;
#else
spi_host_device_t spi_host = VSPI_HOST;
#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);
}
/***************************************************************************************
** 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);
}
////////////////////////////////////////////////////////////////////////////////////////
#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)
{
gpioMode(TFT_D0, mode);
gpioMode(TFT_D1, mode);
gpioMode(TFT_D2, mode);
gpioMode(TFT_D3, mode);
gpioMode(TFT_D4, mode);
gpioMode(TFT_D5, mode);
gpioMode(TFT_D6, mode);
gpioMode(TFT_D7, mode);
return;
/*
// Arduino generic native function, but slower
pinMode(TFT_D0, mode);
pinMode(TFT_D1, mode);
pinMode(TFT_D2, mode);
pinMode(TFT_D3, mode);
pinMode(TFT_D4, mode);
pinMode(TFT_D5, mode);
pinMode(TFT_D6, mode);
pinMode(TFT_D7, mode);
return; //*/
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set ESP32 GPIO pin to input or output (set high) ASAP
***************************************************************************************/
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
{
if(mode == INPUT) GPIO.enable_w1tc = ((uint32_t)1 << gpio);
else GPIO.enable_w1ts = ((uint32_t)1 << gpio);
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[gpio].reg) // Register lookup
= ((uint32_t)2 << FUN_DRV_S) // Set drive strength 2
| (FUN_IE) // Input enable
| ((uint32_t)2 << MCU_SEL_S); // Function select 2
GPIO.pin[gpio].val = 1; // Set pin 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 (ILI9488_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most 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);
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), color32);
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), color32);
WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), color32);
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
len -= 32;
}
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
}
if (len)
{
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, color32);
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&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 (ILI9488_DRIVER) && !defined (TFT_PARALLEL_8_BIT)// Now code for ILI9488
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** 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 ( (color >> 8) == (color & 0x00FF) )
{ if (!len) return;
tft_Write_16(color);
while (--len) {WR_L; WR_H; WR_L; WR_H;}
}
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: pushImageDMA
** 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)
***************************************************************************************/
// 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 >= _width) || (y >= _height) || (!DMA_Enabled)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - 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(); // Incase 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(void)
{
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
};
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 = TFT_CS,
.flags = 0,
.queue_size = 7,
.pre_cb = dc_callback, //Callback to handle D/C line
.post_cb = 0
};
ret = spi_bus_initialize(spi_host, &buscfg, 1);
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
////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,414 @@
////////////////////////////////////////////////////
// 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"
// 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
// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
#if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS
#endif
// ESP32 specific SPI port selection
#ifdef USE_HSPI_PORT
#define SPI_PORT HSPI
#else
#define SPI_PORT VSPI
#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
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions
#if !defined(TFT_PARALLEL_8_BIT) && !defined(ILI9488_DRIVER) && !defined (RPI_DISPLAY_TYPE)
#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 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)
#define DC_C GPIO.out_w1tc = (1 << TFT_DC)
#define DC_D GPIO.out_w1ts = (1 << TFT_DC)
#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
#ifdef RPI_DISPLAY_TYPE // 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)
#elif defined (RPI_DISPLAY_TYPE) // 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)
#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 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 ILI9486 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 ILI9486 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
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_WR
#define WR_L GPIO.out_w1tc = (1 << TFT_WR)
#define WR_H GPIO.out_w1ts = (1 << TFT_WR)
#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 12
#endif
#if (TFT_MISO == -1)
#undef TFT_MISO
#define TFT_MISO 12
#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 19
#endif
#if (TFT_MISO == -1)
#undef TFT_MISO
#define TFT_MISO 19
#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
#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 CONSTRUCTOR_INIT_TFT_DATA_BUS \
for (int32_t c = 0; c<256; c++) \
{ \
xset_mask[c] = 0; \
if ( c & 0x01 ) xset_mask[c] |= (1 << TFT_D0); \
if ( c & 0x02 ) xset_mask[c] |= (1 << TFT_D1); \
if ( c & 0x04 ) xset_mask[c] |= (1 << TFT_D2); \
if ( c & 0x08 ) xset_mask[c] |= (1 << TFT_D3); \
if ( c & 0x10 ) xset_mask[c] |= (1 << TFT_D4); \
if ( c & 0x20 ) xset_mask[c] |= (1 << TFT_D5); \
if ( c & 0x40 ) xset_mask[c] |= (1 << TFT_D6); \
if ( c & 0x80 ) xset_mask[c] |= (1 << TFT_D7); \
} \
// Mask for the 8 data bits to set pin directions
#define dir_mask ((1 << TFT_D0) | (1 << TFT_D1) | (1 << TFT_D2) | (1 << TFT_D3) | (1 << TFT_D4) | (1 << TFT_D5) | (1 << TFT_D6) | (1 << TFT_D7))
// Data bits and the write line are cleared to 0 in one step
#define clr_mask (dir_mask | (1 << TFT_WR))
// 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 = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)(C)); WR_H
// Write 16 bits to TFT
#define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)((C) >> 8)); WR_H; \
GPIO.out_w1tc = 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 = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H
// Write 32 bits to TFT
#define tft_Write_32(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 16)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc = 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 = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 8)); WR_H; \
GPIO.out_w1tc = 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 = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H
// Read pin
#ifdef TFT_RD
#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)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to an ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// 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 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 endianess 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((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
// 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 endianess 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)
#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

View 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 (ILI9488_DRIVER)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** 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
////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,236 @@
//////////////////////////////////////////////////////
// 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 an ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// 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_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
////////////////////////////////////////////////////////////////////////////////////////
// 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

View File

@@ -0,0 +1,259 @@
////////////////////////////////////////////////////
// TFT_eSPI generic driver functions //
////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////////////
// Select the SPI port to use
SPIClass& spi = SPI;
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: tft_Read_8
** Description: Bit bashed SPI to read bidirectional SDA line
***************************************************************************************/
uint8_t TFT_eSPI::tft_Read_8(void)
{
uint8_t ret = 0;
for (uint8_t i = 0; i < 8; i++) { // read results
ret <<= 1;
SCLK_L;
if (digitalRead(TFT_MOSI)) ret |= 1;
SCLK_H;
}
return ret;
}
/***************************************************************************************
** Function name: beginSDA
** Description: Detach SPI from pin to permit software SPI
***************************************************************************************/
void TFT_eSPI::begin_SDA_Read(void)
{
// Release configured SPI port for SDA read
spi.end();
}
/***************************************************************************************
** Function name: endSDA
** Description: Attach SPI pins after software SPI
***************************************************************************************/
void TFT_eSPI::end_SDA_Read(void)
{
// Configure SPI port ready for next TFT access
spi.begin();
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // #if defined (TFT_SDA_READ)
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT) // Code for generic (i.e. any) processor
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for generic processor and parallel display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
while (len>1) {tft_Write_32D(color); len-=2;}
if (len) {tft_Write_16(color);}
}
/***************************************************************************************
** Function name: pushPixels - for gereric processor and parallel display
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;}
if (len) {tft_Write_16(*data);}
return;
}
while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;}
if (len) {tft_Write_16S(*data);}
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set parallel bus to INPUT or OUTPUT
***************************************************************************************/
void TFT_eSPI::busDir(uint32_t mask, uint8_t mode)
{
// mask is unused for generic processor
// Arduino native functions suited well to a generic driver
pinMode(TFT_D0, mode);
pinMode(TFT_D1, mode);
pinMode(TFT_D2, mode);
pinMode(TFT_D3, mode);
pinMode(TFT_D4, mode);
pinMode(TFT_D5, mode);
pinMode(TFT_D6, mode);
pinMode(TFT_D7, mode);
return;
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Faster GPIO pin input/output switch
***************************************************************************************/
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
{
// No fast port based generic approach available
}
/***************************************************************************************
** Function name: read byte - supports class functions
** Description: Read a byte - parallel bus only
***************************************************************************************/
uint8_t TFT_eSPI::readByte(void)
{
uint8_t b = 0;
busDir(0, INPUT);
digitalWrite(TFT_RD, LOW);
b |= digitalRead(TFT_D0) << 0;
b |= digitalRead(TFT_D1) << 1;
b |= digitalRead(TFT_D2) << 2;
b |= digitalRead(TFT_D3) << 3;
b |= digitalRead(TFT_D4) << 4;
b |= digitalRead(TFT_D5) << 5;
b |= digitalRead(TFT_D6) << 6;
b |= digitalRead(TFT_D7) << 7;
digitalWrite(TFT_RD, HIGH);
busDir(0, OUTPUT);
return b;
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 or 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 (ILI9488_DRIVER) // For 24 bit SPI colour TFT
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** 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)
*/

View File

@@ -0,0 +1,158 @@
////////////////////////////////////////////////////
// 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
////////////////////////////////////////////////////////////////////////////////////////
// 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 an ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// 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(0); spi.transfer(C)
#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
#endif // RPI_DISPLAY_TYPE
#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
////////////////////////////////////////////////////////////////////////////////////////
// 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

View File

@@ -0,0 +1,609 @@
////////////////////////////////////////////////////
// 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 dramtically graphics test 0.634s => 0.374s
while (len>31) {
// 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);
len-=32;
}
while (len>7) {
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
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)
{
#ifdef 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 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
#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;
#ifdef STM_PORTA_DATA_BUS
b = GPIOA->IDR;
b = GPIOA->IDR;
b = GPIOA->IDR;
b = (GPIOA->IDR) & 0xFF;
#elif STM_PORTB_DATA_BUS
b = GPIOB->IDR;
b = GPIOB->IDR;
b = GPIOB->IDR;
b = (GPIOB->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 (ILI9488_DRIVER) // For 24 bit colour TFT ############# UNTESTED ###################
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** 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());" in sketch for a blocking wait for DMA to complete
// or "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: pushImageDMA
** 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 >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
if (buffer == nullptr) buffer = image;
uint32_t len = dw*dh;
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)
#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(void)
{
#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 DMA2 clock
dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI2 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(void)
{
__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
////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,970 @@
////////////////////////////////////////////////////
// TFT_eSPI driver functions for STM32 processors //
////////////////////////////////////////////////////
#ifndef _TFT_eSPI_STM32H_
#define _TFT_eSPI_STM32H_
// Processor ID reported by getSetup()
#define PROCESSOR_ID 0x32F
// Include processor specific header
// None
// RPi support not tested - Fast RPi not supported
// 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
// SUPPORT_TRANSACTIONS is mandatory for STM32
#if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the parallel bus interface chip pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined(TFT_PARALLEL_8_BIT)
// The STM32 processors can toggle pins fast, TFTs need setup and hold times
// for writes so here twc can be extended with delays:
//
// 0 1 2 3 4 5 Extra high periods
// TFT_WR ¯|_ _ _ _ _ _ |¯ ¯ ¯ ¯ ¯ ¯ ¯|
// 5 4 3 2 1 0 Extra low periods
// xxxx=======================xxxx
// |<---------- twc --------->|
// |<- tdst ->|<-- tdht -->|
//
// Data is placed bit by bit on bus during period xxxx and TFT_WR driven low
// Period xxxx depends on D0-D7 pin allocations and bit manipulation needed
// Data stable during period ===
// Most TFTs can be "overclocked" and run >2x faster than data sheet figures
////////////////////////////////////////////////////////////////////////////////////////
// Write strobe timing setup
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ILI9341_DRIVER) || defined (ST7796_DRIVER) || defined (ILI9486_DRIVER) // WRX twc spec is <=66ns = 15.15MHz
// Extra write pulse low time (delay for data setup)
#if defined (STM32F1xx)
#define WR_TWRL_0 // Change to WR_TWRL_1 if overclocking processor
#elif defined (STM32F2xx) || defined (STM32F4xx)
#define WR_TWRL_0 // Tested with STM32F446 - 27.6MHz when WR_TWRH_1 defined
//#define WR_TWRL_3 // STM32F446 - 15.6MHz when WR_TWRH_3 defined
#elif defined (STM32F7xx)
#define WR_TWRL_1 //Tested with STM32F767
#else
#define WR_TWRL_5
#endif
// Extra write pulse high time (data hold time, delays next write cycle start)
#if defined (STM32F1xx)
#define WR_TWRH_0
#elif defined (STM32F2xx) || defined (STM32F4xx)
#define WR_TWRH_0 // Tested with STM32F446
//#define WR_TWRL_3
#elif defined (STM32F7xx)
#define WR_TWRH_1 //Tested with STM32F767
#else
#define WR_TWRH_5
#endif
#elif defined (ILI9481_DRIVER) // WRX twc spec is 100ns = 10MHz
// Extra write pulse low time (delay for data setup)
#if defined (STM32F1xx)
#define WR_TWRL_0
#elif defined (STM32F2xx) || defined (STM32F4xx)
//#define WR_TWRL_0 // STM32F446 - ~30MHz when WR_TWRH_0 defined
//#define WR_TWRL_1 // STM32F446 - ~25MHz when WR_TWRH_0 defined
#define WR_TWRL_2 // STM32F446 - ~20MHz when WR_TWRH_2 defined
//#define WR_TWRL_3 // STM32F446 - ~16MHz when WR_TWRH_3 defined
//#define WR_TWRL_4
//#define WR_TWRL_5 // STM32F446 - ~12MHz when WR_TWRH_5 defined
#elif defined (STM32F7xx)
//#define WR_TWRL_0
//#define WR_TWRL_1
//#define WR_TWRL_2
#define WR_TWRL_3
#else
//#define WR_TWRH_0 // Fastest
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3 // Slowest
#endif
// Extra write pulse high time (data hold time, delays next write cycle start)
#if defined (STM32F1xx)
#define WR_TWRH_0
#elif defined (STM32F2xx) || defined (STM32F4xx)
//#define WR_TWRH_0
//#define WR_TWRH_1
#define WR_TWRH_2
//#define WR_TWRH_3
#elif defined (STM32F7xx)
//#define WR_TWRH_0
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3
//#define WR_TWRH_4
//#define WR_TWRH_5
#else
//#define WR_TWRH_0 // Fastest
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3 // Slowest
#endif
#else // Default display slow settings
#if defined (STM32F1xx)
// STM32F1xx series can run at full speed (unless overclocked)
#define WR_TWRL_0
#define WR_TWRH_0
#else
// Extra write pulse low time (delay for data setup)
//#define WR_TWRL_0
//#define WR_TWRL_1
//#define WR_TWRL_2
#define WR_TWRL_3
//#define WR_TWRL_4
//#define WR_TWRL_5
// Extra write pulse high time (data hold time, delays next write cycle start)
//#define WR_TWRH_0
//#define WR_TWRH_1
//#define WR_TWRH_2
//#define WR_TWRH_3
//#define WR_TWRH_4
#define WR_TWRH_5
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
////////////////////////////////////////////////////////////////////////////////////////
#else
// Use SPI1 as default if not defined
#ifndef TFT_SPI_PORT
#define TFT_SPI_PORT 1
#endif
// Global define is _VARIANT_ARDUINO_STM32_, see board package stm32_def.h for specific variants
#if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx)
#define STM32_DMA // DMA is available with these processors
#if (TFT_SPI_PORT == 1)
// Initialise processor specific SPI and DMA instances - used by init()
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \
dmaHal.Instance = DMA2_Stream3
// The DMA hard-coding for SPI1 is in TFT_eSPI_STM32.c as follows:
// DMA_CHANNEL_3
// DMA2_Stream3_IRQn and DMA2_Stream3_IRQHandler()
#elif (TFT_SPI_PORT == 2)
// Initialise processor specific SPI and DMA instances - used by init()
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI2; \
dmaHal.Instance = DMA1_Stream4
// The DMA hard-coding for SPI2 is in TFT_eSPI_STM32.c as follows:
// DMA_CHANNEL_4
// DMA1_Stream4_IRQn and DMA1_Stream4_IRQHandler()
#endif
#elif defined (STM32F1xx)
// For Blue Pill and STM32F1xx processors with DMA support
#define STM32_DMA // DMA is available with these processors
#if (TFT_SPI_PORT == 1)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \
dmaHal.Instance = DMA1_Channel3
#elif (TFT_SPI_PORT == 2)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI2; \
dmaHal.Instance = DMA1_Channel5
#endif
#else
// For STM32 processor with no implemented DMA support (yet)
#if (TFT_SPI_PORT == 1)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1
#elif (TFT_SPI_PORT == 2)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI2
#endif
#endif
#endif
#ifdef STM32_DMA
// Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions
#define DMA_BUSY_CHECK { if (DMA_Enabled) while(dmaBusy()); }
#else
#define DMA_BUSY_CHECK
#endif
// 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 <<<==== TODO
//#define FS_NO_GLOBALS
//#include <FS.h>
#endif // end of parallel/SPI selection
////////////////////////////////////////////////////////////////////////////////////////
// Define the DC (TFT Data/Command or Register Select (RS))pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_DC) || (TFT_DC < 0)
#define DC_C // No macro allocated so it generates no code
#define DC_D // No macro allocated so it generates no code
#undef TFT_DC
#else
// Convert Arduino pin reference Dn or STM pin reference PXn to port and mask
#define DC_PORT digitalPinToPort(TFT_DC)
#define DC_PIN_MASK digitalPinToBitMask(TFT_DC)
// Use bit set reset register
#define DC_C DC_PORT->BSRR = DC_PIN_MASK<<16
#define DC_D DC_PORT->BSRR = DC_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the CS (TFT chip select) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_CS) || (TFT_CS < 0)
#define CS_L // No macro allocated so it generates no code
#define CS_H // No macro allocated so it generates no code
#undef TFT_CS
#else
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
#define CS_PORT digitalPinToPort(TFT_CS)
#define CS_PIN_MASK digitalPinToBitMask(TFT_CS)
// Use bit set reset register
#define CS_L CS_PORT->BSRR = CS_PIN_MASK<<16
#define CS_H CS_PORT->BSRR = CS_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the RD (TFT Read) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_RD
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
#define RD_PORT digitalPinToPort(TFT_RD)
#define RD_PIN_MASK digitalPinToBitMask(TFT_RD)
// Use bit set reset register
#define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16
#define RD_H RD_PORT->BSRR = RD_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the WR (TFT Write) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_WR
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
#define WR_PORT digitalPinToPort(TFT_WR)
#define WR_PIN_MASK digitalPinToBitMask(TFT_WR)
// Use bit set reset register
#define WR_L WR_PORT->BSRR = WR_PIN_MASK<<16
#define WR_H WR_PORT->BSRR = WR_PIN_MASK
#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
// Speed is not important for this signal
#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
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_PARALLEL_8_BIT)
#ifndef TFT_MISO
#define TFT_MISO -1
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the parallel bus interface chip pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT)
// Mask for the 8 data bits to set pin directions (not used)
#define dir_mask 0
#define CONSTRUCTOR_INIT_TFT_DATA_BUS // None
#define INIT_TFT_DATA_BUS // Setup built into TFT_eSPI.cpp
////////////////////////////////////////////////////////////////////////////////////////
// Define the TFT_WR drive cycle timing
////////////////////////////////////////////////////////////////////////////////////////
// Write low extra setup time
#if defined WR_TWRL_0
#define WR_TWRL
#elif defined WR_TWRL_1 // 1 extra low period
#define WR_TWRL WR_L
#elif defined WR_TWRL_2 // 2 extra low periods
#define WR_TWRL WR_L; WR_L
#elif defined WR_TWRL_3 // 3 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L
#elif defined WR_TWRL_4 // 4 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L; WR_L
#elif defined WR_TWRL_5 // 5 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L; WR_L; WR_L
#endif
// Write high extra hold time
#if defined WR_TWRH_0
#define WR_TWRH WR_H
#elif defined WR_TWRH_1 // 1 extra high period
#define WR_TWRH WR_H; WR_H
#elif defined WR_TWRH_2 // 2 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H
#elif defined WR_TWRH_3 // 3 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H
#elif defined WR_TWRH_4 // 4 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H; WR_H
#elif defined WR_TWRH_5 // 5 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H; WR_H; WR_H
#endif
#define WR_STB WR_TWRL; WR_TWRH // Rising edge write strobe
////////////////////////////////////////////////////////////////////////////////////////
// Nucleo 64: hard-coded pins
////////////////////////////////////////////////////////////////////////////////////////
#ifdef NUCLEO_64_TFT
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
#define D0_PIN_NAME digitalPinToPinName(TFT_D0)
#define D1_PIN_NAME digitalPinToPinName(TFT_D1)
#define D2_PIN_NAME digitalPinToPinName(TFT_D2)
#define D3_PIN_NAME digitalPinToPinName(TFT_D3)
#define D4_PIN_NAME digitalPinToPinName(TFT_D4)
#define D5_PIN_NAME digitalPinToPinName(TFT_D5)
#define D6_PIN_NAME digitalPinToPinName(TFT_D6)
#define D7_PIN_NAME digitalPinToPinName(TFT_D7)
// Pin port bit number 0-15 (not used for Nucleo)
#define D0_PIN_BIT (D0_PIN_NAME & 0xF)
#define D1_PIN_BIT (D1_PIN_NAME & 0xF)
#define D2_PIN_BIT (D2_PIN_NAME & 0xF)
#define D3_PIN_BIT (D3_PIN_NAME & 0xF)
#define D4_PIN_BIT (D4_PIN_NAME & 0xF)
#define D5_PIN_BIT (D5_PIN_NAME & 0xF)
#define D6_PIN_BIT (D6_PIN_NAME & 0xF)
#define D7_PIN_BIT (D7_PIN_NAME & 0xF)
// Pin port - better than get_GPIO_Port() which seems to be slow...
#define D0_PIN_PORT GPIOA
#define D1_PIN_PORT GPIOC
#define D2_PIN_PORT GPIOA
#define D3_PIN_PORT GPIOB
#define D4_PIN_PORT GPIOB
#define D5_PIN_PORT GPIOB
#define D6_PIN_PORT GPIOB
#define D7_PIN_PORT GPIOA
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<< 9) // Set/clear mask for PA9
#define D1_PIN_MASK (1UL<< 7) // Set/clear mask for PC7
#define D2_PIN_MASK (1UL<<10) // Set/clear mask for PA10
#define D3_PIN_MASK (1UL<< 3) // Set/clear mask for PB3
#define D4_PIN_MASK (1UL<< 5) // Set/clear mask for PB5
#define D5_PIN_MASK (1UL<< 4) // Set/clear mask for PB4
#define D6_PIN_MASK (1UL<<10) // Set/clear mask for PB10
#define D7_PIN_MASK (1UL<< 8) // Set/clear mask for PA8
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB // Need to slow down strobe
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOA->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D9_BSR_MASK(C); \
GPIOB->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB; \
GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB // Need to slow down strobe
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOA->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D9_BSR_MASK(C); \
GPIOB->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 (((GPIOA->IDR)&(D0_PIN_MASK))>>( 9-0)) // Read pin PA9
#define RD_TFT_D1 (((GPIOC->IDR)&(D1_PIN_MASK))>>( 7-1)) // Read pin PC7
#define RD_TFT_D2 (((GPIOA->IDR)&(D2_PIN_MASK))>>(10-2)) // Read pin PA10
#define RD_TFT_D3 (((GPIOB->IDR)&(D3_PIN_MASK))>>( 3-3)) // Read pin PB3
#define RD_TFT_D4 (((GPIOB->IDR)&(D4_PIN_MASK))>>( 5-4)) // Read pin PB5
#define RD_TFT_D5 (((GPIOB->IDR)&(D5_PIN_MASK))<<(-4+5)) // Read pin PB4
#define RD_TFT_D6 (((GPIOB->IDR)&(D6_PIN_MASK))>>(10-6)) // Read pin PB10
#define RD_TFT_D7 (((GPIOA->IDR)&(D7_PIN_MASK))>>( 8-7)) // Read pin PA8
////////////////////////////////////////////////////////////////////////////////////////
// Nucleo 144: hard-coded pins
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (NUCLEO_144_TFT)
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
// (diagnostic only - not used for Nucleo)
#define D0_PIN_NAME digitalPinToPinName(TFT_D0)
#define D1_PIN_NAME digitalPinToPinName(TFT_D1)
#define D2_PIN_NAME digitalPinToPinName(TFT_D2)
#define D3_PIN_NAME digitalPinToPinName(TFT_D3)
#define D4_PIN_NAME digitalPinToPinName(TFT_D4)
#define D5_PIN_NAME digitalPinToPinName(TFT_D5)
#define D6_PIN_NAME digitalPinToPinName(TFT_D6)
#define D7_PIN_NAME digitalPinToPinName(TFT_D7)
// Pin port bit number 0-15 (diagnostic only - not used for Nucleo)
#define D0_PIN_BIT (D0_PIN_NAME & 0xF)
#define D1_PIN_BIT (D1_PIN_NAME & 0xF)
#define D2_PIN_BIT (D2_PIN_NAME & 0xF)
#define D3_PIN_BIT (D3_PIN_NAME & 0xF)
#define D4_PIN_BIT (D4_PIN_NAME & 0xF)
#define D5_PIN_BIT (D5_PIN_NAME & 0xF)
#define D6_PIN_BIT (D6_PIN_NAME & 0xF)
#define D7_PIN_BIT (D7_PIN_NAME & 0xF)
#if !defined (STM32H7xx)
// Ports associated with pins - get_GPIO_Port() seems to be slow...
#define D0_PIN_PORT GPIOF
#define D1_PIN_PORT GPIOD
#define D2_PIN_PORT GPIOF
#define D3_PIN_PORT GPIOE
#define D4_PIN_PORT GPIOF
#define D5_PIN_PORT GPIOE
#define D6_PIN_PORT GPIOE
#define D7_PIN_PORT GPIOF
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<<12) // Set/clear mask for PF12 PF3
#define D1_PIN_MASK (1UL<<15) // Set/clear mask for PD15
#define D2_PIN_MASK (1UL<<15) // Set/clear mask for PF15 PG14
#define D3_PIN_MASK (1UL<<13) // Set/clear mask for PE13
#define D4_PIN_MASK (1UL<<14) // Set/clear mask for PF14
#define D5_PIN_MASK (1UL<<11) // Set/clear mask for PE11
#define D6_PIN_MASK (1UL<< 9) // Set/clear mask for PE9
#define D7_PIN_MASK (1UL<<13) // Set/clear mask for PF13 PG12
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOF->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D12_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB;\
GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOF->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D12_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 (((GPIOF->IDR)&(D0_PIN_MASK))>>(12-0)) // Read pin PF12
#define RD_TFT_D1 (((GPIOD->IDR)&(D1_PIN_MASK))>>(15-1)) // Read pin PD15
#define RD_TFT_D2 (((GPIOF->IDR)&(D2_PIN_MASK))>>(15-2)) // Read pin PF15
#define RD_TFT_D3 (((GPIOE->IDR)&(D3_PIN_MASK))>>(13-3)) // Read pin PE13
#define RD_TFT_D4 (((GPIOF->IDR)&(D4_PIN_MASK))>>(14-4)) // Read pin PF14
#define RD_TFT_D5 (((GPIOE->IDR)&(D5_PIN_MASK))>>(11-5)) // Read pin PE11
#define RD_TFT_D6 (((GPIOE->IDR)&(D6_PIN_MASK))>>( 9-6)) // Read pin PE9
#define RD_TFT_D7 (((GPIOF->IDR)&(D7_PIN_MASK))>>(13-7)) // Read pin PF13
#else
// Test setup for STM32H743 - starts to run, slow and then crashes! Board support bug?
// Ports associated with pins - get_GPIO_Port() seems to be slow...
#define D0_PIN_PORT GPIOF
#define D1_PIN_PORT GPIOD
#define D2_PIN_PORT GPIOG
#define D3_PIN_PORT GPIOE
#define D4_PIN_PORT GPIOE
#define D5_PIN_PORT GPIOE
#define D6_PIN_PORT GPIOE
#define D7_PIN_PORT GPIOG
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<< 3) // Set/clear mask for PF3
#define D1_PIN_MASK (1UL<<15) // Set/clear mask for PD15
#define D2_PIN_MASK (1UL<<14) // Set/clear mask for PG14
#define D3_PIN_MASK (1UL<<13) // Set/clear mask for PE13
#define D4_PIN_MASK (1UL<<14) // Set/clear mask for PE14
#define D5_PIN_MASK (1UL<<11) // Set/clear mask for PE11
#define D6_PIN_MASK (1UL<< 9) // Set/clear mask for PE9
#define D7_PIN_MASK (1UL<<12) // Set/clear mask for PG12
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOF->BSRR = D8_BSR_MASK(C); \
GPIOG->BSRR = D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB;\
GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOF->BSRR = D8_BSR_MASK(C); \
GPIOG->BSRR = D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 (((GPIOF->IDR)&(D0_PIN_MASK))>>( 3-0)) // Read pin PF3
#define RD_TFT_D1 (((GPIOD->IDR)&(D1_PIN_MASK))>>(15-1)) // Read pin PD15
#define RD_TFT_D2 (((GPIOG->IDR)&(D2_PIN_MASK))>>(14-2)) // Read pin PG14
#define RD_TFT_D3 (((GPIOE->IDR)&(D3_PIN_MASK))>>(13-3)) // Read pin PE13
#define RD_TFT_D4 (((GPIOE->IDR)&(D4_PIN_MASK))>>(14-4)) // Read pin PE14
#define RD_TFT_D5 (((GPIOE->IDR)&(D5_PIN_MASK))>>(11-5)) // Read pin PE11
#define RD_TFT_D6 (((GPIOE->IDR)&(D6_PIN_MASK))>>( 9-6)) // Read pin PE9
#define RD_TFT_D7 (((GPIOG->IDR)&(D7_PIN_MASK))>>(12-7)) // Read pin PG12
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Support for other STM32 boards (not optimised!)
////////////////////////////////////////////////////////////////////////////////////////
#else
#if defined (STM_PORTA_DATA_BUS)
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C)); WR_L; WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB; \
GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB; \
GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 ((GPIOA->IDR) & 0x01) // Read pin TFT_D0
#define RD_TFT_D1 ((GPIOA->IDR) & 0x02) // Read pin TFT_D1
#define RD_TFT_D2 ((GPIOA->IDR) & 0x04) // Read pin TFT_D2
#define RD_TFT_D3 ((GPIOA->IDR) & 0x08) // Read pin TFT_D3
#define RD_TFT_D4 ((GPIOA->IDR) & 0x10) // Read pin TFT_D4
#define RD_TFT_D5 ((GPIOA->IDR) & 0x20) // Read pin TFT_D5
#define RD_TFT_D6 ((GPIOA->IDR) & 0x40) // Read pin TFT_D6
#define RD_TFT_D7 ((GPIOA->IDR) & 0x80) // Read pin TFT_D7
#elif defined (STM_PORTB_DATA_BUS)
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C)); WR_L; WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB; \
GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB; \
GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 ((GPIOB->IDR) & 0x80) // Read pin TFT_D0
#define RD_TFT_D1 ((GPIOB->IDR) & 0x40) // Read pin TFT_D1
#define RD_TFT_D2 ((GPIOB->IDR) & 0x20) // Read pin TFT_D2
#define RD_TFT_D3 ((GPIOB->IDR) & 0x10) // Read pin TFT_D3
#define RD_TFT_D4 ((GPIOB->IDR) & 0x08) // Read pin TFT_D4
#define RD_TFT_D5 ((GPIOB->IDR) & 0x04) // Read pin TFT_D5
#define RD_TFT_D6 ((GPIOB->IDR) & 0x02) // Read pin TFT_D6
#define RD_TFT_D7 ((GPIOB->IDR) & 0x01) // Read pin TFT_D7
#else
// This will work with any STM32 to parallel TFT pin mapping but will be slower
// Convert Arduino pin reference Dx or STM pin reference PXn to port and mask
#define D0_PIN_NAME digitalPinToPinName(TFT_D0)
#define D1_PIN_NAME digitalPinToPinName(TFT_D1)
#define D2_PIN_NAME digitalPinToPinName(TFT_D2)
#define D3_PIN_NAME digitalPinToPinName(TFT_D3)
#define D4_PIN_NAME digitalPinToPinName(TFT_D4)
#define D5_PIN_NAME digitalPinToPinName(TFT_D5)
#define D6_PIN_NAME digitalPinToPinName(TFT_D6)
#define D7_PIN_NAME digitalPinToPinName(TFT_D7)
// Pin port bit number 0-15
#define D0_PIN_BIT (D0_PIN_NAME & 0xF)
#define D1_PIN_BIT (D1_PIN_NAME & 0xF)
#define D2_PIN_BIT (D2_PIN_NAME & 0xF)
#define D3_PIN_BIT (D3_PIN_NAME & 0xF)
#define D4_PIN_BIT (D4_PIN_NAME & 0xF)
#define D5_PIN_BIT (D5_PIN_NAME & 0xF)
#define D6_PIN_BIT (D6_PIN_NAME & 0xF)
#define D7_PIN_BIT (D7_PIN_NAME & 0xF)
// Pin port
#define D0_PIN_PORT digitalPinToPort(TFT_D0)
#define D1_PIN_PORT digitalPinToPort(TFT_D1)
#define D2_PIN_PORT digitalPinToPort(TFT_D2)
#define D3_PIN_PORT digitalPinToPort(TFT_D3)
#define D4_PIN_PORT digitalPinToPort(TFT_D4)
#define D5_PIN_PORT digitalPinToPort(TFT_D5)
#define D6_PIN_PORT digitalPinToPort(TFT_D6)
#define D7_PIN_PORT digitalPinToPort(TFT_D7)
// Pin masks for set/clear
#define D0_PIN_MASK digitalPinToBitMask(TFT_D0)
#define D1_PIN_MASK digitalPinToBitMask(TFT_D1)
#define D2_PIN_MASK digitalPinToBitMask(TFT_D2)
#define D3_PIN_MASK digitalPinToBitMask(TFT_D3)
#define D4_PIN_MASK digitalPinToBitMask(TFT_D4)
#define D5_PIN_MASK digitalPinToBitMask(TFT_D5)
#define D6_PIN_MASK digitalPinToBitMask(TFT_D6)
#define D7_PIN_MASK digitalPinToBitMask(TFT_D7)
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) D0_PIN_PORT->BSRR = D0_BSR_MASK(C); \
D1_PIN_PORT->BSRR = D1_BSR_MASK(C); \
D2_PIN_PORT->BSRR = D2_BSR_MASK(C); \
D3_PIN_PORT->BSRR = D3_BSR_MASK(C); \
WR_L; \
D4_PIN_PORT->BSRR = D4_BSR_MASK(C); \
D5_PIN_PORT->BSRR = D5_BSR_MASK(C); \
D6_PIN_PORT->BSRR = D6_BSR_MASK(C); \
D7_PIN_PORT->BSRR = D7_BSR_MASK(C); \
WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) D0_PIN_PORT->BSRR = D8_BSR_MASK(C); \
D1_PIN_PORT->BSRR = D9_BSR_MASK(C); \
D2_PIN_PORT->BSRR = D10_BSR_MASK(C); \
D3_PIN_PORT->BSRR = D11_BSR_MASK(C); \
WR_L; \
D4_PIN_PORT->BSRR = D12_BSR_MASK(C); \
D5_PIN_PORT->BSRR = D13_BSR_MASK(C); \
D6_PIN_PORT->BSRR = D14_BSR_MASK(C); \
D7_PIN_PORT->BSRR = D15_BSR_MASK(C); \
WR_STB;\
D0_PIN_PORT->BSRR = D0_BSR_MASK(C); \
D1_PIN_PORT->BSRR = D1_BSR_MASK(C); \
D2_PIN_PORT->BSRR = D2_BSR_MASK(C); \
D3_PIN_PORT->BSRR = D3_BSR_MASK(C); \
WR_L; \
D4_PIN_PORT->BSRR = D4_BSR_MASK(C); \
D5_PIN_PORT->BSRR = D5_BSR_MASK(C); \
D6_PIN_PORT->BSRR = D6_BSR_MASK(C); \
D7_PIN_PORT->BSRR = D7_BSR_MASK(C); \
WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) D0_PIN_PORT->BSRR = D0_BSR_MASK(C); \
D1_PIN_PORT->BSRR = D1_BSR_MASK(C); \
D2_PIN_PORT->BSRR = D2_BSR_MASK(C); \
D3_PIN_PORT->BSRR = D3_BSR_MASK(C); \
WR_L; \
D4_PIN_PORT->BSRR = D4_BSR_MASK(C); \
D5_PIN_PORT->BSRR = D5_BSR_MASK(C); \
D6_PIN_PORT->BSRR = D6_BSR_MASK(C); \
D7_PIN_PORT->BSRR = D7_BSR_MASK(C); \
WR_STB; \
D0_PIN_PORT->BSRR = D8_BSR_MASK(C); \
D1_PIN_PORT->BSRR = D9_BSR_MASK(C); \
D2_PIN_PORT->BSRR = D10_BSR_MASK(C); \
D3_PIN_PORT->BSRR = D11_BSR_MASK(C); \
WR_L; \
D4_PIN_PORT->BSRR = D12_BSR_MASK(C); \
D5_PIN_PORT->BSRR = D13_BSR_MASK(C); \
D6_PIN_PORT->BSRR = D14_BSR_MASK(C); \
D7_PIN_PORT->BSRR = D15_BSR_MASK(C); \
WR_STB
#define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C))
#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))
// Read a data bit
#define RD_TFT_D0 ((((D0_PIN_PORT->IDR) >> (D0_PIN_BIT))&1)<<0) // Read pin TFT_D0
#define RD_TFT_D1 ((((D1_PIN_PORT->IDR) >> (D1_PIN_BIT))&1)<<1) // Read pin TFT_D1
#define RD_TFT_D2 ((((D2_PIN_PORT->IDR) >> (D2_PIN_BIT))&1)<<2) // Read pin TFT_D2
#define RD_TFT_D3 ((((D3_PIN_PORT->IDR) >> (D3_PIN_BIT))&1)<<3) // Read pin TFT_D3
#define RD_TFT_D4 ((((D4_PIN_PORT->IDR) >> (D4_PIN_BIT))&1)<<4) // Read pin TFT_D4
#define RD_TFT_D5 ((((D5_PIN_PORT->IDR) >> (D5_PIN_BIT))&1)<<5) // Read pin TFT_D5
#define RD_TFT_D6 ((((D6_PIN_PORT->IDR) >> (D6_PIN_BIT))&1)<<6) // Read pin TFT_D6
#define RD_TFT_D7 ((((D7_PIN_PORT->IDR) >> (D7_PIN_BIT))&1)<<7) // Read pin TFT_D7
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to a SPI ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// Write 8 bits to TFT
#define tft_Write_8(C) \
{ spiBuffer[0] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 1, 10); }
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16(C) \
{ spiBuffer[0] = ((C) & 0xF800)>>8; spiBuffer[1] = ((C) & 0x07E0)>>3; spiBuffer[2] = ((C) & 0x001F)<<3; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, 10); }
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) \
{ spiBuffer[0] = (C) & 0xF8; spiBuffer[1] = ((C) & 0xE000)>>11 | ((C) & 0x07)<<5; spiBuffer[2] = ((C) & 0x1F00)>>5; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, 10); }
// Write 32 bits to TFT
#define tft_Write_32(C) \
{ spiBuffer[0] = (C)>>24; spiBuffer[1] = (C)>>16; spiBuffer[2] = (C)>>8; spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
// Write two address coordinates
#define tft_Write_32C(C,D) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; spiBuffer[2] = (D)>>8; spiBuffer[3] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
// Write same value twice
#define tft_Write_32D(C) \
{ spiBuffer[0] = spiBuffer[2] = (C)>>8; spiBuffer[1] = spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to a SPI Raspberry Pi TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_DISPLAY_TYPE)
#define tft_Write_8(C) \
{ spiBuffer[0] = 0; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_32(C) \
{ spiBuffer[1] = ((C)>>24); spiBuffer[3] = ((C)>>16); spiBuffer[5] = ((C)>>8); spiBuffer[7] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
#define tft_Write_32C(C,D) \
{ spiBuffer[1] = ((C)>>8); spiBuffer[3] = (C); spiBuffer[5] = ((D)>>8); spiBuffer[7] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
#define tft_Write_32D(C) \
{ spiBuffer[1] = ((C)>>8); spiBuffer[3] = (C); spiBuffer[5] = ((C)>>8); spiBuffer[7] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
////////////////////////////////////////////////////////////////////////////////////////
#else
#if defined(ST7789_DRIVER) || defined(ST7789_2_DRIVER)
// Temporary workaround for issue #510 part 2
#define tft_Write_8(C) spi.transfer(C)
#else
#define tft_Write_8(C) \
{ spiBuffer[0] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 1, 10); delayMicroseconds(1);}
#endif
#define tft_Write_16(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_32(C) \
{ spiBuffer[0] = (C)>>24; spiBuffer[1] = (C)>>16; spiBuffer[2] = (C)>>8; spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#define tft_Write_32C(C,D) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; spiBuffer[2] = (D)>>8; spiBuffer[3] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#define tft_Write_32D(C) \
{ spiBuffer[0] = spiBuffer[2] = (C)>>8; spiBuffer[1] = spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to read from display using SPI or software SPI
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ)
// Macros to support a bit banged function call for STM32 and bi-directional SDA pin
#define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8();
#define SCLK_L digitalWrite(TFT_SCLK, LOW)
#define SCLK_H digitalWrite(TFT_SCLK, HIGH)
#elif !defined (TFT_PARALLEL_8_BIT)
// Use a SPI read transfer
#define tft_Read_8() spi.transfer(0)
#endif
#endif // Header end