Remove SPI  LL HAL functions that seem to be broken in latest STM32duino board package.

Replace with low level register access writes and reads.

This change also has significant performance benefits for SPI display update speed!
This commit is contained in:
Bodmer 2023-12-22 01:07:33 +00:00
parent 2d88fe4c6e
commit cbf06d7a21
5 changed files with 132 additions and 115 deletions

View File

@ -24,9 +24,6 @@
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)
////////////////////////////////////////////////////////////////////////////////////////
@ -296,34 +293,19 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
#define BUF_SIZE 240*3
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
{
uint8_t col[BUF_SIZE];
//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;
while(len--) {
TX_FIFO = (r);
TX_FIFO = (g);
TX_FIFO = (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); //*/
SPI_BUSY_CHECK;
}
/***************************************************************************************
** Function name: pushPixels - for STM32 and 3 byte RGB display
@ -333,26 +315,25 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
{
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
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
TX_FIFO = (*data & 0xF8); // Red
TX_FIFO = (*data & 0xE000)>>11 | (*data & 0x07)<<5; // Green
TX_FIFO = (*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
TX_FIFO = (*data & 0xF800)>>8; // Red
TX_FIFO = (*data & 0x07E0)>>3; // Green
TX_FIFO = (*data & 0x001F)<<3; // Blue
data++;
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
}
}
SPI_BUSY_CHECK;
}
////////////////////////////////////////////////////////////////////////////////////////
@ -364,6 +345,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
** 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];
@ -381,7 +363,47 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
len -= BUF_SIZE;
} while ( len>=BUF_SIZE ) ;
// Send remaining pixels
if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/
if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY);
}
//*/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
// Loop unrolling improves speed dramatically graphics test 0.634s => 0.374s
while (len>31) {
#if !defined (SSD1963_DRIVER)
// 32D macro writes 16 bits twice
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
#else
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
#endif
len-=32;
}
while (len>7) {
#if !defined (SSD1963_DRIVER)
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
#else
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color);
#endif
len-=8;
}
while (len--) {tft_Write_16(color);}
}
@ -392,26 +414,23 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
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;
while ( len-- ) {
TX_FIFO = (uint8_t)(*data>>8);
TX_FIFO = (uint8_t)(*data<<8);
data++;
}
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
while ( len-- ) {
// Split out the colours
TX_FIFO = (uint8_t)(*data);
TX_FIFO = (uint8_t)(*data>>8);
data++;
}
// Send remaining pixels (max 65534 bytes)
HAL_SPI_Transmit(&spiHal, (uint8_t*)data, len<<1, HAL_MAX_DELAY);
}
SPI_BUSY_CHECK;
}
////////////////////////////////////////////////////////////////////////////////////////

View File

@ -151,6 +151,15 @@
#define TFT_SPI_PORT 1
#endif
#if (TFT_SPI_PORT == 1)
#define SPIX SPI1
#elif (TFT_SPI_PORT == 2)
#define SPIX SPI2
#elif (TFT_SPI_PORT == 3)
#define SPIX SPI3
#elif (TFT_SPI_PORT == 4)
#define SPIX SPI4
#endif
// Global define is _VARIANT_ARDUINO_STM32_, see board package stm32_def.h for specific variants
#if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx)
@ -226,8 +235,8 @@
#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
#define DC_C DC_DELAY; DC_PORT->BSRR = DC_PIN_MASK<<16
#define DC_D DC_DELAY; DC_PORT->BSRR = DC_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
@ -962,64 +971,56 @@
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour
// Write 8 bits to TFT
#define tft_Write_8(C) \
{ spiBuffer[0] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 1, 10); }
#define SPI_TXE_CHECK while(!__HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_TXE)){}
//BSY check must allow for APB clock delay by checking TXE flag first
#define SPI_BUSY_CHECK SPI_TXE_CHECK; while( __HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_BSY)){}
#define TX_FIFO SPI_TXE_CHECK; *((__IO uint8_t *)&SPIX->DR)
// 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); }
//#define tft_Write_8(C) spi.transfer(C)
#define tft_Write_8(C) TX_FIFO = (C); SPI_BUSY_CHECK
#define tft_Write_16(C) TX_FIFO = ((C) & 0xF800)>>8; TX_FIFO = ((C) & 0x07E0)>>3; TX_FIFO = ((C) & 0x001F)<<3; SPI_BUSY_CHECK
#define tft_Write_16S(C) TX_FIFO = (C) & 0xF8; TX_FIFO = ((C) & 0xE000)>>11 | ((C) & 0x07)<<5; TX_FIFO = ((C) & 0x1F00)>>5; SPI_BUSY_CHECK
#define tft_Write_16N(C) TX_FIFO = ((C) & 0xF800)>>8; TX_FIFO = ((C) & 0x07E0)>>3; TX_FIFO = ((C) & 0x001F)<<3
// 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); }
TX_FIFO = (C)>>24; TX_FIFO = (C)>>16; \
TX_FIFO = (C)>>8; TX_FIFO = (C); SPI_BUSY_CHECK
// 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); }
TX_FIFO = (C)>>8; TX_FIFO = (C); \
TX_FIFO = (D)>>8; TX_FIFO = (D); SPI_BUSY_CHECK
// 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); }
TX_FIFO = (C)>>8; TX_FIFO = (C); \
TX_FIFO = (C)>>8; TX_FIFO = (C); SPI_BUSY_CHECK
////////////////////////////////////////////////////////////////////////////////////////
// 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 SPI_TXE_CHECK while(!__HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_TXE)){}
//BSY check must allow for APB clock delay by checking TXE flag first
#define SPI_BUSY_CHECK SPI_TXE_CHECK; while( __HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_BSY)){}
#define TX_FIFO SPI_TXE_CHECK; *((__IO uint8_t *)&SPIX->DR)
#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_8(C) spi.transfer(C)
#define tft_Write_8(C) TX_FIFO = (0); TX_FIFO = (C); SPI_BUSY_CHECK
#define tft_Write_16(C) TX_FIFO = (C)>>8; TX_FIFO = (C); SPI_BUSY_CHECK
#define tft_Write_16S(C) TX_FIFO = (C); TX_FIFO = (C)>>8; SPI_BUSY_CHECK
#define tft_Write_16N(C) TX_FIFO = (C)>>8; TX_FIFO = (C)
#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); }
TX_FIFO = (C)>>24; TX_FIFO = (C)>>16; \
TX_FIFO = (C)>>8; TX_FIFO = (C); SPI_BUSY_CHECK
#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); }
TX_FIFO = (0); TX_FIFO = (C)>>8; TX_FIFO = (0); TX_FIFO = (C); \
TX_FIFO = (0); TX_FIFO = (D)>>8; TX_FIFO = (0); TX_FIFO = (D); SPI_BUSY_CHECK
#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); }
TX_FIFO = (0); TX_FIFO = (C)>>8; TX_FIFO = (0); TX_FIFO = (C); \
TX_FIFO = (0); TX_FIFO = (C)>>8; TX_FIFO = (0); TX_FIFO = (C); SPI_BUSY_CHECK
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
@ -1027,40 +1028,37 @@
#else
/* Remove patch to fix #2933
#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);}
/* Remove patch to fix #2933
#endif
*/
#define tft_Write_16(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
//#define DC_DELAY delayMicroseconds(1) // Premature BSY clear Hardware bug?
#define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define SPI_TXE_CHECK while(!__HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_TXE)){}
//BSY check must allow for APB clock delay by checking TXE flag first
#define SPI_BUSY_CHECK SPI_TXE_CHECK; while( __HAL_SPI_GET_FLAG(&spiHal, SPI_FLAG_BSY)){}
#define TX_FIFO SPI_TXE_CHECK; *((__IO uint8_t *)&SPIX->DR)
#define tft_Write_8(C) TX_FIFO = (C); SPI_BUSY_CHECK
#define tft_Write_16(C) TX_FIFO = (C)>>8; TX_FIFO = (C); SPI_BUSY_CHECK
#define tft_Write_16S(C) TX_FIFO = (C); TX_FIFO = (C)>>8; SPI_BUSY_CHECK
#define tft_Write_16N(C) TX_FIFO = (C)>>8; TX_FIFO = (C)
#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); }
TX_FIFO = (C)>>24; TX_FIFO = (C)>>16; \
tft_Write_16((uint16_t) ((C)>>0))
#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); }
TX_FIFO = (C)>>8; TX_FIFO = (C); \
tft_Write_16((uint16_t) (D))
#define tft_Write_32D(C) \
{ spiBuffer[0] = spiBuffer[2] = (C)>>8; spiBuffer[1] = spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
TX_FIFO = (C)>>8; TX_FIFO = (C); \
tft_Write_16((uint16_t) (C))
#endif
#ifndef DC_DELAY
//#define DC_DELAY delayMicroseconds(1) // Premature BSY clear hardware bug?
#define DC_DELAY
#endif
#ifndef tft_Write_16N
#define tft_Write_16N tft_Write_16
#endif

View File

@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.5.42"
#define TFT_ESPI_VERSION "2.5.43"
// Bit level feature flags
// Bit 0 set: viewport capability

View File

@ -1,6 +1,6 @@
{
"name": "TFT_eSPI",
"version": "2.5.42",
"version": "2.5.43",
"keywords": "Arduino, tft, display, ttgo, LilyPi, WT32-SC01, ePaper, display, Pico, RP2040 Nano Connect, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, ST7796, RM68140, SSD1351, SSD1963, ILI9225, HX8357D, GC9A01, R61581",
"description": "A TFT and ePaper (SPI or parallel interface) graphics library with optimisation for Raspberry Pi Pico, RP2040, ESP8266, ESP32 and STM32 processors",
"repository":

View File

@ -1,5 +1,5 @@
name=TFT_eSPI
version=2.5.42
version=2.5.43
author=Bodmer
maintainer=Bodmer
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32