Refactor, add new anti-alaiased functions

Beta test
Minor performance improvements
Improved image rendering speed for SPI 18 bit interface TFTs (e.g. ILI9488)
TODO
1. Add AA circle fns to TFT_eSPI
2. Update keywords
3. Add new examples for ESP/STM processors
This commit is contained in:
Bodmer 2021-01-30 02:23:54 +00:00
parent 9a1a53edc2
commit 2f6177ed4b
12 changed files with 1743 additions and 1212 deletions

View File

@ -16,7 +16,7 @@
***************************************************************************************/ ***************************************************************************************/
// The touch controller has a low SPI clock rate // The touch controller has a low SPI clock rate
inline void TFT_eSPI::begin_touch_read_write(void){ inline void TFT_eSPI::begin_touch_read_write(void){
DMA_BUSY_CHECK; DMA_BUSY_CHECK; // Wait for any DMA transfer to complete before changing SPI settings
CS_H; // Just in case it has been left low CS_H; // Just in case it has been left low
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
@ -38,7 +38,6 @@ inline void TFT_eSPI::end_touch_read_write(void){
#else #else
spi.setFrequency(SPI_FREQUENCY); spi.setFrequency(SPI_FREQUENCY);
#endif #endif
//SET_BUS_WRITE_MODE;
} }
/*************************************************************************************** /***************************************************************************************

View File

@ -27,12 +27,14 @@
#endif #endif
#if !defined (TFT_PARALLEL_8_BIT) #if !defined (TFT_PARALLEL_8_BIT)
// Volatile for register reads: // Write only SPI Tx/Rx register
volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); volatile uint32_t *const _spi_w = (uint32_t*)(SPI_W0_REG(SPI_PORT));
volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); // Write only SPI interface control register
// Register writes only: volatile uint32_t *const _spi_user = (uint32_t*)(SPI_USER_REG(SPI_PORT));
volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); // Bit length to transmit N bits (512 max), load with N-1
volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); volatile uint32_t *const _spi_mosi_dlen = (uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT));
// Read/write reister to initiate SPI transfer and check when completed
volatile uint32_t *const _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT));
#endif #endif
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -187,54 +189,41 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
#elif !defined (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI displays #elif !defined (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI displays
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
/*************************************************************************************** /***************************************************************************************
** Function name: pushBlock - for ESP32 ** Function name: pushBlock - for ESP32
** Description: Write a block of pixels of the same colour ** Description: Write a block of pixels of the same colour
***************************************************************************************/ ***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); volatile uint32_t* spi_w = _spi_w;
bool empty = true; uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8);
volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; uint32_t i = 0;
if (len > 31) uint32_t rem = len & 0x1F;
len = len - rem;
if (rem)
{ {
*_spi_mosi_dlen = 511; while (*_spi_cmd&SPI_USR);
spi_w[0] = color32; for (i=0; i < rem; i+=2) *spi_w++ = color32;
spi_w[1] = color32; *_spi_mosi_dlen = (rem << 4) - 1;
spi_w[2] = color32; *_spi_cmd = SPI_USR;
spi_w[3] = color32; if (!len) return;
spi_w[4] = color32; i = i>>1; while(i++<16) *spi_w++ = color32;
spi_w[5] = color32;
spi_w[6] = color32;
spi_w[7] = color32;
spi_w[8] = color32;
spi_w[9] = color32;
spi_w[10] = color32;
spi_w[11] = color32;
spi_w[12] = color32;
spi_w[13] = color32;
spi_w[14] = color32;
spi_w[15] = color32;
while(len>31)
{
while ((*_spi_cmd)&SPI_USR);
*_spi_cmd = SPI_USR;
len -= 32;
}
empty = false;
} }
if (len) while (*_spi_cmd&SPI_USR);
if (!rem) while (i++<16) *spi_w++ = color32;
*_spi_mosi_dlen = 511;
while(len)
{ {
if(empty) {
for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32;
}
len = (len << 4) - 1;
while (*_spi_cmd&SPI_USR); while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = len;
*_spi_cmd = SPI_USR; *_spi_cmd = SPI_USR;
len -= 32;
} }
while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully?
//while (*_spi_cmd&SPI_USR);
} }
/*************************************************************************************** /***************************************************************************************
@ -248,33 +237,43 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
if (len > 31) if (len > 31)
{ {
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 255;
while(len>31) while(len>31)
{ { // Ping-pong the transmit buffer
uint32_t i = 0; uint32_t i = 0;
while(i<8)
{
color[i++] = DAT8TO32(data);
data+=4;
}
_spi_w[8] = color[0];
_spi_w[9] = color[1];
_spi_w[10] = color[2];
_spi_w[11] = color[3];
_spi_w[12] = color[4];
_spi_w[13] = color[5];
_spi_w[14] = color[6];
_spi_w[15] = color[7];
while (*_spi_cmd&SPI_USR);
*_spi_user = SPI_USR_MOSI | SPI_USR_MOSI_HIGHPART;
*_spi_cmd = SPI_USR;
while(i<16) while(i<16)
{ {
color[i++] = DAT8TO32(data); color[i++] = DAT8TO32(data);
data+=4; data+=4;
} }
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); _spi_w[0] = color[8];
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]); _spi_w[1] = color[9];
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]); _spi_w[2] = color[10];
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]); _spi_w[3] = color[11];
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]); _spi_w[4] = color[12];
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]); _spi_w[5] = color[13];
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]); _spi_w[6] = color[14];
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]); _spi_w[7] = color[15];
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]); while (*_spi_cmd&SPI_USR);
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color[8]); *_spi_user = SPI_USR_MOSI;
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color[9]); *_spi_cmd = SPI_USR;
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; len -= 32;
} }
} }
@ -287,31 +286,31 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
color[i++] = DAT8TO32(data); color[i++] = DAT8TO32(data);
data+=4; data+=4;
} }
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); while (*_spi_cmd&SPI_USR);
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 255); *_spi_mosi_dlen = 255;
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color[0]); _spi_w[0] = color[0];
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color[1]); _spi_w[1] = color[1];
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color[2]); _spi_w[2] = color[2];
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color[3]); _spi_w[3] = color[3];
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color[4]); _spi_w[4] = color[4];
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color[5]); _spi_w[5] = color[5];
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color[6]); _spi_w[6] = color[6];
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color[7]); _spi_w[7] = color[7];
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); *_spi_cmd = SPI_USR;
len -= 16; len -= 16;
} }
if (len) if (len)
{ {
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); volatile uint32_t* spi_w = _spi_w;
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1); while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = (len << 4) - 1;
for (uint32_t i=0; i <= (len<<1); i+=4) { for (uint32_t i=0; i <= (len<<1); i+=4) {
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT)+i, DAT8TO32(data)); data+=4; *spi_w++ = DAT8TO32(data); data+=4;
} }
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); *_spi_cmd = SPI_USR;
} }
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); //while (*_spi_cmd&SPI_USR);
} }
/*************************************************************************************** /***************************************************************************************
@ -329,39 +328,46 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
if (len > 31) if (len > 31)
{ {
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 255;
*_spi_user = SPI_USR_MOSI;
while(len>31) while(len>31)
{ { // Ping-pong the transmit buffer
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); _spi_w[8] = *data++;
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), *data++); _spi_w[9] = *data++;
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), *data++); _spi_w[10] = *data++;
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), *data++); _spi_w[11] = *data++;
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), *data++); _spi_w[12] = *data++;
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), *data++); _spi_w[13] = *data++;
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), *data++); _spi_w[14] = *data++;
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), *data++); _spi_w[15] = *data++;
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), *data++); while (*_spi_cmd&SPI_USR);
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), *data++); SET_BUS_WRITE_MODE | SPI_USR_MOSI_HIGHPART;
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), *data++); *_spi_cmd = SPI_USR;
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), *data++); _spi_w[0] = *data++;
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), *data++); _spi_w[1] = *data++;
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), *data++); _spi_w[2] = *data++;
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), *data++); _spi_w[3] = *data++;
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), *data++); _spi_w[4] = *data++;
WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), *data++); _spi_w[5] = *data++;
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); _spi_w[6] = *data++;
_spi_w[7] = *data++;
while (*_spi_cmd&SPI_USR);
SET_BUS_WRITE_MODE;
*_spi_cmd = SPI_USR;
len -= 32; len -= 32;
} }
} }
if (len) if (len)
{ {
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); volatile uint32_t* spi_w = _spi_w;
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1); while (*_spi_cmd&SPI_USR);
for (uint32_t i=0; i <= (len<<1); i+=4) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + i), *data++); *_spi_mosi_dlen = (len << 4) - 1;
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); for (uint32_t i=0; i <= (len<<1); i+=4) *spi_w++ = *data++;
*_spi_cmd = SPI_USR;
} }
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); //while (*_spi_cmd&SPI_USR);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -382,59 +388,62 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
uint32_t r0 = r<<24 | b | g | r; uint32_t r0 = r<<24 | b | g | r;
uint32_t r1 = r0>>8 | g<<16; uint32_t r1 = r0>>8 | g<<16;
uint32_t r2 = r1>>8 | b<<8; uint32_t r2 = r1>>8 | b<<8;
bool empty = true;
if (len > 19) if (len > 19)
{ {
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 479;
_spi_w[ 0] = r0;
_spi_w[ 1] = r1;
_spi_w[ 2] = r2;
_spi_w[ 3] = r0;
_spi_w[ 4] = r1;
_spi_w[ 5] = r2;
_spi_w[ 6] = r0;
_spi_w[ 7] = r1;
_spi_w[ 8] = r2;
_spi_w[ 9] = r0;
_spi_w[10] = r1;
_spi_w[11] = r2;
_spi_w[12] = r0;
_spi_w[13] = r1;
_spi_w[14] = r2;
while(len>19) while(len>19)
{ {
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); while (*_spi_cmd&SPI_USR);
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); *_spi_cmd = SPI_USR;
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; len -= 20;
} }
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); empty = false;
} }
if (len) if (len)
{ {
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (len * 24) - 1, SPI_USR_MOSI_DBITLEN_S); while (*_spi_cmd&SPI_USR);
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); *_spi_mosi_dlen = (len * 24) - 1;
WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1); if (empty) {
WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2); _spi_w[0] = r0;
WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0); _spi_w[1] = r1;
WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1); _spi_w[2] = r2;
WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2); _spi_w[3] = r0;
if (len > 8 ) _spi_w[4] = r1;
{ _spi_w[5] = r2;
WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0); if (len > 8 )
WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1); {
WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2); _spi_w[ 6] = r0;
WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0); _spi_w[ 7] = r1;
WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1); _spi_w[ 8] = r2;
WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2); _spi_w[ 9] = r0;
WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0); _spi_w[10] = r1;
WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1); _spi_w[11] = r2;
WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2); _spi_w[12] = r0;
_spi_w[14] = r1;
_spi_w[14] = r2;
}
} }
*_spi_cmd = SPI_USR;
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); //while (*_spi_cmd&SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
} }
} }
@ -445,9 +454,59 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in; 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++;} } if(!_swapBytes) {
else { while ( len-- ) {tft_Write_16(*data); data++;} }
while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 48-1;
while ( len>1 ) {
// Split out the colours
uint32_t r1 = (*data & 0xF8);
uint32_t g1 = (*data & 0xE000)>>11 | (*data & 0x07)<<5;
uint32_t b1 = (*data++ & 0x1F00)>>5;
uint32_t r2 = (*data & 0xF8);
uint32_t g2 = (*data & 0xE000)>>11 | (*data & 0x07)<<5;
uint32_t b2 = (*data++ & 0x1F00)>>5;
uint32_t rgb1 = r2<<24 | b1<<16 | g1<<8 | r1;
uint32_t rgb2 = b2<<8 | g2;
while (*_spi_cmd&SPI_USR);
_spi_w[0] = rgb1;
_spi_w[1] = rgb2;
*_spi_cmd = SPI_USR;
len -= 2;
}
if (len) {
// Split out the colours
uint32_t r = (*data & 0xF8);
uint32_t g = (*data & 0xE000)>>11 | (*data & 0x07)<<5;
uint32_t b = (*data++ & 0x1F00)>>5;
uint32_t rgb = b<<16 | g<<8 | r;
while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 24-1;
*_spi_w = rgb;
*_spi_cmd = SPI_USR;
}
//was while ( len-- ) {tft_Write_16S(*data); data++;}
}
else {
while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 24-1;
while ( len-- ) {
// Split out the colours
uint32_t r = (*data & 0xF800)>>8;
uint32_t g = (*data & 0x07E0)>>3;
uint32_t b = (*data++ & 0x001F)<<3;
uint32_t rgb = b<<16 | g<<8 | r;
while (*_spi_cmd&SPI_USR);
// Concatenate pixel into 32 bits
*_spi_w = rgb;
*_spi_cmd = SPI_USR;
}
//was while ( len-- ) {tft_Write_16(*data); data++;}
}
} }
/*************************************************************************************** /***************************************************************************************
@ -458,7 +517,21 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in; uint16_t *data = (uint16_t*)data_in;
// ILI9488 write macro is not endianess dependant, so swap byte macro not used here // ILI9488 write macro is not endianess dependant, so swap byte macro not used here
while ( len-- ) {tft_Write_16(*data); data++;} while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = 24-1;
while ( len-- ) {
// Split out the colours
uint32_t r = (*data & 0xF800)>>8;
uint32_t g = (*data & 0x07E0)>>3;
uint32_t b = (*data++ & 0x001F)<<3;
uint32_t rgb = b<<16 | g<<8 | r;
while (*_spi_cmd&SPI_USR);
// Concatenate pixel into 32 bits
*_spi_w = rgb;
*_spi_cmd = SPI_USR;
}
//while ( len-- ) {tft_Write_16(*data); data++;}
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -575,8 +648,8 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
trans.user = (void *)1; trans.user = (void *)1;
trans.tx_buffer = image; //finally send the line data trans.tx_buffer = image; //finally send the line data
trans.length = len * 16; //Data length, in bits trans.length = len * 16; //Data length, in bits
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
assert(ret == ESP_OK); assert(ret == ESP_OK);
@ -611,7 +684,7 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t
if (buffer == nullptr) { if (buffer == nullptr) {
buffer = image; buffer = image;
dmaWait(); if (spiBusyCheck) dmaWait();
} }
// If image is clipped, copy pixels into a contiguous block // If image is clipped, copy pixels into a contiguous block
@ -640,13 +713,13 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t
} }
} }
static spi_transaction_t trans;
esp_err_t ret;
if (spiBusyCheck) dmaWait(); // Incase we did not wait earlier if (spiBusyCheck) dmaWait(); // Incase we did not wait earlier
setAddrWindow(x, y, dw, dh); setAddrWindow(x, y, dw, dh);
esp_err_t ret;
static spi_transaction_t trans;
memset(&trans, 0, sizeof(spi_transaction_t)); memset(&trans, 0, sizeof(spi_transaction_t));
trans.user = (void *)1; trans.user = (void *)1;
@ -712,7 +785,7 @@ bool TFT_eSPI::initDMA(bool ctrl_cs)
.input_delay_ns = 0, .input_delay_ns = 0,
.spics_io_num = pin, .spics_io_num = pin,
.flags = SPI_DEVICE_NO_DUMMY, //0, .flags = SPI_DEVICE_NO_DUMMY, //0,
.queue_size = 1, .queue_size = DMA_QUEUE_SIZE,
.pre_cb = 0, //dc_callback, //Callback to handle D/C line .pre_cb = 0, //dc_callback, //Callback to handle D/C line
.post_cb = 0 .post_cb = 0
}; };

View File

@ -65,12 +65,19 @@
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions // Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions
#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) #if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER)
#define ESP32_DMA #define ESP32_DMA
#define DMA_QUEUE_SIZE 1
// Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions
#define DMA_BUSY_CHECK dmaWait() #define DMA_BUSY_CHECK dmaWait()
#else #else
#define DMA_BUSY_CHECK #define DMA_BUSY_CHECK
#endif #endif
#if defined(TFT_PARALLEL_8_BIT)
#define SPI_BUSY_CHECK
#else
#define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR)
#endif
// If smooth font is used then it is likely SPIFFS will be needed // If smooth font is used then it is likely SPIFFS will be needed
#ifdef SMOOTH_FONT #ifdef SMOOTH_FONT
// Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts
@ -167,7 +174,7 @@
#define CS_L GPIO.out_w1ts = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) #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) #define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS)
#else #else
#define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) #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) #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS)
#endif #endif
#else #else
@ -198,6 +205,7 @@
#define WR_H #define WR_H
#endif #endif
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// Define the touch screen chip select pin drive code // Define the touch screen chip select pin drive code
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -217,11 +225,7 @@
#ifdef USE_HSPI_PORT #ifdef USE_HSPI_PORT
#ifndef TFT_MISO #ifndef TFT_MISO
#define TFT_MISO 12 #define TFT_MISO -1
#endif
#if (TFT_MISO == -1)
#undef TFT_MISO
#define TFT_MISO 12
#endif #endif
#ifndef TFT_MOSI #ifndef TFT_MOSI
@ -243,11 +247,7 @@
#else // VSPI port #else // VSPI port
#ifndef TFT_MISO #ifndef TFT_MISO
#define TFT_MISO 19 #define TFT_MISO -1
#endif
#if (TFT_MISO == -1)
#undef TFT_MISO
#define TFT_MISO 19
#endif #endif
#ifndef TFT_MOSI #ifndef TFT_MOSI
@ -375,6 +375,7 @@
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour #elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
// ESP32 low level SPI writes for 8, 16 and 32 bit values too fast for ILI9488
// Write 8 bits to TFT // Write 8 bits to TFT
#define tft_Write_8(C) spi.transfer(C) #define tft_Write_8(C) spi.transfer(C)
@ -383,6 +384,11 @@
spi.transfer(((C) & 0x07E0)>>3); \ spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3) spi.transfer(((C) & 0x001F)<<3)
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16N(C) spi.transfer(((C) & 0xF800)>>8); \
spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3)
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \
spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
@ -404,11 +410,14 @@
// ESP32 low level SPI writes for 8, 16 and 32 bit values // ESP32 low level SPI writes for 8, 16 and 32 bit values
// to avoid the function call overhead // to avoid the function call overhead
#define TFT_WRITE_BITS(D, B) \ #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ *_spi_w = D; \
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \ *_spi_cmd = SPI_USR; \
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ while (*_spi_cmd & SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
#define TFT_WRITE_BITSN(D, B) *_spi_mosi_dlen = B-1; \
*_spi_w = D; \
*_spi_cmd = SPI_USR;
// Write 8 bits // Write 8 bits
#define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16) #define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16)
@ -416,6 +425,10 @@
// Write 16 bits with corrected endianess for 16 bit colours // Write 16 bits with corrected endianess for 16 bit colours
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
*_spi_w = ((C)<<8 | (C)>>8); \
*_spi_cmd = SPI_USR;
// Write 16 bits // Write 16 bits
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
@ -429,18 +442,16 @@
// Write same value twice // Write same value twice
#define tft_Write_32D(C) tft_Write_32C(C,C) #define tft_Write_32D(C) tft_Write_32C(C,C)
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays // Macros for all other SPI displays
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#else #else
// ESP32 low level SPI writes for 8, 16 and 32 bit values #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
// to avoid the function call overhead *_spi_w = D; \
#define TFT_WRITE_BITS(D, B) \ *_spi_cmd = SPI_USR; \
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ while (*_spi_cmd & SPI_USR);
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 // Write 8 bits
#define tft_Write_8(C) TFT_WRITE_BITS(C, 8) #define tft_Write_8(C) TFT_WRITE_BITS(C, 8)
@ -448,6 +459,10 @@
// Write 16 bits with corrected endianess for 16 bit colours // Write 16 bits with corrected endianess for 16 bit colours
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
*_spi_w = ((C)<<8 | (C)>>8); \
*_spi_cmd = SPI_USR;
// Write 16 bits // Write 16 bits
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)

View File

@ -127,6 +127,7 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
uint32_t r1 = g<<24 | r<<16 | b<<8 | g; uint32_t r1 = g<<24 | r<<16 | b<<8 | g;
uint32_t r2 = b<<24 | g<<16 | r<<8 | b; uint32_t r2 = b<<24 | g<<16 | r<<8 | b;
while(SPI1CMD & SPIBUSY) {}
SPI1W0 = r0; SPI1W0 = r0;
SPI1W1 = r1; SPI1W1 = r1;
SPI1W2 = r2; SPI1W2 = r2;
@ -163,15 +164,16 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
len -= 21; len -= 21;
} }
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }
if (len) if (len)
{ {
len = (len * 24) - 1; len = (len * 24) - 1;
while(SPI1CMD & SPIBUSY) {}
SPI1U1 = (len << SPILMOSI); SPI1U1 = (len << SPILMOSI);
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }
} }
@ -183,6 +185,7 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in; uint16_t *data = (uint16_t*)data_in;
while(SPI1CMD & SPIBUSY) {}
// Send groups of 4 concatenated pixels // Send groups of 4 concatenated pixels
if (len > 3) { if (len > 3) {
@ -222,12 +225,8 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
len -= 4; len -= 4;
} }
while(SPI1CMD & SPIBUSY) {} //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++;}
} }
/*************************************************************************************** /***************************************************************************************
@ -257,23 +256,10 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
// //
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 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); uint16_t color16 = (color >> 8) | (color << 8);
uint32_t color32 = color16 | color16 << 16; uint32_t color32 = color16 | color16 << 16;
/* while(SPI1CMD & SPIBUSY) {}
while(len--) {
SPI1U1 = ((16-1) << SPILMOSI) | ((16-1) << SPILMISO);
SPI1W0 = color16;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
}
return;
//*/
SPI1W0 = color32; SPI1W0 = color32;
SPI1W1 = color32; SPI1W1 = color32;
SPI1W2 = color32; SPI1W2 = color32;
@ -311,15 +297,16 @@ return;
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
len -= 32; len -= 32;
} }
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }
if (len) if (len)
{ {
len = (len << 4) - 1; len = (len << 4) - 1;
while(SPI1CMD & SPIBUSY) {}
SPI1U1 = (len << SPILMOSI); SPI1U1 = (len << SPILMOSI);
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }
} }
@ -339,6 +326,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint32_t color[8]; uint32_t color[8];
while(SPI1CMD & SPIBUSY) {}
SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO); SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO);
@ -381,7 +369,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
} }
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }
@ -396,6 +384,7 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
uint32_t color[8]; uint32_t color[8];
while(SPI1CMD & SPIBUSY) {}
SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO); SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO);
while(len>15) while(len>15)
@ -438,7 +427,7 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){
SPI1CMD |= SPIBUSY; SPI1CMD |= SPIBUSY;
} }
while(SPI1CMD & SPIBUSY) {} //while(SPI1CMD & SPIBUSY) {}
} }

View File

@ -17,6 +17,7 @@
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions // 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 #define DMA_BUSY_CHECK // DMA not available, leave blank
#define SPI_BUSY_CHECK while(SPI1CMD & SPIBUSY) {;}
// Initialise processor specific SPI functions, used by init() // Initialise processor specific SPI functions, used by init()
#if (!defined (SUPPORT_TRANSACTIONS) && defined (ESP8266)) #if (!defined (SUPPORT_TRANSACTIONS) && defined (ESP8266))
@ -127,6 +128,11 @@
spi.transfer(((C) & 0x07E0)>>3); \ spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3) spi.transfer(((C) & 0x001F)<<3)
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16N(C) spi.transfer(((C) & 0xF800)>>8); \
spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3)
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \
spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
@ -160,6 +166,10 @@
#define tft_Write_16(C) TFT_WRITE_BITS((C)>>8 | (C)<<8, 16) #define tft_Write_16(C) TFT_WRITE_BITS((C)>>8 | (C)<<8, 16)
#define tft_Write_16N(C) SPI1U1 = ((16-1) << SPILMOSI); \
SPI1W0 = (C)>>8 | (C)<<8; \
SPI1CMD |= SPIBUSY; \
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32) #define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
@ -191,6 +201,11 @@
SPI1CMD |= SPIBUSY; \ SPI1CMD |= SPIBUSY; \
while(SPI1CMD & SPIBUSY) {;} while(SPI1CMD & SPIBUSY) {;}
#define tft_Write_16N(C) \
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
SPI1W0 = ((C)<<8 | (C)>>8); \
SPI1CMD |= SPIBUSY;
#define tft_Write_16S(C) \ #define tft_Write_16S(C) \
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \ SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
SPI1W0 = C; \ SPI1W0 = C; \

View File

@ -18,8 +18,9 @@
#define SET_BUS_WRITE_MODE // Not used #define SET_BUS_WRITE_MODE // Not used
#define SET_BUS_READ_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 // Code to check if SPI or DMA is busy, used by SPI bus transaction startWrite and/or endWrite functions
#define DMA_BUSY_CHECK // Not used so leave blank #define DMA_BUSY_CHECK // Not used so leave blank
#define SPI_BUSY_CHECK // Not used so leave blank
// To be safe, SUPPORT_TRANSACTIONS is assumed mandatory // To be safe, SUPPORT_TRANSACTIONS is assumed mandatory
#if !defined (SUPPORT_TRANSACTIONS) #if !defined (SUPPORT_TRANSACTIONS)
@ -104,6 +105,11 @@
spi.transfer(((C) & 0x07E0)>>3); \ spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3) spi.transfer(((C) & 0x001F)<<3)
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16N(C) spi.transfer(((C) & 0xF800)>>8); \
spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3)
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \
spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
@ -124,6 +130,7 @@
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers #if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
#define tft_Write_8(C) spi.transfer(C); spi.transfer(C) #define tft_Write_8(C) spi.transfer(C); spi.transfer(C)
#define tft_Write_16(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0)) #define tft_Write_16(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0))
#define tft_Write_16N(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0))
#define tft_Write_16S(C) spi.transfer((uint8_t)((C)>>0));spi.transfer((uint8_t)((C)>>8)) #define tft_Write_16S(C) spi.transfer((uint8_t)((C)>>0));spi.transfer((uint8_t)((C)>>8))
#define tft_Write_32(C) \ #define tft_Write_32(C) \
@ -144,13 +151,15 @@
#else #else
#ifdef __AVR__ // AVR processors do not have 16 bit transfer #ifdef __AVR__ // AVR processors do not have 16 bit transfer
#define tft_Write_8(C) {SPDR=(C); while (!(SPSR&_BV(SPIF)));} #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_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)) #define tft_Write_16N(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 #else
#define tft_Write_8(C) spi.transfer(C) #define tft_Write_8(C) spi.transfer(C)
#define tft_Write_16(C) spi.transfer16(C) #define tft_Write_16(C) spi.transfer16(C)
#define tft_Write_16S(C) spi.transfer16(((C)>>8) | ((C)<<8)) #define tft_Write_16N(C) spi.transfer16(C)
#define tft_Write_16S(C) spi.transfer16(((C)>>8) | ((C)<<8))
#endif // AVR #endif // AVR
#define tft_Write_32(C) \ #define tft_Write_32(C) \

View File

@ -17,6 +17,12 @@
#define SET_BUS_WRITE_MODE // Not used #define SET_BUS_WRITE_MODE // Not used
#define SET_BUS_READ_MODE // Not used #define SET_BUS_READ_MODE // Not used
#if defined(TFT_PARALLEL_8_BIT)
#define SPI_BUSY_CHECK
#else
#define SPI_BUSY_CHECK while (spiHal.State == HAL_SPI_STATE_BUSY_TX)
#endif
// SUPPORT_TRANSACTIONS is mandatory for STM32 // SUPPORT_TRANSACTIONS is mandatory for STM32
#if !defined (SUPPORT_TRANSACTIONS) #if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS #define SUPPORT_TRANSACTIONS
@ -183,7 +189,8 @@
dmaHal.Instance = DMA1_Channel5 dmaHal.Instance = DMA1_Channel5
#endif #endif
#else #else
// For STM32 processor with no implemented DMA support (yet) // For other STM32 processor with no implemented DMA support (yet)
// #define STM32_DMA // Commented out - DMA not tested with other processors
#if (TFT_SPI_PORT == 1) #if (TFT_SPI_PORT == 1)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1 #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1
#elif (TFT_SPI_PORT == 2) #elif (TFT_SPI_PORT == 2)
@ -200,6 +207,7 @@
#define DMA_BUSY_CHECK #define DMA_BUSY_CHECK
#endif #endif
// If smooth fonts are enabled the filing system may need to be loaded // If smooth fonts are enabled the filing system may need to be loaded
#ifdef SMOOTH_FONT #ifdef SMOOTH_FONT
// Call up the filing system for the anti-aliased fonts <<<==== TODO // Call up the filing system for the anti-aliased fonts <<<==== TODO
@ -1032,6 +1040,10 @@
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \ { spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); } HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16N(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \ #define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \ { spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); } HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
@ -1067,6 +1079,10 @@
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \ { spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); } HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16N(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \ #define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \ { spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); } HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }

View File

@ -27,6 +27,8 @@
writecommand(0x3A); //Interface Pixel Format writecommand(0x3A); //Interface Pixel Format
writedata(0x55); //Control interface color format set to 16 writedata(0x55); //Control interface color format set to 16
writecommand(0xB0); //Interface mode control
writedata(0x00); //0x00 = SDA input and SDO output, 0x80 bidirections SDA
writecommand(0xB4); //Column inversion writecommand(0xB4); //Column inversion
writedata(0x01); //1-dot inversion writedata(0x01); //1-dot inversion

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_ #ifndef _TFT_eSPIH_
#define _TFT_eSPIH_ #define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.3.59" #define TFT_ESPI_VERSION "2.4.0"
// Bit level feature flags // Bit level feature flags
// Bit 0 set: viewport capability // Bit 0 set: viewport capability
@ -295,7 +295,7 @@ typedef struct
{ {
String version = TFT_ESPI_VERSION; String version = TFT_ESPI_VERSION;
int32_t esp; // Processor code int32_t esp; // Processor code
uint8_t trans; // SPI transaction supoort uint8_t trans; // SPI transaction support
uint8_t serial; // Serial (SPI) or parallel uint8_t serial; // Serial (SPI) or parallel
uint8_t overlap; // ESP8266 overlap mode uint8_t overlap; // ESP8266 overlap mode
@ -384,6 +384,9 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
height(void), height(void),
width(void); width(void);
// Read the colour of a pixel at x,y and return value in 565 format
virtual uint16_t readPixel(int32_t x, int32_t y);
void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3 void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3
uint8_t getRotation(void); // Read the current rotation uint8_t getRotation(void); // Read the current rotation
@ -391,12 +394,21 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
// The TFT_eSprite class inherits the following functions (not all are useful to Sprite class // The TFT_eSprite class inherits the following functions (not all are useful to Sprite class
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h), // Note: start coordinates + width and height void setAddrWindow(int32_t x, int32_t y, int32_t w, int32_t h); // Note: start coordinates + width and height
setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates
// Viewport commands, see "Viewport_Demo" sketch // Viewport commands, see "Viewport_Demo" sketch
void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true);
bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h);
// Check if whole of specified area is within viewport area, returns true if clipping is not required
bool checkViewport (int32_t x, int32_t y, int32_t w, int32_t h); // Deprecated use checkAddrWindow
bool checkAddrWindow(int32_t x, int32_t y, int32_t w, int32_t h);
// Clip input window to viewport bounds, return false if whole area is out of bounds
bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h);
// Clip input window area to viewport bounds, return false if whole area is out of bounds
bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye);
int32_t getViewportX(void); int32_t getViewportX(void);
int32_t getViewportY(void); int32_t getViewportY(void);
int32_t getViewportWidth(void); int32_t getViewportWidth(void);
@ -417,9 +429,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
// Write a set of pixels stored in memory, use setSwapBytes(true/false) function to correct endianess // Write a set of pixels stored in memory, use setSwapBytes(true/false) function to correct endianess
void pushPixels(const void * data_in, uint32_t len); void pushPixels(const void * data_in, uint32_t len);
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x, int32_t y);
// Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input // Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input
#ifdef TFT_SDA_READ #ifdef TFT_SDA_READ
#if defined (TFT_eSPI_ENABLE_8_BIT_READ) #if defined (TFT_eSPI_ENABLE_8_BIT_READ)
@ -435,6 +444,20 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color), drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color),
fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color); fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color);
// Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2)
void drawWideLine(float ax, float ay, float bx, float by, float wd, uint16_t fg_color, uint16_t bg_color);
// For sprites and also TFT screens where the background pixel colours can be read
void drawWideLine(float ax, float ay, float bx, float by, float wd, uint16_t fg_color);
// Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends
void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint16_t fg_color, uint16_t bg_color);
// For sprites and also TFT screens where the background pixel colours can be read
void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint16_t fg_color);
// Draw an anti-aliased filled circle at ax,ay with radius r (uses drawWideLine)
void drawSpot(float ax, float ay, float r, uint16_t fg_color, uint16_t bg_color);
// For sprites and also TFT screens where the background pixel colours can be read
void drawSpot(float ax, float ay, float r, uint16_t fg_color);
void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color), void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color), drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color),
@ -521,6 +544,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
void setTextColor(uint16_t color), // Set character (glyph) color only (background not over-written) void setTextColor(uint16_t color), // Set character (glyph) color only (background not over-written)
setTextColor(uint16_t fgcolor, uint16_t bgcolor),// Set character (glyph) foreground and backgorund colour setTextColor(uint16_t fgcolor, uint16_t bgcolor),// Set character (glyph) foreground and backgorund colour
setTextSize(uint8_t size); // Set character size multiplier (this increases pixel size) setTextSize(uint8_t size); // Set character size multiplier (this increases pixel size)
// Note: Smooth fonts cannot be scaled using setTextSize
void setTextWrap(bool wrapX, bool wrapY = false); // Turn on/off wrapping of text in TFT width and/or height void setTextWrap(bool wrapX, bool wrapY = false); // Turn on/off wrapping of text in TFT width and/or height
@ -702,6 +726,11 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
// Same as setAddrWindow but exits with CGRAM in read mode // Same as setAddrWindow but exits with CGRAM in read mode
void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h);
// Helper function: calculate distance of a point from a finite length line between two points
float wideLineDistance(float pax, float pay, float bax, float bay, float dr) __attribute__((always_inline));
// As above but adds delta distance for wedge shaped lines
float wedgeLineDistance(float pax, float pay, float bax, float bay, float dr) __attribute__((always_inline));
// Byte read prototype // Byte read prototype
uint8_t readByte(void); uint8_t readByte(void);

View File

@ -24,7 +24,7 @@
// STM32F767 27MHz SPI 0% processor load: Non DMA 97 fps, with DMA 102 fps // STM32F767 27MHz SPI 0% processor load: Non DMA 97 fps, with DMA 102 fps
// ESP32 27MHz SPI 0% processor load: Non DMA 90 fps, with DMA 101 fps // ESP32 27MHz SPI 0% processor load: Non DMA 90 fps, with DMA 101 fps
// ESP32 40MHz SPI 0% processor load: Non DMA 127 fps, with DMA 145 fps // ESP32 40MHz SPI 0% processor load: Non DMA 127 fps, with DMA 152 fps
// NOTE: FOR SPI DISPLAYS ONLY // NOTE: FOR SPI DISPLAYS ONLY
#define USE_DMA_TO_TFT #define USE_DMA_TO_TFT

View File

@ -20,11 +20,19 @@
// Blue Pill overclocked to 128MHz with DMA - 32MHz SPI 116 fps // Blue Pill overclocked to 128MHz with DMA - 32MHz SPI 116 fps
// ESP32 - 8 bit parallel 110 fps (no DMA) // ESP32 - 8 bit parallel 110 fps (no DMA)
// ESP32 - 40MHz SPI *no* DMA 93 fps // ESP32 - 27MHz SPI *no* DMA 75 fps
// ESP32 - 40MHz SPI with DMA 112 fps // ESP32 - 27MHz SPI with DMA 110 fps
// ESP32 - 40MHz SPI *no* DMA 94 fps
// ESP32 - 40MHz SPI with DMA 160 fps
// ESP32 - 80MHz SPI *no* DMA 128 fps
// ESP32 - 80MHz SPI with DMA 187 fps
#define SCREENWIDTH 320 // Comment out next line for no DMA
#define USE_DMA
#define SCREENWIDTH 320
#define SCREENHEIGHT 240 #define SCREENHEIGHT 240
#define BUFFER_SIZE 1024 // DMA buffers (4 kbytes reserved)
#include "graphic.h" #include "graphic.h"
@ -51,7 +59,7 @@ int balloldx = ballx, balloldy = bally; // Prior ball position
// Working buffer for ball rendering...2 scanlines that alternate, // Working buffer for ball rendering...2 scanlines that alternate,
// one is rendered while the other is transferred via DMA. // one is rendered while the other is transferred via DMA.
uint16_t renderbuf[2][SCREENWIDTH]; uint16_t renderbuf[2][BUFFER_SIZE];
uint16_t palette[16]; // Color table for ball rotation effect uint16_t palette[16]; // Color table for ball rotation effect
@ -64,12 +72,12 @@ void setup() {
tft.begin(); tft.begin();
tft.setRotation(3); // Landscape orientation, USB at bottom right tft.setRotation(3); // Landscape orientation, USB at bottom right
tft.setSwapBytes(false); tft.setSwapBytes(false);
// Draw initial framebuffer contents: #ifdef USE_DMA
//tft.setBitmapColor(GRIDCOLOR, BGCOLOR);
tft.fillScreen(BGCOLOR);
tft.initDMA(); tft.initDMA();
#endif
// Draw initial framebuffer contents:
tft.fillScreen(BGCOLOR);
tft.drawBitmap(0, 0, (const uint8_t *)background, SCREENWIDTH, SCREENHEIGHT, GRIDCOLOR); tft.drawBitmap(0, 0, (const uint8_t *)background, SCREENWIDTH, SCREENHEIGHT, GRIDCOLOR);
startTime = millis(); startTime = millis();
@ -127,16 +135,17 @@ void loop() {
x, y, bx1, bgx1; // Loop counters and working vars x, y, bx1, bgx1; // Loop counters and working vars
uint8_t p; // 'packed' value of 2 ball pixels uint8_t p; // 'packed' value of 2 ball pixels
int8_t bufIdx = 0; int8_t bufIdx = 0;
uint32_t pCount = 0;
// Start SPI transaction and drop TFT_CS - avoids transaction overhead in loop // Start SPI transaction and drop TFT_CS - avoids transaction overhead in loop
tft.startWrite(); tft.startWrite();
// Set window area to pour pixels into // Set window area to pour pixels into
tft.setAddrWindow(minx, miny, width, height); tft.setAddrWindow(minx, miny, width, height);
destPtr = &renderbuf[bufIdx][0];
// Draw line by line loop // Draw line by line loop
for(y=0; y<height; y++) { // For each row... for(y=0; y<height; y++) { // For each row...
destPtr = &renderbuf[bufIdx][0];
bx1 = bx; // Need to keep the original bx and bgx values, bx1 = bx; // Need to keep the original bx and bgx values,
bgx1 = bgx; // so copies of them are made here (and changed in loop below) bgx1 = bgx; // so copies of them are made here (and changed in loop below)
for(x=0; x<width; x++) { for(x=0; x<width; x++) {
@ -156,22 +165,29 @@ void loop() {
c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR; c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR;
} }
*destPtr++ = c<<8 | c>>8; // Store pixel color *destPtr++ = c<<8 | c>>8; // Store pixel color
pCount++;
if (pCount >= BUFFER_SIZE) {
#ifdef USE_DMA
tft.pushPixelsDMA(&renderbuf[bufIdx][0], BUFFER_SIZE); // Push line to screen
#else
tft.pushPixels(&renderbuf[bufIdx][0], BUFFER_SIZE);
#endif
bufIdx = 1 - bufIdx;
destPtr = &renderbuf[bufIdx][0];
pCount = 0;
}
bx1++; // Increment bitmap position counters (X axis) bx1++; // Increment bitmap position counters (X axis)
bgx1++; bgx1++;
} }
tft.pushPixelsDMA(&renderbuf[bufIdx][0], width); // Push line to screen
// Push line to screen (swap bytes false for STM/ESP32)
//tft.pushPixels(&renderbuf[bufIdx][0], width);
bufIdx = 1 - bufIdx;
by++; // Increment bitmap position counters (Y axis) by++; // Increment bitmap position counters (Y axis)
bgy++; bgy++;
} }
//if (random(100) == 1) delay(2000); #ifdef USE_DMA
tft.endWrite(); if (pCount) tft.pushPixelsDMA(&renderbuf[bufIdx][0], pCount); // Push line to screen
//delay(5); #else
if (pCount) tft.pushPixels(&renderbuf[bufIdx][0], pCount);
#endif
// Show approximate frame rate // Show approximate frame rate
if(!(++frame & 255)) { // Every 256 frames... if(!(++frame & 255)) { // Every 256 frames...
uint32_t elapsed = (millis() - startTime) / 1000; // Seconds uint32_t elapsed = (millis() - startTime) / 1000; // Seconds