From cc4f35f8c18e65a39455129f90bee8ea8e627d78 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 8 May 2020 21:25:38 +0100 Subject: [PATCH 01/42] ESP32 DMA update dmaBusy() checks and is no longer blocking pushImageDMA() faster if setAddrWindow is not built into transaction list. --- Processors/TFT_eSPI_ESP32.c | 89 +++++++++++++++++-------------------- Processors/TFT_eSPI_ESP32.h | 2 +- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 5 files changed, 44 insertions(+), 53 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index d61dde7..2c3ed64 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -494,23 +494,30 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ /*************************************************************************************** ** Function name: dmaBusy -** Description: Check if DMA is busy (currently blocking!) +** Description: Check if DMA is busy ***************************************************************************************/ bool TFT_eSPI::dmaBusy(void) { if (!DMA_Enabled || !spiBusyCheck) return false; - //spi_transaction_t rtrans; - //bool trans_result=spi_device_polling_transmit(dmaHAL, &rtrans); - //return trans_result; - // This works but blocks - dmaWait(); - 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: Check if DMA is busy (blocking!) +** Description: Wait until DMA is over (blocking!) ***************************************************************************************/ void TFT_eSPI::dmaWait(void) { @@ -535,6 +542,11 @@ 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; @@ -548,7 +560,7 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); assert(ret == ESP_OK); - spiBusyCheck = 1; + spiBusyCheck++; } @@ -574,12 +586,10 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t if (dw < 1 || dh < 1) return; - if (buffer == nullptr) buffer = image; - uint32_t len = dw*dh; - dmaWait(); - + if (buffer == nullptr) { buffer = image; dmaWait(); } + // If image is clipped, copy pixels into a contiguous block if ( (dw != w) || (dh != h) ) { if(_swapBytes) { @@ -606,43 +616,24 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t } } + if (spiBusyCheck) dmaWait(); // Incase we did not wait earlier + + setAddrWindow(x, y, dw, dh); + esp_err_t ret; - static spi_transaction_t trans[6]; - for (int i = 0; i < 6; i++) - { - memset(&trans[i], 0, sizeof(spi_transaction_t)); - if ((i & 1) == 0) - { - trans[i].length = 8; - trans[i].user = (void *)0; - } - else - { - trans[i].length = 8 * 4; - trans[i].user = (void *)1; - } - trans[i].flags = SPI_TRANS_USE_TXDATA; - } - trans[0].tx_data[0] = 0x2A; //Column Address Set - trans[1].tx_data[0] = x >> 8; //Start Col High - trans[1].tx_data[1] = x & 0xFF; //Start Col Low - trans[1].tx_data[2] = (x + dw - 1) >> 8; //End Col High - trans[1].tx_data[3] = (x + dw - 1) & 0xFF; //End Col Low - trans[2].tx_data[0] = 0x2B; //Page address set - trans[3].tx_data[0] = y >> 8; //Start page high - trans[3].tx_data[1] = y & 0xFF; //start page low - trans[3].tx_data[2] = (y + dh - 1) >> 8; //end page high - trans[3].tx_data[3] = (y + dh - 1) & 0xFF; //end page low - trans[4].tx_data[0] = 0x2C; //memory write - trans[5].tx_buffer = buffer; //finally send the line data - trans[5].length = dw * 2 * 8 * dh; //Data length, in bits - trans[5].flags = 0; //undo SPI_TRANS_USE_TXDATA flag - for (int i = 0; i < 6; i++) - { - ret = spi_device_queue_trans(dmaHAL, &trans[i], portMAX_DELAY); - assert(ret == ESP_OK); - } - spiBusyCheck = 6; + 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++; } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index 0da6a18..ee8ceb6 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -307,7 +307,7 @@ // Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions #ifdef ESP32_DMA // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK { if (DMA_Enabled) dmaWait(); } + #define DMA_BUSY_CHECK { if (spiBusyCheck) dmaWait(); } #else #define DMA_BUSY_CHECK #endif diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 77b05bf..d076553 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.4" +#define TFT_ESPI_VERSION "2.2.5" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index 3bed7b0..4be05cb 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.4", + "version": "2.2.5", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 972e24a..9da8b83 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.4 +version=2.2.5 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From cc3a1084fb30d2c2a40807755e7d55f9e4872f55 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 9 May 2020 19:51:03 +0100 Subject: [PATCH 02/42] Fix #617 --- Processors/TFT_eSPI_ESP32.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index ee8ceb6..23477c7 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -42,6 +42,14 @@ #define TFT_PARALLEL_8_BIT // Generic parallel flag #endif + // Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions + #if !defined(TFT_PARALLEL_8_BIT) && !defined(ILI9488_DRIVER) && !defined (RPI_DISPLAY_TYPE) + #define ESP32_DMA + // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions + #define DMA_BUSY_CHECK { if (spiBusyCheck) dmaWait(); } + #else + #define DMA_BUSY_CHECK + #endif // If smooth font is used then it is likely SPIFFS will be needed #ifdef SMOOTH_FONT @@ -302,16 +310,6 @@ //////////////////////////////////////////////////////////////////////////////////////// #else - #define ESP32_DMA // DMA is available for SPI - - // Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions - #ifdef ESP32_DMA - // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK { if (spiBusyCheck) dmaWait(); } - #else - #define DMA_BUSY_CHECK - #endif - // ESP32 low level SPI writes for 8, 16 and 32 bit values // to avoid the function call overhead #define TFT_WRITE_BITS(D, B) \ From 7e4566f3f2b08cb96e6008811b0c710ba815df74 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sun, 10 May 2020 00:19:12 +0100 Subject: [PATCH 03/42] Raise version to 2.2.6 --- TFT_eSPI.h | 7 +++---- library.json | 2 +- library.properties | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/TFT_eSPI.h b/TFT_eSPI.h index d076553..a25100b 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.5" +#define TFT_ESPI_VERSION "2.2.6" /*************************************************************************************** ** Section 1: Load required header files @@ -615,9 +615,8 @@ class TFT_eSPI : public Print { void pushPixelsDMA(uint16_t* image, uint32_t len); // Check if the DMA is complete - use while(tft.dmaBusy); for a blocking wait - // Note: for ESP32 the dmaBusy() function is blocking at the moment - to be updated - bool dmaBusy(void); - void dmaWait(void); + bool dmaBusy(void); // returns true if DMA is still in progress + void dmaWait(void); // wait until DMA is complete bool DMA_Enabled = false; // Flag for DMA enabled state uint8_t spiBusyCheck = 0; // Number of ESP32 transfer buffers to check diff --git a/library.json b/library.json index 4be05cb..4a23f3f 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.5", + "version": "2.2.6", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 9da8b83..a2aaa4e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.5 +version=2.2.6 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 1314a34c3dde047584e85dea526c13233ec9f4d3 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 13 May 2020 16:33:12 +0100 Subject: [PATCH 04/42] Fix #625 pushRect() reinstated to pair with readRect() so swapBytes does not need to be changed from true to false before calling. --- TFT_eSPI.cpp | 6 +++--- TFT_eSPI.h | 4 ++-- library.json | 2 +- library.properties | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index f59c08c..5242b42 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -860,14 +860,14 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da /*************************************************************************************** -** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101") +** 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) { - // Function deprecated, remains for backwards compatibility - // New pushImage() is better as it will crop partly off-screen image blocks + bool swap = _swapBytes; _swapBytes = false; pushImage(x, y, w, h, data); + _swapBytes = swap; } diff --git a/TFT_eSPI.h b/TFT_eSPI.h index a25100b..5558692 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.6" +#define TFT_ESPI_VERSION "2.2.7" /*************************************************************************************** ** Section 1: Load required header files @@ -450,7 +450,7 @@ class TFT_eSPI : public Print { // 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 - this is a deprecated alternative to pushImage() + // 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); // These are used to render images or sprites stored in RAM arrays (used by Sprite class for 16bpp Sprites) diff --git a/library.json b/library.json index 4a23f3f..cbfea7c 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.6", + "version": "2.2.7", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index a2aaa4e..069b77d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.6 +version=2.2.7 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From cd10a92f11414c592fb77319cff4e624a474b7b6 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 13 May 2020 18:28:44 +0100 Subject: [PATCH 05/42] Allow ESP32 SPI pins to be undefined See #618 --- Processors/TFT_eSPI_ESP32.c | 2 +- Processors/TFT_eSPI_ESP32.h | 58 +++++++++++++++++++++++++++++++++++-- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 2c3ed64..30d3d51 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -705,7 +705,7 @@ bool TFT_eSPI::initDMA(void) void TFT_eSPI::deInitDMA(void) { if (!DMA_Enabled) return; - + spi_bus_remove_device(dmaHAL); spi_bus_free(spi_host); DMA_Enabled = false; } diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index 23477c7..f5fe7fd 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -166,12 +166,64 @@ #endif //////////////////////////////////////////////////////////////////////////////////////// -// Make sure TFT_MISO is defined if not used to avoid an error message +// Make sure SPI default pins are assigned if not specified by user or set to -1 //////////////////////////////////////////////////////////////////////////////////////// #if !defined (TFT_PARALLEL_8_BIT) - #ifndef TFT_MISO - #define TFT_MISO -1 + + #ifdef USE_HSPI_PORT + + #ifndef TFT_MISO + #define TFT_MISO 12 + #endif + #if (TFT_MISO == -1) + #undef TFT_MISO + #define TFT_MISO 12 + #endif + + #ifndef TFT_MOSI + #define TFT_MOSI 13 + #endif + #if (TFT_MOSI == -1) + #undef TFT_MOSI + #define TFT_MOSI 13 + #endif + + #ifndef TFT_SCLK 14 + #define TFT_SCLK + #endif + #if (TFT_SCLK == -1) + #undef TFT_SCLK + #define TFT_SCLK 14 + #endif + + #else // VSPI port + + #ifndef TFT_MISO + #define TFT_MISO 19 + #endif + #if (TFT_MISO == -1) + #undef TFT_MISO + #define TFT_MISO 19 + #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 + #endif + #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 5558692..4ab6ce3 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.7" +#define TFT_ESPI_VERSION "2.2.8" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index cbfea7c..70efa62 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.7", + "version": "2.2.8", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 069b77d..a3b3ab4 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.7 +version=2.2.8 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 232330d5cd9ee40c0b49111cff66ddf877bf54c0 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 13 May 2020 22:32:54 +0100 Subject: [PATCH 06/42] Correct typo --- Processors/TFT_eSPI_ESP32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index f5fe7fd..a4290a1 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -188,8 +188,8 @@ #define TFT_MOSI 13 #endif - #ifndef TFT_SCLK 14 - #define TFT_SCLK + #ifndef TFT_SCLK + #define TFT_SCLK 14 #endif #if (TFT_SCLK == -1) #undef TFT_SCLK From 960ff6c7b9b82b9dd987eb4e9855ed68b7fcdb5e Mon Sep 17 00:00:00 2001 From: Bodmer Date: Thu, 14 May 2020 15:33:03 +0100 Subject: [PATCH 07/42] Ensure ESP32_PARALLEL defined --- Processors/TFT_eSPI_ESP32.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index a4290a1..fd56dce 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -39,17 +39,26 @@ // Define a generic flag for 8 bit parallel #if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility - #define TFT_PARALLEL_8_BIT // Generic parallel flag + #if !defined (TFT_PARALLEL_8_BIT) + #define TFT_PARALLEL_8_BIT // Generic parallel flag + #endif #endif - // Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions - #if !defined(TFT_PARALLEL_8_BIT) && !defined(ILI9488_DRIVER) && !defined (RPI_DISPLAY_TYPE) - #define ESP32_DMA - // Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions - #define DMA_BUSY_CHECK { if (spiBusyCheck) dmaWait(); } - #else - #define DMA_BUSY_CHECK +// 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 + +// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions +#if !defined(TFT_PARALLEL_8_BIT) && !defined(ILI9488_DRIVER) && !defined (RPI_DISPLAY_TYPE) + #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 smooth font is used then it is likely SPIFFS will be needed #ifdef SMOOTH_FONT From 0db6eed9e093928ea6bb28c3c2f36d25c9b5cd4d Mon Sep 17 00:00:00 2001 From: kamorris Date: Mon, 25 May 2020 15:29:41 -0700 Subject: [PATCH 08/42] add 4bit image support, tools and examples --- Tools/Images/README.txt | 25 + Tools/Images/bmp2array4bit.py | 251 +++ Tools/Images/star.bmp | Bin 0 -> 12986 bytes .../Sprite/Sprite_image_4bit/Sprite_image.ino | 162 ++ .../Sprite_image_4bit/Sprite_image_4bit.ino | 162 ++ .../Sprite/Sprite_image_4bit/sample_images.h | 3 + .../Sprite/Sprite_image_4bit/starImage.cpp | 1444 +++++++++++++++++ 7 files changed, 2047 insertions(+) create mode 100644 Tools/Images/README.txt create mode 100644 Tools/Images/bmp2array4bit.py create mode 100644 Tools/Images/star.bmp create mode 100644 examples/Sprite/Sprite_image_4bit/Sprite_image.ino create mode 100644 examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino create mode 100644 examples/Sprite/Sprite_image_4bit/sample_images.h create mode 100644 examples/Sprite/Sprite_image_4bit/starImage.cpp diff --git a/Tools/Images/README.txt b/Tools/Images/README.txt new file mode 100644 index 0000000..8ba629c --- /dev/null +++ b/Tools/Images/README.txt @@ -0,0 +1,25 @@ + +bmp2array4bit.py creates C (or C++) code that contains two arrays for adding images to four-bit sprites. See Sprite_image_4bit for an example. + +It is loosely based on Spark Fun's bmp2array script. + +You'll need python 3.6 (the original use Python 2.7) + +usage: python bmp2array4bit.py [-v] star.bmp [-o myfile.c] + +Create the bmp file in Gimp from any image by: + +. Remove the alpha channel (if it has one) + Layer -> Transparency -> Remove Alpha Channel +. Set the mode to indexed. + Image -> Mode -> Indexed... +. Select Generate optimum palette with 16 colors (max) +. Export the file with a .bmp extension. Do NOT select options: + . Run-Length Encoded + . Compatibility Options: "Do not write color space information" + . There are no Advanced Options available with these settings + +I don't have photoshop so cannot help you with that. + +The first array produced is the palette for the image. +The second is the image itself. \ No newline at end of file diff --git a/Tools/Images/bmp2array4bit.py b/Tools/Images/bmp2array4bit.py new file mode 100644 index 0000000..3b6d850 --- /dev/null +++ b/Tools/Images/bmp2array4bit.py @@ -0,0 +1,251 @@ +''' + + This script takes in a bitmap and outputs a text file that is a + byte array used in Arduino files. + + It is loosely based on Spark Fun's bmp2array script. + + You'll need python 3.6 (the original use Python 2.7) + + usage: python fourbitbmp2array.py [-v] star.bmp [-o myfile.c] + + Create the bmp file in Gimp by : + + . Remove the alpha channel (if it has one) Layer -> Transparency -> Remove Alpha Channel + . Set the mode to indexed. Image -> Mode -> Indexed... + . Select Generate optimum palette with 16 colors (max) + . Export the file with a .bmp extension. Options are: + . Run-Length Encoded: not selected + . Compatibility Options: "Do not write color space information" not selected + . There are no Advanced Options available with these settings + + + + +''' + +import sys +import struct +import math +import argparse +import os + +debug = None + +def debugOut(s): + if debug: + print(s) + +# look at arguments +parser = argparse.ArgumentParser(description="Convert bmp file to C array") +parser.add_argument("-v", "--verbose", help="debug output", action="store_true") +parser.add_argument("input", help="input file name") +parser.add_argument("-o", "--output", help="output file name") +args = parser.parse_args() + +if not os.path.exists(args.input): + parser.print_help() + print("The input file {} does not exist".format(args.input)) + sys.exit(1) + +if args.output == None: + output = os.path.basename(args.input).replace(".bmp", ".c") +else: + output = args.output + +debug = args.verbose + +try: + #Open our input file which is defined by the first commandline argument + #then dump it into a list of bytes + infile = open(args.input,"rb") #b is for binary + contents = bytearray(infile.read()) + infile.close() +except: + print("could not read input file {}".format(args.input)) + sys.exit(1) + +# first two bytes should be "BM" +upto = 2 +#Get the size of this image +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +fileSize = struct.unpack("I", bytearray(data)) + +upto += 4 +# four bytes are reserved + +upto += 4 + +debugOut("Size of file: {}".format(fileSize[0])) + +#Get the header offset amount +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +offset = struct.unpack("I", bytearray(data)) + +debugOut("Offset: {}".format(offset[0])) +upto += 4 + +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +headersize = struct.unpack("I", bytearray(data)) +headerLength = headersize[0] +startOfDefinitions = headerLength + upto +debugOut("header size: {}, up to {}, startOfDefinitions {}".format(headersize[0], upto, startOfDefinitions)) +upto += 4 + +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("width: {}".format(t[0])) +width = t[0] + +upto += 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("height: {}".format(t[0])) +height = t[0] + +# 26 +upto += 4 + +data = struct.pack("BB", contents[upto], contents[upto+1]) +t = struct.unpack("H", bytearray(data)) +debugOut("planes: {}".format(t[0])) + +upto = upto + 2 +data = struct.pack("BB", contents[upto], contents[upto+1]) +t = struct.unpack("H", bytearray(data)) +debugOut("bits per pixel: {}".format(t[0])) +bitsPerPixel = t[0] + +upto = upto + 2 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biCompression: {}".format(t[0])) + +upto = upto + 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biSizeImage: {}".format(t[0])) + +upto = upto + 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biXPelsPerMeter: {}".format(t[0])) + +upto = upto + 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biYPelsPerMeter: {}".format(t[0])) + +upto = upto + 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biClrUsed: {}".format(t[0])) +colorsUsed = t + +upto = upto + 4 +data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) +t = struct.unpack("I", bytearray(data)) +debugOut("biClrImportant: {}".format(t[0])) + +upto += 4 + +debugOut("Upto: {} Number of colors used: {} definitions start at: {}".format(upto, colorsUsed[0], startOfDefinitions)) + +#Create color definition array and init the array of color values +colorIndex = [] #(colorsUsed[0]) +for i in range(colorsUsed[0]): + colorIndex.append(0) + +#Assign the colors to the array. upto = 54 +# startOfDefinitions = upto +for i in range(colorsUsed[0]): + upto = startOfDefinitions + (i * 4) + blue = contents[upto] + green = contents[upto + 1] + red = contents[upto + 2] + # ignore the alpha channel. + + # data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3]) + # t = struct.unpack("I", bytearray(data)) + # colorIndex[i] = t[0] + + colorIndex[i] = (((red & 0xf8)<<8) + ((green & 0xfc)<<3)+(blue>>3)) + debugOut("color at index {0} is {1:04x}, (r,g,b,a) = ({2:02x}, {3:02x}, {4:02x}, {5:02x})".format(i, colorIndex[i], red, green, blue, contents[upto+3])) + +#debugOut(the color definitions +# for i in range(colorsUsed[0]): +# print hex(colorIndex[i]) + +# perfect, except upside down. + +#Make a string to hold the output of our script +arraySize = (len(contents) - offset[0]) +outputString = "/* This was generated using a script based on the SparkFun BMPtoArray python script" + '\n' +outputString += " See https://github.com/sparkfun/BMPtoArray for more info */" + '\n\n' +outputString += "static const uint16_t palette[" + str(colorsUsed[0]) + "] = {"; +for i in range(colorsUsed[0]): + # print hexlify(colorIndex[i]) + if i % 4 == 0: + outputString += "\n\t" + outputString += "0x{:04x}, ".format(colorIndex[i]) + +outputString = outputString[:-2] +outputString += "\n};\n\n" +outputString += "// width is " + str(width) + ", height is " + str(height) + "\n" +outputString += "static const uint8_t myGraphic[" + str(arraySize) + "] PROGMEM = {" + '\n' + +if bitsPerPixel != 4: + print("Expected 4 bits per pixel; found {}".format(bitsPerPixel)) + sys.exit(1) + +#Start converting spots to values +#Start at the offset and go to the end of the file +dropLastNumber = True #(width % 4) == 2 or (width % 4) == 1 +paddedWidth = int(math.ceil(bitsPerPixel * width / 32.0) * 4) +debugOut("array range is {} {} len(contents) is {} paddedWidth is {} width is {}".format(offset[0], fileSize[0], len(contents), paddedWidth, width)) + +r = 0 +width = int(width / 2) +#for i in range(offset[0], fileSize[0]): # close but image is upside down. Each row is correct but need to swap columns. +#for i in range(fileSize[0], offset[0], -1): + +for col in range(height-1, -1, -1): + i = 0 + for row in range(width): + colorCode1 = contents[row + col*paddedWidth + offset[0]] + + if r > 0 and r % width == 0: + i = 0 + outputString += '\n\n' + elif (i + 1) % 12 == 0 : + outputString += '\n' + i = 0 + + #debugOut("cell ({0}, {1})".format(row, col) + + r = r + 1 + i = i + 1 + outputString += "0x{:02x}, ".format(colorCode1) + + + +#Once we've reached the end of our input string, pull the last two +#characters off (the last comma and space) since we don't need +#them. Top it off with a closing bracket and a semicolon. +outputString = outputString[:-2] +outputString += "};" + +try: + #Write the output string to our output file + outfile = open(output, "w") + outfile.write(outputString) + outfile.close() +except: + print("could not write output to file {}".format(output)) + sys.exit(1) + +debugOut("{} complete".format(output)) +debugOut("Copy and paste this array into a image.h or other header file") + +if not debug: + print("Completed; the output is in {}".format(output)) diff --git a/Tools/Images/star.bmp b/Tools/Images/star.bmp new file mode 100644 index 0000000000000000000000000000000000000000..21166da425051845d0ce6e6c894b51655639a51e GIT binary patch literal 12986 zcmeHN&u<(_6)rnj-;j36Vu83s0vT~zBGzXsB*O_QWV1dGY}}p$CsxEhf%Y=-{sX{d zE(j!~BqtD;c=8XxPJ9BvA;}5E#p?(pu4}&U{iv?)uI`?h_?VJB(_K~X>+gN9-m99H zum9lqT99^(&!6D$H}{=JP`{$2n6?TWn`7I>9y7SD zVYqE5-@jWFALU2byIHJ&SNyOI@U3Dcyfz6hf&41`iXtx|;fkV-e7;{yifjeKChttduEv@EVxXRL{Mhb!UTCthvc zZnJN6G;Tbo`q=v2I*n*m6qQ8%3VZgCj_|0?e5~VL61*dk@K!mf;vEUzPTAdm1;ay_ zsf3XUSfjBY{D%D~<%|u(t4cT^oIGb$JeANY!xrI2q(|b*@>9D+LRrX&g|wCNqJ*V* z1T1o?Q|eW}+NA8C{+gC1p)TYRd)U7c-b4V$l@R&?UMh;8wsJI6vB2Oh&vq0v!A9xa?f2=_oF z7%$5Yc)*$wPh$c=xnY+GTJ@;&PPPxhI~EL*Gq}eQFTXiwakbn}CJ$ya0Tc;Eyy~OXh~-cPXR?t=eOJjw^8zYN*5(2a`9QoZRB@SM})C5lfp8y(du6S7AoU`|xXw-VKhEmTa zp5nveQ0p|ST4v2!xIT-Gr|E| z@ecgK9V))N>u@Y5C7ux^T*NE4(KZ!bIXgn7cmgPJyz+uLc8a%ir7J3@JB9Frv7*3Z z@m92Sypm$`uo{)qU6%eLXCumdZg5;Z7~nWtn~L9b>I{T7mH@$f`CK{9=g&T$8(svw zkBv^+UOdHyux@M4l>?xcJJ5Ow6m7gxex=KL;w0n;u3|$u+bW#j*{Q;voF#ar&*gdP zsw`q`KHA(_pOn>m$@y;M2;gla1v^C_3 zG*i)kst_;6A;LXk)~zvW&A9cQ5GKhYyyH_`diru+6+-n z@VHQFcoERIDTa9r0AGGwG#j`_x36L&2WJKE)fdF%r*ue2I7L-tOkh4FPHelXAPD+4 z<^=%!UY!$=A6PeR5s^M;=!L)^Q%2CVQ%hNQug=c_m*B;c4LGBhsz;V}f(ab>oqxeU zkTik@n9z%!+C@ST%BXU{d@0JEOCz4=vie-o8`kk^1eG3h3=Q1a1TRv=Q#L( zu7Sra7J3Y?sh4}zRaFos#?I+Qf+AvtUiP<0Q$git-j*JdA6HCC?^Z)Sb_^mX$A((=C7=nQG zH|0lv!4Lc)3+cU=)vfH@Rs~@o0Xa$JljV1s;6c6KwVc;I zw1j>UuXLAXAN&*#l?wc>mY(IWHl!#35AnrZGp#Xa^omNblc5pLl1N=#VJ4zsyyPh@#$Un?s ze0h(5O9^bxIAj}68=v}Y|DK9~iMu|)fPjK~*Z7X%a0AT8&JH{XsCei|o~HqBErA=J zZN!76G+c_q>Tc4D0pN{0_P8x8exwx}=pdR;b+yz-x-(9*Eh6a!@aV9*Tfu|tn9^}# z(`>8ZK|r1b(Gn4oIqd;Kw)wj&nSUQ|lMdzd3x|^he1OifwP&1$LuVdf8rw+XIVIi` z*Ps36d#Q12#%Z?UC0BgQ1w+7_!|E=-$d3tprcXq2R$fZ3hP|sV#@V zbYi?#haq6a-8d{4`HVw2D(!=7Z^r~ggdfHe%RAo~R3^4$9DiSWyYW5!f0IhELiZ_LP z2+h6v33q)!t6|kj@Aj@`b^x@_s%bxrc0ufKsC1Zu?rx+2;DV z8JK{5d+nlt8@giZ$+4(;W1d!R?i5Il#^?$inj#|K;(5^V95_4zTD2B*%@hjBAP@x;rfsmhF~(9$qhN*EW9uhcC`uc~v_a zcbv=Gc(nCn7vX=$WwwJhi=KX@h;NiVGZ!1)B;Ihbxr@w#!x!mp2!Okw_yXOP p6>~AQz}3B2ckvHd9lz52nag~?wX@9Z{<&-YQ{K#YqrmbC{2%kDSkM3f literal 0 HcmV?d00001 diff --git a/examples/Sprite/Sprite_image_4bit/Sprite_image.ino b/examples/Sprite/Sprite_image_4bit/Sprite_image.ino new file mode 100644 index 0000000..e004df4 --- /dev/null +++ b/examples/Sprite/Sprite_image_4bit/Sprite_image.ino @@ -0,0 +1,162 @@ +/* + + Sketch to show how a Sprite can use a four-bit image with + a palette to change the appearance of an image while rendering + it only once. + + Example for library: + https://github.com/Bodmer/TFT_eSPI + + A Sprite is notionally an invisible graphics screen that is + kept in the processors RAM. Graphics can be drawn into the + Sprite just as it 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. + + A 16 bit Sprite occupies (2 * width * height) bytes in RAM. + + On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated, + this size requires 40kBytes of RAM for a 16 bit color depth. + + When 8 bit color depth sprites are created they occupy + (width * height) bytes in RAM, so larger sprites can be + created, or the RAM required is halved. + +*/ + + +// Set delay after plotting the sprite +#define DELAY 30 + +// Width and height of sprite +#define WIDTH 164 +#define HEIGHT 164 + +#include "sample_images.h" + +TFT_eSPI tft = TFT_eSPI(); // Declare object "tft" + +TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object + +const int freq = 5000; +int screenBrightnessChannel = 0; +int resolution = 8; + +byte red = 31; // Red is the top 5 bits of a 16 bit colour value +byte green = 0;// Green is the middle 6 bits +byte blue = 0; // Blue is the bottom 5 bits +byte state = 0; + +int rloop = 0; +int incr = 1; + +uint16_t cmap[16]; + +void setup() +{ + pinMode(21, OUTPUT); + ledcSetup(screenBrightnessChannel, freq, resolution); + ledcAttachPin(21, screenBrightnessChannel); + ledcWrite(screenBrightnessChannel, 127); + + Serial.begin(9600); + Serial.println(); + + delay(50); + + // Initialise the TFT registers + tft.init(); + + spr.setColorDepth(4); + + // Create a sprite of defined size + spr.createSprite(WIDTH, HEIGHT); + + // Clear the TFT screen to black + tft.fillScreen(TFT_BLACK); + + // push the image - only need to do this once. + spr.pushImage(2, 2, 160, 160, (uint16_t *)stars); + + for (int i = 0; i < 16; i++) + cmap[i] = rainbow(); +} + +void loop(void) +{ + // create a palette with the defined colors and push it. + spr.createPalette(cmap, 16); + spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2); + + // update the colors + for (int i = 0; i < 15; i++) { + cmap[i] = cmap[i + 1]; + } + if (incr == 2) { + (void)rainbow(); // skip alternate steps + } + cmap[15] = rainbow(); + rloop += incr; + if (rloop > 0xc0) { + incr = incr == 2 ? 1 : 2; + Serial.printf("incr %d, rloop %d\r\n", incr, rloop); + rloop = 0; + + } + delay(DELAY); + +} + +// ######################################################################### +// Return a 16 bit rainbow colour +// ######################################################################### +unsigned int rainbow() +{ + switch (state) { + case 0: + green ++; + if (green == 64) { + green = 63; + state = 1; + } + break; + case 1: + red--; + if (red == 255) { + red = 0; + state = 2; + } + break; + case 2: + blue ++; + if (blue == 32) { + blue = 31; + state = 3; + } + break; + case 3: + green --; + if (green == 255) { + green = 0; + state = 4; + } + break; + case 4: + red ++; + if (red == 32) { + red = 31; + state = 5; + } + break; + case 5: + blue --; + if (blue == 255) { + blue = 0; + state = 0; + } + break; + } + return red << 11 | green << 5 | blue; +} + diff --git a/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino b/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino new file mode 100644 index 0000000..e004df4 --- /dev/null +++ b/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino @@ -0,0 +1,162 @@ +/* + + Sketch to show how a Sprite can use a four-bit image with + a palette to change the appearance of an image while rendering + it only once. + + Example for library: + https://github.com/Bodmer/TFT_eSPI + + A Sprite is notionally an invisible graphics screen that is + kept in the processors RAM. Graphics can be drawn into the + Sprite just as it 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. + + A 16 bit Sprite occupies (2 * width * height) bytes in RAM. + + On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated, + this size requires 40kBytes of RAM for a 16 bit color depth. + + When 8 bit color depth sprites are created they occupy + (width * height) bytes in RAM, so larger sprites can be + created, or the RAM required is halved. + +*/ + + +// Set delay after plotting the sprite +#define DELAY 30 + +// Width and height of sprite +#define WIDTH 164 +#define HEIGHT 164 + +#include "sample_images.h" + +TFT_eSPI tft = TFT_eSPI(); // Declare object "tft" + +TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object + +const int freq = 5000; +int screenBrightnessChannel = 0; +int resolution = 8; + +byte red = 31; // Red is the top 5 bits of a 16 bit colour value +byte green = 0;// Green is the middle 6 bits +byte blue = 0; // Blue is the bottom 5 bits +byte state = 0; + +int rloop = 0; +int incr = 1; + +uint16_t cmap[16]; + +void setup() +{ + pinMode(21, OUTPUT); + ledcSetup(screenBrightnessChannel, freq, resolution); + ledcAttachPin(21, screenBrightnessChannel); + ledcWrite(screenBrightnessChannel, 127); + + Serial.begin(9600); + Serial.println(); + + delay(50); + + // Initialise the TFT registers + tft.init(); + + spr.setColorDepth(4); + + // Create a sprite of defined size + spr.createSprite(WIDTH, HEIGHT); + + // Clear the TFT screen to black + tft.fillScreen(TFT_BLACK); + + // push the image - only need to do this once. + spr.pushImage(2, 2, 160, 160, (uint16_t *)stars); + + for (int i = 0; i < 16; i++) + cmap[i] = rainbow(); +} + +void loop(void) +{ + // create a palette with the defined colors and push it. + spr.createPalette(cmap, 16); + spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2); + + // update the colors + for (int i = 0; i < 15; i++) { + cmap[i] = cmap[i + 1]; + } + if (incr == 2) { + (void)rainbow(); // skip alternate steps + } + cmap[15] = rainbow(); + rloop += incr; + if (rloop > 0xc0) { + incr = incr == 2 ? 1 : 2; + Serial.printf("incr %d, rloop %d\r\n", incr, rloop); + rloop = 0; + + } + delay(DELAY); + +} + +// ######################################################################### +// Return a 16 bit rainbow colour +// ######################################################################### +unsigned int rainbow() +{ + switch (state) { + case 0: + green ++; + if (green == 64) { + green = 63; + state = 1; + } + break; + case 1: + red--; + if (red == 255) { + red = 0; + state = 2; + } + break; + case 2: + blue ++; + if (blue == 32) { + blue = 31; + state = 3; + } + break; + case 3: + green --; + if (green == 255) { + green = 0; + state = 4; + } + break; + case 4: + red ++; + if (red == 32) { + red = 31; + state = 5; + } + break; + case 5: + blue --; + if (blue == 255) { + blue = 0; + state = 0; + } + break; + } + return red << 11 | green << 5 | blue; +} + diff --git a/examples/Sprite/Sprite_image_4bit/sample_images.h b/examples/Sprite/Sprite_image_4bit/sample_images.h new file mode 100644 index 0000000..3c56f1d --- /dev/null +++ b/examples/Sprite/Sprite_image_4bit/sample_images.h @@ -0,0 +1,3 @@ +#include // Include the graphics library (this includes the sprite functions) + +extern const uint8_t stars[12800] PROGMEM ; \ No newline at end of file diff --git a/examples/Sprite/Sprite_image_4bit/starImage.cpp b/examples/Sprite/Sprite_image_4bit/starImage.cpp new file mode 100644 index 0000000..531cdeb --- /dev/null +++ b/examples/Sprite/Sprite_image_4bit/starImage.cpp @@ -0,0 +1,1444 @@ +#include "sample_images.h" + + +// width is 160, height is 160 +const uint8_t stars[12800] PROGMEM = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x31, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x32, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x33, 0x11, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x33, 0x21, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x34, 0x33, 0x31, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x43, 0x33, 0x11, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x44, 0x33, 0x21, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x11, 0x23, 0x33, 0x44, 0x44, 0x33, 0x31, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x44, 0x43, 0x32, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x54, 0x43, 0x33, 0x21, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x56, 0x64, 0x44, 0x33, 0x31, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x66, 0x44, 0x43, 0x32, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x12, 0x33, 0x34, 0x45, 0x66, 0x66, 0x54, 0x43, 0x33, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x13, 0x33, 0x44, 0x46, 0x66, 0x66, 0x64, 0x44, 0x33, +0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x67, 0x76, 0x65, 0x44, 0x33, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x33, 0x34, 0x45, 0x66, 0x78, 0x86, 0x66, 0x44, 0x43, +0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x88, 0x87, 0x66, 0x64, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x33, 0x44, 0x56, 0x67, 0x88, 0x88, 0x76, 0x65, 0x44, +0x33, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x33, 0x34, 0x44, 0x66, 0x68, 0x88, 0x88, 0x86, 0x66, 0x44, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x12, 0x33, 0x44, 0x46, 0x66, 0x78, 0x89, 0x98, 0x87, 0x66, 0x54, +0x43, 0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x13, 0x33, 0x44, 0x56, 0x67, 0x88, 0x89, 0x98, 0x88, 0x66, 0x65, +0x44, 0x33, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x23, 0x34, 0x44, 0x66, 0x68, 0x88, 0x99, 0x99, 0x88, 0x86, 0x66, +0x44, 0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, +0x33, 0x34, 0x45, 0x66, 0x78, 0x89, 0x99, 0x99, 0x88, 0x87, 0x66, +0x54, 0x43, 0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, +0x33, 0x44, 0x46, 0x66, 0x88, 0x89, 0x9a, 0x99, 0x98, 0x88, 0x66, +0x64, 0x44, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, +0x34, 0x44, 0x66, 0x67, 0x88, 0x99, 0x9b, 0xa9, 0x99, 0x88, 0x76, +0x65, 0x44, 0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, +0x34, 0x45, 0x66, 0x78, 0x88, 0x99, 0xab, 0xba, 0x99, 0x88, 0x86, +0x66, 0x54, 0x43, 0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, +0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x33, 0x22, 0x22, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x33, +0x44, 0x46, 0x66, 0x88, 0x89, 0x99, 0xbb, 0xbb, 0x99, 0x98, 0x88, +0x66, 0x64, 0x44, 0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x22, +0x23, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x33, 0x33, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0x11, +0x11, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x11, 0x23, 0x33, +0x44, 0x56, 0x67, 0x88, 0x99, 0x9a, 0xbb, 0xbb, 0xa9, 0x99, 0x88, +0x76, 0x65, 0x44, 0x33, 0x31, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, +0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x22, 0x22, 0x33, 0x33, 0x33, +0x33, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x22, +0x22, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x33, 0x34, +0x44, 0x66, 0x68, 0x88, 0x99, 0xab, 0xbb, 0xbb, 0xb9, 0x99, 0x88, +0x86, 0x66, 0x44, 0x43, 0x33, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, +0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x44, 0x43, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0x11, 0x12, 0x33, 0x44, +0x46, 0x66, 0x78, 0x89, 0x99, 0xbb, 0xbc, 0xbb, 0xba, 0x99, 0x98, +0x87, 0x66, 0x54, 0x44, 0x33, 0x21, 0x11, 0x11, 0x11, 0x22, 0x22, +0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x43, 0x33, +0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x22, 0x23, 0x33, 0x44, +0x56, 0x67, 0x88, 0x89, 0x9a, 0xbb, 0xbc, 0xcb, 0xbb, 0xa9, 0x98, +0x88, 0x66, 0x65, 0x44, 0x33, 0x32, 0x22, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, 0x44, 0x44, 0x43, +0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x33, 0x34, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, +0x44, 0x44, 0x43, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, +0x66, 0x68, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, +0x88, 0x86, 0x66, 0x44, 0x43, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x34, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x55, 0x44, 0x43, +0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x66, 0x65, 0x55, 0x54, 0x44, +0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x44, 0x45, +0x66, 0x78, 0x89, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xbb, 0xba, 0x99, +0x98, 0x87, 0x66, 0x54, 0x43, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, +0x44, 0x44, 0x44, 0x44, 0x45, 0x55, 0x56, 0x66, 0x65, 0x44, 0x43, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x33, 0x44, 0x56, 0x66, 0x66, 0x66, 0x66, 0x66, +0x55, 0x55, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x56, +0x66, 0x88, 0x89, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, +0x98, 0x88, 0x66, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, +0x45, 0x55, 0x56, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x44, 0x33, +0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x13, 0x33, 0x44, 0x46, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x66, 0x55, 0x55, 0x44, 0x44, 0x44, 0x44, 0x66, +0x68, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xb9, +0x99, 0x88, 0x76, 0x66, 0x44, 0x44, 0x44, 0x45, 0x55, 0x56, 0x66, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x64, 0x44, 0x33, +0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x88, 0x88, 0x77, 0x77, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x55, 0x55, 0x66, +0x78, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xba, +0x99, 0x88, 0x87, 0x66, 0x55, 0x56, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x77, 0x77, 0x88, 0x87, 0x66, 0x54, 0x43, 0x33, +0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x11, 0x33, 0x34, 0x45, 0x66, 0x78, 0x88, 0x88, 0x88, +0x88, 0x87, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x88, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, +0x99, 0x98, 0x88, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, +0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x86, 0x66, 0x54, 0x43, 0x33, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x33, 0x34, 0x44, 0x66, 0x68, 0x88, 0x88, 0x88, +0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x77, 0x76, 0x66, 0x66, 0x67, +0x88, 0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, +0xa9, 0x99, 0x88, 0x76, 0x66, 0x66, 0x67, 0x77, 0x78, 0x88, 0x88, +0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x86, 0x66, 0x44, 0x43, 0x32, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x56, 0x67, 0x88, 0x99, 0x99, +0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x78, +0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcd, 0xdc, 0xcc, 0xcc, 0xbb, +0xba, 0x99, 0x88, 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, +0x88, 0x89, 0x99, 0x99, 0x99, 0x88, 0x76, 0x65, 0x44, 0x33, 0x31, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x56, 0x67, 0x88, 0x89, 0x99, +0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, +0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xcd, 0xdc, 0xcc, 0xcc, 0xbb, +0xbb, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, +0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x66, 0x64, 0x44, 0x33, 0x31, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x88, 0x89, 0x99, +0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, +0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, +0xbb, 0xa9, 0x98, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, +0x99, 0x99, 0xaa, 0x99, 0x98, 0x87, 0x66, 0x64, 0x44, 0x33, 0x21, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x12, 0x33, 0x34, 0x45, 0x66, 0x78, 0x89, 0x99, +0xab, 0xbb, 0xba, 0xaa, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, +0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, +0xbb, 0xb9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, +0xab, 0xbb, 0xba, 0x99, 0x98, 0x87, 0x66, 0x54, 0x43, 0x33, 0x11, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x66, 0x68, 0x88, 0x99, +0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xa9, 0x99, 0x99, +0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, +0xbb, 0xba, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, +0xbb, 0xbb, 0xb9, 0x99, 0x88, 0x86, 0x66, 0x44, 0x43, 0x32, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x68, 0x88, 0x99, +0x9b, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, +0xaa, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, +0xcb, 0xbb, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, +0xbb, 0xbb, 0xb9, 0x99, 0x88, 0x76, 0x65, 0x44, 0x43, 0x32, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x56, 0x67, 0x88, 0x99, +0x9a, 0xbb, 0xbc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, +0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xde, 0xed, 0xdd, 0xcc, 0xcc, +0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, +0xcb, 0xbb, 0xa9, 0x98, 0x88, 0x76, 0x65, 0x44, 0x33, 0x31, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x46, 0x66, 0x88, 0x89, +0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, +0xbb, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, 0xee, 0xdd, 0xdc, 0xcc, +0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcb, 0xbb, 0x99, 0x98, 0x88, 0x66, 0x64, 0x44, 0x33, 0x21, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x78, 0x89, +0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xdd, 0xdc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xbb, 0xba, 0x99, 0x98, 0x87, 0x66, 0x54, 0x43, 0x33, 0x21, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x45, 0x66, 0x78, 0x88, +0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, 0xee, 0xed, 0xdd, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xbb, 0xba, 0x99, 0x88, 0x86, 0x66, 0x54, 0x43, 0x33, 0x11, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x68, 0x88, +0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, 0xee, 0xed, 0xdd, 0xdc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xbb, 0xb9, 0x99, 0x88, 0x86, 0x66, 0x44, 0x43, 0x32, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x33, 0x44, 0x56, 0x67, 0x88, +0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xcc, 0xcc, 0xcb, +0xbb, 0xa9, 0x99, 0x88, 0x76, 0x65, 0x44, 0x33, 0x31, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x56, 0x66, 0x88, +0x89, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, +0xdc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, +0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, +0xbb, 0xa9, 0x98, 0x88, 0x66, 0x64, 0x44, 0x33, 0x31, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x88, +0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, +0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, +0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xcb, +0xbb, 0x99, 0x98, 0x87, 0x66, 0x64, 0x44, 0x33, 0x21, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x45, 0x66, 0x78, +0x89, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xdd, 0xdd, +0xdd, 0xdd, 0xdd, 0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, +0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, +0xba, 0x99, 0x98, 0x87, 0x66, 0x54, 0x43, 0x33, 0x11, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x66, 0x68, +0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, 0xee, +0xee, 0xdd, 0xdd, 0xdd, 0xee, 0xee, 0xef, 0xfe, 0xee, 0xee, 0xdd, +0xdd, 0xde, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, +0xb9, 0x99, 0x88, 0x86, 0x66, 0x44, 0x43, 0x32, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x66, 0x67, +0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xfe, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcc, 0xbb, +0xb9, 0x99, 0x88, 0x76, 0x65, 0x44, 0x33, 0x32, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x56, 0x67, +0x88, 0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xff, 0xff, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, +0xa9, 0x98, 0x88, 0x76, 0x65, 0x44, 0x33, 0x31, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x46, 0x66, +0x88, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xff, 0xff, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, +0x99, 0x98, 0x88, 0x66, 0x64, 0x44, 0x33, 0x21, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x33, 0x44, 0x45, 0x66, +0x78, 0x89, 0x99, 0xbb, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xfe, 0xee, 0xee, +0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, 0xba, +0x99, 0x98, 0x87, 0x66, 0x54, 0x43, 0x33, 0x21, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x45, 0x66, +0x78, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, 0xee, +0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xee, 0xee, +0xee, 0xff, 0xee, 0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, 0xba, +0x99, 0x88, 0x86, 0x66, 0x44, 0x43, 0x33, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x34, 0x44, 0x66, +0x68, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, +0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xfe, 0xee, 0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcc, 0xbb, 0xb9, +0x99, 0x88, 0x86, 0x66, 0x44, 0x43, 0x32, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x33, 0x44, 0x56, +0x67, 0x88, 0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, +0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xfe, 0xee, 0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0xa9, +0x99, 0x88, 0x76, 0x65, 0x44, 0x33, 0x32, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x56, +0x66, 0x88, 0x89, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xde, 0xee, +0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xfe, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0xa9, +0x98, 0x88, 0x66, 0x65, 0x44, 0x43, 0x33, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x44, 0x66, +0x67, 0x88, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, +0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xee, 0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, +0x98, 0x88, 0x76, 0x66, 0x44, 0x44, 0x33, 0x31, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x46, 0x66, +0x78, 0x88, 0x99, 0x9a, 0xbb, 0xbb, 0xcc, 0xcc, 0xcd, 0xdd, 0xee, +0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xee, 0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, 0xbb, 0xa9, +0x99, 0x88, 0x87, 0x66, 0x65, 0x44, 0x43, 0x33, 0x11, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x44, 0x66, 0x67, +0x88, 0x89, 0x99, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, +0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcc, 0xcb, 0xbb, 0xba, +0x99, 0x98, 0x88, 0x76, 0x66, 0x54, 0x44, 0x33, 0x31, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x56, 0x66, 0x78, +0x88, 0x99, 0x9a, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, +0xee, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xfe, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, +0xa9, 0x99, 0x88, 0x87, 0x66, 0x65, 0x44, 0x43, 0x33, 0x11, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x45, 0x66, 0x67, 0x88, +0x89, 0x99, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, +0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcc, 0xcb, 0xbb, +0xba, 0x99, 0x98, 0x88, 0x76, 0x66, 0x54, 0x44, 0x33, 0x32, 0x11, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x56, 0x66, 0x78, 0x88, +0x99, 0x9a, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, +0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xfe, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xbb, +0xbb, 0xa9, 0x99, 0x88, 0x87, 0x66, 0x65, 0x44, 0x43, 0x33, 0x21, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x13, 0x33, 0x44, 0x45, 0x66, 0x67, 0x88, 0x89, +0x99, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, 0xee, +0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, +0xbb, 0xba, 0x99, 0x98, 0x88, 0x76, 0x66, 0x54, 0x44, 0x33, 0x32, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x11, 0x33, 0x34, 0x44, 0x56, 0x66, 0x78, 0x88, 0x99, +0x9a, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xee, +0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xfe, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, +0xcb, 0xbb, 0xa9, 0x99, 0x88, 0x87, 0x66, 0x65, 0x44, 0x43, 0x33, +0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x13, 0x33, 0x44, 0x45, 0x66, 0x67, 0x88, 0x89, 0x99, +0xab, 0xbb, 0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, 0xee, 0xee, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcc, +0xcc, 0xbb, 0xba, 0x99, 0x98, 0x88, 0x76, 0x66, 0x54, 0x44, 0x33, +0x32, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x12, 0x33, 0x34, 0x44, 0x56, 0x66, 0x78, 0x88, 0x99, 0x9a, +0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xee, 0xee, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, +0xcc, 0xcb, 0xbb, 0xa9, 0x99, 0x88, 0x87, 0x66, 0x65, 0x44, 0x43, +0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x23, 0x33, 0x44, 0x45, 0x66, 0x67, 0x88, 0x89, 0x99, 0xab, +0xbb, 0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xde, 0xee, 0xee, 0xee, 0xee, +0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xfe, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdc, 0xcc, +0xcc, 0xcc, 0xbb, 0xba, 0x99, 0x98, 0x88, 0x76, 0x66, 0x54, 0x44, +0x33, 0x32, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x12, 0x33, 0x34, 0x44, 0x56, 0x66, 0x78, 0x88, 0x99, 0x9a, 0xbb, +0xbc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xcc, +0xcc, 0xcc, 0xcb, 0xbb, 0xa9, 0x99, 0x88, 0x87, 0x66, 0x65, 0x44, +0x43, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, +0x23, 0x33, 0x44, 0x45, 0x66, 0x67, 0x88, 0x89, 0x99, 0xab, 0xbb, +0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xde, 0xee, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdd, 0xdc, +0xcc, 0xcc, 0xcc, 0xbb, 0xba, 0x99, 0x98, 0x88, 0x86, 0x66, 0x54, +0x44, 0x33, 0x32, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, +0x33, 0x34, 0x44, 0x56, 0x66, 0x78, 0x88, 0x99, 0x9a, 0xbb, 0xbc, +0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xee, 0xee, 0xee, +0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, +0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xa9, 0x99, 0x88, 0x88, 0x66, 0x65, +0x44, 0x43, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x23, +0x33, 0x44, 0x45, 0x66, 0x67, 0x88, 0x89, 0x99, 0xab, 0xbb, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xee, +0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +0xee, 0xee, 0xee, 0xee, 0xed, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0x99, 0x98, 0x88, 0x86, 0x66, +0x54, 0x44, 0x33, 0x32, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x33, +0x34, 0x44, 0x56, 0x66, 0x78, 0x88, 0x99, 0x9a, 0xbb, 0xbc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, +0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, +0xee, 0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xb9, 0x99, 0x88, 0x88, 0x66, +0x65, 0x44, 0x43, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x23, 0x33, +0x44, 0x45, 0x66, 0x67, 0x88, 0x89, 0x99, 0xab, 0xbb, 0xbb, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, 0xdd, +0xdd, 0xee, 0xee, 0xef, 0xff, 0xff, 0xee, 0xee, 0xff, 0xff, 0xfe, +0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0x99, 0x99, 0x88, 0x86, +0x66, 0x54, 0x44, 0x33, 0x32, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x33, 0x34, +0x44, 0x56, 0x66, 0x88, 0x88, 0x99, 0x9a, 0xbb, 0xbb, 0xbb, 0xbb, +0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, +0xdd, 0xee, 0xee, 0xef, 0xff, 0xee, 0xee, 0xee, 0xee, 0xff, 0xfe, +0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xa9, 0x99, 0x98, 0x88, +0x66, 0x66, 0x44, 0x43, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x23, 0x33, 0x44, +0x45, 0x66, 0x68, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xab, 0xbb, 0xbb, +0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xef, 0xfe, 0xee, 0xee, 0xee, 0xee, 0xef, 0xfe, +0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xa9, 0x99, 0x99, 0x99, 0x88, +0x86, 0x66, 0x64, 0x44, 0x33, 0x32, 0x11, 0x10, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x33, 0x34, 0x44, +0x56, 0x66, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xbb, +0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, +0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, +0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, +0x88, 0x66, 0x66, 0x44, 0x43, 0x33, 0x21, 0x11, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x23, 0x33, 0x44, 0x45, +0x66, 0x67, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, +0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, +0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, +0xbb, 0xbb, 0xba, 0xa9, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, +0x87, 0x76, 0x66, 0x64, 0x44, 0x33, 0x32, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x33, 0x34, 0x44, 0x56, +0x66, 0x66, 0x66, 0x77, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, +0x99, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, +0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, +0xbb, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x77, +0x66, 0x66, 0x66, 0x65, 0x44, 0x43, 0x33, 0x21, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x23, 0x33, 0x44, 0x44, 0x45, +0x56, 0x66, 0x66, 0x66, 0x67, 0x78, 0x88, 0x88, 0x88, 0x89, 0x99, +0x99, 0x99, 0x9a, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xde, 0xee, 0xee, 0xee, +0xee, 0xee, 0xdd, 0xdc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, +0xa9, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x87, 0x76, 0x66, +0x66, 0x66, 0x65, 0x44, 0x44, 0x44, 0x33, 0x33, 0x11, 0x10, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x33, 0x33, 0x44, 0x44, 0x44, +0x44, 0x55, 0x66, 0x66, 0x66, 0x66, 0x77, 0x88, 0x88, 0x88, 0x88, +0x99, 0x99, 0x99, 0x99, 0xaa, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcd, +0xdd, 0xee, 0xee, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xee, 0xee, 0xee, +0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xaa, 0x99, +0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x77, 0x66, 0x66, 0x66, +0x66, 0x54, 0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x31, 0x11, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x01, 0x11, 0x23, 0x33, 0x33, 0x33, 0x34, 0x44, +0x44, 0x44, 0x45, 0x56, 0x66, 0x66, 0x66, 0x67, 0x78, 0x88, 0x88, +0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xde, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xdd, 0xee, 0xee, +0xee, 0xed, 0xdd, 0xdc, 0xcc, 0xcb, 0xbb, 0xba, 0xa9, 0x99, 0x99, +0x99, 0x98, 0x88, 0x88, 0x88, 0x87, 0x76, 0x66, 0x66, 0x66, 0x65, +0x44, 0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x33, 0x32, 0x11, 0x10, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x12, 0x33, 0x33, 0x33, 0x33, +0x44, 0x44, 0x44, 0x44, 0x55, 0x66, 0x66, 0x66, 0x66, 0x77, 0x88, +0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x9a, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xde, 0xee, 0xee, 0xed, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xee, +0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0xa9, 0x99, 0x99, 0x99, +0x88, 0x88, 0x88, 0x88, 0x77, 0x66, 0x66, 0x66, 0x66, 0x54, 0x44, +0x44, 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x21, 0x11, 0x11, 0x11, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x23, 0x33, 0x33, +0x33, 0x34, 0x44, 0x44, 0x44, 0x45, 0x56, 0x66, 0x66, 0x66, 0x67, +0x78, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xde, 0xee, 0xed, 0xdd, 0xdd, 0xdc, 0xcd, 0xdd, 0xdd, 0xde, +0xee, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, 0x99, 0x98, 0x88, +0x88, 0x88, 0x87, 0x76, 0x66, 0x66, 0x66, 0x65, 0x44, 0x44, 0x44, +0x44, 0x43, 0x33, 0x33, 0x33, 0x32, 0x11, 0x11, 0x11, 0x11, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, 0x12, 0x33, +0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x55, 0x66, 0x66, 0x66, +0x66, 0x77, 0x88, 0x88, 0x88, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xde, 0xed, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xcd, 0xdd, 0xdd, +0xde, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, 0x98, 0x88, 0x88, +0x88, 0x77, 0x66, 0x66, 0x66, 0x66, 0x54, 0x44, 0x44, 0x44, 0x44, +0x33, 0x33, 0x33, 0x33, 0x21, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, +0x23, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, 0x45, 0x56, 0x66, +0x66, 0x66, 0x67, 0x78, 0x88, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xde, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, +0xdd, 0xed, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, 0x98, 0x88, 0x87, +0x76, 0x66, 0x66, 0x66, 0x65, 0x44, 0x44, 0x44, 0x44, 0x43, 0x33, +0x33, 0x33, 0x32, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, +0x11, 0x12, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x55, +0x66, 0x66, 0x66, 0x66, 0x78, 0x89, 0x99, 0xbb, 0xbc, 0xcc, 0xcc, +0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, +0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xbb, 0x99, 0x98, 0x87, 0x66, +0x66, 0x66, 0x66, 0x54, 0x44, 0x44, 0x44, 0x44, 0x33, 0x33, 0x33, +0x33, 0x21, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x11, 0x11, 0x11, 0x23, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, +0x44, 0x56, 0x66, 0x66, 0x68, 0x88, 0x99, 0xab, 0xbc, 0xcc, 0xcc, +0xdd, 0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, +0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xba, 0x99, 0x88, 0x86, 0x66, +0x66, 0x65, 0x44, 0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x33, 0x32, +0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x11, 0x11, 0x12, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, +0x44, 0x44, 0x55, 0x66, 0x68, 0x88, 0x99, 0xab, 0xbc, 0xcc, 0xcc, +0xdd, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, +0xcd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xba, 0x99, 0x88, 0x86, 0x66, +0x54, 0x44, 0x44, 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x21, 0x11, +0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x23, 0x33, 0x33, 0x33, 0x34, +0x44, 0x44, 0x44, 0x56, 0x68, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, +0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbc, 0xcc, 0xcc, 0xcc, +0xcc, 0xdd, 0xdd, 0xcc, 0xcc, 0xcb, 0xba, 0x99, 0x88, 0x86, 0x66, +0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x33, 0x32, 0x11, 0x11, 0x11, +0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, 0x12, 0x33, 0x33, 0x33, +0x33, 0x44, 0x44, 0x56, 0x68, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, +0xdd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xdd, 0xcc, 0xcc, 0xbb, 0xba, 0x99, 0x88, 0x86, 0x65, +0x44, 0x43, 0x33, 0x33, 0x33, 0x33, 0x21, 0x11, 0x11, 0x11, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x23, 0x33, +0x33, 0x33, 0x44, 0x56, 0x67, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xba, 0x99, 0x88, 0x76, 0x65, +0x44, 0x33, 0x33, 0x33, 0x32, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, 0x12, +0x33, 0x33, 0x44, 0x56, 0x67, 0x88, 0x99, 0xab, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xba, 0x99, 0x88, 0x76, 0x65, +0x44, 0x33, 0x33, 0x21, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, +0x12, 0x33, 0x44, 0x56, 0x67, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xa9, 0x9a, 0xbb, 0xbb, 0xbc, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, 0x88, 0x76, 0x65, +0x44, 0x33, 0x21, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, +0x12, 0x33, 0x44, 0x46, 0x67, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xba, 0x99, 0x99, 0xab, 0xbb, 0xbb, +0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, 0x88, 0x76, 0x65, +0x44, 0x33, 0x21, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x12, 0x33, 0x44, 0x46, 0x67, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, +0xcc, 0xcc, 0xbb, 0xbb, 0xba, 0x99, 0x99, 0x99, 0x99, 0xab, 0xbb, +0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, 0x88, 0x76, 0x64, +0x44, 0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x12, 0x33, 0x44, 0x46, 0x66, 0x88, 0x99, 0x9b, 0xbb, 0xcc, 0xcc, +0xcc, 0xbb, 0xbb, 0xbb, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xbb, +0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, 0x88, 0x66, 0x64, +0x44, 0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x33, 0x44, 0x46, 0x66, 0x88, 0x89, 0x9a, 0xbb, 0xcc, 0xcc, +0xcb, 0xbb, 0xbb, 0xa9, 0x99, 0x99, 0x88, 0x88, 0x99, 0x99, 0x9a, +0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xbb, 0xb9, 0x99, 0x88, 0x66, 0x64, +0x44, 0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x33, 0x34, 0x46, 0x66, 0x88, 0x89, 0x9a, 0xbb, 0xcc, 0xcb, +0xbb, 0xbb, 0xba, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x99, 0x99, +0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xa9, 0x98, 0x88, 0x66, 0x64, +0x43, 0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x33, 0x34, 0x45, 0x66, 0x88, 0x89, 0x9a, 0xbb, 0xcc, 0xbb, +0xbb, 0xba, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, +0x99, 0xab, 0xbb, 0xbb, 0xcc, 0xbb, 0xa9, 0x98, 0x88, 0x66, 0x64, +0x43, 0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x33, 0x34, 0x45, 0x66, 0x88, 0x89, 0x9a, 0xbb, 0xbb, 0xbb, +0xbb, 0xa9, 0x99, 0x98, 0x88, 0x88, 0x76, 0x67, 0x88, 0x88, 0x89, +0x99, 0x99, 0xbb, 0xbb, 0xbb, 0xbb, 0xa9, 0x98, 0x88, 0x66, 0x54, +0x43, 0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x33, 0x34, 0x45, 0x66, 0x78, 0x89, 0x9a, 0xbb, 0xbb, 0xbb, +0xa9, 0x99, 0x99, 0x88, 0x88, 0x86, 0x66, 0x66, 0x68, 0x88, 0x88, +0x99, 0x99, 0x9a, 0xbb, 0xbb, 0xbb, 0xa9, 0x98, 0x87, 0x66, 0x54, +0x43, 0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x34, 0x45, 0x66, 0x78, 0x89, 0x9a, 0xbb, 0xbb, 0xba, +0x99, 0x99, 0x88, 0x88, 0x87, 0x66, 0x66, 0x66, 0x66, 0x78, 0x88, +0x88, 0x99, 0x99, 0x9a, 0xbb, 0xbb, 0xa9, 0x98, 0x87, 0x66, 0x54, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x34, 0x45, 0x66, 0x78, 0x89, 0x99, 0xbb, 0xba, 0x99, +0x99, 0x98, 0x88, 0x88, 0x66, 0x66, 0x65, 0x56, 0x66, 0x66, 0x78, +0x88, 0x89, 0x99, 0x99, 0xab, 0xbb, 0xa9, 0x98, 0x87, 0x66, 0x54, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x34, 0x44, 0x66, 0x78, 0x89, 0x99, 0xbb, 0xa9, 0x99, +0x98, 0x88, 0x88, 0x76, 0x66, 0x66, 0x44, 0x44, 0x56, 0x66, 0x67, +0x88, 0x88, 0x89, 0x99, 0x99, 0xab, 0x99, 0x98, 0x87, 0x66, 0x54, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x34, 0x44, 0x66, 0x78, 0x89, 0x99, 0xa9, 0x99, 0x99, +0x88, 0x88, 0x86, 0x66, 0x66, 0x54, 0x44, 0x44, 0x45, 0x66, 0x66, +0x67, 0x88, 0x88, 0x99, 0x99, 0x9a, 0x99, 0x98, 0x87, 0x66, 0x44, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x23, 0x34, 0x44, 0x66, 0x68, 0x89, 0x99, 0x99, 0x99, 0x88, +0x88, 0x87, 0x66, 0x66, 0x64, 0x44, 0x44, 0x44, 0x44, 0x45, 0x66, +0x66, 0x78, 0x88, 0x88, 0x99, 0x99, 0x99, 0x98, 0x87, 0x66, 0x44, +0x43, 0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x13, 0x34, 0x44, 0x66, 0x68, 0x88, 0x99, 0x99, 0x98, 0x88, +0x87, 0x66, 0x66, 0x65, 0x44, 0x44, 0x33, 0x33, 0x44, 0x44, 0x56, +0x66, 0x66, 0x78, 0x88, 0x88, 0x99, 0x99, 0x98, 0x86, 0x66, 0x44, +0x43, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x13, 0x33, 0x44, 0x66, 0x68, 0x88, 0x99, 0x98, 0x88, 0x88, +0x76, 0x66, 0x65, 0x44, 0x44, 0x43, 0x33, 0x33, 0x34, 0x44, 0x44, +0x56, 0x66, 0x67, 0x88, 0x88, 0x89, 0x99, 0x88, 0x86, 0x66, 0x44, +0x43, 0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x13, 0x33, 0x44, 0x66, 0x68, 0x88, 0x99, 0x88, 0x88, 0x76, +0x66, 0x66, 0x54, 0x44, 0x43, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, +0x45, 0x66, 0x66, 0x67, 0x88, 0x88, 0x89, 0x88, 0x86, 0x66, 0x44, +0x33, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x13, 0x33, 0x44, 0x56, 0x68, 0x88, 0x88, 0x88, 0x87, 0x66, +0x66, 0x54, 0x44, 0x44, 0x33, 0x33, 0x21, 0x12, 0x33, 0x33, 0x44, +0x44, 0x45, 0x66, 0x66, 0x78, 0x88, 0x88, 0x88, 0x86, 0x65, 0x44, +0x33, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x13, 0x33, 0x44, 0x56, 0x67, 0x88, 0x88, 0x87, 0x66, 0x66, +0x65, 0x44, 0x44, 0x33, 0x33, 0x32, 0x11, 0x11, 0x23, 0x33, 0x33, +0x44, 0x44, 0x46, 0x66, 0x66, 0x78, 0x88, 0x88, 0x86, 0x65, 0x44, +0x33, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x56, 0x67, 0x88, 0x88, 0x76, 0x66, 0x65, +0x44, 0x44, 0x43, 0x33, 0x32, 0x11, 0x11, 0x11, 0x11, 0x23, 0x33, +0x34, 0x44, 0x44, 0x56, 0x66, 0x66, 0x88, 0x88, 0x76, 0x65, 0x44, +0x33, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x56, 0x67, 0x88, 0x76, 0x66, 0x66, 0x54, +0x44, 0x43, 0x33, 0x33, 0x21, 0x11, 0x10, 0x01, 0x11, 0x12, 0x33, +0x33, 0x34, 0x44, 0x44, 0x66, 0x66, 0x67, 0x88, 0x76, 0x65, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x56, 0x67, 0x87, 0x66, 0x66, 0x54, 0x44, +0x44, 0x33, 0x33, 0x21, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x12, +0x33, 0x33, 0x34, 0x44, 0x45, 0x66, 0x66, 0x67, 0x76, 0x65, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x66, 0x66, 0x65, 0x44, 0x44, +0x33, 0x33, 0x32, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, +0x13, 0x33, 0x33, 0x44, 0x44, 0x45, 0x66, 0x66, 0x66, 0x65, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x12, 0x33, 0x44, 0x46, 0x66, 0x66, 0x65, 0x44, 0x44, 0x43, +0x33, 0x32, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, +0x11, 0x23, 0x33, 0x33, 0x44, 0x44, 0x56, 0x66, 0x66, 0x64, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x33, 0x44, 0x46, 0x66, 0x66, 0x44, 0x44, 0x43, 0x33, +0x33, 0x21, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x11, 0x33, 0x33, 0x34, 0x44, 0x44, 0x56, 0x66, 0x64, 0x44, +0x33, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x33, 0x34, 0x46, 0x66, 0x54, 0x44, 0x44, 0x33, 0x33, +0x21, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x11, 0x12, 0x33, 0x33, 0x34, 0x44, 0x45, 0x66, 0x64, 0x44, +0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x33, 0x34, 0x46, 0x64, 0x44, 0x44, 0x33, 0x33, 0x32, +0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x11, 0x13, 0x33, 0x33, 0x44, 0x44, 0x45, 0x64, 0x43, +0x33, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x33, 0x34, 0x44, 0x44, 0x44, 0x43, 0x33, 0x32, 0x11, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x11, 0x11, 0x23, 0x33, 0x33, 0x44, 0x44, 0x44, 0x43, +0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x33, 0x34, 0x44, 0x44, 0x43, 0x33, 0x33, 0x21, 0x11, +0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x11, 0x11, 0x23, 0x33, 0x34, 0x44, 0x44, 0x43, +0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x34, 0x44, 0x43, 0x33, 0x33, 0x21, 0x11, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x11, 0x12, 0x33, 0x33, 0x34, 0x44, 0x43, +0x33, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x34, 0x44, 0x33, 0x33, 0x31, 0x11, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x12, 0x33, 0x33, 0x44, 0x43, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x34, 0x33, 0x33, 0x32, 0x11, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x23, 0x33, 0x33, 0x43, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x33, 0x33, 0x33, 0x11, 0x11, 0x10, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x23, 0x33, 0x33, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x23, 0x33, 0x33, 0x21, 0x11, 0x10, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x12, 0x33, 0x33, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x13, 0x33, 0x31, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x12, 0x33, +0x32, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x13, 0x32, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x13, +0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x11, 0x12, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, +0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, +0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00}; \ No newline at end of file From 5ffd4feac43c600ab00333b8f67e10bdd6add995 Mon Sep 17 00:00:00 2001 From: kamorris Date: Mon, 25 May 2020 17:09:56 -0700 Subject: [PATCH 09/42] prepare for merging. --- Extensions/Sprite.cpp | 46 ++++++++++++++++--- Extensions/Sprite.h | 2 +- .../Sprite_image_4bit/Sprite_image_4bit.ino | 12 +---- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index f3d7e3e..c82024c 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -868,12 +868,46 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ } else if (_bpp == 4) { - // not supported. The image is unlikely to have the correct colors for the color map. - // we could implement a way to push a 4-bit image using the color map? - #ifdef TFT_eSPI_DEBUG - Serial.println("pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) not implemented"); - #endif - return; + // 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. + + const uint8_t *dataBuf = (uint8_t *)data; + int sWidth = (_iwidth >> 1); + + if ((xs & 0x01) == 0 && (xo & 0x01) == 0 && (ws & 0x01) == 0) + { + if ((ws & 0x01) == 0) // use memcpy for better perf. + { + xs = (xs >> 1) + ys * sWidth; + ws = (ws >> 1); + xo = (xo >> 1) + yo * (w>>1); + while (hs--) + { + memcpy(_img4 + xs, dataBuf + xo, ws); + xo += (w >> 1); + xs += sWidth; + } + } + } + else // not optimized + { + for (int32_t yp = yo; yp < yo + hs; yp++) + { + x = xs; + for (int32_t xp = xo; xp < xo + ws; xp++) + { + uint32_t color; + if ((xp & 0x01) == 0) + color = (dataBuf[((xp+yp*w)>>1)] & 0xF0) >> 4; // even index = bits 7 .. 4 + else + color = dataBuf[((xp-1+yp*w)>>1)] & 0x0F; // odd index = bits 3 .. 0. + drawPixel(x, ys, color); + x++; + } + ys++; + } + } } else // 1bpp diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 74ba6b2..b1307b6 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -114,7 +114,7 @@ class TFT_eSprite : public TFT_eSPI { // 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. Not implemented for _bpp == 4. + // 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); void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data); diff --git a/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino b/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino index e004df4..bdf5390 100644 --- a/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino +++ b/examples/Sprite/Sprite_image_4bit/Sprite_image_4bit.ino @@ -39,10 +39,6 @@ TFT_eSPI tft = TFT_eSPI(); // Declare object "tft" TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object -const int freq = 5000; -int screenBrightnessChannel = 0; -int resolution = 8; - byte red = 31; // Red is the top 5 bits of a 16 bit colour value byte green = 0;// Green is the middle 6 bits byte blue = 0; // Blue is the bottom 5 bits @@ -55,11 +51,6 @@ uint16_t cmap[16]; void setup() { - pinMode(21, OUTPUT); - ledcSetup(screenBrightnessChannel, freq, resolution); - ledcAttachPin(21, screenBrightnessChannel); - ledcWrite(screenBrightnessChannel, 127); - Serial.begin(9600); Serial.println(); @@ -94,13 +85,12 @@ void loop(void) cmap[i] = cmap[i + 1]; } if (incr == 2) { - (void)rainbow(); // skip alternate steps + (void)rainbow(); // skip alternate steps to go faster } cmap[15] = rainbow(); rloop += incr; if (rloop > 0xc0) { incr = incr == 2 ? 1 : 2; - Serial.printf("incr %d, rloop %d\r\n", incr, rloop); rloop = 0; } From 3a2157805e04e353d80a92c77275632ababc2961 Mon Sep 17 00:00:00 2001 From: Kate Morris Date: Mon, 25 May 2020 17:12:24 -0700 Subject: [PATCH 10/42] Rename readme.txt to readme.md --- Tools/Images/{README.txt => README.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Tools/Images/{README.txt => README.md} (96%) diff --git a/Tools/Images/README.txt b/Tools/Images/README.md similarity index 96% rename from Tools/Images/README.txt rename to Tools/Images/README.md index 8ba629c..eef2149 100644 --- a/Tools/Images/README.txt +++ b/Tools/Images/README.md @@ -22,4 +22,4 @@ Create the bmp file in Gimp from any image by: I don't have photoshop so cannot help you with that. The first array produced is the palette for the image. -The second is the image itself. \ No newline at end of file +The second is the image itself. From 110128b0550a799aab3638a1702c512e54a7f5f6 Mon Sep 17 00:00:00 2001 From: Kate Morris Date: Mon, 25 May 2020 17:29:39 -0700 Subject: [PATCH 11/42] updated with formatting and links --- Tools/Images/README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Tools/Images/README.md b/Tools/Images/README.md index eef2149..02405a9 100644 --- a/Tools/Images/README.md +++ b/Tools/Images/README.md @@ -1,25 +1,26 @@ +## bmp2array4bit -bmp2array4bit.py creates C (or C++) code that contains two arrays for adding images to four-bit sprites. See Sprite_image_4bit for an example. +bmp2array4bit.py reads a bmp file, and creates C (or C++) code that contains two arrays for adding images to four-bit sprites. See [Sprite_image_4bit](../../examples/Sprite/Sprite_image_4bit) for an example. -It is loosely based on Spark Fun's bmp2array script. +It is loosely based on Spark Fun's bmp2array script, https://github.com/sparkfun/BMPtoArray/blob/master/bmp2array.py. The bmp file format is documented in https://en.wikipedia.org/wiki/BMP_file_format. -You'll need python 3.6 (the original use Python 2.7) +You'll need python 3.6 (the original uses Python 2.7) -usage: python bmp2array4bit.py [-v] star.bmp [-o myfile.c] +`usage: python bmp2array4bit.py [-v] star.bmp [-o myfile.c]` -Create the bmp file in Gimp from any image by: +Create the bmp file in Gimp (www.gimp.org) from any image as follows: -. Remove the alpha channel (if it has one) +* Remove the alpha channel (if it has one) Layer -> Transparency -> Remove Alpha Channel -. Set the mode to indexed. +* Set the mode to indexed. Image -> Mode -> Indexed... -. Select Generate optimum palette with 16 colors (max) -. Export the file with a .bmp extension. Do NOT select options: - . Run-Length Encoded - . Compatibility Options: "Do not write color space information" - . There are no Advanced Options available with these settings +* Select Generate optimum palette with 16 colors (max) +* Export the file with a .bmp extension. Do **NOT** select options: + * Run-Length Encoded + * Compatibility Options: "Do not write color space information" + * There are no Advanced Options available with these settings -I don't have photoshop so cannot help you with that. +(There are other tools that will produce bmp files, and these should work provided you don't use run-length encoding or other advanced features). The first array produced is the palette for the image. The second is the image itself. From b5826586fc471ab60aa97636642f4f92b1ea3617 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 5 Jun 2020 16:05:04 +0100 Subject: [PATCH 12/42] Allow 4bpp Sprites to be rotated 4bpp Sprites can now be pushed to the TFT with a rotation --- Extensions/Sprite.cpp | 58 ++++++++++--------- Extensions/Sprite.h | 5 +- .../Rotated_Sprite_1/Rotated_Sprite_1.ino | 8 ++- .../Sprite_draw_4bit/Sprite_draw_4bit.ino | 2 +- library.json | 2 +- library.properties | 2 +- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index f3d7e3e..30fe9ac 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -59,8 +59,6 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _iwidth = _dwidth = _bitwidth = w; _iheight = _dheight = h; - _colorMap = nullptr; - this->cursor_x = 0; this->cursor_y = 0; @@ -94,6 +92,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _img8_2 = _img8 + (w * h + 1); } + if ( (_bpp == 4) && (_colorMap == nullptr)) createPalette(default_4bit_palette); + // 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) ) @@ -195,7 +195,7 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames) ** Description: Set a palette for a 4-bit per pixel sprite *************************************************************************************x*/ -void TFT_eSprite::createPalette(uint16_t colorMap[], int colors) +void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) { if (_colorMap != nullptr) { @@ -204,14 +204,18 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], int colors) if (colorMap == nullptr) { - return; // do nothing other than clear the existing map + // Create a color map using the default FLASH map + createPalette(default_4bit_palette); + return; } - // allocate color map + // Allocate and clear memory for 16 color map _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); - if (colors > 16) - colors = 16; - for (auto i = 0; i < colors; i++) + + if (colors > 16) colors = 16; + + // Copy map colors + for (uint8_t i = 0; i < colors; i++) { _colorMap[i] = colorMap[i]; } @@ -222,7 +226,7 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], int colors) ** Description: Set a palette for a 4-bit per pixel sprite *************************************************************************************x*/ -void TFT_eSprite::createPalette(const uint16_t colorMap[], int colors) +void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) { if (_colorMap != nullptr) { @@ -231,14 +235,17 @@ void TFT_eSprite::createPalette(const uint16_t colorMap[], int colors) if (colorMap == nullptr) { - return; // do nothing other than clear the existing map + // Create a color map using the default FLASH map + colorMap = default_4bit_palette; } - // allocate color map + // Allocate and clear memory for 16 color map _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); - if (colors > 16) - colors = 16; - for (auto i = 0; i < colors; i++) + + if (colors > 16) colors = 16; + + // Copy map colors + for (uint8_t i = 0; i < colors; i++) { _colorMap[i] = pgm_read_word(colorMap++); } @@ -306,7 +313,7 @@ int8_t TFT_eSprite::getColorDepth(void) /*************************************************************************************** ** Function name: setBitmapColor -** Description: Set the foreground foreground and background colour +** Description: Set the 1bpp foreground foreground and background colour ***************************************************************************************/ void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b) { @@ -317,23 +324,22 @@ void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b) /*************************************************************************************** ** Function name: setPaletteColor -** Description: Set the palette color at the given index +** 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 + if (_colorMap == nullptr || index > 15) return; // out of bounds + _colorMap[index] = color; } /*************************************************************************************** ** Function name: getPaletteColor -** Description: Return the palette color at index, or 0 (black) on error. +** 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; + if (_colorMap == nullptr || index > 15) return 0; // out of bounds return _colorMap[index]; } @@ -395,7 +401,7 @@ int16_t TFT_eSprite::getPivotY(void) #define FP_SCALE 10 bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) { - if ( !_created || _bpp == 4) return false; + if ( !_created) return false; // Bounding box parameters int16_t min_x; @@ -413,6 +419,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) uint32_t xe = _iwidth << FP_SCALE; uint32_t ye = _iheight << FP_SCALE; uint32_t tpcolor = transp; // convert to unsigned + if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; _tft->startWrite(); // Avoid transaction overhead for every tft pixel @@ -461,9 +468,10 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) ** Function name: pushRotated - Fast fixed point integer maths version ** Description: Push a rotated copy of the Sprite to another Sprite *************************************************************************************x*/ +// Not compatible with 4bpp bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) { - if ( !_created || _bpp == 4) return false; // Check this Sprite is created + 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 @@ -658,12 +666,8 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y) } else if (_bpp == 4) { - if (_colorMap == nullptr) { - return; - } _tft->pushImage(x, y, _dwidth, _dheight, _img4, false, _colorMap); } - else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8)); } diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 74ba6b2..489ac69 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -15,6 +15,7 @@ class TFT_eSprite : public TFT_eSPI { // 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 // - 1 byte per pixel for 8 bit colour // - 2 bytes per pixel for 16 bit color depth ~TFT_eSprite(void); @@ -34,8 +35,8 @@ class TFT_eSprite : public TFT_eSPI { 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, int colors = 16); // Palette in RAM - void createPalette(const uint16_t *palette, int colors = 16); // Palette in FLASH + 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); diff --git a/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino b/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino index b789b50..5bc3ffe 100644 --- a/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino +++ b/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino @@ -10,7 +10,7 @@ // screen very simple. The rotation is clockwise with increasing angle. The angle is in // degrees, an angle of 0 means no Sprite rotation. -// The pushRotated() function works with 1, 8 and 16 bit per pixel (bpp) Sprites. +// The pushRotated() function works with 1, 4, 8 and 16 bit per pixel (bpp) Sprites. // The original Sprite is unchanged so can be plotted again at a different angle. @@ -20,6 +20,10 @@ // For 1 bpp Sprites the foreground and background colours are defined with the // function spr.setBitmapColor(foregroundColor, backgroundColor). +// For 4 bpp Sprites the colour map index is used instead of the 16 bit colour +// e.g. spr.setTextColor(5); // Green text in default colour map +// See "Transparent_Sprite_Demo_4bit" example for default colour map details + // Created by Bodmer 6/1/19 as an example to the TFT_eSPI library: // https://github.com/Bodmer/TFT_eSPI @@ -46,7 +50,7 @@ void setup() { void loop() { - int xw = tft.width()/2; // xw, yh is midle of screen + int xw = tft.width()/2; // xw, yh is middle of screen int yh = tft.height()/2; diff --git a/examples/Sprite/Sprite_draw_4bit/Sprite_draw_4bit.ino b/examples/Sprite/Sprite_draw_4bit/Sprite_draw_4bit.ino index 40d9fc1..ca3ebe4 100644 --- a/examples/Sprite/Sprite_draw_4bit/Sprite_draw_4bit.ino +++ b/examples/Sprite/Sprite_draw_4bit/Sprite_draw_4bit.ino @@ -88,7 +88,7 @@ void loop(void) // Pass the palette to the Sprite class spr.createPalette(cmap); - // Push Sprite parially off-screen to test cropping + // Push Sprite partially off-screen to test cropping spr.pushSprite(-40, -40); spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2, 10); spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40); diff --git a/library.json b/library.json index 70efa62..a17e9ee 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.8", + "version": "2.2.9", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index a3b3ab4..8dd4766 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.8 +version=2.2.9 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 21aa38b87f8569379b2680065d13e475ad50ed96 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 5 Jun 2020 16:43:48 +0100 Subject: [PATCH 13/42] Update version --- TFT_eSPI.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 4ab6ce3..49b932d 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.8" +#define TFT_ESPI_VERSION "2.2.9" /*************************************************************************************** ** Section 1: Load required header files From fb86ae4d1bf785e377fd11caec88db7bf614dddb Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 6 Jun 2020 14:55:02 +0100 Subject: [PATCH 14/42] Update Read_User_Setup add #648 Read_User_Setup now includes backlight settings --- TFT_eSPI.cpp | 38 ++++++++++++------- TFT_eSPI.h | 5 ++- .../Read_User_Setup/Read_User_Setup.ino | 14 +++++++ library.json | 2 +- library.properties | 2 +- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 5242b42..b2cb678 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2614,9 +2614,6 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //begin_tft_write(); // Must be called before setWindow - addr_col = 0xFFFF; - addr_row = 0xFFFF; - #ifdef CGRAM_OFFSET x0+=colstart; x1+=colstart; @@ -2624,16 +2621,21 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) y1+=rowstart; #endif - // Column addr set - DC_C; tft_Write_8(TFT_CASET); - DC_D; tft_Write_32C(x0, x1); + // No need to send x if it has not changed (speeds things up) + if (addr_col != (x0<<16 | x1)) { + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32C(x0, x1); + addr_col = (x0<<16 | x1); + } - // Row addr set - DC_C; tft_Write_8(TFT_PASET); - DC_D; tft_Write_32C(y0, y1); + // No need to send y if it has not changed (speeds things up) + if (addr_row != (y0<<16 | y1)) { + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32C(y0, y1); + addr_row = (y0<<16 | y1); + } DC_C; tft_Write_8(TFT_RAMWR); - DC_D; //end_tft_write(); // Must be called after setWindow @@ -2695,17 +2697,17 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) begin_tft_write(); // No need to send x if it has not changed (speeds things up) - if (addr_col != x) { + if (addr_col != (x<<16 | x)) { DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32D(x); - addr_col = x; + addr_col = (x<<16 | x); } // No need to send y if it has not changed (speeds things up) - if (addr_row != y) { + if (addr_row != (y<<16 | y)) { DC_C; tft_Write_8(TFT_PASET); DC_D; tft_Write_32D(y); - addr_row = y; + addr_row = (y<<16 | y); } DC_C; tft_Write_8(TFT_RAMWR); @@ -4204,6 +4206,14 @@ void TFT_eSPI::getSetup(setup_t &tft_settings) tft_settings.pin_tft_d7 = -1; #endif +#if defined (TFT_BL) + tft_settings.pin_tft_led = TFT_BL; +#endif + +#if defined (TFT_BACKLIGHT_ON) + 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; diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 49b932d..8fc7c74 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.9" +#define TFT_ESPI_VERSION "2.2.10" /*************************************************************************************** ** Section 1: Load required header files @@ -335,6 +335,9 @@ 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_tch_cs; // Touch chip select pin int16_t tft_spi_freq;// TFT write SPI frequency diff --git a/examples/Test and diagnostics/Read_User_Setup/Read_User_Setup.ino b/examples/Test and diagnostics/Read_User_Setup/Read_User_Setup.ino index ab823ea..7530051 100644 --- a/examples/Test and diagnostics/Read_User_Setup/Read_User_Setup.ino +++ b/examples/Test and diagnostics/Read_User_Setup/Read_User_Setup.ino @@ -61,6 +61,7 @@ if (user.tft_driver != 0xE9D) // For ePaper displays the size is defined in the Serial.print("Display driver = "); Serial.println(user.tft_driver, HEX); // Hexadecimal code Serial.print("Display width = "); Serial.println(user.tft_width); // Rotation 0 width and height Serial.print("Display height = "); Serial.println(user.tft_height); + Serial.println(); } else if (user.tft_driver == 0xE9D) Serial.println("Display driver = ePaper\n"); @@ -97,6 +98,10 @@ if (user.overlap == true) } #endif String pinNameRef = "GPIO "; +#ifdef ESP8266 + pinNameRef = "PIN_D"; +#endif + if (user.esp == 0x32F) { Serial.println("\n>>>>> Note: STM32 pin references above D15 may not reflect board markings <<<<<"); pinNameRef = "D"; @@ -119,6 +124,15 @@ if (user.pin_tft_d5 != -1) { Serial.print("TFT_D5 = " + pinNameRef); Serial.pr if (user.pin_tft_d6 != -1) { Serial.print("TFT_D6 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d6)); } if (user.pin_tft_d7 != -1) { Serial.print("TFT_D7 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d7)); } +#if defined (TFT_BL) + Serial.print("\nTFT_BL = " + pinNameRef); Serial.println(getPinName(user.pin_tft_led)); + #if defined (TFT_BACKLIGHT_ON) + Serial.print("TFT_BACKLIGHT_ON = "); Serial.println(user.pin_tft_led_on == HIGH ? "HIGH" : "LOW"); + #endif +#endif + +Serial.println(); + uint16_t fonts = tft.fontsLoaded(); if (fonts & (1 << 1)) Serial.print("Font GLCD loaded\n"); if (fonts & (1 << 2)) Serial.print("Font 2 loaded\n"); diff --git a/library.json b/library.json index a17e9ee..67b178d 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.9", + "version": "2.2.10", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 8dd4766..33c9b5a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.9 +version=2.2.10 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 284f52b009b6d479560a76cd3c56078c42a25a23 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Thu, 11 Jun 2020 22:34:22 +0100 Subject: [PATCH 15/42] Allow partially of screen RLE fonts --- TFT_eSPI.cpp | 60 ++++++++++++++++++++++++++++++++++++---------- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index b2cb678..99964d0 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -3578,21 +3578,55 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } } } - else { // Text colour != background && textsize = 1 - // so use faster drawing of characters and background using block write - setWindow(x, y, x + width - 1, y + height - 1); + else { + // Text colour != background && textsize = 1 and character is within screen area + // so use faster drawing of characters and background using block write + if ((x >= 0) && (x + width <= _width) && (y >= 0) && (y + height <= _height)) + { + setWindow(x, y, x + width - 1, y + 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); + // 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 { - line++; w -= line; - pushBlock(textbgcolor,line); + } + else + { + int32_t px = x, py = y; // To hold character block start and end column and row values + int32_t pc = 0; // Pixel count + int32_t pl = 0; // Pixel line length + uint16_t pcol = 0; // Pixel color + + while (pc < w) { + line = pgm_read_byte((uint8_t *)flash_address); + flash_address++; + if (line & 0x80) { pcol = textcolor; line &= 0x7F; } + else pcol = textbgcolor; + line++; + px = x + pc % width; + py = y + pc / width; + + pl = 0; + pc += line; + while (line--) { // In this case the while(line--) is faster + pl++; + if ((px+pl) >= (x + width)) { + drawFastHLine(px, py, pl, pcol); + pl = 0; + px = x; + py ++; + } + } + if (pl)drawFastHLine(px, py, pl, pcol); } } } diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 8fc7c74..059e644 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.10" +#define TFT_ESPI_VERSION "2.2.11" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index 67b178d..f0c9182 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.10", + "version": "2.2.11", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 33c9b5a..cb0e3f8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.10 +version=2.2.11 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 24750c605d6aaefcc39c46a300e588b9fbdb2ac7 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 13 Jun 2020 21:05:47 +0100 Subject: [PATCH 16/42] Add option to use STM32 SPI port 2 See new #define options in "Setup29_ILI9341_STM32.h" --- Processors/TFT_eSPI_STM32.c | 75 +++++++++++++++++++---------- Processors/TFT_eSPI_STM32.h | 44 +++++++++++++---- TFT_eSPI.h | 2 +- User_Setup.h | 28 ++++++++++- User_Setups/Setup29_ILI9341_STM32.h | 13 ++++- User_Setups/SetupX_Template.h | 68 ++++++++++++++++++++------ library.json | 2 +- library.properties | 2 +- 8 files changed, 179 insertions(+), 55 deletions(-) diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index c3acaa7..162e732 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -10,8 +10,11 @@ // No globals #else // Use STM32 default SPI port - SPIClass& spi = SPI; - + #if !defined (TFT_MOSI) || !defined (TFT_MISO) || !defined (TFT_SCLK) + SPIClass& spi = SPI; + #else + SPIClass spi(TFT_MOSI, TFT_MISO, TFT_SCLK); + #endif // SPI HAL peripheral handle SPI_HandleTypeDef spiHal; #endif @@ -484,15 +487,20 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t // The DMA functions here work with SPI only (not parallel) #if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx) /*************************************************************************************** -** Function name: DMA2_StreamX_IRQHandler -** Description: Override the default HAL stream 3 interrupt handler +** Function name: DMAX_StreamX_IRQHandler +** Description: Override the default HAL stream X interrupt handler ***************************************************************************************/ -extern "C" void DMA2_Stream3_IRQHandler(); -void DMA2_Stream3_IRQHandler(void) -{ - // Call the default end of buffer handler - HAL_DMA_IRQHandler(&dmaHal); -} + #if (TFT_SPI_PORT == 1) + extern "C" void DMA2_Stream3_IRQHandler(); + void DMA2_Stream3_IRQHandler(void) + #elif (TFT_SPI_PORT == 2) + extern "C" void DMA1_Stream4_IRQHandler(); + void DMA1_Stream4_IRQHandler(void) + #endif + { + // Call the default end of buffer handler + HAL_DMA_IRQHandler(&dmaHal); + } /*************************************************************************************** ** Function name: initDMA @@ -503,9 +511,14 @@ void DMA2_Stream3_IRQHandler(void) // https://electronics.stackexchange.com/questions/379813/configuring-the-dma-request-multiplexer-on-a-stm32h7-mcu bool TFT_eSPI::initDMA(void) { - __HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock + #if (TFT_SPI_PORT == 1) + __HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock + dmaHal.Init.Channel = DMA_CHANNEL_3; // DMA channel 3 is for SPI1 TX + #elif (TFT_SPI_PORT == 2) + __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA2 clock + dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI2 TX + #endif - dmaHal.Init.Channel = DMA_CHANNEL_3; // DMA channel 3 is for SPI1 TX dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address @@ -517,10 +530,13 @@ bool TFT_eSPI::initDMA(void) // Insert error message here? return DMA_Enabled = false; }; + #if (TFT_SPI_PORT == 1) + HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); // Enable DMA end interrupt handler + #elif (TFT_SPI_PORT == 2) + HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); // Enable DMA end interrupt handler + #endif - HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); // Enable DMA end interrupt handler - - __HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral + __HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral return DMA_Enabled = true; } @@ -530,13 +546,18 @@ bool TFT_eSPI::initDMA(void) ** Function name: DMA1_ChannelX_IRQHandler ** Description: Override the default HAL stream 3 interrupt handler ***************************************************************************************/ -extern "C" void DMA1_Channel3_IRQHandler(); + #if (TFT_SPI_PORT == 1) + extern "C" void DMA1_Channel3_IRQHandler(); + void DMA1_Channel3_IRQHandler(void) + #elif (TFT_SPI_PORT == 2) + extern "C" void DMA1_Channel5_IRQHandler(); + void DMA1_Channel5_IRQHandler(void) + #endif + { + // Call the default end of buffer handler + HAL_DMA_IRQHandler(&dmaHal); + } -void DMA1_Channel3_IRQHandler(void) -{ - // Call the default end of buffer handler - HAL_DMA_IRQHandler(&dmaHal); -} //*/ /*************************************************************************************** ** Function name: initDMA @@ -544,7 +565,7 @@ void DMA1_Channel3_IRQHandler(void) ***************************************************************************************/ bool TFT_eSPI::initDMA(void) { - __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA2 clock + __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral @@ -561,9 +582,13 @@ bool TFT_eSPI::initDMA(void) return DMA_Enabled = false; }; - HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0); - HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); // Enable DMA end interrupt handler - + #if (TFT_SPI_PORT == 1) + HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); // Enable DMA end interrupt handler + #elif (TFT_SPI_PORT == 2) + HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); // Enable DMA end interrupt handler + #endif return DMA_Enabled = true; } diff --git a/Processors/TFT_eSPI_STM32.h b/Processors/TFT_eSPI_STM32.h index 4da52f7..6fcab87 100644 --- a/Processors/TFT_eSPI_STM32.h +++ b/Processors/TFT_eSPI_STM32.h @@ -146,23 +146,49 @@ //////////////////////////////////////////////////////////////////////////////////////// #else + // Use SPI1 as default if not defined + #ifndef TFT_SPI_PORT + #define TFT_SPI_PORT 1 + #endif + // Global define is _VARIANT_ARDUINO_STM32_, see board package stm32_def.h for specific variants #if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx) + #define STM32_DMA // DMA is available with these processors - // Initialise processor specific SPI and DMA instances - used by init() - #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \ - dmaHal.Instance = DMA2_Stream3 - // The DMA hard-coding for SPI1 is in TFT_eSPI_STM32.c as follows: - // DMA_CHANNEL_3 - // DMA2_Stream3_IRQn and DMA2_Stream3_IRQHandler() + + #if (TFT_SPI_PORT == 1) + // Initialise processor specific SPI and DMA instances - used by init() + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \ + dmaHal.Instance = DMA2_Stream3 + // The DMA hard-coding for SPI1 is in TFT_eSPI_STM32.c as follows: + // DMA_CHANNEL_3 + // DMA2_Stream3_IRQn and DMA2_Stream3_IRQHandler() + #elif (TFT_SPI_PORT == 2) + // Initialise processor specific SPI and DMA instances - used by init() + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI2; \ + dmaHal.Instance = DMA1_Stream4 + // The DMA hard-coding for SPI2 is in TFT_eSPI_STM32.c as follows: + // DMA_CHANNEL_4 + // DMA1_Stream4_IRQn and DMA1_Stream4_IRQHandler() + #endif + #elif defined (STM32F1xx) // For Blue Pill and STM32F1xx processors with DMA support #define STM32_DMA // DMA is available with these processors - #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \ - dmaHal.Instance = DMA1_Channel3 + #if (TFT_SPI_PORT == 1) + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \ + dmaHal.Instance = DMA1_Channel3 + #elif (TFT_SPI_PORT == 2) + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI2; \ + dmaHal.Instance = DMA1_Channel5 + #endif #else // For STM32 processor with no implemented DMA support (yet) - #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1 + #if (TFT_SPI_PORT == 1) + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI1 + #elif (TFT_SPI_PORT == 2) + #define INIT_TFT_DATA_BUS spiHal.Instance = SPI2 + #endif #endif #endif diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 059e644..416ad7e 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.11" +#define TFT_ESPI_VERSION "2.2.12" /*************************************************************************************** ** Section 1: Load required header files diff --git a/User_Setup.h b/User_Setup.h index 754215f..32eea56 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -236,6 +236,31 @@ //#define TFT_D6 27 //#define TFT_D7 14 +// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ###### + +// The TFT can be connected to SPI port 1 or 2 +//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz +//#define TFT_MOSI PA7 +//#define TFT_MISO PA6 +//#define TFT_SCLK PA5 + +//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz +//#define TFT_MOSI PB15 +//#define TFT_MISO PB14 +//#define TFT_SCLK PB13 + +// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select +//#define TFT_CS D5 // Chip select control pin to TFT CS +//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select) +//#define TFT_RST D7 // Reset pin to TFT RST (or RESET) +// OR alternatively, we can use STM32 port reference names PXnn +//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5 +//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6 +//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7 + +//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset + // Use an Arduino pin for initial testing as connecting to processor reset + // may not work (pulse too short at power up?) // ################################################################################## // @@ -278,8 +303,9 @@ // #define SPI_FREQUENCY 5000000 // #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 20000000 -#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3 +#define SPI_FREQUENCY 27000000 // #define SPI_FREQUENCY 40000000 +// #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz) // #define SPI_FREQUENCY 80000000 // Optional reduced SPI frequency for reading TFT diff --git a/User_Setups/Setup29_ILI9341_STM32.h b/User_Setups/Setup29_ILI9341_STM32.h index 0a8dc82..e7ccae4 100644 --- a/User_Setups/Setup29_ILI9341_STM32.h +++ b/User_Setups/Setup29_ILI9341_STM32.h @@ -22,7 +22,18 @@ // MOSI and SCK do not need to be defined, connect: // - Arduino SCK to TFT SCK // - Arduino MOSI to TFT SDI(may be marked SDA or MOSI) -// Standard Arduino SPI pins are (SCK=D13, MOSI=D11) this is port pins PA5 and PA7 on Nucleo-F767ZI +// Typical Arduino SPI port 1 pins are (SCK=D13, MISO=D12, MOSI=D11) this is port pins PA5, PA6 and PA7 on Nucleo-F767ZI +// SPI port 2 pins are (SCK=D18, MISO=A7, MOSI=D17) this is typically port pins PB13, PB14 and PB15 + +#define TFT_SPI_PORT 1 // SPI 1 maximum clock rate is 55MHz +#define TFT_MOSI PA7 +#define TFT_MISO PA6 +#define TFT_SCLK PA5 + +//#define TFT_SPI_PORT 2 // SPI 2 maximum clock rate is 27MHz +//#define TFT_MOSI PB15 +//#define TFT_MISO PB14 +//#define TFT_SCLK PB13 // Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select #define TFT_CS D5 // Chip select control pin to TFT CS diff --git a/User_Setups/SetupX_Template.h b/User_Setups/SetupX_Template.h index 8c4e5e2..32eea56 100644 --- a/User_Setups/SetupX_Template.h +++ b/User_Setups/SetupX_Template.h @@ -8,6 +8,7 @@ // run without the need to make any more changes for a particular hardware setup! // Note that some sketches are designed for a particular TFT pixel width/height + // ################################################################################## // // Section 1. Call up the right driver file and any options for it @@ -22,7 +23,13 @@ //#define NUCLEO_64_TFT //#define NUCLEO_144_TFT -// Tell the library to use 8 bit parallel mode(otherwise SPI is assumed) +// STM32 8 bit parallel only: +// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7 +// then this will improve rendering performance by a factor of ~8x +//#define STM_PORTA_DATA_BUS +//#define STM_PORTA_DATA_BUS + +// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) //#define TFT_PARALLEL_8_BIT // Display type - only define if RPi display @@ -33,6 +40,7 @@ //#define ST7735_DRIVER // Define additional parameters below for this display //#define ILI9163_DRIVER // Define additional parameters below for this display //#define S6D02A1_DRIVER +//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI //#define HX8357D_DRIVER //#define ILI9481_DRIVER //#define ILI9486_DRIVER @@ -91,13 +99,6 @@ // #define TFT_INVERSION_ON // #define TFT_INVERSION_OFF -// If a backlight control signal is available then define the TFT_BL pin in Section 2 -// below. The backlight will be turned ON when tft.begin() is called, but the library -// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be -// driven with a PWM signal or turned OFF/ON then this must be handled by the user -// sketch. e.g. with digitalWrite(TFT_BL, LOW); - -// #define TFT_BACKLIGHT_ON HIGH // HIGH or LOW are options // ################################################################################## // @@ -105,6 +106,17 @@ // // ################################################################################## +// If a backlight control signal is available then define the TFT_BL pin in Section 2 +// below. The backlight will be turned ON when tft.begin() is called, but the library +// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be +// driven with a PWM signal or turned OFF/ON then this must be handled by the user +// sketch. e.g. with digitalWrite(TFT_BL, LOW); + +// #define TFT_BL 32 // LED back-light control pin +// #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) + + + // We must use hardware SPI, a minimum of 3 GPIO pins is needed. // Typical setup for ESP8266 NodeMCU ESP-12 is : // @@ -181,8 +193,6 @@ //#define TFT_RST 4 // Reset pin (could connect to RST pin) //#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST -//#define TFT_BL 32 // LED back-light (only for ST7789 with backlight control pin) - //#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen //#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only @@ -203,10 +213,11 @@ // Wemos D32 boards need to be modified, see diagram in Tools folder. // Only ILI9481 and ILI9341 based displays have been tested! -// Parallel bus is only supported on ESP32 -// Uncomment line below to use ESP32 Parallel interface instead of SPI +// Parallel bus is only supported for the STM32 and ESP32 +// Example below is for ESP32 Parallel interface with UNO displays -//#define ESP32_PARALLEL +// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) +//#define TFT_PARALLEL_8_BIT // The ESP32 and TFT the pins used for testing are: //#define TFT_CS 33 // Chip select control pin (library pulls permanently low @@ -225,6 +236,31 @@ //#define TFT_D6 27 //#define TFT_D7 14 +// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ###### + +// The TFT can be connected to SPI port 1 or 2 +//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz +//#define TFT_MOSI PA7 +//#define TFT_MISO PA6 +//#define TFT_SCLK PA5 + +//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz +//#define TFT_MOSI PB15 +//#define TFT_MISO PB14 +//#define TFT_SCLK PB13 + +// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select +//#define TFT_CS D5 // Chip select control pin to TFT CS +//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select) +//#define TFT_RST D7 // Reset pin to TFT RST (or RESET) +// OR alternatively, we can use STM32 port reference names PXnn +//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5 +//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6 +//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7 + +//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset + // Use an Arduino pin for initial testing as connecting to processor reset + // may not work (pulse too short at power up?) // ################################################################################## // @@ -262,14 +298,14 @@ // With an ILI9341 display 40MHz works OK, 80MHz sometimes fails // With a ST7735 display more than 27MHz may not work (spurious pixels and lines) // With an ILI9163 display 27 MHz works OK. -// The RPi typically only works at 20MHz maximum. // #define SPI_FREQUENCY 1000000 // #define SPI_FREQUENCY 5000000 // #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 20000000 -#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3 -// #define SPI_FREQUENCY 40000000 // Maximum to use SPIFFS +#define SPI_FREQUENCY 27000000 +// #define SPI_FREQUENCY 40000000 +// #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz) // #define SPI_FREQUENCY 80000000 // Optional reduced SPI frequency for reading TFT diff --git a/library.json b/library.json index f0c9182..63596f5 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.11", + "version": "2.2.12", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index cb0e3f8..e3559e6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.11 +version=2.2.12 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 8cb59566d4affec62f2c2f3513ea2635b10f9fc8 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 15 Jun 2020 12:22:38 +0100 Subject: [PATCH 17/42] Add multi TFT option support for issue #663 Avoid coordinate optimisation for sketch controlled multiple TFT displays. Add #define MULTI_TFT_SUPPORT to prevent setAddr optimisation that relies on coordinate transfer minimisation. --- TFT_eSPI.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 99964d0..ad9d22e 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2621,6 +2621,13 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) y1+=rowstart; #endif +#ifdef MULTI_TFT_SUPPORT + // No optimisation to permit multiple screens + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32C(x0, x1); + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32C(y0, y1); +#else // No need to send x if it has not changed (speeds things up) if (addr_col != (x0<<16 | x1)) { DC_C; tft_Write_8(TFT_CASET); @@ -2634,6 +2641,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) DC_D; tft_Write_32C(y0, y1); addr_row = (y0<<16 | y1); } +#endif DC_C; tft_Write_8(TFT_RAMWR); DC_D; @@ -2696,6 +2704,13 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) begin_tft_write(); +#ifdef MULTI_TFT_SUPPORT + No optimisation + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32D(x); + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32D(y); +#else // No need to send x if it has not changed (speeds things up) if (addr_col != (x<<16 | x)) { DC_C; tft_Write_8(TFT_CASET); @@ -2709,6 +2724,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) DC_D; tft_Write_32D(y); addr_row = (y<<16 | y); } +#endif DC_C; tft_Write_8(TFT_RAMWR); DC_D; tft_Write_16(color); From 7861a0206efb34ddca229043de7ea6f9859041ba Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 15 Jun 2020 13:54:45 +0100 Subject: [PATCH 18/42] Add missing // --- TFT_eSPI.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index ad9d22e..0252d30 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2705,11 +2705,11 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) begin_tft_write(); #ifdef MULTI_TFT_SUPPORT - No optimisation - DC_C; tft_Write_8(TFT_CASET); - DC_D; tft_Write_32D(x); - DC_C; tft_Write_8(TFT_PASET); - DC_D; tft_Write_32D(y); + // No optimisation + DC_C; tft_Write_8(TFT_CASET); + DC_D; tft_Write_32D(x); + DC_C; tft_Write_8(TFT_PASET); + DC_D; tft_Write_32D(y); #else // No need to send x if it has not changed (speeds things up) if (addr_col != (x<<16 | x)) { From a7be0c0ebe1687df099840a9137fe493c9fd604c Mon Sep 17 00:00:00 2001 From: kamorris Date: Thu, 18 Jun 2020 20:29:10 -0700 Subject: [PATCH 19/42] delete extraneous ino file --- .../Sprite/Sprite_image_4bit/Sprite_image.ino | 162 ------------------ 1 file changed, 162 deletions(-) delete mode 100644 examples/Sprite/Sprite_image_4bit/Sprite_image.ino diff --git a/examples/Sprite/Sprite_image_4bit/Sprite_image.ino b/examples/Sprite/Sprite_image_4bit/Sprite_image.ino deleted file mode 100644 index e004df4..0000000 --- a/examples/Sprite/Sprite_image_4bit/Sprite_image.ino +++ /dev/null @@ -1,162 +0,0 @@ -/* - - Sketch to show how a Sprite can use a four-bit image with - a palette to change the appearance of an image while rendering - it only once. - - Example for library: - https://github.com/Bodmer/TFT_eSPI - - A Sprite is notionally an invisible graphics screen that is - kept in the processors RAM. Graphics can be drawn into the - Sprite just as it 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. - - A 16 bit Sprite occupies (2 * width * height) bytes in RAM. - - On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated, - this size requires 40kBytes of RAM for a 16 bit color depth. - - When 8 bit color depth sprites are created they occupy - (width * height) bytes in RAM, so larger sprites can be - created, or the RAM required is halved. - -*/ - - -// Set delay after plotting the sprite -#define DELAY 30 - -// Width and height of sprite -#define WIDTH 164 -#define HEIGHT 164 - -#include "sample_images.h" - -TFT_eSPI tft = TFT_eSPI(); // Declare object "tft" - -TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object - -const int freq = 5000; -int screenBrightnessChannel = 0; -int resolution = 8; - -byte red = 31; // Red is the top 5 bits of a 16 bit colour value -byte green = 0;// Green is the middle 6 bits -byte blue = 0; // Blue is the bottom 5 bits -byte state = 0; - -int rloop = 0; -int incr = 1; - -uint16_t cmap[16]; - -void setup() -{ - pinMode(21, OUTPUT); - ledcSetup(screenBrightnessChannel, freq, resolution); - ledcAttachPin(21, screenBrightnessChannel); - ledcWrite(screenBrightnessChannel, 127); - - Serial.begin(9600); - Serial.println(); - - delay(50); - - // Initialise the TFT registers - tft.init(); - - spr.setColorDepth(4); - - // Create a sprite of defined size - spr.createSprite(WIDTH, HEIGHT); - - // Clear the TFT screen to black - tft.fillScreen(TFT_BLACK); - - // push the image - only need to do this once. - spr.pushImage(2, 2, 160, 160, (uint16_t *)stars); - - for (int i = 0; i < 16; i++) - cmap[i] = rainbow(); -} - -void loop(void) -{ - // create a palette with the defined colors and push it. - spr.createPalette(cmap, 16); - spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2); - - // update the colors - for (int i = 0; i < 15; i++) { - cmap[i] = cmap[i + 1]; - } - if (incr == 2) { - (void)rainbow(); // skip alternate steps - } - cmap[15] = rainbow(); - rloop += incr; - if (rloop > 0xc0) { - incr = incr == 2 ? 1 : 2; - Serial.printf("incr %d, rloop %d\r\n", incr, rloop); - rloop = 0; - - } - delay(DELAY); - -} - -// ######################################################################### -// Return a 16 bit rainbow colour -// ######################################################################### -unsigned int rainbow() -{ - switch (state) { - case 0: - green ++; - if (green == 64) { - green = 63; - state = 1; - } - break; - case 1: - red--; - if (red == 255) { - red = 0; - state = 2; - } - break; - case 2: - blue ++; - if (blue == 32) { - blue = 31; - state = 3; - } - break; - case 3: - green --; - if (green == 255) { - green = 0; - state = 4; - } - break; - case 4: - red ++; - if (red == 32) { - red = 31; - state = 5; - } - break; - case 5: - blue --; - if (blue == 255) { - blue = 0; - state = 0; - } - break; - } - return red << 11 | green << 5 | blue; -} - From c7383df1a31d7678022690bf422d02de920705ae Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 19 Jun 2020 10:06:28 +0100 Subject: [PATCH 20/42] Raise version --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index e3559e6..d51d0a5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.12 +version=2.2.13 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From af5aba3aaec938cbeeafd5d01ecab03707a05174 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 19 Jun 2020 10:07:08 +0100 Subject: [PATCH 21/42] Raise version --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 63596f5..1e47018 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.12", + "version": "2.2.13", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": From a3fea4299e46d771f471b2ddba68a05d6dfccff3 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 19 Jun 2020 10:07:59 +0100 Subject: [PATCH 22/42] Raise version --- TFT_eSPI.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 416ad7e..3d4d233 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.12" +#define TFT_ESPI_VERSION "2.2.13" /*************************************************************************************** ** Section 1: Load required header files From 8fc52dc1f51cc69b26692afb8baa7311ed451cd9 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 27 Jun 2020 21:37:03 +0100 Subject: [PATCH 23/42] Update ReadMe Update news, move tips towards end. --- README.md | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 48ffa66..50cf1a6 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,22 @@ -# Tips -If you load a new copy of TFT_eSPI then it will over-write 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 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 over-written during an upgrade). # News -1. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488). +1. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI. -2. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h". +2. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488). -3. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program. +3. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h". + +4. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program. ![Animated_dial](https://i.imgur.com/S736Rg6.png) -4. Anti-aliased (smooth) fonts can now be stored as arrays in FLASH (program) memory. This means that processors such as STM32 that do not have SPIFFS support can use the fonts. The processor must have sufficient FLASH memory to store the fonts used. +5. Anti-aliased (smooth) fonts can now be stored as arrays in FLASH (program) memory. This means that processors such as STM32 that do not have SPIFFS support can use the fonts. The processor must have sufficient FLASH memory to store the fonts used. -5. The Sprite class now supports 4 bits per pixel with a 16 color palette. Three new examples have been added. +6. The Sprite class now supports 4 bits per pixel with a 16 color palette. Three new examples have been added. -6. The library has been upgraded to support STM32 processors when used with SPI or 8 bit parallel displays. DMA capability for SPI displays has been added for STM32F103 (e.g. "Blue Pill") and STM32F2xx/4xx/7xx (e.g. 32/64/144 Nucleo boards). New DMA demo examples have been added (for STM32 only). - -7. The ST7796 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28. - -8. A callback function has been added, this allows antialiased fonts to be rendered over colour gradients or images. Two new examples have been added to illustrate this new capability: - - "Smooth_font_reading_TFT" - - "Smooth_font_gradient" - - ![AA_gradien](https://i.imgur.com/YMBcPHp.png) +7. The library has been upgraded to support STM32 processors when used with SPI or 8 bit parallel displays. DMA capability for SPI displays has been added for STM32F103 (e.g. "Blue Pill") and STM32F2xx/4xx/7xx (e.g. 32/64/144 Nucleo boards). New DMA demo examples have been added (for STM32 only). +8. The ST7796 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28. # TFT_eSPI @@ -126,6 +107,19 @@ IO32 wired to IO36 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 over-write 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 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 over-written during an upgrade). + # ePaper displays The library was intended to support only TFT displays but using a Sprite as a 1 bit per pixel screen buffer permits support for the Waveshare 2 and 3 colour SPI ePaper displays. This addition to the library is experimental and only one example is provided. Further examples will be added. From a6d50ea5ef6df5b13ea4b172ec6684abf98d490e Mon Sep 17 00:00:00 2001 From: Bodmer Date: Tue, 7 Jul 2020 00:52:55 +0100 Subject: [PATCH 24/42] #682 Add created() function for sprites New function added: bool created(void); to check if sprite has been rotated. Example: if ( !spr.created() ) Serial.println("Sprite has not been created"); --- Extensions/Sprite.cpp | 10 ++++++++++ Extensions/Sprite.h | 3 +++ TFT_eSPI.h | 2 +- examples/320 x 240/TFT_Matrix/TFT_Matrix.ino | 2 +- .../DMA test/SpriteRotatingCube/SpriteRotatingCube.ino | 2 +- .../FLASH_Array/Unicode_test/Unicode_test.ino | 1 - library.json | 2 +- library.properties | 2 +- 8 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 6ec481c..f63d3fa 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -112,6 +112,16 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) } +/*************************************************************************************** +** Function name: created +** Description: Returns true is sprite has been created +*************************************************************************************x*/ +bool TFT_eSprite::created(void) +{ + return _created; +} + + /*************************************************************************************** ** Function name: ~TFT_eSprite ** Description: Class destructor diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 26a0457..ab4f1c1 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -22,6 +22,9 @@ class TFT_eSprite : public TFT_eSPI { void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); + // Returns true if sprite has been created + bool created(void); + // Delete the sprite to free up the RAM void deleteSprite(void); diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 3d4d233..b1cc8dc 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.13" +#define TFT_ESPI_VERSION "2.2.14" /*************************************************************************************** ** Section 1: Load required header files diff --git a/examples/320 x 240/TFT_Matrix/TFT_Matrix.ino b/examples/320 x 240/TFT_Matrix/TFT_Matrix.ino index 2e2e449..838ce79 100644 --- a/examples/320 x 240/TFT_Matrix/TFT_Matrix.ino +++ b/examples/320 x 240/TFT_Matrix/TFT_Matrix.ino @@ -32,7 +32,7 @@ void setup() { Serial.begin(115200); randomSeed(analogRead(A0)); tft.init(); - tft.setRotation(2); + tft.setRotation(0); tft.fillScreen(ILI9341_BLACK); setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA); } diff --git a/examples/DMA test/SpriteRotatingCube/SpriteRotatingCube.ino b/examples/DMA test/SpriteRotatingCube/SpriteRotatingCube.ino index 07f4831..30f46b3 100644 --- a/examples/DMA test/SpriteRotatingCube/SpriteRotatingCube.ino +++ b/examples/DMA test/SpriteRotatingCube/SpriteRotatingCube.ino @@ -6,7 +6,7 @@ // parallel TFT's (tested with ILI9341 and ILI9481) // The sketch will run on processors without DMA and also parallel -// interface TFT's. Comment out line 25 for no DMA. +// interface TFT's. Comment out line 29 for no DMA. // Library here: // https://github.com/Bodmer/TFT_eSPI diff --git a/examples/Smooth Fonts/FLASH_Array/Unicode_test/Unicode_test.ino b/examples/Smooth Fonts/FLASH_Array/Unicode_test/Unicode_test.ino index 899ab74..a8f6bea 100644 --- a/examples/Smooth Fonts/FLASH_Array/Unicode_test/Unicode_test.ino +++ b/examples/Smooth Fonts/FLASH_Array/Unicode_test/Unicode_test.ino @@ -31,7 +31,6 @@ //==================================================================================== // Libraries //==================================================================================== -// Call up the SPIFFS FLASH filing system this is part of the ESP Core #include // Hardware-specific library diff --git a/library.json b/library.json index 1e47018..2e2f798 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.13", + "version": "2.2.14", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index d51d0a5..1470ff7 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.13 +version=2.2.14 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 90cabab91ad3ef239ef1c95d97db9ab666153292 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Thu, 9 Jul 2020 14:20:34 +0100 Subject: [PATCH 25/42] Update to aid use of ESP32 with multiple displays #687 Fix issue when using ESP32 & using multiple TFT displays & not defining TFT_CS. Note: Future support for multiple displays in all possible hardware combinations may not be practical. --- Processors/TFT_eSPI_ESP32.h | 5 +++-- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index fd56dce..3909b5f 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -115,8 +115,9 @@ // 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 + #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 diff --git a/TFT_eSPI.h b/TFT_eSPI.h index b1cc8dc..4bfa552 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.14" +#define TFT_ESPI_VERSION "2.2.15" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index 2e2f798..3709c76 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.14", + "version": "2.2.15", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 1470ff7..41f6a4f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.14 +version=2.2.15 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From c124688ab102828024d00c32518b969ea7788a42 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sun, 19 Jul 2020 10:45:36 +0100 Subject: [PATCH 26/42] Fix #697 Untested but looks correct! --- Extensions/Sprite.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index f63d3fa..dcb1027 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -1746,9 +1746,9 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t { yp = (yp + 1) >> 1; while (h--) { - drawPixel(x, y+h-1, color & 0x0F); + drawPixel(x, y+h, color & 0x0F); if (w > 1) - memset(_img4 + (yp + ((x-1)>>1)), c2, (w-1)>>1); + memset(_img4 + yp, c2, (w-1)>>1); // same as above but you have a hangover on the left instead yp += (_iwidth >> 1); } @@ -1757,10 +1757,10 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t { yp = (yp + 1) >> 1; while (h--) { - drawPixel(x, y+h-1, color & 0x0F); - drawPixel(x+w-1, y+h-1, color & 0x0F); + drawPixel(x, y+h, color & 0x0F); + if (w > 1) drawPixel(x+w-1, y+h, color & 0x0F); if (w > 2) - memset(_img4 + (yp + ((x-1)>>1)), c2, (w-2)>>1); + memset(_img4 + yp, c2, (w-2)>>1); // maximal hacking, single pixels on left and right. yp += (_iwidth >> 1); } From dc114db01b1d2b89360ab824246da1180b847f2a Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 20:06:44 +0100 Subject: [PATCH 27/42] Srite class updates + others Add 2 new pushSprite functions: 1. Sprite to sprite 2. windowed are of sprite to screen Examples to follow Bug fixes to sprite class --- Extensions/Sprite.cpp | 435 +++++++++++++++++++++++++--------- Extensions/Sprite.h | 13 +- Processors/TFT_eSPI_ESP32.c | 2 +- Processors/TFT_eSPI_ESP32.h | 77 ++++-- Processors/TFT_eSPI_ESP8266.c | 2 +- Processors/TFT_eSPI_ESP8266.h | 2 +- Processors/TFT_eSPI_Generic.h | 7 + Processors/TFT_eSPI_STM32.c | 8 +- Processors/TFT_eSPI_STM32.h | 21 +- TFT_eSPI.cpp | 7 +- TFT_eSPI.h | 2 +- User_Setup_Select.h | 6 +- keywords.txt | 151 +++++++----- library.json | 2 +- library.properties | 2 +- 15 files changed, 507 insertions(+), 230 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index dcb1027..26f2296 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -13,7 +13,7 @@ /*************************************************************************************** ** Function name: TFT_eSprite ** Description: Class constructor -*************************************************************************************x*/ +***************************************************************************************/ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) { _tft = tft; // Pointer to tft class so we can call member functions @@ -47,14 +47,14 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) /*************************************************************************************** ** Function name: createSprite ** Description: Create a sprite (bitmap) of defined width and height -*************************************************************************************x*/ +***************************************************************************************/ // 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 NULL; + if ( w < 1 || h < 1 ) return nullptr; _iwidth = _dwidth = _bitwidth = w; _iheight = _dheight = h; @@ -105,17 +105,28 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) if (_img8) { _created = true; - return _img8; + return _img8_1; } - return NULL; + 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 is sprite has been created -*************************************************************************************x*/ +***************************************************************************************/ bool TFT_eSprite::created(void) { return _created; @@ -125,7 +136,7 @@ bool TFT_eSprite::created(void) /*************************************************************************************** ** Function name: ~TFT_eSprite ** Description: Class destructor -*************************************************************************************x*/ +***************************************************************************************/ TFT_eSprite::~TFT_eSprite(void) { deleteSprite(); @@ -139,14 +150,14 @@ TFT_eSprite::~TFT_eSprite(void) /*************************************************************************************** ** Function name: callocSprite ** Description: Allocate a memory area for the Sprite and return pointer -*************************************************************************************x*/ +***************************************************************************************/ 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 = NULL; + uint8_t* ptr8 = nullptr; if (frames > 2) frames = 2; // Currently restricted to 2 frame buffers if (frames < 1) frames = 1; @@ -154,10 +165,17 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames) if (_bpp == 16) { #if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT) - if ( psramFound() && this->_psram_enable && !_tft->DMA_Enabled) ptr8 = ( uint8_t*) ps_calloc(frames * w * h + frames, sizeof(uint16_t)); + if ( psramFound() && this->_psram_enable && !_tft->DMA_Enabled) + { + ptr8 = ( uint8_t*) ps_calloc(frames * w * h + frames, sizeof(uint16_t)); + //Serial.println("PSRAM"); + } else #endif - ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t)); + { + ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t)); + //Serial.println("Normal RAM"); + } } else if (_bpp == 8) @@ -203,7 +221,7 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames) /*************************************************************************************** ** Function name: createPalette (from RAM array) ** Description: Set a palette for a 4-bit per pixel sprite -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) { @@ -223,7 +241,7 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) _colorMap = (uint16_t *)calloc(16, sizeof(uint16_t)); if (colors > 16) colors = 16; - + // Copy map colors for (uint8_t i = 0; i < colors; i++) { @@ -234,15 +252,10 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors) /*************************************************************************************** ** Function name: createPalette (from FLASH array) ** Description: Set a palette for a 4-bit per pixel sprite -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) { - if (_colorMap != nullptr) - { - free(_colorMap); - } - if (colorMap == nullptr) { // Create a color map using the default FLASH map @@ -264,11 +277,11 @@ void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) /*************************************************************************************** ** Function name: frameBuffer ** Description: For 1 bpp Sprites, select the frame used for graphics -*************************************************************************************x*/ +***************************************************************************************/ // Frames are numbered 1 and 2 void* TFT_eSprite::frameBuffer(int8_t f) { - if (!_created) return NULL; + if (!_created) return nullptr; if ( f == 2 ) _img8 = _img8_2; else _img8 = _img8_1; @@ -285,34 +298,37 @@ void* TFT_eSprite::frameBuffer(int8_t f) /*************************************************************************************** ** Function name: setColorDepth ** Description: Set bits per pixel for colour (1, 8 or 16) -*************************************************************************************x*/ +***************************************************************************************/ void* TFT_eSprite::setColorDepth(int8_t b) { - // Can't change an existing sprite's colour depth so delete it - if (_created) free(_img8_1); + // Do not re-create the sprite if the colour depth does not change + if (_bpp == b) return _img8_1; - // Now define the new colour depth + // 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 it + if (_created) free(_img8_1); + // If it existed, re-create the sprite with the new colour depth if (_created) { _created = false; - return createSprite(_iwidth, _iheight); + return createSprite(_dwidth, _dheight); } - return NULL; + return nullptr; } /*************************************************************************************** ** Function name: getColorDepth ** Description: Get bits per pixel for colour (1, 8 or 16) -*************************************************************************************x*/ +***************************************************************************************/ int8_t TFT_eSprite::getColorDepth(void) { @@ -357,7 +373,7 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index) /*************************************************************************************** ** Function name: deleteSprite ** Description: Delete the sprite to free up memory (RAM) -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::deleteSprite(void) { if (!_created ) return; @@ -369,6 +385,8 @@ void TFT_eSprite::deleteSprite(void) free(_img8_1); + _img8 = nullptr; + _created = false; } @@ -376,7 +394,7 @@ void TFT_eSprite::deleteSprite(void) /*************************************************************************************** ** Function name: setPivot ** Description: Set the pivot point in this Sprite -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::setPivot(int16_t x, int16_t y) { _xpivot = x; @@ -407,7 +425,7 @@ int16_t TFT_eSprite::getPivotY(void) /*************************************************************************************** ** Function name: pushRotated - Fast fixed point integer maths version ** Description: Push rotated Sprite to TFT screen -*************************************************************************************x*/ +***************************************************************************************/ #define FP_SCALE 10 bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) { @@ -426,11 +444,11 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) int32_t xt = min_x - _tft->_xpivot; int32_t yt = min_y - _tft->_ypivot; - uint32_t xe = _iwidth << FP_SCALE; - uint32_t ye = _iheight << FP_SCALE; + uint32_t xe = _dwidth << FP_SCALE; + uint32_t ye = _dheight << FP_SCALE; uint32_t tpcolor = transp; // convert to unsigned 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 @@ -447,8 +465,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) uint32_t rp; int32_t xp = xs >> FP_SCALE; int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; } - else rp = readPixel(xp, yp); + if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; } + else { rp = readPixel(xp, yp); rp = rp>>8 | rp<<8; } if (tpcolor == rp) { if (pixel_count) { // TFT window is already clipped, so this is faster than pushImage() @@ -458,7 +476,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) } } else { - sline_buffer[pixel_count++] = rp>>8 | rp<<8; + sline_buffer[pixel_count++] = rp; } } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); if (pixel_count) { @@ -477,7 +495,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) /*************************************************************************************** ** Function name: pushRotated - Fast fixed point integer maths version ** Description: Push a rotated copy of the Sprite to another Sprite -*************************************************************************************x*/ +***************************************************************************************/ // Not compatible with 4bpp bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) { @@ -497,9 +515,9 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) int32_t xt = min_x - spr->_xpivot; int32_t yt = min_y - spr->_ypivot; - uint32_t xe = _iwidth << FP_SCALE; - uint32_t ye = _iheight << FP_SCALE; - uint32_t tpcolor = transp; // convert to unsigned + uint32_t xe = _dwidth << FP_SCALE; + uint32_t ye = _dheight << FP_SCALE; + uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes bool oldSwapBytes = spr->getSwapBytes(); spr->setSwapBytes(false); @@ -518,8 +536,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) uint32_t rp; int32_t xp = xs >> FP_SCALE; int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; } - else rp = readPixel(xp, yp); + if (_bpp == 16) rp = _img[xp + yp * _iwidth]; + else { rp = readPixel(xp, yp); rp = rp>>8 | rp<<8; } if (tpcolor == rp) { if (pixel_count) { spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); @@ -540,7 +558,7 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) /*************************************************************************************** ** Function name: getRotatedBounds ** Description: Get TFT bounding box of a rotated Sprite wrt pivot -*************************************************************************************x*/ +***************************************************************************************/ bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y) { @@ -572,7 +590,7 @@ bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y /*************************************************************************************** ** Function name: getRotatedBounds ** Description: Get destination Sprite bounding box of a rotated Sprite wrt pivot -*************************************************************************************x*/ +***************************************************************************************/ 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) { @@ -608,7 +626,7 @@ bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min /*************************************************************************************** ** Function name: rotatedBounds ** Description: Get bounding box of a rotated Sprite wrt pivot -*************************************************************************************x*/ +***************************************************************************************/ 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) { @@ -662,7 +680,7 @@ void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t /*************************************************************************************** ** Function name: pushSprite ** Description: Push the sprite to the TFT at x, y -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::pushSprite(int32_t x, int32_t y) { if (!_created) return; @@ -671,7 +689,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y) { bool oldSwapBytes = _tft->getSwapBytes(); _tft->setSwapBytes(false); - _tft->pushImage(x, y, _iwidth, _iheight, _img ); + _tft->pushImage(x, y, _dwidth, _dheight, _img ); _tft->setSwapBytes(oldSwapBytes); } else if (_bpp == 4) @@ -685,7 +703,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y) /*************************************************************************************** ** Function name: pushSprite ** Description: Push the sprite to the TFT at x, y with transparent colour -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) { if (!_created) return; @@ -694,7 +712,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) { bool oldSwapBytes = _tft->getSwapBytes(); _tft->setSwapBytes(false); - _tft->pushImage(x, y, _iwidth, _iheight, _img, transp ); + _tft->pushImage(x, y, _dwidth, _dheight, _img, transp ); _tft->setSwapBytes(oldSwapBytes); } else if (_bpp == 8) @@ -710,10 +728,171 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) } +/*************************************************************************************** +** Function name: pushSprite +** 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 +// 4bpp -> 4bpp (note: color translation depends on the 2 sprites pallet colors) +// 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) + +bool TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y) +{ + if (!_created) return false; + if (!spr->created()) return false; + + // Check destination sprite compatibility + int8_t ds_bpp = spr->getColorDepth(); + if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; + if (_bpp == 8) return false; + if (_bpp == 4 && ds_bpp != 4) return false; + if (_bpp == 1 && ds_bpp != 1) return false; + + bool oldSwapBytes = spr->getSwapBytes(); + spr->setSwapBytes(false); + spr->pushImage(x, y, _dwidth, _dheight, _img ); + spr->setSwapBytes(oldSwapBytes); + + return true; +} + + +/*************************************************************************************** +** Function name: pushSprite +** Description: Push the sprite to another sprite at x, y with transparent colour +***************************************************************************************/ +/* >>>>>> Using a transparent color is not supported at the moment <<<<<< +void TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y, uint16_t transp) +{ + if (!_created) return; + + if (_bpp == 16) + { + bool oldSwapBytes = spr->getSwapBytes(); + spr->setSwapBytes(false); + spr->pushImage(x, y, _dwidth, _dheight, _img, transp ); + spr->setSwapBytes(oldSwapBytes); + } + else if (_bpp == 8) + { + transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3); + spr->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true); + } + else if (_bpp == 4) + { + spr->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap); + } + else spr->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false); +} +*/ + +/*************************************************************************************** +** 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, true ); + else // Render line by line + while (sh--) + _tft->pushImage(tx, ty++, sw, 1, _img8 + _xs + _iwidth * _ys++, 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 + { + uint32_t ds = _xs&1; // Odd x start pixel + + uint32_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 + (_iwidth>>3) * _ys, false ); + else // Render line by line + { + _tft->startWrite(); + _tft->setWindow(tx, ty, tx+sw-1, ty+sh-1); + while (sh--) + { + for (uint32_t dx = _xs; dx < _xs + sw; dx++) _tft->pushColor(readPixel(dx, _ys)); + ty++; + _ys++; + } + _tft->endWrite(); + } + } + + return true; +} + + /*************************************************************************************** ** Function name: readPixelValue ** Description: Read the color map index of a pixel at defined coordinates -*************************************************************************************x*/ +***************************************************************************************/ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) { if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFF; @@ -732,6 +911,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) 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 @@ -740,6 +920,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) if (_bpp == 1) { + // Note: _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) if (_rotation == 1) { uint16_t tx = x; @@ -767,7 +948,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y) /*************************************************************************************** ** Function name: readPixel ** Description: Read 565 colour of a pixel at defined coordinates -*************************************************************************************x*/ +***************************************************************************************/ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) { if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFFFF; @@ -777,7 +958,7 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) uint16_t color = _img[x + y * _iwidth]; return (color >> 8) | (color << 8); } - + if (_bpp == 8) { uint16_t color = _img8[x + y * _iwidth]; @@ -793,6 +974,7 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) 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 @@ -801,6 +983,8 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) 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; @@ -828,18 +1012,19 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) /*************************************************************************************** ** Function name: pushImage -** Description: push 565 colour image into a defined area of a sprite -*************************************************************************************x*/ +** 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) { - if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0) || !_created) return; + if (data == nullptr || !_created) return; + if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0)) return; if ((x + w < 0) || (y + h < 0)) return; - int32_t xo = 0; - int32_t yo = 0; + int32_t xo = 0; + int32_t yo = 0; - int32_t xs = x; - int32_t ys = y; + int32_t xs = x; + int32_t ys = y; int32_t ws = w; int32_t hs = h; @@ -852,17 +1037,34 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite { - for (int32_t yp = yo; yp < yo + hs; yp++) + // Pointer within original image + uint8_t *ptro = (uint8_t *)data + ((xo + yo * w) << 1); + // Pointer within sprite image + uint8_t *ptrs = (uint8_t *)_img + ((xs + ys * _iwidth) << 1); + + if(_iswapBytes) { - x = xs; - for (int32_t xp = xo; xp < xo + ws; xp++) + while (hs--) { - uint16_t color = data[xp + yp * w]; - if(_iswapBytes) color = color<<8 | color>>8; - _img[x + ys * _iwidth] = color; - x++; + // Fast copy with a 1 byte shift + memcpy(ptrs+1, ptro, (ws<<1) - 1); + // Now correct just the even numbered bytes + for (int32_t xp = 0; xp < (ws<<1); xp+=2) + { + ptrs[xp] = ptro[xp+1];; + } + ptro += w<<1; + ptrs += _iwidth<<1; + } + } + else + { + while (hs--) + { + memcpy(ptrs, ptro, ws<<1); + ptro += w << 1; + ptrs += _iwidth << 1; } - ys++; } } else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite @@ -873,8 +1075,9 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ for (int32_t xp = xo; xp < xo + ws; xp++) { uint16_t color = data[xp + yp * w]; - if(_iswapBytes) color = color<<8 | color>>8; - _img8[x + ys * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + // When data source is a sprite, the bytes are already swapped + if(!_iswapBytes) _img8[x + ys * _iwidth] = (uint8_t)((color & 0xE0) | (color & 0x07)<<2 | (color & 0x1800)>>11); + else _img8[x + ys * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); x++; } ys++; @@ -882,13 +1085,13 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ } else if (_bpp == 4) { - // the image is assumed to be 4 bit, where each byte corresponds to two pixels. + // 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. const uint8_t *dataBuf = (uint8_t *)data; int sWidth = (_iwidth >> 1); - + if ((xs & 0x01) == 0 && (xo & 0x01) == 0 && (ws & 0x01) == 0) { if ((ws & 0x01) == 0) // use memcpy for better perf. @@ -906,6 +1109,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ } else // not optimized { + // _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) for (int32_t yp = yo; yp < yo + hs; yp++) { x = xs; @@ -917,7 +1121,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ else color = dataBuf[((xp-1+yp*w)>>1)] & 0x0F; // odd index = bits 3 .. 0. drawPixel(x, ys, color); - x++; + x++; } ys++; } @@ -964,7 +1168,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ /*************************************************************************************** ** Function name: pushImage ** Description: push 565 colour FLASH (PROGMEM) image into a defined area -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { #ifdef ESP32 @@ -1031,6 +1235,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u else // 1bpp { + // _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used) // Move coordinate rotation to support fn if (_rotation == 1) { @@ -1090,26 +1295,26 @@ bool TFT_eSprite::getSwapBytes(void) /*************************************************************************************** ** Function name: setWindow -** Description: Set the bounds of a window for pushColor and writeColor -*************************************************************************************x*/ +** Description: Set the bounds of a window in the sprite +***************************************************************************************/ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { if (x0 > x1) swap_coord(x0, x1); if (y0 > y1) swap_coord(y0, y1); - if ((x0 >= _iwidth) || (x1 < 0) || (y0 >= _iheight) || (y1 < 0)) + if ((x0 >= _dwidth) || (x1 < 0) || (y0 >= _dheight) || (y1 < 0)) { // Point to that extra "off screen" pixel _xs = 0; - _ys = _iheight; + _ys = _dheight; _xe = 0; - _ye = _iheight; + _ye = _dheight; } else { if (x0 < 0) x0 = 0; - if (x1 >= _iwidth) x1 = _iwidth - 1; + if (x1 >= _dwidth) x1 = _dwidth - 1; if (y0 < 0) y0 = 0; - if (y1 >= _iheight) y1 = _iheight - 1; + if (y1 >= _dheight) y1 = _dheight - 1; _xs = x0; _ys = y0; @@ -1125,7 +1330,7 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) /*************************************************************************************** ** Function name: pushColor ** Description: Send a new pixel to the set window -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::pushColor(uint32_t color) { if (!_created ) return; @@ -1147,7 +1352,7 @@ void TFT_eSprite::pushColor(uint32_t color) _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 @@ -1167,7 +1372,7 @@ void TFT_eSprite::pushColor(uint32_t color) /*************************************************************************************** ** Function name: pushColor ** Description: Send a "len" new pixels to the set window -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::pushColor(uint32_t color, uint16_t len) { if (!_created ) return; @@ -1189,7 +1394,7 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len) /*************************************************************************************** ** Function name: writeColor ** Description: Write a pixel with pre-formatted colour to the set window -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::writeColor(uint16_t color) { if (!_created ) return; @@ -1227,7 +1432,7 @@ void TFT_eSprite::writeColor(uint16_t color) /*************************************************************************************** ** Function name: setScrollRect ** Description: Set scroll area within the sprite and the gap fill colour -*************************************************************************************x*/ +***************************************************************************************/ 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; @@ -1238,7 +1443,7 @@ void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint if ((x + w) > _iwidth ) w = _iwidth - x; if ((y + h) > _iheight) h = _iheight - y; - if ( w < 1 || h < 1) return; + if ( w < 1 || h < 1) return; _sx = x; _sy = y; @@ -1252,7 +1457,7 @@ void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint /*************************************************************************************** ** Function name: scroll ** Description: Scroll dx,dy pixels, positive right,down, negative left,up -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::scroll(int16_t dx, int16_t dy) { if (abs(dx) >= _sw || abs(dy) >= _sh) @@ -1264,7 +1469,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy) // 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; // width of sprite + int32_t iw = _iwidth; // rounded up width of sprite // Fetch the x,y origin set by setScrollRect() uint32_t tx = _sx; // to x @@ -1350,7 +1555,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy) /*************************************************************************************** ** Function name: fillSprite ** Description: Fill the whole sprite with defined colour -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::fillSprite(uint32_t color) { if (!_created ) return; @@ -1381,7 +1586,7 @@ void TFT_eSprite::fillSprite(uint32_t color) /*************************************************************************************** ** Function name: setCursor ** Description: Set the sprite text cursor x,y position -*************************************************************************************x*/ +***************************************************************************************/ // Not needed - using TFT_eSPI class function and this->cursor_x/y //void TFT_eSprite::setCursor(int16_t x, int16_t y) //{ @@ -1393,13 +1598,13 @@ void TFT_eSprite::fillSprite(uint32_t color) /*************************************************************************************** ** Function name: width ** Description: Return the width of sprite -*************************************************************************************x*/ +***************************************************************************************/ // Return the size of the display int16_t TFT_eSprite::width(void) { if (!_created ) return 0; - if (_bpp > 1) return _iwidth; + if (_bpp > 1) return _dwidth; if (_rotation == 1 || _rotation == 3) return _dheight; @@ -1410,12 +1615,12 @@ int16_t TFT_eSprite::width(void) /*************************************************************************************** ** Function name: height ** Description: Return the height of sprite -*************************************************************************************x*/ +***************************************************************************************/ int16_t TFT_eSprite::height(void) { if (!_created ) return 0; - if (_bpp > 1) return _iheight; + if (_bpp > 4) return _dheight; if (_rotation == 1 || _rotation == 3) return _dwidth; @@ -1426,7 +1631,7 @@ int16_t TFT_eSprite::height(void) /*************************************************************************************** ** Function name: setRotation ** Description: Rotate coordinate frame for 1bpp sprite -*************************************************************************************x*/ +***************************************************************************************/ // Does nothing for 8 and 16 bpp sprites. TODO allow rotation of these sprites void TFT_eSprite::setRotation(uint8_t rotation) { @@ -1443,7 +1648,7 @@ void TFT_eSprite::setRotation(uint8_t rotation) /*************************************************************************************** ** Function name: getRotation ** Description: Get rotation for 1bpp sprite -*************************************************************************************x*/ +***************************************************************************************/ uint8_t TFT_eSprite::getRotation(void) { @@ -1454,7 +1659,7 @@ uint8_t TFT_eSprite::getRotation(void) /*************************************************************************************** ** Function name: drawPixel ** Description: push a single pixel at an arbitrary position -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) { // Range checking @@ -1510,7 +1715,7 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) /*************************************************************************************** ** Function name: drawLine ** Description: draw a line between 2 arbitrary points -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) { if (!_created ) return; @@ -1566,7 +1771,7 @@ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint3 /*************************************************************************************** ** Function name: drawFastVLine ** Description: draw a vertical line -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { @@ -1621,7 +1826,7 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) /*************************************************************************************** ** Function name: drawFastHLine ** Description: draw a horizontal line -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) { @@ -1677,13 +1882,13 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) /*************************************************************************************** ** Function name: fillRect ** Description: draw a filled rectangle -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { if (!_created ) return; if ((x >= _iwidth) || (y >= _iheight)) return; - + if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } @@ -1782,7 +1987,7 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t /*************************************************************************************** ** Function name: write ** Description: draw characters piped through serial stream -*************************************************************************************x*/ +***************************************************************************************/ size_t TFT_eSprite::write(uint8_t utf8) { uint16_t uniCode = decodeUTF8(utf8); @@ -1864,7 +2069,7 @@ size_t TFT_eSprite::write(uint8_t utf8) height = height * textsize; - if (utf8 == '\n') + if (utf8 == '\n') { this->cursor_y += height; this->cursor_x = 0; @@ -1919,7 +2124,7 @@ size_t TFT_eSprite::write(uint8_t utf8) /*************************************************************************************** ** Function name: drawChar ** Description: draw a single character in the Adafruit GLCD or freefont -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) { if (!_created ) return; @@ -2061,7 +2266,7 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uin /*************************************************************************************** ** Function name: drawChar ** Description: draw a unicode onto the screen -*************************************************************************************x*/ +***************************************************************************************/ // Any UTF-8 decoding must be done before calling drawChar() int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y) { @@ -2258,7 +2463,7 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo /*************************************************************************************** ** Function name: drawGlyph ** Description: Write a character to the sprite cursor position -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::drawGlyph(uint16_t code) { if (code < 0x21) @@ -2289,15 +2494,15 @@ void TFT_eSprite::drawGlyph(uint16_t code) uint16_t gNum = 0; bool found = this->getUnicodeIndex(code, &gNum); - + uint16_t fg = this->textcolor; uint16_t bg = this->textbgcolor; if (found) { - + bool newSprite = !_created; - + if (newSprite) { createSprite(this->gWidth[gNum], this->gFont.yAdvance); @@ -2393,7 +2598,7 @@ void TFT_eSprite::drawGlyph(uint16_t code) /*************************************************************************************** ** Function name: printToSprite ** Description: Write a string to the sprite cursor position -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::printToSprite(String string) { if(!this->fontLoaded) return; @@ -2408,14 +2613,14 @@ void TFT_eSprite::printToSprite(String string) /*************************************************************************************** ** Function name: printToSprite ** Description: Write a string to the sprite cursor position -*************************************************************************************x*/ +***************************************************************************************/ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) { if(!this->fontLoaded) return; uint16_t n = 0; bool newSprite = !_created; - + if (newSprite) { int16_t sWidth = 1; @@ -2459,7 +2664,7 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) /*************************************************************************************** ** Function name: printToSprite ** Description: Print character in a Sprite, create sprite if needed -*************************************************************************************x*/ +***************************************************************************************/ int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) { bool newSprite = !_created; diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index ab4f1c1..723b557 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -10,6 +10,7 @@ class TFT_eSprite : public TFT_eSPI { public: 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 @@ -18,9 +19,10 @@ class TFT_eSprite : public TFT_eSPI { // - 1 nibble per pixel for 4 bit colour // - 1 byte per pixel for 8 bit colour // - 2 bytes per pixel for 16 bit color depth - ~TFT_eSprite(void); + void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); - 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); @@ -131,6 +133,13 @@ class TFT_eSprite : public TFT_eSPI { void pushSprite(int32_t x, int32_t y); void pushSprite(int32_t x, int32_t y, uint16_t transparent); + // Push the sprite to another sprite, this fn calls pushImage() in the destination sprite class. + // >>>>>> Using a transparent color is not supported at the moment <<<<<< + bool pushSprite(TFT_eSprite *spr, int32_t x, int32_t y); + + // 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); + 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); diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 30d3d51..d83424c 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -489,7 +489,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ //////////////////////////////////////////////////////////////////////////////////////// -#if defined ESP32_DMA && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS +#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////// /*************************************************************************************** diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index 3909b5f..d373bf2 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -77,10 +77,16 @@ #define DC_D // No macro allocated so it generates no code #else #if defined (TFT_PARALLEL_8_BIT) - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts = (1 << TFT_DC) + // 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) + #else + #define DC_C + #define DC_D + #endif #else - #if TFT_DC >= 32 + #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)) @@ -90,16 +96,20 @@ #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) #endif - #elif TFT_DC >= 0 - #ifdef RPI_DISPLAY_TYPE // RPi ILI9486 display needs a slower DC change - #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) - #elif defined (RPI_DISPLAY_TYPE) // 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) + #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) @@ -131,8 +141,8 @@ #define CS_H #endif #else - #if TFT_CS >= 32 - #ifdef RPI_DISPLAY_TYPE // RPi ILI9486 display needs a slower CS change + #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)); \ @@ -141,12 +151,12 @@ #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 ILI9486 display needs a slower CS change + #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_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 @@ -159,9 +169,18 @@ //////////////////////////////////////////////////////////////////////////////////////// // Define the WR (TFT Write) pin drive code //////////////////////////////////////////////////////////////////////////////////////// -#ifdef TFT_WR - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) +#if defined (TFT_WR) + #if (TFT_WR >= 0) + // TFT_WR, by design, must 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 //////////////////////////////////////////////////////////////////////////////////////// @@ -302,10 +321,18 @@ // Read pin #ifdef TFT_RD - #define RD_L GPIO.out_w1tc = (1 << TFT_RD) - //#define RD_L digitalWrite(TFT_WR, LOW) - #define RD_H GPIO.out_w1ts = (1 << TFT_RD) - //#define RD_H digitalWrite(TFT_WR, HIGH) + #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 #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP8266.c b/Processors/TFT_eSPI_ESP8266.c index 7a7287c..31e87e7 100644 --- a/Processors/TFT_eSPI_ESP8266.c +++ b/Processors/TFT_eSPI_ESP8266.c @@ -304,7 +304,7 @@ return; SPI1U1 = (511 << SPILMOSI); while(len>31) { -#if defined SPI_FREQUENCY && (SPI_FREQUENCY == 80000000) +#if (defined (SPI_FREQUENCY) && (SPI_FREQUENCY == 80000000)) if(SPI1CMD & SPIBUSY) // added to sync with flag change #endif while(SPI1CMD & SPIBUSY) {} diff --git a/Processors/TFT_eSPI_ESP8266.h b/Processors/TFT_eSPI_ESP8266.h index f3065f1..3b475cf 100644 --- a/Processors/TFT_eSPI_ESP8266.h +++ b/Processors/TFT_eSPI_ESP8266.h @@ -19,7 +19,7 @@ #define DMA_BUSY_CHECK // DMA not available, leave blank // Initialise processor specific SPI functions, used by init() -#if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266) +#if (!defined (SUPPORT_TRANSACTIONS) && defined (ESP8266)) #define INIT_TFT_DATA_BUS \ spi.setBitOrder(MSBFIRST); \ spi.setDataMode(TFT_SPI_MODE); \ diff --git a/Processors/TFT_eSPI_Generic.h b/Processors/TFT_eSPI_Generic.h index ecf69de..1b44d02 100644 --- a/Processors/TFT_eSPI_Generic.h +++ b/Processors/TFT_eSPI_Generic.h @@ -58,6 +58,13 @@ #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 //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index 162e732..1982b84 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -131,7 +131,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ ***************************************************************************************/ void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) { -#ifdef STM_PORTA_DATA_BUS +#if defined (STM_PORTA_DATA_BUS) #if defined (STM32F1xx) if (mode == OUTPUT) GPIOA->CRL = 0x33333333; else GPIOA->CRL = 0x88888888; @@ -139,7 +139,7 @@ void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) if (mode == OUTPUT) GPIOA->MODER = (GPIOA->MODER & 0xFFFF0000) | 0x00005555; else GPIOA->MODER &= 0xFFFF0000; #endif -#elif STM_PORTB_DATA_BUS +#elif defined (STM_PORTB_DATA_BUS) #if defined (STM32F1xx) if (mode == OUTPUT) GPIOB->CRL = 0x33333333; else GPIOB->CRL = 0x88888888; @@ -194,12 +194,12 @@ uint8_t TFT_eSPI::readByte(void) uint8_t b = 0; RD_L; -#ifdef STM_PORTA_DATA_BUS +#if defined (STM_PORTA_DATA_BUS) b = GPIOA->IDR; b = GPIOA->IDR; b = GPIOA->IDR; b = (GPIOA->IDR) & 0xFF; -#elif STM_PORTB_DATA_BUS +#elif defined (STM_PORTB_DATA_BUS) b = GPIOB->IDR; b = GPIOB->IDR; b = GPIOB->IDR; diff --git a/Processors/TFT_eSPI_STM32.h b/Processors/TFT_eSPI_STM32.h index 6fcab87..6b627d8 100644 --- a/Processors/TFT_eSPI_STM32.h +++ b/Processors/TFT_eSPI_STM32.h @@ -243,12 +243,21 @@ // Define the RD (TFT Read) pin drive code //////////////////////////////////////////////////////////////////////////////////////// #ifdef TFT_RD - // Convert Arduino pin reference Dx or STM pin reference PXn to port and mask - #define RD_PORT digitalPinToPort(TFT_RD) - #define RD_PIN_MASK digitalPinToBitMask(TFT_RD) - // Use bit set reset register - #define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16 - #define RD_H RD_PORT->BSRR = RD_PIN_MASK + #if (TFT_RD >= 0) + // Convert Arduino pin reference Dx or STM pin reference PXn to port and mask + #define RD_PORT digitalPinToPort(TFT_RD) + #define RD_PIN_MASK digitalPinToBitMask(TFT_RD) + // Use bit set reset register + #define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16 + #define RD_H RD_PORT->BSRR = RD_PIN_MASK + #else + #define RD_L + #define RD_H + #endif +#else + #define TFT_RD -1 + #define RD_L + #define RD_H #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 0252d30..e3fb4c1 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -335,8 +335,6 @@ void TFT_eSPI::init(uint8_t tc) } // end of: if just _booted // Toggle RST low to reset - begin_tft_write(); - #ifdef TFT_RST if (TFT_RST >= 0) { digitalWrite(TFT_RST, HIGH); @@ -350,8 +348,6 @@ void TFT_eSPI::init(uint8_t tc) writecommand(TFT_SWRST); // Software reset #endif - end_tft_write(); - delay(150); // Wait for reset to complete begin_tft_write(); @@ -946,6 +942,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d uint16_t lineBuf[dw]; // Use buffer to minimise setWindow call count + // The little endian transp color must be byte swapped if the image is big endian if (!_swapBytes) transp = transp >> 8 | transp << 8; while (dh--) @@ -1062,6 +1059,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 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--) { @@ -1247,7 +1245,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da } pushPixels(lineBuf, dw); - dy++; } _swapBytes = swap; // Restore old value diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 4bfa552..f5371e0 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.15" +#define TFT_ESPI_VERSION "2.2.16" /*************************************************************************************** ** Section 1: Load required header files diff --git a/User_Setup_Select.h b/User_Setup_Select.h index abbaa7f..a9f45b3 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -59,7 +59,7 @@ //#include // Setup for Nucleo board //#include // Setup for Nucleo board and parallel display //#include // Setup for Nucleo board and parallel display -//#include // Setup for "Blue Pill" +//#include // Setup for "Blue Pill" //#include // Setup for Nucleo board @@ -69,8 +69,8 @@ //#include // Setup file configured for ESP32 and RPi TFT with touch //#include // Setup file configured for my ST7735S 80x160 -//#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 -//#include // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240 +//#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 +//#include // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240 //#include // Setup file for ESP8266 and ST7789 135 x 240 TFT diff --git a/keywords.txt b/keywords.txt index 2debf03..0cd2511 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,27 +1,34 @@ +# TFT_eSPI core library + TFT_eSPI KEYWORD1 +begin KEYWORD2 init KEYWORD2 drawPixel KEYWORD2 drawChar KEYWORD2 -setAddrWindow KEYWORD2 -setWindow KEYWORD2 -startWrite KEYWORD2 -writeColor KEYWORD2 -endWrite KEYWORD2 -pushColor KEYWORD2 -pushColors KEYWORD2 -fillScreen KEYWORD2 -writeBegin KEYWORD2 -writeEnd KEYWORD2 drawLine KEYWORD2 drawFastVLine KEYWORD2 drawFastHLine KEYWORD2 -drawRect KEYWORD2 fillRect KEYWORD2 +height KEYWORD2 +width KEYWORD2 +setRotation KEYWORD2 +getRotation KEYWORD2 +invertDisplay KEYWORD2 +setAddrWindow KEYWORD2 +setWindow KEYWORD2 +pushColor KEYWORD2 +pushColors KEYWORD2 +pushBlock KEYWORD2 +pushPixels KEYWORD2 +readPixel KEYWORD2 +tft_Read_8 KEYWORD2 +begin_SDA_Read KEYWORD2 +end_SDA_Read KEYWORD2 +fillScreen KEYWORD2 +drawRect KEYWORD2 drawRoundRect KEYWORD2 fillRoundRect KEYWORD2 -setRotation KEYWORD2 -invertDisplay KEYWORD2 drawCircle KEYWORD2 drawCircleHelper KEYWORD2 fillCircle KEYWORD2 @@ -30,18 +37,40 @@ 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 +readRectRGB KEYWORD2 +drawNumber KEYWORD2 +drawFloat KEYWORD2 +drawString KEYWORD2 +drawCentreString KEYWORD2 +drawRightString KEYWORD2 setCursor KEYWORD2 getCursorX KEYWORD2 getCursorY KEYWORD2 setTextColor KEYWORD2 setTextSize KEYWORD2 -setTextFont KEYWORD2 -setFreeFont 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 writedata KEYWORD2 @@ -49,56 +78,51 @@ commandList KEYWORD2 readcommand8 KEYWORD2 readcommand16 KEYWORD2 readcommand32 KEYWORD2 -readPixel KEYWORD2 -readRect KEYWORD2 -pushRect KEYWORD2 -pushImage KEYWORD2 -setSwapBytes KEYWORD2 -getSwapBytes KEYWORD2 -readRectRGB KEYWORD2 -getRotation KEYWORD2 -getTextDatum KEYWORD2 -fontsLoaded KEYWORD2 color565 KEYWORD2 -color16to8 KEYWORD2 color8to16 KEYWORD2 -drawNumber KEYWORD2 -drawFloat KEYWORD2 -drawString KEYWORD2 -drawCentreString KEYWORD2 -drawRightString KEYWORD2 -height KEYWORD2 -width KEYWORD2 -textWidth KEYWORD2 -fontHeight KEYWORD2 -getSetup KEYWORD2 -setAttribute KEYWORD2 -getAttribute KEYWORD2 +color16to8 KEYWORD2 +color16to24 KEYWORD2 +color24to16 KEYWORD2 alphaBlend KEYWORD2 - -getSPIinstance KEYWORD2 -pushBlock KEYWORD2 -pushPixels KEYWORD2 - +alphaBlend24 KEYWORD2 initDMA KEYWORD2 deInitDMA KEYWORD2 pushImageDMA KEYWORD2 -pushBlockDMA 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 -convertRawXY KEYWORD2 getTouchRawZ KEYWORD2 +convertRawXY KEYWORD2 getTouch KEYWORD2 calibrateTouch KEYWORD2 setTouch KEYWORD2 + +# Smooth font functions + +loadFont KEYWORD2 +unloadFont KEYWORD2 +getUnicodeIndex KEYWORD2 +showFont KEYWORD2 + + +# Button class + TFT_eSPI_Button KEYWORD1 initButton KEYWORD2 -textcolor KEYWORD2 initButtonUL KEYWORD2 setLabelDatum KEYWORD2 drawButton KEYWORD2 @@ -109,31 +133,30 @@ justPressed KEYWORD2 justReleased KEYWORD2 +# Sprite class + TFT_eSprite KEYWORD1 createSprite KEYWORD2 -createPalette KEYWORD2 +getPointer KEYWORD2 +created KEYWORD2 +deleteSprite KEYWORD2 +frameBuffer KEYWORD2 setColorDepth KEYWORD2 getColorDepth KEYWORD2 -deleteSprite KEYWORD2 +createPalette KEYWORD2 +setPaletteColor KEYWORD2 +getPaletteColor KEYWORD2 +setBitmapColor KEYWORD2 +fillSprite KEYWORD2 +setScrollRect KEYWORD2 +scroll KEYWORD2 pushRotated KEYWORD2 -pushRotatedHP KEYWORD2 -rotatedBounds KEYWORD2 setPivot KEYWORD2 getPivotX KEYWORD2 getPivotY KEYWORD2 -fillSprite KEYWORD2 -pushBitmap KEYWORD2 -pushSprite KEYWORD2 -setScrollRect KEYWORD2 -scroll KEYWORD2 -printToSprite KEYWORD2 -frameBuffer KEYWORD2 -setBitmapColor KEYWORD2 - -showFont KEYWORD2 -loadFont KEYWORD2 -unloadFont KEYWORD2 -getUnicodeIndex KEYWORD2 -decodeUTF8 KEYWORD2 +getRotatedBounds KEYWORD2 +readPixelValue KEYWORD2 drawGlyph KEYWORD2 +printToSprite KEYWORD2 +pushSprite KEYWORD2 diff --git a/library.json b/library.json index 3709c76..7733bb7 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.15", + "version": "2.2.16", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 41f6a4f..736d8d5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.15 +version=2.2.16 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 31125ca5ac859e141af0a37a06dda816ba9f3ca0 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 23:01:59 +0100 Subject: [PATCH 28/42] Elimnate some warnings #702 --- Extensions/Sprite.cpp | 52 +++++++++++++++++++++---------------------- Extensions/Sprite.h | 14 ++++++------ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 26f2296..a8bd4f3 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -33,8 +33,8 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) _xptr = 0; // pushColor coordinate _yptr = 0; - _xpivot = 0; - _ypivot = 0; + _xPivot = 0; + _yPivot = 0; _colorMap = nullptr; @@ -69,8 +69,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _sh = h; _scolor = TFT_BLACK; - _xpivot = w/2; - _ypivot = h/2; + _xPivot = w/2; + _yPivot = h/2; _img8 = (uint8_t*) callocSprite(w, h, frames); _img8_1 = _img8; @@ -397,8 +397,8 @@ void TFT_eSprite::deleteSprite(void) ***************************************************************************************/ void TFT_eSprite::setPivot(int16_t x, int16_t y) { - _xpivot = x; - _ypivot = y; + _xPivot = x; + _yPivot = y; } @@ -408,7 +408,7 @@ void TFT_eSprite::setPivot(int16_t x, int16_t y) ***************************************************************************************/ int16_t TFT_eSprite::getPivotX(void) { - return _xpivot; + return _xPivot; } @@ -418,7 +418,7 @@ int16_t TFT_eSprite::getPivotX(void) ***************************************************************************************/ int16_t TFT_eSprite::getPivotY(void) { - return _ypivot; + return _yPivot; } @@ -442,8 +442,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) uint16_t sline_buffer[max_x - min_x + 1]; - int32_t xt = min_x - _tft->_xpivot; - int32_t yt = min_y - _tft->_ypivot; + 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; uint32_t tpcolor = transp; // convert to unsigned @@ -454,8 +454,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) // 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))); + 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; @@ -513,8 +513,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) uint16_t sline_buffer[max_x - min_x + 1]; - int32_t xt = min_x - spr->_xpivot; - int32_t yt = min_y - spr->_ypivot; + 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; uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes @@ -525,8 +525,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) // 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))); + 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; @@ -563,13 +563,13 @@ 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); + 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; + *min_x += _tft->_xPivot; + *max_x += _tft->_xPivot; + *min_y += _tft->_yPivot; + *max_y += _tft->_yPivot; // Return if bounding box is outside of TFT area if (*min_x > _tft->width()) return false; @@ -595,13 +595,13 @@ bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min 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); + 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; + *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); diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 723b557..5282bbf 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -9,7 +9,7 @@ class TFT_eSprite : public TFT_eSPI { public: - TFT_eSprite(TFT_eSPI *tft); + explicit TFT_eSprite(TFT_eSPI *tft); ~TFT_eSprite(void); // Create a sprite of width x height pixels, return a pointer to the RAM area @@ -167,15 +167,15 @@ class TFT_eSprite : public TFT_eSPI { uint8_t _bpp; // bits per pixel (1, 8 or 16) uint16_t *_img; // pointer to 16 bit sprite - uint8_t *_img8; // pointer to 8 bit sprite - 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 + uint8_t *_img8; // pointer to 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: 16 entries, used with 4 bit color map. - int16_t _xpivot; // x pivot point coordinate - int16_t _ypivot; // y pivot point coordinate + int16_t _xPivot; // x pivot point coordinate + int16_t _yPivot; // y pivot point coordinate int32_t _sinra; int32_t _cosra; From cfcb9c6632767c89f2960fa3b19dce785cbf7abc Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 23:13:59 +0100 Subject: [PATCH 29/42] Revert "Elimnate some warnings #702" This reverts commit 31125ca5ac859e141af0a37a06dda816ba9f3ca0. --- Extensions/Sprite.cpp | 52 +++++++++++++++++++++---------------------- Extensions/Sprite.h | 14 ++++++------ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index a8bd4f3..26f2296 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -33,8 +33,8 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) _xptr = 0; // pushColor coordinate _yptr = 0; - _xPivot = 0; - _yPivot = 0; + _xpivot = 0; + _ypivot = 0; _colorMap = nullptr; @@ -69,8 +69,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _sh = h; _scolor = TFT_BLACK; - _xPivot = w/2; - _yPivot = h/2; + _xpivot = w/2; + _ypivot = h/2; _img8 = (uint8_t*) callocSprite(w, h, frames); _img8_1 = _img8; @@ -397,8 +397,8 @@ void TFT_eSprite::deleteSprite(void) ***************************************************************************************/ void TFT_eSprite::setPivot(int16_t x, int16_t y) { - _xPivot = x; - _yPivot = y; + _xpivot = x; + _ypivot = y; } @@ -408,7 +408,7 @@ void TFT_eSprite::setPivot(int16_t x, int16_t y) ***************************************************************************************/ int16_t TFT_eSprite::getPivotX(void) { - return _xPivot; + return _xpivot; } @@ -418,7 +418,7 @@ int16_t TFT_eSprite::getPivotX(void) ***************************************************************************************/ int16_t TFT_eSprite::getPivotY(void) { - return _yPivot; + return _ypivot; } @@ -442,8 +442,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) uint16_t sline_buffer[max_x - min_x + 1]; - int32_t xt = min_x - _tft->_xPivot; - int32_t yt = min_y - _tft->_yPivot; + 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; uint32_t tpcolor = transp; // convert to unsigned @@ -454,8 +454,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) // 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))); + 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; @@ -513,8 +513,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) uint16_t sline_buffer[max_x - min_x + 1]; - int32_t xt = min_x - spr->_xPivot; - int32_t yt = min_y - spr->_yPivot; + 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; uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes @@ -525,8 +525,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) // 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))); + 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; @@ -563,13 +563,13 @@ 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); + 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; + *min_x += _tft->_xpivot; + *max_x += _tft->_xpivot; + *min_y += _tft->_ypivot; + *max_y += _tft->_ypivot; // Return if bounding box is outside of TFT area if (*min_x > _tft->width()) return false; @@ -595,13 +595,13 @@ bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min 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); + 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; + *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); diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 5282bbf..723b557 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -9,7 +9,7 @@ class TFT_eSprite : public TFT_eSPI { public: - explicit TFT_eSprite(TFT_eSPI *tft); + TFT_eSprite(TFT_eSPI *tft); ~TFT_eSprite(void); // Create a sprite of width x height pixels, return a pointer to the RAM area @@ -167,15 +167,15 @@ class TFT_eSprite : public TFT_eSPI { uint8_t _bpp; // bits per pixel (1, 8 or 16) uint16_t *_img; // pointer to 16 bit sprite - uint8_t *_img8; // pointer to 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 + uint8_t *_img8; // pointer to 8 bit sprite + 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: 16 entries, used with 4 bit color map. - int16_t _xPivot; // x pivot point coordinate - int16_t _yPivot; // y pivot point coordinate + int16_t _xpivot; // x pivot point coordinate + int16_t _ypivot; // y pivot point coordinate int32_t _sinra; int32_t _cosra; From 52ee45b30b58a498ad4187278dc1ffe413c305d5 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 23:37:24 +0100 Subject: [PATCH 30/42] Correct medium warnings #702 --- Extensions/Sprite.cpp | 40 ++++++++++++++++++++-------------------- Extensions/Sprite.h | 14 +++++++------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 26f2296..20d5d21 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -33,8 +33,8 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) _xptr = 0; // pushColor coordinate _yptr = 0; - _xpivot = 0; - _ypivot = 0; + _xPivot = 0; + _yPivot = 0; _colorMap = nullptr; @@ -69,8 +69,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _sh = h; _scolor = TFT_BLACK; - _xpivot = w/2; - _ypivot = h/2; + _xPivot = w/2; + _yPivot = h/2; _img8 = (uint8_t*) callocSprite(w, h, frames); _img8_1 = _img8; @@ -397,8 +397,8 @@ void TFT_eSprite::deleteSprite(void) ***************************************************************************************/ void TFT_eSprite::setPivot(int16_t x, int16_t y) { - _xpivot = x; - _ypivot = y; + _xPivot = x; + _yPivot = y; } @@ -408,7 +408,7 @@ void TFT_eSprite::setPivot(int16_t x, int16_t y) ***************************************************************************************/ int16_t TFT_eSprite::getPivotX(void) { - return _xpivot; + return _xPivot; } @@ -418,7 +418,7 @@ int16_t TFT_eSprite::getPivotX(void) ***************************************************************************************/ int16_t TFT_eSprite::getPivotY(void) { - return _ypivot; + return _yPivot; } @@ -454,8 +454,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) // 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))); + 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; @@ -513,8 +513,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) uint16_t sline_buffer[max_x - min_x + 1]; - int32_t xt = min_x - spr->_xpivot; - int32_t yt = min_y - spr->_ypivot; + 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; uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes @@ -525,8 +525,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) // 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))); + 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; @@ -563,7 +563,7 @@ 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); + 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; @@ -595,13 +595,13 @@ bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min 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); + 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; + *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); diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 723b557..5282bbf 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -9,7 +9,7 @@ class TFT_eSprite : public TFT_eSPI { public: - TFT_eSprite(TFT_eSPI *tft); + explicit TFT_eSprite(TFT_eSPI *tft); ~TFT_eSprite(void); // Create a sprite of width x height pixels, return a pointer to the RAM area @@ -167,15 +167,15 @@ class TFT_eSprite : public TFT_eSPI { uint8_t _bpp; // bits per pixel (1, 8 or 16) uint16_t *_img; // pointer to 16 bit sprite - uint8_t *_img8; // pointer to 8 bit sprite - 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 + uint8_t *_img8; // pointer to 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: 16 entries, used with 4 bit color map. - int16_t _xpivot; // x pivot point coordinate - int16_t _ypivot; // y pivot point coordinate + int16_t _xPivot; // x pivot point coordinate + int16_t _yPivot; // y pivot point coordinate int32_t _sinra; int32_t _cosra; From 47baa19645f045325fa2c77923907575e174d98d Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 23:52:02 +0100 Subject: [PATCH 31/42] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 50cf1a6..79a514a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# Sprite class change +The Sprite class has been updated to remove an inconsistency for the setSwapBytes() function. Although all the examples are unchanged, user sketches may be affected. If the colors of the sprite change when loading this new version 2.2.16 then it may be necessary to change the swap bytes setting, e.g. for a sprite instance "spr" use either: spr.setSwapBytes(true) or spr.setSwapBytes(true) to correct the colour. # News 1. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI. From 787893f9499adda70b52d34f35a546f6ddfbbf9b Mon Sep 17 00:00:00 2001 From: Bodmer Date: Wed, 5 Aug 2020 23:55:54 +0100 Subject: [PATCH 32/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79a514a..f1f32cd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Sprite class change -The Sprite class has been updated to remove an inconsistency for the setSwapBytes() function. Although all the examples are unchanged, user sketches may be affected. If the colors of the sprite change when loading this new version 2.2.16 then it may be necessary to change the swap bytes setting, e.g. for a sprite instance "spr" use either: spr.setSwapBytes(true) or spr.setSwapBytes(true) to correct the colour. +The Sprite class has been updated to remove an inconsistency for the setSwapBytes() function. Although all the examples are unchanged, user sketches may be affected. If the colors of the sprite change when loading this new version 2.2.16 then it may be necessary to change the swap bytes setting, e.g. for a sprite instance "spr" use either: spr.setSwapBytes(true) or spr.setSwapBytes(false) to correct the colour. # News 1. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI. From a8cd5c5d91d3e4d1d5a77ae7ce4dea97ca507266 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Thu, 6 Aug 2020 12:51:10 +0100 Subject: [PATCH 33/42] Correct TFT_eFEX issue 24 --- TFT_eSPI.cpp | 12 ++++++------ TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index e3fb4c1..9fb7daa 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2626,18 +2626,18 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) DC_D; tft_Write_32C(y0, y1); #else // No need to send x if it has not changed (speeds things up) - if (addr_col != (x0<<16 | x1)) { + //if (addr_col != (x0<<16 | x1)) { DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(x0, x1); - addr_col = (x0<<16 | x1); - } + // addr_col = (x0<<16 | x1); + //} // No need to send y if it has not changed (speeds things up) - if (addr_row != (y0<<16 | y1)) { + //if (addr_row != (y0<<16 | y1)) { DC_C; tft_Write_8(TFT_PASET); DC_D; tft_Write_32C(y0, y1); - addr_row = (y0<<16 | y1); - } + // addr_row = (y0<<16 | y1); + //} #endif DC_C; tft_Write_8(TFT_RAMWR); diff --git a/TFT_eSPI.h b/TFT_eSPI.h index f5371e0..896c814 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.16" +#define TFT_ESPI_VERSION "2.2.17" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index 7733bb7..6a2b563 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.16", + "version": "2.2.17", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 736d8d5..70d3782 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.16 +version=2.2.17 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 1c66d306d530d00b35e9d8f74bfe4c45855660a8 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Sat, 15 Aug 2020 00:19:03 +0100 Subject: [PATCH 34/42] Add SSD1963 for #704 Remove setWindow optimisation clash with TFT_eFEX --- TFT_Drivers/SSD1963_Defines.h | 48 ++++++ TFT_Drivers/SSD1963_Init.h | 306 +++++++++++++++++++++++++++++++++ TFT_Drivers/SSD1963_Rotation.h | 50 ++++++ TFT_eSPI.cpp | 30 ++-- TFT_eSPI.h | 2 +- User_Setup.h | 3 + User_Setup_Select.h | 13 +- library.json | 2 +- library.properties | 2 +- 9 files changed, 433 insertions(+), 23 deletions(-) create mode 100644 TFT_Drivers/SSD1963_Defines.h create mode 100644 TFT_Drivers/SSD1963_Init.h create mode 100644 TFT_Drivers/SSD1963_Rotation.h diff --git a/TFT_Drivers/SSD1963_Defines.h b/TFT_Drivers/SSD1963_Defines.h new file mode 100644 index 0000000..78fac3e --- /dev/null +++ b/TFT_Drivers/SSD1963_Defines.h @@ -0,0 +1,48 @@ +// Change the width and height if required (defined in portrait mode) +// or use the constructor to over-ride defaults +#if defined (SSD1963_480_DRIVER) + #define TFT_WIDTH 272 + #define TFT_HEIGHT 480 +#elif defined (SSD1963_800_DRIVER) + #define TFT_WIDTH 480 + #define TFT_HEIGHT 800 +#elif defined (SSD1963_800ALT_DRIVER) + #define TFT_WIDTH 480 + #define TFT_HEIGHT 800 +#endif + +// 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_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C + +#define TFT_RAMRD 0x2E +#define TFT_IDXRD 0xDD // ILI9341 only, indexed control register read + +#define TFT_MADCTL 0x36 +#define TFT_MAD_MY 0x80 +#define TFT_MAD_MX 0x40 +#define TFT_MAD_MV 0x20 +#define TFT_MAD_ML 0x10 +#define TFT_MAD_BGR 0x08 +#define TFT_MAD_MH 0x04 +#define TFT_MAD_RGB 0x00 + +#ifdef TFT_RGB_ORDER + #if (TFT_RGB_ORDER == 1) + #define TFT_MAD_COLOR_ORDER TFT_MAD_RGB + #else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR + #endif +#else + #define TFT_MAD_COLOR_ORDER TFT_MAD_BGR +#endif + +#define TFT_INVOFF 0x20 +#define TFT_INVON 0x21 diff --git a/TFT_Drivers/SSD1963_Init.h b/TFT_Drivers/SSD1963_Init.h new file mode 100644 index 0000000..e07f918 --- /dev/null +++ b/TFT_Drivers/SSD1963_Init.h @@ -0,0 +1,306 @@ +#if defined (SSD1963_480_DRIVER) + + writecommand(0xE2); //PLL multiplier, set PLL clock to 120M + writedata(0x23); //N=0x36 for 6.5M, 0x23 for 10M crystal + writedata(0x02); + writedata(0x54); + writecommand(0xE0); // PLL enable + writedata(0x01); + + delay(10); + + writecommand(0xE0); + writedata(0x03); + + delay(10); + + writecommand(0x01); // software reset + + delay(100); + + writecommand(0xE6); //PLL setting for PCLK, depends on resolution + writedata(0x01); + writedata(0x1F); + writedata(0xFF); + + writecommand(0xB0); //LCD SPECIFICATION + writedata(0x20); + writedata(0x00); + writedata(0x01); //Set HDP 479 + writedata(0xDF); + writedata(0x01); //Set VDP 271 + writedata(0x0F); + writedata(0x00); + + writecommand(0xB4); //HSYNC + writedata(0x02); //Set HT 531 + writedata(0x13); + writedata(0x00); //Set HPS 8 + writedata(0x08); + writedata(0x2B); //Set HPW 43 + writedata(0x00); //Set LPS 2 + writedata(0x02); + writedata(0x00); + + writecommand(0xB6); //VSYNC + writedata(0x01); //Set VT 288 + writedata(0x20); + writedata(0x00); //Set VPS 4 + writedata(0x04); + writedata(0x0c); //Set VPW 12 + writedata(0x00); //Set FPS 2 + writedata(0x02); + + writecommand(0xBA); + writedata(0x0F); //GPIO[3:0] out 1 + + writecommand(0xB8); + writedata(0x07); //GPIO3=input, GPIO[2:0]=output + writedata(0x01); //GPIO0 normal + + writecommand(0x36); //rotation + writedata(0x2A); + + writecommand(0xF0); //pixel data interface + writedata(0x03); + + delay(1); + + writecommand(0xB8); + writedata(0x0f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF + writedata(0x01); //GPIO0 normal + + writecommand(0xBA); + writedata(0x01); //GPIO[0] out 1 --- LCD display on/off control PIN + + writecommand(0x2A); + writedata(0); + writedata(0); + writedata((271 & 0xFF00)>>8); + writedata(271 & 0xFF); + + writecommand(0x2B); + writedata(0); + writedata(0); + writedata((479 & 0xFF00)>>8); + writedata(479 & 0xFF); + + writecommand(0x2C); + + writecommand(0x29); //display on + + writecommand(0xBE); //set PWM for B/L + writedata(0x06); + writedata(0xf0); + writedata(0x01); + writedata(0xf0); + writedata(0x00); + writedata(0x00); + + writecommand(0xd0); + writedata(0x0d); + + writecommand(0x2C); + +#elif defined (SSD1963_800_DRIVER) + + writecommand(0xE2); //PLL multiplier, set PLL clock to 120M + writedata(0x1E); //N=0x36 for 6.5M, 0x23 for 10M crystal + writedata(0x02); + writedata(0x54); + writecommand(0xE0); // PLL enable + writedata(0x01); + + delay(10); + + writecommand(0xE0); + writedata(0x03); + + delay(10); + + writecommand(0x01); // software reset + + delay(100); + + writecommand(0xE6); //PLL setting for PCLK, depends on resolution + writedata(0x03); + writedata(0xFF); + writedata(0xFF); + + writecommand(0xB0); //LCD SPECIFICATION + writedata(0x20); + writedata(0x00); + writedata(0x03); //Set HDP 799 + writedata(0x1F); + writedata(0x01); //Set VDP 479 + writedata(0xDF); + writedata(0x00); + + writecommand(0xB4); //HSYNC + writedata(0x03); //Set HT 928 + writedata(0xA0); + writedata(0x00); //Set HPS 46 + writedata(0x2E); + writedata(0x30); //Set HPW 48 + writedata(0x00); //Set LPS 15 + writedata(0x0F); + writedata(0x00); + + writecommand(0xB6); //VSYNC + writedata(0x02); //Set VT 525 + writedata(0x0D); + writedata(0x00); //Set VPS 16 + writedata(0x10); + writedata(0x10); //Set VPW 16 + writedata(0x00); //Set FPS 8 + writedata(0x08); + + writecommand(0xBA); + writedata(0x0F); //GPIO[3:0] out 1 + + writecommand(0xB8); + writedata(0x07); //GPIO3=input, GPIO[2:0]=output + writedata(0x01); //GPIO0 normal + + writecommand(0x36); //rotation + writedata(0x2A); + + writecommand(0xF0); //pixel data interface + writedata(0x03); + + delay(1); + + writecommand(0xB8); + writedata(0x0f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF + writedata(0x01); //GPIO0 normal + + writecommand(0xBA); + writedata(0x01); //GPIO[0] out 1 --- LCD display on/off control PIN + + writecommand(0x2A); + writedata(0); + writedata(0); + writedata((479 & 0xFF00)>>8); + writedata(479 & 0xFF); + + writecommand(0x2B); + writedata(0); + writedata(0); + writedata((799 & 0xFF00)>>8); + writedata(799 & 0xFF); + + writecommand(0x2C); + + writecommand(0x29); //display on + + writecommand(0xBE); //set PWM for B/L + writedata(0x06); + writedata(0xf0); + writedata(0x01); + writedata(0xf0); + writedata(0x00); + writedata(0x00); + + writecommand(0xd0); + writedata(0x0d); + + writecommand(0x2C); + +#elif defined (SSD1963_800ALT_DRIVER) + + writecommand(0xE2); //PLL multiplier, set PLL clock to 120M + writedata(0x23); //N=0x36 for 6.5M, 0x23 for 10M crystal + writedata(0x02); + writedata(0x04); + writecommand(0xE0); // PLL enable + writedata(0x01); + + delay(10); + + writecommand(0xE0); + writedata(0x03); + + delay(10); + + writecommand(0x01); // software reset + + delay(100); + + writecommand(0xE6); //PLL setting for PCLK, depends on resolution + writedata(0x04); + writedata(0x93); + writedata(0xE0); + + writecommand(0xB0); //LCD SPECIFICATION + writedata(0x00); // 0x24 + writedata(0x00); + writedata(0x03); //Set HDP 799 + writedata(0x1F); + writedata(0x01); //Set VDP 479 + writedata(0xDF); + writedata(0x00); + + writecommand(0xB4); //HSYNC + writedata(0x03); //Set HT 928 + writedata(0xA0); + writedata(0x00); //Set HPS 46 + writedata(0x2E); + writedata(0x30); //Set HPW 48 + writedata(0x00); //Set LPS 15 + writedata(0x0F); + writedata(0x00); + + writecommand(0xB6); //VSYNC + writedata(0x02); //Set VT 525 + writedata(0x0D); + writedata(0x00); //Set VPS 16 + writedata(0x10); + writedata(0x10); //Set VPW 16 + writedata(0x00); //Set FPS 8 + writedata(0x08); + + writecommand(0xBA); + writedata(0x05); //GPIO[3:0] out 1 + + writecommand(0xB8); + writedata(0x07); //GPIO3=input, GPIO[2:0]=output + writedata(0x01); //GPIO0 normal + + writecommand(0x36); //rotation + writedata(0x22); // -- Set to 0x21 to rotate 180 degrees + + writecommand(0xF0); //pixel data interface + writedata(0x03); + + delay(10); + + writecommand(0x2A); + writedata(0); + writedata(0); + writedata((479 & 0xFF00)>>8); + writedata(479 & 0xFF); + + writecommand(0x2B); + writedata(0); + writedata(0); + writedata((799 & 0xFF00)>>8); + writedata(799 & 0xFF); + + writecommand(0x2C); + + writecommand(0x29); //display on + + writecommand(0xBE); //set PWM for B/L + writedata(0x06); + writedata(0xF0); + writedata(0x01); + writedata(0xF0); + writedata(0x00); + writedata(0x00); + + writecommand(0xD0); + writedata(0x0D); + + writecommand(0x2C); + +#endif \ No newline at end of file diff --git a/TFT_Drivers/SSD1963_Rotation.h b/TFT_Drivers/SSD1963_Rotation.h new file mode 100644 index 0000000..c0fd611 --- /dev/null +++ b/TFT_Drivers/SSD1963_Rotation.h @@ -0,0 +1,50 @@ + +// This is the command sequence that rotates the SSD1963 driver coordinate frame + + rotation = m % 8; // Limit the range of values to 0-7 + + writecommand(TFT_MADCTL); + switch (rotation) { + case 0: + writedata(TFT_MAD_MX | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 1: + writedata(TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + case 2: + writedata(TFT_MAD_MY | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 3: + writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + // These next rotations are for bottom up BMP drawing + case 4: + writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 5: + writedata(TFT_MAD_MV | TFT_MAD_MX | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + case 6: + writedata(TFT_MAD_COLOR_ORDER); + _width = _init_width; + _height = _init_height; + break; + case 7: + writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + _width = _init_height; + _height = _init_width; + break; + + } diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 9fb7daa..b01e4e7 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -395,6 +395,15 @@ void TFT_eSPI::init(uint8_t tc) #elif defined (ST7789_2_DRIVER) #include "TFT_Drivers/ST7789_2_Init.h" +#elif defined (SSD1963_480_DRIVER) + #include "TFT_Drivers/SSD1963_Init.h" + +#elif defined (SSD1963_800_DRIVER) + #include "TFT_Drivers/SSD1963_Init.h" + +#elif defined (SSD1963_800ALT_DRIVER) + #include "TFT_Drivers/SSD1963_Init.h" + #endif #ifdef TFT_INVERSION_ON @@ -2611,6 +2620,9 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //begin_tft_write(); // Must be called before setWindow + addr_row = 0xFFFF; + addr_col = 0xFFFF; + #ifdef CGRAM_OFFSET x0+=colstart; x1+=colstart; @@ -2618,28 +2630,10 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) y1+=rowstart; #endif -#ifdef MULTI_TFT_SUPPORT - // No optimisation to permit multiple screens DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(x0, x1); DC_C; tft_Write_8(TFT_PASET); DC_D; tft_Write_32C(y0, y1); -#else - // No need to send x if it has not changed (speeds things up) - //if (addr_col != (x0<<16 | x1)) { - DC_C; tft_Write_8(TFT_CASET); - DC_D; tft_Write_32C(x0, x1); - // addr_col = (x0<<16 | x1); - //} - - // No need to send y if it has not changed (speeds things up) - //if (addr_row != (y0<<16 | y1)) { - DC_C; tft_Write_8(TFT_PASET); - DC_D; tft_Write_32C(y0, y1); - // addr_row = (y0<<16 | y1); - //} -#endif - DC_C; tft_Write_8(TFT_RAMWR); DC_D; diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 896c814..5efe061 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.17" +#define TFT_ESPI_VERSION "2.2.18" /*************************************************************************************** ** Section 1: Load required header files diff --git a/User_Setup.h b/User_Setup.h index 32eea56..0fb8bf4 100644 --- a/User_Setup.h +++ b/User_Setup.h @@ -50,6 +50,9 @@ //#define R61581_DRIVER //#define RM68140_DRIVER //#define ST7796_DRIVER +//#define SSD1963_480_DRIVER // Untested +//#define SSD1963_800_DRIVER // Untested +//#define SSD1963_800ALT_DRIVER // Untested // Some displays support SPI reads via the MISO pin, other displays have a single // bi-directional SDA pin and the library will try to read this via the MOSI line. diff --git a/User_Setup_Select.h b/User_Setup_Select.h index a9f45b3..ec0fdfd 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -59,7 +59,7 @@ //#include // Setup for Nucleo board //#include // Setup for Nucleo board and parallel display //#include // Setup for Nucleo board and parallel display -//#include // Setup for "Blue Pill" +//#include // Setup for "Blue/Black Pill" //#include // Setup for Nucleo board @@ -154,8 +154,17 @@ #elif defined (RM68140_DRIVER) #include "TFT_Drivers/RM68140_Defines.h" #define TFT_DRIVER 0x6814 +#elif defined (SSD1963_480_DRIVER) + #include "TFT_Drivers/SSD1963_Defines.h" + #define TFT_DRIVER 0x1963 +#elif defined (SSD1963_800_DRIVER) + #include "TFT_Drivers/SSD1963_Defines.h" + #define TFT_DRIVER 0x1963 +#elif defined (SSD1963_800ALT_DRIVER) + #include "TFT_Drivers/SSD1963_Defines.h" + #define TFT_DRIVER 0x1963 // <<<<<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVER HERE - // XYZZY_init.h and XYZZY_rotation.h must also be added in TFT_eSPI.c + // XYZZY_init.h and XYZZY_rotation.h must also be added in TFT_eSPI.cpp #elif defined (XYZZY_DRIVER) #include "TFT_Drivers/XYZZY_Defines.h" #define TFT_DRIVER 0x0000 diff --git a/library.json b/library.json index 6a2b563..2928b13 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.17", + "version": "2.2.18", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 70d3782..8ab3ac1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.17 +version=2.2.18 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 731228d13a90838c091f95018bddc76137c2a2b7 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 28 Aug 2020 21:18:26 +0100 Subject: [PATCH 35/42] Fix deleteSprite Fixes #736 and also delete color map even if the sprite has not been created. --- Extensions/Sprite.cpp | 16 ++++++++-------- TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 20d5d21..4297d35 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -125,7 +125,7 @@ void* TFT_eSprite::getPointer(void) /*************************************************************************************** ** Function name: created -** Description: Returns true is sprite has been created +** Description: Returns true if sprite has been created ***************************************************************************************/ bool TFT_eSprite::created(void) { @@ -376,18 +376,18 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index) ***************************************************************************************/ void TFT_eSprite::deleteSprite(void) { - if (!_created ) return; - if (_colorMap != nullptr) { free(_colorMap); + _colorMap = nullptr; } - free(_img8_1); - - _img8 = nullptr; - - _created = false; + if (_created) + { + free(_img8_1); + _img8 = nullptr; + _created = false; + } } diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 5efe061..10b6754 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.18" +#define TFT_ESPI_VERSION "2.2.19" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index 2928b13..7a8389f 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.18", + "version": "2.2.19", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 8ab3ac1..4e053eb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.18 +version=2.2.19 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From ddf03d43ea18f9781e73922b952cbf8a374af51c Mon Sep 17 00:00:00 2001 From: QrackEE Date: Sat, 5 Sep 2020 16:54:24 +0200 Subject: [PATCH 36/42] Resolve ambigous pushSprite(int int int) methods --- Extensions/Sprite.cpp | 14 +++++++------- Extensions/Sprite.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 4297d35..20b1476 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -739,22 +739,22 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) // 4bpp -> 4bpp (note: color translation depends on the 2 sprites pallet colors) // 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) -bool TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y) +bool TFT_eSprite::pushSprite(TFT_eSprite &spr, int32_t x, int32_t y) { if (!_created) return false; - if (!spr->created()) return false; + if (!spr.created()) return false; // Check destination sprite compatibility - int8_t ds_bpp = spr->getColorDepth(); + int8_t ds_bpp = spr.getColorDepth(); if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; if (_bpp == 8) return false; if (_bpp == 4 && ds_bpp != 4) return false; if (_bpp == 1 && ds_bpp != 1) return false; - bool oldSwapBytes = spr->getSwapBytes(); - spr->setSwapBytes(false); - spr->pushImage(x, y, _dwidth, _dheight, _img ); - spr->setSwapBytes(oldSwapBytes); + bool oldSwapBytes = spr.getSwapBytes(); + spr.setSwapBytes(false); + spr.pushImage(x, y, _dwidth, _dheight, _img ); + spr.setSwapBytes(oldSwapBytes); return true; } diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 5282bbf..823ec1f 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -135,7 +135,7 @@ class TFT_eSprite : public TFT_eSPI { // Push the sprite to another sprite, this fn calls pushImage() in the destination sprite class. // >>>>>> Using a transparent color is not supported at the moment <<<<<< - bool pushSprite(TFT_eSprite *spr, int32_t x, int32_t y); + bool pushSprite(TFT_eSprite &spr, int32_t x, int32_t y); // 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); From 4c314c5c336d68b3f37cd2adfd25447b3074acac Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 7 Sep 2020 13:05:59 +0100 Subject: [PATCH 37/42] Revert "Resolve ambigous pushSprite(int int int) methods" --- Extensions/Sprite.cpp | 14 +++++++------- Extensions/Sprite.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 20b1476..4297d35 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -739,22 +739,22 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) // 4bpp -> 4bpp (note: color translation depends on the 2 sprites pallet colors) // 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) -bool TFT_eSprite::pushSprite(TFT_eSprite &spr, int32_t x, int32_t y) +bool TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y) { if (!_created) return false; - if (!spr.created()) return false; + if (!spr->created()) return false; // Check destination sprite compatibility - int8_t ds_bpp = spr.getColorDepth(); + int8_t ds_bpp = spr->getColorDepth(); if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; if (_bpp == 8) return false; if (_bpp == 4 && ds_bpp != 4) return false; if (_bpp == 1 && ds_bpp != 1) return false; - bool oldSwapBytes = spr.getSwapBytes(); - spr.setSwapBytes(false); - spr.pushImage(x, y, _dwidth, _dheight, _img ); - spr.setSwapBytes(oldSwapBytes); + bool oldSwapBytes = spr->getSwapBytes(); + spr->setSwapBytes(false); + spr->pushImage(x, y, _dwidth, _dheight, _img ); + spr->setSwapBytes(oldSwapBytes); return true; } diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 823ec1f..5282bbf 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -135,7 +135,7 @@ class TFT_eSprite : public TFT_eSPI { // Push the sprite to another sprite, this fn calls pushImage() in the destination sprite class. // >>>>>> Using a transparent color is not supported at the moment <<<<<< - bool pushSprite(TFT_eSprite &spr, int32_t x, int32_t y); + bool pushSprite(TFT_eSprite *spr, int32_t x, int32_t y); // 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); From d7fdcc0991111b713c7e57065952c0a537860d83 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 7 Sep 2020 22:04:42 +0100 Subject: [PATCH 38/42] Fix #740 and #704 #740: To avoid ambiguity the pushSprite for writing a sprite to another sprite has been renamed pushToSprite #704: Change to 18 bit colurs for SSD1963 with SPI interface Remove outdated TFT_SPIFFS_Jpeg example --- Extensions/Sprite.cpp | 20 +- Extensions/Sprite.h | 9 +- Processors/TFT_eSPI_ESP32.h | 25 ++- TFT_Drivers/SSD1963_Defines.h | 5 + TFT_Drivers/SSD1963_Init.h | 6 +- TFT_eSPI.h | 2 +- .../TFT_SPIFFS_Jpeg/JPEG_functions.ino | 191 ------------------ .../TFT_SPIFFS_Jpeg/SPIFFS_functions.ino | 36 ---- .../TFT_SPIFFS_Jpeg/TFT_SPIFFS_Jpeg.ino | 129 ------------ .../ESP32_SDcard_jpeg/ESP32_SDcard_jpeg.ino | 4 +- library.json | 2 +- library.properties | 2 +- 12 files changed, 47 insertions(+), 384 deletions(-) delete mode 100644 examples/160 x 128/TFT_SPIFFS_Jpeg/JPEG_functions.ino delete mode 100644 examples/160 x 128/TFT_SPIFFS_Jpeg/SPIFFS_functions.ino delete mode 100644 examples/160 x 128/TFT_SPIFFS_Jpeg/TFT_SPIFFS_Jpeg.ino diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 4297d35..828ce8e 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -729,7 +729,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) /*************************************************************************************** -** Function name: pushSprite +** Function name: pushToSprite ** Description: Push the sprite to another sprite at x, y ***************************************************************************************/ // Note: The following sprite to sprite colour depths are currently supported: @@ -739,33 +739,33 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) // 4bpp -> 4bpp (note: color translation depends on the 2 sprites pallet colors) // 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) -bool TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y) +bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y) { if (!_created) return false; - if (!spr->created()) return false; + if (!dspr->created()) return false; // Check destination sprite compatibility - int8_t ds_bpp = spr->getColorDepth(); + int8_t ds_bpp = dspr->getColorDepth(); if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false; if (_bpp == 8) return false; if (_bpp == 4 && ds_bpp != 4) return false; if (_bpp == 1 && ds_bpp != 1) return false; - bool oldSwapBytes = spr->getSwapBytes(); - spr->setSwapBytes(false); - spr->pushImage(x, y, _dwidth, _dheight, _img ); - spr->setSwapBytes(oldSwapBytes); + bool oldSwapBytes = dspr->getSwapBytes(); + dspr->setSwapBytes(false); + dspr->pushImage(x, y, _dwidth, _dheight, _img ); + dspr->setSwapBytes(oldSwapBytes); return true; } /*************************************************************************************** -** Function name: pushSprite +** Function name: pushToSprite ** Description: Push the sprite to another sprite at x, y with transparent colour ***************************************************************************************/ /* >>>>>> Using a transparent color is not supported at the moment <<<<<< -void TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y, uint16_t transp) +void TFT_eSprite::pushToSprite(TFT_eSprite *spr, int32_t x, int32_t y, uint16_t transp) { if (!_created) return; diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 5282bbf..3b8d556 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -133,13 +133,14 @@ class TFT_eSprite : public TFT_eSPI { void pushSprite(int32_t x, int32_t y); void pushSprite(int32_t x, int32_t y, uint16_t transparent); - // Push the sprite to another sprite, this fn calls pushImage() in the destination sprite class. - // >>>>>> Using a transparent color is not supported at the moment <<<<<< - bool pushSprite(TFT_eSprite *spr, int32_t x, int32_t y); - // 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. + // >>>>>> Using a transparent color is not supported at the moment <<<<<< + 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); + 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); diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index d373bf2..d1cca5f 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -293,13 +293,26 @@ // Write 8 bits to TFT #define tft_Write_8(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)(C)); WR_H - // Write 16 bits to TFT - #define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)((C) >> 8)); WR_H; \ - GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)((C) >> 0)); WR_H + #if defined (SSD1963_DRIVER) - // 16 bit write with swapped bytes - #define tft_Write_16S(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ - GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H + // Write 18 bit color to TFT + #define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \ + GPIO.out_w1tc = 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) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + + // Write 16 bits to TFT + #define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H + + // 16 bit write with swapped bytes + #define tft_Write_16S(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 0)); WR_H; \ + GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 8)); WR_H + #endif // Write 32 bits to TFT #define tft_Write_32(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) ((C) >> 24)); WR_H; \ diff --git a/TFT_Drivers/SSD1963_Defines.h b/TFT_Drivers/SSD1963_Defines.h index 78fac3e..a047faa 100644 --- a/TFT_Drivers/SSD1963_Defines.h +++ b/TFT_Drivers/SSD1963_Defines.h @@ -11,6 +11,11 @@ #define TFT_HEIGHT 800 #endif +//Set driver type common to all initialisation options +#ifndef SSD1963_DRIVER + #define SSD1963_DRIVER +#endif + // Delay between some initialisation commands #define TFT_INIT_DELAY 0x80 // Not used unless commandlist invoked diff --git a/TFT_Drivers/SSD1963_Init.h b/TFT_Drivers/SSD1963_Init.h index e07f918..0d5da2a 100644 --- a/TFT_Drivers/SSD1963_Init.h +++ b/TFT_Drivers/SSD1963_Init.h @@ -62,7 +62,7 @@ writedata(0x2A); writecommand(0xF0); //pixel data interface - writedata(0x03); + writedata(0x00); //8 bit bus delay(1); @@ -166,7 +166,7 @@ writedata(0x2A); writecommand(0xF0); //pixel data interface - writedata(0x03); + writedata(0x00); //8 bit bus delay(1); @@ -270,7 +270,7 @@ writedata(0x22); // -- Set to 0x21 to rotate 180 degrees writecommand(0xF0); //pixel data interface - writedata(0x03); + writedata(0x00); //8 bit bus delay(10); diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 10b6754..0d942a0 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.19" +#define TFT_ESPI_VERSION "2.2.20" /*************************************************************************************** ** Section 1: Load required header files diff --git a/examples/160 x 128/TFT_SPIFFS_Jpeg/JPEG_functions.ino b/examples/160 x 128/TFT_SPIFFS_Jpeg/JPEG_functions.ino deleted file mode 100644 index 313a2f6..0000000 --- a/examples/160 x 128/TFT_SPIFFS_Jpeg/JPEG_functions.ino +++ /dev/null @@ -1,191 +0,0 @@ -/*==================================================================================== - This sketch contains support functions to render the Jpeg images. - - Created by Bodmer 15th Jan 2017 - ==================================================================================*/ - -// Return the minimum of two values a and b -#define minimum(a,b) (((a) < (b)) ? (a) : (b)) - -//==================================================================================== -// Opens the image file and prime the Jpeg decoder -//==================================================================================== -void drawJpeg(const char *filename, int xpos, int ypos) { - - Serial.println("==========================="); - Serial.print("Drawing file: "); Serial.println(filename); - Serial.println("==========================="); - - // Open the named file (the Jpeg decoder library will close it after rendering image) - fs::File jpegFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS - // File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library - - if ( !jpegFile ) { - Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); - return; - } - - // Use one of the three following methods to initialise the decoder: - //boolean decoded = JpegDec.decodeFsFile(jpegFile); // Pass a SPIFFS file handle to the decoder, - //boolean decoded = JpegDec.decodeSdFile(jpegFile); // or pass the SD file handle to the decoder, - boolean decoded = JpegDec.decodeFsFile(filename); // or pass the filename (leading / distinguishes SPIFFS files) - // Note: the filename can be a String or character array type - if (decoded) { - // print information about the image to the serial port - jpegInfo(); - - // render the image onto the screen at given coordinates - jpegRender(xpos, ypos); - } - else { - Serial.println("Jpeg file format not supported!"); - } -} - -//==================================================================================== -// Decode and render the Jpeg image onto the TFT screen -//==================================================================================== -void jpegRender(int xpos, int ypos) { - - // retrieve infomration about the image - uint16_t *pImg; - uint16_t mcu_w = JpegDec.MCUWidth; - uint16_t mcu_h = JpegDec.MCUHeight; - uint32_t max_x = JpegDec.width; - uint32_t max_y = JpegDec.height; - - // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) - // Typically these MCUs are 16x16 pixel blocks - // Determine the width and height of the right and bottom edge image blocks - uint32_t min_w = minimum(mcu_w, max_x % mcu_w); - uint32_t min_h = minimum(mcu_h, max_y % mcu_h); - - // save the current image block size - uint32_t win_w = mcu_w; - uint32_t win_h = mcu_h; - - // record the current time so we can measure how long it takes to draw an image - uint32_t drawTime = millis(); - - // save the coordinate of the right and bottom edges to assist image cropping - // to the screen size - max_x += xpos; - max_y += ypos; - - // read each MCU block until there are no more - while ( JpegDec.readSwappedBytes()) { // Swap byte order so the SPI buffer can be used - - // save a pointer to the image block - pImg = JpegDec.pImage; - - // calculate where the image block should be drawn on the screen - int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU - int mcu_y = JpegDec.MCUy * mcu_h + ypos; - - // check if the image block size needs to be changed for the right edge - if (mcu_x + mcu_w <= max_x) win_w = mcu_w; - else win_w = min_w; - - // check if the image block size needs to be changed for the bottom edge - if (mcu_y + mcu_h <= max_y) win_h = mcu_h; - else win_h = min_h; - - // copy pixels into a contiguous block - if (win_w != mcu_w) - { - uint16_t *cImg; - int p = 0; - cImg = pImg + win_w; - for (int h = 1; h < win_h; h++) - { - p += mcu_w; - for (int w = 0; w < win_w; w++) - { - *cImg = *(pImg + w + p); - cImg++; - } - } - } - - // draw image MCU block only if it will fit on the screen - if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) - { - tft.pushRect(mcu_x, mcu_y, win_w, win_h, pImg); - } - - else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); - - } - - // calculate how long it took to draw the image - drawTime = millis() - drawTime; // Calculate the time it took - - // print the results to the serial port - Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); - Serial.println("====================================="); - -} - -//==================================================================================== -// Print information decoded from the Jpeg image -//==================================================================================== -void jpegInfo() { - - Serial.println("==============="); - Serial.println("JPEG image info"); - Serial.println("==============="); - Serial.print ("Width :"); Serial.println(JpegDec.width); - Serial.print ("Height :"); Serial.println(JpegDec.height); - Serial.print ("Components :"); Serial.println(JpegDec.comps); - Serial.print ("MCU / row :"); Serial.println(JpegDec.MCUSPerRow); - Serial.print ("MCU / col :"); Serial.println(JpegDec.MCUSPerCol); - Serial.print ("Scan type :"); Serial.println(JpegDec.scanType); - Serial.print ("MCU width :"); Serial.println(JpegDec.MCUWidth); - Serial.print ("MCU height :"); Serial.println(JpegDec.MCUHeight); - Serial.println("==============="); - Serial.println(""); -} - -//==================================================================================== -// Open a Jpeg file and send it to the Serial port in a C array compatible format -//==================================================================================== -void createArray(const char *filename) { - - // Open the named file - fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS - // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library - - if ( !jpgFile ) { - Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); - return; - } - - uint8_t data; - byte line_len = 0; - Serial.println(""); - Serial.println("// Generated by a JPEGDecoder library example sketch:"); - Serial.println("// https://github.com/Bodmer/JPEGDecoder"); - Serial.println(""); - Serial.println("#include "); - Serial.println("// Remove leading / from array name!"); - Serial.print ("const uint8_t "); - while (*filename != '.') Serial.print(*filename++); - Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due - - while ( jpgFile.available()) { - - data = jpgFile.read(); - Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); - Serial.print(data, HEX); Serial.print(",");// Add value and comma - line_len++; - if ( line_len >= 32) { - line_len = 0; - Serial.println(); - } - - } - - Serial.println("};\r\n"); - jpgFile.close(); -} -//==================================================================================== diff --git a/examples/160 x 128/TFT_SPIFFS_Jpeg/SPIFFS_functions.ino b/examples/160 x 128/TFT_SPIFFS_Jpeg/SPIFFS_functions.ino deleted file mode 100644 index a0f8225..0000000 --- a/examples/160 x 128/TFT_SPIFFS_Jpeg/SPIFFS_functions.ino +++ /dev/null @@ -1,36 +0,0 @@ -/*==================================================================================== - This sketch contains support functions for the ESP6266 SPIFFS filing system - - Created by Bodmer 15th Jan 2017 - ==================================================================================*/ - -//==================================================================================== -// Print a SPIFFS directory list (root directory) -//==================================================================================== - -void listFiles(void) { - Serial.println(); - Serial.println("SPIFFS files found:"); - - fs::Dir dir = SPIFFS.openDir("/"); // Root directory - String line = "====================================="; - - Serial.println(line); - Serial.println(" File name Size"); - Serial.println(line); - - while (dir.next()) { - String fileName = dir.fileName(); - Serial.print(fileName); - int spaces = 25 - fileName.length(); // Tabulate nicely - while (spaces--) Serial.print(" "); - fs::File f = dir.openFile("r"); - Serial.print(f.size()); Serial.println(" bytes"); - } - - Serial.println(line); - Serial.println(); - delay(1000); -} -//==================================================================================== - diff --git a/examples/160 x 128/TFT_SPIFFS_Jpeg/TFT_SPIFFS_Jpeg.ino b/examples/160 x 128/TFT_SPIFFS_Jpeg/TFT_SPIFFS_Jpeg.ino deleted file mode 100644 index f500a47..0000000 --- a/examples/160 x 128/TFT_SPIFFS_Jpeg/TFT_SPIFFS_Jpeg.ino +++ /dev/null @@ -1,129 +0,0 @@ -/*==================================================================================== - - This sketch demonstrates loading images which have been stored as files in the - built-in FLASH memory on a NodeMCU 1.0 (ESP8266 based, ESP-12E Module) rendering the - images onto a 160 x 128 pixel TFT screen. - - The images are stored in the SPI FLASH Filing System (SPIFFS), which effectively - functions like a tiny "hard drive". This filing system is built into the ESP8266 - Core that can be loaded from the IDE "Boards manager" menu option. This is at - version 2.3.0 at the time of sketch creation. - - The size of the SPIFFS partition can be set in the IDE as 1Mbyte or 3Mbytes. Either - will work with this sketch. Typically most sketches easily fit within 1 Mbyte so a - 3 Mbyte SPIFS partition can be used, in which case it can contain 100's of Jpeg - full screem images. - - The Jpeg library can be found here: - https://github.com/Bodmer/JPEGDecoder - - Images in the Jpeg format can be created using Paint or IrfanView or other picture - editting software. - - Place the images inside the sketch folder, in a folder called "Data". Then upload - all the files in the folder using the Arduino IDE "ESP8266 Sketch Data Upload" option - in the "Tools" menu: - http://www.esp8266.com/viewtopic.php?f=32&t=10081 - https://github.com/esp8266/arduino-esp8266fs-plugin/releases - - This takes some time, but the SPIFFS content is not altered when a new sketch is - uploaded, so there is no need to upload the same files again! - Note: If open, you must close the "Serial Monitor" window to upload data to SPIFFS! - - The IDE will not copy the "data" folder with the sketch if you save the sketch under - another name. It is necessary to manually make a copy and place it in the sketch - folder. - - This sketch includes example images in the Data folder. - - Saving images, uploading and rendering on the TFT screen couldn't be much easier! - - Created by Bodmer 24th Jan 2017 - Tested in Arduino IDE 1.8.0 esp8266 Core 2.3.0 - ==================================================================================*/ - -//==================================================================================== -// Libraries -//==================================================================================== -// Call up the SPIFFS FLASH filing system this is part of the ESP Core -#define FS_NO_GLOBALS -#include - -// JPEG decoder library -#include - -// SPI library, built into IDE -#include - -// Call up the TFT library -#include // Hardware-specific library for ESP8266 -// The TFT control pins are set in the User_Setup.h file <<<<<<<<<<<<<<<<< NOTE! -// that can be found in the "src" folder of the library - -// Invoke TFT library -TFT_eSPI tft = TFT_eSPI(); - -//==================================================================================== -// Setup -//==================================================================================== -void setup() -{ - Serial.begin(250000); // Used for messages and the C array generator - - delay(10); - Serial.println("NodeMCU decoder test!"); - - tft.begin(); - tft.setRotation(0); // 0 & 2 Portrait. 1 & 3 landscape - tft.fillScreen(TFT_BLACK); - - if (!SPIFFS.begin()) { - Serial.println("SPIFFS initialisation failed!"); - while (1) yield(); // Stay here twiddling thumbs waiting - } - Serial.println("\r\nInitialisation done."); - listFiles(); // Lists the files so you can see what is in the SPIFFS - -} - -//==================================================================================== -// Loop -//==================================================================================== -void loop() -{ - // Note the / before the SPIFFS file name must be present, this means the file is in - // the root directory of the SPIFFS, e.g. "/Tiger.jpg" for a file called "Tiger.jpg" - - tft.setRotation(0); // portrait - tft.fillScreen(random(0xFFFF)); - - drawJpeg("/EagleEye160.jpg", 0, 16); - delay(2000); - - tft.fillScreen(random(0xFFFF)); - drawJpeg("/tiger160.jpg", 4, 0); - delay(2000); - - tft.setRotation(1); // landscape - //tft.fillScreen(random(0xFFFF)); - drawJpeg("/arduino160.jpg", 0, 0); - delay(2000); - - tft.fillScreen(TFT_BLACK); - drawJpeg("/Baboon160.jpg", 0, 4); - delay(2000); - - tft.fillScreen(random(0xFFFF)); - drawJpeg("/Mouse160.jpg", 0, 11); - delay(2000); - - // Create arrays from the jpeg images and send them to the serial port for copy and - // pasting into a sketch (used to make arrays fot the TFT_FLASH_Jpeg sketch) - - //createArray("/EagleEye160.jpg"); - //createArray("/tiger160.jpg"); - //createArray("/Baboon160.jpg"); - //createArray("/Mouse160.jpg"); - //while(1) yield(); // Stay here -} -//==================================================================================== - diff --git a/examples/Generic/ESP32_SDcard_jpeg/ESP32_SDcard_jpeg.ino b/examples/Generic/ESP32_SDcard_jpeg/ESP32_SDcard_jpeg.ino index 9cc8b02..b0e09e2 100644 --- a/examples/Generic/ESP32_SDcard_jpeg/ESP32_SDcard_jpeg.ino +++ b/examples/Generic/ESP32_SDcard_jpeg/ESP32_SDcard_jpeg.ino @@ -153,8 +153,8 @@ void jpegRender(int xpos, int ypos) { // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) // Typically these MCUs are 16x16 pixel blocks // Determine the width and height of the right and bottom edge image blocks - uint32_t min_w = min(mcu_w, max_x % mcu_w); - uint32_t min_h = min(mcu_h, max_y % mcu_h); + uint32_t min_w = jpg_min(mcu_w, max_x % mcu_w); + uint32_t min_h = jpg_min(mcu_h, max_y % mcu_h); // save the current image block size uint32_t win_w = mcu_w; diff --git a/library.json b/library.json index 7a8389f..b870467 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.19", + "version": "2.2.20", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 4e053eb..3ad1b2a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.19 +version=2.2.20 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 0c49b71dd434b938628377f655acb5186e4c0ddc Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 14 Sep 2020 21:40:20 +0100 Subject: [PATCH 39/42] Fix #751 --- Extensions/Sprite.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 828ce8e..2c8a88b 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -446,7 +446,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) int32_t yt = min_y - _tft->_ypivot; uint32_t xe = _dwidth << FP_SCALE; uint32_t ye = _dheight << FP_SCALE; - uint32_t tpcolor = transp; // convert to unsigned + uint16_t tpcolor = transp; // convert to unsigned 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 @@ -462,7 +462,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp) uint32_t pixel_count = 0; do { - uint32_t rp; + uint16_t rp; int32_t xp = xs >> FP_SCALE; int32_t yp = ys >> FP_SCALE; if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; } @@ -517,7 +517,7 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) int32_t yt = min_y - spr->_yPivot; uint32_t xe = _dwidth << FP_SCALE; uint32_t ye = _dheight << FP_SCALE; - uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes + uint16_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes bool oldSwapBytes = spr->getSwapBytes(); spr->setSwapBytes(false); @@ -533,7 +533,7 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp) uint32_t pixel_count = 0; do { - uint32_t rp; + uint16_t rp; int32_t xp = xs >> FP_SCALE; int32_t yp = ys >> FP_SCALE; if (_bpp == 16) rp = _img[xp + yp * _iwidth]; From 49cef1f35dc264e94632397d7eb2350fba69f2b1 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 2 Oct 2020 01:07:15 +0100 Subject: [PATCH 40/42] Support for SSD1963 and ST7706 SPI read The SSD1963 support has been tested with a 480x800 pixel display from Buy Display. Support for reading an ST7796 SPI display has been added. pushToSprite added to keywords list. --- Processors/TFT_eSPI_ESP32.c | 8 +- Processors/TFT_eSPI_STM32.c | 54 +++++++---- Processors/TFT_eSPI_STM32.h | 126 ++++++++++++++++++++++++- TFT_Drivers/SSD1963_Defines.h | 3 + TFT_Drivers/SSD1963_Init.h | 98 ++++++++++++++++++- TFT_Drivers/SSD1963_Rotation.h | 31 +----- TFT_eSPI.cpp | 90 ++++++++++++------ TFT_eSPI.h | 8 +- User_Setup_Select.h | 5 + User_Setups/Setup14_ILI9341_Parallel.h | 2 +- User_Setups/Setup29_ILI9341_STM32.h | 30 ++++-- User_Setups/Setup50_SSD1963_Parallel.h | 92 ++++++++++++++++++ keywords.txt | 1 + library.json | 2 +- library.properties | 2 +- 15 files changed, 458 insertions(+), 94 deletions(-) create mode 100644 User_Setups/Setup50_SSD1963_Parallel.h diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index d83424c..b866d28 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -457,7 +457,11 @@ 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 while (--len) {WR_L; WR_H; WR_L; WR_H;} + #endif } else while (len--) {tft_Write_16(color);} } @@ -649,8 +653,8 @@ 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; + if ((bool)spi_tx->user) {DC_D;} + else {DC_C;} } /*************************************************************************************** diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index 1982b84..dc42e67 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -84,24 +84,42 @@ void TFT_eSPI::end_SDA_Read(void) ** Description: Write a block of pixels of the same colour ***************************************************************************************/ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - // Loop unrolling improves speed dramtically graphics test 0.634s => 0.374s - while (len>31) { - // 32D macro writes 16 bits twice - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - len-=32; - } - while (len>7) { - tft_Write_32D(color); tft_Write_32D(color); - tft_Write_32D(color); tft_Write_32D(color); - len-=8; - } + // Loop unrolling improves speed dramtically graphics test 0.634s => 0.374s + while (len>31) { + #if !defined (SSD1963_DRIVER) + // 32D macro writes 16 bits twice + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + #else + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + #endif + len-=32; + } + + while (len>7) { + #if !defined (SSD1963_DRIVER) + tft_Write_32D(color); tft_Write_32D(color); + tft_Write_32D(color); tft_Write_32D(color); + #else + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); + #endif + len-=8; + } + while (len--) {tft_Write_16(color);} } diff --git a/Processors/TFT_eSPI_STM32.h b/Processors/TFT_eSPI_STM32.h index 6b627d8..943fe2b 100644 --- a/Processors/TFT_eSPI_STM32.h +++ b/Processors/TFT_eSPI_STM32.h @@ -411,6 +411,31 @@ GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \ WR_STB // Need to slow down strobe + #if defined (SSD1963_DRIVER) + + // Write 18 bit color to TFT (untested) + #define tft_Write_16(C) uint8_t r = (((C) & 0xF800)>> 8); uint8_t g = (((C) & 0x07E0)>> 3); uint8_t b = (((C) & 0x001F)<< 3); \ + GPIOA->BSRR = D0_BSR_MASK(r) | D2_BSR_MASK(r) | D7_BSR_MASK(r); \ + WR_L; \ + GPIOC->BSRR = D1_BSR_MASK(r); \ + GPIOB->BSRR = D3_BSR_MASK(r) | D4_BSR_MASK(r) | D5_BSR_MASK(r) | D6_BSR_MASK(r); \ + WR_STB; \ + GPIOA->BSRR = D0_BSR_MASK(g) | D2_BSR_MASK(g) | D7_BSR_MASK(g); \ + WR_L; \ + GPIOC->BSRR = D1_BSR_MASK(g); \ + GPIOB->BSRR = D3_BSR_MASK(g) | D4_BSR_MASK(g) | D5_BSR_MASK(g) | D6_BSR_MASK(g); \ + WR_STB; \ + GPIOA->BSRR = D0_BSR_MASK(b) | D2_BSR_MASK(b) | D7_BSR_MASK(b); \ + WR_L; \ + GPIOC->BSRR = D1_BSR_MASK(b); \ + GPIOB->BSRR = D3_BSR_MASK(b) | D4_BSR_MASK(b) | D5_BSR_MASK(b) | D6_BSR_MASK(b); \ + WR_STB // Need to slow down strobe + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + // Write 16 bits to TFT #define tft_Write_16(C) GPIOA->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D15_BSR_MASK(C); \ WR_L; \ @@ -434,6 +459,7 @@ GPIOC->BSRR = D9_BSR_MASK(C); \ GPIOB->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \ WR_STB + #endif #define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C)) @@ -527,6 +553,31 @@ GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \ WR_STB + #if defined (SSD1963_DRIVER) + + // Write 18 bit color to TFT (untested) + #define tft_Write_16(C) uint8_t r = (((C) & 0xF800)>> 8); uint8_t g = (((C) & 0x07E0)>> 3); uint8_t b = (((C) & 0x001F)<< 3); \ + GPIOF->BSRR = D0_BSR_MASK(r) | D2_BSR_MASK(r) | D4_BSR_MASK(r) | D7_BSR_MASK(r); \ + WR_L; \ + GPIOD->BSRR = D1_BSR_MASK(r); \ + GPIOE->BSRR = D3_BSR_MASK(r) | D5_BSR_MASK(r) | D6_BSR_MASK(r); \ + WR_STB; \ + GPIOF->BSRR = D0_BSR_MASK(g) | D2_BSR_MASK(g) | D4_BSR_MASK(g) | D7_BSR_MASK(g); \ + WR_L; \ + GPIOD->BSRR = D1_BSR_MASK(g); \ + GPIOE->BSRR = D3_BSR_MASK(g) | D5_BSR_MASK(g) | D6_BSR_MASK(g); \ + WR_STB; \ + GPIOF->BSRR = D0_BSR_MASK(b) | D2_BSR_MASK(b) | D4_BSR_MASK(b) | D7_BSR_MASK(b); \ + WR_L; \ + GPIOD->BSRR = D1_BSR_MASK(b); \ + GPIOE->BSRR = D3_BSR_MASK(b) | D5_BSR_MASK(b) | D6_BSR_MASK(b); \ + WR_STB // Need to slow down strobe + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + // Write 16 bits to TFT #define tft_Write_16(C) GPIOF->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D12_BSR_MASK(C) | D15_BSR_MASK(C); \ WR_L; \ @@ -551,6 +602,8 @@ GPIOE->BSRR = D11_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \ WR_STB + #endif + #define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C)) #define tft_Write_32C(C,D) tft_Write_16((uint16_t)(C)); tft_Write_16((uint16_t)(D)) @@ -672,7 +725,20 @@ // Write 8 bits to TFT #define tft_Write_8(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C)); WR_L; WR_STB - + + #if defined (SSD1963_DRIVER) + + // Write 18 bit color to TFT (untested) + #define tft_Write_16(C) uint8_t r = (((C) & 0xF800)>> 8); uint8_t g = (((C) & 0x07E0)>> 3); uint8_t b = (((C) & 0x001F)<< 3); \ + GPIOA->BSRR = (0x00FF0000 | (uint8_t)(r)); WR_L; WR_STB; \ + GPIOA->BSRR = (0x00FF0000 | (uint8_t)(g)); WR_L; WR_STB; \ + GPIOA->BSRR = (0x00FF0000 | (uint8_t)(b)); WR_L; WR_STB + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + // Write 16 bits to TFT #define tft_Write_16(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB; \ GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB @@ -680,6 +746,7 @@ // 16 bit write with swapped bytes #define tft_Write_16S(C) GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB; \ GPIOA->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB + #endif #define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C)) @@ -701,7 +768,20 @@ // Write 8 bits to TFT #define tft_Write_8(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C)); WR_L; WR_STB - + + #if defined (SSD1963_DRIVER) + + // Write 18 bit color to TFT (untested) + #define tft_Write_16(C) uint8_t r = (((C) & 0xF800)>> 8); uint8_t g = (((C) & 0x07E0)>> 3); uint8_t b = (((C) & 0x001F)<< 3); \ + GPIOB->BSRR = (0x00FF0000 | (uint8_t)(r)); WR_L; WR_STB; \ + GPIOB->BSRR = (0x00FF0000 | (uint8_t)(g)); WR_L; WR_STB; \ + GPIOB->BSRR = (0x00FF0000 | (uint8_t)(b)); WR_L; WR_STB + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + // Write 16 bits to TFT #define tft_Write_16(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB; \ GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB @@ -709,6 +789,7 @@ // 16 bit write with swapped bytes #define tft_Write_16S(C) GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>0)); WR_L; WR_STB; \ GPIOB->BSRR = (0x00FF0000 | (uint8_t)(C>>8)); WR_L; WR_STB + #endif #define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C)) @@ -801,6 +882,46 @@ D7_PIN_PORT->BSRR = D7_BSR_MASK(C); \ WR_STB + #if defined (SSD1963_DRIVER) + + // Write 18 bit color to TFT (untested) + #define tft_Write_16(C) uint8_t r = (((C) & 0xF800)>> 8); uint8_t g = (((C) & 0x07E0)>> 3); uint8_t b = (((C) & 0x001F)<< 3); \ + D0_PIN_PORT->BSRR = D8_BSR_MASK(r); \ + D1_PIN_PORT->BSRR = D9_BSR_MASK(r); \ + D2_PIN_PORT->BSRR = D10_BSR_MASK(r); \ + D3_PIN_PORT->BSRR = D11_BSR_MASK(r); \ + WR_L; \ + D4_PIN_PORT->BSRR = D12_BSR_MASK(r); \ + D5_PIN_PORT->BSRR = D13_BSR_MASK(r); \ + D6_PIN_PORT->BSRR = D14_BSR_MASK(r); \ + D7_PIN_PORT->BSRR = D15_BSR_MASK(r); \ + WR_STB;\ + D0_PIN_PORT->BSRR = D8_BSR_MASK(g); \ + D1_PIN_PORT->BSRR = D9_BSR_MASK(g); \ + D2_PIN_PORT->BSRR = D10_BSR_MASK(g); \ + D3_PIN_PORT->BSRR = D11_BSR_MASK(g); \ + WR_L; \ + D4_PIN_PORT->BSRR = D12_BSR_MASK(g); \ + D5_PIN_PORT->BSRR = D13_BSR_MASK(g); \ + D6_PIN_PORT->BSRR = D14_BSR_MASK(g); \ + D7_PIN_PORT->BSRR = D15_BSR_MASK(g); \ + WR_STB;\ + D0_PIN_PORT->BSRR = D0_BSR_MASK(b); \ + D1_PIN_PORT->BSRR = D1_BSR_MASK(b); \ + D2_PIN_PORT->BSRR = D2_BSR_MASK(b); \ + D3_PIN_PORT->BSRR = D3_BSR_MASK(b); \ + WR_L; \ + D4_PIN_PORT->BSRR = D4_BSR_MASK(b); \ + D5_PIN_PORT->BSRR = D5_BSR_MASK(b); \ + D6_PIN_PORT->BSRR = D6_BSR_MASK(b); \ + D7_PIN_PORT->BSRR = D7_BSR_MASK(b); \ + WR_STB + + // 18 bit color write with swapped bytes + #define tft_Write_16S(C) uint16_t Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap) + + #else + // Write 16 bits to TFT #define tft_Write_16(C) D0_PIN_PORT->BSRR = D8_BSR_MASK(C); \ D1_PIN_PORT->BSRR = D9_BSR_MASK(C); \ @@ -844,6 +965,7 @@ D6_PIN_PORT->BSRR = D14_BSR_MASK(C); \ D7_PIN_PORT->BSRR = D15_BSR_MASK(C); \ WR_STB + #endif #define tft_Write_32(C) tft_Write_16((uint16_t)((C)>>16)); tft_Write_16((uint16_t)(C)) diff --git a/TFT_Drivers/SSD1963_Defines.h b/TFT_Drivers/SSD1963_Defines.h index a047faa..1c3e913 100644 --- a/TFT_Drivers/SSD1963_Defines.h +++ b/TFT_Drivers/SSD1963_Defines.h @@ -9,6 +9,9 @@ #elif defined (SSD1963_800ALT_DRIVER) #define TFT_WIDTH 480 #define TFT_HEIGHT 800 +#elif defined (SSD1963_800BD_DRIVER) + #define TFT_WIDTH 480 + #define TFT_HEIGHT 800 #endif //Set driver type common to all initialisation options diff --git a/TFT_Drivers/SSD1963_Init.h b/TFT_Drivers/SSD1963_Init.h index 0d5da2a..f785961 100644 --- a/TFT_Drivers/SSD1963_Init.h +++ b/TFT_Drivers/SSD1963_Init.h @@ -59,7 +59,7 @@ writedata(0x01); //GPIO0 normal writecommand(0x36); //rotation - writedata(0x2A); + writedata(0x21 | TFT_MAD_COLOR_ORDER); writecommand(0xF0); //pixel data interface writedata(0x00); //8 bit bus @@ -163,7 +163,7 @@ writedata(0x01); //GPIO0 normal writecommand(0x36); //rotation - writedata(0x2A); + writedata(0x21 | TFT_MAD_COLOR_ORDER); writecommand(0xF0); //pixel data interface writedata(0x00); //8 bit bus @@ -267,7 +267,7 @@ writedata(0x01); //GPIO0 normal writecommand(0x36); //rotation - writedata(0x22); // -- Set to 0x21 to rotate 180 degrees + writedata(0x21 | TFT_MAD_COLOR_ORDER); // -- Set rotation writecommand(0xF0); //pixel data interface writedata(0x00); //8 bit bus @@ -303,4 +303,96 @@ writecommand(0x2C); +#elif defined (SSD1963_800BD_DRIVER) // Copied from Buy Display code + + writecommand(0xE2); //PLL multiplier, set PLL clock to 120M + writedata(0x23); //N=0x36 for 6.5M, 0x23 for 10M crystal + writedata(0x02); + writedata(0x54); + + writecommand(0xE0); // PLL enable + writedata(0x01); + + delay(10); + + writecommand(0xE0); + writedata(0x03); + + delay(10); + + writecommand(0x01); // software reset + + delay(100); + + writecommand(0xE6); //PLL setting for PCLK, depends on resolution + writedata(0x03); + writedata(0x33); + writedata(0x33); + + writecommand(0xB0); //LCD SPECIFICATION + writedata(0x20); + writedata(0x00); + writedata(799 >> 8); //Set HDP 799 + writedata(799 & 0xFF); + writedata(479 >> 8); //Set VDP 479 + writedata(479 & 0xFF); + writedata(0x00); + + writecommand(0xB4); //HSYNC + writedata(0x04); //Set HT + writedata(0x1F); + writedata(0x00); //Set HPS + writedata(0xD2); + writedata(0x00); //Set HPW + writedata(0x00); //Set LPS + writedata(0x00); + writedata(0x00); + + writecommand(0xB6); //VSYNC + writedata(0x02); //Set VT + writedata(0x0C); + writedata(0x00); //Set VPS + writedata(0x22); + writedata(0x00); //Set VPW + writedata(0x00); //Set FPS + writedata(0x00); + + writecommand(0xB8); + writedata(0x0F); //GPIO3=input, GPIO[2:0]=output + writedata(0x01); //GPIO0 normal + + writecommand(0xBA); + writedata(0x01); //GPIO[0] out 1 --- LCD display on/off control PIN + + writecommand(0x36); //rotation + writedata(0x21 | TFT_MAD_COLOR_ORDER); //set to rotate + + //writecommand(0x003A); //Set the current pixel format for RGB image data + //writedata(0x0050); //16-bit/pixel + + writecommand(0xF0); //pixel data interface + writedata(0x00); //000 = 8 bit bus, 011 = 16 bit, 110 = 9 bit + + writecommand(0xBC); + writedata(0x40); //contrast value + writedata(0x80); //brightness value + writedata(0x40); //saturation value + writedata(0x01); //Post Processor Enable + + + delay(10); + + writecommand(0x29); //display on + + writecommand(0xBE); //set PWM for B/L + writedata(0x06); + writedata(0x80); + writedata(0x01); + writedata(0xF0); + writedata(0x00); + writedata(0x00); + + writecommand(0xD0); + writedata(0x0D); + #endif \ No newline at end of file diff --git a/TFT_Drivers/SSD1963_Rotation.h b/TFT_Drivers/SSD1963_Rotation.h index c0fd611..6e61171 100644 --- a/TFT_Drivers/SSD1963_Rotation.h +++ b/TFT_Drivers/SSD1963_Rotation.h @@ -1,48 +1,27 @@ // This is the command sequence that rotates the SSD1963 driver coordinate frame - rotation = m % 8; // Limit the range of values to 0-7 + rotation = m % 4; // Limit the range of values to 0-3 writecommand(TFT_MADCTL); switch (rotation) { case 0: - writedata(TFT_MAD_MX | TFT_MAD_COLOR_ORDER); + writedata(0x21 | TFT_MAD_COLOR_ORDER); _width = _init_width; _height = _init_height; break; case 1: - writedata(TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + writedata(0x00 | TFT_MAD_COLOR_ORDER); _width = _init_height; _height = _init_width; break; case 2: - writedata(TFT_MAD_MY | TFT_MAD_COLOR_ORDER); + writedata(0x22 | TFT_MAD_COLOR_ORDER); _width = _init_width; _height = _init_height; break; case 3: - writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); - _width = _init_height; - _height = _init_width; - break; - // These next rotations are for bottom up BMP drawing - case 4: - writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_COLOR_ORDER); - _width = _init_width; - _height = _init_height; - break; - case 5: - writedata(TFT_MAD_MV | TFT_MAD_MX | TFT_MAD_COLOR_ORDER); - _width = _init_height; - _height = _init_width; - break; - case 6: - writedata(TFT_MAD_COLOR_ORDER); - _width = _init_width; - _height = _init_height; - break; - case 7: - writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); + writedata(0x03 | TFT_MAD_COLOR_ORDER); _width = _init_height; _height = _init_width; break; diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index b01e4e7..ab3f3ca 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -105,6 +105,11 @@ inline void TFT_eSPI::end_tft_read(void){ if(!inTransaction) {CS_H;} #endif SET_BUS_WRITE_MODE; + +// The ST7796 appears to need a 4ms delay after a CGRAM read, otherwise subsequent writes will fail! +#ifdef ST7796_DRIVER + delay(4); +#endif } /*************************************************************************************** @@ -395,13 +400,7 @@ void TFT_eSPI::init(uint8_t tc) #elif defined (ST7789_2_DRIVER) #include "TFT_Drivers/ST7789_2_Init.h" -#elif defined (SSD1963_480_DRIVER) - #include "TFT_Drivers/SSD1963_Init.h" - -#elif defined (SSD1963_800_DRIVER) - #include "TFT_Drivers/SSD1963_Init.h" - -#elif defined (SSD1963_800ALT_DRIVER) +#elif defined (SSD1963_DRIVER) #include "TFT_Drivers/SSD1963_Init.h" #endif @@ -480,6 +479,9 @@ void TFT_eSPI::setRotation(uint8_t m) #elif defined (ST7789_2_DRIVER) #include "TFT_Drivers/ST7789_2_Rotation.h" +#elif defined (SSD1963_DRIVER) + #include "TFT_Drivers/SSD1963_Rotation.h" + #endif delayMicroseconds(10); @@ -708,6 +710,8 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) bool wasInTransaction = inTransaction; if (inTransaction) { inTransaction= false; end_tft_write();} + uint16_t color = 0; + begin_tft_read(); readAddrWindow(x0, y0, 1, 1); // Sets CS low @@ -721,11 +725,18 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) //#if !defined (ILI9488_DRIVER) - // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte - // as the TFT stores colours as 18 bits - uint8_t r = tft_Read_8(); - uint8_t g = tft_Read_8(); - uint8_t b = tft_Read_8(); + #if defined (ST7796_DRIVER) + // Read the 2 bytes + color = ((tft_Read_8()) << 8) | (tft_Read_8()); + #else + // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte + // as the TFT stores colours as 18 bits + uint8_t r = tft_Read_8(); + uint8_t g = tft_Read_8(); + uint8_t b = tft_Read_8(); + color = color565(r, g, b); + #endif + /* #else @@ -734,6 +745,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) uint8_t r = (tft_Read_8()&0x7E)<<1; uint8_t g = (tft_Read_8()&0x7E)<<1; uint8_t b = (tft_Read_8()&0x7E)<<1; + color = color565(r, g, b); #endif */ @@ -748,7 +760,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) // Reinstate the transaction if one was in progress if(wasInTransaction) { begin_tft_write(); inTransaction = true; } - return color565(r, g, b); + return color; #endif } @@ -815,6 +827,8 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da #else // SPI interface + uint16_t color = 0; + begin_tft_read(); readAddrWindow(x, y, w, h); @@ -830,29 +844,35 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da uint32_t len = w * h; while (len--) { - #if !defined (ILI9488_DRIVER) - - // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte - // as the TFT stores colours as 18 bits - uint8_t r = tft_Read_8(); - uint8_t g = tft_Read_8(); - uint8_t b = tft_Read_8(); + #if !defined (ILI9488_DRIVER) + #if defined (ST7796_DRIVER) + // Read the 2 bytes + color = ((tft_Read_8()) << 8) | (tft_Read_8()); #else + // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte + // as the TFT stores colours as 18 bits + uint8_t r = tft_Read_8(); + uint8_t g = tft_Read_8(); + uint8_t b = tft_Read_8(); + color = color565(r, g, b); + #endif + + #else // The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left uint8_t r = (tft_Read_8()&0x7E)<<1; uint8_t g = (tft_Read_8()&0x7E)<<1; uint8_t b = (tft_Read_8()&0x7E)<<1; - - #endif + color = color565(r, g, b); + #endif // Swapped colour byte order for compatibility with pushRect() - *data++ = (r & 0xF8) | (g & 0xE0) >> 5 | (b & 0xF8) << 5 | (g & 0x1C) << 11; + *data++ = color << 8 | color >> 8; } - CS_H; + //CS_H; #ifdef TFT_SDA_READ end_SDA_Read(); @@ -2620,6 +2640,10 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //begin_tft_write(); // Must be called before setWindow +#if defined (SSD1963_DRIVER) + if ((rotation & 0x1) == 0) { swap_coord(x0, y0); swap_coord(x1, y1); } +#endif + addr_row = 0xFFFF; addr_col = 0xFFFF; @@ -2662,6 +2686,10 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) ye += rowstart; #endif +#if defined (SSD1963_DRIVER) + if ((rotation & 0x1) == 0) { swap_coord(xs, ys); swap_coord(xe, ye); } +#endif + // Column addr set DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(xs, xe); @@ -2693,6 +2721,10 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) y+=rowstart; #endif +#if defined (SSD1963_DRIVER) + if ((rotation & 0x1) == 0) { swap_coord(x, y); } +#endif + begin_tft_write(); #ifdef MULTI_TFT_SUPPORT @@ -3769,11 +3801,11 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 padding += 2; break; } - // Check coordinates are OK, adjust if not +/* // Check coordinates are OK, adjust if not if (poX < 0) poX = 0; if (poX+cwidth > width()) poX = width() - cwidth; if (poY < 0) poY = 0; - if (poY+cheight-baseline> height()) poY = height() - cheight; + if (poY+cheight-baseline> height()) poY = height() - cheight; //*/ } @@ -3851,9 +3883,8 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 break; case 2: fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor); - padXc = (padX-cwidth)>>1; - if (padXc>poX) padXc = poX; - fillRect(poX - padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor); + padXc = poX - ((padX-cwidth)>>1); + fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor); break; case 3: if (padXc>padX) padXc = padX; @@ -3882,7 +3913,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 case 2: drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE); padXc = (padX-sumX)>>1; - if (padXc>poX) padXc = poX; drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE); break; case 3: diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 0d942a0..d4fdd50 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.20" +#define TFT_ESPI_VERSION "2.2.21" /*************************************************************************************** ** Section 1: Load required header files @@ -578,7 +578,7 @@ class TFT_eSPI : public Print { uint32_t alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8_t dither = 0); - // DMA support functions - these are currently just for SPI writes whe using the STM32 processors + // DMA support functions - these are currently just for SPI writes when using the ESP32 or STM32 processors // 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". @@ -593,7 +593,7 @@ class TFT_eSPI : public Print { // processor leaves a function or its content being changed while the DMA engine is reading it. // // The compiler MAY change the implied scope of a buffer which has been set aside by creating - // and an array. For example a buffer defined before a "for-next" loop may get de-allocated when + // an array. For example a buffer defined before a "for-next" loop may get de-allocated when // the loop ends. To avoid this use, for example, malloc() and free() to take control of when // the buffer space is available and ensure it is not released until DMA is complete. // @@ -608,7 +608,7 @@ class TFT_eSPI : public Print { // Push an image to the TFT using DMA, buffer is optional and grabs (double buffers) a copy of the image // Use the buffer if the image data will get over-written or destroyed while DMA is in progress - // If swapping colour bytes is defined, and the double buffer option is NOT used then the bytes + // If swapping colour bytes is defined, and the double buffer option is NOT used, then the bytes // in the original data image will be swapped by the function before DMA is initiated. // The function will wait for the last DMA to complete if it is called while a previous DMA is still // in progress, this simplifies the sketch and helps avoid "gotchas". diff --git a/User_Setup_Select.h b/User_Setup_Select.h index ec0fdfd..a8dcdb6 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -72,6 +72,8 @@ //#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 //#include // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240 +//#include // Setup file for ESP32 and SSD1963 TFT display + //#include // Setup file for ESP8266 and ST7789 135 x 240 TFT //#include @@ -161,6 +163,9 @@ #include "TFT_Drivers/SSD1963_Defines.h" #define TFT_DRIVER 0x1963 #elif defined (SSD1963_800ALT_DRIVER) + #include "TFT_Drivers/SSD1963_Defines.h" + #define TFT_DRIVER 0x1963 +#elif defined (SSD1963_800BD_DRIVER) #include "TFT_Drivers/SSD1963_Defines.h" #define TFT_DRIVER 0x1963 // <<<<<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVER HERE diff --git a/User_Setups/Setup14_ILI9341_Parallel.h b/User_Setups/Setup14_ILI9341_Parallel.h index d19a827..2fc5cee 100644 --- a/User_Setups/Setup14_ILI9341_Parallel.h +++ b/User_Setups/Setup14_ILI9341_Parallel.h @@ -1,6 +1,6 @@ // See SetupX_Template.h for all options available -#define ESP32_PARALLEL +#define TFT_PARALLEL_8_BIT #define ILI9341_DRIVER diff --git a/User_Setups/Setup29_ILI9341_STM32.h b/User_Setups/Setup29_ILI9341_STM32.h index e7ccae4..de612a3 100644 --- a/User_Setups/Setup29_ILI9341_STM32.h +++ b/User_Setups/Setup29_ILI9341_STM32.h @@ -23,17 +23,35 @@ // - Arduino SCK to TFT SCK // - Arduino MOSI to TFT SDI(may be marked SDA or MOSI) // Typical Arduino SPI port 1 pins are (SCK=D13, MISO=D12, MOSI=D11) this is port pins PA5, PA6 and PA7 on Nucleo-F767ZI -// SPI port 2 pins are (SCK=D18, MISO=A7, MOSI=D17) this is typically port pins PB13, PB14 and PB15 +// SPI port 2 pins are (SCK=D18, MISO=A7, MOSI=D17) this is port pins PB13, PC2 and PB15 on Nucleo-F767ZI +/* #define TFT_SPI_PORT 1 // SPI 1 maximum clock rate is 55MHz #define TFT_MOSI PA7 #define TFT_MISO PA6 #define TFT_SCLK PA5 +//*/ -//#define TFT_SPI_PORT 2 // SPI 2 maximum clock rate is 27MHz -//#define TFT_MOSI PB15 -//#define TFT_MISO PB14 -//#define TFT_SCLK PB13 +/* +#define TFT_SPI_PORT 2 // SPI 2 maximum clock rate is 27MHz +#define TFT_MOSI D17 +#define TFT_MISO A7 +#define TFT_SCLK D18 +//*/ + +/* +#define TFT_SPI_PORT 2 // SPI 2 maximum clock rate is 27MHz +#define TFT_MOSI PB15 +#define TFT_MISO PC2 +#define TFT_SCLK PB13 +//*/ + +/* +#define TFT_SPI_PORT 2 // SPI 2 maximum clock rate is 27MHz +#define TFT_MOSI PB15 +#define TFT_MISO PB14 +#define TFT_SCLK PB13 +//*/ // Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select #define TFT_CS D5 // Chip select control pin to TFT CS @@ -63,7 +81,7 @@ // STM32 support for smooth fonts via program memory (FLASH) arrays #define SMOOTH_FONT - + // Nucleo-F767ZI has a ~216MHZ CPU clock, this is divided by 4, 8, 16 etc #define SPI_FREQUENCY 27000000 // 27MHz SPI clock diff --git a/User_Setups/Setup50_SSD1963_Parallel.h b/User_Setups/Setup50_SSD1963_Parallel.h new file mode 100644 index 0000000..59be2d0 --- /dev/null +++ b/User_Setups/Setup50_SSD1963_Parallel.h @@ -0,0 +1,92 @@ +// USER DEFINED SETTINGS +// Set driver type, fonts to be loaded, pins used and SPI control method etc +// +// See the User_Setup_Select.h file if you wish to be able to define multiple +// setups and then easily select which setup file is used by the compiler. +// +// If this file is edited correctly then all the library example sketches should +// run without the need to make any more changes for a particular hardware setup! + +// ################################################################################## +// +// Section 0. Call up the right driver file and any options for it +// +// ################################################################################## + +// Use ESP32 Parallel interface +#define TFT_PARALLEL_8_BIT + +// Only define one driver, the other ones must be commented out +//#define SSD1963_480_DRIVER // 272 x 480 display +//#define SSD1963_800_DRIVER // 480 x 800 display +//#define SSD1963_800ALT_DRIVER // Alternative 480 x 800 display +#define SSD1963_800BD_DRIVER // 480 x 800 displau sourced from https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu + +// ################################################################################## +// +// Section 1. Define the pins that are used to interface with the display here +// +// ################################################################################## + +// ESP32 pins used +#define TFT_CS 33 // Chip select control pin +#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31 +#define TFT_RST 32 // Reset pin + +#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31 +#define TFT_RD 2 + +#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus +#define TFT_D1 13 // so a single register write sets/clears all bits +#define TFT_D2 26 +#define TFT_D3 25 +#define TFT_D4 17 +#define TFT_D5 16 +#define TFT_D6 27 +#define TFT_D7 14 + +// ################################################################################## +// +// Section 2. Define the way the DC and/or CS lines are driven (ESP8266 only) +// +// ################################################################################## + + +// ################################################################################## +// +// Section 3. Define the fonts that are to be used here +// +// ################################################################################## + +// Comment out the #defines below with // to stop that font being loaded +// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not +// normally necessary. If all fonts are loaded the extra FLASH space required is +// about 17Kbytes. To save FLASH space only enable the fonts you need! + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded +// this will save ~20kbytes of FLASH +#define SMOOTH_FONT + +// ################################################################################## +// +// Section 4. Not used +// +// ################################################################################## + + +// ################################################################################## +// +// Section 5. Other options +// +// ################################################################################## + + diff --git a/keywords.txt b/keywords.txt index 0cd2511..41b73b6 100644 --- a/keywords.txt +++ b/keywords.txt @@ -157,6 +157,7 @@ getPivotX KEYWORD2 getPivotY KEYWORD2 getRotatedBounds KEYWORD2 readPixelValue KEYWORD2 +pushToSprite KEYWORD2 drawGlyph KEYWORD2 printToSprite KEYWORD2 pushSprite KEYWORD2 diff --git a/library.json b/library.json index b870467..cb48502 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.20", + "version": "2.2.21", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 3ad1b2a..f8677ac 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.20 +version=2.2.21 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From ef93dbe687b9b429f0b1116a0d4197e00a7fef44 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 2 Oct 2020 20:47:00 +0100 Subject: [PATCH 41/42] Make ST7789 drivers consistent Simplified driver ST7789_2_DRIVER not supports 135 x 240 display. This will not fix #763 since user specifies alternative ST7789_DRIVER which already supports 135x240 displays. --- TFT_Drivers/ST7789_2_Rotation.h | 48 +++++++++++++++++++++++++++------ TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/TFT_Drivers/ST7789_2_Rotation.h b/TFT_Drivers/ST7789_2_Rotation.h index d25cc0c..44a363e 100644 --- a/TFT_Drivers/ST7789_2_Rotation.h +++ b/TFT_Drivers/ST7789_2_Rotation.h @@ -5,8 +5,16 @@ switch (rotation) { case 0: // Portrait #ifdef CGRAM_OFFSET - colstart = 0; - rowstart = 0; + if (_init_width == 135) + { + colstart = 52; + rowstart = 40; + } + else + { + colstart = 0; + rowstart = 0; + } #endif writedata(TFT_MAD_COLOR_ORDER); @@ -16,8 +24,16 @@ case 1: // Landscape (Portrait + 90) #ifdef CGRAM_OFFSET - colstart = 0; - rowstart = 0; + if (_init_width == 135) + { + colstart = 40; + rowstart = 53; + } + else + { + colstart = 0; + rowstart = 0; + } #endif writedata(TFT_MAD_MX | TFT_MAD_MV | TFT_MAD_COLOR_ORDER); @@ -27,8 +43,16 @@ case 2: // Inverter portrait #ifdef CGRAM_OFFSET - colstart = 0; - rowstart = 80; + if (_init_width == 135) + { + colstart = 53; + rowstart = 40; + } + else + { + colstart = 0; + rowstart = 80; + } #endif writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_COLOR_ORDER); @@ -37,8 +61,16 @@ break; case 3: // Inverted landscape #ifdef CGRAM_OFFSET - colstart = 80; - rowstart = 0; + if (_init_width == 135) + { + colstart = 40; + rowstart = 52; + } + else + { + colstart = 80; + rowstart = 0; + } #endif writedata(TFT_MAD_MV | TFT_MAD_MY | TFT_MAD_COLOR_ORDER); diff --git a/TFT_eSPI.h b/TFT_eSPI.h index d4fdd50..68c7c60 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.21" +#define TFT_ESPI_VERSION "2.2.22" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index cb48502..ebf197a 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.21", + "version": "2.2.22", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index f8677ac..e20d1d6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.21 +version=2.2.22 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32 From 22ca8193c532b8634c1201829affda5ccb60335e Mon Sep 17 00:00:00 2001 From: Bodmer Date: Fri, 2 Oct 2020 22:00:03 +0100 Subject: [PATCH 42/42] Improve RLE font rendering See #766 --- TFT_eSPI.cpp | 28 ++++++++++++++++------------ TFT_eSPI.h | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index ab3f3ca..59d6276 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -3570,8 +3570,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) inTransaction = true; w *= height; // Now w is total number of pixels in the character - if ((textsize != 1) || (textcolor == textbgcolor)) { - if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor); + if (textcolor == textbgcolor) { 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 @@ -3618,9 +3617,9 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } } else { - // Text colour != background && textsize = 1 and character is within screen area + // Text colour != background and textsize = 1 and character is within screen area // so use faster drawing of characters and background using block write - if ((x >= 0) && (x + width <= _width) && (y >= 0) && (y + height <= _height)) + if ((textsize == 1) && (x >= 0) && (x + width <= _width) && (y >= 0) && (y + height <= _height)) { setWindow(x, y, x + width - 1, y + height - 1); @@ -3640,7 +3639,8 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } else { - int32_t px = x, py = y; // To hold character block start and end column and row values + 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 @@ -3651,21 +3651,25 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) if (line & 0x80) { pcol = textcolor; line &= 0x7F; } else pcol = textbgcolor; line++; - px = x + pc % width; - py = y + pc / width; + px = pc % width; + tx = x + textsize * px; + py = pc / width; + ty = y + textsize * py; pl = 0; pc += line; - while (line--) { // In this case the while(line--) is faster + while (line--) { pl++; - if ((px+pl) >= (x + width)) { - drawFastHLine(px, py, pl, pcol); + if ((px+pl) >= width) { + fillRect(tx, ty, pl * textsize, textsize, pcol); pl = 0; - px = x; + px = 0; + tx = x; py ++; + ty += textsize; } } - if (pl)drawFastHLine(px, py, pl, pcol); + if (pl) fillRect(tx, ty, pl * textsize, textsize, pcol); } } } diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 68c7c60..07ceabe 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.22" +#define TFT_ESPI_VERSION "2.2.23" /*************************************************************************************** ** Section 1: Load required header files diff --git a/library.json b/library.json index ebf197a..07bd791 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.22", + "version": "2.2.23", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index e20d1d6..caef235 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.22 +version=2.2.23 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32