From 5a6ef1d05d19e2d4277b1cb8d0a0e7034aefad09 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 15 May 2021 19:45:33 +0100 Subject: [PATCH] Fix #1188 Support debugged for ILI9488 TFT with RP2040 processors. Minor improvements to ESP32 code. --- Processors/TFT_eSPI_ESP32.c | 37 ++++++++++++++++++++++++ Processors/TFT_eSPI_ESP32.h | 44 +++++++++++++++++++++++++++- Processors/TFT_eSPI_RP2040.c | 53 +++++++++++++++++++++++----------- Processors/TFT_eSPI_RP2040.h | 52 +++++++++++++++++++++------------ TFT_eSPI.cpp | 56 +++++++++++++++++++++++++++--------- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 8 files changed, 196 insertions(+), 52 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 62150cc..a715ebc 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -191,6 +191,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) ** 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); @@ -236,7 +237,43 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ } while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? } +//*/ +//* +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + volatile uint32_t* spi_w = _spi_w; + uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); + uint32_t i = 0; + uint32_t rem = len & 0x1F; + len = len - rem; + + // Start with partial buffer pixels + if (rem) + { + while (*_spi_cmd&SPI_USR); + for (i=0; i < rem; i+=2) *spi_w++ = color32; + *_spi_mosi_dlen = (rem << 4) - 1; + *_spi_cmd = SPI_USR; + if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } + i = i>>1; while(i++<16) *spi_w++ = color32; + } + + while (*_spi_cmd&SPI_USR); + if (!rem) while (i++<16) *spi_w++ = color32; + *_spi_mosi_dlen = 511; + + // End with full buffer to maximise useful time for downstream code + while(len) + { + while (*_spi_cmd&SPI_USR); + *_spi_cmd = SPI_USR; + len -= 32; + } + + // Do not wait here + //while (*_spi_cmd&SPI_USR); +} +//*/ /*************************************************************************************** ** Function name: pushSwapBytePixels - for ESP32 ** Description: Write a sequence of pixels with swapped bytes diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index b177ed6..0d0b255 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -71,6 +71,12 @@ #define DMA_BUSY_CHECK #endif +#if defined(TFT_PARALLEL_8_BIT) + #define SPI_BUSY_CHECK +#else + #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) +#endif + // If smooth font is used then it is likely SPIFFS will be needed #ifdef SMOOTH_FONT // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts @@ -382,6 +388,9 @@ spi.transfer(((C) & 0x07E0)>>3); \ spi.transfer(((C) & 0x001F)<<3) + // Future option for transfer without wait + #define tft_Write_16N(C) tft_Write_16(C) + // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ @@ -415,6 +424,9 @@ // Write 16 bits with corrected endianess for 16 bit colours #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + // Future option for transfer without wait + #define tft_Write_16N(C) tft_Write_16(C) + // Write 16 bits #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) @@ -432,7 +444,7 @@ // Macros for all other SPI displays //////////////////////////////////////////////////////////////////////////////////////// #else - +/* Old macros // ESP32 low level SPI writes for 8, 16 and 32 bit values // to avoid the function call overhead #define TFT_WRITE_BITS(D, B) \ @@ -458,7 +470,37 @@ // Write same value twice #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) +//*/ +//* Replacement slimmer macros + #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ + *_spi_w = D; \ + *_spi_cmd = SPI_USR; \ + while (*_spi_cmd & SPI_USR); + // Write 8 bits + #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) + + // Write 16 bits with corrected endianess for 16 bit colours + #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + + // Future option for transfer without wait + #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ + *_spi_w = ((C)<<8 | (C)>>8); \ + *_spi_cmd = SPI_USR; + + // Write 16 bits + #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) + + // Write 32 bits + #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) + + // Write two address coordinates + #define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + + // Write same value twice + #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + +//*/ #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_RP2040.c b/Processors/TFT_eSPI_RP2040.c index fbcbfe2..54fe007 100644 --- a/Processors/TFT_eSPI_RP2040.c +++ b/Processors/TFT_eSPI_RP2040.c @@ -7,9 +7,14 @@ //////////////////////////////////////////////////////////////////////////////////////// #if !defined (TFT_PARALLEL_8_BIT) - // Select the SPI port to use - //SPIClass& spi = SPI; - MbedSPI spi = MbedSPI(TFT_MISO, TFT_MOSI, TFT_SCLK); + // Select the SPI port and board package to use + #ifdef ARDUINO_ARCH_MBED + // Arduino RP2040 board package + MbedSPI spi = MbedSPI(TFT_MISO, TFT_MOSI, TFT_SCLK); + #else + // Community RP2040 board package by Earle Philhower + SPIClass& spi = SPI; + #endif #endif #ifdef RP2040_DMA @@ -185,12 +190,31 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) ***************************************************************************************/ 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; + uint16_t r = (color & 0xF800)>>8; + uint16_t g = (color & 0x07E0)>>3; + uint16_t b = (color & 0x001F)<<3; - while ( len-- ) {tft_Write_8(r); tft_Write_8(g); tft_Write_8(b);} + // If more than 32 pixels then change to 16 bit transfers with concatenated pixels + if (len > 32) { + uint32_t rg = r<<8 | g; + uint32_t br = b<<8 | r; + uint32_t gb = g<<8 | b; + // Must wait before changing to 16 bit + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + while ( len > 1 ) { + while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = rg; + while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = br; + while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = gb; + len -= 2; + } + // Must wait before changing back to 8 bit + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + } + + // Mop up the remaining pixels + while ( len-- ) {tft_Write_8N(r);tft_Write_8N(g);tft_Write_8N(b);} } /*************************************************************************************** @@ -202,19 +226,14 @@ 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++; + uint32_t col = *data++; + tft_Write_16(col); } } else { while ( len-- ) { - tft_Write_8((*data & 0xF800)>>8); - tft_Write_8((*data & 0x07E0)>>3); - tft_Write_8((*data & 0x001F)<<3); - data++; + uint32_t col = *data++; + tft_Write_16S(col); } } } diff --git a/Processors/TFT_eSPI_RP2040.h b/Processors/TFT_eSPI_RP2040.h index ba53db6..87ad0cf 100644 --- a/Processors/TFT_eSPI_RP2040.h +++ b/Processors/TFT_eSPI_RP2040.h @@ -8,7 +8,7 @@ #ifndef _TFT_eSPI_RP2040H_ #define _TFT_eSPI_RP2040H_ -#include "hardware/dma.h" +//#include "hardware/dma.h" // Processor ID reported by getSetup() #define PROCESSOR_ID 0x2040 @@ -17,7 +17,7 @@ // None // Processor specific code used by SPI bus transaction begin/end_tft_write functions -#define SET_BUS_WRITE_MODE spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) +#define SET_BUS_WRITE_MODE spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) #define SET_BUS_READ_MODE // spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST) // Code to check if SPI or DMA is busy, used by SPI bus transaction startWrite and/or endWrite functions @@ -56,6 +56,8 @@ #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 sio_hw->gpio_clr = (1ul << TFT_DC) + //#define DC_D sio_hw->gpio_set = (1ul << TFT_DC) #define DC_C sio_hw->gpio_clr = (1ul << TFT_DC) #define DC_D sio_hw->gpio_set = (1ul << TFT_DC) #endif @@ -110,30 +112,44 @@ #if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour // Write 8 bits to TFT - #define tft_Write_8(C) spi.transfer(C) + #define tft_Write_8(C) spi_get_hw(spi0)->dr = (uint32_t)(C); \ + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; \ + + //#define tft_Write_8(C) spi.transfer(C); + #define tft_Write_8N(B) while (!spi_is_writable(spi0)){}; \ + spi_get_hw(spi0)->dr = (uint8_t)(B) // 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) + #define tft_Write_16(C) tft_Write_8N(((C) & 0xF800)>>8); \ + tft_Write_8N(((C) & 0x07E0)>>3); \ + tft_Write_8N(((C) & 0x001F)<<3) // Convert 16 bit colour to 18 bit and write in 3 bytes - #define tft_Write_16N(C) spi.transfer(((C) & 0xF800)>>8); \ - spi.transfer(((C) & 0x07E0)>>3); \ - spi.transfer(((C) & 0x001F)<<3) + #define tft_Write_16N(C) tft_Write_8N(((C) & 0xF800)>>8); \ + tft_Write_8N(((C) & 0x07E0)>>3); \ + tft_Write_8N(((C) & 0x001F)<<3) // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes - #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ - spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ - spi.transfer(((C) & 0x1F00)>>5) + #define tft_Write_16S(C) tft_Write_8N((C) & 0xF8); \ + tft_Write_8N(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ + tft_Write_8N(((C) & 0x1F00)>>5) // Write 32 bits to TFT - #define tft_Write_32(C) spi.transfer16((C)>>16); spi.transfer16((uint16_t)(C)) + #define tft_Write_32(C) tft_Write_8N(C>>24); \ + tft_Write_8N(C>>16); \ + tft_Write_8N(C>>8); \ + tft_Write_8N(C) // Write two address coordinates - #define tft_Write_32C(C,D) spi.transfer16(C); spi.transfer16(D) + #define tft_Write_32C(C,D) tft_Write_8N(C>>8); \ + tft_Write_8N(C); \ + tft_Write_8N(D>>8); \ + tft_Write_8N(D) // Write same value twice - #define tft_Write_32D(C) spi.transfer16(C); spi.transfer16(C) + #define tft_Write_32D(C) tft_Write_8N(C>>8); \ + tft_Write_8N(C); \ + tft_Write_8N(C>>8); \ + tft_Write_8N(C) //////////////////////////////////////////////////////////////////////////////////////// // Macros to write commands/pixel colour data to other displays @@ -178,11 +194,11 @@ #define tft_Write_16S(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C)<<8 | (C)>>8 - #define tft_Write_32(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)((C)>>8);spi_get_hw(spi0)->dr = (uint32_t)(C) + #define tft_Write_32(C) spi_get_hw(spi0)->dr = (uint32_t)((C)>>16); spi_get_hw(spi0)->dr = (uint32_t)(C) - #define tft_Write_32C(C,D) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C);spi_get_hw(spi0)->dr = (uint32_t)(D) + #define tft_Write_32C(C,D) spi_get_hw(spi0)->dr = (uint32_t)(C); spi_get_hw(spi0)->dr = (uint32_t)(D) - #define tft_Write_32D(C) while (!spi_is_writable(spi0)){}; spi_get_hw(spi0)->dr = (uint32_t)(C);spi_get_hw(spi0)->dr = (uint32_t)(C) + #define tft_Write_32D(C) spi_get_hw(spi0)->dr = (uint32_t)(C); spi_get_hw(spi0)->dr = (uint32_t)(C) #endif // RPI_DISPLAY_TYPE #endif diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index c1ab01e..493d01f 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -28,6 +28,10 @@ #include "Processors/TFT_eSPI_Generic.c" #endif +#ifndef SPI_BUSY_CHECK + #define SPI_BUSY_CHECK +#endif + // Clipping macro for pushImage #define PI_CLIP \ if (_vpOoB) return; \ @@ -3041,7 +3045,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) #if defined (ILI9225_DRIVER) if (rotation & 0x01) { swap_coord(x0, y0); swap_coord(x1, y1); } - + SPI_BUSY_CHECK; DC_C; tft_Write_8(TFT_CASET1); DC_D; tft_Write_16(x0); DC_C; tft_Write_8(TFT_CASET2); @@ -3065,7 +3069,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) swap_coord(x0, y0); swap_coord(x1, y1); } - + SPI_BUSY_CHECK; DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_16(x1 | (x0 << 8)); DC_C; tft_Write_8(TFT_PASET); @@ -3088,7 +3092,9 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) #if defined(ARDUINO_ARCH_RP2040) && !defined(TFT_PARALLEL_8BIT) while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; DC_C; - spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + #if !defined (SPI_18BIT_DRIVER) + spi_set_format(spi0, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + #endif spi_get_hw(spi0)->dr = (uint32_t)TFT_CASET; while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; @@ -3114,10 +3120,13 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) spi_get_hw(spi0)->dr = (uint32_t)TFT_RAMWR; while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; - spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + #if !defined (SPI_18BIT_DRIVER) + spi_set_format(spi0, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST); + #endif DC_D; #else + SPI_BUSY_CHECK; DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(x0, x1); DC_C; tft_Write_8(TFT_PASET); @@ -3236,6 +3245,8 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) if (rotation & 0x01) { swap_coord(x, y); } + SPI_BUSY_CHECK; + // Set window to full screen to optimise sequential pixel rendering if (addr_row != 0x9225) { addr_row = 0x9225; // addr_row used for flag @@ -3258,7 +3269,11 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) // write to RAM DC_C; tft_Write_8(TFT_RAMWR); - DC_D; tft_Write_16(color); + #if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32) + DC_D; tft_Write_16(color); + #else + DC_D; tft_Write_16N(color); + #endif // Temporary solution is to include the RP2040 optimised code here #elif defined (ARDUINO_ARCH_RP2040) @@ -3292,11 +3307,19 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_C; spi_get_hw(spi0)->dr = (uint32_t)TFT_RAMWR; - while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; - DC_D; - spi_get_hw(spi0)->dr = (uint32_t)color>>8; - spi_get_hw(spi0)->dr = (uint32_t)color; - + #if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour + uint8_t r = (color & 0xF800)>>8; + uint8_t g = (color & 0x07E0)>>3; + uint8_t b = (color & 0x001F)<<3; + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + tft_Write_8N(r); tft_Write_8N(g); tft_Write_8N(b); + #else + while (spi_get_hw(spi0)->sr & SPI_SSPSR_BSY_BITS) {}; + DC_D; + spi_get_hw(spi0)->dr = (uint32_t)color>>8; + spi_get_hw(spi0)->dr = (uint32_t)color; + #endif /* // Subsequent pixel reads work OK without draining the FIFO... // Drain RX FIFO, then wait for shifting to finish (which may be *after* @@ -3323,6 +3346,8 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) if ((rotation & 0x1) == 0) { swap_coord(x, y); } #endif + SPI_BUSY_CHECK; + #if defined (MULTI_TFT_SUPPORT) || defined (GC9A01_DRIVER) // No optimisation DC_C; tft_Write_8(TFT_CASET); @@ -3359,7 +3384,12 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) } #endif DC_C; tft_Write_8(TFT_RAMWR); - DC_D; tft_Write_16(color); + + #if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32) + DC_D; tft_Write_16(color); + #else + DC_D; tft_Write_16N(color); + #endif #endif end_tft_write(); @@ -3495,11 +3525,11 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t dlen++; err -= dy; if (err < 0) { - err += dx; if (dlen == 1) drawPixel(y0, xs, color); else drawFastVLine(y0, xs, dlen, color); dlen = 0; y0 += ystep; xs = x0 + 1; + err += dx; } } if (dlen) drawFastVLine(y0, xs, dlen, color); @@ -3510,11 +3540,11 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t dlen++; err -= dy; if (err < 0) { - err += dx; if (dlen == 1) drawPixel(xs, y0, color); else drawFastHLine(xs, y0, dlen, color); dlen = 0; y0 += ystep; xs = x0 + 1; + err += dx; } } if (dlen) drawFastHLine(xs, y0, dlen, color); diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 55df84a..d97890f 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.3.66" +#define TFT_ESPI_VERSION "2.3.68" // Bit level feature flags // Bit 0 set: viewport capability diff --git a/library.json b/library.json index daa221a..5464738 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.3.67", + "version": "2.3.68", "keywords": "Arduino, tft, ePaper, display, Pico, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, RM68140, SSD1351, SSD1963, ILI9225, HX8357D", "description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index d05d070..4871c2f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.3.67 +version=2.3.68 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32