From 1476da56ba52938cbca31d8578383871bf05cd7a Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 11 Jan 2020 00:58:38 +0000 Subject: [PATCH] Restructured code, added ST7796 RPi MHS-4.0 inch Display-B type display now supported. --- Extensions/Smooth_font.cpp | 125 +- Extensions/Smooth_font.h | 2 - Extensions/Sprite.cpp | 205 +- Extensions/Sprite.h | 39 +- Fonts/Font16.c | 2 - Fonts/Font32rle.c | 2 - Fonts/Font64rle.c | 3 - Fonts/Font72rle.c | 2 - Fonts/Font72x53rle.c | 2 - Fonts/Font7srle.c | 2 - Fonts/GFXFF/gfxfont.h | 67 +- Fonts/glcdfont.c | 2 - Processors/TFT_eSPI_ESP32.c | 475 +++++ Processors/TFT_eSPI_ESP32.h | 354 ++++ Processors/TFT_eSPI_ESP8266.c | 403 ++++ Processors/TFT_eSPI_ESP8266.h | 243 +++ README.md | 17 +- TFT_Drivers/ST7796_Defines.h | 108 ++ TFT_Drivers/ST7796_Init.h | 110 ++ TFT_Drivers/ST7796_Rotation.h | 50 + TFT_eSPI.cpp | 2213 ++++------------------ TFT_eSPI.h | 458 +---- User_Setup.h | 4 + User_Setup_Select.h | 10 +- User_Setups/Setup27_RPi_ST7796_ESP32.h | 100 + User_Setups/Setup28_RPi_ST7796_ESP8266.h | 105 + keywords.txt | 18 +- library.json | 2 +- library.properties | 2 +- 29 files changed, 2741 insertions(+), 2384 deletions(-) create mode 100644 Processors/TFT_eSPI_ESP32.c create mode 100644 Processors/TFT_eSPI_ESP32.h create mode 100644 Processors/TFT_eSPI_ESP8266.c create mode 100644 Processors/TFT_eSPI_ESP8266.h create mode 100644 TFT_Drivers/ST7796_Defines.h create mode 100644 TFT_Drivers/ST7796_Init.h create mode 100644 TFT_Drivers/ST7796_Rotation.h create mode 100644 User_Setups/Setup27_RPi_ST7796_ESP32.h create mode 100644 User_Setups/Setup28_RPi_ST7796_ESP8266.h diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index c835b48b..b19456b8 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -57,9 +57,6 @@ void TFT_eSPI::loadFont(String fontName, bool flash) a zero/one terminated character string giving the font name last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) - Then the font name seen by Java when it's created - Then the postscript name of the font - Then a boolean to tell if smoothing is on or not. Glyph bitmap example is: // Cursor coordinate positions for this and next character are marked by 'C' @@ -79,7 +76,7 @@ void TFT_eSPI::loadFont(String fontName, bool flash) // | + x..@@@@@@@..x | x marks the corner pixels of the bitmap // | | // +---------------------------+ yAdvance is y delta for the next line, font size or (ascent + descent) - // some fonts can overlay in y direction so may need a user adjust value + // some fonts can overlay in y direction so may need a user adjust value */ @@ -277,126 +274,6 @@ void TFT_eSPI::unloadFont( void ) } -/*************************************************************************************** -** Function name: decodeUTF8 -** Description: Line buffer UTF-8 decoder with fall-back to extended ASCII -*************************************************************************************x*/ -/* Function moved to TFT_eSPI.cpp -#define DECODE_UTF8 -uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining) -{ - byte c = buf[(*index)++]; - //Serial.print("Byte from string = 0x"); Serial.println(c, HEX); - -#ifdef DECODE_UTF8 - // 7 bit Unicode - if ((c & 0x80) == 0x00) return c; - - // 11 bit Unicode - if (((c & 0xE0) == 0xC0) && (remaining > 1)) - return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F); - - // 16 bit Unicode - if (((c & 0xF0) == 0xE0) && (remaining > 2)) - { - c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6); - return c | ((buf[(*index)++]&0x3F)); - } - - // 21 bit Unicode not supported so fall-back to extended ASCII - // if ((c & 0xF8) == 0xF0) return c; -#endif - - return c; // fall-back to extended ASCII -} -*/ - -/*************************************************************************************** -** Function name: decodeUTF8 -** Description: Serial UTF-8 decoder with fall-back to extended ASCII -*************************************************************************************x*/ -/* Function moved to TFT_eSPI.cpp -uint16_t TFT_eSPI::decodeUTF8(uint8_t c) -{ - -#ifdef DECODE_UTF8 - - // 7 bit Unicode - if ((c & 0x80) == 0x00) { - decoderState = 0; - return (uint16_t)c; - } - - if (decoderState == 0) - { - // 11 bit Unicode - if ((c & 0xE0) == 0xC0) - { - decoderBuffer = ((c & 0x1F)<<6); - decoderState = 1; - return 0; - } - - // 16 bit Unicode - if ((c & 0xF0) == 0xE0) - { - decoderBuffer = ((c & 0x0F)<<12); - decoderState = 2; - return 0; - } - // 21 bit Unicode not supported so fall-back to extended ASCII - if ((c & 0xF8) == 0xF0) return (uint16_t)c; - } - else - { - if (decoderState == 2) - { - decoderBuffer |= ((c & 0x3F)<<6); - decoderState--; - return 0; - } - else - { - decoderBuffer |= (c & 0x3F); - decoderState = 0; - return decoderBuffer; - } - } -#endif - - decoderState = 0; - return (uint16_t)c; // fall-back to extended ASCII -} -*/ - - -/*************************************************************************************** -** Function name: alphaBlend -** Description: Blend foreground and background and return new colour -*************************************************************************************x*/ -uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc) -{ - // For speed use fixed point maths and rounding to permit a power of 2 division - uint16_t fgR = ((fgc >> 10) & 0x3E) + 1; - uint16_t fgG = ((fgc >> 4) & 0x7E) + 1; - uint16_t fgB = ((fgc << 1) & 0x3E) + 1; - - uint16_t bgR = ((bgc >> 10) & 0x3E) + 1; - uint16_t bgG = ((bgc >> 4) & 0x7E) + 1; - uint16_t bgB = ((bgc << 1) & 0x3E) + 1; - - // Shift right 1 to drop rounding bit and shift right 8 to divide by 256 - uint16_t r = (((fgR * alpha) + (bgR * (255 - alpha))) >> 9); - uint16_t g = (((fgG * alpha) + (bgG * (255 - alpha))) >> 9); - uint16_t b = (((fgB * alpha) + (bgB * (255 - alpha))) >> 9); - - // Combine RGB565 colours into 16 bits - //return ((r&0x18) << 11) | ((g&0x30) << 5) | ((b&0x18) << 0); // 2 bit greyscale - //return ((r&0x1E) << 11) | ((g&0x3C) << 5) | ((b&0x1E) << 0); // 4 bit greyscale - return (r << 11) | (g << 5) | (b << 0); -} - - /*************************************************************************************** ** Function name: readInt32 ** Description: Get a 32 bit integer from the font file diff --git a/Extensions/Smooth_font.h b/Extensions/Smooth_font.h index a7e2ca68..37331f6a 100644 --- a/Extensions/Smooth_font.h +++ b/Extensions/Smooth_font.h @@ -9,8 +9,6 @@ void unloadFont( void ); bool getUnicodeIndex(uint16_t unicode, uint16_t *index); - uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc); - virtual void drawGlyph(uint16_t code); void showFont(uint32_t td); diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 9c9c18dc..344fe347 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -269,13 +269,116 @@ int16_t TFT_eSprite::getPivotY(void) /*************************************************************************************** -** Function name: pushRotated -** Description: Push a rotated copy of the Sprite to TFT screen +** Function name: pushRotated - Fast fixed point integer maths version +** Description: Push rotated Sprite to TFT screen *************************************************************************************x*/ +#define FP_SCALE 10 bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) { if ( !_created ) return false; + // Trig values for the rotation + float radAngle = -angle * 0.0174532925; // Convert degrees to radians + float sinraf = sin(radAngle); + float cosraf = cos(radAngle); + + int32_t sinra = sinraf * (1<_xpivot; + max_x += _tft->_xpivot; + min_y += _tft->_ypivot; + max_y += _tft->_ypivot; + + // Test only to show bounding box on TFT + // _tft->drawRect(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1, TFT_GREEN); + + // Return if bounding box is outside of TFT area + if (min_x > _tft->width()) return true; + if (min_y > _tft->height()) return true; + if (max_x < 0) return true; + if (max_y < 0) return true; + + // Clip bounding box to be within TFT area + if (min_x < 0) min_x = 0; + if (min_y < 0) min_y = 0; + if (max_x > _tft->width()) max_x = _tft->width(); + if (max_y > _tft->height()) max_y = _tft->height(); + + uint16_t sline_buffer[max_y - min_y + 1]; + + int32_t xt = min_x - _tft->_xpivot; + int32_t yt = min_y - _tft->_ypivot; + + // Keep multiply out of the loop + int32_t cxt = cosra * xt + (_xpivot<startWrite(); // ESP32: avoid transaction overhead for every tft pixel + + // Scan destination bounding box and fetch transformed pixels from source Sprite + for (int32_t x = min_x; x <= max_x; x++) { + cxt += cosra; + sxt += sinra; + bool column_drawn = false; + uint32_t pixel_count = 0; + int32_t y_start = 0; + int32_t xs = cxt - init_syt; + int32_t cyt = init_cyt; + for (int32_t y = min_y; y <= max_y; y++) { + cyt += cosra; + xs -= sinra; + // Do not calculate yp unless xp is in bounds + int32_t xp = truncateFP(xs, FP_SCALE); + if ((xp >= 0) && (xp < _iwidth)) + { + int32_t yp = truncateFP(sxt + cyt, FP_SCALE); + // Check if yp is in bounds + if ((yp >= 0) && (yp < _iheight)) { + uint32_t rp; + if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; } + else rp = readPixel(xp, yp); + if (transp >= 0 ) { + if (rp != transp) _tft->drawPixel(x, y, rp); + } + else { + if (!column_drawn) y_start = y; + sline_buffer[pixel_count++] = rp>>8 | rp<<8; + } + column_drawn = true; + } + } + else if (column_drawn) y = max_y; // Skip remaining column pixels + } + if (pixel_count) _tft->pushImage(x, y_start, 1, pixel_count, sline_buffer); + } + + _tft->endWrite(); // ESP32: end transaction + + return true; +} + + +/*************************************************************************************** +** Function name: pushRotatedHP - Higher Precision version of pushRotated +** Description: Push rotated Sprite to TFT screen +*************************************************************************************x*/ +bool TFT_eSprite::pushRotatedHP(int16_t angle, int32_t transp) +{ + if ( !_created ) return false; + // Trig values for the rotation float radAngle = -angle * 0.0174532925; // Convert degrees to radians float sinra = sin(radAngle); @@ -308,7 +411,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) // Clip bounding box to be within TFT area if (min_x < 0) min_x = 0; if (min_y < 0) min_y = 0; - if (max_x > _tft->width()) max_x = _tft->width(); + if (max_x > _tft->width()) max_x = _tft->width(); if (max_y > _tft->height()) max_y = _tft->height(); _tft->startWrite(); // ESP32: avoid transaction overhead for every tft pixel @@ -344,7 +447,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) /*************************************************************************************** -** Function name: pushRotated +** Function name: pushRotated - Fast fixed point integer maths version ** Description: Push a rotated copy of the Sprite to another Sprite *************************************************************************************x*/ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) @@ -352,6 +455,89 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) if ( !_created ) return false; // Check this Sprite is created if ( !spr->_created ) return false; // Ckeck destination Sprite is created + // Trig values for the rotation + float radAngle = -angle * 0.0174532925; // Convert degrees to radians + float sinraf = sin(radAngle); + float cosraf = cos(radAngle); + + int32_t sinra = sinraf * (1<_xpivot; + max_x += spr->_xpivot; + min_y += spr->_ypivot; + max_y += spr->_ypivot; + + // Test only to show bounding box + // spr->fillSprite(TFT_BLACK); + // spr->drawRect(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1, TFT_GREEN); + + // Return if bounding box is completely outside of destination Sprite + if (min_x > spr->width()) return true; + if (min_y > spr->height()) return true; + if (max_x < 0) return true; + if (max_y < 0) return true; + + // Clip bounding box if it is partially within destination Sprite + if (min_x < 0) min_x = 0; + if (min_y < 0) min_y = 0; + if (max_x > spr->width()) max_x = spr->width(); + if (max_y > spr->height()) max_y = spr->height(); + + // Scan destination bounding box and fetch transformed pixels from source Sprite + for (int32_t x = min_x; x <= max_x; x++) + { + int32_t xt = x - spr->_xpivot; + float cxt = cosra * xt + (_xpivot<_ypivot; + int32_t xs = cxt - sinra * yt; + // Do not calculate yp unless xp is in bounds + int32_t xp = truncateFP(xs, FP_SCALE); + if (xp >= 0 && xp < _iwidth) + { + int32_t ys = sxt + cosra * yt; + // Check if ys is in bounds + int32_t yp = truncateFP(ys, FP_SCALE); + if (yp >= 0 && yp < _iheight) + { + uint32_t rp; + if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; } + else rp = readPixel(xp, yp); + if (rp != transp) spr->drawPixel(x, y, rp); + column_drawn = true; + } + } + else if (column_drawn) y = max_y; // Skip the remaining pixels below the Sprite + } + } + + return true; +} + + +/*************************************************************************************** +** Function name: pushRotated - Higher Precision version of pushRotated +** Description: Push a rotated copy of the Sprite to another Sprite +*************************************************************************************x*/ +bool TFT_eSprite::pushRotatedHP(TFT_eSprite *spr, int16_t angle, int32_t transp) +{ + if ( !_created ) return false; // Check this Sprite is created + if ( !spr->_created ) return false; // Ckeck destination Sprite is created + // Trig values for the rotation float radAngle = -angle * 0.0174532925; // Convert degrees to radians float sinra = sin(radAngle); @@ -385,7 +571,7 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) // Clip bounding box if it is partially within destination Sprite if (min_x < 0) min_x = 0; if (min_y < 0) min_y = 0; - if (max_x > spr->width()) max_x = spr->width(); + if (max_x > spr->width()) max_x = spr->width(); if (max_y > spr->height()) max_y = spr->height(); // Scan destination bounding box and fetch transformed pixels from source Sprite @@ -516,7 +702,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) *************************************************************************************x*/ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) { - if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0; + if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFFFF; if (_bpp == 16) { @@ -557,7 +743,8 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) uint16_t color = (_img8[(x + y * _bitwidth)>>3] << (x & 0x7)) & 0x80; - return color >> 7; + if (color >> 7) return _tft->bitmap_fg; + else return _tft->bitmap_bg; } @@ -1148,7 +1335,7 @@ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint3 { if (!_created ) return; - boolean steep = abs(y1 - y0) > abs(x1 - x0); + bool steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap_coord(x0, y0); swap_coord(x1, y1); @@ -1492,7 +1679,7 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uin #endif //>>>>>>>>>>>>>>>>>> - boolean fillbg = (bg != color); + bool fillbg = (bg != color); if ((size==1) && fillbg) { diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 09574be6..e94577df 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -5,22 +5,29 @@ // graphics are written to the Sprite rather than the TFT. ***************************************************************************************/ +// pushRotated support - Bitwise truncation of fixed point integer value V scaled by S +//#define truncateFP(V,S) ((V + (V < 0 ? -1<<(S-1) : 0))>>S) +#define truncateFP(V,S) ((V + (V < 0 ? -1<<(S-1) : 1<<(S-1)))>>S) + class TFT_eSprite : public TFT_eSPI { public: TFT_eSprite(TFT_eSPI *tft); - virtual ~TFT_eSprite(); // Create a sprite of width x height pixels, return a pointer to the RAM area // Sketch can cast returned value to (uint16_t*) for 16 bit depth if needed - // RAM required is 1 byte per pixel for 8 bit colour depth, 2 bytes for 16 bit + // RAM required is: + // - 1 bit per pixel for 1 bit colour depth + // - 1 byte per pixel for 8 bit colour + // - 2 bytes per pixel for 16 bit color depth void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); // Delete the sprite to free up the RAM void deleteSprite(void); - // Select the frame buffer for graphics + // Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer) + // Returns a pointer to the Sprite frame buffer void* frameBuffer(int8_t f); // Set or get the colour depth to 8 or 16 bits. Can be used to change depth an existing @@ -28,18 +35,22 @@ class TFT_eSprite : public TFT_eSPI { void* setColorDepth(int8_t b); int8_t getColorDepth(void); - void setBitmapColor(uint16_t c, uint16_t b); + // Set foreground and background colours for 1 bit per pixel Sprite + void setBitmapColor(uint16_t fg, uint16_t bg); void drawPixel(int32_t x, int32_t y, uint32_t color); - void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), + void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t font), + // Fill Sprite with a colour fillSprite(uint32_t color), // Define a window to push 16 bit colour pixels into in a raster order - // Colours are converted to 8 bit if depth is set to 8 + // Colours are converted to the set Sprite colour bit depth setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1), + // Push a color (aka singe pixel) to the screen pushColor(uint32_t color), + // Push len colors (pixels) to the screen pushColor(uint32_t color, uint16_t len), // Push a pixel preformatted as a 8 or 16 bit colour (avoids conversion overhead) writeColor(uint16_t color), @@ -52,23 +63,29 @@ class TFT_eSprite : public TFT_eSPI { // The sprite coordinate frame does not move because pixels are moved scroll(int16_t dx, int16_t dy = 0), + // Draw lines drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), + // Fill a rectangular area with a color (aka draw a filled rectangle) fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); // Set the sprite text cursor position for print class (does not change the TFT screen cursor) - //setCursor(int16_t x, int16_t y); + //setCursor(int16_t x, int16_t y); // Not needed, so uses TFT class function - // Set the rotation of the Sprite (for 1bpp Sprites only) + // Set the coordinate rotation of the Sprite (for 1bpp Sprites only) + // Note: this uses coordinate rotation and is primarily for ePaper which does not support + // CGRAM rotation (like TFT drivers do) within the displays internal hardware void setRotation(uint8_t rotation); uint8_t getRotation(void); // Push a rotated copy of Sprite to TFT with optional transparent colour - bool pushRotated(int16_t angle, int32_t transp = -1); + bool pushRotated(int16_t angle, int32_t transp = -1); // Using fixed point maths + bool pushRotatedHP(int16_t angle, int32_t transp = -1); // Using higher precision floating point maths // Push a rotated copy of Sprite to another different Sprite with optional transparent colour - bool pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp = -1); + bool pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp = -1); // Using fixed point maths + bool pushRotatedHP(TFT_eSprite *spr, int16_t angle, int32_t transp = -1); // Using higher precision floating point maths // Set and get the pivot point for this Sprite void setPivot(int16_t x, int16_t y); int16_t getPivotX(void), @@ -138,7 +155,7 @@ class TFT_eSprite : public TFT_eSPI { uint32_t _sw, _sh; // w,h for scroll zone uint32_t _scolor; // gap fill colour for scroll zone - boolean _iswapBytes; // Swap the byte order for Sprite pushImage() + bool _iswapBytes; // Swap the byte order for Sprite pushImage() int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations) int32_t _dwidth, _dheight; // Real display width and height (for <8bpp Sprites) diff --git a/Fonts/Font16.c b/Fonts/Font16.c index 2f8ad464..9a249592 100644 --- a/Fonts/Font16.c +++ b/Fonts/Font16.c @@ -7,8 +7,6 @@ // Comment out next line to return character 0x60 to the grave accent: #define TFT_ESPI_GRAVE_IS_DEGREE -#include - // Width has been increased by 1 pixel so pixel lengths are calculated correctly // for the displayed string diff --git a/Fonts/Font32rle.c b/Fonts/Font32rle.c index 561c5596..321ec862 100644 --- a/Fonts/Font32rle.c +++ b/Fonts/Font32rle.c @@ -4,8 +4,6 @@ // // This font contains 96 ASCII characters -#include - PROGMEM const unsigned char widtbl_f32[96] = // character width table { diff --git a/Fonts/Font64rle.c b/Fonts/Font64rle.c index c474581f..9d1415b0 100644 --- a/Fonts/Font64rle.c +++ b/Fonts/Font64rle.c @@ -7,9 +7,6 @@ // All other characters print as a space -#include - - PROGMEM const unsigned char widtbl_f64[96] = // character width table { 12, 12, 12, 12, 12, 12, 12, 12, // char 32 - 39 diff --git a/Fonts/Font72rle.c b/Fonts/Font72rle.c index bd60b1c7..7f5da5df 100644 --- a/Fonts/Font72rle.c +++ b/Fonts/Font72rle.c @@ -6,8 +6,6 @@ // This font only contains characters [space] 0 1 2 3 4 5 6 7 8 9 0 : - . // All other characters print as a space -#include - PROGMEM const unsigned char widtbl_f72[96] = // character width table { diff --git a/Fonts/Font72x53rle.c b/Fonts/Font72x53rle.c index bcce9cbd..71c2c4f6 100644 --- a/Fonts/Font72x53rle.c +++ b/Fonts/Font72x53rle.c @@ -7,8 +7,6 @@ // This font only contains characters [space] 0 1 2 3 4 5 6 7 8 9 0 : - . // All other characters print as a space -#include - PROGMEM const unsigned char widtbl_f72[96] = // character width table { diff --git a/Fonts/Font7srle.c b/Fonts/Font7srle.c index bb292d7c..e66d03c4 100644 --- a/Fonts/Font7srle.c +++ b/Fonts/Font7srle.c @@ -6,8 +6,6 @@ // This font only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - // All other characters print as a space -#include - PROGMEM const unsigned char widtbl_f7s[96] = // character width table { diff --git a/Fonts/GFXFF/gfxfont.h b/Fonts/GFXFF/gfxfont.h index cd2bcccb..253f50ce 100644 --- a/Fonts/GFXFF/gfxfont.h +++ b/Fonts/GFXFF/gfxfont.h @@ -1,4 +1,4 @@ -// Adopted by Bodmer to support TFT_HX8357_Due library. +// Adopted by Bodmer to support TFT_eSPI library. // Font structures for newer Adafruit_GFX (1.1 and later). // Example fonts are included in 'Fonts' directory. @@ -25,6 +25,71 @@ typedef struct { // Data stored for FONT AS A WHOLE: uint8_t yAdvance; // Newline distance (y axis) } GFXfont; + // Original Adafruit_GFX "Free Fonts" + #include // TT1 + + #include // FF1 or FM9 + #include // FF2 or FM12 + #include // FF3 or FM18 + #include // FF4 or FM24 + + #include // FF5 or FMO9 + #include // FF6 or FMO12 + #include // FF7 or FMO18 + #include // FF8 or FMO24 + + #include // FF9 or FMB9 + #include // FF10 or FMB12 + #include // FF11 or FMB18 + #include // FF12 or FMB24 + + #include // FF13 or FMBO9 + #include // FF14 or FMBO12 + #include // FF15 or FMBO18 + #include // FF16 or FMBO24 + + // Sans serif fonts + #include // FF17 or FSS9 + #include // FF18 or FSS12 + #include // FF19 or FSS18 + #include // FF20 or FSS24 + + #include // FF21 or FSSO9 + #include // FF22 or FSSO12 + #include // FF23 or FSSO18 + #include // FF24 or FSSO24 + + #include // FF25 or FSSB9 + #include // FF26 or FSSB12 + #include // FF27 or FSSB18 + #include // FF28 or FSSB24 + + #include // FF29 or FSSBO9 + #include // FF30 or FSSBO12 + #include // FF31 or FSSBO18 + #include // FF32 or FSSBO24 + + // Serif fonts + #include // FF33 or FS9 + #include // FF34 or FS12 + #include // FF35 or FS18 + #include // FF36 or FS24 + + #include // FF37 or FSI9 + #include // FF38 or FSI12 + #include // FF39 or FSI18 + #include // FF40 or FSI24 + + #include // FF41 or FSB9 + #include // FF42 or FSB12 + #include // FF43 or FSB18 + #include // FF44 or FSB24 + + #include // FF45 or FSBI9 + #include // FF46 or FSBI12 + #include // FF47 or FSBI18 + #include // FF48 or FSBI24 + #endif // LOAD_GFXFF #endif // _GFXFONT_H_ diff --git a/Fonts/glcdfont.c b/Fonts/glcdfont.c index 2123eb7c..882a133b 100644 --- a/Fonts/glcdfont.c +++ b/Fonts/glcdfont.c @@ -3,8 +3,6 @@ #ifndef FONT5X7_H #define FONT5X7_H -#include - // Standard ASCII 5x7 font static const unsigned char font[] PROGMEM = { diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c new file mode 100644 index 00000000..8a41a667 --- /dev/null +++ b/Processors/TFT_eSPI_ESP32.c @@ -0,0 +1,475 @@ + //////////////////////////////////////////////////// + // 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; + #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: 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; + while ( len-- ) {tft_Write_16(*data); data++;} +} + +/*************************************************************************************** +** 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; + if(_swapBytes) { while ( len-- ) {tft_Write_16(*data); data++;} } + else { while ( len-- ) {tft_Write_16S(*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); WR_L; WR_H; + 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 +//////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h new file mode 100644 index 00000000..5626c120 --- /dev/null +++ b/Processors/TFT_eSPI_ESP32.h @@ -0,0 +1,354 @@ + //////////////////////////////////////////////////// + // 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" + +// Processor specific code used by SPI bus transaction startWrite and endWrite functions +#define SET_SPI_WRITE_MODE // Not used +#define SET_SPI_READ_MODE // Not used + +// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions +#define DMA_BUSY_CHECK // DMA not implemented for this processor (yet) + +// 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 + +// If it is a 16bit serial display we must transfer 16 bits every time +// Set commands bits to 16 or 8 +#ifdef RPI_ILI9486_DRIVER + #ifndef RPI_DRIVER + #define RPI_DRIVER + #endif +#endif + +#ifdef RPI_DRIVER + #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 + #define TFT_PARALLEL_8_BIT // Generic parallel flag +#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 + #include "SPIFFS.h" // ESP32 only +#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_DRIVER // 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_ILI9486_DRIVER // RPi ILI9486 display needs a slower DC change + #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1ts = (1 << TFT_DC) + #elif defined (RPI_DRIVER) // 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_ILI9486_DRIVER // 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_ILI9486_DRIVER // 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 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) + + // 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)<>6)<>5)<>4)<>3)<>2)<>1)<>0)<> 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_DRIVER) + + // 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 diff --git a/Processors/TFT_eSPI_ESP8266.c b/Processors/TFT_eSPI_ESP8266.c new file mode 100644 index 00000000..9dd834fe --- /dev/null +++ b/Processors/TFT_eSPI_ESP8266.c @@ -0,0 +1,403 @@ + + ////////////////////////////////////////////////////// + // 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; + 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; + while ( len-- ) {tft_Write_16S(*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 +//////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP8266.h b/Processors/TFT_eSPI_ESP8266.h new file mode 100644 index 00000000..a4bfcf5a --- /dev/null +++ b/Processors/TFT_eSPI_ESP8266.h @@ -0,0 +1,243 @@ + ////////////////////////////////////////////////////// + // 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_SPI_WRITE_MODE SPI1U=SPI1U_WRITE +#define SET_SPI_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 +#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 + +// If it is a 16bit serial display we must transfer 16 bits every time +// Set commands bits to 16 or 8 +#ifdef RPI_ILI9486_DRIVER + #ifndef RPI_DRIVER + #define RPI_DRIVER + #endif +#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_DRIVER) + // Command is 16 bits + #define CMD_BITS 16 + + // ESP32 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-1) + + #define tft_Write_8(C) \ + SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); \ + SPI1W0 = (C)<<(CMD_BITS + 1 - 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 diff --git a/README.md b/README.md index 00e61057..79e35587 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,12 @@ You can take this one step further and have your own setup select file and then To select a new setup you then edit your own my_setup_select.h file (which will not get over-written during an upgrade). # News -1. A new beta test branch has been added to support other processors, in particular STM32: +1. The ST7789 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28. + +2. A new beta test branch has been added to support other processors, in particular STM32: https://github.com/Bodmer/TFT_eSPI/tree/STM32 -2. A callback function has been added, this allows antialiased fonts to be rendered over colour gradients or images. Two new examples have been added to illustrate this new capability: +3. A callback function has been added, this allows antialiased fonts to be rendered over colour gradients or images. Two new examples have been added to illustrate this new capability: "Smooth_font_reading_TFT" @@ -23,25 +25,22 @@ To select a new setup you then edit your own my_setup_select.h file (which will ![AA_gradien](https://i.imgur.com/YMBcPHp.png) -3. Sprites can now by pushed to the screen (or another Sprite) with a rotation angle. The new function is pushRotated(). Three new examples (Rotate_Sprite_1/2/3) have been added to show how the functions can be used to rotate text, images and to draw animated dials with moving needles. +4. Sprites can now by pushed to the screen (or another Sprite) with a rotation angle. The new function is pushRotated(). Three new examples (Rotate_Sprite_1/2/3) have been added to show how the functions can be used to rotate text, images and to draw animated dials with moving needles. -4. A new TFT_eFEX support library has been created which includes extra functions such as drawing a BMP or Jpeg to the screen. This library will simplify the examples. It will be expanded at a future date to include meters, dials and GUI elements like progress bars, graphs and animated buttons: +5. A new TFT_eFEX support library has been created which includes extra functions such as drawing a BMP or Jpeg to the screen. This library will simplify the examples. It will be expanded at a future date to include meters, dials and GUI elements like progress bars, graphs and animated buttons: https://github.com/Bodmer/TFT_eFEX -5. androdlang has published a really nice companion library to extend the graphics capabilities of TFT_eSPI, you can find this here: -https://github.com/androdlang/TFTShape - 6. I have created a user updateable graphics extension library template that can be used to create your own graphics extensions. The Library contains examples and is commented so it should be clear what you need to do to add functions. You can find it here: https://github.com/Bodmer/TFT_eFX # TFT_eSPI -An Arduino IDE compatible graphics and fonts library for ESP8266 and ESP32 processors with drivers for ILI9341, ILI9163, ST7735, S6D02A1, ILI9481, ILI9486, ILI9488, HX8357D and ST7789 based TFT displays that support SPI. The library can be loaded using the Arduino IDE's Library Manager. +An Arduino IDE compatible graphics and fonts library for ESP8266 and ESP32 processors with drivers for ILI9341, ILI9163, ST7735, S6D02A1, ILI9481, ILI9486, ILI9488, HX8357D, ST7789 and ST7796 based TFT displays that support SPI. The library can be loaded using the Arduino IDE's Library Manager. 8 bit parallel interface TFTs (e.g. UNO format mcufriend shields) can used with an ESP32. -The library supports TFT displays designed for the Raspberry Pi that are based on a ILI9486 driver chip with a 480 x 320 pixel screen. This display must be of the Waveshare design and use a 16 bit serial interface based on the 74HC04, 74HC4040 and 2 x 74HC4094 logic chips. A modification to these displays is possible (see mod image in Tools folder) to make many graphics functions much faster (e.g. 23ms to clear the screen, 1.2ms to draw a 72 pixel high numeral). +The library supports TFT displays designed for the Raspberry Pi (RPi) that are based on a ILI9486 or ST7796 driver chip with a 480 x 320 pixel screen. The ILI9486 RPi display must be of the Waveshare design and use a 16 bit serial interface based on the 74HC04, 74HC4040 and 2 x 74HC4094 logic chips. A modification to these displays is possible (see mod image in Tools folder) to make many graphics functions much faster (e.g. 23ms to clear the screen, 1.2ms to draw a 72 pixel high numeral). The RPi ST7796 display is superior to the Waveshare design, it must be of the MHS-4.0 inch Display-B type. Some displays permit the internal TFT screen RAM to be read. The library supports reading from ILI9341, ST7789 and ILI9488 SPI displays for the ESP32 and ESP8266. The 8 bit parallel displays used with the ESP32 can usually can be read too. The TFT_Screen_Capture example allows full screens to be captured and sent to a PC, this is handy to create program documentation. diff --git a/TFT_Drivers/ST7796_Defines.h b/TFT_Drivers/ST7796_Defines.h new file mode 100644 index 00000000..ffab0e99 --- /dev/null +++ b/TFT_Drivers/ST7796_Defines.h @@ -0,0 +1,108 @@ +// Change the width and height if required (defined in portrait mode) +// or use the constructor to over-ride defaults +#define TFT_WIDTH 320 +#define TFT_HEIGHT 480 + +// Generic commands used by TFT_eSPI.cpp +#define TFT_NOP 0x00 +#define TFT_SWRST 0x01 + +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C + +#define TFT_RAMRD 0x2E +#define TFT_IDXRD 0xDD // ILI9341 only, indexed control register read + +#define TFT_MADCTL 0x36 +#define TFT_MAD_MY 0x80 +#define TFT_MAD_MX 0x40 +#define TFT_MAD_MV 0x20 +#define TFT_MAD_ML 0x10 +#define TFT_MAD_BGR 0x08 +#define TFT_MAD_MH 0x04 +#define TFT_MAD_RGB 0x00 + +#ifdef TFT_RGB_ORDER + #if (TFT_RGB_ORDER == 1) + #define TFT_MAD_COLOR_ORDER TFT_MAD_RGB + #else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR + #endif +#else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR +#endif + +#define TFT_INVOFF 0x20 +#define TFT_INVON 0x21 + + +// All ST7796 specific commands some are used by init() +#define ST7796_NOP 0x00 +#define ST7796_SWRESET 0x01 +#define ST7796_RDDID 0x04 +#define ST7796_RDDST 0x09 + +#define ST7796_SLPIN 0x10 +#define ST7796_SLPOUT 0x11 +#define ST7796_PTLON 0x12 +#define ST7796_NORON 0x13 + +#define ST7796_RDMODE 0x0A +#define ST7796_RDMADCTL 0x0B +#define ST7796_RDPIXFMT 0x0C +#define ST7796_RDIMGFMT 0x0A +#define ST7796_RDSELFDIAG 0x0F + +#define ST7796_INVOFF 0x20 +#define ST7796_INVON 0x21 +#define ST7796_GAMMASET 0x26 +#define ST7796_DISPOFF 0x28 +#define ST7796_DISPON 0x29 + +#define ST7796_CASET 0x2A +#define ST7796_PASET 0x2B +#define ST7796_RAMWR 0x2C +#define ST7796_RAMRD 0x2E + +#define ST7796_PTLAR 0x30 +#define ST7796_VSCRDEF 0x33 +#define ST7796_MADCTL 0x36 +#define ST7796_VSCRSADD 0x37 +#define ST7796_PIXFMT 0x3A + +#define ST7796_WRDISBV 0x51 +#define ST7796_RDDISBV 0x52 +#define ST7796_WRCTRLD 0x53 + +#define ST7796_FRMCTR1 0xB1 +#define ST7796_FRMCTR2 0xB2 +#define ST7796_FRMCTR3 0xB3 +#define ST7796_INVCTR 0xB4 +#define ST7796_DFUNCTR 0xB6 + +#define ST7796_PWCTR1 0xC0 +#define ST7796_PWCTR2 0xC1 +#define ST7796_PWCTR3 0xC2 +#define ST7796_PWCTR4 0xC3 +#define ST7796_PWCTR5 0xC4 +#define ST7796_VMCTR1 0xC5 +#define ST7796_VMCTR2 0xC7 + +#define ST7796_RDID4 0xD3 +#define ST7796_RDINDEX 0xD9 +#define ST7796_RDID1 0xDA +#define ST7796_RDID2 0xDB +#define ST7796_RDID3 0xDC +#define ST7796_RDIDX 0xDD // TBC + +#define ST7796_GMCTRP1 0xE0 +#define ST7796_GMCTRN1 0xE1 + +#define ST7796_MADCTL_MY 0x80 +#define ST7796_MADCTL_MX 0x40 +#define ST7796_MADCTL_MV 0x20 +#define ST7796_MADCTL_ML 0x10 +#define ST7796_MADCTL_RGB 0x00 +#define ST7796_MADCTL_BGR 0x08 +#define ST7796_MADCTL_MH 0x04 diff --git a/TFT_Drivers/ST7796_Init.h b/TFT_Drivers/ST7796_Init.h new file mode 100644 index 00000000..afc89f92 --- /dev/null +++ b/TFT_Drivers/ST7796_Init.h @@ -0,0 +1,110 @@ + +// This is the command sequence that initialises the ST7796 driver +// +// This setup information uses simple 8 bit SPI writecommand() and writedata() functions +// +// See ST7735_Setup.h file for an alternative format + +#define TFT_INIT_DELAY 0 +{ + delay(120); + + writecommand(0x01); //Software reset + delay(120); + + writecommand(0x11); //Sleep exit + delay(120); + + writecommand(0xF0); //Command Set control + writedata(0xC3); //Enable extension command 2 partI + + writecommand(0xF0); //Command Set control + writedata(0x96); //Enable extension command 2 partII + + writecommand(0x36); //Memory Data Access Control MX, MY, RGB mode + writedata(0x48); //X-Mirror, Top-Left to right-Buttom, RGB + + writecommand(0x3A); //Interface Pixel Format + writedata(0x05); //Control interface color format set to 16 + + + writecommand(0xB4); //Column inversion + writedata(0x01); //1-dot inversion + + writecommand(0xB6); //Display Function Control + writedata(0x20); //RGB interface for RAM access, RGB transfer in DE mode + //display data path in memory + //Gate outputs in non-display area in Normal scan + //Source output in non-display area =V63 + + writedata(0x02); //Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle=2 + writedata(0x3B); //LCD Drive Line=8*(59+1) + + writecommand(0xE8); //Display Output Ctrl Adjust + writedata(0x40); + writedata(0x8A); + writedata(0x00); + writedata(0x00); + writedata(0x29); //Source eqaulizing period time= 22.5 us + writedata(0x19); //Timing for "Gate start"=25 (Tclk) + writedata(0xA5); //Timing for "Gate End"=37 (Tclk), Gate driver EQ function ON + writedata(0x33); + + writecommand(0xC1); //Power control2 + writedata(0x06); //VAP(GVDD)=3.85+( vcom+vcom offset), VAN(GVCL)=-3.85+( vcom+vcom offset) + + writecommand(0xC2); //Power control 3 + writedata(0xA7); //Source driving current level=low, Gamma driving current level=High + + writecommand(0xC5); //VCOM Control + writedata(0x18); //VCOM=0.9 + + delay(120); + + //ST7796 Gamma Sequence + writecommand(0xE0); //Gamma"+" + writedata(0xF0); + writedata(0x09); + writedata(0x0b); + writedata(0x06); + writedata(0x04); + writedata(0x15); + writedata(0x2F); + writedata(0x54); + writedata(0x42); + writedata(0x3C); + writedata(0x17); + writedata(0x14); + writedata(0x18); + writedata(0x1B); + + writecommand(0xE1); //Gamma"-" + writedata(0xE0); + writedata(0x09); + writedata(0x0B); + writedata(0x06); + writedata(0x04); + writedata(0x03); + writedata(0x2B); + writedata(0x43); + writedata(0x42); + writedata(0x3B); + writedata(0x16); + writedata(0x14); + writedata(0x17); + writedata(0x1B); + + delay(120); + + writecommand(0xF0); //Command Set control + writedata(0x3C); //Disable extension command 2 partI + + writecommand(0xF0); //Command Set control + writedata(0x69); //Disable extension command 2 partII + + spi_end(); + delay(120); + spi_begin(); + + writecommand(0x29); //Display on +} \ No newline at end of file diff --git a/TFT_Drivers/ST7796_Rotation.h b/TFT_Drivers/ST7796_Rotation.h new file mode 100644 index 00000000..4788538a --- /dev/null +++ b/TFT_Drivers/ST7796_Rotation.h @@ -0,0 +1,50 @@ + +// This is the command sequence that rotates the ST7796 driver coordinate frame + + rotation = m % 8; // Limit the range of values to 0-7 + + writecommand(TFT_MADCTL); + switch (rotation) { + case 0: + writedata(TFT_MAD_MX | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 1: + writedata(TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + case 2: + writedata(TFT_MAD_MY | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 3: + writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + // These next rotations are for bottom up BMP drawing + case 4: + writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 5: + writedata(TFT_MAD_MV | TFT_MAD_MX | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + case 6: + writedata(TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 7: + writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + + } diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index aa968eea..8051fd47 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -10,131 +10,139 @@ size. Created by Bodmer 2/12/16 - Bodmer: Added RPi 16 bit display support + Last update by Bodmer 27/12/19 ****************************************************/ #include "TFT_eSPI.h" #if defined (ESP32) - #if !defined (ESP32_PARALLEL) - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #else // use default VSPI port - SPIClass& spi = SPI; - #endif - #endif -#else // ESP8266 - SPIClass& spi = SPI; -#endif - - // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled -#if defined (ESP32) && !defined (SUPPORT_TRANSACTIONS) - #define SUPPORT_TRANSACTIONS -#endif - -// If it is a 16bit serial display we must transfer 16 bits every time -#ifdef RPI_ILI9486_DRIVER - #define CMD_BITS (16-1) + #include "Processors/TFT_eSPI_ESP32.c" +#elif defined (ESP8266) + #include "Processors/TFT_eSPI_ESP8266.c" +#elif defined (STM32) //(STM32F7xx) //(_VARIANT_ARDUINO_STM32_) stm32_def.h + #include "Processors/TFT_eSPI_STM32.c" #else - #define CMD_BITS (8-1) + #include "Processors/TFT_eSPI_Generic.c" #endif -// Fast block write prototype -void writeBlock(uint16_t color, uint32_t repeat); - -// Byte read prototype -uint8_t readByte(void); - -// GPIO parallel input/output control -void busDir(uint32_t mask, uint8_t mode); - -void gpioMode(uint8_t gpio, uint8_t mode); +/*************************************************************************************** +** Function name: spi_begin +** Description: Start SPI transaction for writes and select TFT +***************************************************************************************/ inline void TFT_eSPI::spi_begin(void){ -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L;} +#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) + if (locked) { + locked = false; + spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); + CS_L; + } #else CS_L; #endif -#ifdef ESP8266 - SPI1U = SPI1U_WRITE; -#endif + SET_SPI_WRITE_MODE; } +/*************************************************************************************** +** Function name: spi_end +** Description: End transaction for write and deselect TFT +***************************************************************************************/ inline void TFT_eSPI::spi_end(void){ -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if(!inTransaction) {if (!locked) {locked = true; CS_H; spi.endTransaction();}} - #ifdef ESP8266 - SPI1U = SPI1U_READ; - #endif +#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) + if(!inTransaction) { + if (!locked) { + locked = true; + CS_H; + spi.endTransaction(); + } + } + SET_SPI_READ_MODE; #else if(!inTransaction) {CS_H;} #endif } +/*************************************************************************************** +** Function name: spi_begin_read +** Description: Start SPI transaction for reads and select TFT +***************************************************************************************/ +// Reads require a lower SPI clock rate that writes inline void TFT_eSPI::spi_begin_read(void){ -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L;} + DMA_BUSY_CHECK; // Wait for any DMA transfer to complete before changing SPI settings +#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) + if (locked) { + locked = false; + spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); + CS_L; + } #else - #if !defined(ESP32_PARALLEL) + #if !defined(TFT_PARALLEL_8_BIT) spi.setFrequency(SPI_READ_FREQUENCY); #endif CS_L; #endif -#ifdef ESP8266 - SPI1U = SPI1U_READ; -#endif + SET_SPI_READ_MODE; } +/*************************************************************************************** +** Function name: spi_end_read +** Description: End SPI transaction for reads and deselect TFT +***************************************************************************************/ inline void TFT_eSPI::spi_end_read(void){ -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL) - if(!inTransaction) {if (!locked) {locked = true; CS_H; spi.endTransaction();}} +#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) + if(!inTransaction) { + if (!locked) { + locked = true; + CS_H; + spi.endTransaction(); + } + } #else - #if !defined(ESP32_PARALLEL) + #if !defined(TFT_PARALLEL_8_BIT) spi.setFrequency(SPI_FREQUENCY); #endif if(!inTransaction) {CS_H;} #endif -#ifdef ESP8266 - SPI1U = SPI1U_WRITE; -#endif + SET_SPI_WRITE_MODE; } -#if defined (TOUCH_CS) && defined (SPI_TOUCH_FREQUENCY) // && !defined(ESP32_PARALLEL) - - inline void TFT_eSPI::spi_begin_touch(void){ - CS_H; // Just in case it has been left low +#if defined (TOUCH_CS) && defined (SPI_TOUCH_FREQUENCY) // && !defined(TFT_PARALLEL_8_BIT) +/*************************************************************************************** +** Function name: spi_begin_touch +** Description: Start SPI transaction and select touch controller +***************************************************************************************/ +// The touch controller has a low SPI clock rate +inline void TFT_eSPI::spi_begin_touch(void){ + DMA_BUSY_CHECK; + CS_H; // Just in case it has been left low #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} #else spi.setFrequency(SPI_TOUCH_FREQUENCY); #endif - - #ifdef ESP8266 - SPI1U = SPI1U_READ; - #endif - + SET_SPI_READ_MODE; T_CS_L; - } +} +/*************************************************************************************** +** Function name: spi_end_touch +** Description: End SPI transaction and deselect touch controller +***************************************************************************************/ inline void TFT_eSPI::spi_end_touch(void){ T_CS_H; - #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} #else spi.setFrequency(SPI_FREQUENCY); #endif - - #ifdef ESP8266 - SPI1U = SPI1U_WRITE; - #endif + SET_SPI_WRITE_MODE; } #endif + /*************************************************************************************** ** Function name: TFT_eSPI ** Description: Constructor , we must use hardware SPI pins @@ -146,57 +154,50 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) // might call and initialise other SPI peripherals which would could cause conflicts // if CS is floating or undefined. #ifdef TFT_CS - digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) pinMode(TFT_CS, OUTPUT); + digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) #endif // Configure chip select for touchscreen controller if present #ifdef TOUCH_CS - digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive) pinMode(TOUCH_CS, OUTPUT); + digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive) #endif #ifdef TFT_WR - digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive) pinMode(TFT_WR, OUTPUT); + digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive) #endif #ifdef TFT_DC - digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode pinMode(TFT_DC, OUTPUT); + digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode #endif #ifdef TFT_RST if (TFT_RST >= 0) { - digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device pinMode(TFT_RST, OUTPUT); + digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device } #endif -#ifdef ESP32_PARALLEL - - // Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically - 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); - } +#if defined (TFT_PARALLEL_8_BIT) // Make sure read is high before we set the bus to output - digitalWrite(TFT_RD, HIGH); pinMode(TFT_RD, OUTPUT); - - GPIO.out_w1ts = set_mask(255); // Set data bus to 0xFF + digitalWrite(TFT_RD, HIGH); // Set TFT data bus lines to output - busDir(dir_mask, OUTPUT); + pinMode(TFT_D0, OUTPUT); digitalWrite(TFT_D0, HIGH); + pinMode(TFT_D1, OUTPUT); digitalWrite(TFT_D1, HIGH); + pinMode(TFT_D2, OUTPUT); digitalWrite(TFT_D2, HIGH); + pinMode(TFT_D3, OUTPUT); digitalWrite(TFT_D3, HIGH); + pinMode(TFT_D4, OUTPUT); digitalWrite(TFT_D4, HIGH); + pinMode(TFT_D5, OUTPUT); digitalWrite(TFT_D5, HIGH); + pinMode(TFT_D6, OUTPUT); digitalWrite(TFT_D6, HIGH); + pinMode(TFT_D7, OUTPUT); digitalWrite(TFT_D7, HIGH); + + CONSTRUCTOR_INIT_TFT_DATA_BUS; #endif @@ -217,7 +218,7 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _swapBytes = false; // Do not swap colour bytes by default - locked = true; // ESP32 transaction mutex lock flags + locked = true; // Transaction mutex lock flags inTransaction = false; _booted = true; @@ -287,7 +288,7 @@ void TFT_eSPI::init(uint8_t tc) { if (_booted) { -#if !defined (ESP32) +#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) #if defined (TFT_CS) && (TFT_CS >= 0) cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS); #endif @@ -304,7 +305,7 @@ void TFT_eSPI::init(uint8_t tc) sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK); #endif - #ifdef TFT_SPI_OVERLAP + #if defined (TFT_SPI_OVERLAP) && defined (ESP8266) // Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS // pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss); //spi.pins( 6, 7, 8, 0); @@ -314,7 +315,7 @@ void TFT_eSPI::init(uint8_t tc) spi.begin(); // This will set HMISO to input #else - #if !defined(ESP32_PARALLEL) + #if !defined(TFT_PARALLEL_8_BIT) #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); #else @@ -326,31 +327,24 @@ void TFT_eSPI::init(uint8_t tc) inTransaction = false; locked = true; - // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled - // so the code here is for ESP8266 only -#if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266) - spi.setBitOrder(MSBFIRST); - spi.setDataMode(TFT_SPI_MODE); - spi.setFrequency(SPI_FREQUENCY); -#endif + INIT_TFT_DATA_BUS; -#if defined(ESP32_PARALLEL) - digitalWrite(TFT_CS, HIGH); - pinMode(TFT_CS, OUTPUT); -#else - #ifdef TFT_CS - // Set to output once again in case D6 (MISO) is used for CS - digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) - pinMode(TFT_CS, OUTPUT); - #else - spi.setHwCs(1); // Use hardware SS toggling - #endif + + +#ifdef TFT_CS + // Set to output once again in case D6 (MISO) is used for CS + pinMode(TFT_CS, OUTPUT); + digitalWrite(TFT_CS, HIGH); // Chip select high (inactive) +#elif defined (ESP8266) && !defined (TFT_PARALLEL_8_BIT) + spi.setHwCs(1); // Use hardware SS toggling #endif + + // Set to output once again in case D6 (MISO) is used for DC #ifdef TFT_DC - digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode pinMode(TFT_DC, OUTPUT); + digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode #endif _booted = false; @@ -394,7 +388,10 @@ void TFT_eSPI::init(uint8_t tc) #elif defined (S6D02A1_DRIVER) #include "TFT_Drivers/S6D02A1_Init.h" - + +#elif defined (ST7796_DRIVER) + #include "TFT_Drivers/ST7796_Init.h" + #elif defined (RPI_ILI9486_DRIVER) #include "TFT_Drivers/ILI9486_Init.h" @@ -437,13 +434,13 @@ void TFT_eSPI::init(uint8_t tc) setRotation(rotation); #if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON) - digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); pinMode(TFT_BL, OUTPUT); + digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); #else #if defined (TFT_BL) && defined (M5STACK) // Turn on the back-light LED - digitalWrite(TFT_BL, HIGH); pinMode(TFT_BL, OUTPUT); + digitalWrite(TFT_BL, HIGH); #endif #endif } @@ -471,6 +468,9 @@ void TFT_eSPI::setRotation(uint8_t m) #elif defined (S6D02A1_DRIVER) #include "TFT_Drivers/S6D02A1_Rotation.h" +#elif defined (ST7796_DRIVER) + #include "TFT_Drivers/ST7796_Rotation.h" + #elif defined (RPI_ILI9486_DRIVER) #include "TFT_Drivers/ILI9486_Rotation.h" @@ -597,7 +597,7 @@ void TFT_eSPI::writedata(uint8_t d) uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index) { uint8_t reg = 0; -#ifdef ESP32_PARALLEL +#ifdef TFT_PARALLEL_8_BIT writecommand(cmd_function); // Sets DC and CS high @@ -612,21 +612,18 @@ uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index) CS_H; -#else - // for ILI9341 Interface II i.e. IM [3:0] = "1101" +#else // SPI interface + // Tested with ILI9341 set to Interface II i.e. IM [3:0] = "1101" spi_begin_read(); index = 0x10 + (index & 0x0F); - DC_C; - tft_Write_8(0xD9); - DC_D; - tft_Write_8(index); + DC_C; tft_Write_8(0xD9); + DC_D; tft_Write_8(index); CS_H; // Some displays seem to need CS to be pulsed here, or is just a delay needed? CS_L; - DC_C; - tft_Write_8(cmd_function); + DC_C; tft_Write_8(cmd_function); DC_D; reg = tft_Read_8(); @@ -659,10 +656,10 @@ uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) { uint32_t reg; - reg = (readcommand8(cmd_function, index + 0) << 24); - reg |= (readcommand8(cmd_function, index + 1) << 16); - reg |= (readcommand8(cmd_function, index + 2) << 8); - reg |= (readcommand8(cmd_function, index + 3) << 0); + reg = ((uint32_t)readcommand8(cmd_function, index + 0) << 24); + reg |= ((uint32_t)readcommand8(cmd_function, index + 1) << 16); + reg |= ((uint32_t)readcommand8(cmd_function, index + 2) << 8); + reg |= ((uint32_t)readcommand8(cmd_function, index + 3) << 0); return reg; } @@ -674,7 +671,7 @@ uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) ***************************************************************************************/ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) { -#if defined(ESP32_PARALLEL) +#if defined(TFT_PARALLEL_8_BIT) readAddrWindow(x0, y0, 1, 1); // Sets CS low @@ -713,7 +710,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) return (bgr>>11) | (bgr<<11) | (bgr & 0x7E0); #endif -#else // Not ESP32_PARALLEL +#else // Not TFT_PARALLEL_8_BIT // This function can get called during antialiased font rendering // so a transaction may be in progress @@ -770,76 +767,6 @@ void TFT_eSPI::setCallback(getColorCallback getCol) getColor = getCol; } -/*************************************************************************************** -** Function name: read byte - supports class functions -** Description: Read a byte from ESP32 8 bit data port -***************************************************************************************/ -// Bus MUST be set to input before calling this function! -uint8_t readByte(void) -{ - uint8_t b = 0; - -#ifdef ESP32_PARALLEL - 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; -} - -/*************************************************************************************** -** Function name: GPIO direction control - supports class functions -** Description: Set parallel bus to input or output -***************************************************************************************/ -#ifdef ESP32_PARALLEL -void 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; //*/ -} - -// Set ESP32 GPIO pin to input or output -void 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) = ((uint32_t)2 << FUN_DRV_S) | (FUN_IE) | ((uint32_t)2 << MCU_SEL_S); - GPIO.pin[gpio].val = 0; -} -#endif /*************************************************************************************** ** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101") @@ -849,7 +776,7 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da { if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return; -#if defined(ESP32_PARALLEL) +#if defined(TFT_PARALLEL_8_BIT) readAddrWindow(x, y, w, h); // Sets CS low @@ -862,34 +789,35 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Total pixel count uint32_t len = w * h; -#if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes - // Fetch the 24 bit RGB value - while (len--) { - // Assemble the RGB 16 bit colour - uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3); + #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes + // Fetch the 24 bit RGB value + while (len--) { + // Assemble the RGB 16 bit colour + uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3); - // Swapped byte order for compatibility with pushRect() - *data++ = (rgb<<8) | (rgb>>8); - } -#else // ILI9481 reads as 16 bits - // Fetch the 16 bit BRG pixels - while (len--) { - // Read the BRG 16 bit colour - uint16_t bgr = (readByte() << 8) | readByte(); + // Swapped byte order for compatibility with pushRect() + *data++ = (rgb<<8) | (rgb>>8); + } + #else // ILI9481 reads as 16 bits + // Fetch the 16 bit BRG pixels + while (len--) { + // Read the BRG 16 bit colour + uint16_t bgr = (readByte() << 8) | readByte(); - // Swap Red and Blue (could check MADCTL setting to see if this is needed) - uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0); + // Swap Red and Blue (could check MADCTL setting to see if this is needed) + uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0); + + // Swapped byte order for compatibility with pushRect() + *data++ = (rgb<<8) | (rgb>>8); + } + #endif - // Swapped byte order for compatibility with pushRect() - *data++ = (rgb<<8) | (rgb>>8); - } -#endif CS_H; // Set masked pins D0- D7 to output busDir(dir_mask, OUTPUT); -#else // Not ESP32_PARALLEL +#else // SPI interface spi_begin_read(); @@ -906,7 +834,7 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da uint32_t len = w * h; while (len--) { - //#if !defined (ILI9488_DRIVER) + #if !defined (ILI9488_DRIVER) // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte // as the TFT stores colours as 18 bits @@ -914,15 +842,15 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da uint8_t g = tft_Read_8(); uint8_t b = tft_Read_8(); - //#else + #else - // The 6 colour bits are in LS 6 bits of each byte but we do not include the extra clock pulse + // The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left - // uint8_t r = (tft_Read_8()&0x7E)<<1; - // uint8_t g = (tft_Read_8()&0x7E)<<1; - // uint8_t b = (tft_Read_8()&0x7E)<<1; + uint8_t r = (tft_Read_8()&0x7E)<<1; + uint8_t g = (tft_Read_8()&0x7E)<<1; + uint8_t b = (tft_Read_8()&0x7E)<<1; - //#endif + #endif // Swapped colour byte order for compatibility with pushRect() *data++ = (r & 0xF8) | (g & 0xE0) >> 5 | (b & 0xF8) << 5 | (g & 0x1C) << 11; @@ -939,69 +867,6 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da #endif } -/*************************************************************************************** -** Function name: tft_Read_8 -** Description: Software SPI to read bidirectional SDA line -***************************************************************************************/ -#if defined (ESP8266) && defined (TFT_SDA_READ) -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; -} -#endif - -/*************************************************************************************** -** Function name: beginSDA -** Description: Detach SPI from pin to permit software SPI -***************************************************************************************/ -#ifdef TFT_SDA_READ -void TFT_eSPI::begin_SDA_Read(void) -{ - #ifdef ESP32 - pinMatrixOutDetach(TFT_MOSI, false, false); - pinMode(TFT_MOSI, INPUT); - pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false); - #else // ESP8266 - #ifdef TFT_SPI_OVERLAP - // Reads in overlap mode not supported - #else - spi.end(); - #endif - #endif -} -#endif - -/*************************************************************************************** -** Function name: endSDA -** Description: Attach SPI pins after software SPI -***************************************************************************************/ -#ifdef TFT_SDA_READ -void TFT_eSPI::end_SDA_Read(void) -{ - #ifdef ESP32 - pinMode(TFT_MOSI, OUTPUT); - pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false); - pinMode(TFT_MISO, INPUT); - pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false); - #else - #ifdef TFT_SPI_OVERLAP - spi.pins(6, 7, 8, 0); - #else - spi.begin(); - #endif - #endif -} -#endif /*************************************************************************************** ** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101") @@ -1010,7 +875,7 @@ void TFT_eSPI::end_SDA_Read(void) void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { // Function deprecated, remains for backwards compatibility - // pushImage() is better as it will crop partly off-screen image blocks + // New pushImage() is better as it will crop partly off-screen image blocks pushImage(x, y, w, h, data); } @@ -1044,10 +909,15 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d data += dx + dy * w; - while (dh--) - { - pushColors(data, dw, _swapBytes); - data += w; + // Check if whole image can be pushed + if (dw == w) pushColors(data, dw * dh, _swapBytes); + else { + // Push line segments to crop image + while (dh--) + { + pushColors(data, dw, _swapBytes); + data += w; + } } inTransaction = false; @@ -1083,7 +953,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d int32_t xe = x + dw - 1, ye = y + dh - 1; - uint16_t lineBuf[dw]; + uint16_t lineBuf[dw]; // Use buffer to minimise setWindow call count if (!_swapBytes) transp = transp >> 8 | transp << 8; @@ -1092,7 +962,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d int32_t len = dw; uint16_t* ptr = data; int32_t px = x; - boolean move = true; + bool move = true; uint16_t np = 0; while (len--) @@ -1130,12 +1000,10 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d ** Function name: pushImage - for FLASH (PROGMEM) stored images ** Description: plot 16 bit image ***************************************************************************************/ +#define PI_BUF_SIZE 128 void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { -#ifdef ESP32 - pushImage(x, y, w, h, (uint16_t*)data); -#else - // Partitioned memory FLASH processor + // Requires 32 bit aligned access, so use PROGMEM 16 bit word functions if ((x >= _width) || (y >= _height)) return; int32_t dx = 0; @@ -1145,7 +1013,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 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; @@ -1156,37 +1024,36 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 data += dx + dy * w; - uint16_t buffer[64]; + uint16_t buffer[PI_BUF_SIZE]; uint16_t* pix_buffer = buffer; setWindow(x, y, x + dw - 1, y + dh - 1); // Work out the number whole buffers to send - uint16_t nb = (dw * dh) / 64; + uint16_t nb = (dw * dh) / PI_BUF_SIZE; // Fill and send "nb" buffers to TFT for (int32_t i = 0; i < nb; i++) { - for (int32_t j = 0; j < 64; j++) { - pix_buffer[j] = pgm_read_word(&data[i * 64 + j]); + for (int32_t j = 0; j < PI_BUF_SIZE; j++) { + pix_buffer[j] = pgm_read_word(&data[i * PI_BUF_SIZE + j]); } - pushColors(pix_buffer, 64, _swapBytes); + pushColors(pix_buffer, PI_BUF_SIZE, _swapBytes); } // Work out number of pixels not yet sent - uint16_t np = (dw * dh) % 64; + uint16_t np = (dw * dh) % PI_BUF_SIZE; // Send any partial buffer left over if (np) { for (int32_t i = 0; i < np; i++) { - pix_buffer[i] = pgm_read_word(&data[nb * 64 + i]); + pix_buffer[i] = pgm_read_word(&data[nb * PI_BUF_SIZE + i]); } pushColors(pix_buffer, np, _swapBytes); } inTransaction = false; spi_end(); -#endif // if ESP32 else ESP8266 check } @@ -1196,10 +1063,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transp) { -#ifdef ESP32 - pushImage(x, y, w, h, (uint16_t*) data, transp); -#else - // Partitioned memory FLASH processor + // Requires 32 bit aligned access, so use PROGMEM 16 bit word functions if ((x >= _width) || (y >= (int32_t)_height)) return; int32_t dx = 0; @@ -1226,29 +1090,24 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 if (!_swapBytes) transp = transp >> 8 | transp << 8; - while (dh--) - { + while (dh--) { int32_t len = dw; uint16_t* ptr = (uint16_t*)data; int32_t px = x; - boolean move = true; + bool move = true; uint16_t np = 0; - while (len--) - { + while (len--) { uint16_t color = pgm_read_word(ptr); - if (transp != color) - { + if (transp != color) { if (move) { move = false; setWindow(px, y, xe, ye); } lineBuf[np] = color; np++; } - else - { + else { move = true; - if (np) - { + if (np) { pushColors(lineBuf, np, _swapBytes); np = 0; } @@ -1264,7 +1123,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 inTransaction = false; spi_end(); -#endif // if ESP32 else ESP8266 check } @@ -1308,14 +1166,12 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da uint8_t lsbColor = 0; data += dx + dy * w; - while (dh--) - { + while (dh--) { uint32_t len = dw; uint8_t* ptr = data; uint8_t* linePtr = (uint8_t*)lineBuf; - while(len--) - { + while(len--) { uint32_t color = *ptr++; // Shifts are slow so check if colour has changed first @@ -1331,27 +1187,23 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da *linePtr++ = lsbColor; } - pushColors(lineBuf, dw, false); + pushPixels(lineBuf, dw); data += w; } } - else - { - while (dh--) - { + else { + while (dh--) { w = (w+7) & 0xFFF8; int32_t len = dw; uint8_t* ptr = data; uint8_t* linePtr = (uint8_t*)lineBuf; uint8_t bits = 8; - while(len>0) - { + while(len>0) { if (len < 8) bits = len; uint32_t xp = dx; - for (uint16_t i = 0; i < bits; i++) - { + for (uint16_t i = 0; i < bits; i++) { uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80; if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;} else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;} @@ -1363,7 +1215,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da len -= 8; } - pushColors(lineBuf, dw, false); + pushPixels(lineBuf, dw); dy++; } @@ -1403,8 +1255,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da // Line buffer makes plotting faster uint16_t lineBuf[dw]; - if (bpp8) - { + if (bpp8) { // 8 bits per pixel data += dx + dy * w; uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table @@ -1417,20 +1268,17 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da //int32_t spx = x, spy = y; - while (dh--) - { + while (dh--) { int32_t len = dw; uint8_t* ptr = data; uint8_t* linePtr = (uint8_t*)lineBuf; int32_t px = x; - boolean move = true; + bool move = true; uint16_t np = 0; - while (len--) - { - if (transp != *ptr) - { + while (len--) { + if (transp != *ptr) { if (move) { move = false; setWindow(px, y, xe, ye);} uint8_t color = *ptr; @@ -1446,12 +1294,10 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da *linePtr++ = lsbColor; np++; } - else - { + else { move = true; - if (np) - { - pushColors(lineBuf, np, false); + if (np) { + pushPixels(lineBuf, np); linePtr = (uint8_t*)lineBuf; np = 0; } @@ -1460,45 +1306,36 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da ptr++; } - if (np) pushColors(lineBuf, np, false); - + if (np) pushPixels(lineBuf, np); y++; data += w; } } - else - { + else { // 1 bit per pixel w = (w+7) & 0xFFF8; - while (dh--) - { + while (dh--) { int32_t px = x; - boolean move = true; + bool move = true; uint16_t np = 0; int32_t len = dw; uint8_t* ptr = data; uint8_t bits = 8; - while(len>0) - { + while(len>0) { if (len < 8) bits = len; uint32_t xp = dx; uint32_t yp = (dy * w)>>3; - for (uint16_t i = 0; i < bits; i++) - { + for (uint16_t i = 0; i < bits; i++) { //uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80; - if ((ptr[(xp>>3) + yp] << (xp & 0x7)) & 0x80) - { - if (move) - { + if ((ptr[(xp>>3) + yp] << (xp & 0x7)) & 0x80) { + if (move) { move = false; setWindow(px, y, xe, ye); } np++; } - else - { - if (np) - { - pushColor(bitmap_fg, np); + else { + if (np) { + pushBlock(bitmap_fg, np); np = 0; move = true; } @@ -1509,7 +1346,8 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da ptr++; len -= 8; } - if (np) pushColor(bitmap_fg, np); + + if (np) pushBlock(bitmap_fg, np); y++; dy++; } @@ -1546,11 +1384,11 @@ bool TFT_eSPI::getSwapBytes(void) // If w and h are 1, then 1 pixel is read, *data array size must be 3 bytes per pixel void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data) { -#if defined(ESP32_PARALLEL) +#if defined(TFT_PARALLEL_8_BIT) - // ESP32 parallel bus supported yet + // Parallel bus not supported yet -#else // Not ESP32_PARALLEL +#else // Not TFT_PARALLEL_8_BIT spi_begin_read(); @@ -1726,7 +1564,6 @@ void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) drawFastHLine(x0 - r, y0 - x, 2 * r+1, color); drawFastHLine(x0 - x, y0 + r, 2 * x+1, color); drawFastHLine(x0 - x, y0 - r, 2 * x+1, color); - } inTransaction = false; @@ -1738,7 +1575,7 @@ void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) ** Function name: fillCircleHelper ** Description: Support function for filled circle drawing ***************************************************************************************/ -// Used to support drawing roundrects, changed to horizontal lines (faster in sprites) +// Support drawing roundrects, changed to horizontal lines (faster in sprites) void TFT_eSPI::fillCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t cornername, int32_t delta, uint32_t color) { int32_t f = 1 - r; @@ -1747,19 +1584,19 @@ void TFT_eSPI::fillCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t corne int32_t y = 0; delta++; + while (y < r) { if (f >= 0) { r--; ddF_y += 2; f += ddF_y; } + y++; - //x++; ddF_x += 2; f += ddF_x; - if (cornername & 0x1) - { + if (cornername & 0x1) { drawFastHLine(x0 - r, y0 + y, r + r + delta, color); drawFastHLine(x0 - y, y0 + r, y + y + delta, color); } @@ -1789,24 +1626,21 @@ void TFT_eSPI::drawEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint1 //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; - for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) - { + for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) { // These are ordered to minimise coordinate changes in x or y // drawPixel can then send fewer bounding box commands drawPixel(x0 + x, y0 + y, color); drawPixel(x0 - x, y0 + y, color); drawPixel(x0 - x, y0 - y, color); drawPixel(x0 + x, y0 - y, color); - if (s >= 0) - { + if (s >= 0) { s += fx2 * (1 - y); y--; } s += ry2 * ((4 * x) + 6); } - for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) - { + for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) { // These are ordered to minimise coordinate changes in x or y // drawPixel can then send fewer bounding box commands drawPixel(x0 + x, y0 + y, color); @@ -1844,26 +1678,22 @@ void TFT_eSPI::fillEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint1 //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; - for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) - { + for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) { drawFastHLine(x0 - x, y0 - y, x + x + 1, color); drawFastHLine(x0 - x, y0 + y, x + x + 1, color); - if (s >= 0) - { + if (s >= 0) { s += fx2 * (1 - y); y--; } s += ry2 * ((4 * x) + 6); } - for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) - { + for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) { drawFastHLine(x0 - x, y0 - y, x + x + 1, color); drawFastHLine(x0 - x, y0 + y, x + x + 1, color); - if (s >= 0) - { + if (s >= 0) { s += fy2 * (1 - x); x--; } @@ -2078,6 +1908,29 @@ void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w } +/*************************************************************************************** +** Function name: drawBitmap +** Description: Draw an image stored in an array on the TFT +***************************************************************************************/ +void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor) +{ + //spi_begin(); // Sprite class can use this function, avoiding spi_begin() + inTransaction = true; + + int32_t i, j, byteWidth = (w + 7) / 8; + + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++ ) { + if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) + drawPixel(x + i, y + j, fgcolor); + else drawPixel(x + i, y + j, bgcolor); + } + } + + inTransaction = false; + spi_end(); // Does nothing if Sprite class uses this function +} + /*************************************************************************************** ** Function name: drawXBitmap ** Description: Draw an image stored in an XBM array onto the TFT @@ -2249,7 +2102,7 @@ void TFT_eSPI::setBitmapColor(uint16_t c, uint16_t b) ** Function name: setTextWrap ** Description: Define if text should wrap at end of line ***************************************************************************************/ -void TFT_eSPI::setTextWrap(boolean wrapX, boolean wrapY) +void TFT_eSPI::setTextWrap(bool wrapX, bool wrapY) { textwrapX = wrapX; textwrapY = wrapY; @@ -2347,20 +2200,15 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) uint16_t uniCode = 0; #ifdef SMOOTH_FONT - if(fontLoaded) - { - while (*string) - { + if(fontLoaded) { + while (*string) { uniCode = decodeUTF8(*string++); - if (uniCode) - { + if (uniCode) { if (uniCode == 0x20) str_width += gFont.spaceWidth; - else - { + else { uint16_t gNum = 0; bool found = getUnicodeIndex(uniCode, &gNum); - if (found) - { + if (found) { if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum]; if (*string || isDigits) str_width += gxAdvance[gNum]; else str_width += (gdX[gNum] + gWidth[gNum]); @@ -2374,12 +2222,10 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) } #endif - if (font>1 && font<9) - { + if (font>1 && font<9) { char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop - while (*string) - { + while (*string) { uniCode = *(string++); if (uniCode > 31 && uniCode < 128) str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subtract 32 from uniCode @@ -2387,17 +2233,13 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) } } - else - { + else { #ifdef LOAD_GFXFF - if(gfxFont) // New font - { - while (*string) - { + if(gfxFont) { // New font + while (*string) { uniCode = decodeUTF8(*string++); - if ((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last ))) - { + if ((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last ))) { uniCode -= pgm_read_word(&gfxFont->first); GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[uniCode]); // If this is not the last character or is a digit then use xAdvance @@ -2443,10 +2285,8 @@ int16_t TFT_eSPI::fontHeight(int16_t font) #endif #ifdef LOAD_GFXFF - if (font==1) - { - if(gfxFont) // New font - { + if (font==1) { + if(gfxFont) { // New font return pgm_read_byte(&gfxFont->yAdvance) * textsize; } } @@ -2461,7 +2301,7 @@ int16_t TFT_eSPI::fontHeight(void) /*************************************************************************************** ** Function name: drawChar -** Description: draw a single character in the Adafruit GLCD font +** Description: draw a single character in the GLCD or GFXFF font ***************************************************************************************/ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) { @@ -2479,10 +2319,9 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 #endif //>>>>>>>>>>>>>>>>>> - boolean fillbg = (bg != color); + bool fillbg = (bg != color); - if ((size==1) && fillbg) - { + if ((size==1) && fillbg) { uint8_t column[6]; uint8_t mask = 0x1; spi_begin(); @@ -2492,30 +2331,6 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); column[5] = 0; -#if defined (ESP8266) && !defined (ILI9488_DRIVER) - color = (color >> 8) | (color << 8); - bg = (bg >> 8) | (bg << 8); - - for (int8_t j = 0; j < 8; j++) { - for (int8_t k = 0; k < 5; k++ ) { - if (column[k] & mask) { - SPI1W0 = color; - } - else { - SPI1W0 = bg; - } - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - } - - mask <<= 1; - - SPI1W0 = bg; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - } -#else // for ESP32 or ILI9488 - for (int8_t j = 0; j < 8; j++) { for (int8_t k = 0; k < 5; k++ ) { if (column[k] & mask) {tft_Write_16(color);} @@ -2525,12 +2340,9 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 tft_Write_16(bg); } -#endif - spi_end(); } - else - { + else { //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; for (int8_t i = 0; i < 6; i++ ) { @@ -2540,8 +2352,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 else line = pgm_read_byte(font + (c * 5) + i); - if (size == 1) // default size - { + if (size == 1) { // default size for (int8_t j = 0; j < 8; j++) { if (line & 0x1) drawPixel(x + i, y + j, color); line >>= 1; @@ -2568,8 +2379,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 #ifdef LOAD_GFXFF // Filter out bad characters not present in font - if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last ))) - { + if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last ))) { //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; //>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -2592,32 +2402,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 yo16 = yo; } -// Here we have 3 versions of the same function just for evaluation purposes -// Comment out the next two #defines to revert to the slower Adafruit implementation - -// If FAST_LINE is defined then the free fonts are rendered using horizontal lines -// this makes rendering fonts 2-5 times faster. Particularly good for large fonts. -// This is an elegant solution since it still uses generic functions present in the -// stock library. - -// If FAST_SHIFT is defined then a slightly faster (at least for AVR processors) -// shifting bit mask is used - -// Free fonts don't look good when the size multiplier is >1 so we could remove -// code if this is not wanted and speed things up - -#define FAST_HLINE -#define FAST_SHIFT -//FIXED_SIZE is an option in User_Setup.h that only works with FAST_LINE enabled - -#ifdef FIXED_SIZE - x+=xo; // Save 88 bytes of FLASH - y+=yo; -#endif - -#ifdef FAST_HLINE - - #ifdef FAST_SHIFT + // GFXFF rendering speed up uint16_t hpc = 0; // Horizontal foreground pixel count for(yy=0; yy>= 1; } - // Draw pixels for this line as we are about to increment yy - if (hpc) { -#ifndef FIXED_SIZE - if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color); - else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color); -#else - drawFastHLine(x+xx-hpc, y+yy, hpc, color); -#endif - hpc=0; - } - } - #else - uint16_t hpc = 0; // Horizontal foreground pixel count - for(yy=0; yy> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24)); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - // Row addr set - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_PASET; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); - // Load the two coords as a 32 bit value and shift in one go - SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24)); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - // write to RAM - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - SPI1W0 = TFT_RAMWR; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); - //spi_end(); -} - -#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits - -void TFT_eSPI::setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) -{ - //spi_begin(); // Must be called before setWimdow - - addr_col = 0xFFFF; - addr_row = 0xFFFF; - - // Column addr set - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_CASET<<8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - uint8_t xb[] = { 0, (uint8_t) (xs>>8), 0, (uint8_t) (xs>>0), 0, (uint8_t) (xe>>8), 0, (uint8_t) (xe>>0), }; - spi.writePattern(&xb[0], 8, 1); - - // Row addr set - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_PASET<<8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - uint8_t yb[] = { 0, (uint8_t) (ys>>8), 0, (uint8_t) (ys>>0), 0, (uint8_t) (ye>>8), 0, (uint8_t) (ye>>0), }; - spi.writePattern(&yb[0], 8, 1); - - // write to RAM - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - SPI1W0 = TFT_RAMWR<<8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - // Re-instate SPI flags settings corrupted by SPI library writePattern() call - SPI1U = SPI1U_WRITE; - - //spi_end(); -} - -#else - -#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { - //spi_begin(); // Must be called before setWimdow - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - // Column addr set - DC_C; - - SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - addr_col = 0xFFFF; // Use the waiting time to do something useful - addr_row = 0xFFFF; - while(SPI1CMD & SPIBUSY) {} - DC_D; - - SPI1W0 = x0 >> 0; - SPI1CMD |= SPIBUSY; - x0 = x0 << 8; // Use the waiting time to do something useful - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x1 >> 0; - SPI1CMD |= SPIBUSY; - x1 = x1 << 8; // Use the waiting time to do something useful - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x1; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - // Row addr set - DC_C; - - SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - DC_D; - - SPI1W0 = y0 >> 0; - SPI1CMD |= SPIBUSY; - y0 = y0 << 8; // Use the waiting time to do something useful - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y1 >> 0; - SPI1CMD |= SPIBUSY; - y1 = y1 << 8; // Use the waiting time to do something useful - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y1; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - // write to RAM - DC_C; - - SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - //spi_end(); -} - -#else // This is for the ESP32 - -void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) -{ - //spi_begin(); // Must be called before setWimdow + //spi_begin(); // Must be called before setWindow addr_col = 0xFFFF; addr_row = 0xFFFF; @@ -2936,44 +2476,20 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) y1+=rowstart; #endif - DC_C; - - tft_Write_8(TFT_CASET); - - DC_D; - -#if defined (RPI_ILI9486_DRIVER) - uint8_t xb[] = { 0, (uint8_t) (x0>>8), 0, (uint8_t) (x0>>0), 0, (uint8_t) (x1>>8), 0, (uint8_t) (x1>>0), }; - spi.writePattern(&xb[0], 8, 1); -#else - tft_Write_32(SPI_32(x0, x1)); -#endif - - DC_C; + // Column addr set + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32C(x0, x1); // Row addr set - tft_Write_8(TFT_PASET); + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32C(y0, y1); - DC_D; - -#if defined (RPI_ILI9486_DRIVER) - uint8_t yb[] = { 0, (uint8_t) (y0>>8), 0, (uint8_t) (y0>>0), 0, (uint8_t) (y1>>8), 0, (uint8_t) (y1>>0), }; - spi.writePattern(&yb[0], 8, 1); -#else - tft_Write_32(SPI_32(y0, y1)); -#endif - - DC_C; - - // write to RAM - tft_Write_8(TFT_RAMWR); + DC_C; tft_Write_8(TFT_RAMWR); DC_D; - //spi_end(); + //spi_end(); // Must be called after setWindow } -#endif // end RPI_ILI9486_DRIVER check -#endif // end ESP32 check /*************************************************************************************** @@ -2981,16 +2497,14 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) ** Description: define an area to read a stream of pixels ***************************************************************************************/ // Chip select stays low -#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) { - int32_t xe = xs + w - 1; int32_t ye = ys + h - 1; addr_col = 0xFFFF; addr_row = 0xFFFF; - + #ifdef CGRAM_OFFSET xs += colstart; xe += colstart; @@ -2999,102 +2513,24 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) #endif // Column addr set - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_CASET; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); - // Load the two coords as a 32 bit value and shift in one go - SPI1W0 = (xs >> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24)); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32C(xs, xe); // Row addr set - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_PASET; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); - // Load the two coords as a 32 bit value and shift in one go - SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24)); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - // read from RAM - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - SPI1W0 = TFT_RAMRD; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - -} - -#else //ESP32 - -void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) -{ - - int32_t xe = xs + w - 1; - int32_t ye = ys + h - 1; - - addr_col = 0xFFFF; - addr_row = 0xFFFF; - -#ifdef CGRAM_OFFSET -xs += colstart; -xe += colstart; -ys += rowstart; -ye += rowstart; -#endif - - // Column addr set - DC_C; - - tft_Write_8(TFT_CASET); - - DC_D; - - tft_Write_32(SPI_32(xs, xe)); - - // Row addr set - DC_C; + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32C(ys, ye); - tft_Write_8(TFT_PASET); + // Read CGRAM command + DC_C; tft_Write_8(TFT_RAMRD); DC_D; - - tft_Write_32(SPI_32(ys, ye)); - - DC_C; - - tft_Write_8(TFT_RAMRD); // Read CGRAM command - - DC_D; - } -#endif /*************************************************************************************** ** Function name: drawPixel ** Description: push a single pixel at an arbitrary position ***************************************************************************************/ -#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) { // Range checking @@ -3109,232 +2545,24 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) // No need to send x if it has not changed (speeds things up) if (addr_col != x) { - - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - -#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte - uint8_t cBin[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0)}; - spi.writePattern(&cBin[0], 4, 2); -#else - SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); - // Load the two coords as a 32 bit value and shift in one go - uint32_t xswap = (x >> 8) | (uint16_t)(x << 8); - SPI1W0 = xswap | (xswap << 16); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} -#endif - + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32D(x); addr_col = x; } // No need to send y if it has not changed (speeds things up) if (addr_row != y) { - - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - -#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte - uint8_t cBin[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0)}; - spi.writePattern(&cBin[0], 4, 2); -#else - SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO); - // Load the two coords as a 32 bit value and shift in one go - uint32_t yswap = (y >> 8) | (uint16_t)(y << 8); - SPI1W0 = yswap | (yswap << 16); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} -#endif - + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32D(y); addr_row = y; } - DC_C; - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - - SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - -#if defined (ILI9488_DRIVER) - tft_Write_16(color); -#else - SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); - - SPI1W0 = (color >> 8) | (color << 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} -#endif + DC_C; tft_Write_8(TFT_RAMWR); + DC_D; tft_Write_16(color); spi_end(); } -#else - -#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits - -void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) -{ - // Range checking - if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return; - - spi_begin(); - - SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO); - // No need to send x if it has not changed (speeds things up) - if (addr_col != x) { - DC_C; - - SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - DC_D; - - SPI1W0 = x >> 0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x << 8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x >> 0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = x << 8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - addr_col = x; - } - - // No need to send y if it has not changed (speeds things up) - if (addr_row != y) { - DC_C; - - SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - DC_D; - - SPI1W0 = y >> 0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y << 8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y >> 0; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - SPI1W0 = y << 8; - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - addr_row = y; - } - - DC_C; - - SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - DC_D; - - SPI1W0 = (color >> 8) | (color << 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - - spi_end(); -} - -#else // ESP32 - -void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) -{ - // Range checking - if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return; - - spi_begin(); - -#ifdef CGRAM_OFFSET - x+=colstart; - y+=rowstart; -#endif - - DC_C; - - // No need to send x if it has not changed (speeds things up) - if (addr_col != x) { - - tft_Write_8(TFT_CASET); - - DC_D; - -#if defined (RPI_ILI9486_DRIVER) - uint8_t xb[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), }; - spi.writePattern(&xb[0], 8, 1); -#else - tft_Write_32(SPI_32(x, x)); -#endif - - DC_C; - - addr_col = x; - } - - // No need to send y if it has not changed (speeds things up) - if (addr_row != y) { - - tft_Write_8(TFT_PASET); - - DC_D; - -#if defined (RPI_ILI9486_DRIVER) - uint8_t yb[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), }; - spi.writePattern(&yb[0], 8, 1); -#else - tft_Write_32(SPI_32(y, y)); -#endif - - DC_C; - - addr_row = y; - } - - - tft_Write_8(TFT_RAMWR); - - DC_D; - - tft_Write_16(color); - - spi_end(); -} -#endif -#endif - - /*************************************************************************************** ** Function name: pushColor ** Description: push a single pixel @@ -3357,17 +2585,7 @@ void TFT_eSPI::pushColor(uint16_t color, uint32_t len) { spi_begin(); -#ifdef RPI_WRITE_STROBE - 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;} -#else - #if defined (ESP32_PARALLEL) - while (len--) {tft_Write_16(color);} - #else - writeBlock(color, len); - #endif -#endif + pushBlock(color, len); spi_end(); } @@ -3389,6 +2607,7 @@ void TFT_eSPI::startWrite(void) void TFT_eSPI::endWrite(void) { inTransaction = false; + DMA_BUSY_CHECK; // Safety check - user code should have checked this! spi_end(); } @@ -3398,17 +2617,7 @@ void TFT_eSPI::endWrite(void) ***************************************************************************************/ void TFT_eSPI::writeColor(uint16_t color, uint32_t len) { -#ifdef RPI_WRITE_STROBE - 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;} -#else - #if defined (ESP32_PARALLEL) - while (len--) {tft_Write_16(color);} - #else - writeBlock(color, len); - #endif -#endif + pushBlock(color, len); } /*************************************************************************************** @@ -3416,29 +2625,12 @@ void TFT_eSPI::writeColor(uint16_t color, uint32_t len) ** Description: push an array of pixels for 16 bit raw image drawing ***************************************************************************************/ // Assumed that setAddrWindow() has previously been called - +// len is number of bytes, not pixels void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) { spi_begin(); -#if defined (RPI_WRITE_STROBE) - while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; } - if (len) spi.writePattern(data, len, 1); -#else - #ifdef ESP32_PARALLEL - while (len--) {tft_Write_8(*data); data++;} - #elif defined (ILI9488_DRIVER) - uint16_t color; - while (len>1) {color = (*data++); color |= ((*data++)<<8); tft_Write_16(color); len-=2;} - #else - #if (SPI_FREQUENCY == 80000000) - while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; } - if (len) spi.writePattern(data, len, 1); - #else - spi.writeBytes(data, len); - #endif - #endif -#endif + pushPixels(data, len>>1); spi_end(); } @@ -3451,91 +2643,11 @@ void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap) { spi_begin(); + if (swap) {swap = _swapBytes; _swapBytes = true; } + + pushPixels(data, len); -#if defined (ESP32) || defined (ILI9488_DRIVER) - #if defined (ESP32_PARALLEL) || defined (ILI9488_DRIVER) - if (swap) while ( len-- ) {tft_Write_16(*data); data++;} - else while ( len-- ) {tft_Write_16S(*data); data++;} - #else - if (swap) spi.writePixels(data,len<<1); - else spi.writeBytes((uint8_t*)data,len<<1); - #endif -#else - - uint32_t color[8]; - - SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO); - - - while(len>15) - { - - if (swap) - { - uint32_t i = 0; - while(i<8) - { - color[i] = (*data >> 8) | (uint16_t)(*data << 8); - data++; - color[i] |= ((*data >> 8) | (*data << 8)) << 16; - data++; - i++; - } - } - else - { - 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 - if (swap) - { - uint16_t* ptr = (uint16_t*)color; - while(len--) - { - *ptr++ = (*(data) >> 8) | (uint16_t)(*(data) << 8); - data++; - } - } - else - { - 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) {} - -#endif - + _swapBytes = swap; // Restore old value spi_end(); } @@ -3546,14 +2658,12 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap) ***************************************************************************************/ // Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use // an efficient FastH/V Line draw routine for line segments of 2 pixels or more - -#if defined (RPI_ILI9486_DRIVER) || defined (ESP32) || defined (RPI_WRITE_STROBE) || defined (HX8357D_DRIVER) || defined (ILI9488_DRIVER) - void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) { //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; - boolean steep = abs(y1 - y0) > abs(x1 - x0); + + bool steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap_coord(x0, y0); swap_coord(x1, y1); @@ -3577,140 +2687,39 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t 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; - } - } - if (dlen) drawFastVLine(y0, xs, dlen, color); - } - else - { - for (; x0 <= x1; x0++) { - 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; - } - } - if (dlen) drawFastHLine(xs, y0, dlen, color); - } - inTransaction = false; - spi_end(); -} - -#else - -// This is a weeny bit faster -void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) -{ - - boolean steep = abs(y1 - y0) > abs(x1 - x0); - - if (steep) { - swap_coord(x0, y0); - swap_coord(x1, y1); - } - - if (x0 > x1) { - swap_coord(x0, x1); - swap_coord(y0, y1); - } - - if (x1 < 0) return; - - int16_t dx, dy; - dx = x1 - x0; - dy = abs(y1 - y0); - - int16_t err = dx / 2; - int8_t ystep = (y0 < y1) ? 1 : (-1); - - spi_begin(); - - int16_t swapped_color = (color >> 8) | (color << 8); - - if (steep) // y increments every iteration (y0 is x-axis, and x0 is y-axis) - { - if (x1 >= (int32_t)_height) x1 = _height - 1; - - for (; x0 <= x1; x0++) { - if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) break; - err -= dy; - if (err < 0) { - err += dx; - y0 += ystep; - } - } - - if (x0 > x1) {spi_end(); return;} - - setWindow(y0, x0, y0, _height); - SPI1W0 = swapped_color; - for (; x0 <= x1; x0++) { - while(SPI1CMD & SPIBUSY) {} - SPI1CMD |= SPIBUSY; - - err -= dy; - if (err < 0) { - y0 += ystep; - if ((y0 < 0) || (y0 >= _width)) break; - err += dx; - while(SPI1CMD & SPIBUSY) {} - setWindow(y0, x0+1, y0, _height); - SPI1W0 = swapped_color; + if (dlen == 1) drawPixel(y0, xs, color); + else drawFastVLine(y0, xs, dlen, color); + dlen = 0; + y0 += ystep; xs = x0 + 1; } } + if (dlen) drawFastVLine(y0, xs, dlen, color); } - else // x increments every iteration (x0 is x-axis, and y0 is y-axis) + else { - if (x1 >= _width) x1 = _width - 1; - - for (; x0 <= x1; x0++) { - if ((x0 >= 0) && (y0 >= 0) && (y0 < (int32_t)_height)) break; - err -= dy; - if (err < 0) { - err += dx; - y0 += ystep; - } - } - - if (x0 > x1) {spi_end(); return;} - - setWindow(x0, y0, _width, y0); - SPI1W0 = swapped_color; for (; x0 <= x1; x0++) { - while(SPI1CMD & SPIBUSY) {} - SPI1CMD |= SPIBUSY; - + dlen++; err -= dy; if (err < 0) { - y0 += ystep; - if ((y0 < 0) || (y0 >= (int32_t)_height)) break; err += dx; - while(SPI1CMD & SPIBUSY) {} - setWindow(x0+1, y0, _width, y0); - SPI1W0 = swapped_color; + if (dlen == 1) drawPixel(xs, y0, color); + else drawFastHLine(xs, y0, dlen, color); + dlen = 0; + y0 += ystep; xs = x0 + 1; } } + if (dlen) drawFastHLine(xs, y0, dlen, color); } - while(SPI1CMD & SPIBUSY) {} - + inTransaction = false; spi_end(); } -#endif - /*************************************************************************************** ** Function name: drawFastVLine ** Description: draw a vertical line ***************************************************************************************/ -#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { // Clipping @@ -3726,55 +2735,16 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) setWindow(x, y, x, y + h - 1); - writeBlock(color, h); + pushBlock(color, h); spi_end(); } -#else - -void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) -{ - // Clipping - if ((x < 0) || (x >= _width) || (y >= _height)) return; - - if (y < 0) { h += y; y = 0; } - - if ((y + h) > _height) h = _height - y; - - if (h < 1) return; - - spi_begin(); - - setWindow(x, y, x, y + h - 1); - -#ifdef RPI_WRITE_STROBE - #if defined (ESP8266) - SPI1W0 = (color >> 8) | (color << 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - #else - tft_Write_16(color); - #endif - h--; - while(h--) {WR_L; WR_H;} -#else - #ifdef ESP32_PARALLEL - while (h--) {tft_Write_16(color);} - #else - writeBlock(color, h); - #endif -#endif - - spi_end(); -} -#endif /*************************************************************************************** ** Function name: drawFastHLine ** Description: draw a horizontal line ***************************************************************************************/ -#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) { // Clipping @@ -3790,82 +2760,18 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) setWindow(x, y, x + w - 1, y); - writeBlock(color, w); + pushBlock(color, w); spi_end(); } -#else - -void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) -{ - // Clipping - if ((y < 0) || (x >= _width) || (y >= _height)) return; - - if (x < 0) { w += x; x = 0; } - - if ((x + w) > _width) w = _width - x; - - if (w < 1) return; - - spi_begin(); - - setWindow(x, y, x + w - 1, y); - -#ifdef RPI_WRITE_STROBE - #if defined (ESP8266) - SPI1W0 = (color >> 8) | (color << 8); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - #else - tft_Write_16(color); - #endif - w--; - while(w--) {WR_L; WR_H;} -#else - #ifdef ESP32_PARALLEL - while (w--) {tft_Write_16(color);} - #else - writeBlock(color, w); - #endif -#endif - - spi_end(); -} -#endif /*************************************************************************************** ** Function name: fillRect ** Description: draw a filled rectangle ***************************************************************************************/ -#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) -void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) -{ - // Clipping - if ((x >= _width) || (y >= _height)) return; - - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - - if ((x + w) > _width) w = _width - x; - if ((y + h) > _height) h = _height - y; - - if ((w < 1) || (h < 1)) return; - - spi_begin(); - - setWindow(x, y, x + w - 1, y + h - 1); - - writeBlock(color, w * h); - - spi_end(); -} - -#else - void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { - // Clipping if ((x >= _width) || (y >= _height)) return; @@ -3881,31 +2787,11 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col setWindow(x, y, x + w - 1, y + h - 1); - uint32_t n = (uint32_t)w * (uint32_t)h; - -#ifdef RPI_WRITE_STROBE - tft_Write_16(color); - while(n--) {WR_L; WR_H;} -#else - #ifdef ESP32_PARALLEL - if (color>>8 == (uint8_t)color) - { - tft_Write_8(color); - n--; WR_L; WR_H; - while (n) {WR_L; WR_H; n--; WR_L; WR_H;} - } - else - { - while (n--) {tft_Write_16(color);} - } - #else - writeBlock(color, n); - #endif -#endif + pushBlock(color, w * h); spi_end(); } -#endif + /*************************************************************************************** ** Function name: color565 @@ -3949,7 +2835,7 @@ uint16_t TFT_eSPI::color8to16(uint8_t color) ** Function name: invertDisplay ** Description: invert the display colours i = 1 invert, i = 0 normal ***************************************************************************************/ -void TFT_eSPI::invertDisplay(boolean i) +void TFT_eSPI::invertDisplay(bool i) { spi_begin(); // Send the command twice as otherwise it does not always work! @@ -4014,19 +2900,15 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t c) return (uint16_t)c; } - if (decoderState == 0) - { + if (decoderState == 0) { // 11 bit Unicode Code Point - if ((c & 0xE0) == 0xC0) - { + if ((c & 0xE0) == 0xC0) { decoderBuffer = ((c & 0x1F)<<6); decoderState = 1; return 0; } - // 16 bit Unicode Code Point - if ((c & 0xF0) == 0xE0) - { + if ((c & 0xF0) == 0xE0) { decoderBuffer = ((c & 0x0F)<<12); decoderState = 2; return 0; @@ -4034,16 +2916,13 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t c) // 21 bit Unicode Code Point not supported so fall-back to extended ASCII // if ((c & 0xF8) == 0xF0) return (uint16_t)c; } - else - { - if (decoderState == 2) - { + else { + if (decoderState == 2) { decoderBuffer |= ((c & 0x3F)<<6); decoderState--; return 0; } - else - { + else { decoderBuffer |= (c & 0x3F); decoderState = 0; return decoderBuffer; @@ -4075,8 +2954,7 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining) return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F); // 16 bit Unicode - if (((c & 0xF0) == 0xE0) && (remaining > 2)) - { + if (((c & 0xF0) == 0xE0) && (remaining > 2)) { c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6); return c | ((buf[(*index)++]&0x3F)); } @@ -4089,6 +2967,33 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining) } +/*************************************************************************************** +** Function name: alphaBlend +** Description: Blend foreground and background and return new colour +*************************************************************************************x*/ +uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc) +{ + // For speed use fixed point maths and rounding to permit a power of 2 division + uint16_t fgR = ((fgc >> 10) & 0x3E) + 1; + uint16_t fgG = ((fgc >> 4) & 0x7E) + 1; + uint16_t fgB = ((fgc << 1) & 0x3E) + 1; + + uint16_t bgR = ((bgc >> 10) & 0x3E) + 1; + uint16_t bgG = ((bgc >> 4) & 0x7E) + 1; + uint16_t bgB = ((bgc << 1) & 0x3E) + 1; + + // Shift right 1 to drop rounding bit and shift right 8 to divide by 256 + uint16_t r = (((fgR * alpha) + (bgR * (255 - alpha))) >> 9); + uint16_t g = (((fgG * alpha) + (bgG * (255 - alpha))) >> 9); + uint16_t b = (((fgB * alpha) + (bgB * (255 - alpha))) >> 9); + + // Combine RGB565 colours into 16 bits + //return ((r&0x18) << 11) | ((g&0x30) << 5) | ((b&0x18) << 0); // 2 bit greyscale + //return ((r&0x1E) << 11) | ((g&0x3C) << 5) | ((b&0x1E) << 0); // 4 bit greyscale + return (r << 11) | (g << 5) | (b << 0); +} + + /*************************************************************************************** ** Function name: write ** Description: draw characters piped through serial stream @@ -4104,8 +3009,7 @@ size_t TFT_eSPI::write(uint8_t utf8) if (uniCode == 0) return 1; #ifdef SMOOTH_FONT - if(fontLoaded) - { + if(fontLoaded) { //Serial.print("UniCode="); Serial.println(uniCode); //Serial.print("UTF8 ="); Serial.println(utf8); @@ -4143,8 +3047,7 @@ size_t TFT_eSPI::write(uint8_t utf8) //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #ifdef LOAD_FONT2 - if (textfont == 2) - { + if (textfont == 2) { if (uniCode > 127) return 1; width = pgm_read_byte(widtbl_f16 + uniCode-32); @@ -4160,8 +3063,7 @@ size_t TFT_eSPI::write(uint8_t utf8) #ifdef LOAD_RLE { - if ((textfont>2) && (textfont<9)) - { + if ((textfont>2) && (textfont<9)) { if (uniCode > 127) return 1; // Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 ); @@ -4171,8 +3073,7 @@ size_t TFT_eSPI::write(uint8_t utf8) #endif #ifdef LOAD_GLCD - if (textfont==1) - { + if (textfont==1) { width = 6; height = 8; } @@ -4186,10 +3087,8 @@ size_t TFT_eSPI::write(uint8_t utf8) cursor_y += height; cursor_x = 0; } - else - { - if (textwrapX && (cursor_x + width * textsize > _width)) - { + else { + if (textwrapX && (cursor_x + width * textsize > _width)) { cursor_y += height; cursor_x = 0; } @@ -4200,13 +3099,13 @@ size_t TFT_eSPI::write(uint8_t utf8) //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #ifdef LOAD_GFXFF } // Custom GFX font - else - { + else { if(utf8 == '\n') { cursor_x = 0; cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } else { + } + else { if (uniCode > pgm_read_word(&gfxFont->last )) return 1; if (uniCode < pgm_read_word(&gfxFont->first)) return 1; @@ -4250,8 +3149,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) { if (!uniCode) return 0; - if (font==1) - { + if (font==1) { #ifdef LOAD_GLCD #ifndef LOAD_GFXFF drawChar(x, y, uniCode, textcolor, textbgcolor, textsize); @@ -4272,16 +3170,13 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) return 0; #endif } - else - { - if((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) )) - { + else { + if((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) )) { uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first); GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]); return pgm_read_byte(&glyph->xAdvance) * textsize; } - else - { + else { return 0; } } @@ -4296,8 +3191,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) uniCode -= 32; #ifdef LOAD_FONT2 - if (font == 2) - { + if (font == 2) { flash_address = pgm_read_dword(&chrtbl_f16[uniCode]); width = pgm_read_byte(widtbl_f16 + uniCode); height = chr_hgt_f16; @@ -4309,8 +3203,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) #ifdef LOAD_RLE { - if ((font>2) && (font<9)) - { + if ((font>2) && (font<9)) { flash_address = pgm_read_dword( (const void*)(pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *)) ); width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode ); height= pgm_read_byte( &fontdata[font].height ); @@ -4333,12 +3226,10 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) //spi_begin(); // Sprite class can use this function, avoiding spi_begin() inTransaction = true; - for (int32_t i = 0; i < height; i++) - { + for (int32_t i = 0; i < height; i++) { if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor); - for (int32_t k = 0; k < w; k++) - { + for (int32_t k = 0; k < w; k++) { line = pgm_read_byte((uint8_t *)flash_address + w * i + k); if (line) { if (textsize == 1) { @@ -4371,19 +3262,15 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) inTransaction = false; spi_end(); } - else - // Faster drawing of characters and background using block write - { + else { // Faster drawing of characters and background using block write spi_begin(); setWindow(x, y, x + width - 1, y + height - 1); uint8_t mask; - for (int32_t i = 0; i < height; i++) - { + for (int32_t i = 0; i < height; i++) { pX = width; - for (int32_t k = 0; k < w; k++) - { + for (int32_t k = 0; k < w; k++) { line = pgm_read_byte((uint8_t *) (flash_address + w * i + k) ); mask = 0x80; while (mask && pX) { @@ -4422,8 +3309,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) uint8_t ts = textsize - 1; // Temporary copy of textsize // 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area // w is total number of pixels to plot to fill character block - while (pc < w) - { + while (pc < w) { line = pgm_read_byte((uint8_t *)flash_address); flash_address++; if (line & 0x80) { @@ -4448,8 +3334,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) else {tft_Write_16(textcolor);} px += textsize; - if (px >= (x + width * textsize)) - { + if (px >= (x + width * textsize)) { px = x; py += textsize; } @@ -4461,46 +3346,21 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } } } - else // Text colour != background && textsize = 1 - // so use faster drawing of characters and background using block write - { + else { // Text colour != background && textsize = 1 + // so use faster drawing of characters and background using block write setWindow(x, y, x + width - 1, y + height - 1); -#ifdef RPI_WRITE_STROBE - uint8_t textcolorBin[] = { (uint8_t) (textcolor >> 8), (uint8_t) textcolor }; - uint8_t textbgcolorBin[] = { (uint8_t) (textbgcolor >> 8), (uint8_t) textbgcolor }; -#endif - // Maximum font size is equivalent to 180x180 pixels in area - while (w > 0) - { + while (w > 0) { line = pgm_read_byte((uint8_t *)flash_address++); // 8 bytes smaller when incrementing here if (line & 0x80) { line &= 0x7F; line++; w -= line; -#ifdef RPI_WRITE_STROBE - spi.writePattern(&textcolorBin[0], 2, 1); line--; - while(line--) {WR_L; WR_H;} -#else - #ifdef ESP32_PARALLEL - while (line--) {tft_Write_16(textcolor);} - #else - writeBlock(textcolor,line); - #endif -#endif + pushBlock(textcolor,line); } else { line++; w -= line; -#ifdef RPI_WRITE_STROBE - spi.writePattern(&textbgcolorBin[0], 2, 1); line--; - while(line--) {WR_L; WR_H;} -#else - #ifdef ESP32_PARALLEL - while (line--) {tft_Write_16(textbgcolor);} - #else - writeBlock(textbgcolor,line); - #endif -#endif + pushBlock(textbgcolor,line); } } } @@ -4582,8 +3442,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 cheight = fontHeight(font); } - if (textdatum || padX) - { + if (textdatum || padX) { switch(textdatum) { case TC_DATUM: @@ -4647,8 +3506,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 int8_t xo = 0; #ifdef LOAD_GFXFF - if (freeFont && (textcolor!=textbgcolor)) - { + if (freeFont && (textcolor!=textbgcolor)) { cheight = (glyph_ab + glyph_bb) * textsize; // Get the offset for the first character only to allow for negative offsets uint16_t c2 = 0; @@ -4657,8 +3515,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 while (n < len && c2 == 0) c2 = decodeUTF8((uint8_t*)string, &n, len - n); - if((c2 >= pgm_read_word(&gfxFont->first)) && (c2 <= pgm_read_word(&gfxFont->last) )) - { + if((c2 >= pgm_read_word(&gfxFont->first)) && (c2 <= pgm_read_word(&gfxFont->last) )) { c2 -= pgm_read_word(&gfxFont->first); GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]); xo = pgm_read_byte(&glyph->xOffset) * textsize; @@ -4678,8 +3535,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 uint16_t n = 0; #ifdef SMOOTH_FONT - if(fontLoaded) - { + if(fontLoaded) { if (textcolor!=textbgcolor) fillRect(poX, poY, cwidth, cheight, textbgcolor); //drawLine(poX - 5, poY, poX + 5, poY, TFT_GREEN); //drawLine(poX, poY - 5, poX, poY + 5, TFT_GREEN); @@ -4688,8 +3544,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 setCursor(poX, poY); - while (n < len) - { + while (n < len) { uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); drawGlyph(uniCode); } @@ -4699,8 +3554,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 else #endif { - while (n < len) - { + while (n < len) { uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); sumX += drawChar(uniCode, poX+sumX, poY, font); } @@ -4713,12 +3567,10 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 #ifndef PADDING_DEBUG //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - if((padX>cwidth) && (textcolor!=textbgcolor)) - { + if((padX>cwidth) && (textcolor!=textbgcolor)) { int16_t padXc = poX+cwidth+xo; #ifdef LOAD_GFXFF - if (freeFont) - { + if (freeFont) { poX +=xo; // Adjust for negative offset start character poY -= glyph_ab * textsize; sumX += poX; @@ -4748,8 +3600,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 // This is debug code to show text (green box) and blanked (white box) areas // It shows that the padding areas are being correctly sized and positioned - if((padX>sumX) && (textcolor!=textbgcolor)) - { + if((padX>sumX) && (textcolor!=textbgcolor)) { int16_t padXc = poX+sumX; // Maximum left side padding #ifdef LOAD_GFXFF if ((font == 1) && (gfxFont)) poY -= glyph_ab; @@ -4869,8 +3720,7 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t // Adjust the rounding value for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0; - if (floatNumber < -rounding) // add sign, avoid adding - sign to 0.0! - { + if (floatNumber < -rounding) { // add sign, avoid adding - sign to 0.0! str[ptr++] = '-'; // Negative number str[ptr] = 0; // Put a null in the array as a precaution digits = 0; // Set digits to 0 to compensate so pointer value can be used later @@ -4906,8 +3756,7 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t // Get decimal digits one by one and put in array // Limit digit count so we don't get a false sense of resolution uint8_t i = 0; - while ((i < dp) && (digits < 9)) // while (i < dp) for no limit but array size must be increased - { + while ((i < dp) && (digits < 9)) { // while (i < dp) for no limit but array size must be increased i++; floatNumber *= 10; // for the next decimal temp = floatNumber; // get the decimal @@ -4930,8 +3779,7 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t void TFT_eSPI::setFreeFont(const GFXfont *f) { - if (f == nullptr) // Fix issue #400 (ESP32 crash) - { + if (f == nullptr) { // Fix issue #400 (ESP32 crash) setTextFont(1); // Use GLCD font return; } @@ -4944,8 +3792,7 @@ void TFT_eSPI::setFreeFont(const GFXfont *f) uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first); // Find the biggest above and below baseline offsets - for (uint8_t c = 0; c < numChars; c++) - { + for (uint8_t c = 0; c < numChars; c++) { GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]); int8_t ab = -pgm_read_byte(&glyph1->yOffset); if (ab > glyph_ab) glyph_ab = ab; @@ -4988,267 +3835,20 @@ void TFT_eSPI::setTextFont(uint8_t f) { textfont = (f > 0) ? f : 1; // Don't allow font 0 } - -#endif - - -/*************************************************************************************** -** Function name: writeBlock -** 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% -// -#if defined (ESP8266) && !defined (ILI9488_DRIVER) -void writeBlock(uint16_t color, uint32_t repeat) -{ - uint16_t color16 = (color >> 8) | (color << 8); - uint32_t color32 = color16 | color16 << 16; - - SPI1W0 = color32; - SPI1W1 = color32; - SPI1W2 = color32; - SPI1W3 = color32; - if (repeat > 8) - { - SPI1W4 = color32; - SPI1W5 = color32; - SPI1W6 = color32; - SPI1W7 = color32; - } - if (repeat > 16) - { - SPI1W8 = color32; - SPI1W9 = color32; - SPI1W10 = color32; - SPI1W11 = color32; - } - if (repeat > 24) - { - SPI1W12 = color32; - SPI1W13 = color32; - SPI1W14 = color32; - SPI1W15 = color32; - } - if (repeat > 31) - { - SPI1U1 = (511 << SPILMOSI); - while(repeat>31) - { -#if defined SPI_FREQUENCY && (SPI_FREQUENCY == 80000000) - if(SPI1CMD & SPIBUSY) // added to sync with flag change -#endif - while(SPI1CMD & SPIBUSY) {} - SPI1CMD |= SPIBUSY; - repeat -= 32; - } - while(SPI1CMD & SPIBUSY) {} - } - - if (repeat) - { - repeat = (repeat << 4) - 1; - SPI1U1 = (repeat << SPILMOSI); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - } - -} - -#elif defined (ILI9488_DRIVER) - -#ifdef ESP8266 -void writeBlock(uint16_t color, uint32_t repeat) -{ - - // 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 (repeat > 4) - { - SPI1W3 = r0; - SPI1W4 = r1; - SPI1W5 = r2; - } - if (repeat > 8) - { - SPI1W6 = r0; - SPI1W7 = r1; - SPI1W8 = r2; - } - if (repeat > 12) - { - SPI1W9 = r0; - SPI1W10 = r1; - SPI1W11 = r2; - SPI1W12 = r0; - SPI1W13 = r1; - SPI1W14 = r2; - SPI1W15 = r0; - } - - if (repeat > 20) - { - SPI1U1 = (503 << SPILMOSI); - while(repeat>20) - { - while(SPI1CMD & SPIBUSY) {} - SPI1CMD |= SPIBUSY; - repeat -= 21; - } - while(SPI1CMD & SPIBUSY) {} - } - - if (repeat) - { - repeat = (repeat * 24) - 1; - SPI1U1 = (repeat << SPILMOSI); - SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) {} - } - -} -#else // Now the code for ESP32 and ILI9488 - -void writeBlock(uint16_t color, uint32_t repeat) -{ - // 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 (repeat > 19) - { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); - - while(repeat>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); - repeat -= 20; - } - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } - - if (repeat) - { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (repeat * 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 (repeat > 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); - } - -} -#endif - -#else // Low level register based ESP32 code for 16 bit colour SPI TFTs - -void writeBlock(uint16_t color, uint32_t repeat) -{ - uint32_t color32 = COL_32(color, color); - - if (repeat > 31) // Revert legacy toggle buffer change - { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); - while(repeat>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); - repeat -= 32; - } - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } - - if (repeat) - { - // Revert toggle buffer change - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (repeat << 4) - 1); - for (uint32_t i=0; i <= (repeat>>1); i++) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + (i << 2)), color32); - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } -} #endif /*************************************************************************************** ** Function name: getSPIinstance -** Description: Get the instance of the SPI class (for ESP32 only) +** Description: Get the instance of the SPI class ***************************************************************************************/ -#ifndef ESP32_PARALLEL +#if !defined (TFT_PARALLEL_8_BIT) SPIClass& TFT_eSPI::getSPIinstance(void) { return spi; } #endif - /*************************************************************************************** ** Function name: getSetup ** Description: Get the setup details for diagnostic and sketch access @@ -5257,10 +3857,8 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) { // tft_settings.version is set in header file -#if defined (ESP8266) - tft_settings.esp = 8266; -#elif defined (ESP32) - tft_settings.esp = 32; +#if defined (PROCESSOR_ID) + tft_settings.esp = PROCESSOR_ID; #else tft_settings.esp = -1; #endif @@ -5271,7 +3869,7 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.trans = false; #endif -#if defined (ESP32_PARALLEL) +#if defined (TFT_PARALLEL_8_BIT) tft_settings.serial = false; tft_settings.tft_spi_freq = 0; #else @@ -5360,7 +3958,7 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.pin_tft_rst = -1; #endif -#if defined (ESP32_PARALLEL) +#if defined (TFT_PARALLEL_8_BIT) tft_settings.pin_tft_d0 = TFT_D0; tft_settings.pin_tft_d1 = TFT_D1; tft_settings.pin_tft_d2 = TFT_D2; @@ -5389,6 +3987,7 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) #endif } + //////////////////////////////////////////////////////////////////////////////////////// #ifdef TOUCH_CS #include "Extensions/Touch.cpp" diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 84a8d1f3..95025783 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -15,14 +15,36 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "1.4.21" - -//#define ESP32 //Just used to test ESP32 options +#define TFT_ESPI_VERSION "1.4.30" // Include header file that defines the fonts loaded, the TFT drivers -// available and the pins to be used +// available and the pins to be used, etc, etc #include +//Standard support +#include +#include +#include + +#ifdef __AVR__ + #include +#elif defined(ESP8266) || defined(ESP32) + #include +#else + #define PROGMEM +#endif + +// Include the processor specific drivers +#if defined (ESP32) + #include "Processors/TFT_eSPI_ESP32.h" +#elif defined (ESP8266) + #include "Processors/TFT_eSPI_ESP8266.h" +#elif defined (STM32) + //#include "Processors/TFT_eSPI_STM32.h" +#else + //#include "Processors/TFT_eSPI_Generic.h" +#endif + #ifndef TAB_COLOUR #define TAB_COLOUR 0 #endif @@ -98,398 +120,12 @@ #endif #endif -#include -#include - -#include - -#include - -#ifdef ESP32 - #include "soc/spi_reg.h" - #ifdef USE_HSPI_PORT - #define SPI_PORT HSPI - #else - #define SPI_PORT VSPI - #endif -#endif - -#ifdef SMOOTH_FONT - // Call up the SPIFFS FLASH filing system for the anti-aliased fonts - #define FS_NO_GLOBALS - #include - - #ifdef ESP32 - #include "SPIFFS.h" - #endif -#endif - -#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 (ESP8266) && (TFT_DC == 16) - #define DC_C digitalWrite(TFT_DC, LOW) - #define DC_D digitalWrite(TFT_DC, HIGH) - #elif defined (ESP32) - #if defined (ESP32_PARALLEL) - #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_ILI9486_DRIVER // RPi display needs 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 - #else - #if TFT_DC >= 0 - #ifdef RPI_ILI9486_DRIVER // RPi display needs a slower DC change - #define DC_C GPIO.out_w1ts = (1 << TFT_DC); \ - GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) - #else - #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 - #else - #define DC_C GPOC=dcpinmask - #define DC_D GPOS=dcpinmask - #endif -#endif - -#if defined (TFT_SPI_OVERLAP) - #undef TFT_CS - #define SPI1U_WRITE (SPIUMOSI | SPIUSSE | SPIUCSSETUP | SPIUCSHOLD) - #define SPI1U_READ (SPIUMOSI | SPIUSSE | SPIUCSSETUP | SPIUCSHOLD | SPIUDUPLEX) -#else - #ifdef ESP8266 - #define SPI1U_WRITE (SPIUMOSI | SPIUSSE) - #define SPI1U_READ (SPIUMOSI | SPIUSSE | SPIUDUPLEX) - #endif -#endif - -#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 (ESP8266) && (TFT_CS == 16) - #define CS_L digitalWrite(TFT_CS, LOW) - #define CS_H digitalWrite(TFT_CS, HIGH) - #elif defined (ESP32) - #if defined (ESP32_PARALLEL) - #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_ILI9486_DRIVER // RPi display needs a slower CS change - #define CS_L GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #else - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #endif - #else - #if TFT_CS >= 0 - #ifdef RPI_ILI9486_DRIVER // RPi display needs a slower CS change - #define CS_L GPIO.out_w1ts = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) - #define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS) - #else - #define CS_L GPIO.out_w1tc = (1 << TFT_CS);GPIO.out_w1tc = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) - #endif - #else - #define CS_L - #define CS_H - #endif - #endif - #endif - #else - #define CS_L GPOC=cspinmask - #define CS_H GPOS=cspinmask - #endif -#endif - -// Use single register write for CS_L and DC_C if pins are both in range 0-31 -#ifdef ESP32 - #ifdef TFT_CS - #if (TFT_CS >= 0) && (TFT_CS < 32) && (TFT_DC >= 0) && (TFT_DC < 32) - #ifdef RPI_ILI9486_DRIVER // RPi display needs a slower CD and DC change - #define CS_L_DC_C GPIO.out_w1tc = ((1 << TFT_CS) | (1 << TFT_DC)); \ - GPIO.out_w1tc = ((1 << TFT_CS) | (1 << TFT_DC)) - #else - #define CS_L_DC_C GPIO.out_w1tc = ((1 << TFT_CS) | (1 << TFT_DC)); GPIO.out_w1tc = ((1 << TFT_CS) | (1 << TFT_DC)) - #endif - #else - #define CS_L_DC_C CS_L; DC_C - #endif - #else - #define CS_L_DC_C CS_L; DC_C - #endif -#else // ESP8266 - #define CS_L_DC_C CS_L; DC_C -#endif - -// chip select signal for touchscreen -#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 - - -#ifdef TFT_WR - #if defined (ESP32) - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) - #else - #define WR_L GPOC=wrpinmask - #define WR_H GPOS=wrpinmask - #endif -#endif - -#ifdef ESP8266 - // Concatenate two 16 bit values for the SPI 32 bit register write - #define SPI_32(H,L) ( (H)<<16 | (L) ) - #define COL_32(H,L) ( (H)<<16 | (L) ) -#else - #if defined (ESP32_PARALLEL) || defined (ILI9488_DRIVER) - #define SPI_32(H,L) ( (H)<<16 | (L) ) - #else - #define SPI_32(H,L) ( ((H)<<8 | (H)>>8) | (((L)<<8 | (L)>>8)<<16 ) ) - #endif - // Swap byte order for concatenated 16 bit colors - // AB CD -> DCBA for 32 bit register write - #define COL_32(H,L) ( ((H)<<8 | (H)>>8) | (((L)<<8 | (L)>>8)<<16 ) ) -#endif - -#if defined (ESP32) && defined (ESP32_PARALLEL) - // 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)<>6)<>5)<>4)<>3)<>2)<>1)<>0)<> 0)); WR_H - #else - #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 - #endif - - // 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 - - #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 - -#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) - -#elif defined (RPI_ILI9486_DRIVER) - - #define tft_Write_8(C) spi.transfer(0); spi.transfer(C) - #define tft_Write_16(C) spi.write16(C) - #define tft_Write_16S(C) spi.write16(C<<8 | C>>8) - #define tft_Write_32(C) spi.write32(C) - -#elif defined ESP8266 - - #define tft_Write_8(C) spi.write(C) - #define tft_Write_16(C) spi.write16(C) - #define tft_Write_32(C) spi.write32(C) - -#else // ESP32 using SPI with 16 bit color display - - // ESP32 low level SPI writes for 8, 16 and 32 bit values - // to avoid the function call overhead - - // Write 8 bits - #define tft_Write_8(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 8-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - - // Write 16 bits with corrected endianess for 16 bit colours - #define tft_Write_16(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 16-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C<<8 | C>>8); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - - // Write 16 bits - #define tft_Write_16S(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 16-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - - // Write 32 bits - #define tft_Write_32(C) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 32-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), C); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - -#endif - - -#if !defined (ESP32_PARALLEL) - - // Read from display using SPI or software SPI - #if defined (ESP8266) && defined (TFT_SDA_READ) - // Use a bit banged function call for ESP8266 and bi-directional SDA pin - #define SCLK_L GPOC=sclkpinmask - #define SCLK_H GPOS=sclkpinmask - #else - // Use a SPI read transfer - #define tft_Read_8() spi.transfer(0) - #endif - - // Make sure TFT_MISO is defined if not used to avoid an error message - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - -#endif - - #ifdef LOAD_GFXFF // We can include all the free fonts and they will only be built into // the sketch if they are used - #include - // Call up any user custom fonts #include - - // Original Adafruit_GFX "Free Fonts" - #include // TT1 - - #include // FF1 or FM9 - #include // FF2 or FM12 - #include // FF3 or FM18 - #include // FF4 or FM24 - - #include // FF5 or FMO9 - #include // FF6 or FMO12 - #include // FF7 or FMO18 - #include // FF8 or FMO24 - - #include // FF9 or FMB9 - #include // FF10 or FMB12 - #include // FF11 or FMB18 - #include // FF12 or FMB24 - - #include // FF13 or FMBO9 - #include // FF14 or FMBO12 - #include // FF15 or FMBO18 - #include // FF16 or FMBO24 - - // Sans serif fonts - #include // FF17 or FSS9 - #include // FF18 or FSS12 - #include // FF19 or FSS18 - #include // FF20 or FSS24 - - #include // FF21 or FSSO9 - #include // FF22 or FSSO12 - #include // FF23 or FSSO18 - #include // FF24 or FSSO24 - - #include // FF25 or FSSB9 - #include // FF26 or FSSB12 - #include // FF27 or FSSB18 - #include // FF28 or FSSB24 - - #include // FF29 or FSSBO9 - #include // FF30 or FSSBO12 - #include // FF31 or FSSBO18 - #include // FF32 or FSSBO24 - - // Serif fonts - #include // FF33 or FS9 - #include // FF34 or FS12 - #include // FF35 or FS18 - #include // FF36 or FS24 - - #include // FF37 or FSI9 - #include // FF38 or FSI12 - #include // FF39 or FSI18 - #include // FF40 or FSI24 - - #include // FF41 or FSB9 - #include // FF42 or FSB12 - #include // FF43 or FSB18 - #include // FF44 or FSB24 - - #include // FF45 or FSBI9 - #include // FF46 or FSBI12 - #include // FF47 or FSBI18 - #include // FF48 or FSBI24 - #endif // #ifdef LOAD_GFXFF //These enumerate the text plotting alignment (reference datum point) @@ -542,7 +178,7 @@ swap_coord(T& a, T& b) { T t = a; a = b; b = t; } #ifndef min // Return minimum of two numbers, may already be defined - #define min(a,b) (((a) < (b)) ? (a) : (b)) + // #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif // This structure allows sketches to retrieve the user setup parameters at runtime @@ -550,7 +186,7 @@ swap_coord(T& a, T& b) { T t = a; a = b; b = t; } typedef struct { String version = TFT_ESPI_VERSION; -int16_t esp; +int32_t esp; uint8_t trans; uint8_t serial; uint8_t overlap; @@ -702,7 +338,7 @@ class TFT_eSPI : public Print { fillRoundRect(int32_t x0, int32_t y0, int32_t w, int32_t h, int32_t radius, uint32_t color), setRotation(uint8_t r), - invertDisplay(boolean i), + invertDisplay(bool i), drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color), drawCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t cornername, uint32_t color), @@ -715,10 +351,12 @@ class TFT_eSPI : public Print { drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color), fillTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color), - drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color), - drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color), + drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), + drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), + drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), setBitmapColor(uint16_t fgcolor, uint16_t bgcolor), // For 1bpp sprites + setPivot(int16_t x, int16_t y), setCursor(int16_t x, int16_t y), setCursor(int16_t x, int16_t y, uint8_t font), @@ -726,7 +364,7 @@ class TFT_eSPI : public Print { setTextColor(uint16_t fgcolor, uint16_t bgcolor), setTextSize(uint8_t size), - setTextWrap(boolean wrapX, boolean wrapY = false), + setTextWrap(bool wrapX, bool wrapY = false), setTextDatum(uint8_t datum), setTextPadding(uint16_t x_width), @@ -769,7 +407,13 @@ class TFT_eSPI : public Print { void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true); void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true); - // Swap the byte order for pushImage() - corrects endianness + // Write a solid block of a single colour + void pushBlock(uint16_t color, uint32_t len); + + // 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); + + // Swap the byte order for pushImage() and pushPixels() - corrects endianness void setSwapBytes(bool swap); bool getSwapBytes(void); @@ -820,15 +464,17 @@ class TFT_eSPI : public Print { // Compatibility additions void startWrite(void); // Begin SPI transaction - void writeColor(uint16_t color, uint32_t len); // Write colours without transaction overhead + void writeColor(uint16_t color, uint32_t len); // Write colours without transaction overhead Deprecated, use pushBlock() void endWrite(void); // End SPI transaction uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining); uint16_t decodeUTF8(uint8_t c); + uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc); + size_t write(uint8_t); #ifdef TFT_SDA_READ - #if defined (ESP8266) && defined (TFT_SDA_READ) + #if defined (TFT_eSPI_ENABLE_8_BIT_READ) uint8_t tft_Read_8(void); #endif void begin_SDA_Read(void); @@ -867,8 +513,20 @@ class TFT_eSPI : public Print { inline void spi_begin_read() __attribute__((always_inline)); inline void spi_end_read() __attribute__((always_inline)); + // Private function, sketches must use pushPixels() with setSwapBytes(true) + void pushSwapBytePixels(const void* data_in, uint32_t len); + void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); + // Byte read prototype + uint8_t readByte(void); + + // GPIO parallel input/output control + void busDir(uint32_t mask, uint8_t mode); + + // Single GPIO input/output direction control + void gpioMode(uint8_t gpio, uint8_t mode); + uint8_t tabcolor, colstart = 0, rowstart = 0; // some ST7735 displays need this changed @@ -900,7 +558,7 @@ class TFT_eSPI : public Print { bool isDigits; // adjust bounding box for numbers to reduce visual jiggling bool textwrapX, textwrapY; // If set, 'wrap' text at right and optionally bottom edge of display bool _swapBytes; // Swap the byte order for TFT pushImage() - bool locked, inTransaction; // Transaction and mutex lock flags for ESP32 + bool locked, inTransaction; // Transaction and mutex lock flags bool _booted; // init() or begin() has already run once bool _cp437; // If set, use correct CP437 charset (default is ON) diff --git a/User_Setup.h b/User_Setup.h index 772b56b0..07dcbce5 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -15,6 +15,9 @@ // // ################################################################################## +// Display type - only define if RPi display +//#define RPI_DRIVER + // Only define one driver, the other ones must be commented out #define ILI9341_DRIVER //#define ST7735_DRIVER // Define additional parameters below for this display @@ -29,6 +32,7 @@ //#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display //#define R61581_DRIVER //#define RM68140_DRIVER +//#define ST7796_DRIVER // Some displays support SPI reads via the MISO pin, other displays have a single // bi-directional SDA pin and the library will try to read this via the MOSI line. diff --git a/User_Setup_Select.h b/User_Setup_Select.h index 6a5e1ab0..006ee5ca 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -52,6 +52,9 @@ //#include // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT //#include // Setup file for ESP32 and TTGO T-Wristband ST7735 SPI bus TFT +//#include // ESP32 RPi MHS-4.0 inch Display-B +//#include // ESP8266 RPi MHS-4.0 inch Display-B + //#include // Setup file configured for my ST7735S 80x160 //#include // Setup file for ESP8266 and ST7789 125 x 240 TFT @@ -89,6 +92,9 @@ #elif defined (S6D02A1_DRIVER) #include #define TFT_DRIVER 0x6D02 +#elif defined (ST7796_DRIVER) + #include "TFT_Drivers/ST7796_Defines.h" + #define TFT_DRIVER 0x7796 #elif defined (RPI_ILI9486_DRIVER) #include #define TFT_DRIVER 0x9486 @@ -117,8 +123,8 @@ #include "TFT_Drivers/ST7789_2_Defines.h" #define TFT_DRIVER 0x778B #elif defined (RM68140_DRIVER) - #include "TFT_Drivers/RM68140_Defines.h" - #define TFT_DRIVER 0x6814 + #include "TFT_Drivers/RM68140_Defines.h" + #define TFT_DRIVER 0x6814 #elif defined (XYZZY_DRIVER) // <<<<<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVER HERE #include "TFT_Drivers/XYZZY_Defines.h" #define TFT_DRIVER 0x0000 diff --git a/User_Setups/Setup27_RPi_ST7796_ESP32.h b/User_Setups/Setup27_RPi_ST7796_ESP32.h new file mode 100644 index 00000000..59b51900 --- /dev/null +++ b/User_Setups/Setup27_RPi_ST7796_ESP32.h @@ -0,0 +1,100 @@ +// USER DEFINED SETTINGS +// Set driver type, fonts to be loaded, pins used and SPI control method etc +// +// See the User_Setup_Select.h file if you wish to be able to define multiple +// setups and then easily select which setup file is used by the compiler. +// +// If this file is edited correctly then all the library example sketches should +// run without the need to make any more changes for a particular hardware setup! + +// ################################################################################## +// +// Section 0. Call up the right driver file and any options for it +// +// ################################################################################## + +// Display type - only define if RPi display +#define RPI_DRIVER + +// Only define one driver +#define ST7796_DRIVER + +// ################################################################################## +// +// Section 1. Define the pins that are used to interface with the display here +// +// ################################################################################## + +// >>>>> EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP <<<<< + +// The ESP32 hardware SPI can be mapped to any pins, these are the recommended default + +#define TFT_MISO 19 +#define TFT_MOSI 23 +#define TFT_SCLK 18 +#define TFT_CS 15 // Chip select control pin +#define TFT_DC 2 // Data Command control pin +#define TFT_RST 4 // Reset pin (could connect to RST pin) +//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST + +#define TOUCH_CS 22 // Chip select pin (T_CS) of touch screen + +// ################################################################################## +// +// Section 2. Not used for ESP32 +// +// ################################################################################## + + +// ################################################################################## +// +// Section 3. Define the fonts that are to be used here +// +// ################################################################################## + +// Comment out the #defines below with // to stop that font being loaded +// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not +// normally necessary. If all fonts are loaded the extra FLASH space required is +// about 17Kbytes. To save FLASH space only enable the fonts you need! + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded +// this will save ~20kbytes of FLASH +#define SMOOTH_FONT + +// ################################################################################## +// +// Section 4. Not used +// +// ################################################################################## + + +// ################################################################################## +// +// Section 5. Other options +// +// ################################################################################## + +// Define the SPI clock frequency, this affects the graphics rendering speed. Too +// fast and the TFT driver will not keep up and display corruption appears. +// With an RPi ST7796 MH4.0 display 80MHz is OK for ESP32, 40MHz maximum for ESP8266 + +// #define SPI_FREQUENCY 20000000 +// #define SPI_FREQUENCY 40000000 + #define SPI_FREQUENCY 80000000 + +// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. +// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) +// then uncomment the following line: +//#define USE_HSPI_PORT + +// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: + #define SPI_TOUCH_FREQUENCY 2500000 diff --git a/User_Setups/Setup28_RPi_ST7796_ESP8266.h b/User_Setups/Setup28_RPi_ST7796_ESP8266.h new file mode 100644 index 00000000..23839a08 --- /dev/null +++ b/User_Setups/Setup28_RPi_ST7796_ESP8266.h @@ -0,0 +1,105 @@ +// USER DEFINED SETTINGS +// Set driver type, fonts to be loaded, pins used and SPI control method etc +// +// See the User_Setup_Select.h file if you wish to be able to define multiple +// setups and then easily select which setup file is used by the compiler. +// +// If this file is edited correctly then all the library example sketches should +// run without the need to make any more changes for a particular hardware setup! + +// ################################################################################## +// +// Section 0. Call up the right driver file and any options for it +// +// ################################################################################## + +// Display type - only define if RPi display +#define RPI_DRIVER + +// Only define one driver +#define ST7796_DRIVER + +// ################################################################################## +// +// Section 1. Define the pins that are used to interface with the display here +// +// ################################################################################## + +// >>>> EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP <<<< + +// These are the recommended default + +// Avoid PIN_D8 as this will prevent upload if display pulls the pin high at boot + +// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation +#define TFT_CS PIN_D2 // Chip select control pin D2 +#define TFT_DC PIN_D3 // Data Command control pin +#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line) +//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V + +#define TOUCH_CS PIN_D1 // Chip select pin (T_CS) of touch screen + +// ################################################################################## +// +// Section 2. Not used for ESP32 +// +// ################################################################################## + + +// ################################################################################## +// +// Section 3. Define the fonts that are to be used here +// +// ################################################################################## + +// Comment out the #defines below with // to stop that font being loaded +// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not +// normally necessary. If all fonts are loaded the extra FLASH space required is +// about 17Kbytes. To save FLASH space only enable the fonts you need! + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded +// this will save ~20kbytes of FLASH +#define SMOOTH_FONT + +// ################################################################################## +// +// Section 4. Not used +// +// ################################################################################## + + +// ################################################################################## +// +// Section 5. Other options +// +// ################################################################################## + +// Define the SPI clock frequency, this affects the graphics rendering speed. Too +// fast and the TFT driver will not keep up and display corruption appears. +// With an RPi ST7796 MH4.0 display 80MHz is OK for ESP32, 40MHz maximum for ESP8266 + +// #define SPI_FREQUENCY 20000000 + #define SPI_FREQUENCY 40000000 + +#define SPI_TOUCH_FREQUENCY 2500000 + +// Comment out the following #define if "SPI Transactions" do not need to be +// supported. When commented out the code size will be smaller and sketches will +// run slightly faster, so leave it commented out unless you need it! + +// Transaction support is needed to work with SD library but not needed with TFT_SdFat +// Transaction support is required if other SPI devices are connected. + +// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex) +// so changing it here has no effect + +#define SUPPORT_TRANSACTIONS diff --git a/keywords.txt b/keywords.txt index f89d9816..8de40ed1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -5,7 +5,6 @@ drawPixel KEYWORD2 drawChar KEYWORD2 setAddrWindow KEYWORD2 setWindow KEYWORD2 -readAddrWindow KEYWORD2 startWrite KEYWORD2 writeColor KEYWORD2 endWrite KEYWORD2 @@ -72,6 +71,21 @@ height KEYWORD2 width KEYWORD2 textWidth KEYWORD2 fontHeight KEYWORD2 +getSetup KEYWORD2 +setAttribute KEYWORD2 +getAttribute KEYWORD2 +alphaBlend KEYWORD2 + +getSPIinstance KEYWORD2 +pushBlock KEYWORD2 +pushPixels KEYWORD2 + +initDMA KEYWORD2 +deInitDMA KEYWORD2 +pushImageDMA KEYWORD2 +pushBlockDMA KEYWORD2 +pushPixelsDMA KEYWORD2 +dmaBusy KEYWORD2 getTouchRaw KEYWORD2 convertRawXY KEYWORD2 @@ -100,6 +114,7 @@ setColorDepth KEYWORD2 getColorDepth KEYWORD2 deleteSprite KEYWORD2 pushRotated KEYWORD2 +pushRotatedHP KEYWORD2 rotatedBounds KEYWORD2 setPivot KEYWORD2 getPivotX KEYWORD2 @@ -113,7 +128,6 @@ printToSprite KEYWORD2 frameBuffer KEYWORD2 setBitmapColor KEYWORD2 -alphaBlend KEYWORD2 showFont KEYWORD2 loadFont KEYWORD2 unloadFont KEYWORD2 diff --git a/library.json b/library.json index 474ebcb2..fa100ef3 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "1.4.21", + "version": "1.4.30", "keywords": "tft, ePaper, display, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library for ESP8266 and ESP32", "repository": diff --git a/library.properties b/library.properties index d7f2e397..e1588b09 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=1.4.21 +version=1.4.30 author=Bodmer maintainer=Bodmer sentence=A fast TFT graphics library for ESP8266 and ESP32 processors for the Arduino IDE