diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 6226d4f..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -buy_me_a_coffee: pe5pb diff --git a/include/constants.h b/include/constants.h index 2862100..0774a49 100644 --- a/include/constants.h +++ b/include/constants.h @@ -1,6 +1,6 @@ #pragma once -#define VERSION "v2.20.5b" +#define VERSION "v2.20.5c" #define REVERSE false @@ -15,18 +15,14 @@ (x_ < y_) ? x_ : y_; } #define TIMER_OFFSET_TIMER (TIMER_500_TICK) -#define TIMER_BW_TIMER (TIMER_500_TICK) -#define TIMER_SNR_TIMER 100 -#define TIMER_BAT_TIMER (TIMER_500_TICK) +#define TIMER_BW_TIMER 300 +#define TIMER_SNR_TIMER 50 +#define TIMER_BAT_TIMER 250 #define TIMER_500_TICK 500 -#define BAT_LEVEL_EMPTY 1600 -#define BAT_LEVEL_WARN 1700 -#define BAT_LEVEL_FULL 2270 #define BAT_LEVEL_STAGE 4 -#define BATTERY_WARN_VALUE 3.68 -#define BATTERY_LOW_VALUE 3.0 -#define BATTERY_FULL_VALUE 4.2 +#define BATTERY_LOW_VALUE 3.2 +#define BATTERY_FULL_VALUE 4.12 #define XTAL_0V_ADC 0 #define XTAL_1V_ADC 1050 @@ -57,8 +53,6 @@ #define FREQ_FM_OIRT_START 6500 // use values of 1/10 * kHz #define FREQ_FM_OIRT_END 7400 // use values of 1/10 * kHz -#define FM_DEEMPHASIS_50 50 -#define FM_DEEMPHASIS_75 75 #define REGION_EU 0 #define REGION_US 1 diff --git a/include/globals.h b/include/globals.h index 24e76b8..40a020d 100644 --- a/include/globals.h +++ b/include/globals.h @@ -101,7 +101,6 @@ extern byte band; extern byte bandAM; extern byte bandFM; extern byte bandforbidden; -extern byte battery; extern byte batteryold; extern byte batteryoptions; extern byte BWset; diff --git a/include/gui.h b/include/gui.h index adbfb09..9d667a9 100644 --- a/include/gui.h +++ b/include/gui.h @@ -7,7 +7,6 @@ static const char* const unitString[] = {"dBμV", "dBf", "dBm"}; static const char* const FreqFont[] = {"Classic", "Roubenstil", "Motoya", "Aura2", "Comic", "Modern"}; static const char* const Theme[] = {"Essence", "Cyan", "Crimson", "Monochrome", "Volcano", "Dendro", "Sakura", "Whiteout", "Tangerine", "Ocean", "Indigo", "Queer", "GoldBrite", "Bubblegum"}; -static const char* const Skin[] = {"Essential"}; static const char* BWButtonLabelsFM[] = {"56 kHz", "64 kHz", "72 kHz", "84 kHz", "97 kHz", "114 kHz", "133 kHz", "151 kHz", "168 kHz", "184 kHz", "200 kHz", "217 kHz", "236 kHz", "254 kHz", "287 kHz", "311 kHz", "Auto", "iMS", "EQ"}; static const char* BWButtonLabelsAM[] = {"3 kHz", "4 kHz", "6 kHz", "8 kHz"}; diff --git a/include/nonvolatile.h b/include/nonvolatile.h new file mode 100644 index 0000000..1bc9c25 --- /dev/null +++ b/include/nonvolatile.h @@ -0,0 +1,9 @@ +#include +#include "globals.h" +#include "logbook.h" + +void StoreFrequency(); +void ClearMemoryRange(uint8_t start, uint8_t stop); +void saveData(); +void loadData(); +void DefaultSettings(); \ No newline at end of file diff --git a/lib/TFT_eSPI/CMakeLists.txt b/lib/TFT_eSPI/CMakeLists.txt deleted file mode 100644 index b849c3c..0000000 --- a/lib/TFT_eSPI/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ - -idf_component_register(SRCS "TFT_eSPI.cpp" - INCLUDE_DIRS "." - PRIV_REQUIRES arduino) \ No newline at end of file diff --git a/lib/TFT_eSPI/Extensions/Button.cpp b/lib/TFT_eSPI/Extensions/Button.cpp deleted file mode 100644 index 9c93098..0000000 --- a/lib/TFT_eSPI/Extensions/Button.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/*************************************************************************************** -** Code for the GFX button UI element -** Grabbed from Adafruit_GFX library and enhanced to handle any label font -***************************************************************************************/ -TFT_eSPI_Button::TFT_eSPI_Button(void) { - _gfx = nullptr; - _xd = 0; - _yd = 0; - _textdatum = MC_DATUM; - _label[9] = '\0'; - currstate = false; - laststate = false; -} - -// Classic initButton() function: pass center & size -void TFT_eSPI_Button::initButton( - TFT_eSPI *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h, - uint16_t outline, uint16_t fill, uint16_t textcolor, - char *label, uint8_t textsize) -{ - // Tweak arguments and pass to the newer initButtonUL() function... - initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, - textcolor, label, textsize); -} - -// Newer function instead accepts upper-left corner & size -void TFT_eSPI_Button::initButtonUL( - TFT_eSPI *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h, - uint16_t outline, uint16_t fill, uint16_t textcolor, - char *label, uint8_t textsize) -{ - _x1 = x1; - _y1 = y1; - _w = w; - _h = h; - _outlinecolor = outline; - _fillcolor = fill; - _textcolor = textcolor; - _textsize = textsize; - _gfx = gfx; - strncpy(_label, label, 9); -} - -// Adjust text datum and x, y deltas -void TFT_eSPI_Button::setLabelDatum(int16_t x_delta, int16_t y_delta, uint8_t datum) -{ - _xd = x_delta; - _yd = y_delta; - _textdatum = datum; -} - -void TFT_eSPI_Button::drawButton(bool inverted, String long_name) { - uint16_t fill, outline, text; - - if(!inverted) { - fill = _fillcolor; - outline = _outlinecolor; - text = _textcolor; - } else { - fill = _textcolor; - outline = _outlinecolor; - text = _fillcolor; - } - - uint8_t r = min(_w, _h) / 4; // Corner radius - _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); - _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); - - if (_gfx->textfont == 255) { - _gfx->setCursor(_x1 + (_w / 8), - _y1 + (_h / 4)); - _gfx->setTextColor(text); - _gfx->setTextSize(_textsize); - _gfx->print(_label); - } - else { - _gfx->setTextColor(text, fill); - _gfx->setTextSize(_textsize); - - uint8_t tempdatum = _gfx->getTextDatum(); - _gfx->setTextDatum(_textdatum); - uint16_t tempPadding = _gfx->getTextPadding(); - _gfx->setTextPadding(0); - - if (long_name == "") - _gfx->drawString(_label, _x1 + (_w/2) + _xd, _y1 + (_h/2) - 4 + _yd); - else - _gfx->drawString(long_name, _x1 + (_w/2) + _xd, _y1 + (_h/2) - 4 + _yd); - - _gfx->setTextDatum(tempdatum); - _gfx->setTextPadding(tempPadding); - } -} - -bool TFT_eSPI_Button::contains(int16_t x, int16_t y) { - return ((x >= _x1) && (x < (_x1 + _w)) && - (y >= _y1) && (y < (_y1 + _h))); -} - -void TFT_eSPI_Button::press(bool p) { - laststate = currstate; - currstate = p; -} - -bool TFT_eSPI_Button::isPressed() { return currstate; } -bool TFT_eSPI_Button::justPressed() { return (currstate && !laststate); } -bool TFT_eSPI_Button::justReleased() { return (!currstate && laststate); } diff --git a/lib/TFT_eSPI/Extensions/Button.h b/lib/TFT_eSPI/Extensions/Button.h deleted file mode 100644 index 3a0e2d5..0000000 --- a/lib/TFT_eSPI/Extensions/Button.h +++ /dev/null @@ -1,44 +0,0 @@ -/*************************************************************************************** -// The following button class has been ported over from the Adafruit_GFX library so -// should be compatible. -// A slightly different implementation in this TFT_eSPI library allows the button -// legends to be in any font, allow longer labels and to adjust text positioning -// within button -***************************************************************************************/ - -class TFT_eSPI_Button -{ - public: - TFT_eSPI_Button(void); - // "Classic" initButton() uses centre & size - void initButton(TFT_eSPI *gfx, int16_t x, int16_t y, - uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, - uint16_t textcolor, char *label, uint8_t textsize); - - // New/alt initButton() uses upper-left corner & size - void initButtonUL(TFT_eSPI *gfx, int16_t x1, int16_t y1, - uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, - uint16_t textcolor, char *label, uint8_t textsize); - - // Adjust text datum and x, y deltas - void setLabelDatum(int16_t x_delta, int16_t y_delta, uint8_t datum = MC_DATUM); - - void drawButton(bool inverted = false, String long_name = ""); - bool contains(int16_t x, int16_t y); - - void press(bool p); - bool isPressed(); - bool justPressed(); - bool justReleased(); - - private: - TFT_eSPI *_gfx; - int16_t _x1, _y1; // Coordinates of top-left corner of button - int16_t _xd, _yd; // Button text datum offsets (wrt centre of button) - uint16_t _w, _h; // Width and height of button - uint8_t _textsize, _textdatum; // Text size multiplier and text datum for button - uint16_t _outlinecolor, _fillcolor, _textcolor; - char _label[10]; // Button text is 9 chars maximum unless long_name used - - bool currstate, laststate; // Button states -}; diff --git a/lib/TFT_eSPI/Extensions/Smooth_font.cpp b/lib/TFT_eSPI/Extensions/Smooth_font.cpp deleted file mode 100644 index 686c0ec..0000000 --- a/lib/TFT_eSPI/Extensions/Smooth_font.cpp +++ /dev/null @@ -1,569 +0,0 @@ - // Coded by Bodmer 10/2/18, see license in root directory. - // This is part of the TFT_eSPI class and is associated with anti-aliased font functions - - -//////////////////////////////////////////////////////////////////////////////////////// -// New anti-aliased (smoothed) font functions added below -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: loadFont -** Description: loads parameters from a font vlw array in memory -*************************************************************************************x*/ -void TFT_eSPI::loadFont(const uint8_t array[]) -{ - if (array == nullptr) return; - fontPtr = (uint8_t*) array; - loadFont("", false); -} - -#ifdef FONT_FS_AVAILABLE -/*************************************************************************************** -** Function name: loadFont -** Description: loads parameters from a font vlw file -*************************************************************************************x*/ -void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) -{ - fontFS = ffs; - loadFont(fontName, false); -} -#endif - -/*************************************************************************************** -** Function name: loadFont -** Description: loads parameters from a font vlw file -*************************************************************************************x*/ -void TFT_eSPI::loadFont(String fontName, bool flash) -{ - /* - The vlw font format does not appear to be documented anywhere, so some reverse - engineering has been applied! - - Header of vlw file comprises 6 uint32_t parameters (24 bytes total): - 1. The gCount (number of character glyphs) - 2. A version number (0xB = 11 for the one I am using) - 3. The font size (in points, not pixels) - 4. Deprecated mboxY parameter (typically set to 0) - 5. Ascent in pixels from baseline to top of "d" - 6. Descent in pixels from baseline to bottom of "p" - - Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes): - 1. Glyph Unicode stored as a 32-bit value - 2. Height of bitmap bounding box - 3. Width of bitmap bounding box - 4. gxAdvance for cursor (setWidth in Processing) - 5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up) - 6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left) - 7. padding value, typically 0 - - The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file. - Each pixel is 1 byte, an 8-bit Alpha value which represents the transparency from - 0xFF foreground colour, 0x00 background. The library uses a linear interpolation - between the foreground and background RGB component colours. e.g. - pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255 - To gain a performance advantage fixed point arithmetic is used with rounding and - division by 256 (shift right 8 bits is faster). - - After the bitmaps is: - 1 byte for font name string length (excludes null) - a zero terminated character string giving the font name - 1 byte for Postscript name string length - a zero/one terminated character string giving the font name - last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) - - - Glyph bitmap example is: - // Cursor coordinate positions for this and next character are marked by 'C' - // C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position - // | | - // | | ascent is top of "d", descent is bottom of "p" - // +-- gdX --+ ascent - // | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap - // | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of - // | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX) - // | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions - // | | .@@@.....@@@@ | | - // | gHeight ....@@@@@..@@ + + <-- baseline - // | | ...........@@ | - // | | ...........@@ | gdY is the offset to the top edge of the bitmap - // | | .@@.......@@. descent plot top edge of bitmap at (cursorY + ascent - gdY) - // | + 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 - - */ - - if (fontLoaded) unloadFont(); - -#ifdef FONT_FS_AVAILABLE - if (fontName == "") fs_font = false; - else { fontPtr = nullptr; fs_font = true; } - - if (fs_font) { - spiffs = flash; // true if font is in SPIFFS - - if(spiffs) fontFS = SPIFFS; - - // Avoid a crash on the ESP32 if the file does not exist - if (fontFS.exists("/" + fontName + ".vlw") == false) { - Serial.println("Font file " + fontName + " not found!"); - return; - } - - fontFile = fontFS.open( "/" + fontName + ".vlw", "r"); - - if(!fontFile) return; - - fontFile.seek(0, fs::SeekSet); - } -#else - // Avoid unused varaible warning - fontName = fontName; - flash = flash; -#endif - - gFont.gArray = (const uint8_t*)fontPtr; - - gFont.gCount = (uint16_t)readInt32(); // glyph count in file - readInt32(); // vlw encoder version - discard - gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels - readInt32(); // discard - gFont.ascent = (uint16_t)readInt32(); // top of "d" - gFont.descent = (uint16_t)readInt32(); // bottom of "p" - - // These next gFont values might be updated when the Metrics are fetched - gFont.maxAscent = gFont.ascent; // Determined from metrics - gFont.maxDescent = gFont.descent; // Determined from metrics - gFont.yAdvance = gFont.ascent + gFont.descent; - gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width - - fontLoaded = true; - - // Fetch the metrics for each glyph - loadMetrics(); -} - - -/*************************************************************************************** -** Function name: loadMetrics -** Description: Get the metrics for each glyph and store in RAM -*************************************************************************************x*/ -//#define SHOW_ASCENT_DESCENT -void TFT_eSPI::loadMetrics(void) -{ - uint32_t headerPtr = 24; - uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; - - { - gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16-bit Basic Multilingual Plane (0-FFFF) - gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph - gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph - gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor - gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character - gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X - gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file - } - -#ifdef SHOW_ASCENT_DESCENT - Serial.print("ascent = "); Serial.println(gFont.ascent); - Serial.print("descent = "); Serial.println(gFont.descent); -#endif - -#ifdef FONT_FS_AVAILABLE - if (fs_font) fontFile.seek(headerPtr, fs::SeekSet); -#endif - - uint16_t gNum = 0; - - while (gNum < gFont.gCount) - { - gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value - gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph - gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph - gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor - gdY[gNum] = (int16_t)readInt32(); // y delta from baseline - gdX[gNum] = (int8_t)readInt32(); // x delta from cursor - readInt32(); // ignored - - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]); - - // Different glyph sets have different ascent values not always based on "d", so we could get - // the maximum glyph ascent by checking all characters. BUT this method can generate bad values - // for non-existent glyphs, so we will reply on processing for the value and disable this code for now... - /* - if (gdY[gNum] > gFont.maxAscent) - { - // Try to avoid UTF coding values and characters that tend to give duff values - if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0)) - { - gFont.maxAscent = gdY[gNum]; -#ifdef SHOW_ASCENT_DESCENT - Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent); -#endif - } - } - */ - - // Different glyph sets have different descent values not always based on "p", so get maximum glyph descent - if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent) - { - // Avoid UTF coding values and characters that tend to give duff values - if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF)) - { - gFont.maxDescent = gHeight[gNum] - gdY[gNum]; -#ifdef SHOW_ASCENT_DESCENT - Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxDescent = "); Serial.println(gHeight[gNum] - gdY[gNum]); -#endif - } - } - - gBitmap[gNum] = bitmapPtr; - - bitmapPtr += gWidth[gNum] * gHeight[gNum]; - - gNum++; - yield(); - } - - gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; - - gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width -} - - -/*************************************************************************************** -** Function name: deleteMetrics -** Description: Delete the old glyph metrics and free up the memory -*************************************************************************************x*/ -void TFT_eSPI::unloadFont( void ) -{ - if (gUnicode) - { - free(gUnicode); - gUnicode = NULL; - } - - if (gHeight) - { - free(gHeight); - gHeight = NULL; - } - - if (gWidth) - { - free(gWidth); - gWidth = NULL; - } - - if (gxAdvance) - { - free(gxAdvance); - gxAdvance = NULL; - } - - if (gdY) - { - free(gdY); - gdY = NULL; - } - - if (gdX) - { - free(gdX); - gdX = NULL; - } - - if (gBitmap) - { - free(gBitmap); - gBitmap = NULL; - } - - gFont.gArray = nullptr; - -#ifdef FONT_FS_AVAILABLE - if (fs_font && fontFile) fontFile.close(); -#endif - - fontLoaded = false; -} - - -/*************************************************************************************** -** Function name: readInt32 -** Description: Get a 32-bit integer from the font file -*************************************************************************************x*/ -uint32_t TFT_eSPI::readInt32(void) -{ - uint32_t val = 0; - -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - val = (uint32_t)fontFile.read() << 24; - val |= (uint32_t)fontFile.read() << 16; - val |= (uint32_t)fontFile.read() << 8; - val |= (uint32_t)fontFile.read(); - } - else -#endif - { - val = (uint32_t)pgm_read_byte(fontPtr++) << 24; - val |= (uint32_t)pgm_read_byte(fontPtr++) << 16; - val |= (uint32_t)pgm_read_byte(fontPtr++) << 8; - val |= (uint32_t)pgm_read_byte(fontPtr++); - } - - return val; -} - - -/*************************************************************************************** -** Function name: getUnicodeIndex -** Description: Get the font file index of a Unicode character -*************************************************************************************x*/ -bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) -{ - for (uint16_t i = 0; i < gFont.gCount; i++) - { - if (gUnicode[i] == unicode) - { - *index = i; - return true; - } - } - return false; -} - - -/*************************************************************************************** -** Function name: drawGlyph -** Description: Write a character to the TFT cursor position -*************************************************************************************x*/ -// Expects file to be open -void TFT_eSPI::drawGlyph(uint16_t code) -{ - uint16_t fg = textcolor; - uint16_t bg = textbgcolor; - - // Check if cursor has moved - if (last_cursor_x != cursor_x) - { - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; - } - - if (code < 0x21) - { - if (code == 0x20) { - if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); - cursor_x += gFont.spaceWidth; - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; - return; - } - - if (code == '\n') { - cursor_x = 0; - bg_cursor_x = 0; - last_cursor_x = 0; - cursor_y += gFont.yAdvance; - if (textwrapY && (cursor_y >= height())) cursor_y = 0; - return; - } - } - - uint16_t gNum = 0; - bool found = getUnicodeIndex(code, &gNum); - - if (found) - { - - if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width())) - { - cursor_y += gFont.yAdvance; - cursor_x = 0; - bg_cursor_x = 0; - } - if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; - if (cursor_x == 0) cursor_x -= gdX[gNum]; - - uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; - -#ifdef FONT_FS_AVAILABLE - if (fs_font) - { - fontFile.seek(gBitmap[gNum], fs::SeekSet); - pbuffer = (uint8_t*)malloc(gWidth[gNum]); - } -#endif - - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; - - // if (cx > width() && bg_cursor_x > width()) return; - // if (cursor_y > height()) return; - - int16_t fxs = cx; - uint32_t fl = 0; - int16_t bxs = cx; - uint32_t bl = 0; - int16_t bx = 0; - uint8_t pixel; - - startWrite(); // Avoid slow ESP32 transaction overhead for every pixel - - int16_t fillwidth = 0; - int16_t fillheight = 0; - - // Fill area above glyph - if (_fillbg) { - fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; - if (fillwidth > 0) { - fillheight = gFont.maxAscent - gdY[gNum]; - // Could be negative - if (fillheight > 0) { - fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); - } - } - else { - // Could be negative - fillwidth = 0; - } - - // Fill any area to left of glyph - if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); - // Set x position in glyph area where background starts - if (bg_cursor_x > cx) bx = bg_cursor_x - cx; - // Fill any area to right of glyph - if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) { - fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); - } - } - - for (int32_t y = 0; y < gHeight[gNum]; y++) - { -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - if (spiffs) - { - fontFile.read(pbuffer, gWidth[gNum]); - //Serial.println("SPIFFS"); - } - else - { - endWrite(); // Release SPI for SD card transaction - fontFile.read(pbuffer, gWidth[gNum]); - startWrite(); // Re-start SPI for TFT transaction - //Serial.println("Not SPIFFS"); - } - } -#endif - - for (int32_t x = 0; x < gWidth[gNum]; x++) - { -#ifdef FONT_FS_AVAILABLE - if (fs_font) pixel = pbuffer[x]; - else -#endif - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); - - if (pixel) - { - if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } - if (pixel != 0xFF) - { - if (fl) { - if (fl==1) drawPixel(fxs, y + cy, fg); - else drawFastHLine( fxs, y + cy, fl, fg); - fl = 0; - } - if (getColor) bg = getColor(x + cx, y + cy); - drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg)); - } - else - { - if (fl==0) fxs = x + cx; - fl++; - } - } - else - { - if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } - if (_fillbg) { - if (x >= bx) { - if (bl==0) bxs = x + cx; - bl++; - } - } - } - } - if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } - if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } - } - - // Fill area below glyph - if (fillwidth > 0) { - fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); - if (fillheight > 0) { - fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); - } - } - - if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; - endWrite(); - } - else - { - // Point code not in font so draw a rectangle and move on cursor - drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); - cursor_x += gFont.spaceWidth + 1; - } - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; -} - -/*************************************************************************************** -** Function name: showFont -** Description: Page through all characters in font, td ms between screens -*************************************************************************************x*/ -void TFT_eSPI::showFont(uint32_t td) -{ - if(!fontLoaded) return; - - int16_t cursorX = width(); // Force start of new page to initialise cursor - int16_t cursorY = height();// for the first character - uint32_t timeDelay = 0; // No delay before first page - - fillScreen(textbgcolor); - - for (uint16_t i = 0; i < gFont.gCount; i++) - { - // Check if this will need a new screen - if (cursorX + gdX[i] + gWidth[i] >= width()) { - cursorX = -gdX[i]; - - cursorY += gFont.yAdvance; - if (cursorY + gFont.maxAscent + gFont.descent >= height()) { - cursorX = -gdX[i]; - cursorY = 0; - delay(timeDelay); - timeDelay = td; - fillScreen(textbgcolor); - } - } - - setCursor(cursorX, cursorY); - drawGlyph(gUnicode[i]); - cursorX += gxAdvance[i]; - yield(); - } - - delay(timeDelay); - fillScreen(textbgcolor); -} diff --git a/lib/TFT_eSPI/Extensions/Smooth_font.h b/lib/TFT_eSPI/Extensions/Smooth_font.h deleted file mode 100644 index c31dcad..0000000 --- a/lib/TFT_eSPI/Extensions/Smooth_font.h +++ /dev/null @@ -1,61 +0,0 @@ - // Coded by Bodmer 10/2/18, see license in root directory. - // This is part of the TFT_eSPI class and is associated with anti-aliased font functions - - public: - - // These are for the new anti-aliased fonts - void loadFont(const uint8_t array[]); -#ifdef FONT_FS_AVAILABLE - void loadFont(String fontName, fs::FS &ffs); -#endif - void loadFont(String fontName, bool flash = true); - void unloadFont( void ); - bool getUnicodeIndex(uint16_t unicode, uint16_t *index); - - virtual void drawGlyph(uint16_t code); - - void showFont(uint32_t td); - - // This is for the whole font - typedef struct - { - const uint8_t* gArray; //array start pointer - uint16_t gCount; // Total number of characters - uint16_t yAdvance; // Line advance - uint16_t spaceWidth; // Width of a space character - int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller - int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent - uint16_t maxAscent; // Maximum ascent found in font - uint16_t maxDescent; // Maximum descent found in font - } fontMetrics; - -fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; - - // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) - uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential - uint8_t* gHeight = NULL; //cheight - uint8_t* gWidth = NULL; //cwidth - uint8_t* gxAdvance = NULL; //setWidth - int16_t* gdY = NULL; //topExtent - int8_t* gdX = NULL; //leftExtent - uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap - - bool fontLoaded = false; // Flags when a anti-aliased font is loaded - -#ifdef FONT_FS_AVAILABLE - fs::File fontFile; - fs::FS &fontFS = SPIFFS; - bool spiffs = true; - bool fs_font = false; // For ESP32/8266 use smooth font file or FLASH (PROGMEM) array - -#else - bool fontFile = true; -#endif - - private: - - void loadMetrics(void); - uint32_t readInt32(void); - - uint8_t* fontPtr = nullptr; - diff --git a/lib/TFT_eSPI/Extensions/Sprite.cpp b/lib/TFT_eSPI/Extensions/Sprite.cpp deleted file mode 100644 index 01c3fc7..0000000 --- a/lib/TFT_eSPI/Extensions/Sprite.cpp +++ /dev/null @@ -1,2676 +0,0 @@ -/************************************************************************************** -// The following class creates Sprites in RAM, graphics can then be drawn in the Sprite -// and rendered quickly onto the TFT screen. The class inherits the graphics functions -// from the TFT_eSPI class. Some functions are overridden by this class so that the -// graphics are written to the Sprite rather than the TFT. -// Coded by Bodmer, see license file in root folder -***************************************************************************************/ -/*************************************************************************************** -// Color bytes are swapped when writing to RAM, this introduces a small overhead but -// there is a nett performance gain by using swapped bytes. -***************************************************************************************/ - -/*************************************************************************************** -** Function name: TFT_eSprite -** Description: Class constructor -***************************************************************************************/ -TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) -{ - _tft = tft; // Pointer to tft class so we can call member functions - - _iwidth = 0; // Initialise width and height to 0 (it does not exist yet) - _iheight = 0; - _bpp = 16; - _swapBytes = false; // Do not swap pushImage colour bytes by default - - _created = false; - _vpOoB = true; - - _xs = 0; // window bounds for pushColor - _ys = 0; - _xe = 0; - _ye = 0; - - _xptr = 0; // pushColor coordinate - _yptr = 0; - - _colorMap = nullptr; - - // Ensure end_tft_write() does nothing in inherited functions. - lockTransaction = true; -} - - -/*************************************************************************************** -** Function name: createSprite -** Description: Create a sprite (bitmap) of defined width and height -***************************************************************************************/ -// cast returned value to (uint8_t*) for 8-bit or (uint16_t*) for 16-bit colours -void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) -{ - - if ( _created ) return _img8_1; - - if ( w < 1 || h < 1 ) return nullptr; - - _iwidth = _dwidth = _bitwidth = w; - _iheight = _dheight = h; - - cursor_x = 0; - cursor_y = 0; - - // Default scroll rectangle and gap fill colour - _sx = 0; - _sy = 0; - _sw = w; - _sh = h; - _scolor = TFT_BLACK; - - _img8 = (uint8_t*) callocSprite(w, h, frames); - _img8_1 = _img8; - _img8_2 = _img8; - _img = (uint16_t*) _img8; - _img4 = _img8; - - if ( (_bpp == 16) && (frames > 1) ) { - _img8_2 = _img8 + (w * h * 2 + 1); - } - - // ESP32 only 16bpp check - //if (esp_ptr_dma_capable(_img8_1)) Serial.println("DMA capable Sprite pointer _img8_1"); - //else Serial.println("Not a DMA capable Sprite pointer _img8_1"); - //if (esp_ptr_dma_capable(_img8_2)) Serial.println("DMA capable Sprite pointer _img8_2"); - //else Serial.println("Not a DMA capable Sprite pointer _img8_2"); - - if ( (_bpp == 8) && (frames > 1) ) { - _img8_2 = _img8 + (w * h + 1); - } - - // This is to make it clear what pointer size is expected to be used - // but casting in the user sketch is needed due to the use of void* - if ( (_bpp == 1) && (frames > 1) ) - { - w = (w+7) & 0xFFF8; - _img8_2 = _img8 + ( (w>>3) * h + 1 ); - } - - if (_img8) - { - _created = true; - if ( (_bpp == 4) && (_colorMap == nullptr)) createPalette(default_4bit_palette); - - rotation = 0; - setViewport(0, 0, _dwidth, _dheight); - setPivot(_iwidth/2, _iheight/2); - return _img8_1; - } - - return nullptr; -} - - -/*************************************************************************************** -** Function name: getPointer -** Description: Returns pointer to start of sprite memory area -***************************************************************************************/ -void* TFT_eSprite::getPointer(void) -{ - if (!_created) return nullptr; - return _img8_1; -} - - -/*************************************************************************************** -** Function name: created -** Description: Returns true if sprite has been created -***************************************************************************************/ -bool TFT_eSprite::created(void) -{ - return _created; -} - - -/*************************************************************************************** -** Function name: ~TFT_eSprite -** Description: Class destructor -***************************************************************************************/ -TFT_eSprite::~TFT_eSprite(void) -{ - deleteSprite(); - -#ifdef SMOOTH_FONT - if(fontLoaded) unloadFont(); -#endif -} - - -/*************************************************************************************** -** Function name: callocSprite -** Description: Allocate a memory area for the Sprite and return pointer -***************************************************************************************/ -void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames) -{ - // Add one extra "off screen" pixel to point out-of-bounds setWindow() coordinates - // this means push/writeColor functions do not need additional bounds checks and - // hence will run faster in normal circumstances. - uint8_t* ptr8 = nullptr; - - if (frames > 2) frames = 2; // Currently restricted to 2 frame buffers - if (frames < 1) frames = 1; - - if (_bpp == 16) - { - { - ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t)); - //Serial.println("Normal RAM"); - } - } - - else if (_bpp == 8) - { - ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint8_t)); - } - - else if (_bpp == 4) - { - w = (w+1) & 0xFFFE; // width needs to be multiple of 2, with an extra "off screen" pixel - _iwidth = w; - ptr8 = ( uint8_t*) calloc(((frames * w * h) >> 1) + frames, sizeof(uint8_t)); - } - - else // Must be 1 bpp - { - //_dwidth Display width+height in pixels always in rotation 0 orientation - //_dheight Not swapped for sprite rotations - // Note: for 1bpp _iwidth and _iheight are swapped during Sprite rotations - - w = (w+7) & 0xFFF8; // width should be the multiple of 8 bits to be compatible with epdpaint - _iwidth = w; // _iwidth is rounded up to be multiple of 8, so might not be = _dwidth - _bitwidth = w; // _bitwidth will not be rotated whereas _iwidth may be - - ptr8 = ( uint8_t*) calloc(frames * (w>>3) * h + frames, sizeof(uint8_t)); - } - - return ptr8; -} - - -/*************************************************************************************** -** Function name: createPalette (from RAM array) -** Description: Set a palette for a 4-bit per pixel sprite -***************************************************************************************/ -void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) -{ - if (!_created) return; - - if (colorMap == nullptr) - { - // Create a color map using the default FLASH map - createPalette(default_4bit_palette); - return; - } - - // Allocate and clear memory for 16 color map - if (_colorMap == nullptr) _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); - - if (colors > 16) colors = 16; - - // Copy map colors - for (uint8_t i = 0; i < colors; i++) - { - _colorMap[i] = colorMap[i]; - } -} - - -/*************************************************************************************** -** Function name: createPalette (from FLASH array) -** Description: Set a palette for a 4-bit per pixel sprite -***************************************************************************************/ -void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) -{ - if (!_created) return; - - if (colorMap == nullptr) - { - // Create a color map using the default FLASH map - colorMap = default_4bit_palette; - } - - // Allocate and clear memory for 16 color map - if (_colorMap == nullptr) _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); - - if (colors > 16) colors = 16; - - // Copy map colors - for (uint8_t i = 0; i < colors; i++) - { - _colorMap[i] = pgm_read_word(colorMap++); - } -} - - -/*************************************************************************************** -** Function name: frameBuffer -** Description: For 1 bpp Sprites, select the frame used for graphics -***************************************************************************************/ -// Frames are numbered 1 and 2 -void* TFT_eSprite::frameBuffer(int8_t f) -{ - if (!_created) return nullptr; - - if ( f == 2 ) _img8 = _img8_2; - else _img8 = _img8_1; - - if (_bpp == 16) _img = (uint16_t*)_img8; - - //if (_bpp == 8) _img8 = _img8; - - if (_bpp == 4) _img4 = _img8; - - return _img8; -} - - -/*************************************************************************************** -** Function name: setColorDepth -** Description: Set bits per pixel for colour (1, 8 or 16) -***************************************************************************************/ -void* TFT_eSprite::setColorDepth(int8_t b) -{ - // Do not re-create the sprite if the colour depth does not change - if (_bpp == b) return _img8_1; - - // Validate the new colour depth - if ( b > 8 ) _bpp = 16; // Bytes per pixel - else if ( b > 4 ) _bpp = 8; - else if ( b > 1 ) _bpp = 4; - else _bpp = 1; - - // Can't change an existing sprite's colour depth so delete and create a new one - if (_created) { - deleteSprite(); - return createSprite(_dwidth, _dheight); - } - - return nullptr; -} - - -/*************************************************************************************** -** Function name: getColorDepth -** Description: Get bits per pixel for colour (1, 8 or 16) -***************************************************************************************/ -int8_t TFT_eSprite::getColorDepth(void) -{ - if (_created) return _bpp; - else return 0; -} - - -/*************************************************************************************** -** Function name: setBitmapColor -** Description: Set the 1bpp foreground foreground and background colour -***************************************************************************************/ -void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b) -{ - if (c == b) b = ~c; - _tft->bitmap_fg = c; - _tft->bitmap_bg = b; -} - - -/*************************************************************************************** -** Function name: setPaletteColor -** Description: Set the 4bpp palette color at the given index -***************************************************************************************/ -void TFT_eSprite::setPaletteColor(uint8_t index, uint16_t color) -{ - if (_colorMap == nullptr || index > 15) return; // out of bounds - - _colorMap[index] = color; -} - - -/*************************************************************************************** -** Function name: getPaletteColor -** Description: Return the palette color at 4bpp index, or 0 on error. -***************************************************************************************/ -uint16_t TFT_eSprite::getPaletteColor(uint8_t index) -{ - if (_colorMap == nullptr || index > 15) return 0; // out of bounds - - return _colorMap[index]; -} - - -/*************************************************************************************** -** Function name: deleteSprite -** Description: Delete the sprite to free up memory (RAM) -***************************************************************************************/ -void TFT_eSprite::deleteSprite(void) -{ - if (_colorMap != nullptr) - { - free(_colorMap); - _colorMap = nullptr; - } - - if (_created) - { - free(_img8_1); - _img8 = nullptr; - _created = false; - _vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite - } -} - - -/*************************************************************************************** -** Function name: pushRotated - Fast fixed point integer maths version -** Description: Push rotated Sprite to TFT screen -***************************************************************************************/ -#define FP_SCALE 10 -bool TFT_eSprite::pushRotated(int16_t angle, uint32_t transp) -{ - if ( !_created || _tft->_vpOoB) return false; - - // Bounding box parameters - int16_t min_x; - int16_t min_y; - int16_t max_x; - int16_t max_y; - - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - if ( !getRotatedBounds(angle, &min_x, &min_y, &max_x, &max_y) ) return false; - - uint16_t sline_buffer[max_x - min_x + 1]; - - int32_t xt = min_x - _tft->_xPivot; - int32_t yt = min_y - _tft->_yPivot; - uint32_t xe = _dwidth << FP_SCALE; - uint32_t ye = _dheight << FP_SCALE; - uint16_t tpcolor = (uint16_t)transp; - - if (transp != 0x00FFFFFF) { - if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; - tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes - } - _tft->startWrite(); // Avoid transaction overhead for every tft pixel - - // Scan destination bounding box and fetch transformed pixels from source Sprite - for (int32_t y = min_y; y <= max_y; y++, yt++) { - int32_t x = min_x; - uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - - while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } - if (x == max_x) continue; - - uint32_t pixel_count = 0; - do { - uint32_t rp; - int32_t xp = xs >> FP_SCALE; - int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; } - else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } - if (transp != 0x00FFFFFF && tpcolor == rp) { - if (pixel_count) { - // TFT window is already clipped, so this is faster than pushImage() - _tft->setWindow(x - pixel_count, y, x - 1, y); - _tft->pushPixels(sline_buffer, pixel_count); - pixel_count = 0; - } - } - else { - sline_buffer[pixel_count++] = rp; - } - } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); - if (pixel_count) { - // TFT window is already clipped, so this is faster than pushImage() - _tft->setWindow(x - pixel_count, y, x - 1, y); - _tft->pushPixels(sline_buffer, pixel_count); - } - } - - _tft->endWrite(); // End transaction - - return true; -} - - -/*************************************************************************************** -** Function name: pushRotated - Fast fixed point integer maths version -** Description: Push a rotated copy of the Sprite to another Sprite -***************************************************************************************/ -// Not compatible with 4bpp -bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp) -{ - if ( !_created || _bpp == 4) return false; // Check this Sprite is created - if ( !spr->_created || spr->_bpp == 4) return false; // Ckeck destination Sprite is created - - // Bounding box parameters - int16_t min_x; - int16_t min_y; - int16_t max_x; - int16_t max_y; - - // Get the bounding box of this rotated source Sprite - if ( !getRotatedBounds(spr, angle, &min_x, &min_y, &max_x, &max_y) ) return false; - - uint16_t sline_buffer[max_x - min_x + 1]; - - int32_t xt = min_x - spr->_xPivot; - int32_t yt = min_y - spr->_yPivot; - uint32_t xe = _dwidth << FP_SCALE; - uint32_t ye = _dheight << FP_SCALE; - uint16_t tpcolor = (uint16_t)transp; - - if (transp != 0x00FFFFFF) { - if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; - tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes - } - - bool oldSwapBytes = spr->getSwapBytes(); - spr->setSwapBytes(false); - - // Scan destination bounding box and fetch transformed pixels from source Sprite - for (int32_t y = min_y; y <= max_y; y++, yt++) { - int32_t x = min_x; - uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - - while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } - if (x == max_x) continue; - - uint32_t pixel_count = 0; - do { - uint32_t rp; - int32_t xp = xs >> FP_SCALE; - int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) rp = _img[xp + yp * _iwidth]; - else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } - if (transp != 0x00FFFFFF && tpcolor == rp) { - if (pixel_count) { - spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); - pixel_count = 0; - } - } - else { - sline_buffer[pixel_count++] = rp; - } - } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); - if (pixel_count) spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); - } - spr->setSwapBytes(oldSwapBytes); - return true; -} - - -/*************************************************************************************** -** Function name: getRotatedBounds -** Description: Get TFT bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y) -{ - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); - - // Move bounding box so source Sprite pivot coincides with TFT pivot - *min_x += _tft->_xPivot; - *max_x += _tft->_xPivot; - *min_y += _tft->_yPivot; - *max_y += _tft->_yPivot; - - // Return if bounding box is outside of TFT viewport - if (*min_x > _tft->_vpW) return false; - if (*min_y > _tft->_vpH) return false; - if (*max_x < _tft->_vpX) return false; - if (*max_y < _tft->_vpY) return false; - - // Clip bounding box to be within TFT viewport - if (*min_x < _tft->_vpX) *min_x = _tft->_vpX; - if (*min_y < _tft->_vpY) *min_y = _tft->_vpY; - if (*max_x > _tft->_vpW) *max_x = _tft->_vpW; - if (*max_y > _tft->_vpH) *max_y = _tft->_vpH; - - return true; -} - - -/*************************************************************************************** -** Function name: getRotatedBounds -** Description: Get destination Sprite bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y) -{ - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); - - // Move bounding box so source Sprite pivot coincides with destination Sprite pivot - *min_x += spr->_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 to Sprite boundaries - // Clipping to a viewport will be done by destination Sprite pushImage function - 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(); - - return true; -} - - -/*************************************************************************************** -** Function name: rotatedBounds -** Description: Get bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, - int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y) -{ - // Trig values for the rotation - float radAngle = -angle * 0.0174532925; // Convert degrees to radians - float sina = sin(radAngle); - float cosa = cos(radAngle); - - w -= xp; // w is now right edge coordinate relative to xp - h -= yp; // h is now bottom edge coordinate relative to yp - - // Calculate new corner coordinates - int16_t x0 = -xp * cosa - yp * sina; - int16_t y0 = xp * sina - yp * cosa; - - int16_t x1 = w * cosa - yp * sina; - int16_t y1 = -w * sina - yp * cosa; - - int16_t x2 = h * sina + w * cosa; - int16_t y2 = h * cosa - w * sina; - - int16_t x3 = h * sina - xp * cosa; - int16_t y3 = h * cosa + xp * sina; - - // Find bounding box extremes, enlarge box to accomodate rounding errors - *min_x = x0-2; - if (x1 < *min_x) *min_x = x1-2; - if (x2 < *min_x) *min_x = x2-2; - if (x3 < *min_x) *min_x = x3-2; - - *max_x = x0+2; - if (x1 > *max_x) *max_x = x1+2; - if (x2 > *max_x) *max_x = x2+2; - if (x3 > *max_x) *max_x = x3+2; - - *min_y = y0-2; - if (y1 < *min_y) *min_y = y1-2; - if (y2 < *min_y) *min_y = y2-2; - if (y3 < *min_y) *min_y = y3-2; - - *max_y = y0+2; - if (y1 > *max_y) *max_y = y1+2; - if (y2 > *max_y) *max_y = y2+2; - if (y3 > *max_y) *max_y = y3+2; - - _sinra = round(sina * (1<getSwapBytes(); - _tft->setSwapBytes(false); - _tft->pushImage(x, y, _dwidth, _dheight, _img ); - _tft->setSwapBytes(oldSwapBytes); - } - else if (_bpp == 4) - { - _tft->pushImage(x, y, _dwidth, _dheight, _img4, false, _colorMap); - } - else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8)); -} - - -/*************************************************************************************** -** Function name: pushSprite -** Description: Push the sprite to the TFT at x, y with transparent colour -***************************************************************************************/ -void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) -{ - if (!_created) return; - - if (_bpp == 16) - { - bool oldSwapBytes = _tft->getSwapBytes(); - _tft->setSwapBytes(false); - _tft->pushImage(x, y, _dwidth, _dheight, _img, transp ); - _tft->setSwapBytes(oldSwapBytes); - } - else if (_bpp == 8) - { - transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3); - _tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true); - } - else if (_bpp == 4) - { - _tft->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap); - } - else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false); -} - - -/*************************************************************************************** -** Function name: pushToSprite -** Description: Push the sprite to another sprite at x, y -***************************************************************************************/ -// Note: The following sprite to sprite colour depths are currently supported: -// Source Destination -// 16bpp -> 16bpp -// 16bpp -> 8bpp -// 8bpp -> 8bpp -// 4bpp -> 4bpp (note: color translation depends on the 2 sprites palette colors) -// 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) - -bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y) -{ - if (!_created) return false; - if (!dspr->created()) return false; - - // Check destination sprite compatibility - int8_t ds_bpp = dspr->getColorDepth(); - if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; - if (_bpp == 8 && ds_bpp != 8) return false; - if (_bpp == 4 && ds_bpp != 4) return false; - if (_bpp == 1 && ds_bpp != 1) return false; - - bool oldSwapBytes = dspr->getSwapBytes(); - dspr->setSwapBytes(false); - dspr->pushImage(x, y, _dwidth, _dheight, _img, _bpp); - dspr->setSwapBytes(oldSwapBytes); - - return true; -} - - -/*************************************************************************************** -** Function name: pushToSprite -** Description: Push the sprite to another sprite at x, y with transparent colour -***************************************************************************************/ -// Note: The following sprite to sprite colour depths are currently supported: -// Source Destination -// 16bpp -> 16bpp -// 16bpp -> 8bpp -// 8bpp -> 8bpp -// 1bpp -> 1bpp - -bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transp) -{ - if ( !_created || !dspr->_created) return false; // Check Sprites exist - - // Check destination sprite compatibility - int8_t ds_bpp = dspr->getColorDepth(); - if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; - if (_bpp == 8 && ds_bpp != 8) return false; - if (_bpp == 4 || ds_bpp == 4) return false; - if (_bpp == 1 && ds_bpp != 1) return false; - - bool oldSwapBytes = dspr->getSwapBytes(); - uint16_t sline_buffer[width()]; - - transp = transp>>8 | transp<<8; - - // Scan destination bounding box and fetch transformed pixels from source Sprite - for (int32_t ys = 0; ys < height(); ys++) { - int32_t ox = x; - uint32_t pixel_count = 0; - - for (int32_t xs = 0; xs < width(); xs++) { - uint16_t rp = 0; - if (_bpp == 16) rp = _img[xs + ys * width()]; - else { rp = readPixel(xs, ys); rp = rp>>8 | rp<<8; } - //dspr->drawPixel(xs, ys, rp); - - if (transp == rp) { - if (pixel_count) { - dspr->pushImage(ox, y, pixel_count, 1, sline_buffer); - ox += pixel_count; - pixel_count = 0; - } - ox++; - } - else { - sline_buffer[pixel_count++] = rp; - } - } - if (pixel_count) dspr->pushImage(ox, y, pixel_count, 1, sline_buffer); - y++; - } - dspr->setSwapBytes(oldSwapBytes); - return true; -} - - -/*************************************************************************************** -** Function name: pushSprite -** Description: Push a cropped sprite to the TFT at tx, ty -***************************************************************************************/ -bool TFT_eSprite::pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh) -{ - if (!_created) return false; - - // Perform window boundary checks and crop if needed - setWindow(sx, sy, sx + sw - 1, sy + sh - 1); - - /* These global variables are now populated for the sprite - _xs = x start coordinate - _ys = y start coordinate - _xe = x end coordinate (inclusive) - _ye = y end coordinate (inclusive) - */ - - // Calculate new sprite window bounding box width and height - sw = _xe - _xs + 1; - sh = _ye - _ys + 1; - - if (_ys >= _iheight) return false; - - if (_bpp == 16) - { - bool oldSwapBytes = _tft->getSwapBytes(); - _tft->setSwapBytes(false); - - // Check if a faster block copy to screen is possible - if ( sx == 0 && sw == _dwidth) - _tft->pushImage(tx, ty, sw, sh, _img + _iwidth * _ys ); - else // Render line by line - while (sh--) - _tft->pushImage(tx, ty++, sw, 1, _img + _xs + _iwidth * _ys++ ); - - _tft->setSwapBytes(oldSwapBytes); - } - else if (_bpp == 8) - { - // Check if a faster block copy to screen is possible - if ( sx == 0 && sw == _dwidth) - _tft->pushImage(tx, ty, sw, sh, _img8 + _iwidth * _ys, (bool)true ); - else // Render line by line - while (sh--) - _tft->pushImage(tx, ty++, sw, 1, _img8 + _xs + _iwidth * _ys++, (bool)true ); - } - else if (_bpp == 4) - { - // Check if a faster block copy to screen is possible - if ( sx == 0 && sw == _dwidth) - _tft->pushImage(tx, ty, sw, sh, _img4 + (_iwidth>>1) * _ys, false, _colorMap ); - else // Render line by line - { - int32_t ds = _xs&1; // Odd x start pixel - - int32_t de = 0; // Odd x end pixel - if ((sw > ds) && (_xe&1)) de = 1; - - uint32_t dm = 0; // Midsection pixel count - if (sw > (ds+de)) dm = sw - ds - de; - sw--; - - uint32_t yp = (_xs + ds + _iwidth * _ys)>>1; - _tft->startWrite(); - while (sh--) - { - if (ds) _tft->drawPixel(tx, ty, readPixel(_xs, _ys) ); - if (dm) _tft->pushImage(tx + ds, ty, dm, 1, _img4 + yp, false, _colorMap ); - if (de) _tft->drawPixel(tx + sw, ty, readPixel(_xe, _ys) ); - _ys++; - ty++; - yp += (_iwidth>>1); - } - _tft->endWrite(); - } - } - else // 1bpp - { - // Check if a faster block copy to screen is possible - if ( sx == 0 && sw == _dwidth) - _tft->pushImage(tx, ty, sw, sh, _img8 + (_bitwidth>>3) * _ys, (bool)false ); - else // Render line by line - { - _tft->startWrite(); - while (sh--) - { - _tft->pushImage(tx, ty++, sw, 1, _img8 + (_bitwidth>>3) * _ys++, (bool)false ); - } - _tft->endWrite(); - } - } - - return true; -} - - -/*************************************************************************************** -** Function name: readPixelValue -** Description: Read the color map index of a pixel at defined coordinates -***************************************************************************************/ -uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) -{ - if (_vpOoB || !_created) return 0xFF; - - x+= _xDatum; - y+= _yDatum; - - // Range checking - if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return 0xFF; - - if (_bpp == 16) - { - // Return the pixel colour - return readPixel(x - _xDatum, y - _yDatum); - } - - if (_bpp == 8) - { - // Return the pixel byte value - return _img8[x + y * _iwidth]; - } - - if (_bpp == 4) - { - if (x >= _dwidth) return 0xFF; - if ((x & 0x01) == 0) - return _img4[((x+y*_iwidth)>>1)] >> 4; // even index = bits 7 .. 4 - else - return _img4[((x+y*_iwidth)>>1)] & 0x0F; // odd index = bits 3 .. 0. - } - - if (_bpp == 1) - { - // Note: _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) - if (rotation == 1) - { - uint16_t tx = x; - x = _dheight - y - 1; - y = tx; - } - else if (rotation == 2) - { - x = _dwidth - x - 1; - y = _dheight - y - 1; - } - else if (rotation == 3) - { - uint16_t tx = x; - x = y; - y = _dwidth - tx - 1; - } - // Return 1 or 0 - return (_img8[(x + y * _bitwidth)>>3] >> (7-(x & 0x7))) & 0x01; - } - - return 0; -} - -/*************************************************************************************** -** Function name: readPixel -** Description: Read 565 colour of a pixel at defined coordinates -***************************************************************************************/ -uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) -{ - if (_vpOoB || !_created) return 0xFFFF; - - x+= _xDatum; - y+= _yDatum; - - // Range checking - if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return 0xFFFF; - - if (_bpp == 16) - { - uint16_t color = _img[x + y * _iwidth]; - return (color >> 8) | (color << 8); - } - - if (_bpp == 8) - { - uint16_t color = _img8[x + y * _iwidth]; - if (color != 0) - { - uint8_t blue[] = {0, 11, 21, 31}; - color = (color & 0xE0)<<8 | (color & 0xC0)<<5 - | (color & 0x1C)<<6 | (color & 0x1C)<<3 - | blue[color & 0x03]; - } - return color; - } - - if (_bpp == 4) - { - if (x >= _dwidth) return 0xFFFF; - uint16_t color; - if ((x & 0x01) == 0) - color = _colorMap[_img4[((x+y*_iwidth)>>1)] >> 4]; // even index = bits 7 .. 4 - else - color = _colorMap[_img4[((x+y*_iwidth)>>1)] & 0x0F]; // odd index = bits 3 .. 0. - return color; - } - - // Note: Must be 1bpp - // _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) - if (rotation == 1) - { - uint16_t tx = x; - x = _dheight - y - 1; - y = tx; - } - else if (rotation == 2) - { - x = _dwidth - x - 1; - y = _dheight - y - 1; - } - else if (rotation == 3) - { - uint16_t tx = x; - x = y; - y = _dwidth - tx - 1; - } - - uint16_t color = (_img8[(x + y * _bitwidth)>>3] << (x & 0x7)) & 0x80; - - if (color) return _tft->bitmap_fg; - else return _tft->bitmap_bg; -} - - -/*************************************************************************************** -** Function name: pushImage -** Description: push image into a defined area of a sprite -***************************************************************************************/ -void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp) -{ - if (data == nullptr || !_created) return; - - PI_CLIP; - - if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite - { - // Pointer within original image - uint8_t *ptro = (uint8_t *)data + ((dx + dy * w) << 1); - // Pointer within sprite image - uint8_t *ptrs = (uint8_t *)_img + ((x + y * _iwidth) << 1); - - if(_swapBytes) - { - while (dh--) - { - // Fast copy with a 1 byte shift - memcpy(ptrs+1, ptro, (dw<<1) - 1); - // Now correct just the even numbered bytes - for (int32_t xp = 0; xp < (dw<<1); xp+=2) - { - ptrs[xp] = ptro[xp+1];; - } - ptro += w<<1; - ptrs += _iwidth<<1; - } - } - else - { - while (dh--) - { - memcpy(ptrs, ptro, dw<<1); - ptro += w << 1; - ptrs += _iwidth << 1; - } - } - } - else if (_bpp == 8 && sbpp == 8) // Plot a 8 bpp image into a 8 bpp Sprite - { - // Pointer within original image - uint8_t *ptro = (uint8_t *)data + (dx + dy * w); - // Pointer within sprite image - uint8_t *ptrs = (uint8_t *)_img + (x + y * _iwidth); - - while (dh--) - { - memcpy(ptrs, ptro, dw); - ptro += w; - ptrs += _iwidth; - } - } - else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite - { - uint16_t lastColor = 0; - uint8_t color8 = 0; - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t xyw = x + y * _iwidth; - int32_t dxypw = dx + yp * w; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t color = data[dxypw++]; - if (color != lastColor) { - // When data source is a sprite, the bytes are already swapped - if(!_swapBytes) color8 = (uint8_t)((color & 0xE0) | (color & 0x07)<<2 | (color & 0x1800)>>11); - else color8 = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - } - lastColor = color; - _img8[xyw++] = color8; - } - y++; - } - } - else if (_bpp == 4) - { - // The image is assumed to be 4-bit, where each byte corresponds to two pixels. - // much faster when aligned to a byte boundary, because the alternative is slower, requiring - // tedious bit operations. - - int sWidth = (_iwidth >> 1); - uint8_t *ptr = (uint8_t *)data; - - if ((x & 0x01) == 0 && (dx & 0x01) == 0 && (dw & 0x01) == 0) - { - x = (x >> 1) + y * sWidth; - dw = (dw >> 1); - dx = (dx >> 1) + dy * (w>>1); - while (dh--) - { - memcpy(_img4 + x, ptr + dx, dw); - dx += (w >> 1); - x += sWidth; - } - } - else // not optimized - { - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint32_t color; - if ((xp & 0x01) == 0) - color = (ptr[((xp+yp*w)>>1)] & 0xF0) >> 4; // even index = bits 7 .. 4 - else - color = ptr[((xp-1+yp*w)>>1)] & 0x0F; // odd index = bits 3 .. 0. - drawPixel(ox, y, color); - ox++; - } - y++; - } - } - } - - else // 1bpp - { - // Plot a 1bpp image into a 1bpp Sprite - uint32_t ww = (w+7)>>3; // Width of source image line in bytes - uint8_t *ptr = (uint8_t *)data; - for (int32_t yp = dy; yp < dy + dh; yp++) - { - uint32_t yw = yp * ww; // Byte starting the line containing source pixel - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t readPixel = (ptr[(xp>>3) + yw] & (0x80 >> (xp & 0x7)) ); - drawPixel(ox++, y, readPixel); - } - y++; - } - } -} - - -/*************************************************************************************** -** Function name: pushImage -** Description: push 565 colour FLASH (PROGMEM) image into a defined area -***************************************************************************************/ -void TFT_eSprite::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 - if (data == nullptr || !_created) return; - - PI_CLIP; - - if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite - { - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t color = pgm_read_word(data + xp + yp * w); - if(_swapBytes) color = color<<8 | color>>8; - _img[ox + y * _iwidth] = color; - ox++; - } - y++; - } - } - - else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite - { - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t color = pgm_read_word(data + xp + yp * w); - if(_swapBytes) color = color<<8 | color>>8; - _img8[ox + y * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - ox++; - } - y++; - } - } - - else if (_bpp == 4) - { - #ifdef TFT_eSPI_DEBUG - Serial.println("TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) not implemented"); - #endif - return; - } - - else // Plot a 1bpp image into a 1bpp Sprite - { - x-= _xDatum; // Remove offsets, drawPixel will add - y-= _yDatum; - uint16_t bsw = (w+7) >> 3; // Width in bytes of source image line - uint8_t *ptr = ((uint8_t*)data) + dy * bsw; - - while (dh--) { - int32_t odx = dx; - int32_t ox = x; - while (odx < dx + dw) { - uint8_t pbyte = pgm_read_byte(ptr + (odx>>3)); - uint8_t mask = 0x80 >> (odx & 7); - while (mask) { - uint8_t p = pbyte & mask; - mask = mask >> 1; - drawPixel(ox++, y, p); - odx++; - } - } - ptr += bsw; - y++; - } - } -#endif // if ESP32 check -} - - -/*************************************************************************************** -** Function name: setWindow -** Description: Set the bounds of a window in the sprite -***************************************************************************************/ -// Intentionally not constrained to viewport area, does not manage 1bpp rotations -void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) -{ - if (x0 > x1) transpose(x0, x1); - if (y0 > y1) transpose(y0, y1); - - int32_t w = width(); - int32_t h = height(); - - if ((x0 >= w) || (x1 < 0) || (y0 >= h) || (y1 < 0)) - { // Point to that extra "off screen" pixel - _xs = 0; - _ys = _dheight; - _xe = 0; - _ye = _dheight; - } - else - { - if (x0 < 0) x0 = 0; - if (x1 >= w) x1 = w - 1; - if (y0 < 0) y0 = 0; - if (y1 >= h) y1 = h - 1; - - _xs = x0; - _ys = y0; - _xe = x1; - _ye = y1; - } - - _xptr = _xs; - _yptr = _ys; -} - - -/*************************************************************************************** -** Function name: pushColor -** Description: Send a new pixel to the set window -***************************************************************************************/ -void TFT_eSprite::pushColor(uint16_t color) -{ - if (!_created ) return; - - // Write the colour to RAM in set window - if (_bpp == 16) - _img [_xptr + _yptr * _iwidth] = (uint16_t) (color >> 8) | (color << 8); - - else if (_bpp == 8) - _img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - - else if (_bpp == 4) - { - uint8_t c = (uint8_t)color & 0x0F; - if ((_xptr & 0x01) == 0) { - _img4[(_xptr + _yptr * _iwidth)>>1] = (c << 4) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4 - } - else { - _img4[(_xptr + _yptr * _iwidth)>>1] = (_img4[(_xptr + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits - } - } - - else drawPixel(_xptr, _yptr, color); - - // Increment x - _xptr++; - - // Wrap on x and y to start, increment y if needed - if (_xptr > _xe) - { - _xptr = _xs; - _yptr++; - if (_yptr > _ye) _yptr = _ys; - } - -} - - -/*************************************************************************************** -** Function name: pushColor -** Description: Send a "len" new pixels to the set window -***************************************************************************************/ -void TFT_eSprite::pushColor(uint16_t color, uint32_t len) -{ - if (!_created ) return; - - uint16_t pixelColor; - - if (_bpp == 16) - pixelColor = (uint16_t) (color >> 8) | (color << 8); - - else if (_bpp == 8) - pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - - else pixelColor = (uint16_t) color; // for 1bpp or 4bpp - - while(len--) writeColor(pixelColor); -} - - -/*************************************************************************************** -** Function name: writeColor -** Description: Write a pixel with pre-formatted colour to the set window -***************************************************************************************/ -void TFT_eSprite::writeColor(uint16_t color) -{ - if (!_created ) return; - - // Write 16-bit RGB 565 encoded colour to RAM - if (_bpp == 16) _img [_xptr + _yptr * _iwidth] = color; - - // Write 8-bit RGB 332 encoded colour to RAM - else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color; - - else if (_bpp == 4) - { - uint8_t c = (uint8_t)color & 0x0F; - if ((_xptr & 0x01) == 0) - _img4[(_xptr + _yptr * _iwidth)>>1] = (c << 4) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4 - else - _img4[(_xptr + _yptr * _iwidth)>>1] = (_img4[(_xptr + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits (x is odd) - } - - else drawPixel(_xptr, _yptr, color); - - // Increment x - _xptr++; - - // Wrap on x and y to start, increment y if needed - if (_xptr > _xe) - { - _xptr = _xs; - _yptr++; - if (_yptr > _ye) _yptr = _ys; - } -} - - -/*************************************************************************************** -** Function name: setScrollRect -** Description: Set scroll area within the sprite and the gap fill colour -***************************************************************************************/ -// Intentionally not constrained to viewport area -void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) -{ - if ((x >= _iwidth) || (y >= _iheight) || !_created ) return; - - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - - if ((x + w) > _iwidth ) w = _iwidth - x; - if ((y + h) > _iheight) h = _iheight - y; - - if ( w < 1 || h < 1) return; - - _sx = x; - _sy = y; - _sw = w; - _sh = h; - - _scolor = color; -} - - -/*************************************************************************************** -** Function name: scroll -** Description: Scroll dx,dy pixels, positive right,down, negative left,up -***************************************************************************************/ -void TFT_eSprite::scroll(int16_t dx, int16_t dy) -{ - if (abs(dx) >= _sw || abs(dy) >= _sh) - { - fillRect (_sx, _sy, _sw, _sh, _scolor); - return; - } - - // Fetch the scroll area width and height set by setScrollRect() - uint32_t w = _sw - abs(dx); // line width to copy - uint32_t h = _sh - abs(dy); // lines to copy - int32_t iw = _iwidth; // rounded up width of sprite - - // Fetch the x,y origin set by setScrollRect() - uint32_t tx = _sx; // to x - uint32_t fx = _sx; // from x - uint32_t ty = _sy; // to y - uint32_t fy = _sy; // from y - - // Adjust for x delta - if (dx <= 0) fx -= dx; - else tx += dx; - - // Adjust for y delta - if (dy <= 0) fy -= dy; - else - { // Scrolling down so start copy from bottom - ty = ty + _sh - 1; // "To" pointer - iw = -iw; // Pointer moves backwards - fy = ty - dy; // "From" pointer - } - - // Calculate "from y" and "to y" pointers in RAM - uint32_t fyp = fx + fy * _iwidth; - uint32_t typ = tx + ty * _iwidth; - - // Now move the pixels in RAM - if (_bpp == 16) - { - while (h--) - { // move pixel lines (to, from, byte count) - memmove( _img + typ, _img + fyp, w<<1); - typ += iw; - fyp += iw; - } - } - else if (_bpp == 8) - { - while (h--) - { // move pixel lines (to, from, byte count) - memmove( _img8 + typ, _img8 + fyp, w); - typ += iw; - fyp += iw; - } - } - else if (_bpp == 4) - { - // could optimize for scrolling by even # pixels using memove (later) - if (dx > 0) { tx += w; fx += w; } // Start from right edge - while (h--) - { // move pixels one by one - for (uint16_t xp = 0; xp < w; xp++) - { - if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); - if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); - } - if (dy <= 0) { ty++; fy++; } - else { ty--; fy--; } - } - } - else if (_bpp == 1 ) - { - if (dx > 0) { tx += w; fx += w; } // Start from right edge - while (h--) - { // move pixels one by one - for (uint16_t xp = 0; xp < w; xp++) - { - if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); - if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); - } - if (dy <= 0) { ty++; fy++; } - else { ty--; fy--; } - } - } - else return; // Not 1, 4, 8 or 16 bpp - - // Fill the gap left by the scrolling - if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor); - if (dx < 0) fillRect(_sx + _sw + dx, _sy, -dx, _sh, _scolor); - if (dy > 0) fillRect(_sx, _sy, _sw, dy, _scolor); - if (dy < 0) fillRect(_sx, _sy + _sh + dy, _sw, -dy, _scolor); -} - - -/*************************************************************************************** -** Function name: fillSprite -** Description: Fill the whole sprite with defined colour -***************************************************************************************/ -void TFT_eSprite::fillSprite(uint32_t color) -{ - if (!_created || _vpOoB) return; - - // Use memset if possible as it is super fast - if(_xDatum == 0 && _yDatum == 0 && _xWidth == width()) - { - if(_bpp == 16) { - if ( (uint8_t)color == (uint8_t)(color>>8) ) { - memset(_img, (uint8_t)color, _iwidth * _yHeight * 2); - } - else fillRect(_vpX, _vpY, _xWidth, _yHeight, color); - } - else if (_bpp == 8) - { - color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - memset(_img8, (uint8_t)color, _iwidth * _yHeight); - } - else if (_bpp == 4) - { - uint8_t c = ((color & 0x0F) | (((color & 0x0F) << 4) & 0xF0)); - memset(_img4, c, (_iwidth * _yHeight) >> 1); - } - else if (_bpp == 1) - { - if(color) memset(_img8, 0xFF, (_bitwidth>>3) * _dheight + 1); - else memset(_img8, 0x00, (_bitwidth>>3) * _dheight + 1); - } - } - else fillRect(_vpX - _xDatum, _vpY - _yDatum, _xWidth, _yHeight, color); -} - - -/*************************************************************************************** -** Function name: width -** Description: Return the width of sprite -***************************************************************************************/ -// Return the size of the sprite -int16_t TFT_eSprite::width(void) -{ - if (!_created ) return 0; - - if (_bpp > 1) { - if (_vpDatum) return _xWidth; - return _dwidth; - } - - if (rotation & 1) { - if (_vpDatum) return _xWidth; - return _dheight; - } - - if (_vpDatum) return _xWidth; - return _dwidth; -} - - -/*************************************************************************************** -** Function name: height -** Description: Return the height of sprite -***************************************************************************************/ -int16_t TFT_eSprite::height(void) -{ - if (!_created ) return 0; - - if (_bpp > 1) { - if (_vpDatum) return _yHeight; - return _dheight; - } - - if (rotation & 1) { - if (_vpDatum) return _yHeight; - return _dwidth; - } - - if (_vpDatum) return _yHeight; - return _dheight; -} - - -/*************************************************************************************** -** Function name: setRotation -** Description: Rotate coordinate frame for 1bpp sprite -***************************************************************************************/ -// Does nothing for 4, 8 and 16 bpp sprites. -void TFT_eSprite::setRotation(uint8_t r) -{ - if (_bpp != 1) return; - - rotation = r; - - if (rotation&1) { - resetViewport(); - } - else { - resetViewport(); - } -} - - -/*************************************************************************************** -** Function name: getRotation -** Description: Get rotation for 1bpp sprite -***************************************************************************************/ -uint8_t TFT_eSprite::getRotation(void) -{ - return rotation; -} - - -/*************************************************************************************** -** Function name: drawPixel -** Description: push a single pixel at an arbitrary position -***************************************************************************************/ -void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) -{ - if (!_created || _vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Range checking - if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return; - - if (_bpp == 16) - { - color = (color >> 8) | (color << 8); - _img[x+y*_iwidth] = (uint16_t) color; - } - else if (_bpp == 8) - { - _img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - } - else if (_bpp == 4) - { - uint8_t c = color & 0x0F; - int index = (x+y*_iwidth)>>1;; - if ((x & 0x01) == 0) { - _img4[index] = (uint8_t)((c << 4) | (_img4[index] & 0x0F)); - } - else { - _img4[index] = (uint8_t)(c | (_img4[index] & 0xF0)); - } - } - else // 1 bpp - { - if (rotation == 1) - { - uint16_t tx = x; - x = _dwidth - y - 1; - y = tx; - } - else if (rotation == 2) - { - x = _dwidth - x - 1; - y = _dheight - y - 1; - } - else if (rotation == 3) - { - uint16_t tx = x; - x = y; - y = _dheight - tx - 1; - } - - if (color) _img8[(x + y * _bitwidth)>>3] |= (0x80 >> (x & 0x7)); - else _img8[(x + y * _bitwidth)>>3] &= ~(0x80 >> (x & 0x7)); - } -} - - -/*************************************************************************************** -** Function name: drawLine -** Description: draw a line between 2 arbitrary points -***************************************************************************************/ -void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) -{ - if (!_created || _vpOoB) return; - - //_xDatum and _yDatum Not added here, it is added by drawPixel & drawFastxLine - - bool steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - transpose(x0, y0); - transpose(x1, y1); - } - - if (x0 > x1) { - transpose(x0, x1); - transpose(y0, y1); - } - - int32_t dx = x1 - x0, dy = abs(y1 - y0);; - - int32_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0; - - if (y0 < y1) ystep = 1; - - // Split into steep and not steep for FastH/V separation - if (steep) { - for (; x0 <= x1; x0++) { - dlen++; - err -= dy; - if (err < 0) { - err += dx; - if (dlen == 1) drawPixel(y0, xs, color); - else drawFastVLine(y0, xs, dlen, color); - dlen = 0; y0 += ystep; xs = x0 + 1; - } - } - 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); - } -} - - -/*************************************************************************************** -** Function name: drawFastVLine -** Description: draw a vertical line -***************************************************************************************/ -void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) -{ - if (!_created || _vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Clipping - if ((x < _vpX) || (x >= _vpW) || (y >= _vpH)) return; - - if (y < _vpY) { h += y - _vpY; y = _vpY; } - - if ((y + h) > _vpH) h = _vpH - y; - - if (h < 1) return; - - if (_bpp == 16) - { - color = (color >> 8) | (color << 8); - int32_t yp = x + _iwidth * y; - while (h--) {_img[yp] = (uint16_t) color; yp += _iwidth;} - } - else if (_bpp == 8) - { - color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - while (h--) _img8[x + _iwidth * y++] = (uint8_t) color; - } - else if (_bpp == 4) - { - if ((x & 0x01) == 0) - { - uint8_t c = (uint8_t) (color & 0xF) << 4; - while (h--) { - _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0x0F)); - y++; - } - } - else { - uint8_t c = (uint8_t)color & 0xF; - while (h--) { - _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0xF0)); // x is odd; new color goes into the low bits. - y++; - } - } - } - else - { - x -= _xDatum; // Remove any offset as it will be added by drawPixel - y -= _yDatum; - while (h--) - { - drawPixel(x, y++, color); - } - } -} - - -/*************************************************************************************** -** Function name: drawFastHLine -** Description: draw a horizontal line -***************************************************************************************/ -void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) -{ - if (!_created || _vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Clipping - if ((y < _vpY) || (x >= _vpW) || (y >= _vpH)) return; - - if (x < _vpX) { w += x - _vpX; x = _vpX; } - - if ((x + w) > _vpW) w = _vpW - x; - - if (w < 1) return; - - if (_bpp == 16) - { - color = (color >> 8) | (color << 8); - while (w--) _img[_iwidth * y + x++] = (uint16_t) color; - } - else if (_bpp == 8) - { - color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - memset(_img8+_iwidth * y + x, (uint8_t)color, w); - } - else if (_bpp == 4) - { - uint8_t c = (uint8_t)color & 0x0F; - uint8_t c2 = (c | ((c << 4) & 0xF0)); - if ((x & 0x01) == 1) - { - drawPixel(x - _xDatum, y - _yDatum, color); - x++; w--; - if (w < 1) - return; - } - - if (((w + x) & 0x01) == 1) - { - // handle the extra one at the other end - drawPixel(x - _xDatum + w - 1, y - _yDatum, color); - w--; - if (w < 1) return; - } - memset(_img4 + ((_iwidth * y + x) >> 1), c2, (w >> 1)); - } - else { - x -= _xDatum; // Remove any offset as it will be added by drawPixel - y -= _yDatum; - - while (w--) - { - drawPixel(x++, y, color); - } - } -} - - -/*************************************************************************************** -** Function name: fillRect -** Description: draw a filled rectangle -***************************************************************************************/ -void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) -{ - if (!_created || _vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Clipping - if ((x >= _vpW) || (y >= _vpH)) return; - - if (x < _vpX) { w += x - _vpX; x = _vpX; } - if (y < _vpY) { h += y - _vpY; y = _vpY; } - - if ((x + w) > _vpW) w = _vpW - x; - if ((y + h) > _vpH) h = _vpH - y; - - if ((w < 1) || (h < 1)) return; - - int32_t yp = _iwidth * y + x; - - if (_bpp == 16) - { - color = (color >> 8) | (color << 8); - uint32_t iw = w; - int32_t ys = yp; - if(h--) {while (iw--) _img[yp++] = (uint16_t) color;} - yp = ys; - while (h--) - { - yp += _iwidth; - memcpy( _img+yp, _img+ys, w<<1); - } - } - else if (_bpp == 8) - { - color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - while (h--) - { - memset(_img8 + yp, (uint8_t)color, w); - yp += _iwidth; - } - } - else if (_bpp == 4) - { - uint8_t c1 = (uint8_t)color & 0x0F; - uint8_t c2 = c1 | ((c1 << 4) & 0xF0); - if ((x & 0x01) == 0 && (w & 0x01) == 0) - { - yp = (yp >> 1); - while (h--) - { - memset(_img4 + yp, c2, (w>>1)); - yp += (_iwidth >> 1); - } - } - else if ((x & 0x01) == 0) - { - - // same as above but you have a hangover on the right. - yp = (yp >> 1); - while (h--) - { - if (w > 1) - memset(_img4 + yp, c2, (w-1)>>1); - // handle the rightmost pixel by calling drawPixel - drawPixel(x+w-1-_xDatum, y+h-_yDatum, c1); - yp += (_iwidth >> 1); - } - } - else if ((w & 0x01) == 1) - { - yp = (yp + 1) >> 1; - while (h--) { - drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); - if (w > 1) - memset(_img4 + yp, c2, (w-1)>>1); - // same as above but you have a hangover on the left instead - yp += (_iwidth >> 1); - } - } - else - { - yp = (yp + 1) >> 1; - while (h--) { - drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); - if (w > 1) drawPixel(x+w-1-_xDatum, y+h-_yDatum, color & 0x0F); - if (w > 2) - memset(_img4 + yp, c2, (w-2)>>1); - // maximal hacking, single pixels on left and right. - yp += (_iwidth >> 1); - } - } - } - else - { - x -= _xDatum; - y -= _yDatum; - while (h--) - { - int32_t ww = w; - int32_t xx = x; - while (ww--) drawPixel(xx++, y, color); - y++; - } - } -} - - -/*************************************************************************************** -** Function name: drawChar -** Description: draw a single character in the Adafruit GLCD or freefont -***************************************************************************************/ -void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) -{ - if ( _vpOoB || !_created ) return; - - if (c < 32) return; -#ifdef LOAD_GLCD -//>>>>>>>>>>>>>>>>>> -#ifdef LOAD_GFXFF - if(!gfxFont) { // 'Classic' built-in font -#endif -//>>>>>>>>>>>>>>>>>> - - if ((x >= _vpW - _xDatum) || // Clip right - (y >= _vpH - _yDatum)) // Clip bottom - return; - - if (((x + 6 * size - 1) < (_vpX - _xDatum)) || // Clip left - ((y + 8 * size - 1) < (_vpY - _yDatum))) // Clip top - return; - - if (c > 255) return; - if (!_cp437 && c > 175) c++; - - bool fillbg = (bg != color); - - if ((size==1) && fillbg) - { - uint8_t column[6]; - uint8_t mask = 0x1; - - for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); - column[5] = 0; - - int8_t j, k; - for (j = 0; j < 8; j++) { - for (k = 0; k < 5; k++ ) { - if (column[k] & mask) { - drawPixel(x + k, y + j, color); - } - else { - drawPixel(x + k, y + j, bg); - } - } - - mask <<= 1; - - drawPixel(x + k, y + j, bg); - } - } - else - { - for (int8_t i = 0; i < 6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(font + (c * 5) + i); - - if (size == 1) // default size - { - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) drawPixel(x + i, y + j, color); - line >>= 1; - } - } - else { // big size - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color); - else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg); - line >>= 1; - } - } - } - } - -//>>>>>>>>>>>>>>>>>>>>>>>>>>> -#ifdef LOAD_GFXFF - } else { // Custom font -#endif -//>>>>>>>>>>>>>>>>>>>>>>>>>>> -#endif // LOAD_GLCD - -#ifdef LOAD_GFXFF - // Filter out bad characters not present in font - if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last ))) - { -//>>>>>>>>>>>>>>>>>>>>>>>>>>> - - c -= pgm_read_word(&gfxFont->first); - GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]); - - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - int8_t xo = pgm_read_byte(&glyph->xOffset), - yo = pgm_read_byte(&glyph->yOffset); - - if (((x + xo + w * size - 1) < (_vpX - _xDatum)) || // Clip left - ((y + yo + h * size - 1) < (_vpY - _yDatum))) // Clip top - return; - - uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap); - uint32_t bo = pgm_read_word(&glyph->bitmapOffset); - - uint8_t xx, yy, bits=0, bit=0; - //uint8_t xa = pgm_read_byte(&glyph->xAdvance); - int16_t xo16 = 0, yo16 = 0; - - if(size > 1) { - xo16 = xo; - yo16 = yo; - } - - 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) { - 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); - hpc=0; - } - } - } -#endif - - -#ifdef LOAD_GLCD - #ifdef LOAD_GFXFF - } // End classic vs custom font - #endif -#else - #ifndef LOAD_GFXFF - color = color; - bg = bg; - size = size; - #endif -#endif - -} - - -/*************************************************************************************** -** Function name: drawChar -** Description: draw a Unicode glyph into the sprite -***************************************************************************************/ - // TODO: Rationalise with TFT_eSPI - // Any UTF-8 decoding must be done before calling drawChar() -int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y) -{ - return drawChar(uniCode, x, y, textfont); -} - - // Any UTF-8 decoding must be done before calling drawChar() -int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) -{ - if (_vpOoB || !uniCode) return 0; - - if (font==1) { -#ifdef LOAD_GLCD - #ifndef LOAD_GFXFF - drawChar(x, y, uniCode, textcolor, textbgcolor, textsize); - return 6 * textsize; - #endif -#else - #ifndef LOAD_GFXFF - return 0; - #endif -#endif - -#ifdef LOAD_GFXFF - drawChar(x, y, uniCode, textcolor, textbgcolor, textsize); - if(!gfxFont) { // 'Classic' built-in font - #ifdef LOAD_GLCD - return 6 * textsize; - #else - return 0; - #endif - } - 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 { - return 0; - } - } -#endif - } - - if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0; - - int32_t width = 0; - int32_t height = 0; - uint32_t flash_address = 0; - uniCode -= 32; - -#ifdef LOAD_FONT2 - if (font == 2) { - flash_address = pgm_read_dword(&chrtbl_f16[uniCode]); - width = pgm_read_byte(widtbl_f16 + uniCode); - height = chr_hgt_f16; - } - #ifdef LOAD_RLE - else - #endif -#endif - -#ifdef LOAD_RLE - { - 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 ); - } - } -#endif - - int32_t xd = x + _xDatum; - int32_t yd = y + _yDatum; - - if ((xd + width * textsize < _vpX || xd >= _vpW) && (yd + height * textsize < _vpY || yd >= _vpH)) return width * textsize ; - - int32_t w = width; - int32_t pX = 0; - int32_t pY = y; - uint8_t line = 0; - bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH; - -#ifdef LOAD_FONT2 // chop out code if we do not need it - if (font == 2) { - w = w + 6; // Should be + 7 but we need to compensate for width increment - w = w / 8; - - 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++) - { - line = pgm_read_byte((uint8_t *)flash_address + w * i + k); - if (line) { - if (textsize == 1) { - pX = x + k * 8; - if (line & 0x80) drawPixel(pX, pY, textcolor); - if (line & 0x40) drawPixel(pX + 1, pY, textcolor); - if (line & 0x20) drawPixel(pX + 2, pY, textcolor); - if (line & 0x10) drawPixel(pX + 3, pY, textcolor); - if (line & 0x08) drawPixel(pX + 4, pY, textcolor); - if (line & 0x04) drawPixel(pX + 5, pY, textcolor); - if (line & 0x02) drawPixel(pX + 6, pY, textcolor); - if (line & 0x01) drawPixel(pX + 7, pY, textcolor); - } - else { - pX = x + k * 8 * textsize; - if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor); - if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor); - if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor); - } - } - } - pY += textsize; - } - } - - #ifdef LOAD_RLE - else - #endif -#endif //FONT2 - -#ifdef LOAD_RLE //674 bytes of code - // Font is not 2 and hence is RLE encoded - { - w *= height; // Now w is total number of pixels in the character - int16_t color = textcolor; - if (_bpp == 16) color = (textcolor >> 8) | (textcolor << 8); - else if (_bpp == 8) color = ((textcolor & 0xE000)>>8 | (textcolor & 0x0700)>>6 | (textcolor & 0x0018)>>3); - - int16_t bgcolor = textbgcolor; - if (_bpp == 16) bgcolor = (textbgcolor >> 8) | (textbgcolor << 8); - else if (_bpp == 8) bgcolor = ((textbgcolor & 0xE000)>>8 | (textbgcolor & 0x0700)>>6 | (textbgcolor & 0x0018)>>3); - - if (textcolor == textbgcolor && !clip && _bpp != 1) { - int32_t px = 0, py = pY; // To hold character block start and end column and row values - int32_t pc = 0; // Pixel count - uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel - - uint8_t tnp = 0; // Temporary copy of np for while loop - 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) { - line = pgm_read_byte((uint8_t *)flash_address); - flash_address++; - if (line & 0x80) { - line &= 0x7F; - line++; - if (ts) { - px = xd + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow - py = yd + textsize * (pc / width); - } - else { - px = xd + pc % width; // Keep these px and py calculations outside the loop as they are slow - py = yd + pc / width; - } - while (line--) { // In this case the while(line--) is faster - pc++; // This is faster than putting pc+=line before while()? - setWindow(px, py, px + ts, py + ts); - - if (ts) { - tnp = np; - while (tnp--) writeColor(color); - } - else writeColor(color); - - px += textsize; - - if (px >= (xd + width * textsize)) { - px = xd; - py += textsize; - } - } - } - else { - line++; - pc += line; - } - } - } - else { - // Text colour != background and textsize = 1 and character is within viewport area - // so use faster drawing of characters and background using block write - if (textcolor != textbgcolor && textsize == 1 && !clip && _bpp != 1) - { - setWindow(xd, yd, xd + width - 1, yd + height - 1); - - // Maximum font size is equivalent to 180x180 pixels in area - 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; - while (line--) writeColor(color); - } - else { - line++; w -= line; - while (line--) writeColor(bgcolor); - } - } - } - else - { - int32_t px = 0, py = 0; // To hold character pixel coords - int32_t tx = 0, ty = 0; // To hold character TFT pixel coords - int32_t pc = 0; // Pixel count - int32_t pl = 0; // Pixel line length - uint16_t pcol = 0; // Pixel color - bool pf = true; // Flag for plotting - while (pc < w) { - line = pgm_read_byte((uint8_t *)flash_address); - flash_address++; - if (line & 0x80) { pcol = textcolor; line &= 0x7F; pf = true;} - else { pcol = textbgcolor; if (textcolor == textbgcolor) pf = false;} - line++; - px = pc % width; - tx = x + textsize * px; - py = pc / width; - ty = y + textsize * py; - - pl = 0; - pc += line; - while (line--) { - pl++; - if ((px+pl) >= width) { - if (pf) fillRect(tx, ty, pl * textsize, textsize, pcol); - pl = 0; - px = 0; - tx = x; - py ++; - ty += textsize; - } - } - if (pl && pf) fillRect(tx, ty, pl * textsize, textsize, pcol); - } - } - } - } - // End of RLE font rendering -#endif - -#if !defined (LOAD_FONT2) && !defined (LOAD_RLE) - // Stop warnings - flash_address = flash_address; - w = w; - pX = pX; - pY = pY; - line = line; - clip = clip; -#endif - - return width * textsize; // x + -} - - -#ifdef SMOOTH_FONT -/*************************************************************************************** -** Function name: drawGlyph -** Description: Write a character to the sprite cursor position -***************************************************************************************/ -// -void TFT_eSprite::drawGlyph(uint16_t code) -{ - uint16_t fg = textcolor; - uint16_t bg = textbgcolor; - bool getBG = false; - if (fg == bg) getBG = true; - - // Check if cursor has moved - if (last_cursor_x != cursor_x) - { - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; - } - - if (code < 0x21) - { - if (code == 0x20) { - if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); - cursor_x += gFont.spaceWidth; - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; - return; - } - - if (code == '\n') { - cursor_x = 0; - bg_cursor_x = 0; - last_cursor_x = 0; - cursor_y += gFont.yAdvance; - if (textwrapY && (cursor_y >= height())) cursor_y = 0; - return; - } - } - - uint16_t gNum = 0; - bool found = getUnicodeIndex(code, &gNum); - - if (found) - { - - bool newSprite = !_created; - - if (newSprite) - { - createSprite(gWidth[gNum], gFont.yAdvance); - if(fg != bg) fillSprite(bg); - cursor_x = -gdX[gNum]; - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; - cursor_y = 0; - } - else - { - if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) { - cursor_y += gFont.yAdvance; - cursor_x = 0; - bg_cursor_x = 0; - last_cursor_x = 0; - } - - if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 0; - if ( cursor_x == 0) cursor_x -= gdX[gNum]; - } - - uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; - -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift! - pbuffer = (uint8_t*)malloc(gWidth[gNum]); - } -#endif - - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; - - // if (cx > width() && bg_cursor_x > width()) return; - // if (cursor_y > height()) return; - - int16_t fxs = cx; - uint32_t fl = 0; - int16_t bxs = cx; - uint32_t bl = 0; - int16_t bx = 0; - uint8_t pixel = 0; - - int16_t fillwidth = 0; - int16_t fillheight = 0; - - // Fill area above glyph - if (_fillbg) { - fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; - if (fillwidth > 0) { - fillheight = gFont.maxAscent - gdY[gNum]; - if (fillheight > 0) { - fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); - } - } - else { - // Could be negative - fillwidth = 0; - } - - // Fill any area to left of glyph - if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); - // Set x position in glyph area where background starts - if (bg_cursor_x > cx) bx = bg_cursor_x - cx; - // Fill any area to right of glyph - if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) { - fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); - } - } - - for (int32_t y = 0; y < gHeight[gNum]; y++) - { -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - fontFile.read(pbuffer, gWidth[gNum]); - } -#endif - - for (int32_t x = 0; x < gWidth[gNum]; x++) - { -#ifdef FONT_FS_AVAILABLE - if (fs_font) pixel = pbuffer[x]; - else -#endif - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); - - if (pixel) - { - if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } - if (pixel != 0xFF) - { - if (fl) { - if (fl==1) drawPixel(fxs, y + cy, fg); - else drawFastHLine( fxs, y + cy, fl, fg); - fl = 0; - } - if (getBG) bg = readPixel(x + cx, y + cy); - drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg)); - } - else - { - if (fl==0) fxs = x + cx; - fl++; - } - } - else - { - if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } - if (_fillbg) { - if (x >= bx) { - if (bl==0) bxs = x + cx; - bl++; - } - } - } - } - if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } - if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } - } - - // Fill area below glyph - if (fillwidth > 0) { - fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); - if (fillheight > 0) { - fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); - } - } - - if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; - - if (newSprite) - { - pushSprite(cx, cursor_y); - deleteSprite(); - } - } - else - { - // Not a Unicode in font so draw a rectangle and move on cursor - drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); - cursor_x += gFont.spaceWidth + 1; - } - bg_cursor_x = cursor_x; - last_cursor_x = cursor_x; -} - - -/*************************************************************************************** -** Function name: printToSprite -** Description: Write a string to the sprite cursor position -***************************************************************************************/ -void TFT_eSprite::printToSprite(String string) -{ - if(!fontLoaded) return; - printToSprite((char*)string.c_str(), string.length()); -} - - -/*************************************************************************************** -** Function name: printToSprite -** Description: Write a string to the sprite cursor position -***************************************************************************************/ -void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) -{ - if(!fontLoaded) return; - - uint16_t n = 0; - bool newSprite = !_created; - int16_t cursorX = _tft->cursor_x; - - if (newSprite) - { - int16_t sWidth = 0; - uint16_t index = 0; - bool first = true; - while (n < len) - { - uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); - if (getUnicodeIndex(unicode, &index)) - { - if (first) { - first = false; - sWidth -= gdX[index]; - cursorX += gdX[index]; - } - if (n == len) sWidth += ( gWidth[index] + gdX[index]); - else sWidth += gxAdvance[index]; - } - else sWidth += gFont.spaceWidth + 1; - } - - createSprite(sWidth, gFont.yAdvance); - - if (textcolor != textbgcolor) fillSprite(textbgcolor); - } - - n = 0; - - while (n < len) - { - uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); - //Serial.print("Decoded Unicode = 0x");Serial.println(unicode,HEX); - //Serial.print("n = ");Serial.println(n); - drawGlyph(unicode); - } - - if (newSprite) - { // The sprite had to be created so place at TFT cursor - pushSprite(cursorX, _tft->cursor_y); - deleteSprite(); - } -} - - -/*************************************************************************************** -** Function name: printToSprite -** Description: Print character in a Sprite, create sprite if needed -***************************************************************************************/ -int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) -{ - bool newSprite = !_created; - int16_t sWidth = gWidth[index]; - - if (newSprite) - { - createSprite(sWidth, gFont.yAdvance); - - if (textcolor != textbgcolor) fillSprite(textbgcolor); - - drawGlyph(gUnicode[index]); - - pushSprite(x + gdX[index], y, textbgcolor); - deleteSprite(); - } - - else drawGlyph(gUnicode[index]); - - return gxAdvance[index]; -} -#endif diff --git a/lib/TFT_eSPI/Extensions/Sprite.h b/lib/TFT_eSPI/Extensions/Sprite.h deleted file mode 100644 index 67e29de..0000000 --- a/lib/TFT_eSPI/Extensions/Sprite.h +++ /dev/null @@ -1,188 +0,0 @@ -/*************************************************************************************** -// The following class creates Sprites in RAM, graphics can then be drawn in the Sprite -// and rendered quickly onto the TFT screen. The class inherits the graphics functions -// from the TFT_eSPI class. Some functions are overridden by this class so that the -// graphics are written to the Sprite rather than the TFT. -***************************************************************************************/ - -class TFT_eSprite : public TFT_eSPI { - - public: - - explicit TFT_eSprite(TFT_eSPI *tft); - ~TFT_eSprite(void); - - // 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 bit per pixel for 1 bit colour depth - // - 1 nibble per pixel for 4-bit colour (with palette table) - // - 1 byte per pixel for 8-bit colour (332 RGB format) - // - 2 bytes per pixel for 16-bit color depth (565 RGB format) - void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); - - // Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type - void* getPointer(void); - - // Returns true if sprite has been created - bool created(void); - - // Delete the sprite to free up the RAM - void deleteSprite(void); - - // 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 1, 4, 8 or 16 bits. Can be used to change depth an existing - // sprite, but clears it to black, returns a new pointer if sprite is re-created. - void* setColorDepth(int8_t b); - int8_t getColorDepth(void); - - // Set the palette for a 4-bit depth sprite. Only the first 16 colours in the map are used. - void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in RAM - void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in FLASH - - // Set a single palette index to the given color - void setPaletteColor(uint8_t index, uint16_t color); - - // Get the color at the given palette index - uint16_t getPaletteColor(uint8_t index); - - // Set foreground and background colours for 1 bit per pixel Sprite - void setBitmapColor(uint16_t fg, uint16_t bg); - - // Draw a single pixel at x,y - void drawPixel(int32_t x, int32_t y, uint32_t color); - - // Draw a single character in the GLCD or GFXFF font - void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), - - // 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 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 sprite's set window area - pushColor(uint16_t color), - // Push len colors (pixels) to the sprite's set window area - pushColor(uint16_t color, uint32_t len), - // Push a pixel pre-formatted as a 1, 4, 8 or 16-bit colour (avoids conversion overhead) - writeColor(uint16_t color), - - // Set the scroll zone, top left corner at x,y with defined width and height - // The colour (optional, black is default) is used to fill the gap after the scroll - setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color = TFT_BLACK), - // Scroll the defined zone dx,dy pixels. Negative values left,up, positive right,down - // dy is optional (default is 0, so no up/down scroll). - // 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 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, uint32_t transp = 0x00FFFFFF); - // Push a rotated copy of Sprite to another different Sprite with optional transparent colour - bool pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp = 0x00FFFFFF); - - // Get the TFT bounding box for a rotated copy of this Sprite - bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); - // Get the destination Sprite bounding box for a rotated copy of this Sprite - bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y); - // Bounding box support function - void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, - int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); - - // Read the colour of a pixel at x,y and return value in 565 format - uint16_t readPixel(int32_t x0, int32_t y0); - - // return the numerical value of the pixel at x,y (used when scrolling) - // 16bpp = colour, 8bpp = byte, 4bpp = colour index, 1bpp = 1 or 0 - uint16_t readPixelValue(int32_t x, int32_t y); - - // Write an image (colour bitmap) to the sprite. - void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0); - void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data); - - // Push the sprite to the TFT screen, this fn calls pushImage() in the TFT class. - // Optionally a "transparent" colour can be defined, pixels of that colour will not be rendered - void pushSprite(int32_t x, int32_t y); - void pushSprite(int32_t x, int32_t y, uint16_t transparent); - - // Push a windowed area of the sprite to the TFT at tx, ty - bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh); - - // Push the sprite to another sprite at x,y. This fn calls pushImage() in the destination sprite (dspr) class. - bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y); - bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent); - - // Draw a single character in the selected font - int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), - drawChar(uint16_t uniCode, int32_t x, int32_t y); - - // Return the width and height of the sprite - int16_t width(void), - height(void); - - // Functions associated with anti-aliased fonts - // Draw a single Unicode character using the loaded font - void drawGlyph(uint16_t code); - // Print string to sprite using loaded font at cursor position - void printToSprite(String string); - // Print char array to sprite using loaded font at cursor position - void printToSprite(char *cbuffer, uint16_t len); - // Print indexed glyph to sprite using loaded font at x,y - int16_t printToSprite(int16_t x, int16_t y, uint16_t index); - - private: - - TFT_eSPI *_tft; - - // Reserve memory for the Sprite and return a pointer - void* callocSprite(int16_t width, int16_t height, uint8_t frames = 1); - - // Override the non-inlined TFT_eSPI functions - void begin_nin_write(void) { ; } - void end_nin_write(void) { ; } - - protected: - - uint8_t _bpp; // bits per pixel (1, 4, 8 or 16) - uint16_t *_img; // pointer to 16-bit sprite - uint8_t *_img8; // pointer to 1 and 8-bit sprite frame 1 or frame 2 - uint8_t *_img4; // pointer to 4-bit sprite (uses color map) - uint8_t *_img8_1; // pointer to frame 1 - uint8_t *_img8_2; // pointer to frame 2 - - uint16_t *_colorMap; // color map pointer: 16 entries, used with 4-bit color map. - - int32_t _sinra; // Sine of rotation angle in fixed point - int32_t _cosra; // Cosine of rotation angle in fixed point - - bool _created; // A Sprite has been created and memory reserved - bool _gFont = false; - - int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; // for setWindow - int32_t _sx, _sy; // x,y for scroll zone - uint32_t _sw, _sh; // w,h for scroll zone - uint32_t _scolor; // gap fill colour for scroll zone - - int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations) - int32_t _dwidth, _dheight; // Real sprite width and height (for <8bpp Sprites) - int32_t _bitwidth; // Sprite image bit width for drawPixel (for <8bpp Sprites, not swapped) - -}; diff --git a/lib/TFT_eSPI/Extensions/Touch.cpp b/lib/TFT_eSPI/Extensions/Touch.cpp deleted file mode 100644 index 3d3ed82..0000000 --- a/lib/TFT_eSPI/Extensions/Touch.cpp +++ /dev/null @@ -1,349 +0,0 @@ -// The following touch screen support code by maxpautsch was merged 1/10/17 -// https://github.com/maxpautsch - -// Define TOUCH_CS is the user setup file to enable this code - -// A demo is provided in examples Generic folder - -// Additions by Bodmer to double sample, use Z value to improve detection reliability -// and to correct rotation handling - -// See license in root directory. - -// Define a default pressure threshold -#ifndef Z_THRESHOLD - #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches -#endif - -/*************************************************************************************** -** Function name: begin_touch_read_write - was spi_begin_touch -** Description: Start transaction and select touch controller -***************************************************************************************/ -// The touch controller has a low SPI clock rate -inline void TFT_eSPI::begin_touch_read_write(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 - SET_BUS_READ_MODE; - T_CS_L; -} - -/*************************************************************************************** -** Function name: end_touch_read_write - was spi_end_touch -** Description: End transaction and deselect touch controller -***************************************************************************************/ -inline void TFT_eSPI::end_touch_read_write(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 - //SET_BUS_WRITE_MODE; -} - -/*************************************************************************************** -** Function name: Legacy - deprecated -** Description: Start/end transaction -***************************************************************************************/ -void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();} -void TFT_eSPI::spi_end_touch() { end_touch_read_write();} - -/*************************************************************************************** -** Function name: getTouchRaw -** Description: read raw touch position. Always returns true. -***************************************************************************************/ -uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){ - uint16_t tmp; - - begin_touch_read_write(); - - // Start YP sample request for x position, read 4 times and keep last sample - spi.transfer(0xd0); // Start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion - - tmp = spi.transfer(0); // Read first 8 bits - tmp = tmp <<5; - tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion - - *x = tmp; - - // Start XP sample request for y position, read 4 times and keep last sample - spi.transfer(0); // Read first 8 bits - spi.transfer(0x90); // Read last 8 bits and start new XP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0x90); // Read last 8 bits and start new XP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0x90); // Read last 8 bits and start new XP conversion - - tmp = spi.transfer(0); // Read first 8 bits - tmp = tmp <<5; - tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits - - *y = tmp; - - end_touch_read_write(); - - return true; -} - -/*************************************************************************************** -** Function name: getTouchRawZ -** Description: read raw pressure on touchpad and return Z value. -***************************************************************************************/ -uint16_t TFT_eSPI::getTouchRawZ(void){ - - begin_touch_read_write(); - - // Z sample request - int16_t tz = 0xFFF; - spi.transfer(0xb0); // Start new Z1 conversion - tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion - tz -= spi.transfer16(0x00) >> 3; // Read Z2 - - end_touch_read_write(); - - if (tz == 4095) tz = 0; - - return (uint16_t)tz; -} - -/*************************************************************************************** -** Function name: validTouch -** Description: read validated position. Return false if not pressed. -***************************************************************************************/ -#define _RAWERR 20 // Deadband error allowed in successive position samples -uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ - uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2; - - // Wait until pressure stops increasing to debounce pressure - uint16_t z1 = 1; - uint16_t z2 = 0; - while (z1 > z2) - { - z2 = z1; - z1 = getTouchRawZ(); - delay(1); - } - - // Serial.print("Z = ");Serial.println(z1); - - if (z1 <= threshold) return false; - - getTouchRaw(&x_tmp,&y_tmp); - - // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp); - // Serial.print(", Z = ");Serial.println(z1); - - delay(1); // Small delay to the next sample - if (getTouchRawZ() <= threshold) return false; - - delay(2); // Small delay to the next sample - getTouchRaw(&x_tmp2,&y_tmp2); - - // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2); - // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2)); - - if (abs(x_tmp - x_tmp2) > _RAWERR) return false; - if (abs(y_tmp - y_tmp2) > _RAWERR) return false; - - *x = x_tmp; - *y = y_tmp; - - return true; -} - -/*************************************************************************************** -** Function name: getTouch -** Description: read callibrated position. Return false if not pressed. -***************************************************************************************/ -uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ - uint16_t x_tmp, y_tmp; - - if (threshold<20) threshold = 20; - if (_pressTime > millis()) threshold=20; - - uint8_t n = 5; - uint8_t valid = 0; - while (n--) - { - if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;; - } - - if (valid<1) { _pressTime = 0; return false; } - - _pressTime = millis() + 50; - - convertRawXY(&x_tmp, &y_tmp); - - if (x_tmp >= _width || y_tmp >= _height) return false; - - _pressX = x_tmp; - _pressY = y_tmp; - *x = _pressX; - *y = _pressY; - return valid; -} - -/*************************************************************************************** -** Function name: convertRawXY -** Description: convert raw touch x,y values to screen coordinates -***************************************************************************************/ -void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y) -{ - uint16_t x_tmp = *x, y_tmp = *y, xx, yy; - - if(!touchCalibration_rotate){ - xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1; - yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1; - if(touchCalibration_invert_x) - xx = _width - xx; - if(touchCalibration_invert_y) - yy = _height - yy; - } else { - xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1; - yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1; - if(touchCalibration_invert_x) - xx = _width - xx; - if(touchCalibration_invert_y) - yy = _height - yy; - } - *x = xx; - *y = yy; -} - -/*************************************************************************************** -** Function name: calibrateTouch -** Description: generates calibration parameters for touchscreen. -***************************************************************************************/ -void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){ - int16_t values[] = {0,0,0,0,0,0,0,0}; - uint16_t x_tmp, y_tmp; - - - - for(uint8_t i = 0; i<4; i++){ - fillRect(0, 0, size+1, size+1, color_bg); - fillRect(0, _height-size-1, size+1, size+1, color_bg); - fillRect(_width-size-1, 0, size+1, size+1, color_bg); - fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg); - - if (i == 5) break; // used to clear the arrows - - switch (i) { - case 0: // up left - drawLine(0, 0, 0, size, color_fg); - drawLine(0, 0, size, 0, color_fg); - drawLine(0, 0, size , size, color_fg); - break; - case 1: // bot left - drawLine(0, _height-size-1, 0, _height-1, color_fg); - drawLine(0, _height-1, size, _height-1, color_fg); - drawLine(size, _height-size-1, 0, _height-1 , color_fg); - break; - case 2: // up right - drawLine(_width-size-1, 0, _width-1, 0, color_fg); - drawLine(_width-size-1, size, _width-1, 0, color_fg); - drawLine(_width-1, size, _width-1, 0, color_fg); - break; - case 3: // bot right - drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg); - drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg); - drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg); - break; - } - - // user has to get the chance to release - if(i>0) delay(1000); - - for(uint8_t j= 0; j<8; j++){ - // Use a lower detect threshold as corners tend to be less sensitive - while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2)); - values[i*2 ] += x_tmp; - values[i*2+1] += y_tmp; - } - values[i*2 ] /= 8; - values[i*2+1] /= 8; - } - - - // from case 0 to case 1, the y value changed. - // If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched. - touchCalibration_rotate = false; - if(abs(values[0]-values[2]) > abs(values[1]-values[3])){ - touchCalibration_rotate = true; - touchCalibration_x0 = (values[1] + values[3])/2; // calc min x - touchCalibration_x1 = (values[5] + values[7])/2; // calc max x - touchCalibration_y0 = (values[0] + values[4])/2; // calc min y - touchCalibration_y1 = (values[2] + values[6])/2; // calc max y - } else { - touchCalibration_x0 = (values[0] + values[2])/2; // calc min x - touchCalibration_x1 = (values[4] + values[6])/2; // calc max x - touchCalibration_y0 = (values[1] + values[5])/2; // calc min y - touchCalibration_y1 = (values[3] + values[7])/2; // calc max y - } - - // in addition, the touch screen axis could be in the opposite direction of the TFT axis - touchCalibration_invert_x = false; - if(touchCalibration_x0 > touchCalibration_x1){ - values[0]=touchCalibration_x0; - touchCalibration_x0 = touchCalibration_x1; - touchCalibration_x1 = values[0]; - touchCalibration_invert_x = true; - } - touchCalibration_invert_y = false; - if(touchCalibration_y0 > touchCalibration_y1){ - values[0]=touchCalibration_y0; - touchCalibration_y0 = touchCalibration_y1; - touchCalibration_y1 = values[0]; - touchCalibration_invert_y = true; - } - - // pre calculate - touchCalibration_x1 -= touchCalibration_x0; - touchCalibration_y1 -= touchCalibration_y0; - - if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; - if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; - if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; - if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; - - // export parameters, if pointer valid - if(parameters != NULL){ - parameters[0] = touchCalibration_x0; - parameters[1] = touchCalibration_x1; - parameters[2] = touchCalibration_y0; - parameters[3] = touchCalibration_y1; - parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2); - } -} - - -/*************************************************************************************** -** Function name: setTouch -** Description: imports calibration parameters for touchscreen. -***************************************************************************************/ -void TFT_eSPI::setTouch(uint16_t *parameters){ - touchCalibration_x0 = parameters[0]; - touchCalibration_x1 = parameters[1]; - touchCalibration_y0 = parameters[2]; - touchCalibration_y1 = parameters[3]; - - if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; - if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; - if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; - if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; - - touchCalibration_rotate = parameters[4] & 0x01; - touchCalibration_invert_x = parameters[4] & 0x02; - touchCalibration_invert_y = parameters[4] & 0x04; -} diff --git a/lib/TFT_eSPI/Extensions/Touch.h b/lib/TFT_eSPI/Extensions/Touch.h deleted file mode 100644 index 9bb81fc..0000000 --- a/lib/TFT_eSPI/Extensions/Touch.h +++ /dev/null @@ -1,42 +0,0 @@ - // Coded by Bodmer 10/2/18, see license in root directory. - // This is part of the TFT_eSPI class and is associated with the Touch Screen handlers - - public: - // Get raw x,y ADC values from touch controller - uint8_t getTouchRaw(uint16_t *x, uint16_t *y); - // Get raw z (i.e. pressure) ADC value from touch controller - uint16_t getTouchRawZ(void); - // Convert raw x,y values to calibrated and correctly rotated screen coordinates - void convertRawXY(uint16_t *x, uint16_t *y); - // Get the screen touch coordinates, returns true if screen has been touched - // if the touch coordinates are off screen then x and y are not updated - // The returned value can be treated as a bool type, false or 0 means touch not detected - // In future the function may return an 8-bit "quality" (jitter) value. - // The threshold value is optional, this must be higher than the bias level for z (pressure) - // reported by Test_Touch_Controller when the screen is NOT touched. When touched the z value - // must be higher than the threshold for a touch to be detected. - uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); - - // Run screen calibration and test, report calibration values to the serial port - void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); - // Set the screen calibration values - void setTouch(uint16_t *data); - - private: - // Legacy support only - deprecated TODO: delete - void spi_begin_touch(); - void spi_end_touch(); - - // Handlers for the touch controller bus settings - inline void begin_touch_read_write() __attribute__((always_inline)); - inline void end_touch_read_write() __attribute__((always_inline)); - - // Private function to validate a touch, allow settle time and reduce spurious coordinates - uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); - - // Initialise with example calibration values so processor does not crash if setTouch() not called in setup() - uint16_t touchCalibration_x0 = 300, touchCalibration_x1 = 3600, touchCalibration_y0 = 300, touchCalibration_y1 = 3600; - uint8_t touchCalibration_rotate = 1, touchCalibration_invert_x = 2, touchCalibration_invert_y = 0; - - uint32_t _pressTime; // Press and hold time-out - uint16_t _pressX, _pressY; // For future use (last sampled calibrated coordinates) diff --git a/lib/TFT_eSPI/Fonts/glcdfont.c b/lib/TFT_eSPI/Fonts/glcdfont.c deleted file mode 100644 index 95c1c98..0000000 --- a/lib/TFT_eSPI/Fonts/glcdfont.c +++ /dev/null @@ -1,267 +0,0 @@ -// Original Adafruit_GFX 5x7 font - -#ifndef FONT5X7_H -#define FONT5X7_H - -// Standard ASCII 5x7 font - -static const unsigned char font[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, - 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, - 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, - 0x18, 0x3C, 0x7E, 0x3C, 0x18, - 0x1C, 0x57, 0x7D, 0x57, 0x1C, - 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, - 0x00, 0x18, 0x3C, 0x18, 0x00, - 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, - 0x00, 0x18, 0x24, 0x18, 0x00, - 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, - 0x30, 0x48, 0x3A, 0x06, 0x0E, - 0x26, 0x29, 0x79, 0x29, 0x26, - 0x40, 0x7F, 0x05, 0x05, 0x07, - 0x40, 0x7F, 0x05, 0x25, 0x3F, - 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, - 0x7F, 0x3E, 0x1C, 0x1C, 0x08, - 0x08, 0x1C, 0x1C, 0x3E, 0x7F, - 0x14, 0x22, 0x7F, 0x22, 0x14, - 0x5F, 0x5F, 0x00, 0x5F, 0x5F, - 0x06, 0x09, 0x7F, 0x01, 0x7F, - 0x00, 0x66, 0x89, 0x95, 0x6A, - 0x60, 0x60, 0x60, 0x60, 0x60, - 0x94, 0xA2, 0xFF, 0xA2, 0x94, - 0x08, 0x04, 0x7E, 0x04, 0x08, - 0x10, 0x20, 0x7E, 0x20, 0x10, - 0x08, 0x08, 0x2A, 0x1C, 0x08, - 0x08, 0x1C, 0x2A, 0x08, 0x08, - 0x1E, 0x10, 0x10, 0x10, 0x10, - 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, - 0x30, 0x38, 0x3E, 0x38, 0x30, - 0x06, 0x0E, 0x3E, 0x0E, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5F, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x07, 0x00, - 0x14, 0x7F, 0x14, 0x7F, 0x14, - 0x24, 0x2A, 0x7F, 0x2A, 0x12, - 0x23, 0x13, 0x08, 0x64, 0x62, - 0x36, 0x49, 0x56, 0x20, 0x50, - 0x00, 0x08, 0x07, 0x03, 0x00, - 0x00, 0x1C, 0x22, 0x41, 0x00, - 0x00, 0x41, 0x22, 0x1C, 0x00, - 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, - 0x08, 0x08, 0x3E, 0x08, 0x08, - 0x00, 0x80, 0x70, 0x30, 0x00, - 0x08, 0x08, 0x08, 0x08, 0x08, - 0x00, 0x00, 0x60, 0x60, 0x00, - 0x20, 0x10, 0x08, 0x04, 0x02, - 0x3E, 0x51, 0x49, 0x45, 0x3E, - 0x00, 0x42, 0x7F, 0x40, 0x00, - 0x72, 0x49, 0x49, 0x49, 0x46, - 0x21, 0x41, 0x49, 0x4D, 0x33, - 0x18, 0x14, 0x12, 0x7F, 0x10, - 0x27, 0x45, 0x45, 0x45, 0x39, - 0x3C, 0x4A, 0x49, 0x49, 0x31, - 0x41, 0x21, 0x11, 0x09, 0x07, - 0x36, 0x49, 0x49, 0x49, 0x36, - 0x46, 0x49, 0x49, 0x29, 0x1E, - 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x40, 0x34, 0x00, 0x00, - 0x00, 0x08, 0x14, 0x22, 0x41, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x00, 0x41, 0x22, 0x14, 0x08, - 0x02, 0x01, 0x59, 0x09, 0x06, - 0x3E, 0x41, 0x5D, 0x59, 0x4E, - 0x7C, 0x12, 0x11, 0x12, 0x7C, - 0x7F, 0x49, 0x49, 0x49, 0x36, - 0x3E, 0x41, 0x41, 0x41, 0x22, - 0x7F, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x49, 0x49, 0x49, 0x41, - 0x7F, 0x09, 0x09, 0x09, 0x01, - 0x3E, 0x41, 0x41, 0x51, 0x73, - 0x7F, 0x08, 0x08, 0x08, 0x7F, - 0x00, 0x41, 0x7F, 0x41, 0x00, - 0x20, 0x40, 0x41, 0x3F, 0x01, - 0x7F, 0x08, 0x14, 0x22, 0x41, - 0x7F, 0x40, 0x40, 0x40, 0x40, - 0x7F, 0x02, 0x1C, 0x02, 0x7F, - 0x7F, 0x04, 0x08, 0x10, 0x7F, - 0x3E, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x09, 0x09, 0x09, 0x06, - 0x3E, 0x41, 0x51, 0x21, 0x5E, - 0x7F, 0x09, 0x19, 0x29, 0x46, - 0x26, 0x49, 0x49, 0x49, 0x32, - 0x03, 0x01, 0x7F, 0x01, 0x03, - 0x3F, 0x40, 0x40, 0x40, 0x3F, - 0x1F, 0x20, 0x40, 0x20, 0x1F, - 0x3F, 0x40, 0x38, 0x40, 0x3F, - 0x63, 0x14, 0x08, 0x14, 0x63, - 0x03, 0x04, 0x78, 0x04, 0x03, - 0x61, 0x59, 0x49, 0x4D, 0x43, - 0x00, 0x7F, 0x41, 0x41, 0x41, - 0x02, 0x04, 0x08, 0x10, 0x20, - 0x00, 0x41, 0x41, 0x41, 0x7F, - 0x04, 0x02, 0x01, 0x02, 0x04, - 0x40, 0x40, 0x40, 0x40, 0x40, - 0x00, 0x03, 0x07, 0x08, 0x00, - 0x20, 0x54, 0x54, 0x78, 0x40, - 0x7F, 0x28, 0x44, 0x44, 0x38, - 0x38, 0x44, 0x44, 0x44, 0x28, - 0x38, 0x44, 0x44, 0x28, 0x7F, - 0x38, 0x54, 0x54, 0x54, 0x18, - 0x00, 0x08, 0x7E, 0x09, 0x02, - 0x18, 0xA4, 0xA4, 0x9C, 0x78, - 0x7F, 0x08, 0x04, 0x04, 0x78, - 0x00, 0x44, 0x7D, 0x40, 0x00, - 0x20, 0x40, 0x40, 0x3D, 0x00, - 0x7F, 0x10, 0x28, 0x44, 0x00, - 0x00, 0x41, 0x7F, 0x40, 0x00, - 0x7C, 0x04, 0x78, 0x04, 0x78, - 0x7C, 0x08, 0x04, 0x04, 0x78, - 0x38, 0x44, 0x44, 0x44, 0x38, - 0xFC, 0x18, 0x24, 0x24, 0x18, - 0x18, 0x24, 0x24, 0x18, 0xFC, - 0x7C, 0x08, 0x04, 0x04, 0x08, - 0x48, 0x54, 0x54, 0x54, 0x24, - 0x04, 0x04, 0x3F, 0x44, 0x24, - 0x3C, 0x40, 0x40, 0x20, 0x7C, - 0x1C, 0x20, 0x40, 0x20, 0x1C, - 0x3C, 0x40, 0x30, 0x40, 0x3C, - 0x44, 0x28, 0x10, 0x28, 0x44, - 0x4C, 0x90, 0x90, 0x90, 0x7C, - 0x44, 0x64, 0x54, 0x4C, 0x44, - 0x00, 0x08, 0x36, 0x41, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, - 0x00, 0x41, 0x36, 0x08, 0x00, - 0x02, 0x01, 0x02, 0x04, 0x02, - 0x3C, 0x26, 0x23, 0x26, 0x3C, - 0x1E, 0xA1, 0xA1, 0x61, 0x12, - 0x3A, 0x40, 0x40, 0x20, 0x7A, - 0x38, 0x54, 0x54, 0x55, 0x59, - 0x21, 0x55, 0x55, 0x79, 0x41, - 0x21, 0x54, 0x54, 0x78, 0x41, - 0x21, 0x55, 0x54, 0x78, 0x40, - 0x20, 0x54, 0x55, 0x79, 0x40, - 0x0C, 0x1E, 0x52, 0x72, 0x12, - 0x39, 0x55, 0x55, 0x55, 0x59, - 0x39, 0x54, 0x54, 0x54, 0x59, - 0x39, 0x55, 0x54, 0x54, 0x58, - 0x00, 0x00, 0x45, 0x7C, 0x41, - 0x00, 0x02, 0x45, 0x7D, 0x42, - 0x00, 0x01, 0x45, 0x7C, 0x40, - 0xF0, 0x29, 0x24, 0x29, 0xF0, - 0xF0, 0x28, 0x25, 0x28, 0xF0, - 0x7C, 0x54, 0x55, 0x45, 0x00, - 0x20, 0x54, 0x54, 0x7C, 0x54, - 0x7C, 0x0A, 0x09, 0x7F, 0x49, - 0x32, 0x49, 0x49, 0x49, 0x32, - 0x32, 0x48, 0x48, 0x48, 0x32, - 0x32, 0x4A, 0x48, 0x48, 0x30, - 0x3A, 0x41, 0x41, 0x21, 0x7A, - 0x3A, 0x42, 0x40, 0x20, 0x78, - 0x00, 0x9D, 0xA0, 0xA0, 0x7D, - 0x39, 0x44, 0x44, 0x44, 0x39, - 0x3D, 0x40, 0x40, 0x40, 0x3D, - 0x3C, 0x24, 0xFF, 0x24, 0x24, - 0x48, 0x7E, 0x49, 0x43, 0x66, - 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, - 0xFF, 0x09, 0x29, 0xF6, 0x20, - 0xC0, 0x88, 0x7E, 0x09, 0x03, - 0x20, 0x54, 0x54, 0x79, 0x41, - 0x00, 0x00, 0x44, 0x7D, 0x41, - 0x30, 0x48, 0x48, 0x4A, 0x32, - 0x38, 0x40, 0x40, 0x22, 0x7A, - 0x00, 0x7A, 0x0A, 0x0A, 0x72, - 0x7D, 0x0D, 0x19, 0x31, 0x7D, - 0x26, 0x29, 0x29, 0x2F, 0x28, - 0x26, 0x29, 0x29, 0x29, 0x26, - 0x30, 0x48, 0x4D, 0x40, 0x20, - 0x38, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x38, - 0x2F, 0x10, 0xC8, 0xAC, 0xBA, - 0x2F, 0x10, 0x28, 0x34, 0xFA, - 0x00, 0x00, 0x7B, 0x00, 0x00, - 0x08, 0x14, 0x2A, 0x14, 0x22, - 0x22, 0x14, 0x2A, 0x14, 0x08, - 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code - 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block - 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block - 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x10, 0x10, 0x10, 0xFF, 0x00, - 0x14, 0x14, 0x14, 0xFF, 0x00, - 0x10, 0x10, 0xFF, 0x00, 0xFF, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x14, 0x14, 0x14, 0xFC, 0x00, - 0x14, 0x14, 0xF7, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x14, 0x14, 0xF4, 0x04, 0xFC, - 0x14, 0x14, 0x17, 0x10, 0x1F, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0x1F, 0x00, - 0x10, 0x10, 0x10, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0xF0, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0xFF, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x14, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x1F, 0x10, 0x17, - 0x00, 0x00, 0xFC, 0x04, 0xF4, - 0x14, 0x14, 0x17, 0x10, 0x17, - 0x14, 0x14, 0xF4, 0x04, 0xF4, - 0x00, 0x00, 0xFF, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0xF7, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x17, 0x14, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0xF4, 0x14, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x00, 0x00, 0x1F, 0x10, 0x1F, - 0x00, 0x00, 0x00, 0x1F, 0x14, - 0x00, 0x00, 0x00, 0xFC, 0x14, - 0x00, 0x00, 0xF0, 0x10, 0xF0, - 0x10, 0x10, 0xFF, 0x10, 0xFF, - 0x14, 0x14, 0x14, 0xFF, 0x14, - 0x10, 0x10, 0x10, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x10, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x38, 0x44, 0x44, 0x38, 0x44, - 0x7C, 0x2A, 0x2A, 0x3E, 0x14, - 0x7E, 0x02, 0x02, 0x06, 0x06, - 0x02, 0x7E, 0x02, 0x7E, 0x02, - 0x63, 0x55, 0x49, 0x41, 0x63, - 0x38, 0x44, 0x44, 0x3C, 0x04, - 0x40, 0x7E, 0x20, 0x1E, 0x20, - 0x06, 0x02, 0x7E, 0x02, 0x02, - 0x99, 0xA5, 0xE7, 0xA5, 0x99, - 0x1C, 0x2A, 0x49, 0x2A, 0x1C, - 0x4C, 0x72, 0x01, 0x72, 0x4C, - 0x30, 0x4A, 0x4D, 0x4D, 0x30, - 0x30, 0x48, 0x78, 0x48, 0x30, - 0xBC, 0x62, 0x5A, 0x46, 0x3D, - 0x3E, 0x49, 0x49, 0x49, 0x00, - 0x7E, 0x01, 0x01, 0x01, 0x7E, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x44, 0x44, 0x5F, 0x44, 0x44, - 0x40, 0x51, 0x4A, 0x44, 0x40, - 0x40, 0x44, 0x4A, 0x51, 0x40, - 0x00, 0x00, 0xFF, 0x01, 0x03, - 0xE0, 0x80, 0xFF, 0x00, 0x00, - 0x08, 0x08, 0x6B, 0x6B, 0x08, - 0x36, 0x12, 0x36, 0x24, 0x36, - 0x06, 0x0F, 0x09, 0x0F, 0x06, - 0x00, 0x00, 0x18, 0x18, 0x00, - 0x00, 0x00, 0x10, 0x10, 0x00, - 0x30, 0x40, 0xFF, 0x01, 0x01, - 0x00, 0x1F, 0x01, 0x01, 0x1E, - 0x00, 0x19, 0x1D, 0x17, 0x12, - 0x00, 0x3C, 0x3C, 0x3C, 0x3C, - 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -#endif // FONT5X7_H diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9341_Defines.h b/lib/TFT_eSPI/ILI9341_Defines.h similarity index 87% rename from lib/TFT_eSPI/TFT_Drivers/ILI9341_Defines.h rename to lib/TFT_eSPI/ILI9341_Defines.h index 94ce1ef..caf5bb4 100644 --- a/lib/TFT_eSPI/TFT_Drivers/ILI9341_Defines.h +++ b/lib/TFT_eSPI/ILI9341_Defines.h @@ -1,14 +1,3 @@ -// Change the width and height if required (defined in portrait mode) -// or use the constructor to over-ride defaults - -#if defined (ILI9341_DRIVER) || defined (ILI9341_2_DRIVER) - #define TFT_WIDTH 240 - #define TFT_HEIGHT 320 -#elif defined (ILI9342_DRIVER) - #define TFT_WIDTH 320 - #define TFT_HEIGHT 240 -#endif - // Color definitions for backwards compatibility with old sketches // use colour definitions like TFT_BLACK to make sketches more portable #define ILI9341_BLACK 0x0000 /* 0, 0, 0 */ @@ -35,8 +24,6 @@ // Delay between some initialisation commands #define TFT_INIT_DELAY 0x80 // Not used unless commandlist invoked - -// Generic commands used by TFT_eSPI.cpp #define TFT_NOP 0x00 #define TFT_SWRST 0x01 @@ -51,7 +38,7 @@ #define TFT_RAMWR 0x2C #define TFT_RAMRD 0x2E -#define TFT_IDXRD 0xDD // ILI9341 only, indexed control register read +#define TFT_IDXRD 0xDD #define TFT_MADCTL 0x36 #define TFT_MAD_MY 0x80 @@ -72,7 +59,6 @@ #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR #endif -// All ILI9341 specific commands some are used by init() #define ILI9341_NOP 0x00 #define ILI9341_SWRESET 0x01 #define ILI9341_RDDID 0x04 @@ -129,7 +115,7 @@ #define ILI9341_RDID1 0xDA #define ILI9341_RDID2 0xDB #define ILI9341_RDID3 0xDC -#define ILI9341_RDIDX 0xDD // TBC +#define ILI9341_RDIDX 0xDD #define ILI9341_GMCTRP1 0xE0 #define ILI9341_GMCTRN1 0xE1 diff --git a/lib/TFT_eSPI/ILI9341_Init.h b/lib/TFT_eSPI/ILI9341_Init.h new file mode 100644 index 0000000..b33edab --- /dev/null +++ b/lib/TFT_eSPI/ILI9341_Init.h @@ -0,0 +1,112 @@ +{ + writecommand(0xEF); + writedata(0x03); + writedata(0x80); + writedata(0x02); + + writecommand(0xCF); + writedata(0x00); + writedata(0XC1); + writedata(0X30); + + writecommand(0xED); + writedata(0x64); + writedata(0x03); + writedata(0X12); + writedata(0X81); + + writecommand(0xE8); + writedata(0x85); + writedata(0x00); + writedata(0x78); + + writecommand(0xCB); + writedata(0x39); + writedata(0x2C); + writedata(0x00); + writedata(0x34); + writedata(0x02); + + writecommand(0xF7); + writedata(0x20); + + writecommand(0xEA); + writedata(0x00); + writedata(0x00); + + writecommand(ILI9341_PWCTR1); //Power control + writedata(0x23); //VRH[5:0] + + writecommand(ILI9341_PWCTR2); //Power control + writedata(0x10); //SAP[2:0];BT[3:0] + + writecommand(ILI9341_VMCTR1); //VCM control + writedata(0x3e); + writedata(0x28); + + writecommand(ILI9341_VMCTR2); //VCM control2 + writedata(0x86); //-- + + writecommand(ILI9341_MADCTL); // Memory Access Control + writedata(TFT_MAD_MX | TFT_MAD_COLOR_ORDER); // Rotation 0 (portrait mode) + + writecommand(ILI9341_PIXFMT); + writedata(0x55); + + writecommand(ILI9341_FRMCTR1); + writedata(0x00); + writedata(0x13); // 0x18 79Hz, 0x1B default 70Hz, 0x13 100Hz + + writecommand(ILI9341_DFUNCTR); // Display Function Control + writedata(0x08); + writedata(0x82); + writedata(0x27); + + writecommand(0xF2); // 3Gamma Function Disable + writedata(0x00); + + writecommand(ILI9341_GAMMASET); //Gamma curve selected + writedata(0x01); + + writecommand(ILI9341_GMCTRP1); //Set Gamma + writedata(0x0F); + writedata(0x31); + writedata(0x2B); + writedata(0x0C); + writedata(0x0E); + writedata(0x08); + writedata(0x4E); + writedata(0xF1); + writedata(0x37); + writedata(0x07); + writedata(0x10); + writedata(0x03); + writedata(0x0E); + writedata(0x09); + writedata(0x00); + + writecommand(ILI9341_GMCTRN1); //Set Gamma + writedata(0x00); + writedata(0x0E); + writedata(0x14); + writedata(0x03); + writedata(0x11); + writedata(0x07); + writedata(0x31); + writedata(0xC1); + writedata(0x48); + writedata(0x08); + writedata(0x0F); + writedata(0x0C); + writedata(0x31); + writedata(0x36); + writedata(0x0F); + + writecommand(ILI9341_SLPOUT); //Exit Sleep + + end_tft_write(); + delay(120); + begin_tft_write(); + + writecommand(ILI9341_DISPON); //Display on +} \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9341_Rotation.h b/lib/TFT_eSPI/ILI9341_Rotation.h similarity index 100% rename from lib/TFT_eSPI/TFT_Drivers/ILI9341_Rotation.h rename to lib/TFT_eSPI/ILI9341_Rotation.h diff --git a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.c b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.c deleted file mode 100644 index d3c3865..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.c +++ /dev/null @@ -1,852 +0,0 @@ - //////////////////////////////////////////////////// - // 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 CONFIG_IDF_TARGET_ESP32 - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use default VSPI port - SPIClass spi = SPIClass(VSPI); - #endif - #else - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use FSPI port - SPIClass& spi = SPI; - #endif - #endif -#endif - -#ifdef ESP32_DMA - // DMA SPA handle - spi_device_handle_t dmaHAL; - #ifdef CONFIG_IDF_TARGET_ESP32 - #define DMA_CHANNEL 1 - #ifdef USE_HSPI_PORT - spi_host_device_t spi_host = HSPI_HOST; - #elif defined(USE_FSPI_PORT) - spi_host_device_t spi_host = SPI_HOST; - #else // use VSPI port - spi_host_device_t spi_host = VSPI_HOST; - #endif - #else - #ifdef USE_HSPI_PORT - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = (spi_host_device_t) SPI3_HOST; // Draws once then freezes - #else // use FSPI port - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = (spi_host_device_t) SPI2_HOST; // Draws once then freezes - #endif - #endif -#endif - -#if !defined (TFT_PARALLEL_8_BIT) - // Volatile for register reads: - volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); - volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); - // Register writes only: - volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); - volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: beginSDA - VSPI port only, FPSI port only for S2 -** Description: Detach MOSI and attach MISO to SDA for reads -***************************************************************************************/ -void TFT_eSPI::begin_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_INPUT); - #ifdef CONFIG_IDF_TARGET_ESP32 - pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false); - #else // S2 - pinMatrixInAttach(TFT_MOSI, FSPIQ_IN_IDX, false); - #endif - SET_BUS_READ_MODE; -} - -/*************************************************************************************** -** Function name: endSDA - VSPI port only, FPSI port only for S2 -** Description: Attach MOSI to SDA and detach MISO for writes -***************************************************************************************/ -void TFT_eSPI::end_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_OUTPUT); - #ifdef CONFIG_IDF_TARGET_ESP32 - pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false); - #else // S2 - pinMatrixOutAttach(TFT_MOSI, FSPID_OUT_IDX, false, false); - #endif - SET_BUS_WRITE_MODE; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#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) -{ - // Arduino generic native function - 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); -} - -/*************************************************************************************** -** 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) -{ - pinMode(gpio, mode); - digitalWrite(gpio, 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 (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI 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); - bool empty = true; - volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; - if (len > 31) - { - *_spi_mosi_dlen = 511; - spi_w[0] = color32; - spi_w[1] = color32; - spi_w[2] = color32; - spi_w[3] = color32; - spi_w[4] = color32; - spi_w[5] = color32; - spi_w[6] = color32; - spi_w[7] = color32; - spi_w[8] = color32; - spi_w[9] = color32; - spi_w[10] = color32; - spi_w[11] = color32; - spi_w[12] = color32; - spi_w[13] = color32; - spi_w[14] = color32; - spi_w[15] = color32; - while(len>31) - { - while ((*_spi_cmd)&SPI_USR); - *_spi_cmd = SPI_USR; - len -= 32; - } - empty = false; - } - - if (len) - { - if(empty) { - for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; - } - len = (len << 4) - 1; - while (*_spi_cmd&SPI_USR); - *_spi_mosi_dlen = len; - *_spi_cmd = SPI_USR; - } - while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? -} -//*/ -//* -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - volatile uint32_t* spi_w = _spi_w; - uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); - uint32_t i = 0; - uint32_t rem = len & 0x1F; - len = len - rem; - - // Start with partial buffer pixels - if (rem) - { - while (*_spi_cmd&SPI_USR); - for (i=0; i < rem; i+=2) *spi_w++ = color32; - *_spi_mosi_dlen = (rem << 4) - 1; - *_spi_cmd = SPI_USR; - if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } - i = i>>1; while(i++<16) *spi_w++ = color32; - } - - while (*_spi_cmd&SPI_USR); - if (!rem) while (i++<16) *spi_w++ = color32; - *_spi_mosi_dlen = 511; - - // End with full buffer to maximise useful time for downstream code - while(len) - { - while (*_spi_cmd&SPI_USR); - *_spi_cmd = SPI_USR; - len -= 32; - } - - // Do not wait here - //while (*_spi_cmd&SPI_USR); -} -//*/ -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -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 (SPI_18BIT_DRIVER) // SPI 18-bit colour -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 and 3 byte RGB display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) -{ - // Split out the colours - uint32_t r = (color & 0xF800)>>8; - uint32_t g = (color & 0x07E0)<<5; - uint32_t b = (color & 0x001F)<<19; - // Concatenate 4 pixels into three 32-bit blocks - uint32_t r0 = r<<24 | b | g | r; - uint32_t r1 = r0>>8 | g<<16; - uint32_t r2 = r1>>8 | b<<8; - - if (len > 19) - { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S); - - while(len>19) - { - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2); - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - len -= 20; - } - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } - - if (len) - { - SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (len * 24) - 1, SPI_USR_MOSI_DBITLEN_S); - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2); - if (len > 8 ) - { - WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2); - WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0); - WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1); - WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2); - } - - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, hence !_swapBytes - if(!_swapBytes) { while ( len-- ) {tft_Write_16S(*data); data++;} } - else { while ( len-- ) {tft_Write_16(*data); data++;} } -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, so swap byte macro not used here - while ( len-- ) {tft_Write_16(*data); data++;} -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8-bit parallel -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 and parallel display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - #if defined (SSD1963_DRIVER) - if ( ((color & 0xF800)>> 8) == ((color & 0x07E0)>> 3) && ((color & 0xF800)>> 8)== ((color & 0x001F)<< 3) ) - #else - if ( (color >> 8) == (color & 0x00FF) ) - #endif - { if (!len) return; - tft_Write_16(color); - #if defined (SSD1963_DRIVER) - while (--len) {WR_L; WR_H; WR_L; WR_H; WR_L; WR_H;} - #else - #ifdef PSEUDO_16_BIT - while (--len) {WR_L; WR_H;} - #else - while (--len) {WR_L; WR_H; WR_L; WR_H;} - #endif - #endif - } - else while (len--) {tft_Write_16(color);} -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and parallel display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - while ( len-- ) {tft_Write_16(*data); data++;} -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and parallel display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - if(_swapBytes) { while ( len-- ) {tft_Write_16(*data); data++; } } - else { while ( len-- ) {tft_Write_16S(*data); data++;} } -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of display interface specific functions -//////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: dmaBusy -** Description: Check if DMA is busy -***************************************************************************************/ -bool TFT_eSPI::dmaBusy(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return false; - - spi_transaction_t *rtrans; - esp_err_t ret; - uint8_t checks = spiBusyCheck; - for (int i = 0; i < checks; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0); - if (ret == ESP_OK) spiBusyCheck--; - } - - //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); - if (spiBusyCheck ==0) return false; - return true; -} - - -/*************************************************************************************** -** Function name: dmaWait -** Description: Wait until DMA is over (blocking!) -***************************************************************************************/ -void TFT_eSPI::dmaWait(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return; - spi_transaction_t *rtrans; - esp_err_t ret; - for (int i = 0; i < spiBusyCheck; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); - assert(ret == ESP_OK); - } - spiBusyCheck = 0; -} - - -/*************************************************************************************** -** Function name: pushPixelsDMA -** Description: Push pixels to TFT (len must be less than 32767) -***************************************************************************************/ -// This will byte swap the original image if setSwapBytes(true) was called by sketch. -void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) -{ - if ((len == 0) || (!DMA_Enabled)) return; - - dmaWait(); - - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); - } - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// Fixed const data assumed, will NOT clip or swap bytes -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) -{ - if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; - - uint32_t len = w*h; - - dmaWait(); - - setAddrWindow(x, y, w, h); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //Data pointer - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// This will clip and also swap bytes if setSwapBytes(true) was called by sketch -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) -{ - if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; - - uint32_t len = dw*dh; - - if (buffer == nullptr) { - buffer = image; - dmaWait(); - } - - // If image is clipped, copy pixels into a contiguous block - if ( (dw != w) || (dh != h) ) { - if(_swapBytes) { - for (int32_t yb = 0; yb < dh; yb++) { - for (int32_t xb = 0; xb < dw; xb++) { - uint32_t src = xb + dx + w * (yb + dy); - (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); - } - } - } - else { - for (int32_t yb = 0; yb < dh; yb++) { - memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); - } - } - } - // else, if a buffer pointer has been provided copy whole image to the buffer - else if (buffer != image || _swapBytes) { - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); - } - else { - memcpy(buffer, image, len*2); - } - } - - if (spiBusyCheck) dmaWait(); // In case we did not wait earlier - - setAddrWindow(x, y, dw, dh); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = buffer; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// Processor specific DMA initialisation -//////////////////////////////////////////////////////////////////////////////////////// - -// The DMA functions here work with SPI only (not parallel) -/*************************************************************************************** -** Function name: dc_callback -** Description: Toggles DC line during transaction -***************************************************************************************/ -extern "C" void dc_callback(); - -void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) -{ - if ((bool)spi_tx->user) {DC_D;} - else {DC_C;} -} - -/*************************************************************************************** -** Function name: dma_end_callback -** Description: Clear DMA run flag to stop retransmission loop -***************************************************************************************/ -extern "C" void dma_end_callback(); - -void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) -{ - WRITE_PERI_REG(SPI_DMA_CONF_REG(spi_host), 0); -} - -/*************************************************************************************** -** Function name: initDMA -** Description: Initialise the DMA engine - returns true if init OK -***************************************************************************************/ -bool TFT_eSPI::initDMA(bool ctrl_cs) -{ - if (DMA_Enabled) return false; - - esp_err_t ret; - spi_bus_config_t buscfg = { - .mosi_io_num = TFT_MOSI, - .miso_io_num = TFT_MISO, - .sclk_io_num = TFT_SCLK, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - .data4_io_num = -1, - .data5_io_num = -1, - .data6_io_num = -1, - .data7_io_num = -1, - .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size - .flags = 0, - .intr_flags = 0 - }; - - int8_t pin = -1; - if (ctrl_cs) pin = TFT_CS; - - spi_device_interface_config_t devcfg = { - .command_bits = 0, - .address_bits = 0, - .dummy_bits = 0, - .mode = TFT_SPI_MODE, - .duty_cycle_pos = 0, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .clock_speed_hz = SPI_FREQUENCY, - .input_delay_ns = 0, - .spics_io_num = pin, - .flags = SPI_DEVICE_NO_DUMMY, //0, - .queue_size = 1, - .pre_cb = 0, //dc_callback, //Callback to handle D/C line - #ifdef CONFIG_IDF_TARGET_ESP32 - .post_cb = 0 - #else - .post_cb = dma_end_callback - #endif - }; - ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); - ESP_ERROR_CHECK(ret); - ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); - ESP_ERROR_CHECK(ret); - - DMA_Enabled = true; - spiBusyCheck = 0; - return true; -} - -/*************************************************************************************** -** Function name: deInitDMA -** Description: Disconnect the DMA engine from SPI -***************************************************************************************/ -void TFT_eSPI::deInitDMA(void) -{ - if (!DMA_Enabled) return; - spi_bus_remove_device(dmaHAL); - spi_bus_free(spi_host); - DMA_Enabled = false; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.h b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.h deleted file mode 100644 index ad60e3d..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32.h +++ /dev/null @@ -1,591 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI driver functions for ESP32 processors // - //////////////////////////////////////////////////// - -#ifndef _TFT_eSPI_ESP32H_ -#define _TFT_eSPI_ESP32H_ - -// Processor ID reported by getSetup() -#define PROCESSOR_ID 0x32 - -// Include processor specific header -#include "soc/spi_reg.h" -#include "driver/spi_master.h" -#include "hal/gpio_ll.h" - -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) - #define CONFIG_IDF_TARGET_ESP32 -#endif - -// Fix IDF problems with ESP32C3 -#if CONFIG_IDF_TARGET_ESP32C3 - // Fix ESP32C3 IDF bug for missing definition - #ifndef REG_SPI_BASE - #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) - #endif - - // Fix ESP32C3 IDF bug for name change - #ifndef SPI_MOSI_DLEN_REG - #define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) - #endif - - // Fix ESP32C3 specific register reference - #define out_w1tc out_w1tc.val - #define out_w1ts out_w1ts.val -#endif - -// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled -#if !defined (SUPPORT_TRANSACTIONS) - #define SUPPORT_TRANSACTIONS -#endif - -/* -ESP32: -FSPI not defined -HSPI = 2, uses SPI2 -VSPI = 3, uses SPI3 - -ESP32-S2: -FSPI = 1, uses SPI2 -HSPI = 2, uses SPI3 -VSPI not defined - -ESP32 C3: -FSPI = 0, uses SPI2 ???? To be checked -HSPI = 1, uses SPI3 ???? To be checked -VSPI not defined - -For ESP32/S2/C3: -SPI1_HOST = 0 -SPI2_HOST = 1 -SPI3_HOST = 2 -*/ - -// ESP32 specific SPI port selection -#ifdef USE_HSPI_PORT - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT HSPI //HSPI is port 2 on ESP32 - #else - #define SPI_PORT 3 //HSPI is port 3 on ESP32 S2 - #endif -#elif defined(USE_FSPI_PORT) - #define SPI_PORT 2 //FSPI(ESP32 S2) -#else - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT VSPI - #else - #define SPI_PORT 2 //FSPI(ESP32 S2) - #endif -#endif - -#ifdef RPI_DISPLAY_TYPE - #define CMD_BITS (16-1) -#else - #define CMD_BITS (8-1) -#endif - -// Initialise processor specific SPI functions, used by init() -#define INIT_TFT_DATA_BUS // Not used - -// Define a generic flag for 8-bit parallel -#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility - #if !defined (TFT_PARALLEL_8_BIT) - #define TFT_PARALLEL_8_BIT // Generic parallel flag - #endif -#endif - -// Ensure ESP32 specific flag is defined for 8-bit parallel -#if defined (TFT_PARALLEL_8_BIT) - #if !defined (ESP32_PARALLEL) - #define ESP32_PARALLEL - #endif -#endif - -// Processor specific code used by SPI bus transaction startWrite and endWrite functions -#if !defined (ESP32_PARALLEL) - #if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE - #else - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN - #endif -#else - // Not applicable to parallel bus - #define SET_BUS_WRITE_MODE - #define SET_BUS_READ_MODE -#endif - -// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions -#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) - #define ESP32_DMA - // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK dmaWait() -#else - #define DMA_BUSY_CHECK -#endif - -#if defined(TFT_PARALLEL_8_BIT) - #define SPI_BUSY_CHECK -#else - #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) -#endif - -// If smooth font is used then it is likely SPIFFS will be needed -#ifdef SMOOTH_FONT - // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts - #define FS_NO_GLOBALS - #include - #include "SPIFFS.h" // ESP32 only - #define FONT_FS_AVAILABLE -#endif - - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the DC (TFT Data/Command or Register Select (RS))pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_DC - #define DC_C // No macro allocated so it generates no code - #define DC_D // No macro allocated so it generates no code -#else - #if defined (TFT_PARALLEL_8_BIT) - // TFT_DC, by design, must be in range 0-31 for single register parallel write - #if (TFT_DC >= 0) && (TFT_DC < 32) - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts = (1 << TFT_DC) - #elif (TFT_DC >= 32) - #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC- 32)) - #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC- 32)) - #else - #define DC_C - #define DC_D - #endif - #else - #if (TFT_DC >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change - #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #else - #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #endif - #elif (TFT_DC >= 0) - #if defined (RPI_DISPLAY_TYPE) - #if defined (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) - #else - // 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) - #endif - #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 TFT_CS -1 // Keep DMA code happy - #define CS_L // No macro allocated so it generates no code - #define CS_H // No macro allocated so it generates no code -#else - #if defined (TFT_PARALLEL_8_BIT) - #if TFT_CS >= 32 - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #elif TFT_CS >= 0 - #define CS_L GPIO.out_w1tc = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts = (1 << TFT_CS) - #else - #define CS_L - #define CS_H - #endif - #else - #if (TFT_CS >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change - #define CS_L GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #else - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #endif - #elif (TFT_CS >= 0) - #ifdef RPI_DISPLAY_TYPE // RPi 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 -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_WR) - #if (TFT_WR >= 32) - // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 - #define WR_L GPIO.out1_w1tc.val = (1 << (TFT_WR - 32)) - #define WR_H GPIO.out1_w1ts.val = (1 << (TFT_WR - 32)) - #elif (TFT_WR >= 0) - // TFT_WR, for best performance, should be in range 0-31 for single register parallel write - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) - #else - #define WR_L - #define WR_H - #endif -#else - #define WR_L - #define WR_H -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the touch screen chip select pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TOUCH_CS - #define T_CS_L // No macro allocated so it generates no code - #define T_CS_H // No macro allocated so it generates no code -#else // XPT2046 is slow, so use slower digitalWrite here - #define T_CS_L digitalWrite(TOUCH_CS, LOW) - #define T_CS_H digitalWrite(TOUCH_CS, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Make sure SPI default pins are assigned if not specified by user or set to -1 -//////////////////////////////////////////////////////////////////////////////////////// -#if !defined (TFT_PARALLEL_8_BIT) - - #ifdef USE_HSPI_PORT - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 13 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 13 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 14 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 14 - #endif - - #else // VSPI port - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 23 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 23 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 18 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 18 - #endif - - #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) - #if (TFT_MISO == -1) - #undef TFT_MISO - #define TFT_MISO TFT_MOSI - #endif - #endif - - #endif - -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the parallel bus interface chip pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_PARALLEL_8_BIT) - - // Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically - // can then use e.g. GPIO.out_w1ts = set_mask(0xFF); to set data bus to 0xFF - #define PARALLEL_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 GPIO_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)) - - #if (TFT_WR >= 32) - // Data bits and the write line are cleared sequentially - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK); WR_L - #elif (TFT_WR >= 0) - // Data bits and the write line are cleared to 0 in one step (1.25x faster) - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR)) - #else - #define GPIO_OUT_CLR_MASK - #endif - - // 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H - - // 18-bit color write with swapped bytes - #define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) - - #else - - #ifdef PSEUDO_16_BIT - // One write strobe for both bytes - #define tft_Write_16(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H - #define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H - #else - // Write 16 bits to TFT - #define tft_Write_16(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H - #endif - - #endif - - // Write 32 bits to TFT - #define tft_Write_32(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 16)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((D) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H - - // Read pin - #ifdef TFT_RD - #if (TFT_RD >= 32) - #define RD_L GPIO.out1_w1tc.val = (1 << (TFT_RD - 32)) - #define RD_H GPIO.out1_w1ts.val = (1 << (TFT_RD - 32)) - #elif (TFT_RD >= 0) - #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) - #else - #define RD_L - #define RD_H - #endif - #else - #define TFT_RD -1 - #define RD_L - #define RD_H - #endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to a SPI ILI948x TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour - - // 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) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Convert swapped byte 16-bit colour to 18-bit and write in 3 bytes - #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ - spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ - spi.transfer(((C) & 0x1F00)>>5) - - // Write 32 bits to TFT - #define tft_Write_32(C) spi.write32(C) - - // Write two concatenated 16-bit values to TFT - #define tft_Write_32C(C,D) spi.write32((C)<<16 | (D)) - - // Write 16-bit value twice to TFT - #define tft_Write_32D(C) spi.write32((C)<<16 | (C)) - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to an Raspberry Pi TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (RPI_DISPLAY_TYPE) - - // ESP32 low level SPI writes for 8, 16 and 32-bit values - // to avoid the function call overhead - #define TFT_WRITE_BITS(D, B) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Write 16 bits - #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) - - // 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 -/* Old macros - // ESP32 low level SPI writes for 8, 16 and 32-bit values - // to avoid the function call overhead - #define TFT_WRITE_BITS(D, B) \ - 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 endianness 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) -//*/ -//* Replacement slimmer macros - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ - *_spi_w = ((C)<<8 | (C)>>8); \ - *_spi_cmd = SPI_USR; - - // Write 16 bits - #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) - - // Write 32 bits - #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) - - // Write two address coordinates - #define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) - - // Write same value twice - #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) - -//*/ -#endif - -#ifndef tft_Write_16N - #define tft_Write_16N tft_Write_16 -#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/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.c b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.c deleted file mode 100644 index 8c97a5f..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.c +++ /dev/null @@ -1,861 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI driver functions for ESP32 processors // - //////////////////////////////////////////////////// - -// Temporarily a separate file to TFT_eSPI_ESP32.c until board package low level API stabilises - -//////////////////////////////////////////////////////////////////////////////////////// -// Global variables -//////////////////////////////////////////////////////////////////////////////////////// - -// Select the SPI port to use, ESP32 has 2 options -#if !defined (TFT_PARALLEL_8_BIT) - #ifdef CONFIG_IDF_TARGET_ESP32 - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use default VSPI port - SPIClass spi = SPIClass(VSPI); - #endif - #else - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use FSPI port - SPIClass& spi = SPI; - #endif - #endif -#endif - -#ifdef ESP32_DMA - // DMA SPA handle - spi_device_handle_t dmaHAL; - #ifdef CONFIG_IDF_TARGET_ESP32 - #define DMA_CHANNEL 1 - #ifdef USE_HSPI_PORT - spi_host_device_t spi_host = HSPI_HOST; - #elif defined(USE_FSPI_PORT) - spi_host_device_t spi_host = SPI_HOST; - #else // use VSPI port - spi_host_device_t spi_host = VSPI_HOST; - #endif - #else - #ifdef USE_HSPI_PORT - #define DMA_CHANNEL 2 - spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes - #else // use FSPI port - #define DMA_CHANNEL 1 - spi_host_device_t spi_host = (spi_host_device_t) DMA_CHANNEL; // Draws once then freezes - #endif - #endif -#endif - -#if !defined (TFT_PARALLEL_8_BIT) - // Volatile for register reads: - volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); - volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); - // Register writes only: - volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); - volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: beginSDA - FPSI port only -** Description: Detach MOSI and attach MISO to SDA for reads -***************************************************************************************/ -void TFT_eSPI::begin_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_INPUT); - pinMatrixInAttach(TFT_MOSI, FSPIQ_IN_IDX, false); - SET_BUS_READ_MODE; -} - -/*************************************************************************************** -** Function name: endSDA - FPSI port only -** Description: Attach MOSI to SDA and detach MISO for writes -***************************************************************************************/ -void TFT_eSPI::end_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_OUTPUT); - pinMatrixOutAttach(TFT_MOSI, FSPID_OUT_IDX, false, false); - SET_BUS_WRITE_MODE; -} -//////////////////////////////////////////////////////////////////////////////////////// -#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) -{ - // Arduino generic native function - 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); -} - -/*************************************************************************************** -** 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) -{ - pinMode(gpio, mode); - digitalWrite(gpio, 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 (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI 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); - bool empty = true; - volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; - if (len > 31) - { - *_spi_mosi_dlen = 511; - spi_w[0] = color32; - spi_w[1] = color32; - spi_w[2] = color32; - spi_w[3] = color32; - spi_w[4] = color32; - spi_w[5] = color32; - spi_w[6] = color32; - spi_w[7] = color32; - spi_w[8] = color32; - spi_w[9] = color32; - spi_w[10] = color32; - spi_w[11] = color32; - spi_w[12] = color32; - spi_w[13] = color32; - spi_w[14] = color32; - spi_w[15] = color32; - while(len>31) - { - while ((*_spi_cmd)&SPI_USR); - *_spi_cmd = SPI_USR; - len -= 32; - } - empty = false; - } - - if (len) - { - if(empty) { - for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; - } - len = (len << 4) - 1; - while (*_spi_cmd&SPI_USR); - *_spi_mosi_dlen = len; - *_spi_cmd = SPI_USR; - } - while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? -} -//*/ -//* -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - volatile uint32_t* spi_w = _spi_w; - uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); - uint32_t i = 0; - uint32_t rem = len & 0x1F; - len = len - rem; - - // Start with partial buffer pixels - if (rem) - { - while (*_spi_cmd&SPI_USR); - for (i=0; i < rem; i+=2) *spi_w++ = color32; - *_spi_mosi_dlen = (rem << 4) - 1; -#if CONFIG_IDF_TARGET_ESP32C3 - *_spi_cmd = SPI_UPDATE; - while (*_spi_cmd & SPI_UPDATE); -#endif - *_spi_cmd = SPI_USR; - if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } - i = i>>1; while(i++<16) *spi_w++ = color32; - } - - while (*_spi_cmd&SPI_USR); - if (!rem) while (i++<16) *spi_w++ = color32; - *_spi_mosi_dlen = 511; - - // End with full buffer to maximise useful time for downstream code - while(len) - { - while (*_spi_cmd&SPI_USR); -#if CONFIG_IDF_TARGET_ESP32C3 - *_spi_cmd = SPI_UPDATE; - while (*_spi_cmd & SPI_UPDATE); -#endif - *_spi_cmd = SPI_USR; - len -= 32; - } - - // Do not wait here - //while (*_spi_cmd&SPI_USR); -} -//*/ -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -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]); -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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]); -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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; - } -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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++); -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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++); -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - } - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** 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) - { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 479); - - 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); -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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) - { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len * 24) - 1); - 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); - } -#if CONFIG_IDF_TARGET_ESP32C3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, hence !_swapBytes - if(!_swapBytes) { while ( len-- ) {tft_Write_16S(*data); data++;} } - else { while ( len-- ) {tft_Write_16(*data); data++;} } -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, so swap byte macro not used here - while ( len-- ) {tft_Write_16(*data); data++;} -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8-bit parallel -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 and parallel display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - if ( (color >> 8) == (color & 0x00FF) ) - { if (!len) return; - tft_Write_16(color); - #if defined (SSD1963_DRIVER) - while (--len) {WR_L; WR_H; WR_L; WR_H; WR_L; WR_H;} - #else - #ifdef PSEUDO_16_BIT - while (--len) {WR_L; WR_H;} - #else - while (--len) {WR_L; WR_H; WR_L; WR_H;} - #endif - #endif - } - else while (len--) {tft_Write_16(color);} -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and parallel display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - while ( len-- ) {tft_Write_16(*data); data++;} -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and parallel display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - if(_swapBytes) { while ( len-- ) {tft_Write_16(*data); data++; } } - else { while ( len-- ) {tft_Write_16S(*data); data++;} } -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of display interface specific functions -//////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: dmaBusy -** Description: Check if DMA is busy -***************************************************************************************/ -bool TFT_eSPI::dmaBusy(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return false; - - spi_transaction_t *rtrans; - esp_err_t ret; - uint8_t checks = spiBusyCheck; - for (int i = 0; i < checks; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0); - if (ret == ESP_OK) spiBusyCheck--; - } - - //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); - if (spiBusyCheck ==0) return false; - return true; -} - - -/*************************************************************************************** -** Function name: dmaWait -** Description: Wait until DMA is over (blocking!) -***************************************************************************************/ -void TFT_eSPI::dmaWait(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return; - spi_transaction_t *rtrans; - esp_err_t ret; - for (int i = 0; i < spiBusyCheck; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); - assert(ret == ESP_OK); - } - spiBusyCheck = 0; -} - - -/*************************************************************************************** -** Function name: pushPixelsDMA -** Description: Push pixels to TFT (len must be less than 32767) -***************************************************************************************/ -// This will byte swap the original image if setSwapBytes(true) was called by sketch. -void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) -{ - if ((len == 0) || (!DMA_Enabled)) return; - - dmaWait(); - - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); - } - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// Fixed const data assumed, will NOT clip or swap bytes -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) -{ - if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; - - uint32_t len = w*h; - - dmaWait(); - - setAddrWindow(x, y, w, h); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //Data pointer - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// This will clip and also swap bytes if setSwapBytes(true) was called by sketch -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) -{ - if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; - - uint32_t len = dw*dh; - - if (buffer == nullptr) { - buffer = image; - dmaWait(); - } - - // If image is clipped, copy pixels into a contiguous block - if ( (dw != w) || (dh != h) ) { - if(_swapBytes) { - for (int32_t yb = 0; yb < dh; yb++) { - for (int32_t xb = 0; xb < dw; xb++) { - uint32_t src = xb + dx + w * (yb + dy); - (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); - } - } - } - else { - for (int32_t yb = 0; yb < dh; yb++) { - memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); - } - } - } - // else, if a buffer pointer has been provided copy whole image to the buffer - else if (buffer != image || _swapBytes) { - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); - } - else { - memcpy(buffer, image, len*2); - } - } - - if (spiBusyCheck) dmaWait(); // In case we did not wait earlier - - setAddrWindow(x, y, dw, dh); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = buffer; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// Processor specific DMA initialisation -//////////////////////////////////////////////////////////////////////////////////////// - -// The DMA functions here work with SPI only (not parallel) -/*************************************************************************************** -** Function name: dc_callback -** Description: Toggles DC line during transaction -***************************************************************************************/ -extern "C" void dc_callback(); - -void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) -{ - if ((bool)spi_tx->user) {DC_D;} - else {DC_C;} -} - -/*************************************************************************************** -** Function name: initDMA -** Description: Initialise the DMA engine - returns true if init OK -***************************************************************************************/ -bool TFT_eSPI::initDMA(bool ctrl_cs) -{ - if (DMA_Enabled) return false; - - esp_err_t ret; - spi_bus_config_t buscfg = { - .mosi_io_num = TFT_MOSI, - .miso_io_num = TFT_MISO, - .sclk_io_num = TFT_SCLK, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - .data4_io_num = -1, - .data5_io_num = -1, - .data6_io_num = -1, - .data7_io_num = -1, - .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size - .flags = 0, - .intr_flags = 0 - }; - - int8_t pin = -1; - if (ctrl_cs) pin = TFT_CS; - - spi_device_interface_config_t devcfg = { - .command_bits = 0, - .address_bits = 0, - .dummy_bits = 0, - .mode = TFT_SPI_MODE, - .duty_cycle_pos = 0, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .clock_speed_hz = SPI_FREQUENCY, - .input_delay_ns = 0, - .spics_io_num = pin, - .flags = SPI_DEVICE_NO_DUMMY, //0, - .queue_size = 1, - .pre_cb = 0, //dc_callback, //Callback to handle D/C line - .post_cb = 0 - }; - ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); - ESP_ERROR_CHECK(ret); - ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); - ESP_ERROR_CHECK(ret); - - DMA_Enabled = true; - spiBusyCheck = 0; - return true; -} - -/*************************************************************************************** -** Function name: deInitDMA -** Description: Disconnect the DMA engine from SPI -***************************************************************************************/ -void TFT_eSPI::deInitDMA(void) -{ - if (!DMA_Enabled) return; - spi_bus_remove_device(dmaHAL); - spi_bus_free(spi_host); - DMA_Enabled = false; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h deleted file mode 100644 index 6fa1858..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h +++ /dev/null @@ -1,598 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI driver functions for ESP32 processors // - //////////////////////////////////////////////////// - -// Temporarily a separate file to TFT_eSPI_ESP32.h until board package low level API stabilises - -#ifndef _TFT_eSPI_ESP32H_ -#define _TFT_eSPI_ESP32H_ - -#if !defined(DISABLE_ALL_LIBRARY_WARNINGS) - #warning >>>>------>> DMA is not supported on the ESP32 C3 (possible future update) -#endif - -// Processor ID reported by getSetup() -#define PROCESSOR_ID 0x32 - -// Include processor specific header -#include "soc/spi_reg.h" -#include "driver/spi_master.h" -#include "hal/gpio_ll.h" - -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) - #define CONFIG_IDF_TARGET_ESP32 -#endif - -#ifndef VSPI - #define VSPI FSPI -#endif - -// Fix IDF problems with ESP32C3 -#if CONFIG_IDF_TARGET_ESP32C3 - // Fix ESP32C3 IDF bug for missing definition (VSPI/FSPI only tested at the moment) - #ifndef REG_SPI_BASE - #define REG_SPI_BASE(i) DR_REG_SPI2_BASE - #endif - - // Fix ESP32C3 IDF bug for name change - #ifndef SPI_MOSI_DLEN_REG - #define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) - #endif -#endif - -// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled -#if !defined (SUPPORT_TRANSACTIONS) - #define SUPPORT_TRANSACTIONS -#endif - -/* -ESP32: -FSPI not defined -HSPI = 2, uses SPI2 -VSPI = 3, uses SPI3 - -ESP32-S2: -FSPI = 1, uses SPI2 -HSPI = 2, uses SPI3 -VSPI not defined so have made VSPI = HSPI - -ESP32 C3: Only 1 SPI port available -FSPI = 1, uses SPI2 -HSPI = 1, uses SPI2 -VSPI not defined so have made VSPI = HSPI - -For ESP32/S2/C3: -SPI1_HOST = 0 -SPI2_HOST = 1 -SPI3_HOST = 2 -*/ - -// ESP32 specific SPI port selection - only SPI2_HOST available on C3 -#define SPI_PORT SPI2_HOST - -#ifdef RPI_DISPLAY_TYPE - #define CMD_BITS (16-1) -#else - #define CMD_BITS (8-1) -#endif - -// Initialise processor specific SPI functions, used by init() -#define INIT_TFT_DATA_BUS // Not used - -// Define a generic flag for 8-bit parallel -#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility - #if !defined (TFT_PARALLEL_8_BIT) - #define TFT_PARALLEL_8_BIT // Generic parallel flag - #endif -#endif - -// Ensure ESP32 specific flag is defined for 8-bit parallel -#if defined (TFT_PARALLEL_8_BIT) - #if !defined (ESP32_PARALLEL) - #define ESP32_PARALLEL - #endif -#endif - -// Processor specific code used by SPI bus transaction startWrite and endWrite functions -#if !defined (ESP32_PARALLEL) - #if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE - #else - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN - #endif -#else - // Not applicable to parallel bus - #define SET_BUS_WRITE_MODE - #define SET_BUS_READ_MODE -#endif - -// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions -#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) - #define ESP32_DMA - // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK dmaWait() -#else - #define DMA_BUSY_CHECK -#endif - -#if defined(TFT_PARALLEL_8_BIT) - #define SPI_BUSY_CHECK -#else - #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) -#endif - -// If smooth font is used then it is likely SPIFFS will be needed -#ifdef SMOOTH_FONT - // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts - #define FS_NO_GLOBALS - #include - #include "SPIFFS.h" // ESP32 only - #define FONT_FS_AVAILABLE -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the DC (TFT Data/Command or Register Select (RS))pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_DC - #define DC_C // No macro allocated so it generates no code - #define DC_D // No macro allocated so it generates no code -#else - #if defined (TFT_PARALLEL_8_BIT) - // TFT_DC, by design, must be in range 0-31 for single register parallel write - #if (TFT_DC >= 0) && (TFT_DC < 32) - #define DC_C GPIO.out_w1tc.val = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts.val = (1 << TFT_DC) - #elif (TFT_DC >= 32) - #define DC_C GPIO.out_w1tc.val = (1 << (TFT_DC- 32)) - #define DC_D GPIO.out_w1ts.val = (1 << (TFT_DC- 32)) - #else - #define DC_C - #define DC_D - #endif - #else - #if (TFT_DC >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change - #define DC_C GPIO.out_w1ts.val = (1 << (TFT_DC - 32)); \ - GPIO.out_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out_w1tc.val = (1 << (TFT_DC - 32)); \ - GPIO.out_w1ts.val = (1 << (TFT_DC - 32)) - #else - #define DC_C GPIO.out_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out_w1ts.val = (1 << (TFT_DC - 32)) - #endif - #elif (TFT_DC >= 0) - #if defined (RPI_DISPLAY_TYPE) - #if defined (ILI9486_DRIVER) - // RPi ILI9486 display needs a slower DC change - #define DC_C GPIO.out_w1tc.val = (1 << TFT_DC); \ - GPIO.out_w1tc.val = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \ - GPIO.out_w1ts.val = (1 << TFT_DC) - #else - // Other RPi displays need a slower C->D change - #define DC_C GPIO.out_w1tc.val = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \ - GPIO.out_w1ts.val = (1 << TFT_DC) - #endif - #else - #define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)//;GPIO.out_w1tc.val = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts.val = (1 << TFT_DC)//;GPIO.out_w1ts.val = (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 TFT_CS -1 // Keep DMA code happy - #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.out_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32)) - #elif TFT_CS >= 0 - #define CS_L GPIO.out_w1tc.val = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts.val = (1 << TFT_CS) - #else - #define CS_L - #define CS_H - #endif - #else - #if (TFT_CS >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change - #define CS_L GPIO.out_w1ts.val = (1 << (TFT_CS - 32)); \ - GPIO.out_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); \ - GPIO.out_w1ts.val = (1 << (TFT_CS - 32)) - #else - #define CS_L GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out_w1ts.val = (1 << (TFT_CS - 32)) - #endif - #elif (TFT_CS >= 0) - #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change - #define CS_L GPIO.out_w1ts.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS) - #define CS_H GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1ts.val = (1 << TFT_CS) - #else - #define CS_L GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts.val = (1 << TFT_CS)//;GPIO.out_w1ts.val = (1 << TFT_CS) - #endif - #else - #define CS_L - #define CS_H - #endif - #endif -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the WR (TFT Write) pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_WR) - #if (TFT_WR >= 32) - // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 - #define WR_L GPIO.out_w1tc.val = (1 << (TFT_WR - 32)) - #define WR_H GPIO.out_w1ts.val = (1 << (TFT_WR - 32)) - #elif (TFT_WR >= 0) - // TFT_WR, for best performance, should be in range 0-31 for single register parallel write - #define WR_L GPIO.out_w1tc.val = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts.val = (1 << TFT_WR) - #else - #define WR_L - #define WR_H - #endif -#else - #define WR_L - #define WR_H -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the touch screen chip select pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TOUCH_CS - #define T_CS_L // No macro allocated so it generates no code - #define T_CS_H // No macro allocated so it generates no code -#else // XPT2046 is slow, so use slower digitalWrite here - #define T_CS_L digitalWrite(TOUCH_CS, LOW) - #define T_CS_H digitalWrite(TOUCH_CS, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Make sure SPI default pins are assigned if not specified by user or set to -1 -//////////////////////////////////////////////////////////////////////////////////////// -#if !defined (TFT_PARALLEL_8_BIT) - - #ifdef USE_HSPI_PORT - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 13 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 13 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 14 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 14 - #endif - - #else // VSPI port - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 23 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 23 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 18 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 18 - #endif - - #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) - #if (TFT_MISO == -1) - #undef TFT_MISO - #define TFT_MISO TFT_MOSI - #endif - #endif - - #endif - -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the parallel bus interface chip pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_PARALLEL_8_BIT) - - // Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically - // can then use e.g. GPIO.out_w1ts.val = set_mask(0xFF); to set data bus to 0xFF - #define PARALLEL_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 GPIO_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)) - - #if (TFT_WR >= 32) - // Data bits and the write line are cleared sequentially - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK); WR_L - #elif (TFT_WR >= 0) - // Data bits and the write line are cleared to 0 in one step (1.25x faster) - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR)) - #else - #define GPIO_OUT_CLR_MASK - #endif - - // 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.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H - - // 18-bit color write with swapped bytes - #define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) - - #else - - #ifdef PSEUDO_16_BIT - // One write strobe for both bytes - #define tft_Write_16(C) GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H - #define tft_Write_16S(C) GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H - #else - // Write 16 bits to TFT - #define tft_Write_16(C) GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H - - // 16-bit write with swapped bytes - #define tft_Write_16S(C) GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H - #endif - - #endif - - // Write 32 bits to TFT - #define tft_Write_32(C) GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 24)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 16)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = 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.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = 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.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO.out_w1tc.val = GPIO_OUT_CLR_MASK; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H - - // Read pin - #ifdef TFT_RD - #if (TFT_RD >= 32) - #define RD_L GPIO.out_w1tc.val = (1 << (TFT_RD - 32)) - #define RD_H GPIO.out_w1ts.val = (1 << (TFT_RD - 32)) - #elif (TFT_RD >= 0) - #define RD_L GPIO.out_w1tc.val = (1 << TFT_RD) - //#define RD_L digitalWrite(TFT_WR, LOW) - #define RD_H GPIO.out_w1ts.val = (1 << TFT_RD) - //#define RD_H digitalWrite(TFT_WR, HIGH) - #else - #define RD_L - #define RD_H - #endif - #else - #define TFT_RD -1 - #define RD_L - #define RD_H - #endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to a SPI ILI948x TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour - - // 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) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Convert swapped byte 16-bit colour to 18-bit and write in 3 bytes - #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ - spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ - spi.transfer(((C) & 0x1F00)>>5) - - // Write 32 bits to TFT - #define tft_Write_32(C) spi.write32(C) - - // Write two concatenated 16-bit values to TFT - #define tft_Write_32C(C,D) spi.write32((C)<<16 | (D)) - - // Write 16-bit value twice to TFT - #define tft_Write_32D(C) spi.write32((C)<<16 | (C)) - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to an Raspberry Pi TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (RPI_DISPLAY_TYPE) - - // ESP32 low level SPI writes for 8, 16 and 32-bit values - // to avoid the function call overhead - #define TFT_WRITE_BITS(D, B) \ - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \ - WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \ - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \ - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Write 16 bits - #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) - - // 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 -/* Old macros - // ESP32 low level SPI writes for 8, 16 and 32-bit values - // to avoid the function call overhead - #define TFT_WRITE_BITS(D, B) \ - 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 endianness 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) -//*/ -//* Replacement slimmer macros - #if !defined(CONFIG_IDF_TARGET_ESP32C3) - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - #else - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_UPDATE; \ - while (*_spi_cmd & SPI_UPDATE); \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - #endif - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #if !defined(CONFIG_IDF_TARGET_ESP32C3) - #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ - *_spi_w = ((C)<<8 | (C)>>8); \ - *_spi_cmd = SPI_USR; - #else - #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ - *_spi_w = ((C)<<8 | (C)>>8); \ - *_spi_cmd = SPI_UPDATE; \ - while (*_spi_cmd & SPI_UPDATE); \ - *_spi_cmd = SPI_USR; - #endif - - // 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 - -#ifndef tft_Write_16N - #define tft_Write_16N tft_Write_16 -#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/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.c b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.c deleted file mode 100644 index d689e72..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.c +++ /dev/null @@ -1,898 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI driver functions for ESP32 processors // - //////////////////////////////////////////////////// - -// Temporarily a separate file to TFT_eSPI_ESP32.c until board package low level API stabilises - -//////////////////////////////////////////////////////////////////////////////////////// -// Global variables -//////////////////////////////////////////////////////////////////////////////////////// - -// Select the SPI port to use, ESP32 has 2 options -#if !defined (TFT_PARALLEL_8_BIT) - #ifdef CONFIG_IDF_TARGET_ESP32 - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use default VSPI port - SPIClass spi = SPIClass(VSPI); - #endif - #else - #ifdef USE_HSPI_PORT - SPIClass spi = SPIClass(HSPI); - #elif defined(USE_FSPI_PORT) - SPIClass spi = SPIClass(FSPI); - #else // use FSPI port - SPIClass& spi = SPI; - #endif - #endif -#endif - -#ifdef ESP32_DMA - // DMA SPA handle - spi_device_handle_t dmaHAL; - #ifdef CONFIG_IDF_TARGET_ESP32 - #define DMA_CHANNEL 1 - #ifdef USE_HSPI_PORT - spi_host_device_t spi_host = HSPI_HOST; - #elif defined(USE_FSPI_PORT) - spi_host_device_t spi_host = SPI_HOST; - #else // use VSPI port - spi_host_device_t spi_host = VSPI_HOST; - #endif - #else - #ifdef USE_HSPI_PORT - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = SPI3_HOST; - #else // use FSPI port - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = SPI2_HOST; - #endif - #endif -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: beginSDA - FPSI port only -** Description: Detach MOSI and attach MISO to SDA for reads -***************************************************************************************/ -void TFT_eSPI::begin_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_INPUT); - pinMatrixInAttach(TFT_MOSI, FSPIQ_IN_IDX, false); - SET_BUS_READ_MODE; -} - -/*************************************************************************************** -** Function name: endSDA - FPSI port only -** Description: Attach MOSI to SDA and detach MISO for writes -***************************************************************************************/ -void TFT_eSPI::end_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_OUTPUT); - pinMatrixOutAttach(TFT_MOSI, FSPID_OUT_IDX, false, false); - SET_BUS_WRITE_MODE; -} -//////////////////////////////////////////////////////////////////////////////////////// -#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; - b = gpio_get_level((gpio_num_t)TFT_D0); // Read three times to allow for bus access time - b = gpio_get_level((gpio_num_t)TFT_D0); - b = gpio_get_level((gpio_num_t)TFT_D0); // Data should be stable now - - // Check GPIO bits used and build value - b = (gpio_get_level((gpio_num_t)TFT_D0) << 0); - b |= (gpio_get_level((gpio_num_t)TFT_D1) << 1); - b |= (gpio_get_level((gpio_num_t)TFT_D2) << 2); - b |= (gpio_get_level((gpio_num_t)TFT_D3) << 3); - b |= (gpio_get_level((gpio_num_t)TFT_D4) << 4); - b |= (gpio_get_level((gpio_num_t)TFT_D5) << 5); - b |= (gpio_get_level((gpio_num_t)TFT_D6) << 6); - b |= (gpio_get_level((gpio_num_t)TFT_D7) << 7); - RD_H; -#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) -{ - // Arduino generic native function - 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); -} - -/*************************************************************************************** -** 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) -{ - pinMode(gpio, mode); - digitalWrite(gpio, 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 (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI 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); - bool empty = true; - volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; - if (len > 31) - { - *_spi_mosi_dlen = 511; - spi_w[0] = color32; - spi_w[1] = color32; - spi_w[2] = color32; - spi_w[3] = color32; - spi_w[4] = color32; - spi_w[5] = color32; - spi_w[6] = color32; - spi_w[7] = color32; - spi_w[8] = color32; - spi_w[9] = color32; - spi_w[10] = color32; - spi_w[11] = color32; - spi_w[12] = color32; - spi_w[13] = color32; - spi_w[14] = color32; - spi_w[15] = color32; - while(len>31) - { - while ((*_spi_cmd)&SPI_USR); - *_spi_cmd = SPI_USR; - len -= 32; - } - empty = false; - } - - if (len) - { - if(empty) { - for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; - } - len = (len << 4) - 1; - while (*_spi_cmd&SPI_USR); - *_spi_mosi_dlen = len; - *_spi_cmd = SPI_USR; - } - while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? -} -//*/ -//* -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - volatile uint32_t* spi_w = _spi_w; - uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); - uint32_t i = 0; - uint32_t rem = len & 0x1F; - len = len - rem; - - // Start with partial buffer pixels - if (rem) - { - while (*_spi_cmd&SPI_USR); - for (i=0; i < rem; i+=2) *spi_w++ = color32; - *_spi_mosi_dlen = (rem << 4) - 1; -#if CONFIG_IDF_TARGET_ESP32S3 - *_spi_cmd = SPI_UPDATE; - while (*_spi_cmd & SPI_UPDATE); -#endif - *_spi_cmd = SPI_USR; - if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } - i = i>>1; while(i++<16) *spi_w++ = color32; - } - - while (*_spi_cmd&SPI_USR); - if (!rem) while (i++<16) *spi_w++ = color32; - *_spi_mosi_dlen = 511; - - // End with full buffer to maximise useful time for downstream code - while(len) - { - while (*_spi_cmd&SPI_USR); -#if CONFIG_IDF_TARGET_ESP32S3 - *_spi_cmd = SPI_UPDATE; - while (*_spi_cmd & SPI_UPDATE); -#endif - *_spi_cmd = SPI_USR; - len -= 32; - } - - // Do not wait here - //while (*_spi_cmd&SPI_USR); -} -//*/ -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -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]); -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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]); -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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; - } -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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++); -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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++); -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - } - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** 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) - { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 479); - - 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); -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - 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) - { - WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len * 24) - 1); - 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); - } -#if CONFIG_IDF_TARGET_ESP32S3 - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_UPDATE); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_UPDATE); -#endif - SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); - while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); - } -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, hence !_swapBytes - if(!_swapBytes) { while ( len-- ) {tft_Write_16S(*data); data++;} } - else { while ( len-- ) {tft_Write_16(*data); data++;} } -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - // ILI9488 write macro is not endianess dependant, so swap byte macro not used here - while ( len-- ) {tft_Write_16(*data); data++;} -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8-bit parallel -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 and parallel display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - if ( (color >> 8) == (color & 0x00FF) ) - { if (!len) return; - tft_Write_16(color); - #if defined (SSD1963_DRIVER) - while (--len) {WR_L; WR_H; WR_L; WR_H; WR_L; WR_H;} - #else - #ifdef PSEUDO_16_BIT - while (--len) {WR_L; WR_H;} - #else - while (--len) {WR_L; WR_H; WR_L; WR_H;} - #endif - #endif - } - else while (len--) {tft_Write_16(color);} -} - -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 and parallel display -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - while ( len-- ) {tft_Write_16(*data); data++;} -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 and parallel display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - if(_swapBytes) { while ( len-- ) {tft_Write_16(*data); data++; } } - else { while ( len-- ) {tft_Write_16S(*data); data++;} } -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of display interface specific functions -//////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: dmaBusy -** Description: Check if DMA is busy -***************************************************************************************/ -bool TFT_eSPI::dmaBusy(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return false; - - spi_transaction_t *rtrans; - esp_err_t ret; - uint8_t checks = spiBusyCheck; - for (int i = 0; i < checks; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0); - if (ret == ESP_OK) spiBusyCheck--; - } - - //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); - if (spiBusyCheck ==0) return false; - return true; -} - - -/*************************************************************************************** -** Function name: dmaWait -** Description: Wait until DMA is over (blocking!) -***************************************************************************************/ -void TFT_eSPI::dmaWait(void) -{ - if (!DMA_Enabled || !spiBusyCheck) return; - spi_transaction_t *rtrans; - esp_err_t ret; - for (int i = 0; i < spiBusyCheck; ++i) - { - ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); - assert(ret == ESP_OK); - } - spiBusyCheck = 0; -} - - -/*************************************************************************************** -** Function name: pushPixelsDMA -** Description: Push pixels to TFT (len must be less than 32767) -***************************************************************************************/ -// This will byte swap the original image if setSwapBytes(true) was called by sketch. -void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) -{ - if ((len == 0) || (!DMA_Enabled)) return; - - dmaWait(); - - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); - } - - // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint - // small transfers are performed using a blocking call until DMA capacity is reached. - // User sketch can prevent blocking by managing pixel count and splitting into blocks - // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) - bool temp = _swapBytes; - _swapBytes = false; - while(len>0x4000) { // Transfer 16-bit pixels in blocks if len*2 over 65536 bytes - pushPixels(image, 0x400); - len -= 0x400; image+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) - } - _swapBytes = temp; - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// Fixed const data assumed, will NOT clip or swap bytes -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) -{ - if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; - - uint16_t *buffer = (uint16_t*)image; - uint32_t len = w*h; - - dmaWait(); - - setAddrWindow(x, y, w, h); - // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint - // small transfers are performed using a blocking call until DMA capacity is reached. - // User sketch can prevent blocking by managing pixel count and splitting into blocks - // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) - bool temp = _swapBytes; - _swapBytes = false; - while(len>0x4000) { // Transfer 16-bit pixels in blocks if len*2 over 65536 bytes - pushPixels(buffer, 0x400); - len -= 0x400; buffer+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) - } - _swapBytes = temp; - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = buffer; //Data pointer - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// This will clip and also swap bytes if setSwapBytes(true) was called by sketch -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) -{ - if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; - - uint32_t len = dw*dh; - - if (buffer == nullptr) { - buffer = image; - dmaWait(); - } - - // If image is clipped, copy pixels into a contiguous block - if ( (dw != w) || (dh != h) ) { - if(_swapBytes) { - for (int32_t yb = 0; yb < dh; yb++) { - for (int32_t xb = 0; xb < dw; xb++) { - uint32_t src = xb + dx + w * (yb + dy); - (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); - } - } - } - else { - for (int32_t yb = 0; yb < dh; yb++) { - memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); - } - } - } - // else, if a buffer pointer has been provided copy whole image to the buffer - else if (buffer != image || _swapBytes) { - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); - } - else { - memcpy(buffer, image, len*2); - } - } - - if (spiBusyCheck) dmaWait(); // In case we did not wait earlier - - setAddrWindow(x, y, dw, dh); - - // DMA byte count for transmit is 64Kbytes maximum, so to avoid this constraint - // small transfers are performed using a blocking call until DMA capacity is reached. - // User sketch can prevent blocking by managing pixel count and splitting into blocks - // of 32768 pixels maximum. (equivalent to an area of ~320 x 100 pixels) - bool temp = _swapBytes; - _swapBytes = false; - while(len>0x4000) { // Transfer 16-bit pixels in blocks if len*2 over 65536 bytes - pushPixels(buffer, 0x400); - len -= 0x400; buffer+= 0x400; // Arbitrarily send 1K pixel blocks (2Kbytes) - } - _swapBytes = temp; - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = buffer; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// Processor specific DMA initialisation -//////////////////////////////////////////////////////////////////////////////////////// - -// The DMA functions here work with SPI only (not parallel) -/*************************************************************************************** -** Function name: dc_callback -** Description: Toggles DC line during transaction (not used) -***************************************************************************************/ -extern "C" void dc_callback(); - -void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) -{ - if ((bool)spi_tx->user) {DC_D;} - else {DC_C;} -} - -/*************************************************************************************** -** Function name: dma_end_callback -** Description: Clear DMA run flag to stop retransmission loop -***************************************************************************************/ -extern "C" void dma_end_callback(); - -void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) -{ - WRITE_PERI_REG(SPI_DMA_CONF_REG(spi_host), 0); -} - -/*************************************************************************************** -** Function name: initDMA -** Description: Initialise the DMA engine - returns true if init OK -***************************************************************************************/ -bool TFT_eSPI::initDMA(bool ctrl_cs) -{ - if (DMA_Enabled) return false; - - esp_err_t ret; - spi_bus_config_t buscfg = { - .mosi_io_num = TFT_MOSI, - .miso_io_num = TFT_MISO, - .sclk_io_num = TFT_SCLK, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - .data4_io_num = -1, - .data5_io_num = -1, - .data6_io_num = -1, - .data7_io_num = -1, - .max_transfer_sz = 65536, // ESP32 S3 max size is 64Kbytes - .flags = 0, - .intr_flags = 0 - }; - - int8_t pin = -1; - if (ctrl_cs) pin = TFT_CS; - - spi_device_interface_config_t devcfg = { - .command_bits = 0, - .address_bits = 0, - .dummy_bits = 0, - .mode = TFT_SPI_MODE, - .duty_cycle_pos = 0, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .clock_speed_hz = SPI_FREQUENCY, - .input_delay_ns = 0, - .spics_io_num = pin, - .flags = SPI_DEVICE_NO_DUMMY, //0, - .queue_size = 1, // Not using queues - .pre_cb = 0, //dc_callback, //Callback to handle D/C line (not used) - .post_cb = dma_end_callback //Callback to end transmission - }; - ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); - ESP_ERROR_CHECK(ret); - ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); - ESP_ERROR_CHECK(ret); - - DMA_Enabled = true; - spiBusyCheck = 0; - return true; -} - -/*************************************************************************************** -** Function name: deInitDMA -** Description: Disconnect the DMA engine from SPI -***************************************************************************************/ -void TFT_eSPI::deInitDMA(void) -{ - if (!DMA_Enabled) return; - spi_bus_remove_device(dmaHAL); - spi_bus_free(spi_host); - DMA_Enabled = false; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.h b/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.h deleted file mode 100644 index c1a9e10..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_ESP32_S3.h +++ /dev/null @@ -1,612 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI driver functions for ESP32 processors // - //////////////////////////////////////////////////// - -// Temporarily a separate file to TFT_eSPI_ESP32.h until board package low level API stabilises - -#ifndef _TFT_eSPI_ESP32H_ -#define _TFT_eSPI_ESP32H_ - -// Processor ID reported by getSetup() -#define PROCESSOR_ID 0x32 - -// Include processor specific header -#include "soc/spi_reg.h" -#include "driver/spi_master.h" -#include "hal/gpio_ll.h" - -#if !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) - #define CONFIG_IDF_TARGET_ESP32 -#endif - -#ifndef VSPI - #define VSPI FSPI -#endif - -// Fix IDF problems with ESP32S3 -// Note illogical enumerations: FSPI_HOST=SPI2_HOST=1 HSPI_HOST=SPI3_HOST=2 -#if CONFIG_IDF_TARGET_ESP32S3 - // Fix ESP32C3 IDF bug for missing definition (FSPI only tested at the moment) - #ifndef REG_SPI_BASE // HSPI FSPI/VSPI - #define REG_SPI_BASE(i) (((i)>1) ? (DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE)) - #endif - - // Fix ESP32S3 IDF bug for name change - #ifndef SPI_MOSI_DLEN_REG - #define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) - #endif - -#endif - -// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled -#if !defined (SUPPORT_TRANSACTIONS) - #define SUPPORT_TRANSACTIONS -#endif - -/* -ESP32: -FSPI not defined -HSPI = 2, uses SPI2 -VSPI = 3, uses SPI3 - -ESP32-S2: -FSPI = 1, uses SPI2 -HSPI = 2, uses SPI3 -VSPI not defined - -ESP32 C3: -FSPI = 0, uses SPI2 ???? To be checked -HSPI = 1, uses SPI3 ???? To be checked -VSPI not defined - -For ESP32/S2/C3/S3: -SPI1_HOST = 0 -SPI2_HOST = 1 -SPI3_HOST = 2 -*/ - -// ESP32 specific SPI port selection -#ifdef USE_HSPI_PORT - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT HSPI //HSPI is port 2 on ESP32 - #else - #define SPI_PORT 3 //HSPI is port 3 on ESP32 S2 - #endif -#elif defined(USE_FSPI_PORT) - #define SPI_PORT 2 //FSPI(ESP32 S2) -#else - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT VSPI - #elif CONFIG_IDF_TARGET_ESP32S2 - #define SPI_PORT 2 //FSPI(ESP32 S2) - #elif CONFIG_IDF_TARGET_ESP32S3 - #define SPI_PORT FSPI - #endif -#endif - -#ifdef RPI_DISPLAY_TYPE - #define CMD_BITS (16-1) -#else - #define CMD_BITS (8-1) -#endif - -// Initialise processor specific SPI functions, used by init() -#define INIT_TFT_DATA_BUS // Not used - -// Define a generic flag for 8-bit parallel -#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility - #if !defined (TFT_PARALLEL_8_BIT) - #define TFT_PARALLEL_8_BIT // Generic parallel flag - #endif -#endif - -// Ensure ESP32 specific flag is defined for 8-bit parallel -#if defined (TFT_PARALLEL_8_BIT) - #if !defined (ESP32_PARALLEL) - #define ESP32_PARALLEL - #endif -#endif - -#if !defined(DISABLE_ALL_LIBRARY_WARNINGS) && defined (ESP32_PARALLEL) - #warning >>>>------>> DMA is not supported in parallel mode -#endif - -// Processor specific code used by SPI bus transaction startWrite and endWrite functions -#if !defined (ESP32_PARALLEL) - #define _spi_cmd (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)) - #define _spi_user (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)) - #define _spi_mosi_dlen (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)) - #define _spi_w (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)) - - #if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE - #else - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN - #endif -#else - // Not applicable to parallel bus - #define SET_BUS_WRITE_MODE - #define SET_BUS_READ_MODE -#endif - -// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions -#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER) - #define ESP32_DMA - // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK dmaWait() -#else - #define DMA_BUSY_CHECK -#endif - -#if defined(TFT_PARALLEL_8_BIT) - #define SPI_BUSY_CHECK -#else - #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) -#endif - -// If smooth font is used then it is likely SPIFFS will be needed -#ifdef SMOOTH_FONT - // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts - #define FS_NO_GLOBALS - #include - #include "SPIFFS.h" // ESP32 only - #define FONT_FS_AVAILABLE -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the DC (TFT Data/Command or Register Select (RS))pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_DC - #define DC_C // No macro allocated so it generates no code - #define DC_D // No macro allocated so it generates no code -#else - #if defined (TFT_PARALLEL_8_BIT) - // TFT_DC, by design, must be in range 0-31 for single register parallel write - #if (TFT_DC >= 0) && (TFT_DC < 32) - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts = (1 << TFT_DC) - #elif (TFT_DC >= 32) - #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC- 32)) - #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC- 32)) - #else - #define DC_C - #define DC_D - #endif - #else - #if (TFT_DC >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change - #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #else - #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #endif - #elif (TFT_DC >= 0) - #if defined (RPI_DISPLAY_TYPE) - #if defined (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) - #else - // 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) - #endif - #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 TFT_CS -1 // Keep DMA code happy - #define CS_L // No macro allocated so it generates no code - #define CS_H // No macro allocated so it generates no code -#else - #if defined (TFT_PARALLEL_8_BIT) - #if TFT_CS >= 32 - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #elif TFT_CS >= 0 - #define CS_L GPIO.out_w1tc = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts = (1 << TFT_CS) - #else - #define CS_L - #define CS_H - #endif - #else - #if (TFT_CS >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change - #define CS_L GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #else - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #endif - #elif (TFT_CS >= 0) - #ifdef RPI_DISPLAY_TYPE // RPi 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 -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_WR) - #if (TFT_WR >= 32) - // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 - #define WR_L GPIO.out1_w1tc.val = (1 << (TFT_WR - 32)) - #define WR_H GPIO.out1_w1ts.val = (1 << (TFT_WR - 32)) - #elif (TFT_WR >= 0) - // TFT_WR, for best performance, should be in range 0-31 for single register parallel write - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) - #else - #define WR_L - #define WR_H - #endif -#else - #define WR_L - #define WR_H -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the touch screen chip select pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TOUCH_CS - #define T_CS_L // No macro allocated so it generates no code - #define T_CS_H // No macro allocated so it generates no code -#else // XPT2046 is slow, so use slower digitalWrite here - #define T_CS_L digitalWrite(TOUCH_CS, LOW) - #define T_CS_H digitalWrite(TOUCH_CS, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Make sure SPI default pins are assigned if not specified by user or set to -1 -//////////////////////////////////////////////////////////////////////////////////////// -#if !defined (TFT_PARALLEL_8_BIT) - - #ifdef USE_HSPI_PORT - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 13 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 13 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 14 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 14 - #endif - - #else // VSPI port - - #ifndef TFT_MISO - #define TFT_MISO -1 - #endif - - #ifndef TFT_MOSI - #define TFT_MOSI 23 - #endif - #if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 23 - #endif - - #ifndef TFT_SCLK - #define TFT_SCLK 18 - #endif - #if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 18 - #endif - - #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) - #if (TFT_MISO == -1) - #undef TFT_MISO - #define TFT_MISO TFT_MOSI - #endif - #endif - - #endif - -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the parallel bus interface chip pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_PARALLEL_8_BIT) - - #if (TFT_D0 >= 32) // If D0 is a high GPIO assume all other data bits are high GPIO - #define MASK_OFFSET 32 - #define GPIO_CLR_REG GPIO.out1_w1tc.val - #define GPIO_SET_REG GPIO.out1_w1ts.val - #else - #define MASK_OFFSET 0 - #define GPIO_CLR_REG GPIO.out_w1tc - #define GPIO_SET_REG GPIO.out_w1ts - #endif - - // 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 PARALLEL_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-MASK_OFFSET)); \ - if ( c & 0x02 ) xset_mask[c] |= (1 << (TFT_D1-MASK_OFFSET)); \ - if ( c & 0x04 ) xset_mask[c] |= (1 << (TFT_D2-MASK_OFFSET)); \ - if ( c & 0x08 ) xset_mask[c] |= (1 << (TFT_D3-MASK_OFFSET)); \ - if ( c & 0x10 ) xset_mask[c] |= (1 << (TFT_D4-MASK_OFFSET)); \ - if ( c & 0x20 ) xset_mask[c] |= (1 << (TFT_D5-MASK_OFFSET)); \ - if ( c & 0x40 ) xset_mask[c] |= (1 << (TFT_D6-MASK_OFFSET)); \ - if ( c & 0x80 ) xset_mask[c] |= (1 << (TFT_D7-MASK_OFFSET)); \ - } \ - - // Mask for the 8 data bits to set pin directions - #define GPIO_DIR_MASK ((1 << (TFT_D0-MASK_OFFSET)) | (1 << (TFT_D1-MASK_OFFSET)) | (1 << (TFT_D2-MASK_OFFSET)) | (1 << (TFT_D3-MASK_OFFSET)) | (1 << (TFT_D4-MASK_OFFSET)) | (1 << (TFT_D5-MASK_OFFSET)) | (1 << (TFT_D6-MASK_OFFSET)) | (1 << (TFT_D7-MASK_OFFSET))) - - #if (TFT_WR >= 32) - #if (TFT_D0 >= 32) - // Data bits and the write line are cleared to 0 in one step (1.25x faster) - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << (TFT_WR-32))) - #elif (TFT_D0 >= 0) - // Data bits and the write line are cleared sequentially - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK); WR_L - #endif - #elif (TFT_WR >= 0) - #if (TFT_D0 >= 32) - // Data bits and the write line are cleared sequentially - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK); WR_L - #elif (TFT_D0 >= 0) - // Data bits and the write line are cleared to 0 in one step (1.25x faster) - #define GPIO_OUT_CLR_MASK (GPIO_DIR_MASK | (1 << TFT_WR)) - #endif - #else - #define GPIO_OUT_CLR_MASK - #endif - - // 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 = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \ - GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H - - // 18-bit color write with swapped bytes - #define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) - - #else - - #ifdef PSEUDO_16_BIT - // One write strobe for both bytes - #define tft_Write_16(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H - #define tft_Write_16S(C) GPIO.out_w1tc = GPIO_OUT_CLR_MASK; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H - #else - // Write 16 bits to TFT - #define tft_Write_16(C) GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H - - // 16-bit write with swapped bytes - #define tft_Write_16S(C) GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H - #endif - - #endif - - // Write 32 bits to TFT - #define tft_Write_32(C) GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 24)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 16)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H - - // Write two concatenated 16-bit values to TFT - #define tft_Write_32C(C,D) GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((D) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((D) >> 0)); WR_H - - // Write 16-bit value twice to TFT - used by drawPixel() - #define tft_Write_32D(C) GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 8)); WR_H; \ - GPIO_CLR_REG = GPIO_OUT_CLR_MASK; GPIO_SET_REG = set_mask((uint8_t) ((C) >> 0)); WR_H - - // Read pin - #ifdef TFT_RD - #if (TFT_RD >= 32) - #define RD_L GPIO.out1_w1tc.val = (1 << (TFT_RD - 32)) - #define RD_H GPIO.out1_w1ts.val = (1 << (TFT_RD - 32)) - #elif (TFT_RD >= 0) - #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) - #else - #define RD_L - #define RD_H - #endif - #else - #define TFT_RD -1 - #define RD_L - #define RD_H - #endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to a SPI ILI948x TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour - - // 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) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Convert swapped byte 16-bit colour to 18-bit and write in 3 bytes - #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ - spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ - spi.transfer(((C) & 0x1F00)>>5) - - // Write 32 bits to TFT - #define tft_Write_32(C) spi.write32(C) - - // Write two concatenated 16-bit values to TFT - #define tft_Write_32C(C,D) spi.write32((C)<<16 | (D)) - - // Write 16-bit value twice to TFT - #define tft_Write_32D(C) spi.write32((C)<<16 | (C)) - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to an Raspberry Pi TFT -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (RPI_DISPLAY_TYPE) - // ESP32-S3 low level SPI writes for 8, 16 and 32-bit values - // to avoid the function call overhead - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_UPDATE; \ - while (*_spi_cmd & SPI_UPDATE); \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #define tft_Write_16N(C) tft_Write_16(C) - - // Write 16 bits - #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) - - // 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 - #if !defined(CONFIG_IDF_TARGET_ESP32S3) - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - #else - #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ - *_spi_w = D; \ - *_spi_cmd = SPI_UPDATE; \ - while (*_spi_cmd & SPI_UPDATE); \ - *_spi_cmd = SPI_USR; \ - while (*_spi_cmd & SPI_USR); - #endif - // Write 8 bits - #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) - - // Write 16 bits with corrected endianness for 16-bit colours - #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) - - // Future option for transfer without wait - #if !defined(CONFIG_IDF_TARGET_ESP32S3) - #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ - *_spi_w = ((C)<<8 | (C)>>8); \ - *_spi_cmd = SPI_USR; - #else - #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ - *_spi_w = ((C)<<8 | (C)>>8); \ - *_spi_cmd = SPI_UPDATE; \ - while (*_spi_cmd & SPI_UPDATE); \ - *_spi_cmd = SPI_USR; - #endif - - // 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 - -#ifndef tft_Write_16N - #define tft_Write_16N tft_Write_16 -#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/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.c b/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.c deleted file mode 100644 index 1c2287b..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.c +++ /dev/null @@ -1,263 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI generic driver functions // - //////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////// -// Global variables -//////////////////////////////////////////////////////////////////////////////////////// - -// Select the SPI port to use -#ifdef TFT_SPI_PORT - SPIClass& spi = TFT_SPI_PORT; -#else - SPIClass& spi = SPI; -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: tft_Read_8 -** Description: Bit bashed SPI to read bidirectional SDA line -***************************************************************************************/ -uint8_t TFT_eSPI::tft_Read_8(void) -{ - uint8_t ret = 0; - - for (uint8_t i = 0; i < 8; i++) { // read results - ret <<= 1; - SCLK_L; - if (digitalRead(TFT_MOSI)) ret |= 1; - SCLK_H; - } - - return ret; -} - -/*************************************************************************************** -** Function name: beginSDA -** Description: Detach SPI from pin to permit software SPI -***************************************************************************************/ -void TFT_eSPI::begin_SDA_Read(void) -{ - // Release configured SPI port for SDA read - spi.end(); -} - -/*************************************************************************************** -** Function name: endSDA -** Description: Attach SPI pins after software SPI -***************************************************************************************/ -void TFT_eSPI::end_SDA_Read(void) -{ - // Configure SPI port ready for next TFT access - spi.begin(); -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // #if defined (TFT_SDA_READ) -//////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_PARALLEL_8_BIT) // Code for generic (i.e. any) processor -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for generic processor and parallel display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - while (len>1) {tft_Write_32D(color); len-=2;} - if (len) {tft_Write_16(color);} -} - -/*************************************************************************************** -** Function name: pushPixels - for gereric processor and parallel display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - if(_swapBytes) { - while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;} - if (len) {tft_Write_16(*data);} - return; - } - - while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;} - if (len) {tft_Write_16S(*data);} -} - -/*************************************************************************************** -** Function name: GPIO direction control - supports class functions -** Description: Set parallel bus to INPUT or OUTPUT -***************************************************************************************/ -void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) -{ - // mask is unused for generic processor - // Arduino native functions suited well to a generic driver - pinMode(TFT_D0, mode); - pinMode(TFT_D1, mode); - pinMode(TFT_D2, mode); - pinMode(TFT_D3, mode); - pinMode(TFT_D4, mode); - pinMode(TFT_D5, mode); - pinMode(TFT_D6, mode); - pinMode(TFT_D7, mode); - return; -} - -/*************************************************************************************** -** Function name: GPIO direction control - supports class functions -** Description: Faster GPIO pin input/output switch -***************************************************************************************/ -void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode) -{ - // No fast port based generic approach available -} - -/*************************************************************************************** -** Function name: read byte - supports class functions -** Description: Read a byte - parallel bus only -***************************************************************************************/ -uint8_t TFT_eSPI::readByte(void) -{ - uint8_t b = 0; - - busDir(0, INPUT); - digitalWrite(TFT_RD, LOW); - - b |= digitalRead(TFT_D0) << 0; - b |= digitalRead(TFT_D1) << 1; - b |= digitalRead(TFT_D2) << 2; - b |= digitalRead(TFT_D3) << 3; - b |= digitalRead(TFT_D4) << 4; - b |= digitalRead(TFT_D5) << 5; - b |= digitalRead(TFT_D6) << 6; - b |= digitalRead(TFT_D7) << 7; - - digitalWrite(TFT_RD, HIGH); - busDir(0, OUTPUT); - - return b; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 or STM32 RPi TFT -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - if(len) { tft_Write_16(color); len--; } - while(len--) {WR_L; WR_H;} -} - -/*************************************************************************************** -** Function name: pushPixels - for ESP32 or STM32 RPi TFT -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) -{ - uint16_t *data = (uint16_t*)data_in; - - if (_swapBytes) while ( len-- ) {tft_Write_16S(*data); data++;} - else while ( len-- ) {tft_Write_16(*data); data++;} -} - -//////////////////////////////////////////////////////////////////////////////////////// -#elif defined (SPI_18BIT_DRIVER) // SPI 18-bit colour -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for STM32 and 3 byte RGB display -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) -{ - // Split out the colours - uint8_t r = (color & 0xF800)>>8; - uint8_t g = (color & 0x07E0)>>3; - uint8_t b = (color & 0x001F)<<3; - - while ( len-- ) {tft_Write_8(r); tft_Write_8(g); tft_Write_8(b);} -} - -/*************************************************************************************** -** Function name: pushPixels - for STM32 and 3 byte RGB display -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - if (_swapBytes) { - while ( len-- ) { - uint16_t color = *data >> 8 | *data << 8; - tft_Write_8((color & 0xF800)>>8); - tft_Write_8((color & 0x07E0)>>3); - tft_Write_8((color & 0x001F)<<3); - data++; - } - } - else { - while ( len-- ) { - tft_Write_8((*data & 0xF800)>>8); - tft_Write_8((*data & 0x07E0)>>3); - tft_Write_8((*data & 0x001F)<<3); - data++; - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////// -#else // Standard SPI 16-bit colour TFT -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for STM32 -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - while ( len-- ) {tft_Write_16(color);} -} - -/*************************************************************************************** -** Function name: pushPixels - for STM32 -** Description: Write a sequence of pixels -***************************************************************************************/ -void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ - - uint16_t *data = (uint16_t*)data_in; - - if (_swapBytes) while ( len-- ) {tft_Write_16(*data); data++;} - else while ( len-- ) {tft_Write_16S(*data); data++;} -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of display interface specific functions -//////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////// -// DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -// Placeholder for DMA functions - -/* -Minimal function set to support DMA: - -bool TFT_eSPI::initDMA(void) -void TFT_eSPI::deInitDMA(void) -bool TFT_eSPI::dmaBusy(void) -void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image) - -*/ diff --git a/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.h b/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.h deleted file mode 100644 index df7981d..0000000 --- a/lib/TFT_eSPI/Processors/TFT_eSPI_Generic.h +++ /dev/null @@ -1,188 +0,0 @@ - //////////////////////////////////////////////////// - // TFT_eSPI generic driver functions // - //////////////////////////////////////////////////// - -// This is a generic driver for Arduino boards, it supports SPI interface displays -// 8-bit parallel interface to TFT is not supported for generic processors - -#ifndef _TFT_eSPI_GENERICH_ -#define _TFT_eSPI_GENERICH_ - -// Processor ID reported by getSetup() -#define PROCESSOR_ID 0x0000 - -// Include processor specific header -// None - -// Processor specific code used by SPI bus transaction startWrite and endWrite functions -#define SET_BUS_WRITE_MODE // Not used -#define SET_BUS_READ_MODE // Not used - -// Code to check if DMA is busy, used by SPI bus transaction startWrite and endWrite functions -#define DMA_BUSY_CHECK // Not used so leave blank - -// To be safe, SUPPORT_TRANSACTIONS is assumed mandatory -#if !defined (SUPPORT_TRANSACTIONS) - #define SUPPORT_TRANSACTIONS -#endif - -// Initialise processor specific SPI functions, used by init() -#define INIT_TFT_DATA_BUS - -// If smooth fonts are enabled the filing system may need to be loaded -#ifdef SMOOTH_FONT - // Call up the filing system for the anti-aliased fonts - //#define FS_NO_GLOBALS - //#include -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the DC (TFT Data/Command or Register Select (RS))pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_DC - #define DC_C // No macro allocated so it generates no code - #define DC_D // No macro allocated so it generates no code -#else - #define DC_C digitalWrite(TFT_DC, LOW) - #define DC_D digitalWrite(TFT_DC, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the CS (TFT chip select) pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_CS - #define CS_L // No macro allocated so it generates no code - #define CS_H // No macro allocated so it generates no code -#else - #define CS_L digitalWrite(TFT_CS, LOW) - #define CS_H digitalWrite(TFT_CS, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Make sure TFT_RD is defined if not used to avoid an error message -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_RD - #define TFT_RD -1 -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the WR (TFT Write) pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifdef TFT_WR - #define WR_L digitalWrite(TFT_WR, LOW) - #define WR_H digitalWrite(TFT_WR, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Define the touch screen chip select pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if !defined TOUCH_CS || (TOUCH_CS < 0) - #define T_CS_L // No macro allocated so it generates no code - #define T_CS_H // No macro allocated so it generates no code -#else - #define T_CS_L digitalWrite(TOUCH_CS, LOW) - #define T_CS_H digitalWrite(TOUCH_CS, HIGH) -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Make sure TFT_MISO is defined if not used to avoid an error message -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_MISO - #define TFT_MISO -1 -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to a SPI ILI948x TFT -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (SPI_18BIT_DRIVER) // SPI 18-bit colour - - // Write 8 bits to TFT - #define tft_Write_8(C) spi.transfer(C) - - // Convert 16-bit colour to 18-bit and write in 3 bytes - #define tft_Write_16(C) spi.transfer(((C) & 0xF800)>>8); \ - spi.transfer(((C) & 0x07E0)>>3); \ - spi.transfer(((C) & 0x001F)<<3) - - // Convert swapped byte 16-bit colour to 18-bit and write in 3 bytes - #define tft_Write_16S(C) spi.transfer((C) & 0xF8); \ - spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ - spi.transfer(((C) & 0x1F00)>>5) - // Write 32 bits to TFT - #define tft_Write_32(C) spi.transfer16((C)>>16); spi.transfer16((uint16_t)(C)) - - // Write two address coordinates - #define tft_Write_32C(C,D) spi.transfer16(C); spi.transfer16(D) - - // Write same value twice - #define tft_Write_32D(C) spi.transfer16(C); spi.transfer16(C) - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to write commands/pixel colour data to other displays -//////////////////////////////////////////////////////////////////////////////////////// -#else - #if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16-bit transfers - #define tft_Write_8(C) spi.transfer(C); spi.transfer(C) - #define tft_Write_16(C) spi.transfer((uint8_t)((C)>>8));spi.transfer((uint8_t)((C)>>0)) - #define tft_Write_16S(C) spi.transfer((uint8_t)((C)>>0));spi.transfer((uint8_t)((C)>>8)) - - #define tft_Write_32(C) \ - tft_Write_16((uint16_t) ((C)>>16)); \ - tft_Write_16((uint16_t) ((C)>>0)) - - #define tft_Write_32C(C,D) \ - spi.transfer(0); spi.transfer((C)>>8); \ - spi.transfer(0); spi.transfer((C)>>0); \ - spi.transfer(0); spi.transfer((D)>>8); \ - spi.transfer(0); spi.transfer((D)>>0) - - #define tft_Write_32D(C) \ - spi.transfer(0); spi.transfer((C)>>8); \ - spi.transfer(0); spi.transfer((C)>>0); \ - spi.transfer(0); spi.transfer((C)>>8); \ - spi.transfer(0); spi.transfer((C)>>0) - - #else - #ifdef __AVR__ // AVR processors do not have 16-bit transfer - #define tft_Write_8(C) {SPDR=(C); while (!(SPSR&_BV(SPIF)));} - #define tft_Write_16(C) tft_Write_8((uint8_t)((C)>>8));tft_Write_8((uint8_t)((C)>>0)) - #define tft_Write_16S(C) tft_Write_8((uint8_t)((C)>>0));tft_Write_8((uint8_t)((C)>>8)) - #else - #define tft_Write_8(C) spi.transfer(C) - #define tft_Write_16(C) spi.transfer16(C) - #define tft_Write_16S(C) spi.transfer16(((C)>>8) | ((C)<<8)) - #endif // AVR - - #define tft_Write_32(C) \ - tft_Write_16((uint16_t) ((C)>>16)); \ - tft_Write_16((uint16_t) ((C)>>0)) - - #define tft_Write_32C(C,D) \ - tft_Write_16((uint16_t) (C)); \ - tft_Write_16((uint16_t) (D)) - - #define tft_Write_32D(C) \ - tft_Write_16((uint16_t) (C)); \ - tft_Write_16((uint16_t) (C)) - #endif // RPI_DISPLAY_TYPE -#endif - -#ifndef tft_Write_16N - #define tft_Write_16N tft_Write_16 -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// Macros to read from display using SPI or software SPI -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) - // Use a bit banged function call for STM32 and bi-directional SDA pin - #define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(void); - #define SCLK_L digitalWrite(TFT_SCLK, LOW) - #define SCLK_H digitalWrite(TFT_SCLK, LOW) -#else - // Use a SPI read transfer - #define tft_Read_8() spi.transfer(0) -#endif - - -#endif // Header end diff --git a/lib/TFT_eSPI/Processors/pio_16bit_parallel.pio.h b/lib/TFT_eSPI/Processors/pio_16bit_parallel.pio.h deleted file mode 100644 index 655c1b1..0000000 --- a/lib/TFT_eSPI/Processors/pio_16bit_parallel.pio.h +++ /dev/null @@ -1,62 +0,0 @@ -// -------------------------------------------------- // -// This file is autogenerated by pioasm; do not edit! // -// 16-bit parallel // -// -------------------------------------------------- // - -#pragma once - -#if !PICO_NO_HARDWARE -#include "hardware/pio.h" -#endif - -// ------ // -// tft_io // -// ------ // - -#define tft_io_wrap_target 7 -#define tft_io_wrap 20 -#define tft_io_offset_block_fill 0u -#define tft_io_offset_start_8 7u -#define tft_io_offset_start_tx 7u -#define tft_io_offset_set_addr_window 10u - -static const uint16_t tft_io_program_instructions[] = { - 0x98a0, // 0: pull block side 1 - 0xa027, // 1: mov x, osr - 0x80a0, // 2: pull block - 0xa047, // 3: mov y, osr - 0xb8e1, // 4: mov osr, x side 1 - 0x7100, // 5: out pins, 32 side 0 [1] - 0x1884, // 6: jmp y--, 4 side 1 - // .wrap_target - 0x98a0, // 7: pull block side 1 - 0x7100, // 8: out pins, 32 side 0 [1] - 0x1807, // 9: jmp 7 side 1 - 0xf822, // 10: set x, 2 side 1 - 0xe000, // 11: set pins, 0 - 0x80a0, // 12: pull block - 0x7000, // 13: out pins, 32 side 0 - 0x0033, // 14: jmp !x, 19 - 0x98a0, // 15: pull block side 1 - 0xe001, // 16: set pins, 1 - 0x7108, // 17: out pins, 8 side 0 [1] - 0x19f1, // 18: jmp !osre, 17 side 1 [1] - 0x184b, // 19: jmp x--, 11 side 1 - 0xe001, // 20: set pins, 1 - // .wrap -}; - -#if !PICO_NO_HARDWARE -static const struct pio_program tft_io_program = { - .instructions = tft_io_program_instructions, - .length = 21, - .origin = -1, -}; - -static inline pio_sm_config tft_io_program_get_default_config(uint offset) { - pio_sm_config c = pio_get_default_sm_config(); - sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap); - sm_config_set_sideset(&c, 2, true, false); - return c; -} -#endif diff --git a/lib/TFT_eSPI/Processors/pio_8bit_parallel.pio.h b/lib/TFT_eSPI/Processors/pio_8bit_parallel.pio.h deleted file mode 100644 index b5d6a8c..0000000 --- a/lib/TFT_eSPI/Processors/pio_8bit_parallel.pio.h +++ /dev/null @@ -1,70 +0,0 @@ -// -------------------------------------------------- // -// This file is autogenerated by pioasm; do not edit! // -// 8-bit parallel // -// -------------------------------------------------- // - -#pragma once - -#if !PICO_NO_HARDWARE -#include "hardware/pio.h" -#endif - -// ------ // -// tft_io // -// ------ // - -#define tft_io_wrap_target 9 -#define tft_io_wrap 27 - -#define tft_io_offset_block_fill 0u -#define tft_io_offset_start_tx 9u -#define tft_io_offset_start_8 14u -#define tft_io_offset_set_addr_window 17u - -static const uint16_t tft_io_program_instructions[] = { - 0x98a0, // 0: pull block side 1 - 0xa027, // 1: mov x, osr - 0x80a0, // 2: pull block - 0xa047, // 3: mov y, osr - 0xb8e1, // 4: mov osr, x side 1 - 0x7118, // 5: out pins, 24 side 0 [1] - 0xb942, // 6: nop side 1 [1] - 0x7108, // 7: out pins, 8 side 0 [1] - 0x1884, // 8: jmp y--, 4 side 1 - // .wrap_target - 0x98a0, // 9: pull block side 1 - 0x7118, // 10: out pins, 24 side 0 [1] - 0xb942, // 11: nop side 1 [1] - 0x7108, // 12: out pins, 8 side 0 [1] - 0x1809, // 13: jmp 9 side 1 - 0x98a0, // 14: pull block side 1 - 0x7100, // 15: out pins, 32 side 0 [1] - 0x1809, // 16: jmp 9 side 1 - 0xf822, // 17: set x, 2 side 1 - 0xe000, // 18: set pins, 0 - 0x80a0, // 19: pull block - 0x7000, // 20: out pins, 32 side 0 - 0x003a, // 21: jmp !x, 26 - 0x98a0, // 22: pull block side 1 - 0xe001, // 23: set pins, 1 - 0x7108, // 24: out pins, 8 side 0 [1] - 0x19f8, // 25: jmp !osre, 24 side 1 [1] - 0x1852, // 26: jmp x--, 18 side 1 - 0xe001, // 27: set pins, 1 - // .wrap -}; - -#if !PICO_NO_HARDWARE -static const struct pio_program tft_io_program = { - .instructions = tft_io_program_instructions, - .length = 28, - .origin = -1, -}; - -static inline pio_sm_config tft_io_program_get_default_config(uint offset) { - pio_sm_config c = pio_get_default_sm_config(); - sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap); - sm_config_set_sideset(&c, 2, true, false); - return c; -} -#endif diff --git a/lib/TFT_eSPI/Processors/pio_8bit_parallel_18bpp.pio.h b/lib/TFT_eSPI/Processors/pio_8bit_parallel_18bpp.pio.h deleted file mode 100644 index b2aaff4..0000000 --- a/lib/TFT_eSPI/Processors/pio_8bit_parallel_18bpp.pio.h +++ /dev/null @@ -1,73 +0,0 @@ -// -------------------------------------------------- // -// This file is autogenerated by pioasm; do not edit! // -// -------------------------------------------------- // - -#pragma once - -#if !PICO_NO_HARDWARE -#include "hardware/pio.h" -#endif - -// ------ // -// tft_io // -// ------ // - -#define tft_io_wrap_target 11 -#define tft_io_wrap 31 - -#define tft_io_offset_block_fill 0u -#define tft_io_offset_start_tx 11u -#define tft_io_offset_start_8 18u -#define tft_io_offset_set_addr_window 21u - -static const uint16_t tft_io_program_instructions[] = { - 0x98a0, // 0: pull block side 1 - 0xa027, // 1: mov x, osr - 0x80a0, // 2: pull block - 0xa047, // 3: mov y, osr - 0xb8e1, // 4: mov osr, x side 1 - 0x7110, // 5: out pins, 16 side 0 [1] - 0xb942, // 6: nop side 1 [1] - 0x7108, // 7: out pins, 8 side 0 [1] - 0xb942, // 8: nop side 1 [1] - 0x7108, // 9: out pins, 8 side 0 [1] - 0x1884, // 10: jmp y--, 4 side 1 - // .wrap_target - 0x98a0, // 11: pull block side 1 - 0x7110, // 12: out pins, 16 side 0 [1] - 0xb942, // 13: nop side 1 [1] - 0x7108, // 14: out pins, 8 side 0 [1] - 0xb942, // 15: nop side 1 [1] - 0x7108, // 16: out pins, 8 side 0 [1] - 0x180b, // 17: jmp 11 side 1 - 0x98a0, // 18: pull block side 1 - 0x7100, // 19: out pins, 32 side 0 [1] - 0x180b, // 20: jmp 11 side 1 - 0xf822, // 21: set x, 2 side 1 - 0xe000, // 22: set pins, 0 - 0x80a0, // 23: pull block - 0x7000, // 24: out pins, 32 side 0 - 0x003e, // 25: jmp !x, 30 - 0x98a0, // 26: pull block side 1 - 0xe001, // 27: set pins, 1 - 0x7108, // 28: out pins, 8 side 0 [1] - 0x19fc, // 29: jmp !osre, 28 side 1 [1] - 0x1856, // 30: jmp x--, 22 side 1 - 0xe001, // 31: set pins, 1 - // .wrap -}; - -#if !PICO_NO_HARDWARE -static const struct pio_program tft_io_program = { - .instructions = tft_io_program_instructions, - .length = 32, - .origin = -1, -}; - -static inline pio_sm_config tft_io_program_get_default_config(uint offset) { - pio_sm_config c = pio_get_default_sm_config(); - sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap); - sm_config_set_sideset(&c, 2, true, false); - return c; -} -#endif diff --git a/lib/TFT_eSPI/Processors/pio_SPI.pio.h b/lib/TFT_eSPI/Processors/pio_SPI.pio.h deleted file mode 100644 index 0848529..0000000 --- a/lib/TFT_eSPI/Processors/pio_SPI.pio.h +++ /dev/null @@ -1,74 +0,0 @@ -// -------------------------------------------------- // -// This file is autogenerated by pioasm; do not edit! // -// 8 + 16-bit SPI - no auto colour conversion // -// -------------------------------------------------- // - -#pragma once - -#if !PICO_NO_HARDWARE -#include "hardware/pio.h" -#endif - -// ------ // -// tft_io // -// ------ // - -#define tft_io_wrap_target 27 -#define tft_io_wrap 31 - -#define tft_io_offset_start_8 0u -#define tft_io_offset_set_addr_window 3u -#define tft_io_offset_block_fill 17u -#define tft_io_offset_start_tx 27u - -static const uint16_t tft_io_program_instructions[] = { - 0x90a0, // 0: pull block side 0 - 0x6019, // 1: out pins, 25 - 0x181e, // 2: jmp 30 side 1 - 0xf022, // 3: set x, 2 side 0 - 0xe000, // 4: set pins, 0 - 0x90a0, // 5: pull block side 0 - 0x6019, // 6: out pins, 25 - 0xb842, // 7: nop side 1 - 0x7001, // 8: out pins, 1 side 0 - 0x18e8, // 9: jmp !osre, 8 side 1 - 0xf001, // 10: set pins, 1 side 0 - 0x003b, // 11: jmp !x, 27 - 0x80a0, // 12: pull block - 0x7001, // 13: out pins, 1 side 0 - 0x18ed, // 14: jmp !osre, 13 side 1 - 0x1044, // 15: jmp x--, 4 side 0 - 0x001b, // 16: jmp 27 - 0x90a0, // 17: pull block side 0 - 0xa027, // 18: mov x, osr - 0x80a0, // 19: pull block - 0xa047, // 20: mov y, osr - 0xb0e1, // 21: mov osr, x side 0 - 0x7011, // 22: out pins, 17 side 0 - 0xb842, // 23: nop side 1 - 0x7001, // 24: out pins, 1 side 0 - 0x18f8, // 25: jmp !osre, 24 side 1 - 0x1095, // 26: jmp y--, 21 side 0 - // .wrap_target - 0x90a0, // 27: pull block side 0 - 0x7011, // 28: out pins, 17 side 0 - 0xb842, // 29: nop side 1 - 0x7001, // 30: out pins, 1 side 0 - 0x18fe, // 31: jmp !osre, 30 side 1 - // .wrap -}; - -#if !PICO_NO_HARDWARE -static const struct pio_program tft_io_program = { - .instructions = tft_io_program_instructions, - .length = 32, - .origin = -1, -}; - -static inline pio_sm_config tft_io_program_get_default_config(uint offset) { - pio_sm_config c = pio_get_default_sm_config(); - sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap); - sm_config_set_sideset(&c, 2, true, false); - return c; -} -#endif diff --git a/lib/TFT_eSPI/Processors/pio_SPI_18bit.pio.h b/lib/TFT_eSPI/Processors/pio_SPI_18bit.pio.h deleted file mode 100644 index 09bbfeb..0000000 --- a/lib/TFT_eSPI/Processors/pio_SPI_18bit.pio.h +++ /dev/null @@ -1,74 +0,0 @@ -// -------------------------------------------------- // -// This file is autogenerated by pioasm; do not edit! // -// 8 + 18-bit SPI - no auto colour conversion // -// -------------------------------------------------- // - -#pragma once - -#if !PICO_NO_HARDWARE -#include "hardware/pio.h" -#endif - -// ------ // -// tft_io // -// ------ // - -#define tft_io_wrap_target 27 -#define tft_io_wrap 31 - -#define tft_io_offset_start_8 0u -#define tft_io_offset_set_addr_window 3u -#define tft_io_offset_block_fill 17u -#define tft_io_offset_start_tx 27u - -static const uint16_t tft_io_program_instructions[] = { - 0x90a0, // 0: pull block side 0 - 0x6019, // 1: out pins, 25 - 0x181e, // 2: jmp 30 side 1 - 0xf022, // 3: set x, 2 side 0 - 0xe000, // 4: set pins, 0 - 0x90a0, // 5: pull block side 0 - 0x6019, // 6: out pins, 25 - 0xb842, // 7: nop side 1 - 0x7001, // 8: out pins, 1 side 0 - 0x18e8, // 9: jmp !osre, 8 side 1 - 0xf001, // 10: set pins, 1 side 0 - 0x003b, // 11: jmp !x, 27 - 0x80a0, // 12: pull block - 0x7001, // 13: out pins, 1 side 0 - 0x18ed, // 14: jmp !osre, 13 side 1 - 0x1044, // 15: jmp x--, 4 side 0 - 0x001b, // 16: jmp 27 - 0x90a0, // 17: pull block side 0 - 0xa027, // 18: mov x, osr - 0x80a0, // 19: pull block - 0xa047, // 20: mov y, osr - 0xb0e1, // 21: mov osr, x side 0 - 0x7009, // 22: out pins, 9 side 0 - 0xb842, // 23: nop side 1 - 0x7001, // 24: out pins, 1 side 0 - 0x18f8, // 25: jmp !osre, 24 side 1 - 0x1095, // 26: jmp y--, 21 side 0 - // .wrap_target - 0x90a0, // 27: pull block side 0 - 0x7009, // 28: out pins, 9 side 0 - 0xb842, // 29: nop side 1 - 0x7001, // 30: out pins, 1 side 0 - 0x18fe, // 31: jmp !osre, 30 side 1 - // .wrap -}; - -#if !PICO_NO_HARDWARE -static const struct pio_program tft_io_program = { - .instructions = tft_io_program_instructions, - .length = 32, - .origin = -1, -}; - -static inline pio_sm_config tft_io_program_get_default_config(uint offset) { - pio_sm_config c = pio_get_default_sm_config(); - sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap); - sm_config_set_sideset(&c, 2, true, false); - return c; -} -#endif diff --git a/lib/TFT_eSPI/README.md b/lib/TFT_eSPI/README.md deleted file mode 100644 index 0c0c15b..0000000 --- a/lib/TFT_eSPI/README.md +++ /dev/null @@ -1,227 +0,0 @@ -A ["Discussions"](https://github.com/Bodmer/TFT_eSPI/discussions) facility has been added for Q&A etc. Use the ["Issues"](https://github.com/Bodmer/TFT_eSPI/issues) tab only for problems with the library. Thanks! -# News -1. The Create_font Processing sketch has been updated to automatically create a complete C header file. The automatic opening of the font folder can also be disabled within the Processing sketch. (Thanks to Pierre-Loup Martin). - -2. New board setup files have been added for the Seeed XIAO with round display, LilyGo T-Embed S3, LilyGo_T_QT_Pro_S3, ESP32 S3 Box and ESP32_S3_Box_Lite. The "RPi" interface style boards are now supported with the ESP32 S3. - -3. New functions have been added to draw smooth (antialiased) arcs, circles, and rounded rectangle outlines. New sketches are provided in the "Smooth Graphics" examples folder. Arcs can be drawn with or without anti-aliasing (which will then render faster). The arc ends can be straight or rounded. The arc drawing algorithm uses an optimised fixed point sqrt() function to improve performance on processors that do not have a hardware Floating Point Unit (e.g. RP2040). Here are two demo images, on the left smooth (anti-aliased) arcs with rounded ends, the image to the right is the same resolution (grabbed from the same 240x240 TFT) with the smoothing diasbled (no anti-aliasing): - - ![arcs](https://github.com/Bodmer/Github-images/blob/main/aa_arc_240x240.png) ![pixelated_arcs](https://github.com/Bodmer/Github-images/blob/main/no_aa_arc_240x240.png) - - Here the smooth arcs have been used to create anti-aliased meter gauges on a 320x240 TFT: - - ![arcs](https://github.com/Bodmer/Github-images/blob/main/xarc_meters_320x240.png) - -4. An excellent new compatible library is available which can render TrueType fonts on a TFT screen (or into a sprite). This has been developed by [takkaO](https://github.com/takkaO/OpenFontRender). The library provides access to compact font files, with fully scaleable anti-aliased glyphs. Left, middle and right justified text can also be printed to the screen. I have added TFT_eSPI specific examples to the OpenFontRender library and tested on RP2040 and ESP32 processors, the ESP8266 does not have sufficient RAM due to the glyph render complexity. Here is a demo screen where a single 12kbyte font file binary was used to render fully anti-aliased glyphs of gradually increasing size on a 320x480 TFT screen: - - ![ttf_font_demo](https://i.imgur.com/bKkilIb.png) - -5. New GUI examples have been added for sliders, buttons, graphs and meters. These examples require a new support library here: - - [TFT_eWidget](https://github.com/Bodmer/TFT_eWidget) - -6. Support has been added in v2.4.70 for the RP2040 with 16-bit parallel displays. This has been tested and the screen update performance is very good (4ms to clear 320 x 480 screen with HC8357C). The use of the RP2040 PIO makes it easy to change the write cycle timing for different displays. DMA with 16-bit transfers is also supported. - -7. Support for the ESP32-S2, ESP32-S3 and ESP32-C3 has been added (DMA only on ESP32 S3 at the moment). Tested with v2.0.3 RC1 of the ESP32 board package. Example setups: - - [Setup70_ESP32_S2_ILI9341.h](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70_ESP32_S2_ILI9341.h) - - [Setup70b_ESP32_S3_ILI9341.h](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70b_ESP32_S3_ILI9341.h) - - [Setup70c_ESP32_C3_ILI9341.h](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70c_ESP32_C3_ILI9341.h) - - [Setup70d_ILI9488_S3_Parallel.h](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70d_ILI9488_S3_Parallel.h) - -8. Smooth fonts can now be rendered direct to the TFT with very little flicker for quickly changing values. This is achieved by a line-by-line and block-by-block update of the glyph area without drawing pixels twice. This is a "breaking" change for some sketches because a new true/false parameter is needed to render the background. The default is false if the parameter is missing, Examples: - - tft.setTextColor(TFT_WHITE, TFT_BLUE, true); - spr.setTextColor(TFT_BLUE, TFT_BLACK, true); - -Note: background rendering for Smooth fonts is also now available when using the print stream e.g. with: tft.println("Hello World"); - -9. New anti-aliased graphics functions to draw lines, wedge shaped lines, circles and rounded rectangles. [Examples are included](https://github.com/Bodmer/TFT_eSPI/tree/master/examples/Smooth%20Graphics). Examples have also been added to [display PNG compressed images](https://github.com/Bodmer/TFT_eSPI/tree/master/examples/PNG%20Images) (note: requires ~40kbytes RAM). - -10. Users of PowerPoint experienced with running macros may be interested in the [pptm sketch generator here](https://github.com/Bodmer/PowerPoint_to_sketch), this converts graphics and tables drawn in PowerPoint slides into an Arduino sketch that renders the graphics on a 480x320 TFT. This is based on VB macros [created by Kris Kasprzak here](https://github.com/KrisKasprzak/Powerpoint-ILI9341_t3). - -11. The library contains two new functions for rectangles filled with a horizontal or vertical coloured gradient: - - tft.fillRectHGradient(x, y, w, h, color1, color2); - - tft.fillRectVGradient(x, y, w, h, color1, color2); - - ![Gradient](https://i.imgur.com/atR0DmP.png) - -12. The RP2040 8-bit parallel interface uses the PIO. The PIO now manages the "setWindow" and "block fill" actions, releasing the processor for other tasks when areas of the screen are being filled with a colour. The PIO can optionally be used for SPI interface displays if #define RP2040_PIO_SPI is put in the setup file. Touch screens and pixel read operations are not supported when the PIO interface is used. -The RP2040 PIO features only work with [Earle Philhower's board package](https://github.com/earlephilhower/arduino-pico), NOT the Arduino Mbed version. - -The use of PIO for SPI allows the RP2040 to be over-clocked (up to 250MHz works on my boards) in Earle's board package whilst still maintaining high SPI clock rates. - -# TFT_eSPI - -A feature rich Arduino IDE compatible graphics and fonts library for 32-bit processors. The library is targeted at 32-bit processors, it has been performance optimised for RP2040, STM32, ESP8266 and ESP32 types, other 32-bit processors may be used but will use the slower generic Arduino interface calls. The library can be loaded using the Arduino IDE's Library Manager. Direct Memory Access (DMA) can be used with the ESP32, RP2040 and STM32 processors with SPI interface displays to improve rendering performance. DMA with a parallel interface (8 and 16-bit) is only supported with the RP2040. - -The updates for the ESP32 S2/C3/S3 means that the library requires the ESP32 Arduino board package 2.x.x or later. - -The screen controller, interface pins and library configuration settings must be defined inside the library. They can NOT be defined in the Arduino sketch. See the User_Setup_Select.h file for details. This approach has significant advantages, it keeps the examples clean from long configuration options and once the setup is defined any example can be run without modification. PlatformIO users can define these settings on a per project basis within a platformio.ini file, see Docs folder in library. - -Lots of example sketches are provided which demonstrate using the functions in the library. Due to the popularity of the library there are lots of online tutorials for TFT_eSPI that have been created by enthusiastic users. - -Optimised drivers have been tested with the following processors: - -* RP2040, e.g. Raspberry Pi Pico -* ESP32 and ESP32-S2, ESP32-C3, ESP32-S3 -* ESP8266 -* STM32F1xx, STM32F2xx, STM32F4xx, STM32F767 (higher RAM processors recommended) - -The library supports the following interface types for these processors: - -| Processor | 4 wire SPI | 8-bit parallel | 16-bit parallel | DMA support | -|-----------| :---: | :---: | :---: | :---: | -| RP2040 | Yes | Yes | Yes | Yes (all) | -| ESP32 | Yes | Yes | No | Yes (SPI only) | -| ESP32 C3 | Yes | No | No | No | -| ESP32 S2 | Yes | No | No | No | -| ESP32 S3 | Yes | Yes | No | Yes (SPI only) | -| ESP8266 | Yes | No | No | No | -| STM32Fxxx | Yes | Yes | No | Yes (SPI only) | -| Other | Yes | No | No | No | - -For other (generic) processors only SPI interface displays are supported and the slower Arduino SPI library functions are used by the library. Higher clock speed processors such as used for the Teensy 3.x and 4.x boards will still provide a very good performance with the generic Arduino SPI functions. - -4 wire SPI means the display must have SPI interface comaptible signals and a "Data/Command" control signal, this signal line is sometimes labelled DC, RS or A0. - -Due to lack of GPIO pins the 8-bit parallel interface is NOT supported on the ESP8266. 8-bit parallel interface TFTs (e.g. UNO format mcufriend shields) can used with the STM32Fxxx Nucleo 64/144 range or the UNO format ESP32 (see below for ESP32). - -Support for the XPT2046 touch screen controller is built into the library and can be used with SPI interface displays. Third party touch support libraries are also available when using a display parallel interface. - -Displays using the following controllers are supported: - -* GC9A01 -* ILI9163 -* ILI9225 -* ILI9341 -* ILI9342 -* ILI9481 (DMA not supported with SPI) -* ILI9486 (DMA not supported with SPI) -* ILI9488 (DMA not supported with SPI) -* HX8357B (16-bit parallel tested with RP2040) -* HX8357C (16-bit parallel tested with RP2040) -* HX8357D -* R61581 -* RM68120 (support files added but untested) -* RM68140 -* S6D02A1 -* SSD1351 -* SSD1963 (this controller only has a parallel interface option) -* ST7735 -* ST7789 -* ST7796 - -ILI9341 and ST7796 SPI based displays are recommended as starting point for experimenting with this library. - -The library supports some 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. Note that due to design variations between these displays not all RPi displays will work with this library, so purchasing a RPi display of these types solely for use with this library is NOT recommended. - -A "good" RPi display is the [MHS-4.0 inch Display-B type ST7796](http://www.lcdwiki.com/MHS-4.0inch_Display-B) which provides good performance. This has a dedicated controller and can be clocked at up to 80MHz with the ESP32 (125MHz with overclocked RP2040, 55MHz with STM32 and 40MHz with ESP8266). The [MHS-3.5 inch RPi ILI9486](http://www.lcdwiki.com/MHS-3.5inch_RPi_Display) based display is also supported, however the MHS ILI9341 based display of the same type does NOT work with this library. - -Some displays permit the internal TFT screen RAM to be read, a few of the examples use this feature. The TFT_Screen_Capture example allows full screens to be captured and sent to a PC, this is handy to create program documentation. - -The library includes a "Sprite" class, this enables flicker free updates of complex graphics. Direct writes to the TFT with graphics functions are still available, so existing sketches do not need to be changed. - -# Sprites - -A Sprite is notionally an invisible graphics screen that is kept in the processors RAM. Graphics can be drawn into the Sprite just as they can be drawn directly to the screen. Once the Sprite is completed it can be plotted onto the screen in any position. If there is sufficient RAM then the Sprite can be the same size as the screen and used as a frame buffer. Sprites by default use 16-bit colours, the bit depth can be set to 8 bits (256 colours) , or 1 bit (any 2 colours) to reduce the RAM needed. On an ESP8266 the largest 16-bit colour Sprite that can be created is about 160x128 pixels, this consumes 40Kbytes of RAM. On an ESP32 the workspace RAM is more limited than the datasheet implies so a 16-bit colour Sprite is limited to about 200x200 pixels (~80Kbytes), an 8-bit sprite to 320x240 pixels (~76kbytes). A 1 bit per pixel Sprite requires only 9600 bytes for a full 320 x 240 screen buffer, this is ideal for supporting use with 2 colour bitmap fonts. - -One or more sprites can be created, a sprite can be any pixel width and height, limited only by available RAM. The RAM needed for a 16-bit colour depth Sprite is (2 x width x height) bytes, for a Sprite with 8-bit colour depth the RAM needed is (width x height) bytes. Sprites can be created and deleted dynamically as needed in the sketch, this means RAM can be freed up after the Sprite has been plotted on the screen, more RAM intensive WiFi based code can then be run and normal graphics operations still work. - -Drawing graphics into a sprite is very fast, for those familiar with the Adafruit "graphicstest" example, this whole test completes in 18ms in a 160x128 sprite. Examples of sprite use can be found in the "examples/Sprite" folder. - -Sprites can be plotted to the TFT with one colour being specified as "transparent", see Transparent_Sprite_Demo example. - -If an ESP32 board has SPIRAM (i.e. PSRAM) fitted then Sprites will use the PSRAM memory and large full screen buffer Sprites can be created. Full screen Sprites take longer to render (~45ms for a 320 x 240 16-bit Sprite), so bear that in mind. - -The "Animated_dial" example shows how dials can be created using a rotated Sprite for the needle. To run this example the TFT interface must support reading from the screen RAM (not all do). The dial rim and scale is a jpeg image, created using a paint program. - -![Animated_dial](https://i.imgur.com/S736Rg6.png) - - -# Touch controller support - -The XPT2046 touch screen controller is supported for SPI based displays only. The SPI bus for the touch controller is shared with the TFT and only an additional chip select line is needed. This support will eventually be deprecated when a suitable touch screen library is available. - -The Button class from Adafruit_GFX is incorporated, with the enhancement that the button labels can be in any font. - -# ESP8266 overlap mode - -The library supports SPI overlap on the ESP8266 so the TFT screen can share MOSI, MISO and SCLK pins with the program FLASH, this frees up GPIO pins for other uses. Only one SPI device can be connected to the FLASH pins and the chips select for the TFT must be on pin D3 (GPIO0). - - -# Fonts - -The library contains proportional fonts, different sizes can be enabled/disabled at compile time to optimise the use of FLASH memory. Anti-aliased (smooth) font files in vlw format stored in SPIFFS are supported. Any 16-bit Unicode character can be included and rendered, this means many language specific characters can be rendered to the screen. - -The library is based on the Adafruit GFX and Adafruit driver libraries and the aim is to retain compatibility. Significant additions have been made to the library to boost the speed for the different processors (it is typically 3 to 10 times faster) and to add new features. The new graphics functions include different size proportional fonts and formatting features. There are lots of example sketches to demonstrate the different features and included functions. - -Configuration of the library font selections, pins used to interface with the TFT and other features is made by editing the User_Setup.h file in the library folder, or by selecting your own configuration in the "User_Setup_Selet,h" file. Fonts and features can easily be enabled/disabled by commenting out lines. - - -# Anti-aliased Fonts - -Anti-aliased (smooth) font files in "vlw" format are generated by the free [Processing IDE](https://processing.org/) using a sketch included in the library Tools folder. This sketch with the Processing IDE can be used to generate font files from your computer's font set or any TrueType (.ttf) font, the font file can include **any** combination of 16-bit Unicode characters. This means Greek, Japanese and any other UCS-2 glyphs can be used. Character arrays and Strings in UTF-8 format are supported. - -The .vlw files must be uploaded to the processors FLASH filing system (SPIFFS, LittleFS or SD card) for use. Alternatively the .vlw files can be converted to C arrays (see "Smooth Font -> FLASH_Array" examples) and stored directly in FLASH as part of the compile process. The array based approach is convenient, provides performance improvements and is suitable where: either use of a filing system is undesirable, or the processor type (e.g. STM32) does not support a FLASH based filing system. - -Here is the Adafruit_GFX "FreeSans12pt" bitmap font compared to the same font drawn as anti-aliased: - -![Smooth_font](https://i.imgur.com/gAeDPFY.png) - -The smooth font example displays the following screen: - -![Example](https://i.imgur.com/xJF0Oz7.png) - -It would be possible to compress the vlw font files but the rendering performance to a TFT is still good when storing the font file(s) in SPIFFS, LittleFS or FLASH arrays. - -Here is an example screenshot showing the anti-aliased Hiragana character Unicode block (0x3041 to 0x309F) in 24pt from the Microsoft Yahei font: - -![Hiragana glyphs](https://i.imgur.com/jeXf2st.png) - -Anti-aliased fonts can also be drawn over a gradient background with a callback to fetch the background colour of each pixel. This pixel colour can be set by the gradient algorithm or by reading back the TFT screen memory (if reading the display is supported). - -Anti-aliased fonts cannot be scaled with setTextSize so you need to create a font for each size you need. See examples. - -# 8-bit parallel support - -The common 8-bit "Mcufriend" shields are supported for the STM Nucleo 64/144 boards and ESP32 UNO style board. The STM32 "Blue/Black Pill" boards can also be used with 8-bit parallel displays. - -The ESP32 board I have been using for testing has the following pinout: - -![Example](https://i.imgur.com/bvM6leE.jpg) - -UNO style boards with a Wemos R32(ESP32) label are also available at low cost with the same pinout. - -Unfortunately the typical UNO/mcufriend TFT display board maps LCD_RD, LCD_CS and LCD_RST signals to the ESP32 analogue pins 35, 34 and 36 which are input only. To solve this I linked in the 3 spare pins IO15, IO33 and IO32 by adding wires to the bottom of the board as follows: - -IO15 wired to IO35 - -IO33 wired to IO34 - -IO32 wired to IO36 - -This is an [example setup file](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup14_ILI9341_Parallel.h) with the correct GPIO for this UNO board. - -![Example](https://i.imgur.com/pUZn6lF.jpg) - -If the display board is fitted with a resistance based touch screen then this can be used by performing the modifications described here and the fork of the Adafruit library: -https://github.com/s60sc/Adafruit_TouchScreen - -# Tips -If you load a new copy of TFT_eSPI then it will overwrite your setups if they are kept within the TFT_eSPI folder. One way around this is to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file e.g.: -``` -#include <../TFT_eSPI_Setups/my_custom_setup.h> -``` -You must make sure only one setup file is called. In the custom setup file I add the file path as a commented out first line that can be cut and pasted back into the upgraded User_Setup_Select.h file. The ../ at the start of the path means go up one directory level. Clearly you could use different file paths or directory names as long as it does not clash with another library or folder name. - -You can take this one step further and have your own setup select file and then you only need to replace the Setup.h line reference in User_Setup_Select.h to, for example: -``` -#include <../TFT_eSPI_Setups/my_setup_select.h> -``` -To select a new setup you then edit your own my_setup_select.h file (which will not get overwritten during an upgrade). diff --git a/lib/TFT_eSPI/README.txt b/lib/TFT_eSPI/README.txt deleted file mode 100644 index 45eb4fb..0000000 --- a/lib/TFT_eSPI/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -This is a stand-alone library that contains both graphics functions -and the TFT chip driver library. It supports the ESP8266, ESP32, -STM32 and RP2040 processors with performance optimised code. Other -Arduino IDE compatible boards are also supported but the library -then uses generic functions which will be slower. The library uses -32-bit variables extensively so this will affect performance on 8 -and 16-bit processors. diff --git a/lib/TFT_eSPI/TFT_Drivers/EPD_Defines.h b/lib/TFT_eSPI/TFT_Drivers/EPD_Defines.h deleted file mode 100644 index 6a6838c..0000000 --- a/lib/TFT_eSPI/TFT_Drivers/EPD_Defines.h +++ /dev/null @@ -1,27 +0,0 @@ -// Null set for ePaper -#define TFT_WIDTH 1000 -#define TFT_HEIGHT 1000 - -#define TFT_INIT_DELAY 0 - -#define TFT_NOP 0x00 -#define TFT_SWRST 0x00 - -#define TFT_CASET 0x00 -#define TFT_PASET 0x00 -#define TFT_RAMWR 0x00 - -#define TFT_RAMRD 0x00 -#define TFT_IDXRD 0x00 - -#define TFT_MADCTL 0x00 -#define TFT_MAD_MY 0x00 -#define TFT_MAD_MX 0x00 -#define TFT_MAD_MV 0x00 -#define TFT_MAD_ML 0x00 -#define TFT_MAD_BGR 0x00 -#define TFT_MAD_MH 0x00 -#define TFT_MAD_RGB 0x00 - -#define TFT_INVOFF 0x00 -#define TFT_INVON 0x00 diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9341_Init.h b/lib/TFT_eSPI/TFT_Drivers/ILI9341_Init.h deleted file mode 100644 index 05a5dda..0000000 --- a/lib/TFT_eSPI/TFT_Drivers/ILI9341_Init.h +++ /dev/null @@ -1,248 +0,0 @@ - -// This is the command sequence that initialises the ILI9341 driver -// -// This setup information uses simple 8-bit SPI writecommand() and writedata() functions -// -// See ST7735_Setup.h file for an alternative format - -#if defined (ILI9341_DRIVER) || defined (ILI9342_DRIVER) -{ - writecommand(0xEF); - writedata(0x03); - writedata(0x80); - writedata(0x02); - - writecommand(0xCF); - writedata(0x00); - writedata(0XC1); - writedata(0X30); - - writecommand(0xED); - writedata(0x64); - writedata(0x03); - writedata(0X12); - writedata(0X81); - - writecommand(0xE8); - writedata(0x85); - writedata(0x00); - writedata(0x78); - - writecommand(0xCB); - writedata(0x39); - writedata(0x2C); - writedata(0x00); - writedata(0x34); - writedata(0x02); - - writecommand(0xF7); - writedata(0x20); - - writecommand(0xEA); - writedata(0x00); - writedata(0x00); - - writecommand(ILI9341_PWCTR1); //Power control - writedata(0x23); //VRH[5:0] - - writecommand(ILI9341_PWCTR2); //Power control - writedata(0x10); //SAP[2:0];BT[3:0] - - writecommand(ILI9341_VMCTR1); //VCM control - writedata(0x3e); - writedata(0x28); - - writecommand(ILI9341_VMCTR2); //VCM control2 - writedata(0x86); //-- - - writecommand(ILI9341_MADCTL); // Memory Access Control -#ifdef M5STACK - writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); // Rotation 0 (portrait mode) -#else - writedata(TFT_MAD_MX | TFT_MAD_COLOR_ORDER); // Rotation 0 (portrait mode) -#endif - - writecommand(ILI9341_PIXFMT); - writedata(0x55); - - writecommand(ILI9341_FRMCTR1); - writedata(0x00); - writedata(0x13); // 0x18 79Hz, 0x1B default 70Hz, 0x13 100Hz - - writecommand(ILI9341_DFUNCTR); // Display Function Control - writedata(0x08); - writedata(0x82); - writedata(0x27); - - writecommand(0xF2); // 3Gamma Function Disable - writedata(0x00); - - writecommand(ILI9341_GAMMASET); //Gamma curve selected - writedata(0x01); - - writecommand(ILI9341_GMCTRP1); //Set Gamma - writedata(0x0F); - writedata(0x31); - writedata(0x2B); - writedata(0x0C); - writedata(0x0E); - writedata(0x08); - writedata(0x4E); - writedata(0xF1); - writedata(0x37); - writedata(0x07); - writedata(0x10); - writedata(0x03); - writedata(0x0E); - writedata(0x09); - writedata(0x00); - - writecommand(ILI9341_GMCTRN1); //Set Gamma - writedata(0x00); - writedata(0x0E); - writedata(0x14); - writedata(0x03); - writedata(0x11); - writedata(0x07); - writedata(0x31); - writedata(0xC1); - writedata(0x48); - writedata(0x08); - writedata(0x0F); - writedata(0x0C); - writedata(0x31); - writedata(0x36); - writedata(0x0F); - - writecommand(ILI9341_SLPOUT); //Exit Sleep - - end_tft_write(); - delay(120); - begin_tft_write(); - - writecommand(ILI9341_DISPON); //Display on - -} - -#elif defined (ILI9341_2_DRIVER) // Alternative init sequence, see https://github.com/Bodmer/TFT_eSPI/issues/1172 - -{ -writecommand(0xCF); -writedata(0x00); -writedata(0XC1); -writedata(0X30); - -writecommand(0xED); -writedata(0x64); -writedata(0x03); -writedata(0X12); -writedata(0X81); - -writecommand(0xE8); -writedata(0x85); -writedata(0x00); -writedata(0x78); - -writecommand(0xCB); -writedata(0x39); -writedata(0x2C); -writedata(0x00); -writedata(0x34); -writedata(0x02); - -writecommand(0xF7); -writedata(0x20); - -writecommand(0xEA); -writedata(0x00); -writedata(0x00); - -writecommand(ILI9341_PWCTR1); //Power control -writedata(0x10); //VRH[5:0] - -writecommand(ILI9341_PWCTR2); //Power control -writedata(0x00); //SAP[2:0];BT[3:0] - -writecommand(ILI9341_VMCTR1); //VCM control -writedata(0x30); -writedata(0x30); - -writecommand(ILI9341_VMCTR2); //VCM control2 -writedata(0xB7); //-- - -writecommand(ILI9341_PIXFMT); -writedata(0x55); - -writecommand(0x36); // Memory Access Control -writedata(0x08); // Rotation 0 (portrait mode) - -writecommand(ILI9341_FRMCTR1); -writedata(0x00); -writedata(0x1A); - -writecommand(ILI9341_DFUNCTR); // Display Function Control -writedata(0x08); -writedata(0x82); -writedata(0x27); - -writecommand(0xF2); // 3Gamma Function Disable -writedata(0x00); - -writecommand(0x26); //Gamma curve selected -writedata(0x01); - -writecommand(0xE0); //Set Gamma -writedata(0x0F); -writedata(0x2A); -writedata(0x28); -writedata(0x08); -writedata(0x0E); -writedata(0x08); -writedata(0x54); -writedata(0xA9); -writedata(0x43); -writedata(0x0A); -writedata(0x0F); -writedata(0x00); -writedata(0x00); -writedata(0x00); -writedata(0x00); - -writecommand(0XE1); //Set Gamma -writedata(0x00); -writedata(0x15); -writedata(0x17); -writedata(0x07); -writedata(0x11); -writedata(0x06); -writedata(0x2B); -writedata(0x56); -writedata(0x3C); -writedata(0x05); -writedata(0x10); -writedata(0x0F); -writedata(0x3F); -writedata(0x3F); -writedata(0x0F); - -writecommand(0x2B); -writedata(0x00); -writedata(0x00); -writedata(0x01); -writedata(0x3f); - -writecommand(0x2A); -writedata(0x00); -writedata(0x00); -writedata(0x00); -writedata(0xef); - -writecommand(ILI9341_SLPOUT); //Exit Sleep - -end_tft_write(); -delay(120); -begin_tft_write(); - -writecommand(ILI9341_DISPON); //Display on -} -#endif \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Defines.h b/lib/TFT_eSPI/TFT_Drivers/ILI9481_Defines.h deleted file mode 100644 index bd5fb88..0000000 --- a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Defines.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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 - - -// Delay between some initialisation commands -#define TFT_INIT_DELAY 0x80 // Not used unless commandlist invoked - - -// Generic commands used by TFT_eSPI.cpp -#define TFT_NOP 0x00 -#define TFT_SWRST 0x01 - -#define TFT_SLPIN 0x10 -#define TFT_SLPOUT 0x11 - -#define TFT_INVOFF 0x20 -#define TFT_INVON 0x21 - -#define TFT_DISPOFF 0x28 -#define TFT_DISPON 0x29 - -#define TFT_CASET 0x2A -#define TFT_PASET 0x2B -#define TFT_RAMWR 0x2C - -#define TFT_RAMRD 0x2E - -#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_RGB 0x00 -#define TFT_MAD_BGR 0x08 -#define TFT_MAD_MH 0x04 -#define TFT_MAD_SS 0x02 -#define TFT_MAD_GS 0x01 - -#define TFT_IDXRD 0x00 // ILI9341 only, indexed control register read diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Init.h b/lib/TFT_eSPI/TFT_Drivers/ILI9481_Init.h deleted file mode 100644 index a5f19b8..0000000 --- a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Init.h +++ /dev/null @@ -1,736 +0,0 @@ - -// This is the command sequence that initialises the ILI9481 driver -// -// This setup information uses simple 8-bit SPI writecommand() and writedata() functions -// -// See ST7735_Setup.h file for an alternative format - -#define ILI9481_INIT_1 // Original default -//#define ILI9481_INIT_2 // CPT29 -//#define ILI9481_INIT_3 // PVI35 -//#define ILI9481_INIT_4 // AUO317 -//#define ILI9481_INIT_5 // CMO35 ***** -//#define ILI9481_INIT_6 // RGB -//#define ILI9481_INIT_7 // From #1774 -//#define ILI9481_INIT_8 // From #1774 - -///////////////////////////////////////////////////////////////////////////////////////// -#ifdef ILI9481_INIT_1 -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x42); - writedata(0x18); - - writecommand(0xD1); - writedata(0x00); - writedata(0x07); - writedata(0x10); - - writecommand(0xD2); - writedata(0x01); - writedata(0x02); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC8); - writedata(0x00); - writedata(0x32); - writedata(0x36); - writedata(0x45); - writedata(0x06); - writedata(0x16); - writedata(0x37); - writedata(0x75); - writedata(0x77); - writedata(0x54); - writedata(0x0C); - writedata(0x00); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// -#elif defined (ILI9481_INIT_2) -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x41); - writedata(0x1D); - - writecommand(0xD1); - writedata(0x00); - writedata(0x2B); - writedata(0x1F); - - writecommand(0xD2); - writedata(0x01); - writedata(0x11); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC8); - writedata(0x00); - writedata(0x14); - writedata(0x33); - writedata(0x10); - writedata(0x00); - writedata(0x16); - writedata(0x44); - writedata(0x36); - writedata(0x77); - writedata(0x00); - writedata(0x0F); - writedata(0x00); - - writecommand(0xB0); - writedata(0x00); - - writecommand(0xE4); - writedata(0xA0); - - writecommand(0xF0); - writedata(0x01); - - writecommand(0xF3); - writedata(0x02); - writedata(0x1A); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// -#elif defined (ILI9481_INIT_3) -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x41); - writedata(0x1D); - - writecommand(0xD1); - writedata(0x00); - writedata(0x2B); - writedata(0x1F); - - writecommand(0xD2); - writedata(0x01); - writedata(0x11); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC8); - writedata(0x00); - writedata(0x14); - writedata(0x33); - writedata(0x10); - writedata(0x00); - writedata(0x16); - writedata(0x44); - writedata(0x36); - writedata(0x77); - writedata(0x00); - writedata(0x0F); - writedata(0x00); - - writecommand(0xB0); - writedata(0x00); - - writecommand(0xE4); - writedata(0xA0); - - writecommand(0xF0); - writedata(0x01); - - writecommand(0xF3); - writedata(0x40); - writedata(0x0A); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// -#elif defined (ILI9481_INIT_4) -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x40); - writedata(0x1D); - - writecommand(0xD1); - writedata(0x00); - writedata(0x18); - writedata(0x13); - - writecommand(0xD2); - writedata(0x01); - writedata(0x11); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC8); - writedata(0x00); - writedata(0x44); - writedata(0x06); - writedata(0x44); - writedata(0x0A); - writedata(0x08); - writedata(0x17); - writedata(0x33); - writedata(0x77); - writedata(0x44); - writedata(0x08); - writedata(0x0C); - - writecommand(0xB0); - writedata(0x00); - - writecommand(0xE4); - writedata(0xA0); - - writecommand(0xF0); - writedata(0x01); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// -#elif defined (ILI9481_INIT_5) -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x41); - writedata(0x1D); - - writecommand(0xD1); - writedata(0x00); - writedata(0x1C); - writedata(0x1F); - - writecommand(0xD2); - writedata(0x01); - writedata(0x11); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC6); - writedata(0x83); - - writecommand(0xC8); - writedata(0x00); - writedata(0x26); - writedata(0x21); - writedata(0x00); - writedata(0x00); - writedata(0x1F); - writedata(0x65); - writedata(0x23); - writedata(0x77); - writedata(0x00); - writedata(0x0F); - writedata(0x00); - - writecommand(0xB0); - writedata(0x00); - - writecommand(0xE4); - writedata(0xA0); - - writecommand(0xF0); - writedata(0x01); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// -#elif defined (ILI9481_INIT_6) -// Configure ILI9481 display - - writecommand(TFT_SLPOUT); - delay(20); - - writecommand(0xD0); - writedata(0x07); - writedata(0x41); - writedata(0x1D); - - writecommand(0xD1); - writedata(0x00); - writedata(0x2B); - writedata(0x1F); - - writecommand(0xD2); - writedata(0x01); - writedata(0x11); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x11); - writedata(0x00); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC6); - writedata(0x80); - - writecommand(0xC8); - writedata(0x00); - writedata(0x14); - writedata(0x33); - writedata(0x10); - writedata(0x00); - writedata(0x16); - writedata(0x44); - writedata(0x36); - writedata(0x77); - writedata(0x00); - writedata(0x0F); - writedata(0x00); - - writecommand(0xB0); - writedata(0x00); - - writecommand(0xE4); - writedata(0xA0); - - writecommand(0xF0); - writedata(0x08); - - writecommand(0xF3); - writedata(0x40); - writedata(0x0A); - - writecommand(0xF6); - writedata(0x84); - - writecommand(0xF7); - writedata(0x80); - - writecommand(0xB3); - writedata(0x00); - writedata(0x01); - writedata(0x06); - writedata(0x30); - - writecommand(0xB4); - writedata(0x00); - - writecommand(0x0C); - writedata(0x00); - writedata(0x55); - - writecommand(TFT_MADCTL); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(TFT_CASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(TFT_PASET); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDF); - - delay(120); - writecommand(TFT_DISPON); - - delay(25); -// End of ILI9481 display configuration -///////////////////////////////////////////////////////////////////////////////////////// - - -// From #1774 -#elif defined (ILI9481_INIT_7) - ///ili9481+cmi3.5ips //效果不好 - //************* Start Initial Sequence **********// - writecommand(0x11); - delay(20); - writecommand(0xD0); - writedata(0x07); - writedata(0x42); - writedata(0x1B); - - writecommand(0xD1); - writedata(0x00); - writedata(0x14); - writedata(0x1B); - - writecommand(0xD2); - writedata(0x01); - writedata(0x12); - - writecommand(0xC0); - writedata(0x10); - writedata(0x3B); - writedata(0x00); - writedata(0x02); - writedata(0x01); - - writecommand(0xC5); - writedata(0x03); - - writecommand(0xC8); - writedata(0x00); - writedata(0x46); - writedata(0x44); - writedata(0x50); - writedata(0x04); - writedata(0x16); - writedata(0x33); - writedata(0x13); - writedata(0x77); - writedata(0x05); - writedata(0x0F); - writedata(0x00); - - writecommand(0x36); - writedata(0x0A); - - writecommand(0x3A); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if !defined (TFT_PARALLEL_8_BIT) && !defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(0x22); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); - - writecommand(0x2B); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xE0); - delay(120); - writecommand(0x29); - -#elif defined (ILI9481_INIT_8) - - //3.5IPS ILI9481+CMI - writecommand(0x01); //Soft_rese - delay(220); - - writecommand(0x11); - delay(280); - - writecommand(0xd0); //Power_Setting - writedata(0x07);//07 VC[2:0] Sets the ratio factor of Vci to generate the reference voltages Vci1 - writedata(0x44);//41 BT[2:0] Sets the Step up factor and output voltage level from the reference voltages Vci1 - writedata(0x1E);//1f 17 1C VRH[3:0]: Sets the factor to generate VREG1OUT from VCILVL - delay(220); - - writecommand(0xd1); //VCOM Control - writedata(0x00);//00 - writedata(0x0C);//1A VCM [6:0] is used to set factor to generate VCOMH voltage from the reference voltage VREG1OUT 15 09 - writedata(0x1A);//1F VDV[4:0] is used to set the VCOM alternating amplitude in the range of VREG1OUT x 0.70 to VREG1OUT 1F 18 - - writecommand(0xC5); //Frame Rate - writedata(0x03); // 03 02 - - writecommand(0xd2); //Power_Setting for Normal Mode - writedata(0x01); //01 - writedata(0x11); //11 - - writecommand(0xE4); //? - writedata(0xa0); - writecommand(0xf3); - writedata(0x00); - writedata(0x2a); - - //1 OK - writecommand(0xc8); - writedata(0x00); - writedata(0x26); - writedata(0x21); - writedata(0x00); - writedata(0x00); - writedata(0x1f); - writedata(0x65); - writedata(0x23); - writedata(0x77); - writedata(0x00); - writedata(0x0f); - writedata(0x00); - //GAMMA SETTING - - writecommand(0xC0); //Panel Driving Setting - writedata(0x00); //1//00 REV SM GS - writedata(0x3B); //2//NL[5:0]: Sets the number of lines to drive the LCD at an interval of 8 lines. - writedata(0x00); //3//SCN[6:0] - writedata(0x02); //4//PTV: Sets the Vcom output in non-display area drive period - writedata(0x11); //5//NDL: Sets the source output level in non-display area. PTG: Sets the scan mode in non-display area. - - writecommand(0xc6); //Interface Control - writedata(0x83); - //GAMMA SETTING - - writecommand(0xf0); //? - writedata(0x01); - - writecommand(0xE4);//? - writedata(0xa0); - - //////倒装设置 NG - writecommand(0x36); - writedata(0x0A); // 8C:出来两行 CA:出来一个点 - - writecommand(0x3a); - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) || defined (RPI_DISPLAY_TYPE) - writedata(0x55); // 16-bit colour interface - #else - writedata(0x66); // 18-bit colour interface - #endif - - #if defined (TFT_PARALLEL_8_BIT) || defined (TFT_PARALLEL_16_BIT) - writecommand(TFT_INVON); - #endif - - writecommand(0xb4);//Display Mode and Frame Memory Write Mode Setting - writedata(0x02); - writedata(0x00); //? - writedata(0x00); - writedata(0x01); - - delay(280); - - writecommand(0x2a); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0x3F); //3F - - writecommand(0x2b); - writedata(0x00); - writedata(0x00); - writedata(0x01); - writedata(0xDf); //DF - - //writecommand(0x21); - writecommand(0x29); - writecommand(0x2c); - -#endif \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Rotation.h b/lib/TFT_eSPI/TFT_Drivers/ILI9481_Rotation.h deleted file mode 100644 index e80d08e..0000000 --- a/lib/TFT_eSPI/TFT_Drivers/ILI9481_Rotation.h +++ /dev/null @@ -1,27 +0,0 @@ - // This is the command sequence that rotates the ILI9481 driver coordinate frame - - writecommand(TFT_MADCTL); - rotation = m % 4; - switch (rotation) { - case 0: // Portrait - writedata(TFT_MAD_BGR | TFT_MAD_SS); - _width = TFT_WIDTH; - _height = TFT_HEIGHT; - break; - case 1: // Landscape (Portrait + 90) - writedata(TFT_MAD_MV | TFT_MAD_BGR); - _width = TFT_HEIGHT; - _height = TFT_WIDTH; - break; - case 2: // Inverter portrait - writedata(TFT_MAD_BGR | TFT_MAD_GS); - _width = TFT_WIDTH; - _height = TFT_HEIGHT; - break; - case 3: // Inverted landscape - writedata(TFT_MAD_MV | TFT_MAD_BGR | TFT_MAD_SS | TFT_MAD_GS); - _width = TFT_HEIGHT; - _height = TFT_WIDTH; - break; - } - \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_config.h b/lib/TFT_eSPI/TFT_config.h deleted file mode 100644 index a5c7090..0000000 --- a/lib/TFT_eSPI/TFT_config.h +++ /dev/null @@ -1,320 +0,0 @@ - -/////////////////////////////////////////////////////////// -/* Support file for ESP32 IDF use */ -/* See library docs folder */ -/* */ -/* DO NOT EDIT THIS FILE */ -/* */ -/////////////////////////////////////////////////////////// - -/** - * @file TFT_config.h - * @author Ricard Bitriá Ribes (https://github.com/dracir9) - * Created Date: 22-01-2022 - * ----- - * Last Modified: 25-02-2023 - * Modified By: Ricard Bitriá Ribes - * ----- - * @copyright (c) 2022 Ricard Bitriá Ribes - */ - -#ifndef TFT_CONFIG_H -#define TFT_CONFIG_H - -#include "sdkconfig.h" - -/*************************************************************************************** -** Others -***************************************************************************************/ - -#ifdef CONFIG_DISABLE_WARNINGS - #define DISABLE_ALL_LIBRARY_WARNINGS -#endif - -/*************************************************************************************** -** TFT_eSPI Configuration defines -***************************************************************************************/ -// Override defaults -#define USER_SETUP_LOADED - -/*************************************************************************************** -** Section 1: Load TFT driver -***************************************************************************************/ -#if defined (CONFIG_TFT_ILI9341_DRIVER) - #define ILI9341_DRIVER -#elif defined (CONFIG_TFT_ILI9341_2_DRIVER) - #define ILI9341_2_DRIVER -#elif defined (CONFIG_TFT_ST7735_DRIVER) - #define ST7735_DRIVER -#elif defined (CONFIG_TFT_ILI9163_DRIVER) - #define ILI9163_DRIVER -#elif defined (CONFIG_TFT_S6D02A1_DRIVER) - #define S6D02A1_DRIVER -#elif defined (CONFIG_TFT_HX8357D_DRIVER) - #define HX8357D_DRIVER -#elif defined (CONFIG_TFT_ILI9481_DRIVER) - #define ILI9481_DRIVER -#elif defined (CONFIG_TFT_ILI9486_DRIVER) - #define ILI9486_DRIVER -#elif defined (CONFIG_TFT_ILI9488_DRIVER) - #define ILI9488_DRIVER -#elif defined (CONFIG_TFT_ST7789_DRIVER) - #define ST7789_DRIVER -#elif defined (CONFIG_TFT_ST7789_2_DRIVER) - #define ST7789_2_DRIVER -#elif defined (CONFIG_TFT_R61581_DRIVER) - #define R61581_DRIVER -#elif defined (CONFIG_TFT_RM68140_DRIVER) - #define RM68140_DRIVER -#elif defined (CONFIG_TFT_ST7796_DRIVER) - #define ST7796_DRIVER -#elif defined (CONFIG_TFT_SSD1351_DRIVER) - #define SSD1351_DRIVER -#elif defined (CONFIG_TFT_SSD1963_480_DRIVER) - #define SSD1963_480_DRIVER -#elif defined (CONFIG_TFT_SSD1963_800_DRIVER) - #define SSD1963_800_DRIVER -#elif defined (CONFIG_TFT_SSD1963_800ALT_DRIVER) - #define SSD1963_800ALT_DRIVER -#elif defined (CONFIG_TFT_ILI9225_DRIVER) - #define ILI9225_DRIVER -#elif defined (CONFIG_TFT_GC9A01_DRIVER) - #define GC9A01_DRIVER -#endif - -#ifdef CONFIG_TFT_RGB_ORDER - #define TFT_RGB_ORDER TFT_RGB -#endif - -#ifdef CONFIG_TFT_BGR_ORDER - #define TFT_RGB_ORDER TFT_BGR -#endif - -#ifdef CONFIG_TFT_M5STACK - #define M5STACK -#endif - -#ifdef CONFIG_TFT_WIDTH - #define TFT_WIDTH CONFIG_TFT_WIDTH -#endif - -#ifdef CONFIG_TFT_HEIGHT - #define TFT_HEIGHT CONFIG_TFT_HEIGHT -#endif - -#if defined (CONFIG_TFT_ST7735_INITB) - #define ST7735_INITB -#elif defined (CONFIG_TFT_ST7735_GREENTAB) - #define ST7735_GREENTAB -#elif defined (CONFIG_TFT_ST7735_GREENTAB2) - #define ST7735_GREENTAB2 -#elif defined (CONFIG_TFT_ST7735_GREENTAB3) - #define ST7735_GREENTAB3 -#elif defined (CONFIG_TFT_ST7735_GREENTAB128) - #define ST7735_GREENTAB128 -#elif defined (CONFIG_TFT_ST7735_GREENTAB160x80) - #define ST7735_GREENTAB160x80 -#elif defined (CONFIG_TFT_ST7735_REDTAB) - #define ST7735_REDTAB -#elif defined (CONFIG_TFT_ST7735_BLACKTAB) - #define ST7735_BLACKTAB -#elif defined (CONFIG_TFT_ST7735_REDTAB160x80) - #define ST7735_REDTAB160x80 -#endif - -#if defined (CONFIG_TFT_INVERSION_ON) - #define TFT_INVERSION_ON -#elif defined (CONFIG_TFT_INVERSION_OFF) - #define TFT_INVERSION_OFF -#endif - -/*************************************************************************************** -** Section 2: General Pin configuration -***************************************************************************************/ -// General pins -#if CONFIG_TFT_CS == -1 - #error "Invalid Chip Select pin. Check TFT_eSPI configuration" -#else - #define TFT_CS CONFIG_TFT_CS -#endif - -#if CONFIG_TFT_DC == -1 - #error "Invalid Data/Command pin. Check TFT_eSPI configuration" -#else - #define TFT_DC CONFIG_TFT_DC -#endif - -#if CONFIG_TFT_RST == -1 - #if !defined(DISABLE_ALL_LIBRARY_WARNINGS) - #warning "Invalid Reset pin. Check TFT_eSPI configuration" - #endif -#else - #define TFT_RST CONFIG_TFT_RST -#endif - -// Backlight config -#ifdef CONFIG_ENABLE_BL - #if CONFIG_TFT_BL == -1 - #error "Invalid backlight control pin. Check TFT_eSPI configuration" - #else - #define TFT_BL CONFIG_TFT_BL - #endif - - #define TFT_BACKLIGHT_ON CONFIG_TFT_BACKLIGHT_ON -#endif - - -/*************************************************************************************** -** Section 3: Data bus Pin configuration -***************************************************************************************/ - -// 8 BIT PARALLEL BUS -#ifdef CONFIG_TFT_PARALLEL_8_BIT - - #define TFT_PARALLEL_8_BIT - - #if CONFIG_TFT_D0 == -1 - #error "Invalid Data 0 pin. Check TFT_eSPI configuration" - #else - #define TFT_D0 CONFIG_TFT_D0 - #endif - - #if CONFIG_TFT_D1 == -1 - #error "Invalid Data 1 pin. Check TFT_eSPI configuration" - #else - #define TFT_D1 CONFIG_TFT_D1 - #endif - - #if CONFIG_TFT_D2 == -1 - #error "Invalid Data 2 pin. Check TFT_eSPI configuration" - #else - #define TFT_D2 CONFIG_TFT_D2 - #endif - - #if CONFIG_TFT_D3 == -1 - #error "Invalid Data 3 pin. Check TFT_eSPI configuration" - #else - #define TFT_D3 CONFIG_TFT_D3 - #endif - - #if CONFIG_TFT_D4 == -1 - #error "Invalid Data 4 pin. Check TFT_eSPI configuration" - #else - #define TFT_D4 CONFIG_TFT_D4 - #endif - - #if CONFIG_TFT_D5 == -1 - #error "Invalid Data 5 pin. Check TFT_eSPI configuration" - #else - #define TFT_D5 CONFIG_TFT_D5 - #endif - - #if CONFIG_TFT_D6 == -1 - #error "Invalid Data 6 pin. Check TFT_eSPI configuration" - #else - #define TFT_D6 CONFIG_TFT_D6 - #endif - - #if CONFIG_TFT_D7 == -1 - #error "Invalid Data 7 pin. Check TFT_eSPI configuration" - #else - #define TFT_D7 CONFIG_TFT_D7 - #endif - - #if CONFIG_TFT_WR == -1 - #error "Invalid Write strobe pin. Check TFT_eSPI configuration" - #else - #define TFT_WR CONFIG_TFT_WR - #endif - - #if CONFIG_TFT_RD == -1 - #error "Invalid Read strobe pin. Check TFT_eSPI configuration" - #else - #define TFT_RD CONFIG_TFT_RD - #endif - -// SPI BUS -#else - #if CONFIG_TFT_HSPI_PORT - #define USE_HSPI_PORT - #endif - - #if CONFIG_TFT_MISO != -1 - #define TFT_MISO CONFIG_TFT_MISO - #endif - - #if CONFIG_TFT_MOSI == -1 - #error "Invalid MOSI pin. Check TFT_eSPI configuration" - #else - #define TFT_MOSI CONFIG_TFT_MOSI - #endif - - #if CONFIG_TFT_SCLK == -1 - #error "Invalid Clock pin. Check TFT_eSPI configuration" - #else - #define TFT_SCLK CONFIG_TFT_SCLK - #endif - - #define SPI_FREQUENCY CONFIG_TFT_SPI_FREQUENCY - - #if CONFIG_TFT_SPI_READ_FREQ != -1 - #define SPI_READ_FREQUENCY CONFIG_TFT_SPI_READ_FREQ - #endif - - #ifdef CONFIG_TFT_SDA_READ - #define TFT_SDA_READ - #endif -#endif - - -/*************************************************************************************** -** Section 4: Setup Fonts -***************************************************************************************/ - -#ifdef CONFIG_TFT_LOAD_GLCD - #define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH -#endif - -#ifdef CONFIG_TFT_LOAD_FONT2 - #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters -#endif - -#ifdef CONFIG_TFT_LOAD_FONT4 - #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters -#endif - -#ifdef CONFIG_TFT_LOAD_FONT6 - #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm -#endif - -#ifdef CONFIG_TFT_LOAD_FONT7 - #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. -#endif - -#ifdef CONFIG_TFT_LOAD_FONT8 - #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. -#endif - -#ifdef CONFIG_TFT_LOAD_GFXFF - #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts -#endif - -#if CONFIG_TFT_SMOOTH_FONT - #define SMOOTH_FONT -#endif - -/*************************************************************************************** -** Section 5: Touchscreen configuration -***************************************************************************************/ - -#ifdef CONFIG_ENABLE_TOUCH - #if CONFIG_TOUCH_CS == -1 - #error "Invalid Touch Chip Select pin. Check TFT_eSPI configuration" - #else - #define TOUCH_CS CONFIG_TOUCH_CS - #endif - - #define SPI_TOUCH_FREQUENCY CONFIG_SPI_TOUCH_FREQUENCY -#endif - -#endif // TFT_CONFIG_H diff --git a/lib/TFT_eSPI/TFT_eSPI.cpp b/lib/TFT_eSPI/TFT_eSPI.cpp index 3dc98a0..837db3a 100644 --- a/lib/TFT_eSPI/TFT_eSPI.cpp +++ b/lib/TFT_eSPI/TFT_eSPI.cpp @@ -1,32 +1,600 @@ -/*************************************************** - Arduino TFT graphics library targeted at 32-bit - processors such as ESP32, ESP8266 and STM32. - - This is a stand-alone library that contains the - hardware driver, the graphics functions and the - proportional fonts. - - The larger fonts are Run Length Encoded to reduce their - size. - - Created by Bodmer 2/12/16 - Last update by Bodmer 20/03/20 - ****************************************************/ - #include "TFT_eSPI.h" +#include +#include -#if defined (ESP32) - #if defined(CONFIG_IDF_TARGET_ESP32S3) - #include "Processors/TFT_eSPI_ESP32_S3.c" // Tested with SPI and 8-bit parallel - #elif defined(CONFIG_IDF_TARGET_ESP32C3) - #include "Processors/TFT_eSPI_ESP32_C3.c" // Tested with SPI (8-bit parallel will probably work too!) +#if !defined (TFT_PARALLEL_8_BIT) + #ifdef CONFIG_IDF_TARGET_ESP32 + SPIClass spi = SPIClass(VSPI); #else - #include "Processors/TFT_eSPI_ESP32.c" + SPIClass& spi = SPI; #endif -#else - #include "Processors/TFT_eSPI_Generic.c" #endif +#ifdef ESP32_DMA + // DMA SPA handle + spi_device_handle_t dmaHAL; + #ifdef CONFIG_IDF_TARGET_ESP32 + #define DMA_CHANNEL 1 + #ifdef USE_HSPI_PORT + spi_host_device_t spi_host = HSPI_HOST; + #elif defined(USE_FSPI_PORT) + spi_host_device_t spi_host = SPI_HOST; + #else // use VSPI port + spi_host_device_t spi_host = VSPI_HOST; + #endif + #else + #ifdef USE_HSPI_PORT + #define DMA_CHANNEL SPI_DMA_CH_AUTO + spi_host_device_t spi_host = (spi_host_device_t) SPI3_HOST; // Draws once then freezes + #else // use FSPI port + #define DMA_CHANNEL SPI_DMA_CH_AUTO + spi_host_device_t spi_host = (spi_host_device_t) SPI2_HOST; // Draws once then freezes + #endif + #endif +#endif + +#if !defined (TFT_PARALLEL_8_BIT) + // Volatile for register reads: + volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); + volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); + // Register writes only: + volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); + volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: beginSDA - VSPI port only, FPSI port only for S2 +** Description: Detach MOSI and attach MISO to SDA for reads +***************************************************************************************/ +void TFT_eSPI::begin_SDA_Read(void) +{ + gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_INPUT); + #ifdef CONFIG_IDF_TARGET_ESP32 + pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false); + #else // S2 + pinMatrixInAttach(TFT_MOSI, FSPIQ_IN_IDX, false); + #endif + SET_BUS_READ_MODE; +} + +/*************************************************************************************** +** Function name: endSDA - VSPI port only, FPSI port only for S2 +** Description: Attach MOSI to SDA and detach MISO for writes +***************************************************************************************/ +void TFT_eSPI::end_SDA_Read(void) +{ + gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_OUTPUT); + #ifdef CONFIG_IDF_TARGET_ESP32 + pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false); + #else // S2 + pinMatrixOutAttach(TFT_MOSI, FSPID_OUT_IDX, false, false); + #endif + SET_BUS_WRITE_MODE; +} + +//////////////////////////////////////////////////////////////////////////////////////// +#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; + return b; +} + +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** 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); + bool empty = true; + volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; + if (len > 31) + { + *_spi_mosi_dlen = 511; + spi_w[0] = color32; + spi_w[1] = color32; + spi_w[2] = color32; + spi_w[3] = color32; + spi_w[4] = color32; + spi_w[5] = color32; + spi_w[6] = color32; + spi_w[7] = color32; + spi_w[8] = color32; + spi_w[9] = color32; + spi_w[10] = color32; + spi_w[11] = color32; + spi_w[12] = color32; + spi_w[13] = color32; + spi_w[14] = color32; + spi_w[15] = color32; + while(len>31) + { + while ((*_spi_cmd)&SPI_USR); + *_spi_cmd = SPI_USR; + len -= 32; + } + empty = false; + } + + if (len) + { + if(empty) { + for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; + } + len = (len << 4) - 1; + while (*_spi_cmd&SPI_USR); + *_spi_mosi_dlen = len; + *_spi_cmd = SPI_USR; + } + while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? +} +//*/ +//* +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + volatile uint32_t* spi_w = _spi_w; + uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); + uint32_t i = 0; + uint32_t rem = len & 0x1F; + len = len - rem; + + // Start with partial buffer pixels + if (rem) + { + while (*_spi_cmd&SPI_USR); + for (i=0; i < rem; i+=2) *spi_w++ = color32; + *_spi_mosi_dlen = (rem << 4) - 1; + *_spi_cmd = SPI_USR; + if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } + i = i>>1; while(i++<16) *spi_w++ = color32; + } + + while (*_spi_cmd&SPI_USR); + if (!rem) while (i++<16) *spi_w++ = color32; + *_spi_mosi_dlen = 511; + + // End with full buffer to maximise useful time for downstream code + while(len) + { + while (*_spi_cmd&SPI_USR); + *_spi_cmd = SPI_USR; + len -= 32; + } + + // Do not wait here + //while (*_spi_cmd&SPI_USR); +} +//*/ +/*************************************************************************************** +** Function name: pushSwapBytePixels - for ESP32 +** Description: Write a sequence of pixels with swapped bytes +***************************************************************************************/ +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); +} +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: dmaBusy +** Description: Check if DMA is busy +***************************************************************************************/ +bool TFT_eSPI::dmaBusy(void) +{ + if (!DMA_Enabled || !spiBusyCheck) return false; + + spi_transaction_t *rtrans; + esp_err_t ret; + uint8_t checks = spiBusyCheck; + for (int i = 0; i < checks; ++i) + { + ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0); + if (ret == ESP_OK) spiBusyCheck--; + } + + //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); + if (spiBusyCheck ==0) return false; + return true; +} + + +/*************************************************************************************** +** Function name: dmaWait +** Description: Wait until DMA is over (blocking!) +***************************************************************************************/ +void TFT_eSPI::dmaWait(void) +{ + if (!DMA_Enabled || !spiBusyCheck) return; + spi_transaction_t *rtrans; + esp_err_t ret; + for (int i = 0; i < spiBusyCheck; ++i) + { + ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); + assert(ret == ESP_OK); + } + spiBusyCheck = 0; +} + + +/*************************************************************************************** +** Function name: pushPixelsDMA +** Description: Push pixels to TFT (len must be less than 32767) +***************************************************************************************/ +// This will byte swap the original image if setSwapBytes(true) was called by sketch. +void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) +{ + if ((len == 0) || (!DMA_Enabled)) return; + + dmaWait(); + + if(_swapBytes) { + for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); + } + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = image; //finally send the line data + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + + +/*************************************************************************************** +** Function name: pushImageDMA +** Description: Push image to a window (w*h must be less than 65536) +***************************************************************************************/ +// Fixed const data assumed, will NOT clip or swap bytes +void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) +{ + if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; + + uint32_t len = w*h; + + dmaWait(); + + setAddrWindow(x, y, w, h); + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = image; //Data pointer + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + + +/*************************************************************************************** +** Function name: pushImageDMA +** Description: Push image to a window (w*h must be less than 65536) +***************************************************************************************/ +// This will clip and also swap bytes if setSwapBytes(true) was called by sketch +void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) +{ + if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; + + int32_t dx = 0; + int32_t dy = 0; + int32_t dw = w; + int32_t dh = h; + + if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } + if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } + + if ((x + dw) > _vpW ) dw = _vpW - x; + if ((y + dh) > _vpH ) dh = _vpH - y; + + if (dw < 1 || dh < 1) return; + + uint32_t len = dw*dh; + + if (buffer == nullptr) { + buffer = image; + dmaWait(); + } + + // If image is clipped, copy pixels into a contiguous block + if ( (dw != w) || (dh != h) ) { + if(_swapBytes) { + for (int32_t yb = 0; yb < dh; yb++) { + for (int32_t xb = 0; xb < dw; xb++) { + uint32_t src = xb + dx + w * (yb + dy); + (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); + } + } + } + else { + for (int32_t yb = 0; yb < dh; yb++) { + memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); + } + } + } + // else, if a buffer pointer has been provided copy whole image to the buffer + else if (buffer != image || _swapBytes) { + if(_swapBytes) { + for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); + } + else { + memcpy(buffer, image, len*2); + } + } + + if (spiBusyCheck) dmaWait(); // In case we did not wait earlier + + setAddrWindow(x, y, dw, dh); + + esp_err_t ret; + static spi_transaction_t trans; + + memset(&trans, 0, sizeof(spi_transaction_t)); + + trans.user = (void *)1; + trans.tx_buffer = buffer; //finally send the line data + trans.length = len * 16; //Data length, in bits + trans.flags = 0; //SPI_TRANS_USE_TXDATA flag + + ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); + assert(ret == ESP_OK); + + spiBusyCheck++; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Processor specific DMA initialisation +//////////////////////////////////////////////////////////////////////////////////////// + +// The DMA functions here work with SPI only (not parallel) +/*************************************************************************************** +** Function name: dc_callback +** Description: Toggles DC line during transaction +***************************************************************************************/ +extern "C" void dc_callback(); + +void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) +{ + if ((bool)spi_tx->user) {DC_D;} + else {DC_C;} +} + +/*************************************************************************************** +** Function name: dma_end_callback +** Description: Clear DMA run flag to stop retransmission loop +***************************************************************************************/ +extern "C" void dma_end_callback(); + +void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) +{ + WRITE_PERI_REG(SPI_DMA_CONF_REG(spi_host), 0); +} + +/*************************************************************************************** +** Function name: initDMA +** Description: Initialise the DMA engine - returns true if init OK +***************************************************************************************/ +bool TFT_eSPI::initDMA(bool ctrl_cs) +{ + if (DMA_Enabled) return false; + + esp_err_t ret; + spi_bus_config_t buscfg = { + .mosi_io_num = TFT_MOSI, + .miso_io_num = TFT_MISO, + .sclk_io_num = TFT_SCLK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .data4_io_num = -1, + .data5_io_num = -1, + .data6_io_num = -1, + .data7_io_num = -1, + .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size + .flags = 0, + .intr_flags = 0 + }; + + int8_t pin = -1; + if (ctrl_cs) pin = TFT_CS; + + spi_device_interface_config_t devcfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = TFT_SPI_MODE, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .clock_speed_hz = SPI_FREQUENCY, + .input_delay_ns = 0, + .spics_io_num = pin, + .flags = SPI_DEVICE_NO_DUMMY, //0, + .queue_size = 1, + .pre_cb = 0, //dc_callback, //Callback to handle D/C line + #ifdef CONFIG_IDF_TARGET_ESP32 + .post_cb = 0 + #else + .post_cb = dma_end_callback + #endif + }; + ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); + ESP_ERROR_CHECK(ret); + ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); + ESP_ERROR_CHECK(ret); + + DMA_Enabled = true; + spiBusyCheck = 0; + return true; +} + +/*************************************************************************************** +** Function name: deInitDMA +** Description: Disconnect the DMA engine from SPI +***************************************************************************************/ +void TFT_eSPI::deInitDMA(void) +{ + if (!DMA_Enabled) return; + spi_bus_remove_device(dmaHAL); + spi_bus_free(spi_host); + DMA_Enabled = false; +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // End of DMA FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////// + #ifndef SPI_BUSY_CHECK #define SPI_BUSY_CHECK #endif @@ -52,46 +620,25 @@ \ if (dw < 1 || dh < 1) return; -/*************************************************************************************** -** Function name: Legacy - deprecated -** Description: Start/end transaction -***************************************************************************************/ - void TFT_eSPI::spi_begin() {begin_tft_write();} - void TFT_eSPI::spi_end() { end_tft_write();} - void TFT_eSPI::spi_begin_read() {begin_tft_read(); } - void TFT_eSPI::spi_end_read() { end_tft_read(); } -/*************************************************************************************** -** Function name: begin_tft_write (was called spi_begin) -** Description: Start SPI transaction for writes and select TFT -***************************************************************************************/ inline void TFT_eSPI::begin_tft_write(void){ if (locked) { locked = false; // Flag to show SPI access now unlocked -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) spi.beginTransaction(SPISettings(spi_write_speed * 1000000, MSBFIRST, TFT_SPI_MODE)); -#endif CS_L; - SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used + SET_BUS_WRITE_MODE; } } -// Non-inlined version to permit override void TFT_eSPI::begin_nin_write(void){ if (locked) { locked = false; // Flag to show SPI access now unlocked -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) spi.beginTransaction(SPISettings(spi_write_speed * 1000000, MSBFIRST, TFT_SPI_MODE)); -#endif CS_L; - SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used + SET_BUS_WRITE_MODE; } } -/*************************************************************************************** -** Function name: end_tft_write (was called spi_end) -** Description: End transaction for write and deselect TFT -***************************************************************************************/ inline void TFT_eSPI::end_tft_write(void){ if(!inTransaction) { // Flag to stop ending transaction during multiple graphics calls if (!locked) { // Locked when beginTransaction has been called @@ -99,56 +646,34 @@ inline void TFT_eSPI::end_tft_write(void){ SPI_BUSY_CHECK; // Check send complete and clean out unused rx data CS_H; SET_BUS_READ_MODE; // In case bus has been configured for tx only -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) spi.endTransaction(); -#endif } } } -// Non-inlined version to permit override -inline void TFT_eSPI::end_nin_write(void){ +inline void TFT_eSPI::end_nin_write() { if(!inTransaction) { // Flag to stop ending transaction during multiple graphics calls if (!locked) { // Locked when beginTransaction has been called locked = true; // Flag to show SPI access now locked SPI_BUSY_CHECK; // Check send complete and clean out unused rx data CS_H; SET_BUS_READ_MODE; // In case SPI has been configured for tx only -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BI) spi.endTransaction(); -#endif } } } -/*************************************************************************************** -** Function name: begin_tft_read (was called spi_begin_read) -** Description: Start transaction for reads and select TFT -***************************************************************************************/ -// Reads require a lower SPI clock rate than writes -inline void TFT_eSPI::begin_tft_read(void){ - 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) +inline void TFT_eSPI::begin_tft_read() { + dmaWait(); if (locked) { locked = false; spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L; } -#else - #if !defined(TFT_PARALLEL_8_BIT) - spi.setFrequency(SPI_READ_FREQUENCY); - #endif - CS_L; -#endif SET_BUS_READ_MODE; } -/*************************************************************************************** -** Function name: end_tft_read (was called spi_end_read) -** Description: End transaction for reads and deselect TFT -***************************************************************************************/ inline void TFT_eSPI::end_tft_read(void){ -#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) if(!inTransaction) { if (!locked) { locked = true; @@ -156,19 +681,9 @@ inline void TFT_eSPI::end_tft_read(void){ spi.endTransaction(); } } -#else - #if !defined(TFT_PARALLEL_8_BIT) - spi.setFrequency(spi_write_speed * 1000000); - #endif - if(!inTransaction) {CS_H;} -#endif SET_BUS_WRITE_MODE; } -/*************************************************************************************** -** Function name: setViewport -** Description: Set the clipping region for the TFT screen -***************************************************************************************/ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum) { // Viewport metrics (not clipped) @@ -191,12 +706,8 @@ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDa if ((x + w) > width() ) { w = width() - x; } if ((y + h) > height() ) { h = height() - y; } - //Serial.print(" x=");Serial.print( x);Serial.print(", y=");Serial.print( y); - //Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h); - // Check if viewport is entirely out of bounds - if (w < 1 || h < 1) - { + if (w < 1 || h < 1) { // Set default values and Out of Bounds flag in case of error _xDatum = 0; _yDatum = 0; @@ -206,8 +717,7 @@ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDa return; } - if (!vpDatum) - { + if (!vpDatum) { _xDatum = 0; // Reset to top left of screen if not using a viewport datum _yDatum = 0; _xWidth = width(); @@ -220,21 +730,9 @@ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDa _vpW = x + w; _vpH = y + h; _vpDatum = vpDatum; - - //Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum); - //Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight); - - //Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY); - //Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH); } -/*************************************************************************************** -** Function name: checkViewport -** Description: Check if any part of specified area is visible in viewport -***************************************************************************************/ -// Note: Setting w and h to 1 will check if coordinate x,y is in area -bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h) -{ +bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h) { if (_vpOoB) return false; x+= _xDatum; y+= _yDatum; @@ -257,84 +755,37 @@ bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h) return true; } -/*************************************************************************************** -** Function name: setSPISpeed -** Description: Set SPI speed -***************************************************************************************/ -void TFT_eSPI::setSPISpeed(uint8_t speed) -{ - if(speed > 0 && speed < 80) - spi_write_speed = speed; +void TFT_eSPI::setSPISpeed(uint8_t speed) { + if(speed > 0 && speed < 80) spi_write_speed = speed; } -/*************************************************************************************** -** Function name: resetViewport -** Description: Reset viewport to whole TFT screen, datum at 0,0 -***************************************************************************************/ -void TFT_eSPI::resetViewport(void) -{ - // Reset viewport to the whole screen (or sprite) area - _vpDatum = false; - _vpOoB = false; - _xDatum = 0; - _yDatum = 0; - _vpX = 0; - _vpY = 0; - _vpW = width(); - _vpH = height(); - _xWidth = width(); - _yHeight = height(); +void TFT_eSPI::resetViewport() { + _vpDatum = _vpOoB = false; + _xDatum = _yDatum = _vpX = _vpY = 0; + _vpW = _xWidth = width(); + _vpH = _yHeight = height(); } -/*************************************************************************************** -** Function name: getViewportX -** Description: Get x position of the viewport datum -***************************************************************************************/ -int32_t TFT_eSPI::getViewportX(void) -{ +int32_t TFT_eSPI::getViewportX() { return _xDatum; } -/*************************************************************************************** -** Function name: getViewportY -** Description: Get y position of the viewport datum -***************************************************************************************/ -int32_t TFT_eSPI::getViewportY(void) -{ +int32_t TFT_eSPI::getViewportY() { return _yDatum; } -/*************************************************************************************** -** Function name: getViewportWidth -** Description: Get width of the viewport -***************************************************************************************/ -int32_t TFT_eSPI::getViewportWidth(void) -{ +int32_t TFT_eSPI::getViewportWidth() { return _xWidth; } -/*************************************************************************************** -** Function name: getViewportHeight -** Description: Get height of the viewport -***************************************************************************************/ -int32_t TFT_eSPI::getViewportHeight(void) -{ +int32_t TFT_eSPI::getViewportHeight() { return _yHeight; } -/*************************************************************************************** -** Function name: getViewportDatum -** Description: Get datum flag of the viewport (true = viewport corner) -***************************************************************************************/ -bool TFT_eSPI::getViewportDatum(void) -{ +bool TFT_eSPI::getViewportDatum() { return _vpDatum; } -/*************************************************************************************** -** Function name: frameViewport -** Description: Draw a frame inside or outside the viewport of width w -***************************************************************************************/ void TFT_eSPI::frameViewport(uint16_t color, int32_t w) { // Save datum position @@ -342,8 +793,7 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w) // If w is positive the frame is drawn inside the viewport // a large positive width will clear the screen inside the viewport - if (w>0) - { + if (w>0) { // Set vpDatum true to simplify coordinate derivation _vpDatum = true; fillRect(0, 0, _vpW - _vpX, w, color); // Top @@ -351,10 +801,7 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w) fillRect(_xWidth - w, w, w, _yHeight - w - w, color); // Right fillRect(0, _yHeight - w, _xWidth, w, color); // Bottom } - else - // If w is negative the frame is drawn outside the viewport - // a large negative width will clear the screen outside the viewport - { + else { w = -w; // Save old values @@ -385,10 +832,6 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w) _vpDatum = _dT; } -/*************************************************************************************** -** Function name: clipAddrWindow -** Description: Clip address window x,y,w,h to screen and viewport -***************************************************************************************/ bool TFT_eSPI::clipAddrWindow(int32_t *x, int32_t *y, int32_t *w, int32_t *h) { if (_vpOoB) return false; // Area is outside of viewport @@ -410,10 +853,6 @@ bool TFT_eSPI::clipAddrWindow(int32_t *x, int32_t *y, int32_t *w, int32_t *h) return true; // Area is wholly or partially inside viewport } -/*************************************************************************************** -** Function name: clipWindow -** Description: Clip window xs,yx,xe,ye to screen and viewport -***************************************************************************************/ bool TFT_eSPI::clipWindow(int32_t *xs, int32_t *ys, int32_t *xe, int32_t *ye) { if (_vpOoB) return false; // Area is outside of viewport @@ -436,98 +875,51 @@ bool TFT_eSPI::clipWindow(int32_t *xs, int32_t *ys, int32_t *xe, int32_t *ye) return true; // Area is wholly or partially inside viewport } -/*************************************************************************************** -** Function name: TFT_eSPI -** Description: Constructor , we must use hardware SPI pins -***************************************************************************************/ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) { - _init_width = _width = w; // Set by specific xxxxx_Defines.h file or by users sketch - _init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch + _init_width = _width = w; + _init_height = _height = h; - // Reset the viewport to the whole screen resetViewport(); - rotation = 0; - cursor_y = cursor_x = last_cursor_x = bg_cursor_x = 0; - textfont = 1; - textsize = 1; - textcolor = bitmap_fg = 0xFFFF; // White - textbgcolor = bitmap_bg = 0x0000; // Black - padX = 0; // No padding + rotation = padX = 0; + cursor_y = cursor_x = last_cursor_x = bg_cursor_x = 0; + textfont = textsize = 1; + textcolor = bitmap_fg = 0xFFFF; + textbgcolor = bitmap_bg = 0x0000; - _fillbg = false; // Smooth font only at the moment, force text background fill - - isDigits = false; // No bounding box adjustment - textwrapX = true; // Wrap text at end of line when using print stream - textwrapY = false; // Wrap text at bottom of screen when using print stream - textdatum = TL_DATUM; // Top Left text alignment is default + _fillbg = isDigits = textwrapY = false; + textwrapX = true; + textdatum = TL_DATUM; fontsloaded = 0; - _swapBytes = false; // Do not swap colour bytes by default + _swapBytes = false; - locked = true; // Transaction mutex lock flag to ensure begin/endTranaction pairing - inTransaction = false; // Flag to prevent multiple sequential functions to keep bus access open - lockTransaction = false; // start/endWrite lock flag to allow sketch to keep SPI bus access open + locked = true; + inTransaction = false; + lockTransaction = false; - _booted = true; // Default attributes - _cp437 = false; // Legacy GLCD font bug fix disabled by default - _utf8 = true; // UTF8 decoding enabled + _booted = true; + _cp437 = false; + _utf8 = true; -#if defined (FONT_FS_AVAILABLE) && defined (SMOOTH_FONT) - fs_font = true; // Smooth font filing system or array (fs_font = false) flag -#endif + fs_font = true; - addr_row = 0xFFFF; // drawPixel command length optimiser - addr_col = 0xFFFF; // drawPixel command length optimiser + addr_row = 0xFFFF; + addr_col = 0xFFFF; _xPivot = 0; _yPivot = 0; -// Legacy support for bit GPIO masks cspinmask = 0; dcpinmask = 0; wrpinmask = 0; sclkpinmask = 0; -// Flags for which fonts are loaded -#ifdef LOAD_GLCD - fontsloaded = 0x0002; // Bit 1 set -#endif - -#ifdef LOAD_FONT2 - fontsloaded |= 0x0004; // Bit 2 set -#endif - -#ifdef LOAD_FONT4 - fontsloaded |= 0x0010; // Bit 4 set -#endif - -#ifdef LOAD_FONT6 - fontsloaded |= 0x0040; // Bit 6 set -#endif - -#ifdef LOAD_FONT7 - fontsloaded |= 0x0080; // Bit 7 set -#endif - -#ifdef LOAD_FONT8 - fontsloaded |= 0x0100; // Bit 8 set -#endif - -#ifdef LOAD_FONT8N - fontsloaded |= 0x0200; // Bit 9 set -#endif - -#ifdef SMOOTH_FONT + fontsloaded = 0x0002; // Bit 1 set fontsloaded |= 0x8000; // Bit 15 set -#endif } -/*************************************************************************************** -** Function name: initBus -** Description: initialise the SPI or parallel bus -***************************************************************************************/ void TFT_eSPI::initBus(void) { #ifdef TFT_CS @@ -537,13 +929,10 @@ void TFT_eSPI::initBus(void) { } #endif -// Configure chip select for touchscreen controller if present -#ifdef TOUCH_CS - if (TOUCH_CS >= 0) { - pinMode(TOUCH_CS, OUTPUT); - digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive) - } -#endif +if (TOUCH_CS >= 0) { + pinMode(TOUCH_CS, OUTPUT); + digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive) +} #if defined (TFT_WR) if (TFT_WR >= 0) { @@ -565,63 +954,22 @@ void TFT_eSPI::initBus(void) { digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device } #endif - -#if defined (TFT_PARALLEL_8_BIT) - - // Make sure read is high before we set the bus to output - if (TFT_RD >= 0) { - pinMode(TFT_RD, OUTPUT); - digitalWrite(TFT_RD, HIGH); - } - - // Set TFT data bus lines to 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); - - PARALLEL_INIT_TFT_DATA_BUS; - -#endif } -/*************************************************************************************** -** Function name: begin -** Description: Included for backwards compatibility -***************************************************************************************/ -void TFT_eSPI::begin(uint8_t tc) +void TFT_eSPI::init() { - init(tc); -} - - -/*************************************************************************************** -** Function name: init (tc is tab colour for ST7735 displays only) -** Description: Reset, then initialise the TFT display registers -***************************************************************************************/ -void TFT_eSPI::init(uint8_t tc) -{ - if (_booted) - { + if (_booted) { initBus(); - #if !defined(TFT_PARALLEL_8_BIT) - #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) - spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); // This will set MISO to input - #else - spi.begin(); // This will set MISO to input - #endif + #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) + spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); // This will set MISO to input + #else + spi.begin(); // This will set MISO to input #endif lockTransaction = false; inTransaction = false; locked = true; - INIT_TFT_DATA_BUS; - #if defined (TFT_CS) // Set to output once again in case MISO is used for CS @@ -667,9 +1015,7 @@ void TFT_eSPI::init(uint8_t tc) begin_tft_write(); - tc = tc; // Suppress warning - - #include "TFT_Drivers/ILI9341_Init.h" + #include "ILI9341_Init.h" #ifdef TFT_INVERSION_ON writecommand(TFT_INVON); @@ -699,17 +1045,10 @@ void TFT_eSPI::init(uint8_t tc) #endif } - -/*************************************************************************************** -** Function name: setRotation -** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing -***************************************************************************************/ -void TFT_eSPI::setRotation(uint8_t m) -{ - +void TFT_eSPI::setRotation(uint8_t m) { begin_tft_write(); - #include "TFT_Drivers/ILI9341_Rotation.h" + #include "ILI9341_Rotation.h" delayMicroseconds(10); @@ -718,79 +1057,42 @@ void TFT_eSPI::setRotation(uint8_t m) addr_row = 0xFFFF; addr_col = 0xFFFF; - // Reset the viewport to the whole screen resetViewport(); } - -/*************************************************************************************** -** Function name: getRotation -** Description: Return the rotation value (as used by setRotation()) -***************************************************************************************/ -uint8_t TFT_eSPI::getRotation(void) -{ +uint8_t TFT_eSPI::getRotation() { return rotation; } - -/*************************************************************************************** -** Function name: setOrigin -** Description: Set graphics origin to position x,y wrt to top left corner -***************************************************************************************/ -//Note: setRotation, setViewport and resetViewport will revert origin to top left void TFT_eSPI::setOrigin(int32_t x, int32_t y) { _xDatum = x; _yDatum = y; } - -/*************************************************************************************** -** Function name: getOriginX -** Description: Set graphics origin to position x -***************************************************************************************/ -int32_t TFT_eSPI::getOriginX(void) -{ +int32_t TFT_eSPI::getOriginX() { return _xDatum; } - -/*************************************************************************************** -** Function name: getOriginY -** Description: Set graphics origin to position y -***************************************************************************************/ -int32_t TFT_eSPI::getOriginY(void) -{ +int32_t TFT_eSPI::getOriginY() { return _yDatum; } -/*************************************************************************************** -** Function name: commandList, used for FLASH based lists only (e.g. ST7735) -** Description: Get initialisation commands from FLASH and send to TFT -***************************************************************************************/ void TFT_eSPI::commandList (const uint8_t *addr) { - uint8_t numCommands; - uint8_t numArgs; - uint8_t ms; - - numCommands = pgm_read_byte(addr++); // Number of commands to follow - - while (numCommands--) // For each command... - { + uint8_t numCommands = pgm_read_byte(addr++), numArgs, ms; + while (numCommands--) { writecommand(pgm_read_byte(addr++)); // Read, issue command numArgs = pgm_read_byte(addr++); // Number of args to follow ms = numArgs & TFT_INIT_DELAY; // If high bit set, delay follows args numArgs &= ~TFT_INIT_DELAY; // Mask out delay bit - while (numArgs--) // For each argument... - { + while (numArgs--) { writedata(pgm_read_byte(addr++)); // Read, issue argument } - if (ms) - { + if (ms) { ms = pgm_read_byte(addr++); // Read post-command delay time (ms) delay( (ms==255 ? 500 : ms) ); } @@ -798,11 +1100,6 @@ void TFT_eSPI::commandList (const uint8_t *addr) } - -/*************************************************************************************** -** Function name: spiwrite -** Description: Write 8 bits to SPI port (legacy support only) -***************************************************************************************/ void TFT_eSPI::spiwrite(uint8_t c) { begin_tft_write(); @@ -810,12 +1107,6 @@ void TFT_eSPI::spiwrite(uint8_t c) end_tft_write(); } - -/*************************************************************************************** -** Function name: writecommand -** Description: Send an 8-bit command to the TFT -***************************************************************************************/ -#ifndef RM68120_DRIVER void TFT_eSPI::writecommand(uint8_t c) { begin_tft_write(); @@ -828,57 +1119,7 @@ void TFT_eSPI::writecommand(uint8_t c) end_tft_write(); } -#else -void TFT_eSPI::writecommand(uint16_t c) -{ - begin_tft_write(); - DC_C; - - tft_Write_16(c); - - DC_D; - - end_tft_write(); - -} -void TFT_eSPI::writeRegister8(uint16_t c, uint8_t d) -{ - begin_tft_write(); - - DC_C; - - tft_Write_16(c); - - DC_D; - - tft_Write_8(d); - - end_tft_write(); - -} -void TFT_eSPI::writeRegister16(uint16_t c, uint16_t d) -{ - begin_tft_write(); - - DC_C; - - tft_Write_16(c); - - DC_D; - - tft_Write_16(d); - - end_tft_write(); - -} - -#endif - -/*************************************************************************************** -** Function name: writedata -** Description: Send a 8-bit data value to the TFT -***************************************************************************************/ void TFT_eSPI::writedata(uint8_t d) { begin_tft_write(); @@ -900,22 +1141,6 @@ void TFT_eSPI::writedata(uint8_t d) uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index) { uint8_t reg = 0; -#if defined(TFT_PARALLEL_8_BIT) - - writecommand(cmd_function); // Sets DC and CS high - - busDir(GPIO_DIR_MASK, INPUT); - - CS_L; - - // Read nth parameter (assumes caller discards 1st parameter or points index to 2nd) - while(index--) reg = readByte(); - - busDir(GPIO_DIR_MASK, OUTPUT); - - CS_H; - -#else // SPI interface // Tested with ILI9341 set to Interface II i.e. IM [3:0] = "1101" begin_tft_read(); index = 0x10 + (index & 0x0F); @@ -931,17 +1156,10 @@ uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index) reg = tft_Read_8(); end_tft_read(); -#endif return reg; } - -/*************************************************************************************** -** Function name: readcommand16 -** Description: Read a 16-bit data value from an indexed command register -***************************************************************************************/ -uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index) -{ +uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index) { uint32_t reg; reg = (readcommand8(cmd_function, index + 0) << 8); @@ -951,12 +1169,7 @@ uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index) } -/*************************************************************************************** -** Function name: readcommand32 -** Description: Read a 32-bit data value from an indexed command register -***************************************************************************************/ -uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) -{ +uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) { uint32_t reg; reg = ((uint32_t)readcommand8(cmd_function, index + 0) << 24); @@ -967,11 +1180,6 @@ uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) return reg; } - -/*************************************************************************************** -** Function name: read pixel (for SPI Interface II i.e. IM [3:0] = "1101") -** Description: Read 565 pixel colours from a pixel -***************************************************************************************/ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) { if (_vpOoB) return 0; @@ -981,35 +1189,6 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) // Range checking if ((x0 < _vpX) || (y0 < _vpY) ||(x0 >= _vpW) || (y0 >= _vpH)) return 0; - -#if defined(TFT_PARALLEL_8_BIT) - - if (!inTransaction) { CS_L; } // CS_L can be multi-statement - - readAddrWindow(x0, y0, 1, 1); - - // Set masked pins D0- D7 to input - busDir(GPIO_DIR_MASK, INPUT); - - // Dummy read to throw away don't care value - readByte(); - - // Fetch the 16-bit BRG pixel - //uint16_t rgb = (readByte() << 8) | readByte(); - - - // Read window pixel 24-bit RGB values and fill in LS bits - uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3); - - if (!inTransaction) { CS_H; } // CS_H can be multi-statement - - // Set masked pins D0- D7 to output - busDir(GPIO_DIR_MASK, OUTPUT); - - return rgb; - -#else // Not TFT_PARALLEL_8_BIT - // This function can get called during anti-aliased font rendering // so a transaction may be in progress bool wasInTransaction = inTransaction; @@ -1046,59 +1225,16 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) if(wasInTransaction) { begin_tft_write(); inTransaction = true; } return color; - -#endif } -void TFT_eSPI::setCallback(getColorCallback getCol) -{ +void TFT_eSPI::setCallback(getColorCallback getCol) { getColor = getCol; } - -/*************************************************************************************** -** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101") -** Description: Read 565 pixel colours from a defined area -***************************************************************************************/ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { PI_CLIP ; -#if defined(TFT_PARALLEL_8_BIT) - - CS_L; - - readAddrWindow(x, y, dw, dh); - - data += dx + dy * w; - - // Set masked pins D0- D7 to input - busDir(GPIO_DIR_MASK, INPUT); - - // Dummy read to throw away don't care value - readByte(); - - // Fetch the 24-bit RGB value - while (dh--) { - int32_t lw = dw; - uint16_t* line = data; - while (lw--) { - // Assemble the RGB 16-bit colour - uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3); - - // Swapped byte order for compatibility with pushRect() - *line++ = (rgb<<8) | (rgb>>8); - } - data += w; - } - - CS_H; - - // Set masked pins D0- D7 to output - busDir(GPIO_DIR_MASK, OUTPUT); - -#else // SPI interface - // This function can get called after a begin_tft_write // so a transaction may be in progress bool wasInTransaction = inTransaction; @@ -1148,14 +1284,8 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Reinstate the transaction if one was in progress if(wasInTransaction) { begin_tft_write(); inTransaction = true; } -#endif } - -/*************************************************************************************** -** Function name: push rectangle -** Description: push 565 pixel colours into a defined area -***************************************************************************************/ void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { bool swap = _swapBytes; _swapBytes = false; @@ -1163,11 +1293,6 @@ void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da _swapBytes = swap; } - -/*************************************************************************************** -** Function name: pushImage -** Description: plot 16-bit colour sprite or image onto TFT -***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { PI_CLIP; @@ -1183,8 +1308,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d if (dw == w) pushPixels(data, dw * dh); else { // Push line segments to crop image - while (dh--) - { + while (dh--) { pushPixels(data, dw); data += w; } @@ -1194,10 +1318,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d end_tft_write(); } -/*************************************************************************************** -** Function name: pushImage -** Description: plot 16-bit sprite or image with 1 colour being transparent -***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transp) { PI_CLIP; @@ -1221,19 +1341,14 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d bool move = true; uint16_t np = 0; - while (len--) - { - if (transp != *ptr) - { + while (len--) { + if (transp != *ptr) { if (move) { move = false; sx = px; } lineBuf[np] = *ptr; np++; - } - else - { + } else { move = true; - if (np) - { + if (np) { setWindow(sx, y, sx + np - 1, y); pushPixels((uint16_t*)lineBuf, np); np = 0; @@ -1252,11 +1367,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d end_tft_write(); } - -/*************************************************************************************** -** Function name: pushImage - for FLASH (PROGMEM) stored images -** Description: plot 16-bit image -***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { // Requires 32-bit aligned access, so use PROGMEM 16-bit word functions @@ -1273,9 +1383,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 // Fill and send line buffers to TFT for (int32_t i = 0; i < dh; i++) { - for (int32_t j = 0; j < dw; j++) { - buffer[j] = pgm_read_word(&data[i * w + j]); - } + for (int32_t j = 0; j < dw; j++) buffer[j] = pgm_read_word(&data[i * w + j]); pushPixels(buffer, dw); } @@ -1283,13 +1391,8 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 end_tft_write(); } -/*************************************************************************************** -** Function name: pushImage - for FLASH (PROGMEM) stored images -** Description: plot 16-bit image with 1 colour being transparent -***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transp) { - // Requires 32-bit aligned access, so use PROGMEM 16-bit word functions PI_CLIP; begin_tft_write(); @@ -1297,10 +1400,8 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 data += dx + dy * w; - uint16_t lineBuf[dw]; - // The little endian transp color must be byte swapped if the image is big endian if (!_swapBytes) transp = transp >> 8 | transp << 8; while (dh--) { @@ -1356,8 +1457,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8 // Line buffer makes plotting faster uint16_t lineBuf[dw]; - if (bpp8) - { + if (bpp8) { _swapBytes = false; uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5-bit colour lookup table @@ -1425,19 +1525,15 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8 ptr++; } - while (len--) - { + while (len--) { colors = pgm_read_byte(ptr); index = ((colors & 0xF0) >> 4) & 0x0F; *linePtr++ = cmap[index]; - if (len--) - { + if (len--) { index = colors & 0x0F; *linePtr++ = cmap[index]; - } else { - break; // nothing to do here - } + } else break; ptr++; } @@ -1447,16 +1543,13 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8 } _swapBytes = swap; // Restore old value } - else // Must be 1bpp - { + else { _swapBytes = false; uint8_t * ptr = (uint8_t*)data; uint32_t ww = (w+7)>>3; // Width of source image line in bytes - for (int32_t yp = dy; yp < dy + dh; yp++) - { + for (int32_t yp = dy; yp < dy + dh; yp++) { uint8_t* linePtr = (uint8_t*)lineBuf; - for (int32_t xp = dx; xp < dx + dw; xp++) - { + for (int32_t xp = dx; xp < dx + dw; xp++) { uint16_t col = (pgm_read_byte(ptr + (xp>>3)) & (0x80 >> (xp & 0x7)) ); if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;} else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;} @@ -1471,11 +1564,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8 end_tft_write(); } - -/*************************************************************************************** -** Function name: pushImage -** Description: plot 8-bit or 4-bit or 1 bit image or sprite using a line buffer -***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8, uint16_t *cmap) { PI_CLIP; @@ -1921,28 +2009,7 @@ bool TFT_eSPI::getSwapBytes(void) ** Description: Read RGB pixel colours from a defined area ***************************************************************************************/ // 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(TFT_PARALLEL_8_BIT) - - uint32_t len = w * h; - uint8_t* buf565 = data + len; - - readRect(x0, y0, w, h, (uint16_t*)buf565); - - while (len--) { - uint16_t pixel565 = (*buf565++)<<8; - pixel565 |= *buf565++; - uint8_t red = (pixel565 & 0xF800) >> 8; red |= red >> 5; - uint8_t green = (pixel565 & 0x07E0) >> 3; green |= green >> 6; - uint8_t blue = (pixel565 & 0x001F) << 3; blue |= blue >> 5; - *data++ = red; - *data++ = green; - *data++ = blue; - } - -#else // Not TFT_PARALLEL_8_BIT - +void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data) { begin_tft_read(); readAddrWindow(x0, y0, w, h); // Sets CS low @@ -1969,8 +2036,6 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_ *data++ = (tft_Read_8()&0x7E)<<1; *data++ = (tft_Read_8()&0x7E)<<1; - #endif - } CS_H; @@ -2791,7 +2856,6 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) int32_t str_width = 0; uint16_t uniCode = 0; -#ifdef SMOOTH_FONT if(fontLoaded) { while (*string) { uniCode = decodeUTF8(*string++); @@ -2812,7 +2876,6 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) isDigits = false; return str_width; } -#endif if (font>1 && font<9) { char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop @@ -2826,28 +2889,7 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) } else { - -#ifdef LOAD_GFXFF - if(gfxFont) { // New font - while (*string) { - uniCode = decodeUTF8(*string++); - 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 - if (*string || isDigits) str_width += pgm_read_byte(&glyph->xAdvance); - // Else use the offset plus width since this can be bigger than xAdvance - else str_width += ((int8_t)pgm_read_byte(&glyph->xOffset) + pgm_read_byte(&glyph->width)); - } - } - } - else -#endif - { -#ifdef LOAD_GLCD - while (*string++) str_width += 6; -#endif - } + while (*string++) str_width += 6; } isDigits = false; return str_width * textsize; @@ -2873,17 +2915,8 @@ int16_t TFT_eSPI::fontHeight(uint8_t font) { if (font > 8) return 0; -#ifdef SMOOTH_FONT if(fontLoaded) return gFont.yAdvance; -#endif -#ifdef LOAD_GFXFF - if (font==1) { - if(gfxFont) { // New font - return pgm_read_byte(&gfxFont->yAdvance) * textsize; - } - } -#endif return pgm_read_byte( &fontdata[font].height ) * textsize; } @@ -2900,13 +2933,6 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 { if (_vpOoB) return; -#ifdef LOAD_GLCD -//>>>>>>>>>>>>>>>>>> - #ifdef LOAD_GFXFF - if(!gfxFont) { // 'Classic' built-in GLCD font - #endif -//>>>>>>>>>>>>>>>>>> - int32_t xd = x + _xDatum; int32_t yd = y + _yDatum; @@ -2971,85 +2997,6 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 inTransaction = lockTransaction; end_tft_write(); // Does nothing if Sprite class uses this function } - -//>>>>>>>>>>>>>>>>>>>>>>>>>>> - #ifdef LOAD_GFXFF - } else { // Custom font - #endif -//>>>>>>>>>>>>>>>>>>>>>>>>>>> -#endif // LOAD_GLCD - -#ifdef LOAD_GFXFF - // Filter out bad characters not present in font - if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last ))) { - //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() - inTransaction = true; -//>>>>>>>>>>>>>>>>>>>>>>>>>>> - - c -= pgm_read_word(&gfxFont->first); - GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]); - uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap); - - uint32_t bo = pgm_read_word(&glyph->bitmapOffset); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - //xa = pgm_read_byte(&glyph->xAdvance); - int8_t xo = pgm_read_byte(&glyph->xOffset), - yo = pgm_read_byte(&glyph->yOffset); - uint8_t xx, yy, bits=0, bit=0; - int16_t xo16 = 0, yo16 = 0; - - if(size > 1) { - xo16 = xo; - yo16 = yo; - } - - // 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) { - 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); - hpc=0; - } - } - - inTransaction = lockTransaction; - end_tft_write(); // Does nothing if Sprite class uses this function - } -#endif - -#ifdef LOAD_GLCD - #ifdef LOAD_GFXFF - } // End classic vs custom font - #endif -#else - #ifndef LOAD_GFXFF - // Avoid warnings if fonts are disabled - x = x; - y = y; - color = color; - bg = bg; - size = size; - #endif -#endif - } @@ -3177,11 +3124,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_C; tft_Write_8(TFT_RAMWR); - #if defined(TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) || !defined(ESP32) - DC_D; tft_Write_16(color); - #else - DC_D; tft_Write_16N(color); - #endif + DC_D; tft_Write_16N(color); end_tft_write(); } @@ -3233,7 +3176,7 @@ void TFT_eSPI::endWrite(void) { lockTransaction = false; // Release sketch induced transaction lock inTransaction = false; - DMA_BUSY_CHECK; // Safety check - user code should have checked this! + dmaWait(); // Safety check - user code should have checked this! end_tft_write(); // Release SPI bus } @@ -3659,7 +3602,7 @@ void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, int32_t r1 = r * r; r++; int32_t r2 = r * r; - + for (int32_t cy = r - 1; cy > 0; cy--) { int32_t dy2 = (r - cy) * (r - cy); @@ -4459,67 +4402,21 @@ size_t TFT_eSPI::write(uint8_t utf8) if (utf8 == '\r') return 1; -#ifdef SMOOTH_FONT if(fontLoaded) { if (uniCode < 32 && utf8 != '\n') return 1; - drawGlyph(uniCode); - return 1; } -#endif if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors uint16_t cwidth = 0; uint16_t cheight = 0; -//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - //Serial.print((uint8_t) uniCode); // Debug line sends all printed TFT text to serial port - //Serial.println(uniCode, HEX); // Debug line sends all printed TFT text to serial port - //delay(5); // Debug optional wait for serial port to flush through -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -#ifdef LOAD_GFXFF - if(!gfxFont) { -#endif -//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - -#ifdef LOAD_FONT2 - if (textfont == 2) { - if (uniCode < 32 || uniCode > 127) return 1; - - cwidth = pgm_read_byte(widtbl_f16 + uniCode-32); - cheight = chr_hgt_f16; - // Font 2 is rendered in whole byte widths so we must allow for this - cwidth = (cwidth + 6) / 8; // Width in whole bytes for font 2, should be + 7 but must allow for font width change - cwidth = cwidth * 8; // Width converted back to pixels - } - #ifdef LOAD_RLE - else - #endif -#endif - -#ifdef LOAD_RLE - { - if ((textfont>2) && (textfont<9)) { - if (uniCode < 32 || uniCode > 127) return 1; - // Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements - cwidth = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 ); - cheight= pgm_read_byte( &fontdata[textfont].height ); - } - } -#endif - -#ifdef LOAD_GLCD if (textfont==1) { cwidth = 6; cheight = 8; } -#else - if (textfont==1) return 1; -#endif cheight = cheight * textsize; @@ -4536,37 +4433,6 @@ size_t TFT_eSPI::write(uint8_t utf8) cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont); } -//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -#ifdef LOAD_GFXFF - } // Custom GFX font - else { - if(utf8 == '\n') { - cursor_x = 0; - cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } else { - if (uniCode > pgm_read_word(&gfxFont->last )) return 1; - if (uniCode < pgm_read_word(&gfxFont->first)) return 1; - - uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first); - GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - if((w > 0) && (h > 0)) { // Is there an associated bitmap? - int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); - if(textwrapX && ((cursor_x + textsize * (xo + w)) > width())) { - // Drawing character would go off right edge; wrap to new line - cursor_x = 0; - cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } - if (textwrapY && (cursor_y >= (int32_t) height())) cursor_y = 0; - drawChar(cursor_x, cursor_y, uniCode, textcolor, textbgcolor, textsize); - } - cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize; - } - } -#endif // LOAD_GFXFF -//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - return 1; } @@ -4587,40 +4453,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) { if (_vpOoB || !uniCode) return 0; - if (font==1) { -#ifdef LOAD_GLCD - #ifndef LOAD_GFXFF - drawChar(x, y, uniCode, textcolor, textbgcolor, textsize); - return 6 * textsize; - #endif -#else - #ifndef LOAD_GFXFF - return 0; - #endif -#endif - -#ifdef LOAD_GFXFF - drawChar(x, y, uniCode, textcolor, textbgcolor, textsize); - if(!gfxFont) { // 'Classic' built-in font - #ifdef LOAD_GLCD - return 6 * textsize; - #else - return 0; - #endif - } - 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 { - return 0; - } - } -#endif - } - + if (font==1) return 0; if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0; int32_t width = 0; @@ -4628,27 +4461,6 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) uint32_t flash_address = 0; uniCode -= 32; -#ifdef LOAD_FONT2 - if (font == 2) { - flash_address = pgm_read_dword(&chrtbl_f16[uniCode]); - width = pgm_read_byte(widtbl_f16 + uniCode); - height = chr_hgt_f16; - } - #ifdef LOAD_RLE - else - #endif -#endif - -#ifdef LOAD_RLE - { - 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 ); - } - } -#endif - int32_t xd = x + _xDatum; int32_t yd = y + _yDatum; @@ -4660,200 +4472,6 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) uint8_t line = 0; bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH; -#ifdef LOAD_FONT2 // chop out code if we do not need it - if (font == 2) { - w = w + 6; // Should be + 7 but we need to compensate for width increment - w = w / 8; - - if (textcolor == textbgcolor || textsize != 1 || clip) { - //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() - inTransaction = true; - - 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++) { - line = pgm_read_byte((uint8_t *)flash_address + w * i + k); - if (line) { - if (textsize == 1) { - pX = x + k * 8; - if (line & 0x80) drawPixel(pX, pY, textcolor); - if (line & 0x40) drawPixel(pX + 1, pY, textcolor); - if (line & 0x20) drawPixel(pX + 2, pY, textcolor); - if (line & 0x10) drawPixel(pX + 3, pY, textcolor); - if (line & 0x08) drawPixel(pX + 4, pY, textcolor); - if (line & 0x04) drawPixel(pX + 5, pY, textcolor); - if (line & 0x02) drawPixel(pX + 6, pY, textcolor); - if (line & 0x01) drawPixel(pX + 7, pY, textcolor); - } - else { - pX = x + k * 8 * textsize; - if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor); - if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor); - if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor); - if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor); - } - } - } - pY += textsize; - } - - inTransaction = lockTransaction; - end_tft_write(); - } - else { // Faster drawing of characters and background using block write - - begin_tft_write(); - - setWindow(xd, yd, xd + width - 1, yd + height - 1); - - uint8_t mask; - for (int32_t i = 0; i < height; i++) { - pX = width; - for (int32_t k = 0; k < w; k++) { - line = pgm_read_byte((uint8_t *) (flash_address + w * i + k) ); - mask = 0x80; - while (mask && pX) { - if (line & mask) {tft_Write_16(textcolor);} - else {tft_Write_16(textbgcolor);} - pX--; - mask = mask >> 1; - } - } - if (pX) {tft_Write_16(textbgcolor);} - } - - end_tft_write(); - } - } - - #ifdef LOAD_RLE - else - #endif -#endif //FONT2 - -#ifdef LOAD_RLE //674 bytes of code - // Font is not 2 and hence is RLE encoded - { - begin_tft_write(); - inTransaction = true; - - w *= height; // Now w is total number of pixels in the character - if (textcolor == textbgcolor && !clip) { - - int32_t px = 0, py = pY; // To hold character block start and end column and row values - int32_t pc = 0; // Pixel count - uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel - - uint8_t tnp = 0; // Temporary copy of np for while loop - 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) { - line = pgm_read_byte((uint8_t *)flash_address); - flash_address++; - if (line & 0x80) { - line &= 0x7F; - line++; - if (ts) { - px = xd + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow - py = yd + textsize * (pc / width); - } - else { - px = xd + pc % width; // Keep these px and py calculations outside the loop as they are slow - py = yd + pc / width; - } - while (line--) { // In this case the while(line--) is faster - pc++; // This is faster than putting pc+=line before while()? - setWindow(px, py, px + ts, py + ts); - - if (ts) { - tnp = np; - while (tnp--) {tft_Write_16(textcolor);} - } - else {tft_Write_16(textcolor);} - px += textsize; - - if (px >= (xd + width * textsize)) { - px = xd; - py += textsize; - } - } - } - else { - line++; - pc += line; - } - } - } - else { - // Text colour != background and textsize = 1 and character is within viewport area - // so use faster drawing of characters and background using block write - if (textcolor != textbgcolor && textsize == 1 && !clip) - { - setWindow(xd, yd, xd + width - 1, yd + height - 1); - - // Maximum font size is equivalent to 180x180 pixels in area - 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; - pushBlock(textcolor,line); - } - else { - line++; w -= line; - pushBlock(textbgcolor,line); - } - } - } - else - { - int32_t px = 0, py = 0; // To hold character pixel coords - int32_t tx = 0, ty = 0; // To hold character TFT pixel coords - int32_t pc = 0; // Pixel count - int32_t pl = 0; // Pixel line length - uint16_t pcol = 0; // Pixel color - bool pf = true; // Flag for plotting - while (pc < w) { - line = pgm_read_byte((uint8_t *)flash_address); - flash_address++; - if (line & 0x80) { pcol = textcolor; line &= 0x7F; pf = true;} - else { pcol = textbgcolor; if (textcolor == textbgcolor) pf = false;} - line++; - px = pc % width; - tx = x + textsize * px; - py = pc / width; - ty = y + textsize * py; - - pl = 0; - pc += line; - while (line--) { - pl++; - if ((px+pl) >= width) { - if (pf) fillRect(tx, ty, pl * textsize, textsize, pcol); - pl = 0; - px = 0; - tx = x; - py ++; - ty += textsize; - } - } - if (pl && pf) fillRect(tx, ty, pl * textsize, textsize, pcol); - } - } - } - inTransaction = lockTransaction; - end_tft_write(); - } - // End of RLE font rendering -#endif - -#if !defined (LOAD_FONT2) && !defined (LOAD_RLE) // Stop warnings flash_address = flash_address; w = w; @@ -4861,7 +4479,6 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) pY = pY; line = line; clip = clip; -#endif return width * textsize; // x + } @@ -4904,36 +4521,10 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font uint16_t cheight = 8 * textsize; -#ifdef LOAD_GFXFF - #ifdef SMOOTH_FONT - bool freeFont = (font == 1 && gfxFont && !fontLoaded); - #else - bool freeFont = (font == 1 && gfxFont); - #endif - - if (freeFont) { - cheight = glyph_ab * textsize; - poY += cheight; // Adjust for baseline datum of free fonts - baseline = cheight; - padding =101; // Different padding method used for Free Fonts - - // We need to make an adjustment for the bottom of the string (eg 'y' character) - if ((textdatum == BL_DATUM) || (textdatum == BC_DATUM) || (textdatum == BR_DATUM)) { - cheight += glyph_bb * textsize; - } - } -#endif - - - // If it is not font 1 (GLCD or free font) get the baseline and pixel height of the font -#ifdef SMOOTH_FONT if(fontLoaded) { baseline = gFont.maxAscent; cheight = fontHeight(); - } - else -#endif - if (font!=1) { + } else if (font!=1) { baseline = pgm_read_byte( &fontdata[font].baseline ) * textsize; cheight = fontHeight(font); } @@ -4996,36 +4587,10 @@ 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)) { - cheight = (glyph_ab + glyph_bb) * textsize; - // Get the offset for the first character only to allow for negative offsets - uint16_t c2 = 0; - uint16_t len = strlen(string); - uint16_t n = 0; - - 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) )) { - c2 -= pgm_read_word(&gfxFont->first); - GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]); - xo = pgm_read_byte(&glyph->xOffset) * textsize; - // Adjust for negative xOffset - if (xo > 0) xo = 0; - else cwidth -= xo; - // Add 1 pixel of padding all round - //cheight +=2; - //fillRect(poX+xo-1, poY - 1 - glyph_ab * textsize, cwidth+2, cheight, textbgcolor); - fillRect(poX+xo, poY - glyph_ab * textsize, cwidth, cheight, textbgcolor); - } - padding -=100; - } -#endif uint16_t len = strlen(string); uint16_t n = 0; -#ifdef SMOOTH_FONT if(fontLoaded) { setCursor(poX, poY); @@ -5039,11 +4604,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 } _fillbg = fillbg; // restore state sumX += cwidth; - //fontFile.close(); - } - else -#endif - { + } else { while (n < len) { uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); sumX += drawChar(uniCode, poX+sumX, poY, font); @@ -5059,13 +4620,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 if((padX>cwidth) && (textcolor!=textbgcolor)) { int16_t padXc = poX+cwidth+xo; -#ifdef LOAD_GFXFF - if (freeFont) { - poX +=xo; // Adjust for negative offset start character - poY -= glyph_ab * textsize; - sumX += poX; - } -#endif switch(padding) { case 1: fillRect(padXc,poY,padX-cwidth,cheight, textbgcolor); @@ -5091,9 +4645,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 if((padX>sumX) && (textcolor!=textbgcolor)) { int16_t padXc = poX+sumX; // Maximum left side padding -#ifdef LOAD_GFXFF - if ((font == 1) && (gfxFont)) poY -= glyph_ab; -#endif drawRect(poX,poY,sumX,cheight, TFT_GREEN); switch(padding) { case 1: @@ -5117,52 +4668,6 @@ return sumX; } -/*************************************************************************************** -** Function name: drawCentreString (deprecated, use setTextDatum()) -** Descriptions: draw string centred on dX -***************************************************************************************/ -int16_t TFT_eSPI::drawCentreString(const String& string, int32_t dX, int32_t poY, uint8_t font) -{ - int16_t len = string.length() + 2; - char buffer[len]; - string.toCharArray(buffer, len); - return drawCentreString(buffer, dX, poY, font); -} - -int16_t TFT_eSPI::drawCentreString(const char *string, int32_t dX, int32_t poY, uint8_t font) -{ - uint8_t tempdatum = textdatum; - int32_t sumX = 0; - textdatum = TC_DATUM; - sumX = drawString(string, dX, poY, font); - textdatum = tempdatum; - return sumX; -} - - -/*************************************************************************************** -** Function name: drawRightString (deprecated, use setTextDatum()) -** Descriptions: draw string right justified to dX -***************************************************************************************/ -int16_t TFT_eSPI::drawRightString(const String& string, int32_t dX, int32_t poY, uint8_t font) -{ - int16_t len = string.length() + 2; - char buffer[len]; - string.toCharArray(buffer, len); - return drawRightString(buffer, dX, poY, font); -} - -int16_t TFT_eSPI::drawRightString(const char *string, int32_t dX, int32_t poY, uint8_t font) -{ - uint8_t tempdatum = textdatum; - int16_t sumX = 0; - textdatum = TR_DATUM; - sumX = drawString(string, dX, poY, font); - textdatum = tempdatum; - return sumX; -} - - /*************************************************************************************** ** Function name: drawNumber ** Description: draw a long integer @@ -5265,52 +4770,6 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t } -/*************************************************************************************** -** Function name: setFreeFont -** Descriptions: Sets the GFX free font to use -***************************************************************************************/ - -#ifdef LOAD_GFXFF - -void TFT_eSPI::setFreeFont(const GFXfont *f) -{ - if (f == nullptr) { // Fix issue #400 (ESP32 crash) - setTextFont(1); // Use GLCD font - return; - } - - textfont = 1; - gfxFont = (GFXfont *)f; - - glyph_ab = 0; - glyph_bb = 0; - uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first); - - // Find the biggest above and below baseline offsets - for (uint16_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; - int8_t bb = pgm_read_byte(&glyph1->height) - ab; - if (bb > glyph_bb) glyph_bb = bb; - } -} - - -/*************************************************************************************** -** Function name: setTextFont -** Description: Set the font for the print stream -***************************************************************************************/ -void TFT_eSPI::setTextFont(uint8_t f) -{ - textfont = (f > 0) ? f : 1; // Don't allow font 0 - textfont = (f > 8) ? 1 : f; // Don't allow font > 8 - gfxFont = NULL; -} - -#else - - /*************************************************************************************** ** Function name: setFreeFont ** Descriptions: Sets the GFX free font to use @@ -5332,19 +4791,15 @@ void TFT_eSPI::setTextFont(uint8_t f) textfont = (f > 0) ? f : 1; // Don't allow font 0 textfont = (f > 8) ? 1 : f; // Don't allow font > 8 } -#endif - /*************************************************************************************** ** Function name: getSPIinstance ** Description: Get the instance of the SPI class ***************************************************************************************/ -#if !defined (TFT_PARALLEL_8_BIT) SPIClass& TFT_eSPI::getSPIinstance(void) { return spi; } -#endif /*************************************************************************************** @@ -5387,34 +4842,25 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.esp = -1; #endif -#if defined (SUPPORT_TRANSACTIONS) tft_settings.trans = true; -#else - tft_settings.trans = false; -#endif -#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) - tft_settings.serial = false; - tft_settings.tft_spi_freq = 0; -#else - tft_settings.serial = true; - tft_settings.tft_spi_freq = spi_write_speed * 1000000/100000; - #ifdef SPI_READ_FREQUENCY - tft_settings.tft_rd_freq = SPI_READ_FREQUENCY/100000; - #endif - #ifndef GENERIC_PROCESSOR - #ifdef TFT_SPI_PORT - tft_settings.port = TFT_SPI_PORT; - #else - tft_settings.port = 255; - #endif - #endif - #ifdef RP2040_PIO_SPI - tft_settings.interface = 0x10; +tft_settings.serial = true; +tft_settings.tft_spi_freq = spi_write_speed * 1000000/100000; +#ifdef SPI_READ_FREQUENCY + tft_settings.tft_rd_freq = SPI_READ_FREQUENCY/100000; +#endif +#ifndef GENERIC_PROCESSOR + #ifdef TFT_SPI_PORT + tft_settings.port = TFT_SPI_PORT; #else - tft_settings.interface = 0x0; + tft_settings.port = 255; #endif #endif +#ifdef RP2040_PIO_SPI + tft_settings.interface = 0x10; +#else + tft_settings.interface = 0x0; +#endif #if defined(TFT_SPI_OVERLAP) tft_settings.overlap = true; @@ -5494,26 +4940,6 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.pin_tft_rst = -1; #endif -#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) - tft_settings.pin_tft_d0 = TFT_D0; - tft_settings.pin_tft_d1 = TFT_D1; - tft_settings.pin_tft_d2 = TFT_D2; - tft_settings.pin_tft_d3 = TFT_D3; - tft_settings.pin_tft_d4 = TFT_D4; - tft_settings.pin_tft_d5 = TFT_D5; - tft_settings.pin_tft_d6 = TFT_D6; - tft_settings.pin_tft_d7 = TFT_D7; -#else - tft_settings.pin_tft_d0 = -1; - tft_settings.pin_tft_d1 = -1; - tft_settings.pin_tft_d2 = -1; - tft_settings.pin_tft_d3 = -1; - tft_settings.pin_tft_d4 = -1; - tft_settings.pin_tft_d5 = -1; - tft_settings.pin_tft_d6 = -1; - tft_settings.pin_tft_d7 = -1; -#endif - #if defined (TFT_BL) tft_settings.pin_tft_led = TFT_BL; #endif @@ -5522,25 +4948,3115 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.pin_tft_led_on = TFT_BACKLIGHT_ON; #endif -#if defined (TOUCH_CS) tft_settings.pin_tch_cs = TOUCH_CS; tft_settings.tch_spi_freq = SPI_TOUCH_FREQUENCY/100000; -#else - tft_settings.pin_tch_cs = -1; - tft_settings.tch_spi_freq = 0; -#endif +} + +void TFT_eSPI::loadFont(const uint8_t array[]) +{ + if (array == nullptr) return; + fontPtr = (uint8_t*) array; + loadFont("", false); +} + +void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) +{ + fontFS = ffs; + loadFont(fontName, false); +} + +void TFT_eSPI::loadFont(String fontName, bool flash) +{ + /* + The vlw font format does not appear to be documented anywhere, so some reverse + engineering has been applied! + + Header of vlw file comprises 6 uint32_t parameters (24 bytes total): + 1. The gCount (number of character glyphs) + 2. A version number (0xB = 11 for the one I am using) + 3. The font size (in points, not pixels) + 4. Deprecated mboxY parameter (typically set to 0) + 5. Ascent in pixels from baseline to top of "d" + 6. Descent in pixels from baseline to bottom of "p" + + Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes): + 1. Glyph Unicode stored as a 32-bit value + 2. Height of bitmap bounding box + 3. Width of bitmap bounding box + 4. gxAdvance for cursor (setWidth in Processing) + 5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up) + 6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left) + 7. padding value, typically 0 + + The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file. + Each pixel is 1 byte, an 8-bit Alpha value which represents the transparency from + 0xFF foreground colour, 0x00 background. The library uses a linear interpolation + between the foreground and background RGB component colours. e.g. + pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255 + To gain a performance advantage fixed point arithmetic is used with rounding and + division by 256 (shift right 8 bits is faster). + + After the bitmaps is: + 1 byte for font name string length (excludes null) + a zero terminated character string giving the font name + 1 byte for Postscript name string length + a zero/one terminated character string giving the font name + last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) + + + Glyph bitmap example is: + // Cursor coordinate positions for this and next character are marked by 'C' + // C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position + // | | + // | | ascent is top of "d", descent is bottom of "p" + // +-- gdX --+ ascent + // | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap + // | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of + // | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX) + // | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions + // | | .@@@.....@@@@ | | + // | gHeight ....@@@@@..@@ + + <-- baseline + // | | ...........@@ | + // | | ...........@@ | gdY is the offset to the top edge of the bitmap + // | | .@@.......@@. descent plot top edge of bitmap at (cursorY + ascent - gdY) + // | + 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 + + */ + + if (fontLoaded) unloadFont(); + + if (fontName == "") fs_font = false; + else { fontPtr = nullptr; fs_font = true; } + + if (fs_font) { + spiffs = flash; // true if font is in SPIFFS + + if(spiffs) fontFS = SPIFFS; + + // Avoid a crash on the ESP32 if the file does not exist + if (fontFS.exists("/" + fontName + ".vlw") == false) { + Serial.println("Font file " + fontName + " not found!"); + return; + } + + fontFile = fontFS.open( "/" + fontName + ".vlw", "r"); + + if(!fontFile) return; + + fontFile.seek(0, fs::SeekSet); + } + + gFont.gArray = (const uint8_t*)fontPtr; + + gFont.gCount = (uint16_t)readInt32(); // glyph count in file + readInt32(); // vlw encoder version - discard + gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels + readInt32(); // discard + gFont.ascent = (uint16_t)readInt32(); // top of "d" + gFont.descent = (uint16_t)readInt32(); // bottom of "p" + + // These next gFont values might be updated when the Metrics are fetched + gFont.maxAscent = gFont.ascent; // Determined from metrics + gFont.maxDescent = gFont.descent; // Determined from metrics + gFont.yAdvance = gFont.ascent + gFont.descent; + gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width + + fontLoaded = true; + + // Fetch the metrics for each glyph + loadMetrics(); } -//////////////////////////////////////////////////////////////////////////////////////// -#ifdef TOUCH_CS - #include "Extensions/Touch.cpp" +void TFT_eSPI::loadMetrics(void) +{ + uint32_t headerPtr = 24; + uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; + + { + gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16-bit Basic Multilingual Plane (0-FFFF) + gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph + gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph + gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor + gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character + gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X + gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file + } + + if (fs_font) fontFile.seek(headerPtr, fs::SeekSet); + + uint16_t gNum = 0; + + while (gNum < gFont.gCount) + { + gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value + gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph + gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph + gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor + gdY[gNum] = (int16_t)readInt32(); // y delta from baseline + gdX[gNum] = (int8_t)readInt32(); // x delta from cursor + readInt32(); // ignored + + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]); + + // Different glyph sets have different ascent values not always based on "d", so we could get + // the maximum glyph ascent by checking all characters. BUT this method can generate bad values + // for non-existent glyphs, so we will reply on processing for the value and disable this code for now... + /* + if (gdY[gNum] > gFont.maxAscent) + { + // Try to avoid UTF coding values and characters that tend to give duff values + if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0)) + { + gFont.maxAscent = gdY[gNum]; +#ifdef SHOW_ASCENT_DESCENT + Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent); +#endif + } + } + */ + + // Different glyph sets have different descent values not always based on "p", so get maximum glyph descent + if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent) + { + // Avoid UTF coding values and characters that tend to give duff values + if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF)) + { + gFont.maxDescent = gHeight[gNum] - gdY[gNum]; + } + } + + gBitmap[gNum] = bitmapPtr; + + bitmapPtr += gWidth[gNum] * gHeight[gNum]; + + gNum++; + yield(); + } + + gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; + + gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width +} + + +/*************************************************************************************** +** Function name: deleteMetrics +** Description: Delete the old glyph metrics and free up the memory +*************************************************************************************x*/ +void TFT_eSPI::unloadFont( void ) +{ + if (gUnicode) + { + free(gUnicode); + gUnicode = NULL; + } + + if (gHeight) + { + free(gHeight); + gHeight = NULL; + } + + if (gWidth) + { + free(gWidth); + gWidth = NULL; + } + + if (gxAdvance) + { + free(gxAdvance); + gxAdvance = NULL; + } + + if (gdY) + { + free(gdY); + gdY = NULL; + } + + if (gdX) + { + free(gdX); + gdX = NULL; + } + + if (gBitmap) + { + free(gBitmap); + gBitmap = NULL; + } + + gFont.gArray = nullptr; + + if (fs_font && fontFile) fontFile.close(); + + fontLoaded = false; +} + + +/*************************************************************************************** +** Function name: readInt32 +** Description: Get a 32-bit integer from the font file +*************************************************************************************x*/ +uint32_t TFT_eSPI::readInt32(void) +{ + uint32_t val = 0; + + if (fs_font) { + val = (uint32_t)fontFile.read() << 24; + val |= (uint32_t)fontFile.read() << 16; + val |= (uint32_t)fontFile.read() << 8; + val |= (uint32_t)fontFile.read(); + } + else + { + val = (uint32_t)pgm_read_byte(fontPtr++) << 24; + val |= (uint32_t)pgm_read_byte(fontPtr++) << 16; + val |= (uint32_t)pgm_read_byte(fontPtr++) << 8; + val |= (uint32_t)pgm_read_byte(fontPtr++); + } + + return val; +} + +bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) +{ + for (uint16_t i = 0; i < gFont.gCount; i++) + { + if (gUnicode[i] == unicode) + { + *index = i; + return true; + } + } + return false; +} + +void TFT_eSPI::drawGlyph(uint16_t code) +{ + uint16_t fg = textcolor; + uint16_t bg = textbgcolor; + + // Check if cursor has moved + if (last_cursor_x != cursor_x) + { + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; + } + + if (code < 0x21) + { + if (code == 0x20) { + if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); + cursor_x += gFont.spaceWidth; + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; + return; + } + + if (code == '\n') { + cursor_x = 0; + bg_cursor_x = 0; + last_cursor_x = 0; + cursor_y += gFont.yAdvance; + if (textwrapY && (cursor_y >= height())) cursor_y = 0; + return; + } + } + + uint16_t gNum = 0; + bool found = getUnicodeIndex(code, &gNum); + + if (found) + { + + if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width())) + { + cursor_y += gFont.yAdvance; + cursor_x = 0; + bg_cursor_x = 0; + } + if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; + if (cursor_x == 0) cursor_x -= gdX[gNum]; + + uint8_t* pbuffer = nullptr; + const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + + if (fs_font) + { + fontFile.seek(gBitmap[gNum], fs::SeekSet); + pbuffer = (uint8_t*)malloc(gWidth[gNum]); + } + + int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; + int16_t cx = cursor_x + gdX[gNum]; + + // if (cx > width() && bg_cursor_x > width()) return; + // if (cursor_y > height()) return; + + int16_t fxs = cx; + uint32_t fl = 0; + int16_t bxs = cx; + uint32_t bl = 0; + int16_t bx = 0; + uint8_t pixel; + + startWrite(); // Avoid slow ESP32 transaction overhead for every pixel + + int16_t fillwidth = 0; + int16_t fillheight = 0; + + // Fill area above glyph + if (_fillbg) { + fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; + if (fillwidth > 0) { + fillheight = gFont.maxAscent - gdY[gNum]; + // Could be negative + if (fillheight > 0) { + fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); + } + } + else { + // Could be negative + fillwidth = 0; + } + + // Fill any area to left of glyph + if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); + // Set x position in glyph area where background starts + if (bg_cursor_x > cx) bx = bg_cursor_x - cx; + // Fill any area to right of glyph + if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) { + fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); + } + } + + for (int32_t y = 0; y < gHeight[gNum]; y++) + { + if (fs_font) { + if (spiffs) + { + fontFile.read(pbuffer, gWidth[gNum]); + //Serial.println("SPIFFS"); + } + else + { + endWrite(); // Release SPI for SD card transaction + fontFile.read(pbuffer, gWidth[gNum]); + startWrite(); // Re-start SPI for TFT transaction + //Serial.println("Not SPIFFS"); + } + } + + for (int32_t x = 0; x < gWidth[gNum]; x++) + { + if (fs_font) pixel = pbuffer[x]; + else + pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + + if (pixel) + { + if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } + if (pixel != 0xFF) + { + if (fl) { + if (fl==1) drawPixel(fxs, y + cy, fg); + else drawFastHLine( fxs, y + cy, fl, fg); + fl = 0; + } + if (getColor) bg = getColor(x + cx, y + cy); + drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg)); + } + else + { + if (fl==0) fxs = x + cx; + fl++; + } + } + else + { + if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } + if (_fillbg) { + if (x >= bx) { + if (bl==0) bxs = x + cx; + bl++; + } + } + } + } + if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } + if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } + } + + // Fill area below glyph + if (fillwidth > 0) { + fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); + if (fillheight > 0) { + fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); + } + } + + if (pbuffer) free(pbuffer); + cursor_x += gxAdvance[gNum]; + endWrite(); + } + else + { + // Point code not in font so draw a rectangle and move on cursor + drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); + cursor_x += gFont.spaceWidth + 1; + } + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; +} + +/*************************************************************************************** +** Function name: showFont +** Description: Page through all characters in font, td ms between screens +*************************************************************************************x*/ +void TFT_eSPI::showFont(uint32_t td) +{ + if(!fontLoaded) return; + + int16_t cursorX = width(); // Force start of new page to initialise cursor + int16_t cursorY = height();// for the first character + uint32_t timeDelay = 0; // No delay before first page + + fillScreen(textbgcolor); + + for (uint16_t i = 0; i < gFont.gCount; i++) { + // Check if this will need a new screen + if (cursorX + gdX[i] + gWidth[i] >= width()) { + cursorX = -gdX[i]; + + cursorY += gFont.yAdvance; + if (cursorY + gFont.maxAscent + gFont.descent >= height()) { + cursorX = -gdX[i]; + cursorY = 0; + delay(timeDelay); + timeDelay = td; + fillScreen(textbgcolor); + } + } + + setCursor(cursorX, cursorY); + drawGlyph(gUnicode[i]); + cursorX += gxAdvance[i]; + yield(); + } + + delay(timeDelay); + fillScreen(textbgcolor); +} + +// The following touch screen support code by maxpautsch was merged 1/10/17 +// https://github.com/maxpautsch + +// A demo is provided in examples Generic folder + +// Additions by Bodmer to double sample, use Z value to improve detection reliability +// and to correct rotation handling + +// See license in root directory. + +// Define a default pressure threshold +#ifndef Z_THRESHOLD + #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches #endif -#include "Extensions/Sprite.cpp" +/*************************************************************************************** +** Function name: begin_touch_read_write - was spi_begin_touch +** Description: Start transaction and select touch controller +***************************************************************************************/ +// The touch controller has a low SPI clock rate +inline void TFT_eSPI::begin_touch_read_write(void){ + dmaWait(); + CS_H; // Just in case it has been left low + if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} + SET_BUS_READ_MODE; + digitalWrite(TOUCH_CS, LOW); +} -#ifdef SMOOTH_FONT - #include "Extensions/Smooth_font.cpp" -#endif -//////////////////////////////////////////////////////////////////////////////////////// +/*************************************************************************************** +** Function name: end_touch_read_write - was spi_end_touch +** Description: End transaction and deselect touch controller +***************************************************************************************/ +inline void TFT_eSPI::end_touch_read_write(void){ + digitalWrite(TOUCH_CS, HIGH); + if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} +} +/*************************************************************************************** +** Function name: Legacy - deprecated +** Description: Start/end transaction +***************************************************************************************/ +void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();} +void TFT_eSPI::spi_end_touch() { end_touch_read_write();} + +/*************************************************************************************** +** Function name: getTouchRaw +** Description: read raw touch position. Always returns true. +***************************************************************************************/ +uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){ + uint16_t tmp; + + begin_touch_read_write(); + + // Start YP sample request for x position, read 4 times and keep last sample + spi.transfer(0xd0); // Start new YP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0xd0); // Read last 8 bits and start new YP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0xd0); // Read last 8 bits and start new YP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0xd0); // Read last 8 bits and start new YP conversion + + tmp = spi.transfer(0); // Read first 8 bits + tmp = tmp <<5; + tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion + + *x = tmp; + + // Start XP sample request for y position, read 4 times and keep last sample + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + spi.transfer(0); // Read first 8 bits + spi.transfer(0x90); // Read last 8 bits and start new XP conversion + + tmp = spi.transfer(0); // Read first 8 bits + tmp = tmp <<5; + tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits + + *y = tmp; + + end_touch_read_write(); + + return true; +} + +/*************************************************************************************** +** Function name: getTouchRawZ +** Description: read raw pressure on touchpad and return Z value. +***************************************************************************************/ +uint16_t TFT_eSPI::getTouchRawZ(void){ + + begin_touch_read_write(); + + // Z sample request + int16_t tz = 0xFFF; + spi.transfer(0xb0); // Start new Z1 conversion + tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion + tz -= spi.transfer16(0x00) >> 3; // Read Z2 + + end_touch_read_write(); + + if (tz == 4095) tz = 0; + + return (uint16_t)tz; +} + +/*************************************************************************************** +** Function name: validTouch +** Description: read validated position. Return false if not pressed. +***************************************************************************************/ +#define _RAWERR 20 // Deadband error allowed in successive position samples +uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ + uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2; + + // Wait until pressure stops increasing to debounce pressure + uint16_t z1 = 1; + uint16_t z2 = 0; + while (z1 > z2) + { + z2 = z1; + z1 = getTouchRawZ(); + delay(1); + } + + // Serial.print("Z = ");Serial.println(z1); + + if (z1 <= threshold) return false; + + getTouchRaw(&x_tmp,&y_tmp); + + // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp); + // Serial.print(", Z = ");Serial.println(z1); + + delay(1); // Small delay to the next sample + if (getTouchRawZ() <= threshold) return false; + + delay(2); // Small delay to the next sample + getTouchRaw(&x_tmp2,&y_tmp2); + + // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2); + // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2)); + + if (abs(x_tmp - x_tmp2) > _RAWERR) return false; + if (abs(y_tmp - y_tmp2) > _RAWERR) return false; + + *x = x_tmp; + *y = y_tmp; + + return true; +} + +/*************************************************************************************** +** Function name: getTouch +** Description: read callibrated position. Return false if not pressed. +***************************************************************************************/ +uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ + uint16_t x_tmp, y_tmp; + + if (threshold<20) threshold = 20; + if (_pressTime > millis()) threshold=20; + + uint8_t n = 5; + uint8_t valid = 0; + while (n--) + { + if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;; + } + + if (valid<1) { _pressTime = 0; return false; } + + _pressTime = millis() + 50; + + convertRawXY(&x_tmp, &y_tmp); + + if (x_tmp >= _width || y_tmp >= _height) return false; + + _pressX = x_tmp; + _pressY = y_tmp; + *x = _pressX; + *y = _pressY; + return valid; +} + +/*************************************************************************************** +** Function name: convertRawXY +** Description: convert raw touch x,y values to screen coordinates +***************************************************************************************/ +void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y) +{ + uint16_t x_tmp = *x, y_tmp = *y, xx, yy; + + if(!touchCalibration_rotate){ + xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1; + yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1; + if(touchCalibration_invert_x) + xx = _width - xx; + if(touchCalibration_invert_y) + yy = _height - yy; + } else { + xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1; + yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1; + if(touchCalibration_invert_x) + xx = _width - xx; + if(touchCalibration_invert_y) + yy = _height - yy; + } + *x = xx; + *y = yy; +} + +/*************************************************************************************** +** Function name: calibrateTouch +** Description: generates calibration parameters for touchscreen. +***************************************************************************************/ +void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){ + int16_t values[] = {0,0,0,0,0,0,0,0}; + uint16_t x_tmp, y_tmp; + + + + for(uint8_t i = 0; i<4; i++){ + fillRect(0, 0, size+1, size+1, color_bg); + fillRect(0, _height-size-1, size+1, size+1, color_bg); + fillRect(_width-size-1, 0, size+1, size+1, color_bg); + fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg); + + if (i == 5) break; // used to clear the arrows + + switch (i) { + case 0: // up left + drawLine(0, 0, 0, size, color_fg); + drawLine(0, 0, size, 0, color_fg); + drawLine(0, 0, size , size, color_fg); + break; + case 1: // bot left + drawLine(0, _height-size-1, 0, _height-1, color_fg); + drawLine(0, _height-1, size, _height-1, color_fg); + drawLine(size, _height-size-1, 0, _height-1 , color_fg); + break; + case 2: // up right + drawLine(_width-size-1, 0, _width-1, 0, color_fg); + drawLine(_width-size-1, size, _width-1, 0, color_fg); + drawLine(_width-1, size, _width-1, 0, color_fg); + break; + case 3: // bot right + drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg); + drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg); + drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg); + break; + } + + // user has to get the chance to release + if(i>0) delay(1000); + + for(uint8_t j= 0; j<8; j++){ + // Use a lower detect threshold as corners tend to be less sensitive + while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2)); + values[i*2 ] += x_tmp; + values[i*2+1] += y_tmp; + } + values[i*2 ] /= 8; + values[i*2+1] /= 8; + } + + + // from case 0 to case 1, the y value changed. + // If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched. + touchCalibration_rotate = false; + if(abs(values[0]-values[2]) > abs(values[1]-values[3])){ + touchCalibration_rotate = true; + touchCalibration_x0 = (values[1] + values[3])/2; // calc min x + touchCalibration_x1 = (values[5] + values[7])/2; // calc max x + touchCalibration_y0 = (values[0] + values[4])/2; // calc min y + touchCalibration_y1 = (values[2] + values[6])/2; // calc max y + } else { + touchCalibration_x0 = (values[0] + values[2])/2; // calc min x + touchCalibration_x1 = (values[4] + values[6])/2; // calc max x + touchCalibration_y0 = (values[1] + values[5])/2; // calc min y + touchCalibration_y1 = (values[3] + values[7])/2; // calc max y + } + + // in addition, the touch screen axis could be in the opposite direction of the TFT axis + touchCalibration_invert_x = false; + if(touchCalibration_x0 > touchCalibration_x1){ + values[0]=touchCalibration_x0; + touchCalibration_x0 = touchCalibration_x1; + touchCalibration_x1 = values[0]; + touchCalibration_invert_x = true; + } + touchCalibration_invert_y = false; + if(touchCalibration_y0 > touchCalibration_y1){ + values[0]=touchCalibration_y0; + touchCalibration_y0 = touchCalibration_y1; + touchCalibration_y1 = values[0]; + touchCalibration_invert_y = true; + } + + // pre calculate + touchCalibration_x1 -= touchCalibration_x0; + touchCalibration_y1 -= touchCalibration_y0; + + if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; + if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; + if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; + if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; + + // export parameters, if pointer valid + if(parameters != NULL){ + parameters[0] = touchCalibration_x0; + parameters[1] = touchCalibration_x1; + parameters[2] = touchCalibration_y0; + parameters[3] = touchCalibration_y1; + parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2); + } +} + + +/*************************************************************************************** +** Function name: setTouch +** Description: imports calibration parameters for touchscreen. +***************************************************************************************/ +void TFT_eSPI::setTouch(uint16_t *parameters){ + touchCalibration_x0 = parameters[0]; + touchCalibration_x1 = parameters[1]; + touchCalibration_y0 = parameters[2]; + touchCalibration_y1 = parameters[3]; + + if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; + if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; + if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; + if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; + + touchCalibration_rotate = parameters[4] & 0x01; + touchCalibration_invert_x = parameters[4] & 0x02; + touchCalibration_invert_y = parameters[4] & 0x04; +} + +TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) +{ + _tft = tft; // Pointer to tft class so we can call member functions + + _iwidth = 0; // Initialise width and height to 0 (it does not exist yet) + _iheight = 0; + _bpp = 16; + _swapBytes = false; // Do not swap pushImage colour bytes by default + + _created = false; + _vpOoB = true; + + _xs = 0; // window bounds for pushColor + _ys = 0; + _xe = 0; + _ye = 0; + + _xptr = 0; // pushColor coordinate + _yptr = 0; + + _colorMap = nullptr; + + // Ensure end_tft_write() does nothing in inherited functions. + lockTransaction = true; +} + + +/*************************************************************************************** +** Function name: createSprite +** Description: Create a sprite (bitmap) of defined width and height +***************************************************************************************/ +// cast returned value to (uint8_t*) for 8-bit or (uint16_t*) for 16-bit colours +void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) +{ + + if ( _created ) return _img8_1; + + if ( w < 1 || h < 1 ) return nullptr; + + _iwidth = _dwidth = _bitwidth = w; + _iheight = _dheight = h; + + cursor_x = 0; + cursor_y = 0; + + // Default scroll rectangle and gap fill colour + _sx = 0; + _sy = 0; + _sw = w; + _sh = h; + _scolor = TFT_BLACK; + + _img8 = (uint8_t*) callocSprite(w, h, frames); + _img8_1 = _img8; + _img8_2 = _img8; + _img = (uint16_t*) _img8; + _img4 = _img8; + + if ( (_bpp == 16) && (frames > 1) ) { + _img8_2 = _img8 + (w * h * 2 + 1); + } + + // ESP32 only 16bpp check + //if (esp_ptr_dma_capable(_img8_1)) Serial.println("DMA capable Sprite pointer _img8_1"); + //else Serial.println("Not a DMA capable Sprite pointer _img8_1"); + //if (esp_ptr_dma_capable(_img8_2)) Serial.println("DMA capable Sprite pointer _img8_2"); + //else Serial.println("Not a DMA capable Sprite pointer _img8_2"); + + if ( (_bpp == 8) && (frames > 1) ) { + _img8_2 = _img8 + (w * h + 1); + } + + // This is to make it clear what pointer size is expected to be used + // but casting in the user sketch is needed due to the use of void* + if ( (_bpp == 1) && (frames > 1) ) + { + w = (w+7) & 0xFFF8; + _img8_2 = _img8 + ( (w>>3) * h + 1 ); + } + + if (_img8) + { + _created = true; + if ( (_bpp == 4) && (_colorMap == nullptr)) createPalette(default_4bit_palette); + + rotation = 0; + setViewport(0, 0, _dwidth, _dheight); + setPivot(_iwidth/2, _iheight/2); + return _img8_1; + } + + return nullptr; +} + +/*************************************************************************************** +** Function name: getPointer +** Description: Returns pointer to start of sprite memory area +***************************************************************************************/ +void* TFT_eSprite::getPointer(void) +{ + if (!_created) return nullptr; + return _img8_1; +} + + +/*************************************************************************************** +** Function name: created +** Description: Returns true if sprite has been created +***************************************************************************************/ +bool TFT_eSprite::created(void) +{ + return _created; +} + + +/*************************************************************************************** +** Function name: ~TFT_eSprite +** Description: Class destructor +***************************************************************************************/ +TFT_eSprite::~TFT_eSprite(void) +{ + deleteSprite(); + if(fontLoaded) unloadFont(); +} + + +/*************************************************************************************** +** Function name: callocSprite +** Description: Allocate a memory area for the Sprite and return pointer +***************************************************************************************/ +void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames) +{ + // Add one extra "off screen" pixel to point out-of-bounds setWindow() coordinates + // this means push/writeColor functions do not need additional bounds checks and + // hence will run faster in normal circumstances. + uint8_t* ptr8 = nullptr; + + if (frames > 2) frames = 2; // Currently restricted to 2 frame buffers + if (frames < 1) frames = 1; + + if (_bpp == 16) + { + { + ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t)); + //Serial.println("Normal RAM"); + } + } + + else if (_bpp == 8) + { + ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint8_t)); + } + + else if (_bpp == 4) + { + w = (w+1) & 0xFFFE; // width needs to be multiple of 2, with an extra "off screen" pixel + _iwidth = w; + ptr8 = ( uint8_t*) calloc(((frames * w * h) >> 1) + frames, sizeof(uint8_t)); + } + + else // Must be 1 bpp + { + //_dwidth Display width+height in pixels always in rotation 0 orientation + //_dheight Not swapped for sprite rotations + // Note: for 1bpp _iwidth and _iheight are swapped during Sprite rotations + + w = (w+7) & 0xFFF8; // width should be the multiple of 8 bits to be compatible with epdpaint + _iwidth = w; // _iwidth is rounded up to be multiple of 8, so might not be = _dwidth + _bitwidth = w; // _bitwidth will not be rotated whereas _iwidth may be + + ptr8 = ( uint8_t*) calloc(frames * (w>>3) * h + frames, sizeof(uint8_t)); + } + + return ptr8; +} + + +/*************************************************************************************** +** Function name: createPalette (from RAM array) +** Description: Set a palette for a 4-bit per pixel sprite +***************************************************************************************/ +void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) +{ + if (!_created) return; + + if (colorMap == nullptr) + { + // Create a color map using the default FLASH map + createPalette(default_4bit_palette); + return; + } + + // Allocate and clear memory for 16 color map + if (_colorMap == nullptr) _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); + + if (colors > 16) colors = 16; + + // Copy map colors + for (uint8_t i = 0; i < colors; i++) + { + _colorMap[i] = colorMap[i]; + } +} + + +/*************************************************************************************** +** Function name: createPalette (from FLASH array) +** Description: Set a palette for a 4-bit per pixel sprite +***************************************************************************************/ +void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) +{ + if (!_created) return; + + if (colorMap == nullptr) + { + // Create a color map using the default FLASH map + colorMap = default_4bit_palette; + } + + // Allocate and clear memory for 16 color map + if (_colorMap == nullptr) _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); + + if (colors > 16) colors = 16; + + // Copy map colors + for (uint8_t i = 0; i < colors; i++) + { + _colorMap[i] = pgm_read_word(colorMap++); + } +} + + +/*************************************************************************************** +** Function name: frameBuffer +** Description: For 1 bpp Sprites, select the frame used for graphics +***************************************************************************************/ +// Frames are numbered 1 and 2 +void* TFT_eSprite::frameBuffer(int8_t f) +{ + if (!_created) return nullptr; + + if ( f == 2 ) _img8 = _img8_2; + else _img8 = _img8_1; + + if (_bpp == 16) _img = (uint16_t*)_img8; + + //if (_bpp == 8) _img8 = _img8; + + if (_bpp == 4) _img4 = _img8; + + return _img8; +} + + +/*************************************************************************************** +** Function name: setColorDepth +** Description: Set bits per pixel for colour (1, 8 or 16) +***************************************************************************************/ +void* TFT_eSprite::setColorDepth(int8_t b) +{ + // Do not re-create the sprite if the colour depth does not change + if (_bpp == b) return _img8_1; + + // Validate the new colour depth + if ( b > 8 ) _bpp = 16; // Bytes per pixel + else if ( b > 4 ) _bpp = 8; + else if ( b > 1 ) _bpp = 4; + else _bpp = 1; + + // Can't change an existing sprite's colour depth so delete and create a new one + if (_created) { + deleteSprite(); + return createSprite(_dwidth, _dheight); + } + + return nullptr; +} + + +/*************************************************************************************** +** Function name: getColorDepth +** Description: Get bits per pixel for colour (1, 8 or 16) +***************************************************************************************/ +int8_t TFT_eSprite::getColorDepth(void) +{ + if (_created) return _bpp; + else return 0; +} + + +/*************************************************************************************** +** Function name: setBitmapColor +** Description: Set the 1bpp foreground foreground and background colour +***************************************************************************************/ +void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b) +{ + if (c == b) b = ~c; + _tft->bitmap_fg = c; + _tft->bitmap_bg = b; +} + + +/*************************************************************************************** +** Function name: setPaletteColor +** Description: Set the 4bpp palette color at the given index +***************************************************************************************/ +void TFT_eSprite::setPaletteColor(uint8_t index, uint16_t color) +{ + if (_colorMap == nullptr || index > 15) return; // out of bounds + + _colorMap[index] = color; +} + + +/*************************************************************************************** +** Function name: getPaletteColor +** Description: Return the palette color at 4bpp index, or 0 on error. +***************************************************************************************/ +uint16_t TFT_eSprite::getPaletteColor(uint8_t index) +{ + if (_colorMap == nullptr || index > 15) return 0; // out of bounds + + return _colorMap[index]; +} + + +/*************************************************************************************** +** Function name: deleteSprite +** Description: Delete the sprite to free up memory (RAM) +***************************************************************************************/ +void TFT_eSprite::deleteSprite(void) +{ + if (_colorMap != nullptr) + { + free(_colorMap); + _colorMap = nullptr; + } + + if (_created) + { + free(_img8_1); + _img8 = nullptr; + _created = false; + _vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite + } +} + + +/*************************************************************************************** +** Function name: pushRotated - Fast fixed point integer maths version +** Description: Push rotated Sprite to TFT screen +***************************************************************************************/ +#define FP_SCALE 10 +bool TFT_eSprite::pushRotated(int16_t angle, uint32_t transp) +{ + if ( !_created || _tft->_vpOoB) return false; + + // Bounding box parameters + int16_t min_x; + int16_t min_y; + int16_t max_x; + int16_t max_y; + + // Get the bounding box of this rotated source Sprite relative to Sprite pivot + if ( !getRotatedBounds(angle, &min_x, &min_y, &max_x, &max_y) ) return false; + + uint16_t sline_buffer[max_x - min_x + 1]; + + int32_t xt = min_x - _tft->_xPivot; + int32_t yt = min_y - _tft->_yPivot; + uint32_t xe = _dwidth << FP_SCALE; + uint32_t ye = _dheight << FP_SCALE; + uint16_t tpcolor = (uint16_t)transp; + + if (transp != 0x00FFFFFF) { + if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; + tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes + } + _tft->startWrite(); // Avoid transaction overhead for every tft pixel + + // Scan destination bounding box and fetch transformed pixels from source Sprite + for (int32_t y = min_y; y <= max_y; y++, yt++) { + int32_t x = min_x; + uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); + uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); + + while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } + if (x == max_x) continue; + + uint32_t pixel_count = 0; + do { + uint32_t rp; + int32_t xp = xs >> FP_SCALE; + int32_t yp = ys >> FP_SCALE; + if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; } + else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } + if (transp != 0x00FFFFFF && tpcolor == rp) { + if (pixel_count) { + // TFT window is already clipped, so this is faster than pushImage() + _tft->setWindow(x - pixel_count, y, x - 1, y); + _tft->pushPixels(sline_buffer, pixel_count); + pixel_count = 0; + } + } + else { + sline_buffer[pixel_count++] = rp; + } + } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); + if (pixel_count) { + // TFT window is already clipped, so this is faster than pushImage() + _tft->setWindow(x - pixel_count, y, x - 1, y); + _tft->pushPixels(sline_buffer, pixel_count); + } + } + + _tft->endWrite(); // End transaction + + return true; +} + + +/*************************************************************************************** +** Function name: pushRotated - Fast fixed point integer maths version +** Description: Push a rotated copy of the Sprite to another Sprite +***************************************************************************************/ +// Not compatible with 4bpp +bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp) +{ + if ( !_created || _bpp == 4) return false; // Check this Sprite is created + if ( !spr->_created || spr->_bpp == 4) return false; // Ckeck destination Sprite is created + + // Bounding box parameters + int16_t min_x; + int16_t min_y; + int16_t max_x; + int16_t max_y; + + // Get the bounding box of this rotated source Sprite + if ( !getRotatedBounds(spr, angle, &min_x, &min_y, &max_x, &max_y) ) return false; + + uint16_t sline_buffer[max_x - min_x + 1]; + + int32_t xt = min_x - spr->_xPivot; + int32_t yt = min_y - spr->_yPivot; + uint32_t xe = _dwidth << FP_SCALE; + uint32_t ye = _dheight << FP_SCALE; + uint16_t tpcolor = (uint16_t)transp; + + if (transp != 0x00FFFFFF) { + if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; + tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes + } + + bool oldSwapBytes = spr->getSwapBytes(); + spr->setSwapBytes(false); + + // Scan destination bounding box and fetch transformed pixels from source Sprite + for (int32_t y = min_y; y <= max_y; y++, yt++) { + int32_t x = min_x; + uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); + uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); + + while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } + if (x == max_x) continue; + + uint32_t pixel_count = 0; + do { + uint32_t rp; + int32_t xp = xs >> FP_SCALE; + int32_t yp = ys >> FP_SCALE; + if (_bpp == 16) rp = _img[xp + yp * _iwidth]; + else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } + if (transp != 0x00FFFFFF && tpcolor == rp) { + if (pixel_count) { + spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); + pixel_count = 0; + } + } + else { + sline_buffer[pixel_count++] = rp; + } + } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); + if (pixel_count) spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); + } + spr->setSwapBytes(oldSwapBytes); + return true; +} + + +/*************************************************************************************** +** Function name: getRotatedBounds +** Description: Get TFT bounding box of a rotated Sprite wrt pivot +***************************************************************************************/ +bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, + int16_t *max_x, int16_t *max_y) +{ + // Get the bounding box of this rotated source Sprite relative to Sprite pivot + getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); + + // Move bounding box so source Sprite pivot coincides with TFT pivot + *min_x += _tft->_xPivot; + *max_x += _tft->_xPivot; + *min_y += _tft->_yPivot; + *max_y += _tft->_yPivot; + + // Return if bounding box is outside of TFT viewport + if (*min_x > _tft->_vpW) return false; + if (*min_y > _tft->_vpH) return false; + if (*max_x < _tft->_vpX) return false; + if (*max_y < _tft->_vpY) return false; + + // Clip bounding box to be within TFT viewport + if (*min_x < _tft->_vpX) *min_x = _tft->_vpX; + if (*min_y < _tft->_vpY) *min_y = _tft->_vpY; + if (*max_x > _tft->_vpW) *max_x = _tft->_vpW; + if (*max_y > _tft->_vpH) *max_y = _tft->_vpH; + + return true; +} + + +/*************************************************************************************** +** Function name: getRotatedBounds +** Description: Get destination Sprite bounding box of a rotated Sprite wrt pivot +***************************************************************************************/ +bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, + int16_t *max_x, int16_t *max_y) +{ + // Get the bounding box of this rotated source Sprite relative to Sprite pivot + getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); + + // Move bounding box so source Sprite pivot coincides with destination Sprite pivot + *min_x += spr->_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 to Sprite boundaries + // Clipping to a viewport will be done by destination Sprite pushImage function + 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(); + + return true; +} + + +/*************************************************************************************** +** Function name: rotatedBounds +** Description: Get bounding box of a rotated Sprite wrt pivot +***************************************************************************************/ +void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, + int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y) +{ + // Trig values for the rotation + float radAngle = -angle * 0.0174532925; // Convert degrees to radians + float sina = sin(radAngle); + float cosa = cos(radAngle); + + w -= xp; // w is now right edge coordinate relative to xp + h -= yp; // h is now bottom edge coordinate relative to yp + + // Calculate new corner coordinates + int16_t x0 = -xp * cosa - yp * sina; + int16_t y0 = xp * sina - yp * cosa; + + int16_t x1 = w * cosa - yp * sina; + int16_t y1 = -w * sina - yp * cosa; + + int16_t x2 = h * sina + w * cosa; + int16_t y2 = h * cosa - w * sina; + + int16_t x3 = h * sina - xp * cosa; + int16_t y3 = h * cosa + xp * sina; + + // Find bounding box extremes, enlarge box to accomodate rounding errors + *min_x = x0-2; + if (x1 < *min_x) *min_x = x1-2; + if (x2 < *min_x) *min_x = x2-2; + if (x3 < *min_x) *min_x = x3-2; + + *max_x = x0+2; + if (x1 > *max_x) *max_x = x1+2; + if (x2 > *max_x) *max_x = x2+2; + if (x3 > *max_x) *max_x = x3+2; + + *min_y = y0-2; + if (y1 < *min_y) *min_y = y1-2; + if (y2 < *min_y) *min_y = y2-2; + if (y3 < *min_y) *min_y = y3-2; + + *max_y = y0+2; + if (y1 > *max_y) *max_y = y1+2; + if (y2 > *max_y) *max_y = y2+2; + if (y3 > *max_y) *max_y = y3+2; + + _sinra = round(sina * (1<getSwapBytes(); + _tft->setSwapBytes(false); + _tft->pushImage(x, y, _dwidth, _dheight, _img ); + _tft->setSwapBytes(oldSwapBytes); + } + else if (_bpp == 4) + { + _tft->pushImage(x, y, _dwidth, _dheight, _img4, false, _colorMap); + } + else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8)); +} + + +/*************************************************************************************** +** Function name: pushSprite +** Description: Push the sprite to the TFT at x, y with transparent colour +***************************************************************************************/ +void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) +{ + if (!_created) return; + + if (_bpp == 16) + { + bool oldSwapBytes = _tft->getSwapBytes(); + _tft->setSwapBytes(false); + _tft->pushImage(x, y, _dwidth, _dheight, _img, transp ); + _tft->setSwapBytes(oldSwapBytes); + } + else if (_bpp == 8) + { + transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3); + _tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true); + } + else if (_bpp == 4) + { + _tft->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap); + } + else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false); +} + + +/*************************************************************************************** +** Function name: pushToSprite +** Description: Push the sprite to another sprite at x, y +***************************************************************************************/ +// Note: The following sprite to sprite colour depths are currently supported: +// Source Destination +// 16bpp -> 16bpp +// 16bpp -> 8bpp +// 8bpp -> 8bpp +// 4bpp -> 4bpp (note: color translation depends on the 2 sprites palette colors) +// 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) + +bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y) +{ + if (!_created) return false; + if (!dspr->created()) return false; + + // Check destination sprite compatibility + int8_t ds_bpp = dspr->getColorDepth(); + if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; + if (_bpp == 8 && ds_bpp != 8) return false; + if (_bpp == 4 && ds_bpp != 4) return false; + if (_bpp == 1 && ds_bpp != 1) return false; + + bool oldSwapBytes = dspr->getSwapBytes(); + dspr->setSwapBytes(false); + dspr->pushImage(x, y, _dwidth, _dheight, _img, _bpp); + dspr->setSwapBytes(oldSwapBytes); + + return true; +} + + +/*************************************************************************************** +** Function name: pushToSprite +** Description: Push the sprite to another sprite at x, y with transparent colour +***************************************************************************************/ +// Note: The following sprite to sprite colour depths are currently supported: +// Source Destination +// 16bpp -> 16bpp +// 16bpp -> 8bpp +// 8bpp -> 8bpp +// 1bpp -> 1bpp + +bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transp) +{ + if ( !_created || !dspr->_created) return false; // Check Sprites exist + + // Check destination sprite compatibility + int8_t ds_bpp = dspr->getColorDepth(); + if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; + if (_bpp == 8 && ds_bpp != 8) return false; + if (_bpp == 4 || ds_bpp == 4) return false; + if (_bpp == 1 && ds_bpp != 1) return false; + + bool oldSwapBytes = dspr->getSwapBytes(); + uint16_t sline_buffer[width()]; + + transp = transp>>8 | transp<<8; + + // Scan destination bounding box and fetch transformed pixels from source Sprite + for (int32_t ys = 0; ys < height(); ys++) { + int32_t ox = x; + uint32_t pixel_count = 0; + + for (int32_t xs = 0; xs < width(); xs++) { + uint16_t rp = 0; + if (_bpp == 16) rp = _img[xs + ys * width()]; + else { rp = readPixel(xs, ys); rp = rp>>8 | rp<<8; } + //dspr->drawPixel(xs, ys, rp); + + if (transp == rp) { + if (pixel_count) { + dspr->pushImage(ox, y, pixel_count, 1, sline_buffer); + ox += pixel_count; + pixel_count = 0; + } + ox++; + } + else { + sline_buffer[pixel_count++] = rp; + } + } + if (pixel_count) dspr->pushImage(ox, y, pixel_count, 1, sline_buffer); + y++; + } + dspr->setSwapBytes(oldSwapBytes); + return true; +} + + +/*************************************************************************************** +** Function name: pushSprite +** Description: Push a cropped sprite to the TFT at tx, ty +***************************************************************************************/ +bool TFT_eSprite::pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh) +{ + if (!_created) return false; + + // Perform window boundary checks and crop if needed + setWindow(sx, sy, sx + sw - 1, sy + sh - 1); + + /* These global variables are now populated for the sprite + _xs = x start coordinate + _ys = y start coordinate + _xe = x end coordinate (inclusive) + _ye = y end coordinate (inclusive) + */ + + // Calculate new sprite window bounding box width and height + sw = _xe - _xs + 1; + sh = _ye - _ys + 1; + + if (_ys >= _iheight) return false; + + if (_bpp == 16) + { + bool oldSwapBytes = _tft->getSwapBytes(); + _tft->setSwapBytes(false); + + // Check if a faster block copy to screen is possible + if ( sx == 0 && sw == _dwidth) + _tft->pushImage(tx, ty, sw, sh, _img + _iwidth * _ys ); + else // Render line by line + while (sh--) + _tft->pushImage(tx, ty++, sw, 1, _img + _xs + _iwidth * _ys++ ); + + _tft->setSwapBytes(oldSwapBytes); + } + else if (_bpp == 8) + { + // Check if a faster block copy to screen is possible + if ( sx == 0 && sw == _dwidth) + _tft->pushImage(tx, ty, sw, sh, _img8 + _iwidth * _ys, (bool)true ); + else // Render line by line + while (sh--) + _tft->pushImage(tx, ty++, sw, 1, _img8 + _xs + _iwidth * _ys++, (bool)true ); + } + else if (_bpp == 4) + { + // Check if a faster block copy to screen is possible + if ( sx == 0 && sw == _dwidth) + _tft->pushImage(tx, ty, sw, sh, _img4 + (_iwidth>>1) * _ys, false, _colorMap ); + else // Render line by line + { + int32_t ds = _xs&1; // Odd x start pixel + + int32_t de = 0; // Odd x end pixel + if ((sw > ds) && (_xe&1)) de = 1; + + uint32_t dm = 0; // Midsection pixel count + if (sw > (ds+de)) dm = sw - ds - de; + sw--; + + uint32_t yp = (_xs + ds + _iwidth * _ys)>>1; + _tft->startWrite(); + while (sh--) + { + if (ds) _tft->drawPixel(tx, ty, readPixel(_xs, _ys) ); + if (dm) _tft->pushImage(tx + ds, ty, dm, 1, _img4 + yp, false, _colorMap ); + if (de) _tft->drawPixel(tx + sw, ty, readPixel(_xe, _ys) ); + _ys++; + ty++; + yp += (_iwidth>>1); + } + _tft->endWrite(); + } + } + else // 1bpp + { + // Check if a faster block copy to screen is possible + if ( sx == 0 && sw == _dwidth) + _tft->pushImage(tx, ty, sw, sh, _img8 + (_bitwidth>>3) * _ys, (bool)false ); + else // Render line by line + { + _tft->startWrite(); + while (sh--) + { + _tft->pushImage(tx, ty++, sw, 1, _img8 + (_bitwidth>>3) * _ys++, (bool)false ); + } + _tft->endWrite(); + } + } + + return true; +} + + +/*************************************************************************************** +** Function name: readPixelValue +** Description: Read the color map index of a pixel at defined coordinates +***************************************************************************************/ +uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) +{ + if (_vpOoB || !_created) return 0xFF; + + x+= _xDatum; + y+= _yDatum; + + // Range checking + if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return 0xFF; + + if (_bpp == 16) + { + // Return the pixel colour + return readPixel(x - _xDatum, y - _yDatum); + } + + if (_bpp == 8) + { + // Return the pixel byte value + return _img8[x + y * _iwidth]; + } + + if (_bpp == 4) + { + if (x >= _dwidth) return 0xFF; + if ((x & 0x01) == 0) + return _img4[((x+y*_iwidth)>>1)] >> 4; // even index = bits 7 .. 4 + else + return _img4[((x+y*_iwidth)>>1)] & 0x0F; // odd index = bits 3 .. 0. + } + + if (_bpp == 1) + { + // Note: _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) + if (rotation == 1) + { + uint16_t tx = x; + x = _dheight - y - 1; + y = tx; + } + else if (rotation == 2) + { + x = _dwidth - x - 1; + y = _dheight - y - 1; + } + else if (rotation == 3) + { + uint16_t tx = x; + x = y; + y = _dwidth - tx - 1; + } + // Return 1 or 0 + return (_img8[(x + y * _bitwidth)>>3] >> (7-(x & 0x7))) & 0x01; + } + + return 0; +} + +/*************************************************************************************** +** Function name: readPixel +** Description: Read 565 colour of a pixel at defined coordinates +***************************************************************************************/ +uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) +{ + if (_vpOoB || !_created) return 0xFFFF; + + x+= _xDatum; + y+= _yDatum; + + // Range checking + if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return 0xFFFF; + + if (_bpp == 16) + { + uint16_t color = _img[x + y * _iwidth]; + return (color >> 8) | (color << 8); + } + + if (_bpp == 8) + { + uint16_t color = _img8[x + y * _iwidth]; + if (color != 0) + { + uint8_t blue[] = {0, 11, 21, 31}; + color = (color & 0xE0)<<8 | (color & 0xC0)<<5 + | (color & 0x1C)<<6 | (color & 0x1C)<<3 + | blue[color & 0x03]; + } + return color; + } + + if (_bpp == 4) + { + if (x >= _dwidth) return 0xFFFF; + uint16_t color; + if ((x & 0x01) == 0) + color = _colorMap[_img4[((x+y*_iwidth)>>1)] >> 4]; // even index = bits 7 .. 4 + else + color = _colorMap[_img4[((x+y*_iwidth)>>1)] & 0x0F]; // odd index = bits 3 .. 0. + return color; + } + + // Note: Must be 1bpp + // _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) + if (rotation == 1) + { + uint16_t tx = x; + x = _dheight - y - 1; + y = tx; + } + else if (rotation == 2) + { + x = _dwidth - x - 1; + y = _dheight - y - 1; + } + else if (rotation == 3) + { + uint16_t tx = x; + x = y; + y = _dwidth - tx - 1; + } + + uint16_t color = (_img8[(x + y * _bitwidth)>>3] << (x & 0x7)) & 0x80; + + if (color) return _tft->bitmap_fg; + else return _tft->bitmap_bg; +} + + +/*************************************************************************************** +** Function name: pushImage +** Description: push image into a defined area of a sprite +***************************************************************************************/ +void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp) +{ + if (data == nullptr || !_created) return; + + PI_CLIP; + + if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite + { + // Pointer within original image + uint8_t *ptro = (uint8_t *)data + ((dx + dy * w) << 1); + // Pointer within sprite image + uint8_t *ptrs = (uint8_t *)_img + ((x + y * _iwidth) << 1); + + if(_swapBytes) + { + while (dh--) + { + // Fast copy with a 1 byte shift + memcpy(ptrs+1, ptro, (dw<<1) - 1); + // Now correct just the even numbered bytes + for (int32_t xp = 0; xp < (dw<<1); xp+=2) + { + ptrs[xp] = ptro[xp+1];; + } + ptro += w<<1; + ptrs += _iwidth<<1; + } + } + else + { + while (dh--) + { + memcpy(ptrs, ptro, dw<<1); + ptro += w << 1; + ptrs += _iwidth << 1; + } + } + } + else if (_bpp == 8 && sbpp == 8) // Plot a 8 bpp image into a 8 bpp Sprite + { + // Pointer within original image + uint8_t *ptro = (uint8_t *)data + (dx + dy * w); + // Pointer within sprite image + uint8_t *ptrs = (uint8_t *)_img + (x + y * _iwidth); + + while (dh--) + { + memcpy(ptrs, ptro, dw); + ptro += w; + ptrs += _iwidth; + } + } + else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite + { + uint16_t lastColor = 0; + uint8_t color8 = 0; + for (int32_t yp = dy; yp < dy + dh; yp++) + { + int32_t xyw = x + y * _iwidth; + int32_t dxypw = dx + yp * w; + for (int32_t xp = dx; xp < dx + dw; xp++) + { + uint16_t color = data[dxypw++]; + if (color != lastColor) { + // When data source is a sprite, the bytes are already swapped + if(!_swapBytes) color8 = (uint8_t)((color & 0xE0) | (color & 0x07)<<2 | (color & 0x1800)>>11); + else color8 = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + } + lastColor = color; + _img8[xyw++] = color8; + } + y++; + } + } + else if (_bpp == 4) + { + // The image is assumed to be 4-bit, where each byte corresponds to two pixels. + // much faster when aligned to a byte boundary, because the alternative is slower, requiring + // tedious bit operations. + + int sWidth = (_iwidth >> 1); + uint8_t *ptr = (uint8_t *)data; + + if ((x & 0x01) == 0 && (dx & 0x01) == 0 && (dw & 0x01) == 0) + { + x = (x >> 1) + y * sWidth; + dw = (dw >> 1); + dx = (dx >> 1) + dy * (w>>1); + while (dh--) + { + memcpy(_img4 + x, ptr + dx, dw); + dx += (w >> 1); + x += sWidth; + } + } + else // not optimized + { + for (int32_t yp = dy; yp < dy + dh; yp++) + { + int32_t ox = x; + for (int32_t xp = dx; xp < dx + dw; xp++) + { + uint32_t color; + if ((xp & 0x01) == 0) + color = (ptr[((xp+yp*w)>>1)] & 0xF0) >> 4; // even index = bits 7 .. 4 + else + color = ptr[((xp-1+yp*w)>>1)] & 0x0F; // odd index = bits 3 .. 0. + drawPixel(ox, y, color); + ox++; + } + y++; + } + } + } + + else // 1bpp + { + // Plot a 1bpp image into a 1bpp Sprite + uint32_t ww = (w+7)>>3; // Width of source image line in bytes + uint8_t *ptr = (uint8_t *)data; + for (int32_t yp = dy; yp < dy + dh; yp++) + { + uint32_t yw = yp * ww; // Byte starting the line containing source pixel + int32_t ox = x; + for (int32_t xp = dx; xp < dx + dw; xp++) + { + uint16_t readPixel = (ptr[(xp>>3) + yw] & (0x80 >> (xp & 0x7)) ); + drawPixel(ox++, y, readPixel); + } + y++; + } + } +} + + +/*************************************************************************************** +** Function name: pushImage +** Description: push 565 colour FLASH (PROGMEM) image into a defined area +***************************************************************************************/ +void TFT_eSprite::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 + if (data == nullptr || !_created) return; + + PI_CLIP; + + if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite + { + for (int32_t yp = dy; yp < dy + dh; yp++) + { + int32_t ox = x; + for (int32_t xp = dx; xp < dx + dw; xp++) + { + uint16_t color = pgm_read_word(data + xp + yp * w); + if(_swapBytes) color = color<<8 | color>>8; + _img[ox + y * _iwidth] = color; + ox++; + } + y++; + } + } + + else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite + { + for (int32_t yp = dy; yp < dy + dh; yp++) + { + int32_t ox = x; + for (int32_t xp = dx; xp < dx + dw; xp++) + { + uint16_t color = pgm_read_word(data + xp + yp * w); + if(_swapBytes) color = color<<8 | color>>8; + _img8[ox + y * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + ox++; + } + y++; + } + } + + else if (_bpp == 4) + { + #ifdef TFT_eSPI_DEBUG + Serial.println("TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) not implemented"); + #endif + return; + } + + else // Plot a 1bpp image into a 1bpp Sprite + { + x-= _xDatum; // Remove offsets, drawPixel will add + y-= _yDatum; + uint16_t bsw = (w+7) >> 3; // Width in bytes of source image line + uint8_t *ptr = ((uint8_t*)data) + dy * bsw; + + while (dh--) { + int32_t odx = dx; + int32_t ox = x; + while (odx < dx + dw) { + uint8_t pbyte = pgm_read_byte(ptr + (odx>>3)); + uint8_t mask = 0x80 >> (odx & 7); + while (mask) { + uint8_t p = pbyte & mask; + mask = mask >> 1; + drawPixel(ox++, y, p); + odx++; + } + } + ptr += bsw; + y++; + } + } +#endif // if ESP32 check +} + + +/*************************************************************************************** +** Function name: setWindow +** Description: Set the bounds of a window in the sprite +***************************************************************************************/ +// Intentionally not constrained to viewport area, does not manage 1bpp rotations +void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) +{ + if (x0 > x1) transpose(x0, x1); + if (y0 > y1) transpose(y0, y1); + + int32_t w = width(); + int32_t h = height(); + + if ((x0 >= w) || (x1 < 0) || (y0 >= h) || (y1 < 0)) + { // Point to that extra "off screen" pixel + _xs = 0; + _ys = _dheight; + _xe = 0; + _ye = _dheight; + } + else + { + if (x0 < 0) x0 = 0; + if (x1 >= w) x1 = w - 1; + if (y0 < 0) y0 = 0; + if (y1 >= h) y1 = h - 1; + + _xs = x0; + _ys = y0; + _xe = x1; + _ye = y1; + } + + _xptr = _xs; + _yptr = _ys; +} + + +/*************************************************************************************** +** Function name: pushColor +** Description: Send a new pixel to the set window +***************************************************************************************/ +void TFT_eSprite::pushColor(uint16_t color) +{ + if (!_created ) return; + + // Write the colour to RAM in set window + if (_bpp == 16) + _img [_xptr + _yptr * _iwidth] = (uint16_t) (color >> 8) | (color << 8); + + else if (_bpp == 8) + _img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + + else if (_bpp == 4) + { + uint8_t c = (uint8_t)color & 0x0F; + if ((_xptr & 0x01) == 0) { + _img4[(_xptr + _yptr * _iwidth)>>1] = (c << 4) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4 + } + else { + _img4[(_xptr + _yptr * _iwidth)>>1] = (_img4[(_xptr + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits + } + } + + else drawPixel(_xptr, _yptr, color); + + // Increment x + _xptr++; + + // Wrap on x and y to start, increment y if needed + if (_xptr > _xe) + { + _xptr = _xs; + _yptr++; + if (_yptr > _ye) _yptr = _ys; + } + +} + + +/*************************************************************************************** +** Function name: pushColor +** Description: Send a "len" new pixels to the set window +***************************************************************************************/ +void TFT_eSprite::pushColor(uint16_t color, uint32_t len) +{ + if (!_created ) return; + + uint16_t pixelColor; + + if (_bpp == 16) + pixelColor = (uint16_t) (color >> 8) | (color << 8); + + else if (_bpp == 8) + pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + + else pixelColor = (uint16_t) color; // for 1bpp or 4bpp + + while(len--) writeColor(pixelColor); +} + + +/*************************************************************************************** +** Function name: writeColor +** Description: Write a pixel with pre-formatted colour to the set window +***************************************************************************************/ +void TFT_eSprite::writeColor(uint16_t color) +{ + if (!_created ) return; + + // Write 16-bit RGB 565 encoded colour to RAM + if (_bpp == 16) _img [_xptr + _yptr * _iwidth] = color; + + // Write 8-bit RGB 332 encoded colour to RAM + else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color; + + else if (_bpp == 4) + { + uint8_t c = (uint8_t)color & 0x0F; + if ((_xptr & 0x01) == 0) + _img4[(_xptr + _yptr * _iwidth)>>1] = (c << 4) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4 + else + _img4[(_xptr + _yptr * _iwidth)>>1] = (_img4[(_xptr + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits (x is odd) + } + + else drawPixel(_xptr, _yptr, color); + + // Increment x + _xptr++; + + // Wrap on x and y to start, increment y if needed + if (_xptr > _xe) + { + _xptr = _xs; + _yptr++; + if (_yptr > _ye) _yptr = _ys; + } +} + + +/*************************************************************************************** +** Function name: setScrollRect +** Description: Set scroll area within the sprite and the gap fill colour +***************************************************************************************/ +// Intentionally not constrained to viewport area +void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) +{ + if ((x >= _iwidth) || (y >= _iheight) || !_created ) return; + + if (x < 0) { w += x; x = 0; } + if (y < 0) { h += y; y = 0; } + + if ((x + w) > _iwidth ) w = _iwidth - x; + if ((y + h) > _iheight) h = _iheight - y; + + if ( w < 1 || h < 1) return; + + _sx = x; + _sy = y; + _sw = w; + _sh = h; + + _scolor = color; +} + + +/*************************************************************************************** +** Function name: scroll +** Description: Scroll dx,dy pixels, positive right,down, negative left,up +***************************************************************************************/ +void TFT_eSprite::scroll(int16_t dx, int16_t dy) +{ + if (abs(dx) >= _sw || abs(dy) >= _sh) + { + fillRect (_sx, _sy, _sw, _sh, _scolor); + return; + } + + // Fetch the scroll area width and height set by setScrollRect() + uint32_t w = _sw - abs(dx); // line width to copy + uint32_t h = _sh - abs(dy); // lines to copy + int32_t iw = _iwidth; // rounded up width of sprite + + // Fetch the x,y origin set by setScrollRect() + uint32_t tx = _sx; // to x + uint32_t fx = _sx; // from x + uint32_t ty = _sy; // to y + uint32_t fy = _sy; // from y + + // Adjust for x delta + if (dx <= 0) fx -= dx; + else tx += dx; + + // Adjust for y delta + if (dy <= 0) fy -= dy; + else + { // Scrolling down so start copy from bottom + ty = ty + _sh - 1; // "To" pointer + iw = -iw; // Pointer moves backwards + fy = ty - dy; // "From" pointer + } + + // Calculate "from y" and "to y" pointers in RAM + uint32_t fyp = fx + fy * _iwidth; + uint32_t typ = tx + ty * _iwidth; + + // Now move the pixels in RAM + if (_bpp == 16) + { + while (h--) + { // move pixel lines (to, from, byte count) + memmove( _img + typ, _img + fyp, w<<1); + typ += iw; + fyp += iw; + } + } + else if (_bpp == 8) + { + while (h--) + { // move pixel lines (to, from, byte count) + memmove( _img8 + typ, _img8 + fyp, w); + typ += iw; + fyp += iw; + } + } + else if (_bpp == 4) + { + // could optimize for scrolling by even # pixels using memove (later) + if (dx > 0) { tx += w; fx += w; } // Start from right edge + while (h--) + { // move pixels one by one + for (uint16_t xp = 0; xp < w; xp++) + { + if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); + if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); + } + if (dy <= 0) { ty++; fy++; } + else { ty--; fy--; } + } + } + else if (_bpp == 1 ) + { + if (dx > 0) { tx += w; fx += w; } // Start from right edge + while (h--) + { // move pixels one by one + for (uint16_t xp = 0; xp < w; xp++) + { + if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); + if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); + } + if (dy <= 0) { ty++; fy++; } + else { ty--; fy--; } + } + } + else return; // Not 1, 4, 8 or 16 bpp + + // Fill the gap left by the scrolling + if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor); + if (dx < 0) fillRect(_sx + _sw + dx, _sy, -dx, _sh, _scolor); + if (dy > 0) fillRect(_sx, _sy, _sw, dy, _scolor); + if (dy < 0) fillRect(_sx, _sy + _sh + dy, _sw, -dy, _scolor); +} + + +/*************************************************************************************** +** Function name: fillSprite +** Description: Fill the whole sprite with defined colour +***************************************************************************************/ +void TFT_eSprite::fillSprite(uint32_t color) +{ + if (!_created || _vpOoB) return; + + // Use memset if possible as it is super fast + if(_xDatum == 0 && _yDatum == 0 && _xWidth == width()) + { + if(_bpp == 16) { + if ( (uint8_t)color == (uint8_t)(color>>8) ) { + memset(_img, (uint8_t)color, _iwidth * _yHeight * 2); + } + else fillRect(_vpX, _vpY, _xWidth, _yHeight, color); + } + else if (_bpp == 8) + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + memset(_img8, (uint8_t)color, _iwidth * _yHeight); + } + else if (_bpp == 4) + { + uint8_t c = ((color & 0x0F) | (((color & 0x0F) << 4) & 0xF0)); + memset(_img4, c, (_iwidth * _yHeight) >> 1); + } + else if (_bpp == 1) + { + if(color) memset(_img8, 0xFF, (_bitwidth>>3) * _dheight + 1); + else memset(_img8, 0x00, (_bitwidth>>3) * _dheight + 1); + } + } + else fillRect(_vpX - _xDatum, _vpY - _yDatum, _xWidth, _yHeight, color); +} + + +/*************************************************************************************** +** Function name: width +** Description: Return the width of sprite +***************************************************************************************/ +// Return the size of the sprite +int16_t TFT_eSprite::width(void) +{ + if (!_created ) return 0; + + if (_bpp > 1) { + if (_vpDatum) return _xWidth; + return _dwidth; + } + + if (rotation & 1) { + if (_vpDatum) return _xWidth; + return _dheight; + } + + if (_vpDatum) return _xWidth; + return _dwidth; +} + + +/*************************************************************************************** +** Function name: height +** Description: Return the height of sprite +***************************************************************************************/ +int16_t TFT_eSprite::height(void) +{ + if (!_created ) return 0; + + if (_bpp > 1) { + if (_vpDatum) return _yHeight; + return _dheight; + } + + if (rotation & 1) { + if (_vpDatum) return _yHeight; + return _dwidth; + } + + if (_vpDatum) return _yHeight; + return _dheight; +} + + +/*************************************************************************************** +** Function name: setRotation +** Description: Rotate coordinate frame for 1bpp sprite +***************************************************************************************/ +// Does nothing for 4, 8 and 16 bpp sprites. +void TFT_eSprite::setRotation(uint8_t r) +{ + if (_bpp != 1) return; + + rotation = r; + + if (rotation&1) { + resetViewport(); + } + else { + resetViewport(); + } +} + + +/*************************************************************************************** +** Function name: getRotation +** Description: Get rotation for 1bpp sprite +***************************************************************************************/ +uint8_t TFT_eSprite::getRotation(void) +{ + return rotation; +} + + +/*************************************************************************************** +** Function name: drawPixel +** Description: push a single pixel at an arbitrary position +***************************************************************************************/ +void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) +{ + if (!_created || _vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + + // Range checking + if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return; + + if (_bpp == 16) + { + color = (color >> 8) | (color << 8); + _img[x+y*_iwidth] = (uint16_t) color; + } + else if (_bpp == 8) + { + _img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + } + else if (_bpp == 4) + { + uint8_t c = color & 0x0F; + int index = (x+y*_iwidth)>>1;; + if ((x & 0x01) == 0) { + _img4[index] = (uint8_t)((c << 4) | (_img4[index] & 0x0F)); + } + else { + _img4[index] = (uint8_t)(c | (_img4[index] & 0xF0)); + } + } + else // 1 bpp + { + if (rotation == 1) + { + uint16_t tx = x; + x = _dwidth - y - 1; + y = tx; + } + else if (rotation == 2) + { + x = _dwidth - x - 1; + y = _dheight - y - 1; + } + else if (rotation == 3) + { + uint16_t tx = x; + x = y; + y = _dheight - tx - 1; + } + + if (color) _img8[(x + y * _bitwidth)>>3] |= (0x80 >> (x & 0x7)); + else _img8[(x + y * _bitwidth)>>3] &= ~(0x80 >> (x & 0x7)); + } +} + + +/*************************************************************************************** +** Function name: drawLine +** Description: draw a line between 2 arbitrary points +***************************************************************************************/ +void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) +{ + if (!_created || _vpOoB) return; + + //_xDatum and _yDatum Not added here, it is added by drawPixel & drawFastxLine + + bool steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + transpose(x0, y0); + transpose(x1, y1); + } + + if (x0 > x1) { + transpose(x0, x1); + transpose(y0, y1); + } + + int32_t dx = x1 - x0, dy = abs(y1 - y0);; + + int32_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0; + + if (y0 < y1) ystep = 1; + + // Split into steep and not steep for FastH/V separation + if (steep) { + for (; x0 <= x1; x0++) { + dlen++; + err -= dy; + if (err < 0) { + err += dx; + if (dlen == 1) drawPixel(y0, xs, color); + else drawFastVLine(y0, xs, dlen, color); + dlen = 0; y0 += ystep; xs = x0 + 1; + } + } + 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); + } +} + + +/*************************************************************************************** +** Function name: drawFastVLine +** Description: draw a vertical line +***************************************************************************************/ +void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) +{ + if (!_created || _vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + + // Clipping + if ((x < _vpX) || (x >= _vpW) || (y >= _vpH)) return; + + if (y < _vpY) { h += y - _vpY; y = _vpY; } + + if ((y + h) > _vpH) h = _vpH - y; + + if (h < 1) return; + + if (_bpp == 16) + { + color = (color >> 8) | (color << 8); + int32_t yp = x + _iwidth * y; + while (h--) {_img[yp] = (uint16_t) color; yp += _iwidth;} + } + else if (_bpp == 8) + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + while (h--) _img8[x + _iwidth * y++] = (uint8_t) color; + } + else if (_bpp == 4) + { + if ((x & 0x01) == 0) + { + uint8_t c = (uint8_t) (color & 0xF) << 4; + while (h--) { + _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0x0F)); + y++; + } + } + else { + uint8_t c = (uint8_t)color & 0xF; + while (h--) { + _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0xF0)); // x is odd; new color goes into the low bits. + y++; + } + } + } + else + { + x -= _xDatum; // Remove any offset as it will be added by drawPixel + y -= _yDatum; + while (h--) + { + drawPixel(x, y++, color); + } + } +} + + +/*************************************************************************************** +** Function name: drawFastHLine +** Description: draw a horizontal line +***************************************************************************************/ +void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) +{ + if (!_created || _vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + + // Clipping + if ((y < _vpY) || (x >= _vpW) || (y >= _vpH)) return; + + if (x < _vpX) { w += x - _vpX; x = _vpX; } + + if ((x + w) > _vpW) w = _vpW - x; + + if (w < 1) return; + + if (_bpp == 16) + { + color = (color >> 8) | (color << 8); + while (w--) _img[_iwidth * y + x++] = (uint16_t) color; + } + else if (_bpp == 8) + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + memset(_img8+_iwidth * y + x, (uint8_t)color, w); + } + else if (_bpp == 4) + { + uint8_t c = (uint8_t)color & 0x0F; + uint8_t c2 = (c | ((c << 4) & 0xF0)); + if ((x & 0x01) == 1) + { + drawPixel(x - _xDatum, y - _yDatum, color); + x++; w--; + if (w < 1) + return; + } + + if (((w + x) & 0x01) == 1) + { + // handle the extra one at the other end + drawPixel(x - _xDatum + w - 1, y - _yDatum, color); + w--; + if (w < 1) return; + } + memset(_img4 + ((_iwidth * y + x) >> 1), c2, (w >> 1)); + } + else { + x -= _xDatum; // Remove any offset as it will be added by drawPixel + y -= _yDatum; + + while (w--) + { + drawPixel(x++, y, color); + } + } +} + + +/*************************************************************************************** +** Function name: fillRect +** Description: draw a filled rectangle +***************************************************************************************/ +void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) +{ + if (!_created || _vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + + // Clipping + if ((x >= _vpW) || (y >= _vpH)) return; + + if (x < _vpX) { w += x - _vpX; x = _vpX; } + if (y < _vpY) { h += y - _vpY; y = _vpY; } + + if ((x + w) > _vpW) w = _vpW - x; + if ((y + h) > _vpH) h = _vpH - y; + + if ((w < 1) || (h < 1)) return; + + int32_t yp = _iwidth * y + x; + + if (_bpp == 16) + { + color = (color >> 8) | (color << 8); + uint32_t iw = w; + int32_t ys = yp; + if(h--) {while (iw--) _img[yp++] = (uint16_t) color;} + yp = ys; + while (h--) + { + yp += _iwidth; + memcpy( _img+yp, _img+ys, w<<1); + } + } + else if (_bpp == 8) + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + while (h--) + { + memset(_img8 + yp, (uint8_t)color, w); + yp += _iwidth; + } + } + else if (_bpp == 4) + { + uint8_t c1 = (uint8_t)color & 0x0F; + uint8_t c2 = c1 | ((c1 << 4) & 0xF0); + if ((x & 0x01) == 0 && (w & 0x01) == 0) + { + yp = (yp >> 1); + while (h--) + { + memset(_img4 + yp, c2, (w>>1)); + yp += (_iwidth >> 1); + } + } + else if ((x & 0x01) == 0) + { + + // same as above but you have a hangover on the right. + yp = (yp >> 1); + while (h--) + { + if (w > 1) + memset(_img4 + yp, c2, (w-1)>>1); + // handle the rightmost pixel by calling drawPixel + drawPixel(x+w-1-_xDatum, y+h-_yDatum, c1); + yp += (_iwidth >> 1); + } + } + else if ((w & 0x01) == 1) + { + yp = (yp + 1) >> 1; + while (h--) { + drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); + if (w > 1) + memset(_img4 + yp, c2, (w-1)>>1); + // same as above but you have a hangover on the left instead + yp += (_iwidth >> 1); + } + } + else + { + yp = (yp + 1) >> 1; + while (h--) { + drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); + if (w > 1) drawPixel(x+w-1-_xDatum, y+h-_yDatum, color & 0x0F); + if (w > 2) + memset(_img4 + yp, c2, (w-2)>>1); + // maximal hacking, single pixels on left and right. + yp += (_iwidth >> 1); + } + } + } + else + { + x -= _xDatum; + y -= _yDatum; + while (h--) + { + int32_t ww = w; + int32_t xx = x; + while (ww--) drawPixel(xx++, y, color); + y++; + } + } +} + + +/*************************************************************************************** +** Function name: drawChar +** Description: draw a single character in the Adafruit GLCD or freefont +***************************************************************************************/ +void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) +{ + if ( _vpOoB || !_created ) return; + + if (c < 32) return; + if ((x >= _vpW - _xDatum) || // Clip right + (y >= _vpH - _yDatum)) // Clip bottom + return; + + if (((x + 6 * size - 1) < (_vpX - _xDatum)) || // Clip left + ((y + 8 * size - 1) < (_vpY - _yDatum))) // Clip top + return; + + if (c > 255) return; + if (!_cp437 && c > 175) c++; + + bool fillbg = (bg != color); + + if ((size==1) && fillbg) + { + uint8_t column[6]; + uint8_t mask = 0x1; + + for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); + column[5] = 0; + + int8_t j, k; + for (j = 0; j < 8; j++) { + for (k = 0; k < 5; k++ ) { + if (column[k] & mask) { + drawPixel(x + k, y + j, color); + } + else { + drawPixel(x + k, y + j, bg); + } + } + + mask <<= 1; + + drawPixel(x + k, y + j, bg); + } + } + else + { + for (int8_t i = 0; i < 6; i++ ) { + uint8_t line; + if (i == 5) + line = 0x0; + else + line = pgm_read_byte(font + (c * 5) + i); + + if (size == 1) // default size + { + for (int8_t j = 0; j < 8; j++) { + if (line & 0x1) drawPixel(x + i, y + j, color); + line >>= 1; + } + } else { // big size + for (int8_t j = 0; j < 8; j++) { + if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color); + else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg); + line >>= 1; + } + } + } + } +} + +int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y) { + return drawChar(uniCode, x, y, textfont); +} + +int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) { + if (_vpOoB || !uniCode) return 0; + + if (font==1) return 0; + + if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0; + + int32_t width = 0; + int32_t height = 0; + uint32_t flash_address = 0; + uniCode -= 32; + + int32_t xd = x + _xDatum; + int32_t yd = y + _yDatum; + + if ((xd + width * textsize < _vpX || xd >= _vpW) && (yd + height * textsize < _vpY || yd >= _vpH)) return width * textsize ; + + int32_t w = width; + int32_t pX = 0; + int32_t pY = y; + uint8_t line = 0; + bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH; + + flash_address = flash_address; + w = w; + pX = pX; + pY = pY; + line = line; + clip = clip; + + return width * textsize; // x + +} + +void TFT_eSprite::drawGlyph(uint16_t code) +{ + uint16_t fg = textcolor; + uint16_t bg = textbgcolor; + bool getBG = false; + if (fg == bg) getBG = true; + + // Check if cursor has moved + if (last_cursor_x != cursor_x) { + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; + } + + if (code < 0x21) { + if (code == 0x20) { + if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); + cursor_x += gFont.spaceWidth; + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; + return; + } + + if (code == '\n') { + cursor_x = 0; + bg_cursor_x = 0; + last_cursor_x = 0; + cursor_y += gFont.yAdvance; + if (textwrapY && (cursor_y >= height())) cursor_y = 0; + return; + } + } + + uint16_t gNum = 0; + bool found = getUnicodeIndex(code, &gNum); + + if (found) { + bool newSprite = !_created; + if (newSprite) { + createSprite(gWidth[gNum], gFont.yAdvance); + if(fg != bg) fillSprite(bg); + cursor_x = -gdX[gNum]; + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; + cursor_y = 0; + } else { + if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) { + cursor_y += gFont.yAdvance; + cursor_x = 0; + bg_cursor_x = 0; + last_cursor_x = 0; + } + + if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 0; + if ( cursor_x == 0) cursor_x -= gdX[gNum]; + } + + uint8_t* pbuffer = nullptr; + const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + + if (fs_font) { + fontFile.seek(gBitmap[gNum], fs::SeekSet); + pbuffer = (uint8_t*)malloc(gWidth[gNum]); + } + + int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; + int16_t cx = cursor_x + gdX[gNum]; + + int16_t fxs = cx; + uint32_t fl = 0; + int16_t bxs = cx; + uint32_t bl = 0; + int16_t bx = 0; + uint8_t pixel = 0; + + int16_t fillwidth = 0; + int16_t fillheight = 0; + + // Fill area above glyph + if (_fillbg) { + fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; + if (fillwidth > 0) { + fillheight = gFont.maxAscent - gdY[gNum]; + if (fillheight > 0) fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); + } + else fillwidth = 0; + + // Fill any area to left of glyph + if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); + // Set x position in glyph area where background starts + if (bg_cursor_x > cx) bx = bg_cursor_x - cx; + // Fill any area to right of glyph + if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); + } + + for (int32_t y = 0; y < gHeight[gNum]; y++) { + if (fs_font) fontFile.read(pbuffer, gWidth[gNum]); + + for (int32_t x = 0; x < gWidth[gNum]; x++) { + if (fs_font) pixel = pbuffer[x]; + else pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + + if (pixel) { + if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } + if (pixel != 0xFF) + { + if (fl) { + if (fl==1) drawPixel(fxs, y + cy, fg); + else drawFastHLine( fxs, y + cy, fl, fg); + fl = 0; + } + if (getBG) bg = readPixel(x + cx, y + cy); + drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg)); + } else { + if (fl==0) fxs = x + cx; + fl++; + } + } else { + if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } + if (_fillbg) { + if (x >= bx) { + if (bl==0) bxs = x + cx; + bl++; + } + } + } + } + if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; } + if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } + } + + // Fill area below glyph + if (fillwidth > 0) { + fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); + if (fillheight > 0) fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); + } + + if (pbuffer) free(pbuffer); + cursor_x += gxAdvance[gNum]; + + if (newSprite) { + pushSprite(cx, cursor_y); + deleteSprite(); + } + } + else { + drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); + cursor_x += gFont.spaceWidth + 1; + } + bg_cursor_x = cursor_x; + last_cursor_x = cursor_x; +} + +void TFT_eSprite::printToSprite(String string) +{ + if(!fontLoaded) return; + printToSprite((char*)string.c_str(), string.length()); +} + +void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) +{ + if(!fontLoaded) return; + + uint16_t n = 0; + bool newSprite = !_created; + int16_t cursorX = _tft->cursor_x; + + if (newSprite) { + int16_t sWidth = 0; + uint16_t index = 0; + bool first = true; + while (n < len) { + uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); + if (getUnicodeIndex(unicode, &index)) { + if (first) { + first = false; + sWidth -= gdX[index]; + cursorX += gdX[index]; + } + if (n == len) sWidth += ( gWidth[index] + gdX[index]); + else sWidth += gxAdvance[index]; + } + else sWidth += gFont.spaceWidth + 1; + } + + createSprite(sWidth, gFont.yAdvance); + + if (textcolor != textbgcolor) fillSprite(textbgcolor); + } + + n = 0; + + while(n < len) drawGlyph(decodeUTF8((uint8_t*)cbuffer, &n, len - n)); + + if (newSprite) { + pushSprite(cursorX, _tft->cursor_y); + deleteSprite(); + } +} + +int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) { + bool newSprite = !_created; + int16_t sWidth = gWidth[index]; + + if (newSprite) { + createSprite(sWidth, gFont.yAdvance); + + if (textcolor != textbgcolor) fillSprite(textbgcolor); + + drawGlyph(gUnicode[index]); + + pushSprite(x + gdX[index], y, textbgcolor); + deleteSprite(); + } + + else drawGlyph(gUnicode[index]); + + return gxAdvance[index]; +} diff --git a/lib/TFT_eSPI/TFT_eSPI.h b/lib/TFT_eSPI/TFT_eSPI.h index 968887c..ebc9b89 100644 --- a/lib/TFT_eSPI/TFT_eSPI.h +++ b/lib/TFT_eSPI/TFT_eSPI.h @@ -1,221 +1,459 @@ -/*************************************************** - Arduino TFT graphics library targeted at ESP8266 - and ESP32 based boards. - - This is a stand-alone library that contains the - hardware driver, the graphics functions and the - proportional fonts. - - The built-in fonts 4, 6, 7 and 8 are Run Length - Encoded (RLE) to reduce the FLASH footprint. - - Last review/edit by Bodmer: 04/02/22 - ****************************************************/ - -// Stop fonts etc. being loaded multiple times -#ifndef _TFT_eSPIH_ -#define _TFT_eSPIH_ +#pragma once #define TFT_ESPI_VERSION "2.5.43" -// Bit level feature flags -// Bit 0 set: viewport capability -#define TFT_ESPI_FEATURES 1 - -/*************************************************************************************** -** Section 1: Load required header files -***************************************************************************************/ - -//Standard support #include #include -#if !defined (TFT_PARALLEL_8_BIT) && !defined (RP2040_PIO_INTERFACE) - #include -#endif -/*************************************************************************************** -** Section 2: Load library and processor specific header files -***************************************************************************************/ -// Include header file that defines the fonts loaded, the TFT drivers -// available and the pins to be used, etc. etc. -#ifdef CONFIG_TFT_eSPI_ESPIDF - #include "TFT_config.h" -#endif - -// New ESP8266 board package uses ARDUINO_ARCH_ESP8266 -// old package defined ESP8266 -#if defined (ESP8266) - #ifndef ARDUINO_ARCH_ESP8266 - #define ARDUINO_ARCH_ESP8266 - #endif -#endif - -// The following lines allow the user setup to be included in the sketch folder, see -// "Sketch_with_tft_setup" generic example. -#if !defined __has_include - #if !defined(DISABLE_ALL_LIBRARY_WARNINGS) - #warning Compiler does not support __has_include, so sketches cannot define the setup - #endif -#else - #if __has_include() - // Include the sketch setup file - #include - #ifndef USER_SETUP_LOADED - // Prevent loading further setups - #define USER_SETUP_LOADED - #endif - #endif -#endif +#include #include -// Handle FLASH based storage e.g. PROGMEM -#if defined(ARDUINO_ARCH_RP2040) - #undef pgm_read_byte - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #undef pgm_read_word - #define pgm_read_word(addr) ({ \ - typeof(addr) _addr = (addr); \ - *(const unsigned short *)(_addr); \ - }) - #undef pgm_read_dword - #define pgm_read_dword(addr) ({ \ - typeof(addr) _addr = (addr); \ - *(const unsigned long *)(_addr); \ - }) -#elif defined(__AVR__) - #include -#elif defined(ARDUINO_ARCH_ESP8266) || defined(ESP32) - #include -#else - #ifndef PROGMEM - #define PROGMEM - #endif -#endif +#include -// Include the processor specific drivers -#if defined(CONFIG_IDF_TARGET_ESP32S3) - #include "Processors/TFT_eSPI_ESP32_S3.h" -#elif defined(CONFIG_IDF_TARGET_ESP32C3) - #include "Processors/TFT_eSPI_ESP32_C3.h" -#elif defined (ESP32) - #include "Processors/TFT_eSPI_ESP32.h" -#elif defined (ARDUINO_ARCH_ESP8266) - #include "Processors/TFT_eSPI_ESP8266.h" -#elif defined (STM32) - #include "Processors/TFT_eSPI_STM32.h" -#elif defined(ARDUINO_ARCH_RP2040) - #include "Processors/TFT_eSPI_RP2040.h" -#else - #include "Processors/TFT_eSPI_Generic.h" - #define GENERIC_PROCESSOR -#endif +// Processor ID reported by getSetup() +#define PROCESSOR_ID 0x32 -/*************************************************************************************** -** Section 3: Interface setup -***************************************************************************************/ -#ifndef TAB_COLOUR - #define TAB_COLOUR 0 -#endif - -// If the SPI frequency is not defined, set a default -#ifndef SPI_FREQUENCY - #define SPI_FREQUENCY 20000000 -#endif - -// If the SPI read frequency is not defined, set a default -#ifndef SPI_READ_FREQUENCY - #define SPI_READ_FREQUENCY 10000000 -#endif - -// Some ST7789 boards do not work with Mode 0 -#ifndef TFT_SPI_MODE - #if defined(ST7789_DRIVER) || defined(ST7789_2_DRIVER) - #define TFT_SPI_MODE SPI_MODE3 +#ifdef USE_HSPI_PORT + #ifdef CONFIG_IDF_TARGET_ESP32 + #define SPI_PORT HSPI //HSPI is port 2 on ESP32 #else - #define TFT_SPI_MODE SPI_MODE0 + #define SPI_PORT 3 //HSPI is port 3 on ESP32 S2 + #endif +#elif defined(USE_FSPI_PORT) + #define SPI_PORT 2 //FSPI(ESP32 S2) +#else + #ifdef CONFIG_IDF_TARGET_ESP32 + #define SPI_PORT VSPI + #else + #define SPI_PORT 2 //FSPI(ESP32 S2) #endif #endif -// If the XPT2046 SPI frequency is not defined, set a default -#ifndef SPI_TOUCH_FREQUENCY - #define SPI_TOUCH_FREQUENCY 2500000 +// Include processor specific header +#include "soc/spi_reg.h" +#include "driver/spi_master.h" +#include "hal/gpio_ll.h" + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) + #define CONFIG_IDF_TARGET_ESP32 #endif -#ifndef SPI_BUSY_CHECK - #define SPI_BUSY_CHECK +#if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) + #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE + #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE +#else + #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI + #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN #endif -// If half duplex SDA mode is defined then MISO pin should be -1 -#ifdef TFT_SDA_READ - #ifdef TFT_MISO - #if TFT_MISO != -1 - #undef TFT_MISO - #define TFT_MISO -1 - #warning TFT_MISO set to -1 +#define ESP32_DMA + +#define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) + +// If smooth font is used then it is likely SPIFFS will be needed +// Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts +#define FS_NO_GLOBALS +#include +#include "SPIFFS.h" // ESP32 only + +#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 >= 32) + #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change + #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ + GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) + #define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \ + GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) + #else + #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) + #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) #endif - #endif -#endif - -/*************************************************************************************** -** Section 4: Setup fonts -***************************************************************************************/ -// Use GLCD font in error case where user requests a smooth font file -// that does not exist (this is a temporary fix to stop ESP32 reboot) -#ifdef SMOOTH_FONT - #ifndef LOAD_GLCD - #define LOAD_GLCD + #elif (TFT_DC >= 0) + #if defined (RPI_DISPLAY_TYPE) + #if defined (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) + #else + // 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) + #endif + #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 -// Only load the fonts defined in User_Setup.h (to save space) -// Set flag so RLE rendering code is optionally compiled -#ifdef LOAD_GLCD - #include -#endif - -#ifdef LOAD_FONT2 - #include -#endif - -#ifdef LOAD_FONT4 - #include - #define LOAD_RLE -#endif - -#ifdef LOAD_FONT6 - #include - #ifndef LOAD_RLE - #define LOAD_RLE +//////////////////////////////////////////////////////////////////////////////////////// +// Define the CS (TFT chip select) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_CS + #define TFT_CS -1 // Keep DMA code happy + #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 >= 32) + #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)) + #elif (TFT_CS >= 0) + #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) + #else + #define CS_L + #define CS_H #endif #endif -#ifdef LOAD_FONT7 - #include - #ifndef LOAD_RLE - #define LOAD_RLE +//////////////////////////////////////////////////////////////////////////////////////// +// Define the WR (TFT Write) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_WR) + #if (TFT_WR >= 32) + // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 + #define WR_L GPIO.out1_w1tc.val = (1 << (TFT_WR - 32)) + #define WR_H GPIO.out1_w1ts.val = (1 << (TFT_WR - 32)) + #elif (TFT_WR >= 0) + // TFT_WR, for best performance, should be in range 0-31 for single register parallel write + #define WR_L GPIO.out_w1tc = (1 << TFT_WR) + #define WR_H GPIO.out_w1ts = (1 << TFT_WR) + #else + #define WR_L + #define WR_H #endif +#else + #define WR_L + #define WR_H #endif -#ifdef LOAD_FONT8 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif -#elif defined LOAD_FONT8N // Optional narrower version - #define LOAD_FONT8 - #include - #ifndef LOAD_RLE - #define LOAD_RLE - #endif +#ifndef TFT_MISO + #define TFT_MISO -1 #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 -#endif // #ifdef LOAD_GFXFF +#ifndef TFT_MOSI + #define TFT_MOSI 23 +#endif +#if (TFT_MOSI == -1) + #undef TFT_MOSI + #define TFT_MOSI 23 +#endif + +#ifndef TFT_SCLK + #define TFT_SCLK 18 +#endif +#if (TFT_SCLK == -1) + #undef TFT_SCLK + #define TFT_SCLK 18 +#endif + +#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ + *_spi_w = D; \ + *_spi_cmd = SPI_USR; \ + while (*_spi_cmd & SPI_USR); + +// Write 8 bits +#define tft_Write_8(C) TFT_WRITE_BITS(C, 8) + +// Write 16 bits with corrected endianness for 16-bit colours +#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) + +// Future option for transfer without wait +#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ + *_spi_w = ((C)<<8 | (C)>>8); \ + *_spi_cmd = SPI_USR; + +// Write 16 bits +#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) + +// Write 32 bits +#define tft_Write_32(C) TFT_WRITE_BITS(C, 32) + +// Write two address coordinates +#define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + +// Write same value twice +#define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to read from display using SPI or software SPI +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined (TFT_PARALLEL_8_BIT) + #define tft_Read_8() spi.transfer(0) +#endif + +#define DAT8TO32(P) ( (uint32_t)P[0]<<8 | P[1] | P[2]<<24 | P[3]<<16 ) + +#ifndef TFT_SPI_MODE + #define TFT_SPI_MODE SPI_MODE0 +#endif + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x21, 0x54, 0x54, 0x78, 0x41, + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0xF0, 0x29, 0x24, 0x29, 0xF0, + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x32, 0x48, 0x48, 0x48, 0x32, + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x39, 0x44, 0x44, 0x44, 0x39, + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0x7C, 0x2A, 0x2A, 0x3E, 0x14, + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; // Create a null default font in case some fonts not used (to prevent crash) const uint8_t widtbl_null[1] = {0}; @@ -229,58 +467,21 @@ typedef struct { const uint8_t *widthtbl; uint8_t height; uint8_t baseline; - } fontinfo; +} fontinfo; // Now fill the structure const PROGMEM fontinfo fontdata [] = { - #ifdef LOAD_GLCD { (const uint8_t *)font, widtbl_null, 0, 0 }, - #else - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - // GLCD font (Font 1) does not have all parameters { (const uint8_t *)chrtbl_null, widtbl_null, 8, 7 }, - - #ifdef LOAD_FONT2 - { (const uint8_t *)chrtbl_f16, widtbl_f16, chr_hgt_f16, baseline_f16}, - #else { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - // Font 3 current unused { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - - #ifdef LOAD_FONT4 - { (const uint8_t *)chrtbl_f32, widtbl_f32, chr_hgt_f32, baseline_f32}, - #else { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - // Font 5 current unused { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - - #ifdef LOAD_FONT6 - { (const uint8_t *)chrtbl_f64, widtbl_f64, chr_hgt_f64, baseline_f64}, - #else { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - #ifdef LOAD_FONT7 - { (const uint8_t *)chrtbl_f7s, widtbl_f7s, chr_hgt_f7s, baseline_f7s}, - #else { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - #endif - - #ifdef LOAD_FONT8 - { (const uint8_t *)chrtbl_f72, widtbl_f72, chr_hgt_f72, baseline_f72} - #else { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 } - #endif }; -/*************************************************************************************** -** Section 5: Font datum enumeration -***************************************************************************************/ //These enumerate the text plotting alignment (reference datum point) #define TL_DATUM 0 // Top left (default) #define TC_DATUM 1 // Top centre @@ -352,68 +553,51 @@ static const uint16_t default_4bit_palette[] PROGMEM = { TFT_PINK // 15 }; -/*************************************************************************************** -** Section 7: Diagnostic support -***************************************************************************************/ -// #define TFT_eSPI_DEBUG // Switch on debug support serial messages (not used yet) -// #define TFT_eSPI_FNx_DEBUG // Switch on debug support for function "x" (not used yet) - -// This structure allows sketches to retrieve the user setup parameters at runtime -// by calling getSetup(), zero impact on code size unless used, mainly for diagnostics typedef struct { -String version = TFT_ESPI_VERSION; -String setup_info; // Setup reference name available to use in a user setup -uint32_t setup_id; // ID available to use in a user setup -int32_t esp; // Processor code -uint8_t trans; // SPI transaction support -uint8_t serial; // Serial (SPI) or parallel -#ifndef GENERIC_PROCESSOR -uint8_t port; // SPI port -#endif -uint8_t overlap; // ESP8266 overlap mode -uint8_t interface; // Interface type + String version = TFT_ESPI_VERSION; + String setup_info; // Setup reference name available to use in a user setup + uint32_t setup_id; // ID available to use in a user setup + int32_t esp; // Processor code + uint8_t trans; // SPI transaction support + uint8_t serial; // Serial (SPI) + #ifndef GENERIC_PROCESSOR + uint8_t port; // SPI port + #endif + uint8_t overlap; // ESP8266 overlap mode + uint8_t interface; // Interface type -uint16_t tft_driver; // Hexadecimal code -uint16_t tft_width; // Rotation 0 width and height -uint16_t tft_height; + uint16_t tft_driver; // Hexadecimal code + uint16_t tft_width; // Rotation 0 width and height + uint16_t tft_height; -uint8_t r0_x_offset; // Display offsets, not all used yet -uint8_t r0_y_offset; -uint8_t r1_x_offset; -uint8_t r1_y_offset; -uint8_t r2_x_offset; -uint8_t r2_y_offset; -uint8_t r3_x_offset; -uint8_t r3_y_offset; + uint8_t r0_x_offset; // Display offsets, not all used yet + uint8_t r0_y_offset; + uint8_t r1_x_offset; + uint8_t r1_y_offset; + uint8_t r2_x_offset; + uint8_t r2_y_offset; + uint8_t r3_x_offset; + uint8_t r3_y_offset; -int8_t pin_tft_mosi; // SPI pins -int8_t pin_tft_miso; -int8_t pin_tft_clk; -int8_t pin_tft_cs; + int8_t pin_tft_mosi; // SPI pins + int8_t pin_tft_miso; + int8_t pin_tft_clk; + int8_t pin_tft_cs; -int8_t pin_tft_dc; // Control pins -int8_t pin_tft_rd; -int8_t pin_tft_wr; -int8_t pin_tft_rst; + int8_t pin_tft_dc; // Control pins + int8_t pin_tft_rd; + int8_t pin_tft_wr; + int8_t pin_tft_rst; -int8_t pin_tft_d0; // Parallel port pins -int8_t pin_tft_d1; -int8_t pin_tft_d2; -int8_t pin_tft_d3; -int8_t pin_tft_d4; -int8_t pin_tft_d5; -int8_t pin_tft_d6; -int8_t pin_tft_d7; + int8_t pin_tft_led; + int8_t pin_tft_led_on; -int8_t pin_tft_led; -int8_t pin_tft_led_on; + int8_t pin_tch_cs; // Touch chip select pin -int8_t pin_tch_cs; // Touch chip select pin - -int16_t tft_spi_freq;// TFT write SPI frequency -int16_t tft_rd_freq; // TFT read SPI frequency -int16_t tch_spi_freq;// Touch controller read/write SPI frequency + int16_t tft_spi_freq;// TFT write SPI frequency + int16_t tft_rd_freq; // TFT read SPI frequency + int16_t tch_spi_freq;// Touch controller read/write SPI frequency } setup_t; /*************************************************************************************** @@ -428,18 +612,11 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac //--------------------------------------- public ------------------------------------// public: - - // Change SPI speed on the fly - void setSPISpeed(uint8_t speed_Mhz); - + void setSPISpeed(uint8_t speed_Mhz); TFT_eSPI(int16_t _W = TFT_WIDTH, int16_t _H = TFT_HEIGHT); + void init(); - // init() and begin() are equivalent, begin() included for backwards compatibility - // Sketch defined tab colour option is for ST7735 displays only - void init(uint8_t tc = TAB_COLOUR), begin(uint8_t tc = TAB_COLOUR); - - // These are virtual so the TFT_eSprite class can override them with sprite specific functions - virtual void drawPixel(int32_t x, int32_t y, uint32_t color), + virtual void drawPixel(int32_t x, int32_t y, uint32_t color), drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), @@ -450,59 +627,34 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac drawChar(uint16_t uniCode, int32_t x, int32_t y), height(void), width(void); - - // Read the colour of a pixel at x,y and return value in 565 format virtual uint16_t readPixel(int32_t x, int32_t y); - - virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates - - // Push (aka write pixel) colours to the set window + virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); virtual void pushColor(uint16_t color); - - // These are non-inlined to enable override virtual void begin_nin_write(); virtual void end_nin_write(); - void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3 - uint8_t getRotation(void); // Read the current rotation - - // Change the origin position from the default top left - // Note: setRotation, setViewport and resetViewport will revert origin to top left corner of screen/sprite + void setRotation(uint8_t r); + uint8_t getRotation(); void setOrigin(int32_t x, int32_t y); - int32_t getOriginX(void); - int32_t getOriginY(void); - - void invertDisplay(bool i); // Tell TFT to invert all displayed colours - - - // The TFT_eSprite class inherits the following functions (not all are useful to Sprite class + int32_t getOriginX(); + int32_t getOriginY(); + void invertDisplay(bool i); void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); // Note: start coordinates + width and height - - // Viewport commands, see "Viewport_Demo" sketch void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h); - int32_t getViewportX(void); - int32_t getViewportY(void); - int32_t getViewportWidth(void); - int32_t getViewportHeight(void); - bool getViewportDatum(void); + int32_t getViewportX(); + int32_t getViewportY(); + int32_t getViewportWidth(); + int32_t getViewportHeight(); + bool getViewportDatum(); void frameViewport(uint16_t color, int32_t w); - void resetViewport(void); - - // Clip input window to viewport bounds, return false if whole area is out of bounds + void resetViewport(); bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h); - // Clip input window area to viewport bounds, return false if whole area is out of bounds bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye); - - // Push (aka write pixel) colours to the TFT (use setAddrWindow() first) void pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock() pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option pushColors(uint8_t *data, uint32_t len); // Deprecated, use pushPixels() - - // 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); // Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input @@ -577,31 +729,19 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2) // If bg_color is not included the background pixel colour will be read from TFT or sprite void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends - // If bg_color is not included the background pixel colour will be read from TFT or sprite void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - - // Image rendering - // Swap the byte order for pushImage() and pushPixels() - corrects endianness void setSwapBytes(bool swap); - bool getSwapBytes(void); - - // Draw bitmap + bool getSwapBytes(); void 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); // Define the 2 colours for 1bpp sprites - // Set TFT pivot point (use when rendering rotated sprites) void setPivot(int16_t x, int16_t y); - int16_t getPivotX(void), // Get pivot x - getPivotY(void); // Get pivot y + int16_t getPivotX(), // Get pivot x + getPivotY(); // Get pivot y - // The next functions can be used as a pair to copy screen blocks (or horizontal/vertical lines) to another location - // Read a block of pixels to a data buffer, buffer is 16-bit and the size must be at least w * h void readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); // Write a block of pixels to the screen which have been read by readRect() void pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); @@ -645,13 +785,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac drawString(const char *string, int32_t x, int32_t y, uint8_t font), // Draw string using specified font number drawString(const char *string, int32_t x, int32_t y), // Draw string using current font drawString(const String& string, int32_t x, int32_t y, uint8_t font),// Draw string using specified font number - drawString(const String& string, int32_t x, int32_t y), // Draw string using current font - - drawCentreString(const char *string, int32_t x, int32_t y, uint8_t font), // Deprecated, use setTextDatum() and drawString() - drawRightString(const char *string, int32_t x, int32_t y, uint8_t font), // Deprecated, use setTextDatum() and drawString() - drawCentreString(const String& string, int32_t x, int32_t y, uint8_t font),// Deprecated, use setTextDatum() and drawString() - drawRightString(const String& string, int32_t x, int32_t y, uint8_t font); // Deprecated, use setTextDatum() and drawString() - + drawString(const String& string, int32_t x, int32_t y); // Draw string using current font // Text rendering and font handling support functions void setCursor(int16_t x, int16_t y), // Set cursor for tft.print() @@ -672,14 +806,8 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac void setTextPadding(uint16_t x_width); // Set text padding (background blanking/over-write) width in pixels uint16_t getTextPadding(void); // Get text padding -#ifdef LOAD_GFXFF - void setFreeFont(const GFXfont *f = NULL), // Select the GFX Free Font - setTextFont(uint8_t font); // Set the font number to use in future -#else void setFreeFont(uint8_t font), // Not used, historical fix to prevent an error setTextFont(uint8_t font); // Set the font number to use in future -#endif - int16_t textWidth(const char *string, uint8_t font), // Returns pixel width of string in specified font textWidth(const char *string), // Returns pixel width of string in current font textWidth(const String& string, uint8_t font), // As above for String types @@ -703,13 +831,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // Low level read/write void spiwrite(uint8_t); // legacy support only -#ifdef RM68120_DRIVER - void writecommand(uint16_t c); // Send a 16-bit command, function resets DC/RS high ready for data - void writeRegister8(uint16_t c, uint8_t d); // Write 8-bit data data to 16-bit command register - void writeRegister16(uint16_t c, uint16_t d); // Write 16-bit data data to 16-bit command register -#else void writecommand(uint8_t c); // Send an 8-bit command, function resets DC/RS high ready for data -#endif void writedata(uint8_t d); // Send data with DC/RS set high void commandList(const uint8_t *addr); // Send a initialisation sequence to TFT stored in FLASH @@ -744,7 +866,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // Direct Memory Access (DMA) support functions // These can be used for SPI writes when using the ESP32 (original) or STM32 processors. - // DMA also works on a RP2040 processor with PIO based SPI and parallel (8 and 16-bit) interfaces + // DMA also works on a RP2040 processor with PIO based SPI interfaces // Bear in mind DMA will only be of benefit in particular circumstances and can be tricky // to manage by noobs. The functions have however been designed to be noob friendly and // avoid a few DMA behaviour "gotchas". @@ -821,9 +943,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac bool verifySetupID(uint32_t id); // Global variables -#if !defined (TFT_PARALLEL_8_BIT) && !defined (RP2040_PIO_INTERFACE) static SPIClass& getSPIinstance(void); // Get SPI class handle -#endif uint32_t textcolor, textbgcolor; // Text foreground and background colours uint32_t bitmap_fg, bitmap_bg; // Bitmap foreground (bit=1) and background (bit=0) colours @@ -836,6 +956,46 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac uint8_t decoderState = 0; // UTF8 decoder state - not for user access uint16_t decoderBuffer; // Unicode code-point buffer - not for user access + void loadFont(const uint8_t array[]); + void loadFont(String fontName, fs::FS &ffs); + void loadFont(String fontName, bool flash = true); + void unloadFont( void ); + bool getUnicodeIndex(uint16_t unicode, uint16_t *index); + + virtual void drawGlyph(uint16_t code); + + void showFont(uint32_t td); + + typedef struct + { + const uint8_t* gArray; //array start pointer + uint16_t gCount; // Total number of characters + uint16_t yAdvance; // Line advance + uint16_t spaceWidth; // Width of a space character + int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller + int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent + uint16_t maxAscent; // Maximum ascent found in font + uint16_t maxDescent; // Maximum descent found in font + } fontMetrics; + + fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; + + // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) + uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential + uint8_t* gHeight = NULL; //cheight + uint8_t* gWidth = NULL; //cwidth + uint8_t* gxAdvance = NULL; //setWidth + int16_t* gdY = NULL; //topExtent + int8_t* gdX = NULL; //leftExtent + uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap + + bool fontLoaded = false; // Flags when a anti-aliased font is loaded + + fs::File fontFile; + fs::FS &fontFS = SPIFFS; + bool spiffs = true; + bool fs_font = false; + //--------------------------------------- private ------------------------------------// private: // Legacy begin and end prototypes - deprecated TODO: delete @@ -888,21 +1048,17 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac volatile uint32_t *dcport, *csport; uint32_t cspinmask, dcpinmask, wrpinmask, sclkpinmask; - #if defined(ESP32_PARALLEL) - // Bit masks for ESP32 parallel bus interface - uint32_t xclr_mask, xdir_mask; // Port set/clear and direction control masks - - // Lookup table for ESP32 parallel bus interface uses 1kbyte RAM, - uint32_t xset_mask[256]; // Makes Sprite rendering test 33% faster, for slower macro equivalent - // see commented out #define set_mask(C) within TFT_eSPI_ESP32.h - #endif - //uint32_t lastColor = 0xFFFF; // Last colour - used to minimise bit shifting overhead getColorCallback getColor = nullptr; // Smooth font callback function pointer bool locked, inTransaction, lockTransaction; // SPI transaction and mutex lock flags + void loadMetrics(void); + uint32_t readInt32(void); + + uint8_t* fontPtr = nullptr; + //-------------------------------------- protected ----------------------------------// protected: @@ -948,47 +1104,228 @@ uint8_t spi_write_speed; // SPI write speed bool _fillbg; // Fill background flag (just for for smooth fonts at the moment) -#if defined (SSD1963_DRIVER) - uint16_t Cswap; // Swap buffer for SSD1963 - uint8_t r6, g6, b6; // RGB buffer for SSD1963 -#endif + public: + // Get raw x,y ADC values from touch controller + uint8_t getTouchRaw(uint16_t *x, uint16_t *y); + // Get raw z (i.e. pressure) ADC value from touch controller + uint16_t getTouchRawZ(void); + // Convert raw x,y values to calibrated and correctly rotated screen coordinates + void convertRawXY(uint16_t *x, uint16_t *y); + // Get the screen touch coordinates, returns true if screen has been touched + // if the touch coordinates are off screen then x and y are not updated + // The returned value can be treated as a bool type, false or 0 means touch not detected + // In future the function may return an 8-bit "quality" (jitter) value. + // The threshold value is optional, this must be higher than the bias level for z (pressure) + // reported by Test_Touch_Controller when the screen is NOT touched. When touched the z value + // must be higher than the threshold for a touch to be detected. + uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); -#ifdef LOAD_GFXFF - GFXfont *gfxFont; -#endif + // Run screen calibration and test, report calibration values to the serial port + void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); + // Set the screen calibration values + void setTouch(uint16_t *data); -/*************************************************************************************** -** Section 9: TFT_eSPI class conditional extensions -***************************************************************************************/ -// Load the Touch extension -#ifdef TOUCH_CS - #if defined (TFT_PARALLEL_8_BIT) || defined (RP2040_PIO_INTERFACE) - #if !defined(DISABLE_ALL_LIBRARY_WARNINGS) - #error >>>>------>> Touch functions not supported in 8/16-bit parallel mode or with RP2040 PIO. - #endif - #else - #include "Extensions/Touch.h" // Loaded if TOUCH_CS is defined by user - #endif -#else - #if !defined(DISABLE_ALL_LIBRARY_WARNINGS) - #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available! - #endif -#endif + private: + // Legacy support only - deprecated TODO: delete + void spi_begin_touch(); + void spi_end_touch(); -// Load the Anti-aliased font extension -#ifdef SMOOTH_FONT - #include "Extensions/Smooth_font.h" // Loaded if SMOOTH_FONT is defined by user -#endif + // Handlers for the touch controller bus settings + inline void begin_touch_read_write() __attribute__((always_inline)); + inline void end_touch_read_write() __attribute__((always_inline)); -}; // End of class TFT_eSPI + // Private function to validate a touch, allow settle time and reduce spurious coordinates + uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); -// Swap any type -template static inline void -transpose(T& a, T& b) { T t = a; a = b; b = t; } + // Initialise with example calibration values so processor does not crash if setTouch() not called in setup() + uint16_t touchCalibration_x0 = 300, touchCalibration_x1 = 3600, touchCalibration_y0 = 300, touchCalibration_y1 = 3600; + uint8_t touchCalibration_rotate = 1, touchCalibration_invert_x = 2, touchCalibration_invert_y = 0; -// Fast alphaBlend -template static inline uint16_t -fastBlend(A alpha, F fgc, B bgc) + uint32_t _pressTime; // Press and hold time-out + uint16_t _pressX, _pressY; // For future use (last sampled calibrated coordinates) +}; + +class TFT_eSprite : public TFT_eSPI { + public: + explicit TFT_eSprite(TFT_eSPI *tft); + ~TFT_eSprite(void); + + // 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 bit per pixel for 1 bit colour depth + // - 1 nibble per pixel for 4-bit colour (with palette table) + // - 1 byte per pixel for 8-bit colour (332 RGB format) + // - 2 bytes per pixel for 16-bit color depth (565 RGB format) + void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); + + // Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type + void* getPointer(void); + + // Returns true if sprite has been created + bool created(void); + + // Delete the sprite to free up the RAM + void deleteSprite(void); + + // 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 1, 4, 8 or 16 bits. Can be used to change depth an existing + // sprite, but clears it to black, returns a new pointer if sprite is re-created. + void* setColorDepth(int8_t b); + int8_t getColorDepth(void); + + // Set the palette for a 4-bit depth sprite. Only the first 16 colours in the map are used. + void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in RAM + void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in FLASH + + // Set a single palette index to the given color + void setPaletteColor(uint8_t index, uint16_t color); + + // Get the color at the given palette index + uint16_t getPaletteColor(uint8_t index); + + // Set foreground and background colours for 1 bit per pixel Sprite + void setBitmapColor(uint16_t fg, uint16_t bg); + + // Draw a single pixel at x,y + void drawPixel(int32_t x, int32_t y, uint32_t color); + + // Draw a single character in the GLCD or GFXFF font + void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), + + // 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 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 sprite's set window area + pushColor(uint16_t color), + // Push len colors (pixels) to the sprite's set window area + pushColor(uint16_t color, uint32_t len), + // Push a pixel pre-formatted as a 1, 4, 8 or 16-bit colour (avoids conversion overhead) + writeColor(uint16_t color), + + // Set the scroll zone, top left corner at x,y with defined width and height + // The colour (optional, black is default) is used to fill the gap after the scroll + setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color = TFT_BLACK), + // Scroll the defined zone dx,dy pixels. Negative values left,up, positive right,down + // dy is optional (default is 0, so no up/down scroll). + // 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 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, uint32_t transp = 0x00FFFFFF); + // Push a rotated copy of Sprite to another different Sprite with optional transparent colour + bool pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp = 0x00FFFFFF); + + // Get the TFT bounding box for a rotated copy of this Sprite + bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); + // Get the destination Sprite bounding box for a rotated copy of this Sprite + bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, + int16_t *max_x, int16_t *max_y); + // Bounding box support function + void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, + int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); + + // Read the colour of a pixel at x,y and return value in 565 format + uint16_t readPixel(int32_t x0, int32_t y0); + + // return the numerical value of the pixel at x,y (used when scrolling) + // 16bpp = colour, 8bpp = byte, 4bpp = colour index, 1bpp = 1 or 0 + uint16_t readPixelValue(int32_t x, int32_t y); + + // Write an image (colour bitmap) to the sprite. + void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0); + void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data); + + // Push the sprite to the TFT screen, this fn calls pushImage() in the TFT class. + // Optionally a "transparent" colour can be defined, pixels of that colour will not be rendered + void pushSprite(int32_t x, int32_t y); + void pushSprite(int32_t x, int32_t y, uint16_t transparent); + + // Push a windowed area of the sprite to the TFT at tx, ty + bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh); + + // Push the sprite to another sprite at x,y. This fn calls pushImage() in the destination sprite (dspr) class. + bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y); + bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent); + + // Draw a single character in the selected font + int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), + drawChar(uint16_t uniCode, int32_t x, int32_t y); + + // Return the width and height of the sprite + int16_t width(void), + height(void); + + // Functions associated with anti-aliased fonts + // Draw a single Unicode character using the loaded font + void drawGlyph(uint16_t code); + // Print string to sprite using loaded font at cursor position + void printToSprite(String string); + // Print char array to sprite using loaded font at cursor position + void printToSprite(char *cbuffer, uint16_t len); + // Print indexed glyph to sprite using loaded font at x,y + int16_t printToSprite(int16_t x, int16_t y, uint16_t index); + + private: + + TFT_eSPI *_tft; + + // Reserve memory for the Sprite and return a pointer + void* callocSprite(int16_t width, int16_t height, uint8_t frames = 1); + + // Override the non-inlined TFT_eSPI functions + void begin_nin_write(void) { ; } + void end_nin_write(void) { ; } + + protected: + + uint8_t _bpp; // bits per pixel (1, 4, 8 or 16) + uint16_t *_img; // pointer to 16-bit sprite + uint8_t *_img8; // pointer to 1 and 8-bit sprite frame 1 or frame 2 + uint8_t *_img4; // pointer to 4-bit sprite (uses color map) + uint8_t *_img8_1; // pointer to frame 1 + uint8_t *_img8_2; // pointer to frame 2 + + uint16_t *_colorMap; // color map pointer: 16 entries, used with 4-bit color map. + + int32_t _sinra; // Sine of rotation angle in fixed point + int32_t _cosra; // Cosine of rotation angle in fixed point + + bool _created; // A Sprite has been created and memory reserved + bool _gFont = false; + + int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; // for setWindow + int32_t _sx, _sy; // x,y for scroll zone + uint32_t _sw, _sh; // w,h for scroll zone + uint32_t _scolor; // gap fill colour for scroll zone + + int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations) + int32_t _dwidth, _dheight; // Real sprite width and height (for <8bpp Sprites) + int32_t _bitwidth; // Sprite image bit width for drawPixel (for <8bpp Sprites, not swapped) +}; + +template static inline void transpose(T& a, T& b) { T t = a; a = b; b = t; } +template static inline uint16_t fastBlend(A alpha, F fgc, B bgc) { // Split out and blend 5-bit red and blue channels uint32_t rxb = bgc & 0xF81F; @@ -998,13 +1335,4 @@ fastBlend(A alpha, F fgc, B bgc) xgx += ((fgc & 0x07E0) - xgx) * alpha >> 8; // Recombine channels return (rxb & 0xF81F) | (xgx & 0x07E0); -} - -/*************************************************************************************** -** Section 10: Additional extension classes -***************************************************************************************/ - -// Load the Sprite Class -#include "Extensions/Sprite.h" - -#endif // ends #ifndef _TFT_eSPIH_ +} \ No newline at end of file diff --git a/lib/TFT_eSPI/User_Setup_Select.h b/lib/TFT_eSPI/User_Setup_Select.h index 36e57a2..0cd4913 100644 --- a/lib/TFT_eSPI/User_Setup_Select.h +++ b/lib/TFT_eSPI/User_Setup_Select.h @@ -1,27 +1,31 @@ #pragma once -#define ILI9341_DRIVER -#define TFT_DMA_SUPPORT -#define TFT_CS 5 -#define TFT_DC 17 -#define TFT_RST 16 -#define TOUCH_CS 32 +#define TFT_CS 5 +#define TFT_DC 17 +#define TFT_RST 16 +#define TOUCH_CS 32 -#define SPI_FREQUENCY 7500000 +#define SPI_FREQUENCY 7500000 #define SPI_READ_FREQUENCY 20000000 #define SPI_TOUCH_FREQUENCY 2500000 -#define SMOOTH_FONT #ifdef ARS #define TFT_RGB_ORDER TFT_RGB #endif -// Identical looking TFT displays may have a different colour ordering in the 16-bit colour #define TFT_BGR 0 // Colour order Blue-Green-Red #define TFT_RGB 1 // Colour order Red-Green-Blue -#include -#define TFT_DRIVER 0x9341 +#ifndef ARS + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 +#else + #define TFT_WIDTH 320 + #define TFT_HEIGHT 240 +#endif + +#include +#define TFT_DRIVER 0x9341 #define PIN_D0 16 // GPIO16 WAKE #define PIN_D1 5 // GPIO5 User purpose diff --git a/lib/TFT_eSPI/keywords.txt b/lib/TFT_eSPI/keywords.txt deleted file mode 100644 index 21439a9..0000000 --- a/lib/TFT_eSPI/keywords.txt +++ /dev/null @@ -1,209 +0,0 @@ -# TFT_eSPI core library - -TFT_eSPI KEYWORD1 - -begin KEYWORD2 -init KEYWORD2 -drawPixel KEYWORD2 -drawChar KEYWORD2 -drawLine KEYWORD2 -drawFastVLine KEYWORD2 -drawFastHLine KEYWORD2 -fillRect KEYWORD2 -height KEYWORD2 -width KEYWORD2 -readPixel KEYWORD2 -setWindow KEYWORD2 -pushColor KEYWORD2 - -setRotation KEYWORD2 -getRotation KEYWORD2 -setOrigin KEYWORD2 -getOriginX KEYWORD2 -getOriginY KEYWORD2 -invertDisplay KEYWORD2 -setAddrWindow KEYWORD2 - -setViewport KEYWORD2 -checkViewport KEYWORD2 -resetViewport KEYWORD2 -getViewportX KEYWORD2 -getViewportY KEYWORD2 -getViewportWidth KEYWORD2 -getViewportHeight KEYWORD2 -getViewportDatum KEYWORD2 -frameViewport KEYWORD2 -resetViewport KEYWORD2 -clipAddrWindow KEYWORD2 -clipWindow KEYWORD2 -pushColors KEYWORD2 -pushBlock KEYWORD2 -pushPixels KEYWORD2 - -tft_Read_8 KEYWORD2 -begin_SDA_Read KEYWORD2 -end_SDA_Read KEYWORD2 - -fillScreen KEYWORD2 - -drawRect KEYWORD2 -fillRectHGradient KEYWORD2 -fillRectVGradient KEYWORD2 -drawRoundRect KEYWORD2 -fillRoundRect KEYWORD2 - -drawCircle KEYWORD2 -drawCircleHelper KEYWORD2 -fillCircle KEYWORD2 -fillCircleHelper KEYWORD2 -drawEllipse KEYWORD2 -fillEllipse KEYWORD2 -drawTriangle KEYWORD2 -fillTriangle KEYWORD2 - -setSwapBytes KEYWORD2 -getSwapBytes KEYWORD2 - -drawBitmap KEYWORD2 -drawXBitmap KEYWORD2 - -setPivot KEYWORD2 -getPivotX KEYWORD2 -getPivotY KEYWORD2 - -readRect KEYWORD2 -pushRect KEYWORD2 -pushImage KEYWORD2 -pushMaskedImage KEYWORD2 -readRectRGB KEYWORD2 - -drawNumber KEYWORD2 -drawFloat KEYWORD2 -drawString KEYWORD2 -drawCentreString KEYWORD2 -drawRightString KEYWORD2 - -setCursor KEYWORD2 -getCursorX KEYWORD2 -getCursorY KEYWORD2 -setTextColor KEYWORD2 -setTextSize KEYWORD2 -setTextWrap KEYWORD2 -setTextDatum KEYWORD2 -getTextDatum KEYWORD2 -setTextPadding KEYWORD2 -getTextPadding KEYWORD2 -setFreeFont KEYWORD2 -setTextFont KEYWORD2 -textWidth KEYWORD2 -fontHeight KEYWORD2 -decodeUTF8 KEYWORD2 -write KEYWORD2 -setCallback KEYWORD2 -fontsLoaded KEYWORD2 - -spiwrite KEYWORD2 -writecommand KEYWORD2 -writeRegister KEYWORD2 -writedata KEYWORD2 -commandList KEYWORD2 -readcommand8 KEYWORD2 -readcommand16 KEYWORD2 -readcommand32 KEYWORD2 - -color565 KEYWORD2 -color8to16 KEYWORD2 -color16to8 KEYWORD2 -color16to24 KEYWORD2 -color24to16 KEYWORD2 -alphaBlend KEYWORD2 -alphaBlend24 KEYWORD2 - -initDMA KEYWORD2 -deInitDMA KEYWORD2 -pushImageDMA KEYWORD2 -pushPixelsDMA KEYWORD2 -dmaBusy KEYWORD2 -dmaWait KEYWORD2 - -startWrite KEYWORD2 -writeColor KEYWORD2 -endWrite KEYWORD2 - -setAttribute KEYWORD2 -getAttribute KEYWORD2 -getSetup KEYWORD2 -getSPIinstance KEYWORD2 - - -# Touch functions - -getTouchRaw KEYWORD2 -getTouchRawZ KEYWORD2 -convertRawXY KEYWORD2 -getTouch KEYWORD2 -calibrateTouch KEYWORD2 -setTouch KEYWORD2 - -# Smooth (anti-aliased) graphics functions -drawSmoothCircle KEYWORD2 -fillSmoothCircle KEYWORD2 -drawSmoothRoundRect KEYWORD2 -fillSmoothRoundRect KEYWORD2 -drawSmoothArc KEYWORD2 -drawArc KEYWORD2 -drawSpot KEYWORD2 -drawWideLine KEYWORD2 -drawWedgeLine KEYWORD2 - -# Smooth font functions - -loadFont KEYWORD2 -unloadFont KEYWORD2 -getUnicodeIndex KEYWORD2 -showFont KEYWORD2 - - -# Button class - -TFT_eSPI_Button KEYWORD1 - -initButton KEYWORD2 -initButtonUL KEYWORD2 -setLabelDatum KEYWORD2 -drawButton KEYWORD2 -contains KEYWORD2 -press KEYWORD2 -isPressed KEYWORD2 -justPressed KEYWORD2 -justReleased KEYWORD2 - - -# Sprite class - -TFT_eSprite KEYWORD1 - -createSprite KEYWORD2 -getPointer KEYWORD2 -created KEYWORD2 -deleteSprite KEYWORD2 -frameBuffer KEYWORD2 -setColorDepth KEYWORD2 -getColorDepth KEYWORD2 -createPalette KEYWORD2 -setPaletteColor KEYWORD2 -getPaletteColor KEYWORD2 -setBitmapColor KEYWORD2 -fillSprite KEYWORD2 -setScrollRect KEYWORD2 -scroll KEYWORD2 -pushRotated KEYWORD2 -setPivot KEYWORD2 -getPivotX KEYWORD2 -getPivotY KEYWORD2 -getRotatedBounds KEYWORD2 -readPixelValue KEYWORD2 -pushToSprite KEYWORD2 -drawGlyph KEYWORD2 -printToSprite KEYWORD2 -pushSprite KEYWORD2 diff --git a/lib/TFT_eSPI/library.json b/lib/TFT_eSPI/library.json index f590f3e..f85e53c 100644 --- a/lib/TFT_eSPI/library.json +++ b/lib/TFT_eSPI/library.json @@ -1,8 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.5.43", - "keywords": "Arduino, tft, display, ttgo, LilyPi, WT32-SC01, ePaper, display, Pico, RP2040 Nano Connect, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, ST7796, RM68140, SSD1351, SSD1963, ILI9225, HX8357D, GC9A01, R61581", - "description": "A TFT and ePaper (SPI or parallel interface) graphics library with optimisation for Raspberry Pi Pico, RP2040, ESP8266, ESP32 and STM32 processors", + "version": "2.5.43l", "repository": { "type": "git", @@ -17,6 +15,6 @@ } ], "frameworks": "arduino", - "platforms": "raspberrypi, espressif8266, espressif32, ststm32", + "platforms": "espressif32", "headers": "TFT_eSPI.h" } diff --git a/lib/TFT_eSPI/library.properties b/lib/TFT_eSPI/library.properties deleted file mode 100644 index 319d4ec..0000000 --- a/lib/TFT_eSPI/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=TFT_eSPI -version=2.5.43 -author=Bodmer -maintainer=Bodmer -sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32 -paragraph=Supports TFT displays using drivers (ILI9341 etc.) that operate with hardware SPI or 8/16-bit parallel. -category=Display -url=https://github.com/Bodmer/TFT_eSPI -architectures=* -includes=TFT_eSPI.h - diff --git a/src/RdsPiBuffer.cpp b/src/RdsPiBuffer.cpp index 43d003f..ae4322e 100644 --- a/src/RdsPiBuffer.cpp +++ b/src/RdsPiBuffer.cpp @@ -28,10 +28,8 @@ RdsPiBuffer::State RdsPiBuffer::getState(uint16_t value) { uint8_t count = 0; uint8_t correctCount = 0; - for (uint8_t i = 0; i < this->fill; i++) - { - if (this->buff[i] == value) - { + for (uint8_t i = 0; i < this->fill; i++) { + if (this->buff[i] == value) { count++; if ((this->errorBuff[i / 8] & (1 << (i % 8))) == 0) correctCount++; } diff --git a/src/globals.cpp b/src/globals.cpp index 5379db4..cbc3adb 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -2,11 +2,7 @@ bool RDSstatus; bool RDSstatusold; -#ifdef ARS -TFT_eSPI tft = TFT_eSPI(320, 240); -#else -TFT_eSPI tft = TFT_eSPI(240, 320); -#endif +TFT_eSPI tft = TFT_eSPI(); bool Data_Accelerator = false; @@ -78,7 +74,6 @@ byte band; byte bandAM; byte bandFM; byte bandforbidden; -byte battery; byte batteryold; byte batteryoptions; byte BWset; @@ -339,7 +334,6 @@ mem presets[EE_PRESETS_CNT]; TEF6686 radio; ESP32Time rtc(0); - // FrequencySprite.createSprite(200, 50); // RDSSprite.createSprite(165, 19); // PSSprite.createSprite(150, 32); diff --git a/src/gui.cpp b/src/gui.cpp index caa6bf6..67c550c 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -1341,7 +1341,7 @@ void ShowOneLine(byte position, byte item, bool selected) { FullLineSprite.setTextDatum(TR_DATUM); FullLineSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); - if (fmdeemphasis != DEEMPHASIS_NONE) FullLineSprite.drawString(String((fmdeemphasis == DEEMPHASIS_50 ? FM_DEEMPHASIS_50 : FM_DEEMPHASIS_75), DEC), 258, 2); + if (fmdeemphasis != DEEMPHASIS_NONE) FullLineSprite.drawString(String((fmdeemphasis == DEEMPHASIS_50 ? 50 : 75), DEC), 258, 2); if (fmdeemphasis != DEEMPHASIS_NONE) FullLineSprite.setTextColor(ActiveColor, ActiveColorSmooth, false); FullLineSprite.drawString(((fmdeemphasis != DEEMPHASIS_NONE) != 0 ? "μs" : textUI(30)), 298, 2); break; @@ -2429,7 +2429,7 @@ void ShowOneButton(byte position, byte item, bool selected) { PSSprite.drawString(textUI(30), 75, 15); } else { PSSprite.setTextDatum(TR_DATUM); - PSSprite.drawString(String((fmdeemphasis == DEEMPHASIS_50 ? FM_DEEMPHASIS_50 : FM_DEEMPHASIS_75), DEC), 73, 15); + PSSprite.drawString(String((fmdeemphasis == DEEMPHASIS_50 ? 50 : 75), DEC), 73, 15); PSSprite.setTextColor(ActiveColor, ActiveColorSmooth, false); PSSprite.setTextDatum(TL_DATUM); PSSprite.drawString("μs", 77, 15); @@ -3511,7 +3511,7 @@ void MenuUpDown(bool dir) { if (fmdeemphasis != DEEMPHASIS_NONE) OneBigLineSprite.drawString("μs", 155, 0); if (fmdeemphasis != DEEMPHASIS_NONE) OneBigLineSprite.setTextDatum(TR_DATUM); else OneBigLineSprite.setTextDatum(TC_DATUM); OneBigLineSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); - OneBigLineSprite.drawString((fmdeemphasis != DEEMPHASIS_NONE ? (fmdeemphasis == DEEMPHASIS_50 ? String(FM_DEEMPHASIS_50, DEC) : String(FM_DEEMPHASIS_75, DEC)) : textUI(30)), 135, 0); + OneBigLineSprite.drawString((fmdeemphasis != DEEMPHASIS_NONE ? (fmdeemphasis == DEEMPHASIS_50 ? String(50, DEC) : String(75, DEC)) : textUI(30)), 135, 0); OneBigLineSprite.pushSprite(24, 118); radio.setDeemphasis(fmdeemphasis); break; @@ -4801,7 +4801,7 @@ void DoMenu() { if (fmdeemphasis != DEEMPHASIS_NONE) OneBigLineSprite.drawString("μs", 155, 0); if (fmdeemphasis != DEEMPHASIS_NONE) OneBigLineSprite.setTextDatum(TR_DATUM); else OneBigLineSprite.setTextDatum(TC_DATUM); OneBigLineSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); - OneBigLineSprite.drawString((fmdeemphasis != DEEMPHASIS_NONE ? (fmdeemphasis == DEEMPHASIS_50 ? String(FM_DEEMPHASIS_50, DEC) : String(FM_DEEMPHASIS_75, DEC)) : textUI(30)), 135, 0); + OneBigLineSprite.drawString((fmdeemphasis != DEEMPHASIS_NONE ? (fmdeemphasis == DEEMPHASIS_50 ? String(50, DEC) : String(75, DEC)) : textUI(30)), 135, 0); OneBigLineSprite.pushSprite(24, 118); break; } diff --git a/src/main.cpp b/src/main.cpp index ad01075..14ae127 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #pragma region includes #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" -#include #include #include #include @@ -15,16 +14,13 @@ using fs::FS; #include "FONT28_CHS.h" #include "FONT48DEC.h" #include "FREQFONT.h" -#include "TEF6686.h" -#include "constants.h" -#include "language.h" +#include "globals.h" #include "gui.h" #include "comms.h" #include "rds.h" #include "touch.h" -#include "logbook.h" +#include "nonvolatile.h" #include "utils.h" -#include "globals.h" #pragma endregion #pragma region to move @@ -63,22 +59,6 @@ void Touch_IRQ_Handler() { touch_detect = true; } -void StoreFrequency() { - switch (band) { - case BAND_LW: freqold = frequency_LW; frequency_AM = frequency_LW; break; - case BAND_MW: freqold = frequency_MW; frequency_AM = frequency_MW; break; - case BAND_SW: freqold = frequency_SW; frequency_AM = frequency_SW; break; - } - EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, frequency); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, frequency_OIRT); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, frequency_AM); - EEPROM.writeByte(EE_BYTE_BAND, band); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, frequency_LW); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, frequency_MW); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, frequency_SW); - EEPROM.commit(); -} - void deepSleep() { analogWrite(SMETERPIN, 0); pinMode(STANDBYLED, OUTPUT); @@ -883,29 +863,6 @@ int GetNum() { return -1; } -void ClearMemoryRange(uint8_t start, uint8_t stop) { - for (uint8_t pos = start; pos <= stop; pos++) { - EEPROM.writeByte(pos + EE_PRESETS_BAND_START, BAND_FM); - EEPROM.writeUInt((pos * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY); - EEPROM.writeByte(pos + EE_PRESET_BW_START, 0); - EEPROM.writeByte(pos + EE_PRESET_MS_START, 1); - - for (int y = 0; y < 9; y++) { - EEPROM.writeByte((pos * 9) + y + EE_PRESETS_RDSPS_START, '\0'); - presets[pos].RDSPS[y] = '\0'; - } - - for (int y = 0; y < 5; y++) { - EEPROM.writeByte((pos * 5) + y + EE_PRESETS_RDSPI_START, '\0'); - presets[pos].RDSPI[y] = '\0'; - } - - EEPROM.commit(); - presets[pos].band = BAND_FM; - presets[pos].frequency = EE_PRESETS_FREQUENCY; - } -} - void StoreMemoryPos(uint8_t _pos) { EEPROM.writeByte(_pos + EE_PRESETS_BAND_START, band); EEPROM.writeByte(_pos + EE_PRESET_BW_START, BWset); @@ -1118,94 +1075,6 @@ void endMenu() { SelectBand(); } -void saveData() { - EEPROM.writeByte(EE_BYTE_VOLSET, VolSet); - EEPROM.writeUInt(EE_UINT16_CONVERTERSET, ConverterSet); - EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, LowEdgeSet); - EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, HighEdgeSet); - EEPROM.writeByte(EE_BYTE_CONTRASTSET, ContrastSet); - EEPROM.writeByte(EE_BYTE_STEREOLEVEL, StereoLevel); - EEPROM.writeByte(EE_BYTE_BANDFM, bandFM); - EEPROM.writeByte(EE_BYTE_BANDAM, bandAM); - EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, HighCutLevel); - EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, HighCutOffset); - EEPROM.writeByte(EE_BYTE_LEVELOFFSET, LevelOffset); - EEPROM.writeByte(EE_BYTE_RTBUFFER, radio.rds.rtbuffer); - EEPROM.writeByte(EE_BYTE_EDGEBEEP, edgebeep); - EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, softmuteam); - EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, softmutefm); - EEPROM.writeByte(EE_BYTE_LANGUAGE, language); - EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, showrdserrors); - EEPROM.writeByte(EE_BYTE_LOWLEVELSET, LowLevelSet); - EEPROM.writeByte(EE_BYTE_REGION, radio.rds.region); - EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, radio.underscore); - EEPROM.writeByte(EE_BYTE_USBMODE, USBmode); - EEPROM.writeByte(EE_BYTE_WIFI, wifi); - EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, subnetclient); - EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, showSWMIBand); - EEPROM.writeByte(EE_BYTE_RDS_FILTER, radio.rds.filter); - EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, radio.rds.pierrors); - EEPROM.writeByte(EE_BYTE_USESQUELCH, usesquelch); - EEPROM.writeByte(EE_BYTE_SHOWMODULATION, showmodulation); - EEPROM.writeByte(EE_BYTE_AM_NB, amnb); - EEPROM.writeByte(EE_BYTE_FM_NB, fmnb); - EEPROM.writeByte(EE_BYTE_AUDIOMODE, audiomode); - EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, touchrotating); - EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, LowEdgeOIRTSet); - EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, HighEdgeOIRTSet); - EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, hardwaremodel); - EEPROM.writeByte(EE_BYTE_POWEROPTIONS, poweroptions); - EEPROM.writeByte(EE_BYTE_CURRENTTHEME, CurrentTheme); - EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, fmdefaultstepsize); - EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, screensaverset); - EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, AMLevelOffset); - EEPROM.writeByte(EE_BYTE_UNIT, unit); - EEPROM.writeByte(EE_BYTE_AF, af); - EEPROM.writeByte(EE_BYTE_STEREO, StereoToggle); - EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, batteryoptions); - EEPROM.writeByte(EE_BYTE_AM_CO_DECT, amcodect); - EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, amcodectcount); - EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, amgain); - EEPROM.writeByte(EE_BYTE_SORTAF, radio.rds.sortaf); - EEPROM.writeByte(EE_BYTE_STATIONLISTID, stationlistid); - EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, fmdeemphasis); - EEPROM.writeByte(EE_BYTE_FASTPS, radio.rds.fastps); - EEPROM.writeByte(EE_BYTE_TOT, tot); - EEPROM.writeByte(EE_BYTE_MWREGION, mwstepsize); - EEPROM.writeByte(EE_BYTE_SPISPEED, spispeed); - EEPROM.writeByte(EE_BYTE_AMSCANSENS, amscansens); - EEPROM.writeByte(EE_BYTE_FMSCANSENS, fmscansens); - EEPROM.writeByte(EE_BYTE_FREQFONT, freqfont); - EEPROM.writeByte(EE_BYTE_SKIN, CurrentSkin); - EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, XDRGTKMuteScreen); - EEPROM.writeByte(EE_BYTE_FMAGC, fmagc); - EEPROM.writeByte(EE_BYTE_AMAGC, amagc); - EEPROM.writeByte(EE_BYTE_FMSI, fmsi); - EEPROM.writeByte(EE_BYTE_SCANSTART, scanstart); - EEPROM.writeByte(EE_BYTE_SCANSTOP, scanstop); - EEPROM.writeByte(EE_BYTE_SCANHOLD, scanhold); - EEPROM.writeByte(EE_BYTE_SCANMEM, scanmem); - EEPROM.writeByte(EE_BYTE_SCANCANCEL, scancancel); - EEPROM.writeByte(EE_BYTE_SCANMUTE, scanmute); - EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, autosquelch); - EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, longbandpress); - EEPROM.writeByte(EE_BYTE_SHOWCLOCK, showclock); - EEPROM.writeByte(EE_BYTE_SHOWLONGPS, showlongps); - EEPROM.writeUInt(EE_UINT16_MEMSTARTFREQ, memstartfreq); - EEPROM.writeUInt(EE_UINT16_MEMSTOPFREQ, memstopfreq); - EEPROM.writeByte(EE_BYTE_MEMSTARTPOS, memstartpos); - EEPROM.writeByte(EE_BYTE_MEMSTOPPOS, memstoppos); - EEPROM.writeByte(EE_BYTE_MEMPIONLY, mempionly); - EEPROM.writeByte(EE_BYTE_MEMDOUBLEPI, memdoublepi); - EEPROM.writeByte(EE_BYTE_WAITONLYONSIGNAL, scanholdonsignal); - EEPROM.writeByte(EE_BYTE_NTPOFFSET, NTPoffset); - EEPROM.writeByte(EE_BYTE_AUTOLOG, autolog); - EEPROM.writeByte(EE_BYTE_AUTODST, autoDST); - EEPROM.writeByte(EE_BYTE_CLOCKAMPM, clockampm); - EEPROM.writeUInt(EE_UINT16_PICTLOCK, radio.rds.PICTlock); - EEPROM.commit(); -} - void cancelDXScan() { tunemode = scanmodeold; memorypos = memoryposold; @@ -1264,7 +1133,6 @@ void MuteScreen(bool setting) { } #pragma endregion -void DefaultSettings(); void read_encoder(); void setup() { WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); @@ -1279,118 +1147,7 @@ void setup() { setupmode = true; EEPROM.begin(EE_TOTAL_CNT); - if (EEPROM.readByte(EE_BYTE_CHECKBYTE) != EE_CHECKBYTE_VALUE) DefaultSettings(); - - frequency = EEPROM.readUInt(EE_UINT16_FREQUENCY_FM); - frequency_OIRT = EEPROM.readUInt(EE_UINT16_FREQUENCY_OIRT); - VolSet = EEPROM.readByte(EE_BYTE_VOLSET); - ConverterSet = EEPROM.readUInt(EE_UINT16_CONVERTERSET); - LowEdgeSet = EEPROM.readUInt(EE_UINT16_FMLOWEDGESET); - HighEdgeSet = EEPROM.readUInt(EE_UINT16_FMHIGHEDGESET); - ContrastSet = EEPROM.readByte(EE_BYTE_CONTRASTSET); - StereoLevel = EEPROM.readByte(EE_BYTE_STEREOLEVEL); - bandFM = EEPROM.readByte(EE_BYTE_BANDFM); - bandAM = EEPROM.readByte(EE_BYTE_BANDAM); - HighCutLevel = EEPROM.readByte(EE_BYTE_HIGHCUTLEVEL); - HighCutOffset = EEPROM.readByte(EE_BYTE_HIGHCUTOFFSET); - LevelOffset = EEPROM.readByte(EE_BYTE_LEVELOFFSET); - radio.rds.rtbuffer = EEPROM.readByte(EE_BYTE_RTBUFFER); - edgebeep = EEPROM.readByte(EE_BYTE_EDGEBEEP); - softmuteam = EEPROM.readByte(EE_BYTE_SOFTMUTEAM); - softmutefm = EEPROM.readByte(EE_BYTE_SOFTMUTEFM); - frequency_AM = EEPROM.readUInt(EE_UINT16_FREQUENCY_AM); - language = EEPROM.readByte(EE_BYTE_LANGUAGE); - showrdserrors = EEPROM.readByte(EE_BYTE_SHOWRDSERRORS); - TEF = EEPROM.readByte(EE_BYTE_TEF); - displayflip = EEPROM.readByte(EE_BYTE_DISPLAYFLIP); - rotarymode = EEPROM.readByte(EE_BYTE_ROTARYMODE); - tunemode = EEPROM.readByte(EE_BYTE_TUNEMODE); - if (tunemode == TUNE_MAN) stepsize = EEPROM.readByte(EE_BYTE_STEPSIZE); else stepsize = 0; - optenc = EEPROM.readByte(EE_BYTE_OPTENC); - iMSset = EEPROM.readByte(EE_BYTE_IMSSET); - EQset = EEPROM.readByte(EE_BYTE_EQSET); - band = EEPROM.readByte(EE_BYTE_BAND); - LowLevelSet = EEPROM.readByte(EE_BYTE_LOWLEVELSET); - memorypos = EEPROM.readByte(EE_BYTE_MEMORYPOS); - radio.rds.region = EEPROM.readByte(EE_BYTE_REGION); - radio.underscore = EEPROM.readByte(EE_BYTE_RDS_UNDERSCORE); - USBmode = EEPROM.readByte(EE_BYTE_USBMODE); - wifi = EEPROM.readByte(EE_BYTE_WIFI); - subnetclient = EEPROM.readByte(EE_BYTE_SUBNETCLIENT); - showSWMIBand = EEPROM.readByte(EE_BYTE_SHOWSWMIBAND); - radio.rds.filter = EEPROM.readByte(EE_BYTE_RDS_FILTER); - radio.rds.pierrors = EEPROM.readByte(EE_BYTE_RDS_PIERRORS); - frequency_LW = EEPROM.readUInt(EE_UINT16_FREQUENCY_LW); - frequency_MW = EEPROM.readUInt(EE_UINT16_FREQUENCY_MW); - frequency_SW = EEPROM.readUInt(EE_UINT16_FREQUENCY_SW); - XDRGTK_key = EEPROM.readString(EE_STRING_XDRGTK_KEY); - usesquelch = EEPROM.readByte(EE_BYTE_USESQUELCH); - showmodulation = EEPROM.readByte(EE_BYTE_SHOWMODULATION); - amnb = EEPROM.readByte(EE_BYTE_AM_NB); - fmnb = EEPROM.readByte(EE_BYTE_FM_NB); - audiomode = EEPROM.readByte(EE_BYTE_AUDIOMODE); - touchrotating = EEPROM.readByte(EE_BYTE_TOUCH_ROTATING); - hardwaremodel = EEPROM.readByte(EE_BYTE_HARDWARE_MODEL); - poweroptions = EEPROM.readByte(EE_BYTE_POWEROPTIONS); - CurrentTheme = EEPROM.readByte(EE_BYTE_CURRENTTHEME); - fmdefaultstepsize = EEPROM.readByte(EE_BYTE_FMDEFAULTSTEPSIZE); - screensaverset = EEPROM.readByte(EE_BYTE_SCREENSAVERSET); - AMLevelOffset = EEPROM.readInt(EE_INT16_AMLEVELOFFSET); - unit = EEPROM.readByte(EE_BYTE_UNIT); - af = EEPROM.readByte(EE_BYTE_AF); - if (af == 2) radio.rds.afreg = true; else radio.rds.afreg = false; - StereoToggle = EEPROM.readByte(EE_BYTE_STEREO); - batteryoptions = EEPROM.readByte(EE_BYTE_BATTERY_OPTIONS); - amcodect = EEPROM.readByte(EE_BYTE_AM_CO_DECT); - amcodectcount = EEPROM.readByte(EE_BYTE_AM_CO_DECT_COUNT); - amgain = EEPROM.readByte(EE_BYTE_AM_RF_GAIN); - radio.rds.sortaf = EEPROM.readByte(EE_BYTE_SORTAF); - stationlistid = EEPROM.readByte(EE_BYTE_STATIONLISTID); - fmdeemphasis = EEPROM.readByte(EE_BYTE_FM_DEEMPHASIS); - BWsetFM = EEPROM.readByte(EE_BYTE_BWSET_FM); - BWsetAM = EEPROM.readByte(EE_BYTE_BWSET_AM); - nowToggleSWMIBand = EEPROM.readByte(EE_BYTE_BANDAUTOSW); - radio.rds.fastps = EEPROM.readByte(EE_BYTE_FASTPS); - tot = EEPROM.readByte(EE_BYTE_TOT); - mwstepsize = EEPROM.readByte(EE_BYTE_MWREGION); - spispeed = EEPROM.readByte(EE_BYTE_SPISPEED); - amscansens = EEPROM.readByte(EE_BYTE_AMSCANSENS); - fmscansens = EEPROM.readByte(EE_BYTE_FMSCANSENS); - freqfont = EEPROM.readByte(EE_BYTE_FREQFONT); - CurrentSkin = EEPROM.readByte(EE_BYTE_SKIN); - XDRGTKMuteScreen = EEPROM.readByte(EE_BYTE_XDRGTKMUTE); - fmagc = EEPROM.readByte(EE_BYTE_FMAGC); - amagc = EEPROM.readByte(EE_BYTE_AMAGC); - fmsi = EEPROM.readByte(EE_BYTE_FMSI); - scanstart = EEPROM.readByte(EE_BYTE_SCANSTART); - scanstop = EEPROM.readByte(EE_BYTE_SCANSTOP); - scanhold = EEPROM.readByte(EE_BYTE_SCANHOLD); - scanmem = EEPROM.readByte(EE_BYTE_SCANMEM); - scancancel = EEPROM.readByte(EE_BYTE_SCANCANCEL); - scanmute = EEPROM.readByte(EE_BYTE_SCANMUTE); - autosquelch = EEPROM.readByte(EE_BYTE_AUTOSQUELCH); - longbandpress = EEPROM.readByte(EE_BYTE_LONGBANDPRESS); - showclock = EEPROM.readByte(EE_BYTE_SHOWCLOCK); - showlongps = EEPROM.readByte(EE_BYTE_SHOWLONGPS); - memstartfreq = EEPROM.readUInt(EE_UINT16_MEMSTARTFREQ); - memstopfreq = EEPROM.readUInt(EE_UINT16_MEMSTOPFREQ); - memstartpos = EEPROM.readByte(EE_BYTE_MEMSTARTPOS); - memstoppos = EEPROM.readByte(EE_BYTE_MEMSTOPPOS); - mempionly = EEPROM.readByte(EE_BYTE_MEMPIONLY); - memdoublepi = EEPROM.readByte(EE_BYTE_MEMDOUBLEPI); - scanholdonsignal = EEPROM.readByte(EE_BYTE_WAITONLYONSIGNAL); - TouchCalData[0] = EEPROM.readUInt(EE_UINT16_CALTOUCH1); - TouchCalData[1] = EEPROM.readUInt(EE_UINT16_CALTOUCH2); - TouchCalData[2] = EEPROM.readUInt(EE_UINT16_CALTOUCH3); - TouchCalData[3] = EEPROM.readUInt(EE_UINT16_CALTOUCH4); - TouchCalData[4] = EEPROM.readUInt(EE_UINT16_CALTOUCH5); - invertdisplay = EEPROM.readByte(EE_BYTE_INVERTDISPLAY); - NTPoffset = EEPROM.readByte(EE_BYTE_NTPOFFSET); - autolog = EEPROM.readByte(EE_BYTE_AUTOLOG); - autoDST = EEPROM.readByte(EE_BYTE_AUTODST); - clockampm = EEPROM.readByte(EE_BYTE_CLOCKAMPM); - logcounter = EEPROM.readUInt(EE_UINT16_LOGCOUNTER); - radio.rds.PICTlock = EEPROM.readUInt(EE_UINT16_PICTLOCK); + loadData(); if (spispeed == SPI_SPEED_DEFAULT) tft.setSPISpeed(SPI_FREQUENCY / 1000000); else if (spispeed == 7) setAutoSpeedSPI(); @@ -1488,19 +1245,15 @@ void setup() { FrequencySprite.setSwapBytes(true); RDSSprite.createSprite(165, 19); - RDSSprite.setTextDatum(TL_DATUM); RDSSprite.setSwapBytes(true); PTYSprite.createSprite(160, 19); - PTYSprite.setTextDatum(TL_DATUM); PTYSprite.setSwapBytes(true); PSSprite.createSprite(150, 32); - PSSprite.setTextDatum(TL_DATUM); PSSprite.setSwapBytes(true); SquelchSprite.createSprite(27, 19); - SquelchSprite.setTextDatum(TL_DATUM); SquelchSprite.setSwapBytes(true); FullLineSprite.createSprite(308, 19); @@ -1511,7 +1264,6 @@ void setup() { SignalSprite.createSprite(80, 48); SignalSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); - SignalSprite.setTextDatum(TR_DATUM); SignalSprite.setSwapBytes(true); UpdateFonts(0); @@ -1683,7 +1435,7 @@ void setup() { Udp.stop(); tft.fillRect(184, 230, 16, 6, SignificantColor); } - delay(1000); + delay(750); radio.setVolume(VolSet); radio.setOffset(LevelOffset); @@ -3756,10 +3508,9 @@ void ShowBattery() { if (millis() >= batupdatetimer + TIMER_BAT_TIMER) batupdatetimer = millis(); else return; - uint16_t v = analogRead(BATTERY_PIN); - battery = map(constrain(v, BAT_LEVEL_EMPTY, BAT_LEVEL_FULL), BAT_LEVEL_EMPTY, BAT_LEVEL_FULL, 0, BAT_LEVEL_STAGE); - byte batteryprobe = map(constrain(v, BAT_LEVEL_EMPTY, BAT_LEVEL_FULL), BAT_LEVEL_EMPTY, BAT_LEVEL_FULL, 0, 20); - + float v = analogReadMilliVolts(BATTERY_PIN) * 0.002; + byte battery = map(constrain(v, BATTERY_LOW_VALUE, BATTERY_FULL_VALUE), BATTERY_LOW_VALUE, BATTERY_FULL_VALUE, 0, BAT_LEVEL_STAGE); + byte batteryprobe = map(constrain(v, BATTERY_LOW_VALUE, BATTERY_FULL_VALUE), BATTERY_LOW_VALUE, BATTERY_FULL_VALUE, 0, 20); if (batteryold != batteryprobe) { if (batterydetect) { if (battery == 0) { @@ -3769,21 +3520,21 @@ void ShowBattery() { tft.drawRoundRect(277, 6, 37, 20, 2, ActiveColor); tft.fillRoundRect(313, 13, 4, 6, 2, ActiveColor); } - if (batteryoptions != BATTERY_VALUE && batteryoptions != BATTERY_PERCENT && battery != 0) tft.fillRoundRect(279, 8, (battery * 8) , 16, 2, BarInsignificantColor); - else tft.fillRoundRect(279, 8, 33, 16, 2, BackgroundColor); + + if (batteryoptions != BATTERY_VALUE && batteryoptions != BATTERY_PERCENT && battery != 0) { + if(v > BATTERY_FULL_VALUE) tft.fillRoundRect(279, 8, 32, 16, 2, ActiveColor); + else tft.fillRoundRect(279, 8, battery * 8, 16, 2, SecondaryColor); + } else tft.fillRoundRect(279, 8, 32, 16, 2, BackgroundColor); } batteryold = batteryprobe; batteryVold = 0; vPerold = 0; - if (batterydetect) { - float batteryV = constrain((((float)v / 4095.0) * 3.3 * (1100 / 1000.0) * 2.0), 0.0, 5.0); - float vPer = constrain((batteryV - BATTERY_LOW_VALUE) / (BATTERY_FULL_VALUE - BATTERY_LOW_VALUE), 0.0, 0.99) * 100; - - if (abs(batteryV - batteryVold) > 0.05 && batteryoptions == BATTERY_VALUE) { - tftPrint(ALEFT, String(batteryV, 2) + "V", 279, 9, BatteryValueColor, BatteryValueColorSmooth, 16); - batteryVold = batteryV; + float vPer = constrain((v - BATTERY_LOW_VALUE) / (BATTERY_FULL_VALUE - BATTERY_LOW_VALUE), 0.0, 1.0) * 100.0; + if (abs(v - batteryVold) > 0.05 && batteryoptions == BATTERY_VALUE) { + tftPrint(ALEFT, String(v, 2) + "V", 279, 9, BatteryValueColor, BatteryValueColorSmooth, 16); + batteryVold = v; } else if (int(vPer) != int(vPerold) && batteryoptions == BATTERY_PERCENT && abs(vPer - vPerold) > 0.5) { tftPrint(ALEFT, String(vPer, 0) + "%", 279, 9, BatteryValueColor, BatteryValueColorSmooth, 16); vPerold = vPer; @@ -4062,144 +3813,6 @@ void read_encoder() { } } -void DefaultSettings() { - EEPROM.writeByte(EE_BYTE_CHECKBYTE, EE_CHECKBYTE_VALUE); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, 9500); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, FREQ_FM_OIRT_START); - EEPROM.writeByte(EE_BYTE_VOLSET, 0); - EEPROM.writeUInt(EE_UINT16_CONVERTERSET, 0); - EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, 875); - EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, 1080); - EEPROM.writeByte(EE_BYTE_CONTRASTSET, 50); - EEPROM.writeByte(EE_BYTE_STEREOLEVEL, 0); - EEPROM.writeByte(EE_BYTE_BANDFM, FM_BAND_ALL); - EEPROM.writeByte(EE_BYTE_BANDAM, AM_BAND_ALL); - EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, 70); - EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, 0); - EEPROM.writeByte(EE_BYTE_LEVELOFFSET, 0); - EEPROM.writeByte(EE_BYTE_RTBUFFER, 1); - EEPROM.writeByte(EE_BYTE_EDGEBEEP, 0); - EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, 1); - EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, 0); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, 828); - EEPROM.writeByte(EE_BYTE_LANGUAGE, 0); - EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, 1); - EEPROM.writeByte(EE_BYTE_TEF, 0); - EEPROM.writeByte(EE_BYTE_STEPSIZE, 0); - EEPROM.writeByte(EE_BYTE_TUNEMODE, 0); - EEPROM.writeByte(EE_BYTE_OPTENC, 0); - EEPROM.writeByte(EE_BYTE_IMSSET, 1); - EEPROM.writeByte(EE_BYTE_EQSET, 1); - EEPROM.writeByte(EE_BYTE_BAND, BAND_FM); - EEPROM.writeByte(EE_BYTE_LOWLEVELSET, -15); - EEPROM.writeByte(EE_BYTE_MEMORYPOS, 0); - EEPROM.writeByte(EE_BYTE_REGION, 0); - EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, 0); - EEPROM.writeByte(EE_BYTE_USBMODE, 0); - EEPROM.writeByte(EE_BYTE_WIFI, 0); - EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, 1); - EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, 1); - EEPROM.writeByte(EE_BYTE_RDS_FILTER, 1); - EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, 0); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, 180); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, 540); - EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, 1800); - EEPROM.writeString(EE_STRING_XDRGTK_KEY, "password"); - EEPROM.writeByte(EE_BYTE_USESQUELCH, 1); - EEPROM.writeByte(EE_BYTE_SHOWMODULATION, 1); - EEPROM.writeByte(EE_BYTE_AM_NB, 0); - EEPROM.writeByte(EE_BYTE_FM_NB, 0); - EEPROM.writeByte(EE_BYTE_AUDIOMODE, 0); - EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, 0); - EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, 0); - EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, 0); - EEPROM.writeByte(EE_BYTE_POWEROPTIONS, 1); - EEPROM.writeByte(EE_BYTE_CURRENTTHEME, 0); - EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, 1); - EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, 0); - EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, 0); - EEPROM.writeByte(EE_BYTE_UNIT, 0); - EEPROM.writeByte(EE_BYTE_AF, 0); - EEPROM.writeByte(EE_BYTE_STEREO, 1); - EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, BATTERY_VALUE); - EEPROM.writeByte(EE_BYTE_AM_CO_DECT, 100); - EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, 3); - EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, 0); - EEPROM.writeByte(EE_BYTE_SORTAF, 1); - EEPROM.writeByte(EE_BYTE_STATIONLISTID, 1); - EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, DEEMPHASIS_50); - EEPROM.writeByte(EE_BYTE_BWSET_FM, 0); - EEPROM.writeByte(EE_BYTE_BWSET_AM, 2); - EEPROM.writeByte(EE_BYTE_BANDAUTOSW, 0); - EEPROM.writeByte(EE_BYTE_FASTPS, 1); - EEPROM.writeByte(EE_BYTE_TOT, 0); - EEPROM.writeByte(EE_BYTE_MWREGION, 0); - EEPROM.writeByte(EE_BYTE_AMSCANSENS, 4); - EEPROM.writeByte(EE_BYTE_FMSCANSENS, 4); - EEPROM.writeByte(EE_BYTE_FREQFONT, 3); - EEPROM.writeByte(EE_BYTE_SKIN, 0); - EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, 0); - EEPROM.writeByte(EE_BYTE_FMAGC, 92); - EEPROM.writeByte(EE_BYTE_AMAGC, 100); - EEPROM.writeByte(EE_BYTE_FMSI, 1); - EEPROM.writeByte(EE_BYTE_SCANSTART, 0); - EEPROM.writeByte(EE_BYTE_SCANSTOP, 9); - EEPROM.writeByte(EE_BYTE_SCANHOLD, 5); - EEPROM.writeByte(EE_BYTE_SCANMEM, 1); - EEPROM.writeByte(EE_BYTE_SCANCANCEL, 0); - EEPROM.writeByte(EE_BYTE_SCANMUTE, 0); - EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, 0); - EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, 0); - EEPROM.writeByte(EE_BYTE_SHOWCLOCK, 1); - EEPROM.writeByte(EE_BYTE_SHOWLONGPS, 1); - EEPROM.writeUInt(EE_UINT16_MEMSTARTFREQ, 875); - EEPROM.writeUInt(EE_UINT16_MEMSTOPFREQ, 1080); - EEPROM.writeByte(EE_BYTE_MEMSTARTPOS, 1); - EEPROM.writeByte(EE_BYTE_MEMSTOPPOS, 10); - EEPROM.writeByte(EE_BYTE_MEMPIONLY, 1); - EEPROM.writeByte(EE_BYTE_MEMDOUBLEPI, 0); - EEPROM.writeByte(EE_BYTE_WAITONLYONSIGNAL, 1); - EEPROM.writeUInt(EE_UINT16_CALTOUCH1, 300); - EEPROM.writeUInt(EE_UINT16_CALTOUCH2, 3450); - EEPROM.writeUInt(EE_UINT16_CALTOUCH3, 300); - EEPROM.writeUInt(EE_UINT16_CALTOUCH4, 3450); - EEPROM.writeUInt(EE_UINT16_CALTOUCH5, 3); - EEPROM.writeByte(EE_BYTE_NTPOFFSET, 1); - EEPROM.writeByte(EE_BYTE_AUTOLOG, 1); - EEPROM.writeByte(EE_BYTE_AUTODST, 1); - EEPROM.writeByte(EE_BYTE_CLOCKAMPM, 0); - EEPROM.writeUInt(EE_UINT16_PICTLOCK, 0); - - EEPROM.writeByte(EE_BYTE_SPISPEED, 7); - -#ifdef DEEPELEC_DP_66X - EEPROM.writeByte(EE_BYTE_ROTARYMODE, 1); - EEPROM.writeByte(EE_BYTE_INVERTDISPLAY, 0); - EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 1); - EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, PORTABLE_TOUCH_ILI9341); -#else - EEPROM.writeByte(EE_BYTE_ROTARYMODE, 0); - EEPROM.writeByte(EE_BYTE_INVERTDISPLAY, 1); - EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 0); - EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, BASE_ILI9341); -#endif - - for (int i = 0; i < EE_PRESETS_CNT; i++) { - EEPROM.writeByte(i + EE_PRESETS_BAND_START, BAND_FM); - EEPROM.writeUInt((i * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY); - EEPROM.writeByte(i + EE_PRESET_BW_START, 0); - EEPROM.writeByte(i + EE_PRESET_MS_START, 1); - - for (int y = 0; y < 9; y++) EEPROM.writeByte((i * 9) + y + EE_PRESETS_RDSPS_START, '\0'); - - for (int y = 0; y < 5; y++) EEPROM.writeByte((i * 5) + y + EE_PRESETS_RDSPI_START, '\0'); - } - - EEPROM.commit(); - - handleCreateNewLogbook(); -} - void tftReplace(int8_t offset, const String & textold, const String & text, int16_t x, int16_t y, int color, int smoothcolor, int background, uint8_t fontsize) { const uint8_t *selectedFont = nullptr; if (language == LANGUAGE_CHS) { diff --git a/src/nonvolatile.cpp b/src/nonvolatile.cpp new file mode 100644 index 0000000..a807056 --- /dev/null +++ b/src/nonvolatile.cpp @@ -0,0 +1,381 @@ +#include "nonvolatile.h" + +void StoreFrequency() { + switch (band) { + case BAND_LW: freqold = frequency_LW; frequency_AM = frequency_LW; break; + case BAND_MW: freqold = frequency_MW; frequency_AM = frequency_MW; break; + case BAND_SW: freqold = frequency_SW; frequency_AM = frequency_SW; break; + } + EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, frequency); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, frequency_OIRT); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, frequency_AM); + EEPROM.writeByte(EE_BYTE_BAND, band); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, frequency_LW); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, frequency_MW); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, frequency_SW); + EEPROM.commit(); +} + +void ClearMemoryRange(uint8_t start, uint8_t stop) { + for (uint8_t pos = start; pos <= stop; pos++) { + EEPROM.writeByte(pos + EE_PRESETS_BAND_START, BAND_FM); + EEPROM.writeUInt((pos * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY); + EEPROM.writeByte(pos + EE_PRESET_BW_START, 0); + EEPROM.writeByte(pos + EE_PRESET_MS_START, 1); + + for (int y = 0; y < 9; y++) { + EEPROM.writeByte((pos * 9) + y + EE_PRESETS_RDSPS_START, '\0'); + presets[pos].RDSPS[y] = '\0'; + } + + for (int y = 0; y < 5; y++) { + EEPROM.writeByte((pos * 5) + y + EE_PRESETS_RDSPI_START, '\0'); + presets[pos].RDSPI[y] = '\0'; + } + + EEPROM.commit(); + presets[pos].band = BAND_FM; + presets[pos].frequency = EE_PRESETS_FREQUENCY; + } +} + +void saveData() { + EEPROM.writeByte(EE_BYTE_VOLSET, VolSet); + EEPROM.writeUInt(EE_UINT16_CONVERTERSET, ConverterSet); + EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, LowEdgeSet); + EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, HighEdgeSet); + EEPROM.writeByte(EE_BYTE_CONTRASTSET, ContrastSet); + EEPROM.writeByte(EE_BYTE_STEREOLEVEL, StereoLevel); + EEPROM.writeByte(EE_BYTE_BANDFM, bandFM); + EEPROM.writeByte(EE_BYTE_BANDAM, bandAM); + EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, HighCutLevel); + EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, HighCutOffset); + EEPROM.writeByte(EE_BYTE_LEVELOFFSET, LevelOffset); + EEPROM.writeByte(EE_BYTE_RTBUFFER, radio.rds.rtbuffer); + EEPROM.writeByte(EE_BYTE_EDGEBEEP, edgebeep); + EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, softmuteam); + EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, softmutefm); + EEPROM.writeByte(EE_BYTE_LANGUAGE, language); + EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, showrdserrors); + EEPROM.writeByte(EE_BYTE_LOWLEVELSET, LowLevelSet); + EEPROM.writeByte(EE_BYTE_REGION, radio.rds.region); + EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, radio.underscore); + EEPROM.writeByte(EE_BYTE_USBMODE, USBmode); + EEPROM.writeByte(EE_BYTE_WIFI, wifi); + EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, subnetclient); + EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, showSWMIBand); + EEPROM.writeByte(EE_BYTE_RDS_FILTER, radio.rds.filter); + EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, radio.rds.pierrors); + EEPROM.writeByte(EE_BYTE_USESQUELCH, usesquelch); + EEPROM.writeByte(EE_BYTE_SHOWMODULATION, showmodulation); + EEPROM.writeByte(EE_BYTE_AM_NB, amnb); + EEPROM.writeByte(EE_BYTE_FM_NB, fmnb); + EEPROM.writeByte(EE_BYTE_AUDIOMODE, audiomode); + EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, touchrotating); + EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, LowEdgeOIRTSet); + EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, HighEdgeOIRTSet); + EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, hardwaremodel); + EEPROM.writeByte(EE_BYTE_POWEROPTIONS, poweroptions); + EEPROM.writeByte(EE_BYTE_CURRENTTHEME, CurrentTheme); + EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, fmdefaultstepsize); + EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, screensaverset); + EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, AMLevelOffset); + EEPROM.writeByte(EE_BYTE_UNIT, unit); + EEPROM.writeByte(EE_BYTE_AF, af); + EEPROM.writeByte(EE_BYTE_STEREO, StereoToggle); + EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, batteryoptions); + EEPROM.writeByte(EE_BYTE_AM_CO_DECT, amcodect); + EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, amcodectcount); + EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, amgain); + EEPROM.writeByte(EE_BYTE_SORTAF, radio.rds.sortaf); + EEPROM.writeByte(EE_BYTE_STATIONLISTID, stationlistid); + EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, fmdeemphasis); + EEPROM.writeByte(EE_BYTE_FASTPS, radio.rds.fastps); + EEPROM.writeByte(EE_BYTE_TOT, tot); + EEPROM.writeByte(EE_BYTE_MWREGION, mwstepsize); + EEPROM.writeByte(EE_BYTE_SPISPEED, spispeed); + EEPROM.writeByte(EE_BYTE_AMSCANSENS, amscansens); + EEPROM.writeByte(EE_BYTE_FMSCANSENS, fmscansens); + EEPROM.writeByte(EE_BYTE_FREQFONT, freqfont); + EEPROM.writeByte(EE_BYTE_SKIN, CurrentSkin); + EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, XDRGTKMuteScreen); + EEPROM.writeByte(EE_BYTE_FMAGC, fmagc); + EEPROM.writeByte(EE_BYTE_AMAGC, amagc); + EEPROM.writeByte(EE_BYTE_FMSI, fmsi); + EEPROM.writeByte(EE_BYTE_SCANSTART, scanstart); + EEPROM.writeByte(EE_BYTE_SCANSTOP, scanstop); + EEPROM.writeByte(EE_BYTE_SCANHOLD, scanhold); + EEPROM.writeByte(EE_BYTE_SCANMEM, scanmem); + EEPROM.writeByte(EE_BYTE_SCANCANCEL, scancancel); + EEPROM.writeByte(EE_BYTE_SCANMUTE, scanmute); + EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, autosquelch); + EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, longbandpress); + EEPROM.writeByte(EE_BYTE_SHOWCLOCK, showclock); + EEPROM.writeByte(EE_BYTE_SHOWLONGPS, showlongps); + EEPROM.writeUInt(EE_UINT16_MEMSTARTFREQ, memstartfreq); + EEPROM.writeUInt(EE_UINT16_MEMSTOPFREQ, memstopfreq); + EEPROM.writeByte(EE_BYTE_MEMSTARTPOS, memstartpos); + EEPROM.writeByte(EE_BYTE_MEMSTOPPOS, memstoppos); + EEPROM.writeByte(EE_BYTE_MEMPIONLY, mempionly); + EEPROM.writeByte(EE_BYTE_MEMDOUBLEPI, memdoublepi); + EEPROM.writeByte(EE_BYTE_WAITONLYONSIGNAL, scanholdonsignal); + EEPROM.writeByte(EE_BYTE_NTPOFFSET, NTPoffset); + EEPROM.writeByte(EE_BYTE_AUTOLOG, autolog); + EEPROM.writeByte(EE_BYTE_AUTODST, autoDST); + EEPROM.writeByte(EE_BYTE_CLOCKAMPM, clockampm); + EEPROM.writeUInt(EE_UINT16_PICTLOCK, radio.rds.PICTlock); + EEPROM.commit(); +} + +void loadData() { + if (EEPROM.readByte(EE_BYTE_CHECKBYTE) != EE_CHECKBYTE_VALUE) DefaultSettings(); + + frequency = EEPROM.readUInt(EE_UINT16_FREQUENCY_FM); + frequency_OIRT = EEPROM.readUInt(EE_UINT16_FREQUENCY_OIRT); + VolSet = EEPROM.readByte(EE_BYTE_VOLSET); + ConverterSet = EEPROM.readUInt(EE_UINT16_CONVERTERSET); + LowEdgeSet = EEPROM.readUInt(EE_UINT16_FMLOWEDGESET); + HighEdgeSet = EEPROM.readUInt(EE_UINT16_FMHIGHEDGESET); + ContrastSet = EEPROM.readByte(EE_BYTE_CONTRASTSET); + StereoLevel = EEPROM.readByte(EE_BYTE_STEREOLEVEL); + bandFM = EEPROM.readByte(EE_BYTE_BANDFM); + bandAM = EEPROM.readByte(EE_BYTE_BANDAM); + HighCutLevel = EEPROM.readByte(EE_BYTE_HIGHCUTLEVEL); + HighCutOffset = EEPROM.readByte(EE_BYTE_HIGHCUTOFFSET); + LevelOffset = EEPROM.readByte(EE_BYTE_LEVELOFFSET); + radio.rds.rtbuffer = EEPROM.readByte(EE_BYTE_RTBUFFER); + edgebeep = EEPROM.readByte(EE_BYTE_EDGEBEEP); + softmuteam = EEPROM.readByte(EE_BYTE_SOFTMUTEAM); + softmutefm = EEPROM.readByte(EE_BYTE_SOFTMUTEFM); + frequency_AM = EEPROM.readUInt(EE_UINT16_FREQUENCY_AM); + language = EEPROM.readByte(EE_BYTE_LANGUAGE); + showrdserrors = EEPROM.readByte(EE_BYTE_SHOWRDSERRORS); + TEF = EEPROM.readByte(EE_BYTE_TEF); + displayflip = EEPROM.readByte(EE_BYTE_DISPLAYFLIP); + rotarymode = EEPROM.readByte(EE_BYTE_ROTARYMODE); + tunemode = EEPROM.readByte(EE_BYTE_TUNEMODE); + if (tunemode == TUNE_MAN) stepsize = EEPROM.readByte(EE_BYTE_STEPSIZE); else stepsize = 0; + optenc = EEPROM.readByte(EE_BYTE_OPTENC); + iMSset = EEPROM.readByte(EE_BYTE_IMSSET); + EQset = EEPROM.readByte(EE_BYTE_EQSET); + band = EEPROM.readByte(EE_BYTE_BAND); + LowLevelSet = EEPROM.readByte(EE_BYTE_LOWLEVELSET); + memorypos = EEPROM.readByte(EE_BYTE_MEMORYPOS); + radio.rds.region = EEPROM.readByte(EE_BYTE_REGION); + radio.underscore = EEPROM.readByte(EE_BYTE_RDS_UNDERSCORE); + USBmode = EEPROM.readByte(EE_BYTE_USBMODE); + wifi = EEPROM.readByte(EE_BYTE_WIFI); + subnetclient = EEPROM.readByte(EE_BYTE_SUBNETCLIENT); + showSWMIBand = EEPROM.readByte(EE_BYTE_SHOWSWMIBAND); + radio.rds.filter = EEPROM.readByte(EE_BYTE_RDS_FILTER); + radio.rds.pierrors = EEPROM.readByte(EE_BYTE_RDS_PIERRORS); + frequency_LW = EEPROM.readUInt(EE_UINT16_FREQUENCY_LW); + frequency_MW = EEPROM.readUInt(EE_UINT16_FREQUENCY_MW); + frequency_SW = EEPROM.readUInt(EE_UINT16_FREQUENCY_SW); + XDRGTK_key = EEPROM.readString(EE_STRING_XDRGTK_KEY); + usesquelch = EEPROM.readByte(EE_BYTE_USESQUELCH); + showmodulation = EEPROM.readByte(EE_BYTE_SHOWMODULATION); + amnb = EEPROM.readByte(EE_BYTE_AM_NB); + fmnb = EEPROM.readByte(EE_BYTE_FM_NB); + audiomode = EEPROM.readByte(EE_BYTE_AUDIOMODE); + touchrotating = EEPROM.readByte(EE_BYTE_TOUCH_ROTATING); + hardwaremodel = EEPROM.readByte(EE_BYTE_HARDWARE_MODEL); + poweroptions = EEPROM.readByte(EE_BYTE_POWEROPTIONS); + CurrentTheme = EEPROM.readByte(EE_BYTE_CURRENTTHEME); + fmdefaultstepsize = EEPROM.readByte(EE_BYTE_FMDEFAULTSTEPSIZE); + screensaverset = EEPROM.readByte(EE_BYTE_SCREENSAVERSET); + AMLevelOffset = EEPROM.readInt(EE_INT16_AMLEVELOFFSET); + unit = EEPROM.readByte(EE_BYTE_UNIT); + af = EEPROM.readByte(EE_BYTE_AF); + if (af == 2) radio.rds.afreg = true; else radio.rds.afreg = false; + StereoToggle = EEPROM.readByte(EE_BYTE_STEREO); + batteryoptions = EEPROM.readByte(EE_BYTE_BATTERY_OPTIONS); + amcodect = EEPROM.readByte(EE_BYTE_AM_CO_DECT); + amcodectcount = EEPROM.readByte(EE_BYTE_AM_CO_DECT_COUNT); + amgain = EEPROM.readByte(EE_BYTE_AM_RF_GAIN); + radio.rds.sortaf = EEPROM.readByte(EE_BYTE_SORTAF); + stationlistid = EEPROM.readByte(EE_BYTE_STATIONLISTID); + fmdeemphasis = EEPROM.readByte(EE_BYTE_FM_DEEMPHASIS); + BWsetFM = EEPROM.readByte(EE_BYTE_BWSET_FM); + BWsetAM = EEPROM.readByte(EE_BYTE_BWSET_AM); + nowToggleSWMIBand = EEPROM.readByte(EE_BYTE_BANDAUTOSW); + radio.rds.fastps = EEPROM.readByte(EE_BYTE_FASTPS); + tot = EEPROM.readByte(EE_BYTE_TOT); + mwstepsize = EEPROM.readByte(EE_BYTE_MWREGION); + spispeed = EEPROM.readByte(EE_BYTE_SPISPEED); + amscansens = EEPROM.readByte(EE_BYTE_AMSCANSENS); + fmscansens = EEPROM.readByte(EE_BYTE_FMSCANSENS); + freqfont = EEPROM.readByte(EE_BYTE_FREQFONT); + CurrentSkin = EEPROM.readByte(EE_BYTE_SKIN); + XDRGTKMuteScreen = EEPROM.readByte(EE_BYTE_XDRGTKMUTE); + fmagc = EEPROM.readByte(EE_BYTE_FMAGC); + amagc = EEPROM.readByte(EE_BYTE_AMAGC); + fmsi = EEPROM.readByte(EE_BYTE_FMSI); + scanstart = EEPROM.readByte(EE_BYTE_SCANSTART); + scanstop = EEPROM.readByte(EE_BYTE_SCANSTOP); + scanhold = EEPROM.readByte(EE_BYTE_SCANHOLD); + scanmem = EEPROM.readByte(EE_BYTE_SCANMEM); + scancancel = EEPROM.readByte(EE_BYTE_SCANCANCEL); + scanmute = EEPROM.readByte(EE_BYTE_SCANMUTE); + autosquelch = EEPROM.readByte(EE_BYTE_AUTOSQUELCH); + longbandpress = EEPROM.readByte(EE_BYTE_LONGBANDPRESS); + showclock = EEPROM.readByte(EE_BYTE_SHOWCLOCK); + showlongps = EEPROM.readByte(EE_BYTE_SHOWLONGPS); + memstartfreq = EEPROM.readUInt(EE_UINT16_MEMSTARTFREQ); + memstopfreq = EEPROM.readUInt(EE_UINT16_MEMSTOPFREQ); + memstartpos = EEPROM.readByte(EE_BYTE_MEMSTARTPOS); + memstoppos = EEPROM.readByte(EE_BYTE_MEMSTOPPOS); + mempionly = EEPROM.readByte(EE_BYTE_MEMPIONLY); + memdoublepi = EEPROM.readByte(EE_BYTE_MEMDOUBLEPI); + scanholdonsignal = EEPROM.readByte(EE_BYTE_WAITONLYONSIGNAL); + TouchCalData[0] = EEPROM.readUInt(EE_UINT16_CALTOUCH1); + TouchCalData[1] = EEPROM.readUInt(EE_UINT16_CALTOUCH2); + TouchCalData[2] = EEPROM.readUInt(EE_UINT16_CALTOUCH3); + TouchCalData[3] = EEPROM.readUInt(EE_UINT16_CALTOUCH4); + TouchCalData[4] = EEPROM.readUInt(EE_UINT16_CALTOUCH5); + invertdisplay = EEPROM.readByte(EE_BYTE_INVERTDISPLAY); + NTPoffset = EEPROM.readByte(EE_BYTE_NTPOFFSET); + autolog = EEPROM.readByte(EE_BYTE_AUTOLOG); + autoDST = EEPROM.readByte(EE_BYTE_AUTODST); + clockampm = EEPROM.readByte(EE_BYTE_CLOCKAMPM); + logcounter = EEPROM.readUInt(EE_UINT16_LOGCOUNTER); + radio.rds.PICTlock = EEPROM.readUInt(EE_UINT16_PICTLOCK); +} + +void DefaultSettings() { + EEPROM.writeByte(EE_BYTE_CHECKBYTE, EE_CHECKBYTE_VALUE); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, 9500); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, FREQ_FM_OIRT_START); + EEPROM.writeByte(EE_BYTE_VOLSET, 0); + EEPROM.writeUInt(EE_UINT16_CONVERTERSET, 0); + EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, 875); + EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, 1080); + EEPROM.writeByte(EE_BYTE_CONTRASTSET, 50); + EEPROM.writeByte(EE_BYTE_STEREOLEVEL, 0); + EEPROM.writeByte(EE_BYTE_BANDFM, FM_BAND_ALL); + EEPROM.writeByte(EE_BYTE_BANDAM, AM_BAND_ALL); + EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, 70); + EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, 0); + EEPROM.writeByte(EE_BYTE_LEVELOFFSET, 0); + EEPROM.writeByte(EE_BYTE_RTBUFFER, 1); + EEPROM.writeByte(EE_BYTE_EDGEBEEP, 0); + EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, 1); + EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, 0); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, 828); + EEPROM.writeByte(EE_BYTE_LANGUAGE, 0); + EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, 1); + EEPROM.writeByte(EE_BYTE_TEF, 0); + EEPROM.writeByte(EE_BYTE_STEPSIZE, 0); + EEPROM.writeByte(EE_BYTE_TUNEMODE, 0); + EEPROM.writeByte(EE_BYTE_OPTENC, 0); + EEPROM.writeByte(EE_BYTE_IMSSET, 1); + EEPROM.writeByte(EE_BYTE_EQSET, 1); + EEPROM.writeByte(EE_BYTE_BAND, BAND_FM); + EEPROM.writeByte(EE_BYTE_LOWLEVELSET, -15); + EEPROM.writeByte(EE_BYTE_MEMORYPOS, 0); + EEPROM.writeByte(EE_BYTE_REGION, 0); + EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, 0); + EEPROM.writeByte(EE_BYTE_USBMODE, 0); + EEPROM.writeByte(EE_BYTE_WIFI, 0); + EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, 1); + EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, 1); + EEPROM.writeByte(EE_BYTE_RDS_FILTER, 1); + EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, 0); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, 180); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, 540); + EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, 1800); + EEPROM.writeString(EE_STRING_XDRGTK_KEY, "password"); + EEPROM.writeByte(EE_BYTE_USESQUELCH, 1); + EEPROM.writeByte(EE_BYTE_SHOWMODULATION, 1); + EEPROM.writeByte(EE_BYTE_AM_NB, 0); + EEPROM.writeByte(EE_BYTE_FM_NB, 0); + EEPROM.writeByte(EE_BYTE_AUDIOMODE, 0); + EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, 0); + EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, 0); + EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, 0); + EEPROM.writeByte(EE_BYTE_POWEROPTIONS, 1); + EEPROM.writeByte(EE_BYTE_CURRENTTHEME, 0); + EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, 1); + EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, 0); + EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, 0); + EEPROM.writeByte(EE_BYTE_UNIT, 0); + EEPROM.writeByte(EE_BYTE_AF, 0); + EEPROM.writeByte(EE_BYTE_STEREO, 1); + EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, BATTERY_VALUE); + EEPROM.writeByte(EE_BYTE_AM_CO_DECT, 100); + EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, 3); + EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, 0); + EEPROM.writeByte(EE_BYTE_SORTAF, 1); + EEPROM.writeByte(EE_BYTE_STATIONLISTID, 1); + EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, DEEMPHASIS_50); + EEPROM.writeByte(EE_BYTE_BWSET_FM, 0); + EEPROM.writeByte(EE_BYTE_BWSET_AM, 2); + EEPROM.writeByte(EE_BYTE_BANDAUTOSW, 0); + EEPROM.writeByte(EE_BYTE_FASTPS, 1); + EEPROM.writeByte(EE_BYTE_TOT, 0); + EEPROM.writeByte(EE_BYTE_MWREGION, 0); + EEPROM.writeByte(EE_BYTE_AMSCANSENS, 4); + EEPROM.writeByte(EE_BYTE_FMSCANSENS, 4); + EEPROM.writeByte(EE_BYTE_FREQFONT, 3); + EEPROM.writeByte(EE_BYTE_SKIN, 0); + EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, 0); + EEPROM.writeByte(EE_BYTE_FMAGC, 92); + EEPROM.writeByte(EE_BYTE_AMAGC, 100); + EEPROM.writeByte(EE_BYTE_FMSI, 1); + EEPROM.writeByte(EE_BYTE_SCANSTART, 0); + EEPROM.writeByte(EE_BYTE_SCANSTOP, 9); + EEPROM.writeByte(EE_BYTE_SCANHOLD, 5); + EEPROM.writeByte(EE_BYTE_SCANMEM, 1); + EEPROM.writeByte(EE_BYTE_SCANCANCEL, 0); + EEPROM.writeByte(EE_BYTE_SCANMUTE, 0); + EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, 0); + EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, 0); + EEPROM.writeByte(EE_BYTE_SHOWCLOCK, 1); + EEPROM.writeByte(EE_BYTE_SHOWLONGPS, 1); + EEPROM.writeUInt(EE_UINT16_MEMSTARTFREQ, 875); + EEPROM.writeUInt(EE_UINT16_MEMSTOPFREQ, 1080); + EEPROM.writeByte(EE_BYTE_MEMSTARTPOS, 1); + EEPROM.writeByte(EE_BYTE_MEMSTOPPOS, 10); + EEPROM.writeByte(EE_BYTE_MEMPIONLY, 1); + EEPROM.writeByte(EE_BYTE_MEMDOUBLEPI, 0); + EEPROM.writeByte(EE_BYTE_WAITONLYONSIGNAL, 1); + EEPROM.writeUInt(EE_UINT16_CALTOUCH1, 300); + EEPROM.writeUInt(EE_UINT16_CALTOUCH2, 3450); + EEPROM.writeUInt(EE_UINT16_CALTOUCH3, 300); + EEPROM.writeUInt(EE_UINT16_CALTOUCH4, 3450); + EEPROM.writeUInt(EE_UINT16_CALTOUCH5, 3); + EEPROM.writeByte(EE_BYTE_NTPOFFSET, 1); + EEPROM.writeByte(EE_BYTE_AUTOLOG, 1); + EEPROM.writeByte(EE_BYTE_AUTODST, 1); + EEPROM.writeByte(EE_BYTE_CLOCKAMPM, 0); + EEPROM.writeUInt(EE_UINT16_PICTLOCK, 0); + + EEPROM.writeByte(EE_BYTE_SPISPEED, 7); + +#ifdef DEEPELEC_DP_66X + EEPROM.writeByte(EE_BYTE_ROTARYMODE, 1); + EEPROM.writeByte(EE_BYTE_INVERTDISPLAY, 0); + EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 1); + EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, PORTABLE_TOUCH_ILI9341); +#else + EEPROM.writeByte(EE_BYTE_ROTARYMODE, 0); + EEPROM.writeByte(EE_BYTE_INVERTDISPLAY, 1); + EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 0); + EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, BASE_ILI9341); +#endif + + for (int i = 0; i < EE_PRESETS_CNT; i++) { + EEPROM.writeByte(i + EE_PRESETS_BAND_START, BAND_FM); + EEPROM.writeUInt((i * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY); + EEPROM.writeByte(i + EE_PRESET_BW_START, 0); + EEPROM.writeByte(i + EE_PRESET_MS_START, 1); + + for (int y = 0; y < 9; y++) EEPROM.writeByte((i * 9) + y + EE_PRESETS_RDSPS_START, '\0'); + + for (int y = 0; y < 5; y++) EEPROM.writeByte((i * 5) + y + EE_PRESETS_RDSPI_START, '\0'); + } + + EEPROM.commit(); + + handleCreateNewLogbook(); +} \ No newline at end of file diff --git a/src/rds.cpp b/src/rds.cpp index 64475cb..bda560b 100644 --- a/src/rds.cpp +++ b/src/rds.cpp @@ -179,7 +179,6 @@ void readRds() { dropout = true; } } else { - // --- RDS recovery or memory reset --- if (dropout || memreset) { if (!rdsstatscreen) { if (radio.rds.region == 0) tftPrint(ACENTER, PIold, 275, advancedRDS ? 75 : 187, RDSColor, RDSColorSmooth, 28);