From f8ae9b7037cbd302613aaf1de7bb5ca3ea3d661b Mon Sep 17 00:00:00 2001 From: prenticedavid Date: Tue, 15 Mar 2016 21:03:51 +0000 Subject: [PATCH] start off commit --- ILI9341_regValues.txt | 247 +++ MCUFRIEND_kbv.cpp | 1832 +++++++++++++++++ MCUFRIEND_kbv.h | 50 + TFT_HX8357GLUE.h | 146 ++ UTFTGLUE.h | 119 ++ bitmaps/miniwoof.bmp | Bin 0 -> 57654 bytes bitmaps/test.bmp | Bin 0 -> 230456 bytes bitmaps/woof.bmp | Bin 0 -> 230456 bytes .../GLUE_Demo_320x240/GLUE_Demo_320x240.ino | 353 ++++ .../GLUE_Demo_400x240/GLUE_Demo_400x240.ino | 337 +++ .../GLUE_Demo_480x320/GLUE_Demo_480x320.ino | 333 +++ examples/LCD_ID_readreg/LCD_ID_readreg.ino | 257 +++ .../TouchScreen_Calibr_kbv.ino | 364 ++++ .../Touch_shield_kbv/Touch_shield_kbv.ino | 290 +++ .../UTouch_Calibr_kbv/UTouch_Calibr_kbv.ino | 376 ++++ examples/aspect_kbv/aspect_kbv.ino | 40 + examples/graphictest_kbv/graphictest_kbv.ino | 569 +++++ examples/graphictest_kbv/icons.c | 408 ++++ .../graphictest_slim/graphictest_slim.ino | 21 + examples/graphictest_slim/graphictest_v25.cpp | 552 +++++ examples/graphictest_slim/icons.c | 408 ++++ examples/readpixel_kbv/readpixel_kbv.ino | 135 ++ examples/scroll_kbv/scroll_kbv.ino | 49 + examples/testcard_kbv/testcard_kbv.ino | 183 ++ keywords.txt | 67 + mcufriend_kbv_2_8.txt | 148 ++ mcufriend_serial.h | 243 +++ mcufriend_shield.h | 262 +++ mcufriend_special.h | 680 ++++++ mcufriend_special_2.h | 77 + 30 files changed, 8546 insertions(+) create mode 100644 ILI9341_regValues.txt create mode 100644 MCUFRIEND_kbv.cpp create mode 100644 MCUFRIEND_kbv.h create mode 100644 TFT_HX8357GLUE.h create mode 100644 UTFTGLUE.h create mode 100644 bitmaps/miniwoof.bmp create mode 100644 bitmaps/test.bmp create mode 100644 bitmaps/woof.bmp create mode 100644 examples/GLUE_Demo_320x240/GLUE_Demo_320x240.ino create mode 100644 examples/GLUE_Demo_400x240/GLUE_Demo_400x240.ino create mode 100644 examples/GLUE_Demo_480x320/GLUE_Demo_480x320.ino create mode 100644 examples/LCD_ID_readreg/LCD_ID_readreg.ino create mode 100644 examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino create mode 100644 examples/Touch_shield_kbv/Touch_shield_kbv.ino create mode 100644 examples/UTouch_Calibr_kbv/UTouch_Calibr_kbv.ino create mode 100644 examples/aspect_kbv/aspect_kbv.ino create mode 100644 examples/graphictest_kbv/graphictest_kbv.ino create mode 100644 examples/graphictest_kbv/icons.c create mode 100644 examples/graphictest_slim/graphictest_slim.ino create mode 100644 examples/graphictest_slim/graphictest_v25.cpp create mode 100644 examples/graphictest_slim/icons.c create mode 100644 examples/readpixel_kbv/readpixel_kbv.ino create mode 100644 examples/scroll_kbv/scroll_kbv.ino create mode 100644 examples/testcard_kbv/testcard_kbv.ino create mode 100644 keywords.txt create mode 100644 mcufriend_kbv_2_8.txt create mode 100644 mcufriend_serial.h create mode 100644 mcufriend_shield.h create mode 100644 mcufriend_special.h create mode 100644 mcufriend_special_2.h diff --git a/ILI9341_regValues.txt b/ILI9341_regValues.txt new file mode 100644 index 0000000..2d4ff13 --- /dev/null +++ b/ILI9341_regValues.txt @@ -0,0 +1,247 @@ + case 0x9341: + _lcd_capable = AUTO_READINC | TWO_PARM_WINDOW | MV_AXIS; + static const uint8_t ILI9341_regValues_kbv[] PROGMEM = { //.kbv MCUFRIEND_kbv + 0x01, 0, // software reset + TFTLCD_DELAY, 150, // 5ms if awake, 125ms if asleep. + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xCF, 3, 0x00, 0xC1, 0x30, //Power Control B [00 81 30] + 0xE8, 3, 0x85, 0x00, 0x78, //Driver Timing A [04 11 7A] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xC0, 1, 0x23, //Power Control 1 [26] + 0xC1, 1, 0x10, //Power Control 2 [00] + 0xC5, 2, 0x3E, 0x28, //VCOM 1 [31 3C] + 0xC7, 1, 0x86, //VCOM 2 [C0] + 0x36, 1, 0x48, //Memory Access [00] + 0xB1, 2, 0x00, 0x18, //Frame Control [00 1B] + 0xB6, 3, 0x08, 0x82, 0x27, //Display Function [0A 82 27 XX] + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00, + 0xE1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f, + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_2_6[] PROGMEM = { // LG 2.6" from AN + 0x01, 0, // software reset + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xCF, 3, 0x00, 0xC1, 0x30, //Power Control B [00 81 30] + 0xE8, 3, 0x85, 0x00, 0x78, //Driver Timing A [04 11 7A] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xC0, 1, 0x23, //Power Control 1 [26] + 0xC1, 1, 0x10, //Power Control 2 [00] + 0xC5, 2, 0x2B, 0x2B, //VCOM 1 [31 3C] + 0xC7, 1, 0xC0, //VCOM 2 [C0] + 0x36, 1, 0x48, //Memory Access [00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] +// 0xB6, 3, 0x0A, 0x02, 0x27, //Display Function [0A 82 27 XX] .kbv REV=0 + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00, + 0xE1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f, + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_2_0[] PROGMEM = { // BOE 2.0" + 0x01, 0, // software reset + 0xCF, 3, 0x00, 0x99, 0x30, //Power Control B [00 81 30] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xE8, 3, 0x85, 0x10, 0x78, //Driver Timing A [04 11 7A] + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xC0, 1, 0x26, //Power Control 1 [26] + 0xC1, 1, 0x12, //Power Control 2 [00] + 0xC5, 2, 0x2B, 0x2C, //VCOM 1 [31 3C] + 0xC7, 1, 0xC4, //VCOM 2 [C0] + 0x36, 1, 0x08, //Memory Access [00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] +// 0xB6, 3, 0x0A, 0xA2, 0x27, //?? Display Function [0A 82 27 XX] .kbv SS=1 + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x24, 0x21, 0x0a, 0x0e, 0x09, 0x51, 0xa9, 0x44, 0x07, 0x10, 0x03, 0x2c, 0x0b, 0x00, + 0xE1, 15, 0x00, 0x1b, 0x1e, 0x05, 0x11, 0x06, 0x2e, 0x56, 0x3b, 0x08, 0x0f, 0x0c, 0x13, 0x14, 0x0f, + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_2_4[] PROGMEM = { // BOE 2.4" + 0x01, 0, // software reset + TFTLCD_DELAY, 50, // .kbv + 0xCF, 3, 0x00, 0x81, 0x30, //Power Control B [00 81 30] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xE8, 3, 0x85, 0x10, 0x78, //Driver Timing A [04 11 7A] + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] +// 0xB6, 2, 0x0A, 0xA2, 0x27, //Display Function [0A 82 27 XX] .kbv SS=1 + 0xC0, 1, 0x21, //Power Control 1 [26] + 0xC1, 1, 0x11, //Power Control 2 [00] + 0xC5, 2, 0x3F, 0x3C, //VCOM 1 [31 3C] + 0xC7, 1, 0xB5, //VCOM 2 [C0] + 0x36, 1, 0x48, //Memory Access [00] + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x26, 0x24, 0x0b, 0x0e, 0x09, 0x54, 0xa8, 0x46, 0x0c, 0x17, 0x09, 0x0f, 0x07, 0x00, + 0xE1, 15, 0x00, 0x19, 0x1b, 0x04, 0x10, 0x07, 0x2a, 0x47, 0x39, 0x03, 0x06, 0x06, 0x30, 0x38, 0x0f, + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_ada[] PROGMEM = { // Adafruit_TFTLCD only works with EXTC=0 + 0x01, 0, // software reset + TFTLCD_DELAY, 50, + 0x28, 0, //Display Off + 0xC0, 1, 0x23, //Power Control 1 [26] + 0xC1, 1, 0x10, //Power Control 2 [00] + 0xC5, 2, 0x2B, 0x2B, //VCOM 1 [31 3C] + 0xC7, 1, 0xC0, //VCOM 2 [C0] + 0x36, 1, 0x88, //Memory Access [00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] + 0xB7, 1, 0x07, //Entry Mode [00] + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_ada9341[] PROGMEM = { // Adafruit_ILI9341 + 0xEF, 3, 0x03, 0x80, 0x02, // + 0xCF, 3, 0x00, 0xC1, 0x30, //Power Control B [00 81 30] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xE8, 3, 0x85, 0x00, 0x78, //Driver Timing A [04 11 7A] + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xC0, 1, 0x23, //Power Control 1 [26] + 0xC1, 1, 0x11, //Power Control 2 [00] + 0xC5, 2, 0x3E, 0x28, //VCOM 1 [31 3C] + 0xC7, 1, 0x86, //VCOM 2 [C0] + 0x36, 1, 0x48, //Memory Access [00] + 0xB1, 2, 0x00, 0x18, //Frame Control [00 1B] + 0xB6, 3, 0x0A, 0x82, 0x27, //?? Display Function [0A 82 27 XX] + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00, + 0xE1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f, + + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; +// init_table(ILI9341_regValues_kbv, sizeof(ILI9341_regValues_kbv)); //ok for me +// init_table(ILI9341_regValues_2_0, sizeof(ILI9341_regValues_2_0)); //wrong direction + init_table(ILI9341_regValues_2_4, sizeof(ILI9341_regValues_2_4)); //wrong direction +// init_table(ILI9341_regValues_2_6, sizeof(ILI9341_regValues_2_6)); //inverted +// init_table(ILI9341_regValues_ada, sizeof(ILI9341_regValues_ada)); //white screen +// init_table(ILI9341_regValues_ada9341, sizeof(ILI9341_regValues_ada9341)); //ok for me + break; + + case 0x9486: + _lcd_capable = AUTO_READINC | TWO_PARM_WINDOW | MV_AXIS; + static const uint8_t ILI9486_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + 0x28, 0, //Display Off + 0xC0, 2, 0x0d, 0x0d, //Power Control 1 [0x0E0E] + 0xC1, 2, 0x43, 0x00, //Power Control 2 [0x4300] + 0xC2, 1, 0x00, //Power Control 3 + 0xC5, 4, 0x00, 0x48, 0x00, 0x48, //VCOM Control 1 [0x00400040] + 0xB6, 3, 0x00, 0x22, 0x3B, // Display Function Control .kbv SS=1 + // 0xE0,15, 0x0f,0x31,0x2b,0x0c,0x0e,0x08,0x4e,0xf1,0x37,0x07,0x10,0x03,0x0e,0x09,0x00, + // 0xE1,15, 0x00,0x0e,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0f,0x0c,0x31,0x36,0x0f, + 0x20, 0, // Display Inversion OFF + 0x36, 1, 0x0A, //Memory Access + 0x3A, 1, 0x55, //Interlace Pixel +// 0x21, 0, //Invert display !!! + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 50, + 0x29, 0, //Display On + }; + init_table(ILI9486_regValues, sizeof(ILI9486_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 320; + break; + + case 0x9488: + _lcd_capable = AUTO_READINC | TWO_PARM_WINDOW | MV_AXIS; + static const uint8_t ILI9488_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + 0x28, 0, //Display Off + 0xC0, 2, 0x0E, 0x0E, //Power Control 1 [0E 0E] + 0xC1, 1, 0x43, //Power Control 2 [43] + 0xC5, 4, 0x00, 0x22, 0x80, 0x40, //VCOM Control 1 [00 40 00 40] + 0x36, 1, 0x08, //Memory Access [00] + 0x3A, 1, 0x55, //Interlace Pixel [XX] + 0xB1, 2, 0xB0, 0x11, //Frame Rate Control [B0 11] + 0xB6, 3, 0x02, 0x02, 0x3B, //Display Function [02 02 3B] .kbv SS=0 + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + // 0x2C, 0, + }; + static const uint8_t ILI9488_regValues_max[] PROGMEM = { // Atmel MaxTouch + 0x01, 0, //Soft Reset + TFTLCD_DELAY, 50, + 0x28, 0, //Display Off + 0xC0, 2, 0x10, 0x10, //Power Control 1 [0E 0E] + 0xC1, 1, 0x41, //Power Control 2 [43] + 0xC5, 4, 0x00, 0x22, 0x80, 0x40, //VCOM Control 1 [00 40 00 40] + 0x36, 1, 0x68, //Memory Access [00] + 0xB0, 1, 0x00, //Interface [00] + 0xB1, 2, 0xB0, 0x11, //Frame Rate Control [B0 11] + 0xB4, 1, 0x02, //Inversion Control [02] + 0xB7, 1, 0xC6, //Entry Mode [06] + 0x3A, 1, 0x55, //Interlace Pixel Format [XX] + 0xF7, 4, 0xA9, 0x51, 0x2C, 0x82, //Adjustment Control 3 [A9 51 2C 82] + 0x11, 0, //Sleep Out + TFTLCD_DELAY, 150, + 0x29, 0, //Display On + }; +// init_table(ILI9488_regValues, sizeof(ILI9488_regValues)); + init_table(ILI9488_regValues_max, sizeof(ILI9488_regValues_max)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 320; + break; +// ################################################################################### + case 0x7789: + case 0x8552: + _lcd_capable = AUTO_READINC | TWO_PARM_WINDOW | MV_AXIS; + static const uint8_t ST7789_regValues[] PROGMEM = { + (0x0011); //exit SLEEP mode + TFTLCD_DELAY, 10, + (0x0036), 1, 0x80, //MADCTL: memory data access control + (0x003A), 1, 0x66, //COLMOD: Interface Pixel format *** I use 262K-colors in 18bit/pixel format when using 8-bit interface to allow 3-bytes per pixel +// (0x003A), 1, 0x0055, //COLMOD: Interface Pixel format *** I use 65K-colors in 16bit/pixel (5-6-5) format when using 16-bit interface to allow 1-byte per pixel + (0x00B2), 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, //PORCTRK: Porch setting + (0x00B7), 1, 0x35, //GCTRL: Gate Control + (0x00BB), 1, 0x2B, //VCOMS: VCOM setting + (0x00C0), 1, 0x2C, //LCMCTRL: LCM Control + (0x00C2), 2, 0x01, 0xFF, //VDVVRHEN: VDV and VRH Command Enable + (0x00C3), 1, 0x11, //VRHS: VRH Set + (0x00C4), 1, 0x20, //VDVS: VDV Set + (0x00C6), 1, 0x0F, //FRCTRL2: Frame Rate control in normal mode + (0x00D0), 2, 0xA4, 0xA1, //PWCTRL1: Power Control 1 + (0x00E0), 14, 0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19, //PVGAMCTRL: Positive Voltage Gamma control + (0x00E1), 14, 0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19, //NVGAMCTRL: Negative Voltage Gamma control + (0x002A), 4, 0x00, 0x00, 0x00, 0xEF, //X address set + (0x002B), 4, 0x00, 0x00, 0x01, 0x3F, //Y address set + TFTLCD_DELAY, 10, + }; + init_table(ST7789_regValues, sizeof(ST7789_regValues)); // + break; + + diff --git a/MCUFRIEND_kbv.cpp b/MCUFRIEND_kbv.cpp new file mode 100644 index 0000000..db65c84 --- /dev/null +++ b/MCUFRIEND_kbv.cpp @@ -0,0 +1,1832 @@ + //#define SUPPORT_0139 //costs about 238 bytes + //#define SUPPORT_1963 +#define SUPPORT_4535 //costs about 184 bytes + //#define SUPPORT_8347A //costs about 408 bytes +#define SUPPORT_8347D //costs about 408 bytes + +#include "MCUFRIEND_kbv.h" +#if defined(USE_SERIAL) + //#include +#include "mcufriend_serial.h" + //uint8_t running; +#elif defined(USE_KEIL) +#include "pin_freedom_8.h" +#define CTL_INIT() { RD_OUTPUT; WR_OUTPUT; CD_OUTPUT; CS_OUTPUT; RESET_OUTPUT; } +#define WriteCmd(x) { CD_COMMAND; write16(x); } +#define WriteData(x) { CD_DATA; write16(x); } +#else +#include "mcufriend_shield.h" +#endif + +#define wait_ms(ms) delay(ms) +#define MIPI_DCS_REV1 (1<<0) +#define AUTO_READINC (1<<1) +#define READ_BGR (1<<2) +#define READ_LOWHIGH (1<<3) +#define READ_24BITS (1<<4) +#define XSA_XEA_16BIT (1<<5) +#define READ_NODUMMY (1<<6) +#define INVERT_GS (1<<8) +#define INVERT_SS (1<<9) +#define MV_AXIS (1<<10) +#define INVERT_RGB (1<<11) +#define REV_SCREEN (1<<12) + +#if (defined(__AVR_ATmega2560__) || defined(__SAM3X8E__))\ + && (defined(USE_MEGA_16BIT_SHIELD) || defined(USE_DUE_16BIT_SHIELD)) +#define USING_16BIT_BUS 1 +#else +#define USING_16BIT_BUS 0 +#endif + +#if defined USE_GFX_KBV +MCUFRIEND_kbv::MCUFRIEND_kbv():Adafruit_GFX(240, 320) +{ + // we can not access GPIO pins until AHB has been enabled. +} +#else +MCUFRIEND_kbv::MCUFRIEND_kbv(int CS, int RS, int WR, int RD, int RST):Adafruit_GFX(240, 320) +{ + // we can not access GPIO pins until AHB has been enabled. +} +#endif + +static uint8_t done_reset, is8347; + +void MCUFRIEND_kbv::reset(void) +{ + done_reset = 1; + setWriteDir(); + CTL_INIT(); + CS_IDLE; + RD_IDLE; + WR_IDLE; + RESET_IDLE; + wait_ms(50); + RESET_ACTIVE; + wait_ms(100); + RESET_IDLE; + wait_ms(100); +} + +void MCUFRIEND_kbv::WriteCmdData(uint16_t cmd, uint16_t dat) +{ + CS_ACTIVE; + WriteCmd(cmd); + WriteData(dat); + CS_IDLE; +} + +static void WriteCmdParamN(uint16_t cmd, int8_t N, uint8_t * block) + //void MCUFRIEND_kbv::WriteCmdParamN(uint16_t cmd, int8_t N, uint8_t * block) +{ + CS_ACTIVE; + WriteCmd(cmd); + while (N-- > 0) { + uint8_t u8 = *block++; + CD_DATA; + write8(u8); + if (N && is8347) { + cmd++; + WriteCmd(cmd); + } + } + CS_IDLE; +} + +static inline void WriteCmdParam4(uint8_t cmd, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4) +{ + uint8_t d[4]; + d[0] = d1, d[1] = d2, d[2] = d3, d[3] = d4; + WriteCmdParamN(cmd, 4, d); +} + +static uint16_t read16bits(void) +{ + uint16_t ret; + uint8_t lo; +#if USING_16BIT_BUS + READ_16(ret); //single strobe to read whole bus + if (ret > 255) //ID might say 0x00D3 + return ret; +#else + READ_8(ret); +#endif + //all MIPI_DCS_REV1 style params are 8-bit + READ_8(lo); + return (ret << 8) | lo; +} + +uint16_t MCUFRIEND_kbv::readReg(uint16_t reg) +{ + uint16_t ret; + uint8_t lo; + if (!done_reset) + reset(); + CS_ACTIVE; + WriteCmd(reg); + setReadDir(); + CD_DATA; + // READ_16(ret); + ret = read16bits(); + RD_IDLE; + CS_IDLE; + setWriteDir(); + return ret; +} + +uint32_t MCUFRIEND_kbv::readReg32(uint16_t reg) +{ + uint16_t h, l; + CS_ACTIVE; + WriteCmd(reg); + setReadDir(); + CD_DATA; + h = read16bits(); + l = read16bits(); + RD_IDLE; + CS_IDLE; + setWriteDir(); + return ((uint32_t) h << 16) | (l); +} + +uint16_t MCUFRIEND_kbv::readID(void) +{ + uint16_t ret, ret2; + uint8_t msb; + ret = readReg(0); //forces a reset() if called before begin() + if (ret == 0x5408) //the SPFD5408 fails the 0xD3D3 test. + return 0x5408; + if (ret == 0x0089 || ret == 0x8989) + return 0x1289; + ret = readReg(0x67); //HX8347-A + if (ret == 0x4747) + return 0x8347; + ret = readReg32(0xA1); //for SSD1963 [0x01576101] + if (ret == 0x6101) + return 0x1963; + ret = readReg32(0xBF); //for ILI9481 + if (ret == 0x0494) + return 0x9481; + ret = readReg32(0xEF); //for ILI9327 + if (ret == 0x0493) + return 0x9327; + ret = readReg32(0x04); //0x8552 for ST7789V + if (ret == 0x8552) + return 0x7789; + ret = readReg32(0xD3); //for ILI9488, 9486, 9340, 9341 + msb = ret >> 8; + if (msb == 0x93 || msb == 0x94) + return ret; //0x9488, 9486, 9340, 9341 + if (ret == 0x00D3 || ret == 0xD3D3) + return ret; //16-bit write-only bus + return readReg(0); //0154, 7783, 9320, 9325, 9335, B505, B509 +} + + // independent cursor and window registers. S6D0154, ST7781 increments. ILI92320/5 do not. +int16_t MCUFRIEND_kbv::readGRAM(int16_t x, int16_t y, uint16_t * block, int16_t w, int16_t h) +{ + uint16_t ret, dummy, _MR = _MW; + int16_t n = w * h, row = 0, col = 0; + uint8_t r, g, b, tmp; + if (_lcd_capable & MIPI_DCS_REV1) + _MR = 0x2E; + setAddrWindow(x, y, x + w - 1, y + h - 1); + while (n > 0) { + if (!(_lcd_capable & MIPI_DCS_REV1)) { + WriteCmdData(_MC, x + col); + WriteCmdData(_MP, y + row); + } + CS_ACTIVE; + WriteCmd(_MR); + setReadDir(); + CD_DATA; + if (_lcd_capable & READ_NODUMMY) { + ; + } else if ((_lcd_capable & MIPI_DCS_REV1) || _lcd_ID == 0x1289) { + READ_8(r); + } else { + READ_16(dummy); + } + while (n) { + if (_lcd_capable & READ_24BITS) { + READ_8(r); + READ_8(g); + READ_8(b); + if (_lcd_capable & READ_BGR) + ret = color565(b, g, r); + else + ret = color565(r, g, b); + } else { + READ_16(ret); + if (_lcd_capable & READ_LOWHIGH) + ret = (ret >> 8) | (ret << 8); + if (_lcd_capable & READ_BGR) + ret = (ret & 0x07E0) | (ret >> 11) | (ret << 11); + } + *block++ = ret; + n--; + if (!(_lcd_capable & AUTO_READINC)) + break; + } + if (++col >= w) { + col = 0; + if (++row >= h) + row = 0; + } + RD_IDLE; + CS_IDLE; + setWriteDir(); + } + if (!(_lcd_capable & MIPI_DCS_REV1)) + setAddrWindow(0, 0, width() - 1, height() - 1); + return 0; +} + +void MCUFRIEND_kbv::setRotation(uint8_t r) +{ + uint16_t GS, SS, ORG, REV = _lcd_rev; + uint8_t val, d[3]; + rotation = r & 3; // just perform the operation ourselves on the protected variables + _width = (rotation & 1) ? HEIGHT : WIDTH; + _height = (rotation & 1) ? WIDTH : HEIGHT; + switch (rotation) { + case 0: //PORTRAIT: + val = 0x48; //MY=0, MX=1, MV=0, ML=0, BGR=1 + break; + case 1: //LANDSCAPE: 90 degrees + val = 0x28; //MY=0, MX=0, MV=1, ML=0, BGR=1 + break; + case 2: //PORTRAIT_REV: 180 degrees + val = 0x98; //MY=1, MX=0, MV=0, ML=1, BGR=1 + break; + case 3: //LANDSCAPE_REV: 270 degrees + val = 0xF8; //MY=1, MX=1, MV=1, ML=1, BGR=1 + break; + } + if (_lcd_capable & INVERT_GS) + val ^= 0x80; + if (_lcd_capable & INVERT_SS) + val ^= 0x40; + if (_lcd_capable & INVERT_RGB) + val ^= 0x08; + if (_lcd_capable & MIPI_DCS_REV1) { + if (_lcd_ID == 0x9486) { +#if USING_16BIT_BUS + // my 16-bit write-only shield seems to be an ILI9486 + _lcd_capable &= ~REV_SCREEN; + GS = (val & 0x80) ? (1 << 6) : 0; //MY + SS = (val & 0x40) ? (1 << 5) : 0; //MX + val &= 0x28; //keep MV, BGR, MY=0, MX=0, ML=0 + d[0] = 0; + d[1] = GS | SS | 0x02; //MY, MX + d[2] = 0x3B; + WriteCmdParamN(0xB6, 3, d); +#endif + goto common_MC; + } else if (_lcd_ID == 0x1963 || _lcd_ID == 0x9481) { + if (val & 0x80) + val |= 0x01; //GS + if ((val & 0x40)) + val |= 0x02; //SS + val &= (_lcd_ID == 0x1963) ? ~0xC0 : ~0xD0; //MY=0, MX=0 with ML=0 for ILI9481 + goto common_MC; + } else if (is8347) { + _MC = 0x02, _MP = 0x06, _MW = 0x22, _SC = 0x02, _EC = 0x04, _SP = 0x06, _EP = 0x08; + goto common_BGR; + } + common_MC: + _MC = 0x2A, _MP = 0x2B, _MW = 0x2C, _SC = 0x2A, _EC = 0x2A, _SP = 0x2B, _EP = 0x2B; + common_BGR: + WriteCmdParamN(is8347 ? 0x16 : 0x36, 1, &val); + _lcd_madctl = val; + } + // cope with 9320 variants + else { + switch (_lcd_ID) { +#ifdef SUPPORT_0139 + case 0x0139: + _SC = 0x46, _EC = 0x46, _SP = 0x48, _EP = 0x47; + goto common_S6D; +#endif + case 0x0154: + _SC = 0x37, _EC = 0x36, _SP = 0x39, _EP = 0x38; + common_S6D: + _MC = 0x20, _MP = 0x21, _MW = 0x22; + GS = (val & 0x80) ? (1 << 9) : 0; + SS = (val & 0x40) ? (1 << 8) : 0; + WriteCmdData(0x01, GS | SS | 0x0028); // set Driver Output Control + goto common_ORG; + case 0xB509: + _MC = 0x200, _MP = 0x201, _MW = 0x202, _SC = 0x210, _EC = 0x211, _SP = 0x212, _EP = 0x213; + GS = (val & 0x80) ? (1 << 15) : 0; + WriteCmdData(0x400, GS | 0x6200); + goto common_SS; + default: + _MC = 0x20, _MP = 0x21, _MW = 0x22, _SC = 0x50, _EC = 0x51, _SP = 0x52, _EP = 0x53; + GS = (val & 0x80) ? (1 << 15) : 0; + WriteCmdData(0x60, GS | 0x2700); // Gate Scan Line (0xA700) + common_SS: + SS = (val & 0x40) ? (1 << 8) : 0; + WriteCmdData(0x01, SS); // set Driver Output Control + common_ORG: + ORG = (val & 0x20) ? (1 << 3) : 0; + if (val & 0x08) + ORG |= 0x1000; //BGR + _lcd_madctl = ORG | 0x0030; + WriteCmdData(0x03, _lcd_madctl); // set GRAM write direction and BGR=1. + break; + case 0x1289: + _MC = 0x4E, _MP = 0x4F, _MW = 0x22, _SC = 0x44, _EC = 0x44, _SP = 0x45, _EP = 0x46; + if (rotation & 1) + val ^= 0xD0; // exchange Landscape modes + GS = (val & 0x80) ? (1 << 14) | (1 << 12) : 0; //called TB (top-bottom) + SS = (val & 0x40) ? (1 << 9) : 0; //called RL (right-left) + ORG = (val & 0x20) ? (1 << 3) : 0; //called AM + _lcd_drivOut = GS | SS | (REV << 13) | 0x013F; //REV=0, BGR=0, MUX=319 + if (val & 0x08) + _lcd_drivOut |= 0x0800; //BGR + WriteCmdData(0x01, _lcd_drivOut); // set Driver Output Control + WriteCmdData(0x11, ORG | 0x6070); // set GRAM write direction. + break; + } + } + if ((rotation & 1) && ((_lcd_capable & MV_AXIS) == 0)) { + uint16_t x; + x = _MC, _MC = _MP, _MP = x; + x = _SC, _SC = _SP, _SP = x; //.kbv check 0139 + x = _EC, _EC = _EP, _EP = x; //.kbv check 0139 + } + setAddrWindow(0, 0, width() - 1, height() - 1); + vertScroll(0, HEIGHT, 0); //reset scrolling after a rotation +} + +void MCUFRIEND_kbv::drawPixel(int16_t x, int16_t y, uint16_t color) +{ + // MCUFRIEND just plots at edge if you try to write outside of the box: + if (x < 0 || y < 0 || x >= width() || y >= height()) + return; + if (_lcd_capable & MIPI_DCS_REV1) { + WriteCmdParam4(_MC, x >> 8, x, x >> 8, x); + WriteCmdParam4(_MP, y >> 8, y, y >> 8, y); + } else { + WriteCmdData(_MC, x); + WriteCmdData(_MP, y); + } + WriteCmdData(_MW, color); +} + +void MCUFRIEND_kbv::setAddrWindow(int16_t x, int16_t y, int16_t x1, int16_t y1) +{ + if (_lcd_capable & MIPI_DCS_REV1) { + WriteCmdParam4(_MC, x >> 8, x, x1 >> 8, x1); + WriteCmdParam4(_MP, y >> 8, y, y1 >> 8, y1); + } else { + WriteCmdData(_MC, x); + WriteCmdData(_MP, y); + if (_lcd_capable & XSA_XEA_16BIT) { + if (rotation & 1) + y1 = y = (y1 << 8) | y; + else + x1 = x = (x1 << 8) | x; + } + WriteCmdData(_SC, x); + WriteCmdData(_SP, y); + WriteCmdData(_EC, x1); + WriteCmdData(_EP, y1); + } +} + +void MCUFRIEND_kbv::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) +{ + int16_t end; + if (w < 0) { + w = -w; + x -= w; + } //+ve w + end = x + w; + if (x < 0) + x = 0; + if (end > width()) + end = width(); + w = end - x; + if (h < 0) { + h = -h; + y -= h; + } //+ve h + end = y + h; + if (y < 0) + y = 0; + if (end > height()) + end = height(); + h = end - y; + + setAddrWindow(x, y, x + w - 1, y + h - 1); + CS_ACTIVE; + WriteCmd(_MW); + if (h > w) { + end = h; + h = w; + w = end; + } + uint8_t hi = color >> 8, lo = color & 0xFF; + CD_DATA; + while (h-- > 0) { + end = w; +#if USING_16BIT_BUS +#if defined(__SAM3X8E__) +#define STROBE_16BIT {WR_ACTIVE;WR_ACTIVE;WR_ACTIVE;WR_IDLE;WR_IDLE;} +#else +#define STROBE_16BIT {WR_ACTIVE; WR_IDLE;} +#endif + write_16(color); //we could just do the strobe + lo = end & 7; + hi = end >> 3; + if (hi) + do { + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + STROBE_16BIT; + } while (--hi > 0); + while (lo-- > 0) { + STROBE_16BIT; + } +#else + do { + write8(hi); + write8(lo); + } while (--end != 0); +#endif + } + CS_IDLE; + if (!(_lcd_capable & MIPI_DCS_REV1)) + setAddrWindow(0, 0, width() - 1, height() - 1); +} + +void MCUFRIEND_kbv::pushColors(uint16_t * block, int16_t n, bool first) +{ + uint16_t color; + CS_ACTIVE; + if (first) { + WriteCmd(_MW); + } + CD_DATA; + while (n-- > 0) { + color = *block++; + write16(color); + } + CS_IDLE; +} + +void MCUFRIEND_kbv::pushColors(uint8_t * block, int16_t n, bool first) +{ + uint16_t color; + uint8_t h, l; + CS_ACTIVE; + if (first) { + WriteCmd(_MW); + } + CD_DATA; + while (n-- > 0) { + h = (*block++); + l = (*block++); + color = h << 8 | l; + write16(color); + } + CS_IDLE; +} + +void MCUFRIEND_kbv::pushColors(const uint8_t * block, int16_t n, bool first) +{ + uint16_t color; + uint8_t h, l; + CS_ACTIVE; + if (first) { + WriteCmd(_MW); + } + CD_DATA; + while (n-- > 0) { + l = pgm_read_byte(block++); + h = pgm_read_byte(block++); + color = h << 8 | l; + write16(color); + } + CS_IDLE; +} + +void MCUFRIEND_kbv::vertScroll(int16_t top, int16_t scrollines, int16_t offset) +{ + int16_t bfa = HEIGHT - top - scrollines; // bottom fixed area + int16_t vsp; + int16_t sea = top; + vsp = top + offset; // vertical start position + if (offset < 0) + vsp += scrollines; //keep in unsigned range + sea = top + scrollines - 1; + if (_lcd_capable & MIPI_DCS_REV1) { + uint8_t d[6]; // for multi-byte parameters + if (_lcd_ID == 0x9327) { //panel is wired for 240x432 + if (rotation == 2 || rotation == 3) { //180 or 270 degrees + if (scrollines == HEIGHT) { + scrollines = 432; // we get a glitch but hey-ho + vsp -= 432 - HEIGHT; + } + if (vsp < 0) + vsp += 432; + } + bfa = 432 - top - scrollines; + } + d[0] = top >> 8; //TFA + d[1] = top; + d[2] = scrollines >> 8; //VSA + d[3] = scrollines; + d[4] = bfa >> 8; //BFA + d[5] = bfa; + WriteCmdParamN(is8347 ? 0x0E : 0x33, 6, d); + d[0] = vsp >> 8; //VSP + d[1] = vsp; + WriteCmdParamN(is8347 ? 0x14 : 0x37, 2, d); + return; + } + // cope with 9320 style variants: + switch (_lcd_ID) { + case 0x7783: + WriteCmdData(0x61, _lcd_rev); //!NDL, !VLE, REV + WriteCmdData(0x6A, vsp); //VL# + break; +#ifdef SUPPORT_0139 + case 0x0139: + WriteCmdData(0x41, sea); //SEA + WriteCmdData(0x42, top); //SSA + WriteCmdData(0x43, vsp - top); //SST + break; +#endif + case 0x0154: + WriteCmdData(0x31, sea); //SEA + WriteCmdData(0x32, top); //SSA + WriteCmdData(0x33, vsp - top); //SST + break; + case 0x1289: + WriteCmdData(0x41, vsp); //VL# + break; + case 0xB509: + WriteCmdData(0x401, (1 << 1) | _lcd_rev); //VLE, REV + WriteCmdData(0x404, vsp); //VL# + break; + default: + // 0x6809, 0x9320, 0x9325, 0x9335, 0xB505 can only scroll whole screen + WriteCmdData(0x61, (1 << 1) | _lcd_rev); //!NDL, VLE, REV + WriteCmdData(0x6A, vsp); //VL# + break; + } +} + +void MCUFRIEND_kbv::invertDisplay(boolean i) +{ + uint8_t val; + _lcd_rev = ((_lcd_capable & REV_SCREEN) != 0) ^ i; + if (_lcd_capable & MIPI_DCS_REV1) { + if (is8347) { + // HX8347D: 0x36 Panel Characteristic. REV_Panel + // HX8347A: 0x36 is Display Control 10 +#if defined(SUPPORT_8347D) + val = _lcd_rev ? 8 : 10; //HX8347-D: SCROLLON=bit3, INVON=bit1 +#else + val = _lcd_rev ? 6 : 2; //INVON id bit#2 on HX8347-A. NORON=bit#1 +#endif + // HX8347: 0x01 Display Mode has diff bit mapping for A, D + WriteCmdParamN(0x01, 1, &val); + } else + WriteCmdParamN(_lcd_rev ? 0x21 : 0x20, 0, NULL); + return; + } + // cope with 9320 style variants: + switch (_lcd_ID) { +#ifdef SUPPORT_0139 + case 0x0139: +#endif + case 0x0154: + WriteCmdData(0x07, 0x13 | (_lcd_rev << 2)); //.kbv kludge + break; + case 0x1289: + _lcd_drivOut &= ~(1 << 13); + if (_lcd_rev) + _lcd_drivOut |= (1 << 13); + WriteCmdData(0x01, _lcd_drivOut); + break; + case 0xB509: + WriteCmdData(0x401, (1 << 1) | _lcd_rev); //.kbv kludge VLE + break; + default: + WriteCmdData(0x61, _lcd_rev); + break; + } +} + +#define TFTLCD_DELAY 0xFFFF +#define TFTLCD_DELAY8 0xFF +static void init_table(const void *table, int16_t size) +{ + uint8_t *p = (uint8_t *) table, dat[16]; + while (size > 0) { + uint8_t cmd = pgm_read_byte(p++); + uint8_t len = pgm_read_byte(p++); + if (cmd == TFTLCD_DELAY8) { + delay(len); + len = 0; + } else { + for (uint8_t i = 0; i < len; i++) + dat[i] = pgm_read_byte(p++); + WriteCmdParamN(cmd, len, dat); + } + size -= len + 2; + } +} + +static void init_table16(const void *table, int16_t size) +{ + uint16_t *p = (uint16_t *) table; + while (size > 0) { + uint16_t cmd = pgm_read_word(p++); + uint16_t d = pgm_read_word(p++); + if (cmd == TFTLCD_DELAY) + delay(d); + else { + CS_ACTIVE; + WriteCmd(cmd); + WriteData(d); + CS_IDLE; + } + size -= 2 * sizeof(int16_t); + } +} + +void MCUFRIEND_kbv::begin(uint16_t ID) +{ + int16_t *p16; //so we can "write" to a const protected variable. + reset(); + _lcd_xor = 0; + if (ID == 0) + ID = 0x9341; + switch (_lcd_ID = ID) { +/* + static const uint16_t _regValues[] PROGMEM = { + 0x0000, 0x0001, // start oscillation + 0x0007, 0x0000, // source output control 0 D0 + 0x0013, 0x0000, // power control 3 off + 0x0011, 0x2604, // + 0x0014, 0x0015, // + 0x0010, 0x3C00, // + // 0x0013, 0x0040, // + // 0x0013, 0x0060, // + // 0x0013, 0x0070, // + 0x0013, 0x0070, // power control 3 PON PON1 AON + + 0x0001, 0x0127, // driver output control + // 0x0002, 0x0700, // field 0 b/c waveform xor waveform + 0x0003, 0x1030, // + 0x0007, 0x0000, // + 0x0008, 0x0404, // + 0x000B, 0x0200, // + 0x000C, 0x0000, // + 0x00015,0x0000, // + + //gamma setting + 0x0030, 0x0000, + 0x0031, 0x0606, + 0x0032, 0x0006, + 0x0033, 0x0403, + 0x0034, 0x0107, + 0x0035, 0x0101, + 0x0036, 0x0707, + 0x0037, 0x0304, + 0x0038, 0x0A00, + 0x0039, 0x0706, + + 0x0040, 0x0000, + 0x0041, 0x0000, + 0x0042, 0x013F, + 0x0043, 0x0000, + 0x0044, 0x0000, + 0x0045, 0x0000, + 0x0046, 0xEF00, + 0x0047, 0x013F, + 0x0048, 0x0000, + 0x0007, 0x0011, + 0x0007, 0x0017, +}; +*/ +#ifdef SUPPORT_0139 + case 0x0139: + _lcd_capable = AUTO_READINC | REV_SCREEN | XSA_XEA_16BIT; + static const uint16_t S6D0139_regValues[] PROGMEM = { + 0x0000, 0x0001, //Start oscillator + 0x0011, 0x1a00, //Power Control 2 + 0x0014, 0x2020, //Power Control 4 + 0x0010, 0x0900, //Power Control 1 + 0x0013, 0x0040, //Power Control 3 + 0x0013, 0x0060, //Power Control 3 + 0x0013, 0x0070, //Power Control 3 + 0x0011, 0x1a04, //Power Control 2 + 0x0010, 0x2f00, //Power Control 1 + 0x0001, 0x0127, //Driver Control: SM=0, GS=0, SS=1, 240x320 + 0x0002, 0x0100, //LCD Control: (.kbv was 0700) FLD=0, BC= 0, EOR=1 + 0x0003, 0x1030, //Entry Mode: TR1=0, DFM=0, BGR=1, I_D=3 + 0x0007, 0x0000, //Display Control: everything off + 0x0008, 0x0808, //Blank Period: FP=98, BP=8 + 0x0009, 0x0000, //f.k. + 0x000b, 0x0000, //Frame Control: + 0x000c, 0x0000, //Interface Control: system i/f + 0x0040, 0x0000, //Scan Line + 0x0041, 0x0000, //Vertical Scroll Control + 0x0042, 0x013f, //Screen 1 End + 0x0043, 0x0000, //Screen 1 start + 0x0044, 0x00ef, //Screen 2 end + 0x0045, 0x0000, //Screen 2 start + 0x0046, 0xef00, //Horiz address H=end, L=start + 0x0047, 0x013f, //Vert end + 0x0048, 0x0000, //Vert start + 0x0007, 0x0014, //Display Control: SPT=1, REV=1 + 0x0007, 0x0016, //Display Control: SPT=1, REV=1, display on + 0x0007, 0x0017, //Display Control: SPT=1, REV=1, display on, GON + }; + init_table16(S6D0139_regValues, sizeof(S6D0139_regValues)); + break; +#endif + case 0x0154: + _lcd_capable = AUTO_READINC | REV_SCREEN; + static const uint16_t S6D0154_regValues[] PROGMEM = { + 0x0011, 0x001A, + 0x0012, 0x3121, + 0x0013, 0x006C, + 0x0014, 0x4249, + + 0x0010, 0x0800, + TFTLCD_DELAY, 10, + 0x0011, 0x011A, + TFTLCD_DELAY, 10, + 0x0011, 0x031A, + TFTLCD_DELAY, 10, + 0x0011, 0x071A, + TFTLCD_DELAY, 10, + 0x0011, 0x0F1A, + TFTLCD_DELAY, 10, + 0x0011, 0x0F3A, + TFTLCD_DELAY, 30, + + 0x0001, 0x0128, + 0x0002, 0x0100, + 0x0003, 0x1030, + 0x0007, 0x1012, + 0x0008, 0x0303, + 0x000B, 0x1100, + 0x000C, 0x0000, + 0x000F, 0x1801, + 0x0015, 0x0020, + /* + 0x0050,0x0101, + 0x0051,0x0603, + 0x0052,0x0408, + 0x0053,0x0000, + 0x0054,0x0605, + 0x0055,0x0406, + 0x0056,0x0303, + 0x0057,0x0303, + 0x0058,0x0010, + 0x0059,0x1000, + */ + 0x0007, 0x0012, + TFTLCD_DELAY, 40, + 0x0007, 0x0013, /* GRAM Address Set */ + 0x0007, 0x0017, /* Display Control DISPLAY ON */ + + 0x0036, 0x00EF, + 0x0037, 0x0000, + 0x0038, 0x013F, + 0x0039, 0x0000, + }; + init_table16(S6D0154_regValues, sizeof(S6D0154_regValues)); + + break; + + case 0x1289: + _lcd_capable = 0 | XSA_XEA_16BIT | REV_SCREEN; + // came from MikroElektronika library http://www.hmsprojects.com/tft_lcd.html + static const uint16_t SSD1289_regValues[] PROGMEM = { + 0x0000, 0x0001, + 0x0003, 0xA8A4, + 0x000C, 0x0000, + 0x000D, 0x080C, // was 0x800C + 0x000E, 0x2B00, + 0x001E, 0x00B7, + 0x0001, 0x2B3F, // was 0x2B3F, + 0x0002, 0x0400, // was 0x0600 + 0x0010, 0x0000, + 0x0011, 0x6070, // was 0x6070 + 0x0005, 0x0000, + 0x0006, 0x0000, + 0x0016, 0xEF1C, + 0x0017, 0x0003, + 0x0007, 0x0233, + 0x000B, 0x0000, + 0x000F, 0x0000, + 0x0041, 0x0000, + 0x0042, 0x0000, + 0x0048, 0x0000, + 0x0049, 0x013F, + 0x004A, 0x0000, + 0x004B, 0x0000, + 0x0044, 0xEF95, + 0x0045, 0x0000, + 0x0046, 0x013F, + 0x0030, 0x0707, + 0x0031, 0x0204, + 0x0032, 0x0204, + 0x0033, 0x0502, + 0x0034, 0x0507, + 0x0035, 0x0204, + 0x0036, 0x0204, + 0x0037, 0x0502, + 0x003A, 0x0302, + 0x003B, 0x0302, + 0x0023, 0x0000, + 0x0024, 0x0000, + 0x0025, 0x8000, + 0x004f, 0x0000, + 0x004e, 0x0000, + }; + init_table16(SSD1289_regValues, sizeof(SSD1289_regValues)); + break; + +#ifdef SUPPORT_1963 + case 0x1963: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | READ_NODUMMY | INVERT_SS | INVERT_RGB; + // from NHD 5.0" 8-bit + static const uint8_t SSD1963_NHD_50_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 100, + (0xE0), 1, 0x01, // PLL enable + TFTLCD_DELAY8, 10, + (0xE0), 1, 0x03, // Lock PLL + (0xB0), 7, 0x08, 0x80, 0x03, 0x1F, 0x01, 0xDF, 0x00, //LCD SPECIFICATION + (0xF0), 1, 0x03, //was 00 pixel data interface + // (0x3A), 1, 0x60, // SET R G B format = 6 6 6 + (0xE2), 3, 0x1D, 0x02, 0x54, //PLL multiplier, set PLL clock to 120M + (0xE6), 3, 0x02, 0xFF, 0xFF, //PLL setting for PCLK, depends on resolution + (0xB4), 8, 0x04, 0x20, 0x00, 0x58, 0x80, 0x00, 0x00, 0x00, //HSYNC + (0xB6), 7, 0x02, 0x0D, 0x00, 0x20, 0x01, 0x00, 0x00, //VSYNC + (0x13), 0, //Enter Normal mode + (0x38), 0, //Exit Idle mode + 0x29, 0, //Display On + }; + // from NHD 7.0" 8-bit + static const uint8_t SSD1963_NHD_70_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 120, + (0xE2), 3, 0x1D, 0x02, 0x04, //PLL multiplier, set PLL clock to 120M + (0xE0), 1, 0x01, // PLL enable + TFTLCD_DELAY8, 10, + (0xE0), 1, 0x03, // Lock PLL + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 120, + (0xB0), 7, 0x08, 0x80, 0x03, 0x1F, 0x01, 0xDF, 0x00, //LCD SPECIFICATION + (0xF0), 1, 0x03, //was 00 pixel data interface + // (0x3A), 1, 0x60, // SET R G B format = 6 6 6 + (0xE6), 3, 0x0F, 0xFF, 0xFF, //PLL setting for PCLK, depends on resolution + (0xB4), 8, 0x04, 0x20, 0x00, 0x58, 0x80, 0x00, 0x00, 0x00, //HSYNC + (0xB6), 7, 0x02, 0x0D, 0x00, 0x20, 0x01, 0x00, 0x00, //VSYNC + (0x13), 0, //Enter Normal mode + (0x38), 0, //Exit Idle mode + 0x29, 0, //Display On + }; + // from UTFTv2.81 initlcd.h + static const uint8_t SSD1963_800_regValues[] PROGMEM = { + (0xE2), 3, 0x1E, 0x02, 0x54, //PLL multiplier, set PLL clock to 120M + (0xE0), 1, 0x01, // PLL enable + TFTLCD_DELAY8, 10, + (0xE0), 1, 0x03, // + TFTLCD_DELAY8, 10, + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 100, + (0xE6), 3, 0x03, 0xFF, 0xFF, //PLL setting for PCLK, depends on resolution + (0xB0), 7, 0x24, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x00, //LCD SPECIFICATION + // (0xB0), 7, 0x24, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x2D, //LCD SPECIFICATION + (0xB4), 8, 0x03, 0xA0, 0x00, 0x2E, 0x30, 0x00, 0x0F, 0x00, //HSYNC + (0xB6), 7, 0x02, 0x0D, 0x00, 0x10, 0x10, 0x00, 0x08, //VSYNC + (0xBA), 1, 0x0F, //GPIO[3:0] out 1 + (0xB8), 2, 0x07, 0x01, //GPIO3=input, GPIO[2:0]=output + (0xF0), 1, 0x03, //pixel data interface + TFTLCD_DELAY8, 1, + 0x28, 0, //Display Off + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 100, + 0x29, 0, //Display On + (0xBE), 6, 0x06, 0xF0, 0x01, 0xF0, 0x00, 0x00, //set PWM for B/L + (0xD0), 1, 0x0D, + }; + init_table(SSD1963_800_regValues, sizeof(SSD1963_800_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 800; + break; +#endif + +#ifdef SUPPORT_4535 + case 0x4535: + _lcd_capable = 0 | REV_SCREEN; // | INVERT_GS; + static const uint16_t LGDP4535_regValues[] PROGMEM = { + 0x0015, 0x0030, // Set the internal vcore voltage + 0x009A, 0x0010, // Start internal OSC + 0x0011, 0x0020, // set SS and SM bit + 0x0010, 0x3428, // set 1 line inversion + 0x0012, 0x0002, // set GRAM write direction and BGR=1 + 0x0013, 0x1038, // Resize register + TFTLCD_DELAY, 40, + 0x0012, 0x0012, // set the back porch and front porch + TFTLCD_DELAY, 40, + 0x0010, 0x3420, // set non-display area refresh cycle ISC[3:0] + 0x0013, 0x3045, // FMARK function + TFTLCD_DELAY, 70, + 0x0030, 0x0000, // RGB interface setting + 0x0031, 0x0402, // Frame marker Position + 0x0032, 0x0307, // RGB interface polarity + 0x0033, 0x0304, // SAP, BT[3:0], AP, DSTB, SLP, STB + 0x0034, 0x0004, // DC1[2:0], DC0[2:0], VC[2:0] + 0x0035, 0x0401, // VREG1OUT voltage + 0x0036, 0x0707, // VDV[4:0] for VCOM amplitude + 0x0037, 0x0305, // SAP, BT[3:0], AP, DSTB, SLP, STB + 0x0038, 0x0610, // DC1[2:0], DC0[2:0], VC[2:0] + 0x0039, 0x0610, // VREG1OUT voltage + 0x0001, 0x0100, // VDV[4:0] for VCOM amplitude + 0x0002, 0x0300, // VCM[4:0] for VCOMH + 0x0003, 0x1030, // GRAM horizontal Address + 0x0008, 0x0808, // GRAM Vertical Address + 0x000A, 0x0008, + 0x0060, 0x2700, // Gate Scan Line + 0x0061, 0x0001, // NDL,VLE, REV + 0x0090, 0x013E, + 0x0092, 0x0100, + 0x0093, 0x0100, + 0x00A0, 0x3000, + 0x00A3, 0x0010, + 0x0007, 0x0001, + 0x0007, 0x0021, + 0x0007, 0x0023, + 0x0007, 0x0033, + 0x0007, 0x0133, + }; + init_table16(LGDP4535_regValues, sizeof(LGDP4535_regValues)); + break; +#endif + + case 0x7783: + _lcd_capable = AUTO_READINC | REV_SCREEN | INVERT_GS; + static const uint16_t ST7781_regValues[] PROGMEM = { + 0x00FF, 0x0001, //can we do 0xFF + 0x00F3, 0x0008, + // LCD_Write_COM(0x00F3, + + 0x00, 0x0001, + 0x0001, 0x0100, // Driver Output Control Register (R01h) + 0x0002, 0x0700, // LCD Driving Waveform Control (R02h) + 0x0003, 0x1030, // Entry Mode (R03h) + 0x0008, 0x0302, + 0x0009, 0x0000, + 0x0010, 0x0000, // Power Control 1 (R10h) + 0x0011, 0x0007, // Power Control 2 (R11h) + 0x0012, 0x0000, // Power Control 3 (R12h) + 0x0013, 0x0000, // Power Control 4 (R13h) + TFTLCD_DELAY, 50, + 0x0010, 0x14B0, // Power Control 1 (R10h) + TFTLCD_DELAY, 10, + 0x0011, 0x0007, // Power Control 2 (R11h) + TFTLCD_DELAY, 10, + 0x0012, 0x008E, // Power Control 3 (R12h) + 0x0013, 0x0C00, // Power Control 4 (R13h) + 0x0029, 0x0015, // NVM read data 2 (R29h) + TFTLCD_DELAY, 10, + 0x0030, 0x0000, // Gamma Control 1 + 0x0031, 0x0107, // Gamma Control 2 + 0x0032, 0x0000, // Gamma Control 3 + 0x0035, 0x0203, // Gamma Control 6 + 0x0036, 0x0402, // Gamma Control 7 + 0x0037, 0x0000, // Gamma Control 8 + 0x0038, 0x0207, // Gamma Control 9 + 0x0039, 0x0000, // Gamma Control 10 + 0x003C, 0x0203, // Gamma Control 13 + 0x003D, 0x0403, // Gamma Control 14 + 0x0050, 0x0000, // Window Horizontal RAM Address Start (R50h) + 0x0051, 240 - 1, // Window Horizontal RAM Address End (R51h) + 0x0052, 0X0000, // Window Vertical RAM Address Start (R52h) + 0x0053, 320 - 1, // Window Vertical RAM Address End (R53h) + 0x0060, 0xA700, // Driver Output Control (R60h) .kbv was 0xa700 + 0x0061, 0x0001, // Driver Output Control (R61h) + 0x0090, 0X0029, // Panel Interface Control 1 (R90h) + + // Display On + 0x0007, 0x0133, // Display Control (R07h) + TFTLCD_DELAY, 50, + }; + init_table16(ST7781_regValues, sizeof(ST7781_regValues)); + break; + case 0x7789: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS; + static const uint8_t ST7789_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + (0x11), 0, //exit SLEEP mode + TFTLCD_DELAY8, 100, // if from Sleep + (0x36), 1, 0x80, //MADCTL: memory data access control + // (0x3A), 1, 0x66, //COLMOD: Interface Pixel format *** I use 262K-colors in 18bit/pixel format when using 8-bit interface to allow 3-bytes per pixel + (0x3A), 1, 0x55, //COLMOD: Interface Pixel format *** I use 65K-colors in 16bit/pixel (5-6-5) format when using 16-bit interface to allow 1-byte per pixel + (0xB2), 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, //PORCTRK: Porch setting [08 08 00 22 22] PSEN=0 anyway + (0xB7), 1, 0x35, //GCTRL: Gate Control [35] + (0xBB), 1, 0x2B, //VCOMS: VCOM setting VCOM=1.175 [20] VCOM=0.9 + (0xC0), 1, 0x04, //LCMCTRL: LCM Control [2C] + (0xC2), 2, 0x01, 0xFF, //VDVVRHEN: VDV and VRH Command Enable [01 FF] + (0xC3), 1, 0x11, //VRHS: VRH Set VAP=4.4, VAN=-4.4 [0B] + (0xC4), 1, 0x20, //VDVS: VDV Set [20] + (0xC6), 1, 0x0F, //FRCTRL2: Frame Rate control in normal mode [0F] + (0xD0), 2, 0xA4, 0xA1, //PWCTRL1: Power Control 1 [A4 A1] + (0xE0), 14, 0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19, //PVGAMCTRL: Positive Voltage Gamma control + (0xE1), 14, 0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19, //NVGAMCTRL: Negative Voltage Gamma control + (0x2A), 4, 0x00, 0x00, 0x00, 0xEF, //X address set + (0x2B), 4, 0x00, 0x00, 0x01, 0x3F, //Y address set + 0x29, 0, //Display On + TFTLCD_DELAY8, 10, + }; + static const uint8_t ST7789_regValues_arcain6[] PROGMEM = { + 0x01, 0, //Soft Reset + (0x11), 0, //exit SLEEP mode + TFTLCD_DELAY8, 100, // if from Sleep + (0x36), 1, 0x00, //MADCTL: memory data access control + (0x3A), 1, 0x05, //COLMOD: Interface Pixel format *** I use 65K-colors in 16bit/pixel (5-6-5) format when using 16-bit interface to allow 1-byte per pixel + (0xB2), 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, //PORCTRK: Porch setting [08 08 00 22 22] PSEN=0 anyway + (0xB7), 1, 0x35, //GCTRL: Gate Control [35] + (0xBB), 1, 0x35, //VCOMS: VCOM setting VCOM=??? [20] VCOM=0.9 + (0xC0), 1, 0x2C, //LCMCTRL: LCM Control [2C] + (0xC2), 2, 0x01, 0xFF, //VDVVRHEN: VDV and VRH Command Enable [01 FF] + (0xC3), 1, 0x13, //VRHS: VRH Set VAP=???, VAN=-??? [0B] + (0xC4), 1, 0x20, //VDVS: VDV Set [20] + (0xC6), 1, 0x0F, //FRCTRL2: Frame Rate control in normal mode [0F] + (0xCA), 1, 0x0F, //REGSEL2 [0F] + (0xC8), 1, 0x08, //REGSEL1 [08] + (0x55), 1, 0x90, //WRCACE [00] + (0xD0), 2, 0xA4, 0xA1, //PWCTRL1: Power Control 1 [A4 A1] + (0xE0), 14, 0xD0, 0x00, 0x06, 0x09, 0x0B, 0x2A, 0x3C, 0x55, 0x4B, 0x08, 0x16, 0x14, 0x19, 0x20, //PVGAMCTRL: Positive Voltage Gamma control + (0xE1), 14, 0xD0, 0x00, 0x06, 0x09, 0x0B, 0x29, 0x36, 0x54, 0x4B, 0x0D, 0x16, 0x14, 0x21, 0x20, //NVGAMCTRL: Negative Voltage Gamma control + // (0x2A), 4, 0x00, 0x00, 0x00, 0xEF, //X address set + // (0x2B), 4, 0x00, 0x00, 0x01, 0x3F, //Y address set + 0x29, 0, //Display On + TFTLCD_DELAY8, 10, + }; + init_table(ST7789_regValues, sizeof(ST7789_regValues)); // + break; +#ifdef SUPPORT_8347D + case 0x4747: //HX8347-D + _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS; + goto common_8347DGI; + case 0x9595: //HX8347-I + _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS; + common_8347DGI: + is8347 = 1; + static const uint8_t HX8347G_2_regValues[] PROGMEM = { + 0xEA, 2, 0x00, 0x20, //PTBA[15:0] + 0xEC, 2, 0x0C, 0xC4, //STBA[15:0] + 0xE8, 1, 0x38, //OPON[7:0] + 0xE9, 1, 0x10, //OPON1[7:0] + 0xF1, 1, 0x01, //OTPS1B + 0xF2, 1, 0x10, //GEN + //Gamma 2.2 Setting + 0x40, 13, 0x01, 0x00, 0x00, 0x10, 0x0E, 0x24, 0x04, 0x50, 0x02, 0x13, 0x19, 0x19, 0x16, + 0x50, 14, 0x1B, 0x31, 0x2F, 0x3F, 0x3F, 0x3E, 0x2F, 0x7B, 0x09, 0x06, 0x06, 0x0C, 0x1D, 0xCC, + //Power Voltage Setting + 0x1B, 1, 0x1B, //VRH=4.65V + 0x1A, 1, 0x01, //BT (VGH~15V,VGL~-10V,DDVDH~5V) + 0x24, 1, 0x2F, //VMH(VCOM High voltage ~3.2V) + 0x25, 1, 0x57, //VML(VCOM Low voltage -1.2V) + //****VCOM offset**/// + 0x23, 1, 0x88, //for Flicker adjust //can reload from OTP + //Power on Setting + 0x18, 1, 0x34, //I/P_RADJ,N/P_RADJ, Normal mode 60Hz + 0x19, 1, 0x01, //OSC_EN='1', start Osc + 0x01, 1, 0x00, //DP_STB='0', out deep sleep + 0x1F, 1, 0x88, // GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0 + TFTLCD_DELAY8, 5, + 0x1F, 1, 0x80, // GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0 + TFTLCD_DELAY8, 3, + 0x1F, 1, 0x90, // GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0 + TFTLCD_DELAY8, 5, + 0x1F, 1, 0xD0, // GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0 + TFTLCD_DELAY8, 5, + //262k/65k color selection + 0x17, 1, 0x05, //default 0x06 262k color // 0x05 65k color + //SET PANEL + 0x36, 1, 0x00, //SS_P, GS_P,REV_P,BGR_P + //Display ON Setting + 0x28, 1, 0x38, //GON=1, DTE=1, D=1000 + TFTLCD_DELAY8, 40, + 0x28, 1, 0x3F, //GON=1, DTE=1, D=1100 + + 0x16, 1, 0x18, + //Set GRAM Area + 0x02, 2, 0x00, 0x00, //Column Start + 0x04, 2, 0x00, 0xEF, //Column End + 0x06, 2, 0x00, 0x00, //Row Start + 0x08, 2, 0x01, 0x3F, //Row End + }; + init_table(HX8347G_2_regValues, sizeof(HX8347G_2_regValues)); + break; +#endif +#ifdef SUPPORT_8347A + case 0x8347: + _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS; + // AN.01 The reference setting of CMO 3.2” Panel + static const uint8_t HX8347A_CMO32_regValues[] PROGMEM = { + // VENDOR Gamma for 3.2" + (0x46), 12, 0xA4, 0x53, 0x00, 0x44, 0x04, 0x67, 0x33, 0x77, 0x12, 0x4C, 0x46, 0x44, + //240x320 window setting + (0x02), 2, 0x00, 0x00, // Column address start2 + (0x04), 2, 0x00, 0xEF, // Column address end2 + (0x06), 2, 0x00, 0x00, // Row address start2 + (0x08), 2, 0x01, 0x3F, // Row address end2 + // Display Setting + (0x01), 1, 0x06, // IDMON=0, INVON=1, NORON=1, PTLON=0 + (0x16), 1, 0x48, // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0 + (0x23), 3, 0x95, 0x95, 0xFF, // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111 + + (0x27), 4, 0x02, 0x02, 0x02, 0x02, // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2 + (0x2C), 2, 0x02, 0x02, // I_BP=2, I_FP=2 + + (0x3a), 4, 0x01, 0x01, 0xF0, 0x00, // N_RTN=0, N_NW=1, P_RTN=0, P_NW=1, I_RTN=15, I_NW=0, DIV=0 + TFTLCD_DELAY8, 5, + (0x35), 2, 0x38, 0x78, // EQS=38h, EQP=78h + (0x3E), 1, 0x38, // SON=38h + (0x40), 2, 0x0F, 0xF0, // GDON=0Fh, GDOFF + // Power Supply Setting + (0x19), 1, 0x49, // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz + (0x93), 1, 0x0F, // RADJ=1111, 100% + TFTLCD_DELAY8, 5, + (0x20), 1, 0x40, // BT=0100 + (0x1D), 3, 0x07, 0x00, 0x04, // VC1=7, VC3=0, VRH=?? + //VCOM SETTING for 3.2" + (0x44), 2, 0x4D, 0x11, // VCM=100 1101, VDV=1 0001 + TFTLCD_DELAY8, 10, + (0x1C), 1, 0x04, // AP=100 + TFTLCD_DELAY8, 20, + (0x1B), 1, 0x18, // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 40, + (0x1B), 1, 0x10, // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 40, + (0x43), 1, 0x80, //set VCOMG=1 + TFTLCD_DELAY8, 100, + // Display ON Setting + (0x90), 1, 0x7F, // SAP=0111 1111 + (0x26), 1, 0x04, //GON=0, DTE=0, D=01 + TFTLCD_DELAY8, 40, + (0x26), 1, 0x24, //GON=1, DTE=0, D=01 + (0x26), 1, 0x2C, //GON=1, DTE=0, D=11 + TFTLCD_DELAY8, 40, + (0x26), 1, 0x3C, //GON=1, DTE=1, D=11 + // INTERNAL REGISTER SETTING + (0x57), 1, 0x02, // TEST_Mode=1: into TEST mode + (0x55), 1, 0x00, // VDC_SEL=000, VDDD=1.95V + (0xFE), 1, 0x5A, // For ESD protection + (0x57), 1, 0x00, // TEST_Mode=0: exit TEST mode + }; + // AN.01 The reference setting of CMO 2.4” Panel + static const uint8_t HX8347A_CMO24_regValues[] PROGMEM = { + // VENDOR Gamma for 2.4" + (0x46), 12, 0x94, 0x41, 0x00, 0x33, 0x23, 0x45, 0x44, 0x77, 0x12, 0xCC, 0x46, 0x82, + //240x320 window setting + (0x02), 2, 0x00, 0x00, // Column address start2 + (0x04), 2, 0x00, 0xEF, // Column address end2 + (0x06), 2, 0x00, 0x00, // Row address start2 + (0x08), 2, 0x01, 0x3F, // Row address end2 + // Display Setting + (0x01), 1, 0x06, // IDMON=0, INVON=1, NORON=1, PTLON=0 + (0x16), 1, 0x48, // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0 + (0x23), 3, 0x95, 0x95, 0xFF, // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111 + + (0x27), 4, 0x02, 0x02, 0x02, 0x02, // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2 + (0x2C), 2, 0x02, 0x02, // I_BP=2, I_FP=2 + + (0x3a), 4, 0x01, 0x01, 0xF0, 0x00, // N_RTN=0, N_NW=1, P_RTN=0, P_NW=1, I_RTN=15, I_NW=0, DIV=0 + TFTLCD_DELAY8, 5, + (0x35), 2, 0x38, 0x78, // EQS=38h, EQP=78h + (0x3E), 1, 0x38, // SON=38h + (0x40), 2, 0x0F, 0xF0, // GDON=0Fh, GDOFF + // Power Supply Setting + (0x19), 1, 0x49, // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz + (0x93), 1, 0x0F, // RADJ=1111, 100% + TFTLCD_DELAY8, 5, + (0x20), 1, 0x40, // BT=0100 + (0x1D), 3, 0x07, 0x00, 0x04, // VC1=7, VC3=0, VRH=?? + //VCOM SETTING for 2.4" + (0x44), 2, 0x40, 0x12, // VCM=100 0000, VDV=1 0001 + TFTLCD_DELAY8, 10, + (0x1C), 1, 0x04, // AP=100 + TFTLCD_DELAY8, 20, + (0x1B), 1, 0x18, // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 40, + (0x1B), 1, 0x10, // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 40, + (0x43), 1, 0x80, //set VCOMG=1 + TFTLCD_DELAY8, 100, + // Display ON Setting + (0x90), 1, 0x7F, // SAP=0111 1111 + (0x26), 1, 0x04, //GON=0, DTE=0, D=01 + TFTLCD_DELAY8, 40, + (0x26), 1, 0x24, //GON=1, DTE=0, D=01 + (0x26), 1, 0x2C, //GON=1, DTE=0, D=11 + TFTLCD_DELAY8, 40, + (0x26), 1, 0x3C, //GON=1, DTE=1, D=11 + // INTERNAL REGISTER SETTING + (0x57), 1, 0x02, // TEST_Mode=1: into TEST mode + (0x55), 1, 0x00, // VDC_SEL=000, VDDD=1.95V + (0xFE), 1, 0x5A, // For ESD protection + (0x57), 1, 0x00, // TEST_Mode=0: exit TEST mode + }; + static const uint8_t HX8347A_ITDB02_regValues[] PROGMEM = { + // VENDOR Gamma ITDB02 same as CMO32. Delays are shorter than AN01 + (0x46), 12, 0xA4, 0x53, 0x00, 0x44, 0x04, 0x67, 0x33, 0x77, 0x12, 0x4C, 0x46, 0x44, + //240x320 window setting + (0x02), 2, 0x00, 0x00, // Column address start2 + (0x04), 2, 0x00, 0xEF, // Column address end2 + (0x06), 2, 0x00, 0x00, // Row address start2 + (0x08), 2, 0x01, 0x3F, // Row address end2 + // Display Setting + (0x01), 1, 0x06, // IDMON=0, INVON=1, NORON=1, PTLON=0 + (0x16), 1, 0xC8, // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0 .itead + (0x23), 3, 0x95, 0x95, 0xFF, // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111 + + (0x27), 4, 0x02, 0x02, 0x02, 0x02, // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2 + (0x2C), 2, 0x02, 0x02, // I_BP=2, I_FP=2 + + (0x3a), 4, 0x01, 0x00, 0xF0, 0x00, // N_RTN=0, N_NW=1, P_RTN=0, ?? P_NW=1, I_RTN=15, I_NW=0, DIV=0 .itead + TFTLCD_DELAY8, 5, + (0x35), 2, 0x38, 0x78, // EQS=38h, EQP=78h + (0x3E), 1, 0x38, // SON=38h + (0x40), 2, 0x0F, 0xF0, // GDON=0Fh, GDOFF + // Power Supply Setting + (0x19), 1, 0x49, // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz + (0x93), 1, 0x0F, // RADJ=1111, 100% + TFTLCD_DELAY8, 5, + (0x20), 1, 0x40, // BT=0100 + (0x1D), 3, 0x07, 0x00, 0x04, // VC1=7, VC3=0, VRH=?? + //VCOM SETTING for ITDB02 + (0x44), 2, 0x4D, 0x0E, // VCM=101 0000 4D, VDV=1 0001 .itead + TFTLCD_DELAY8, 5, + (0x1C), 1, 0x04, // AP=100 + TFTLCD_DELAY8, 5, + (0x1B), 1, 0x18, // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 5, + (0x1B), 1, 0x10, // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0 + TFTLCD_DELAY8, 5, + (0x43), 1, 0x80, //set VCOMG=1 + TFTLCD_DELAY8, 5, + // Display ON Setting + (0x90), 1, 0x7F, // SAP=0111 1111 + (0x26), 1, 0x04, //GON=0, DTE=0, D=01 + TFTLCD_DELAY8, 5, + (0x26), 1, 0x24, //GON=1, DTE=0, D=01 + (0x26), 1, 0x2C, //GON=1, DTE=0, D=11 + TFTLCD_DELAY8, 5, + (0x26), 1, 0x3C, //GON=1, DTE=1, D=11 + // INTERNAL REGISTER SETTING for ITDB02 + (0x57), 1, 0x02, // TEST_Mode=1: into TEST mode + (0x95), 1, 0x01, // SET DISPLAY CLOCK AND PUMPING CLOCK TO SYNCHRONIZE .itead + (0x57), 1, 0x00, // TEST_Mode=0: exit TEST mode + }; + static const uint8_t HX8347A_NHD_regValues[] PROGMEM = { + //Gamma Setting NHD + (0x46), 12, 0x94, 0x41, 0x00, 0x33, 0x23, 0x45, 0x44, 0x77, 0x12, 0xCC, 0x46, 0x82, + (0x02), 2, 0x00, 0x00, //COLSTARTH + (0x04), 2, 0x00, 0xEF, //COLENDH + (0x06), 2, 0x00, 0x00, //ROWSTARTH + (0x08), 2, 0x01, 0x3F, //ROWENDH + (0x01), 1, 0x06, //Display Mode [06] + (0x16), 1, 0xC8, //MADCTL [00] MY=1, MX=1, BGR=1 +// (0x70), 1, 0x05, //Panel [06] 16-bit + (0x23), 3, 0x95, 0x95, 0xFF, //Cycle Control 1-3 [95 95 FF] + (0x27), 4, 0x02, 0x02, 0x02, 0x02, //Display Control 2-5 [02 02 02 02] + (0x2C), 2, 0x02, 0x02, //Display Control 6-7 [02 02] + (0x3A), 4, 0x01, 0x01, 0xF0, 0x00, //Cycle Control 1-4 [01 01 F0 00] + TFTLCD_DELAY8, 80, + (0x35), 2, 0x38, 0x78, //Display Control 9-10 [09 09] EQS=56, EQP=120 + (0x3E), 1, 0x38, //Cycle Control 5 [38] + (0x40), 1, 0x0F, //Cycle Control 6 [03] GDON=15 + (0x41), 1, 0xF0, //Cycle Control 14 [F8] GDOF=248 + + (0x19), 1, 0x2D, //OSC Control 1 [86] CADJ=2, CUADJ=6, OSCEN=1 + (0x93), 1, 0x06, //SAP Idle mode [00] ??? .nhd + TFTLCD_DELAY8, 80, + (0x20), 1, 0x40, //Power Control 6 [40] + (0x1D), 3, 0x07, 0x00, 0x04, //Power Control 3-5 [04 00 06] VC=7 + (0x44), 2, 0x3C, 0x12, //VCOM Control 2-3 [5A 11] VCM=60, VDV=18 + TFTLCD_DELAY8, 80, + (0x1C), 1, 0x04, //Power Control 2 [04] + TFTLCD_DELAY8, 80, + (0x43), 1, 0x80, //VCOM Control 1 [80] + TFTLCD_DELAY8, 80, + (0x1B), 1, 0x08, //Power Control 1 [00] DK=1 + TFTLCD_DELAY8, 80, + (0x1B), 1, 0x10, //Power Control 1 [00] PON=1 + TFTLCD_DELAY8, 80, + (0x90), 1, 0x7F, //Display Control 8 [0A] + (0x26), 1, 0x04, //Display Control 1 [A0] D=1 + TFTLCD_DELAY8, 80, + (0x26), 1, 0x24, //Display Control 1 [A0] GON=1, D=1 + (0x26), 1, 0x2C, //Display Control 1 [A0] GON=1, D=3 + TFTLCD_DELAY8, 80, + (0x26), 1, 0x3C, //Display Control 1 [A0] GON=1, DTE=1, D=3 + (0x57), 1, 0x02, //? + (0x55), 1, 0x00, //? + (0x57), 1, 0x00, //? + }; + // Atmel ASF code uses VCOM2-3: 0x38, 0x12. 50ms delays and no TEST mode changes. + init_table(HX8347A_NHD_regValues, sizeof(HX8347A_NHD_regValues)); + // init_table(HX8347A_CMO32_regValues, sizeof(HX8347A_CMO32_regValues)); + // init_table(HX8347A_CMO24_regValues, sizeof(HX8347A_CMO24_regValues)); + // init_table(HX8347A_ITDB02_regValues, sizeof(HX8347A_ITDB02_regValues)); + // init_table(HX8347G_2_regValues, sizeof(HX8347G_2_regValues)); + break; +#endif + case 0x5408: + _lcd_capable = 0 | REV_SCREEN | READ_BGR | INVERT_GS; + goto common_9320; + case 0x9320: + _lcd_capable = 0 | REV_SCREEN | READ_BGR; + common_9320: + static const uint16_t ILI9320_regValues[] PROGMEM = { + 0x00e5, 0x8000, + 0x0000, 0x0001, + 0x0001, 0x100, + 0x0002, 0x0700, + 0x0003, 0x1030, + 0x0004, 0x0000, + 0x0008, 0x0202, + 0x0009, 0x0000, + 0x000A, 0x0000, + 0x000C, 0x0000, + 0x000D, 0x0000, + 0x000F, 0x0000, + //-----Power On sequence----------------------- + 0x0010, 0x0000, + 0x0011, 0x0007, + 0x0012, 0x0000, + 0x0013, 0x0000, + TFTLCD_DELAY, 50, + 0x0010, 0x17B0, + 0x0011, 0x0007, + TFTLCD_DELAY, 10, + 0x0012, 0x013A, + TFTLCD_DELAY, 10, + 0x0013, 0x1A00, + 0x0029, 0x000c, + TFTLCD_DELAY, 10, + //-----Gamma control----------------------- + 0x0030, 0x0000, + 0x0031, 0x0505, + 0x0032, 0x0004, + 0x0035, 0x0006, + 0x0036, 0x0707, + 0x0037, 0x0105, + 0x0038, 0x0002, + 0x0039, 0x0707, + 0x003C, 0x0704, + 0x003D, 0x0807, + //-----Set RAM area----------------------- + 0x0050, 0x0000, + 0x0051, 0x00EF, + 0x0052, 0x0000, + 0x0053, 0x013F, + 0x0060, 0xA700, //GS=1 + 0x0061, 0x0001, + 0x006A, 0x0000, + 0x0021, 0x0000, + 0x0020, 0x0000, + //-----Partial Display Control------------ + 0x0080, 0x0000, + 0x0081, 0x0000, + 0x0082, 0x0000, + 0x0083, 0x0000, + 0x0084, 0x0000, + 0x0085, 0x0000, + //-----Panel Control---------------------- + 0x0090, 0x0010, + 0x0092, 0x0000, + 0x0093, 0x0003, + 0x0095, 0x0110, + 0x0097, 0x0000, + 0x0098, 0x0000, + //-----Display on----------------------- + 0x0007, 0x0173, + TFTLCD_DELAY, 50, + }; + init_table16(ILI9320_regValues, sizeof(ILI9320_regValues)); + break; + case 0x6809: + _lcd_capable = 0 | REV_SCREEN | INVERT_GS | AUTO_READINC; + goto common_93x5; + case 0x9325: + _lcd_capable = 0 | REV_SCREEN | INVERT_GS; + goto common_93x5; + case 0x9335: + _lcd_capable = 0 | REV_SCREEN; + common_93x5: + static const uint16_t ILI9325_regValues[] PROGMEM = { + 0x00E5, 0x78F0, // set SRAM internal timing + 0x0001, 0x0100, // set Driver Output Control + 0x0002, 0x0200, // set 1 line inversion + 0x0003, 0x1030, // set GRAM write direction and BGR=1. + 0x0004, 0x0000, // Resize register + 0x0005, 0x0000, // .kbv 16bits Data Format Selection + 0x0008, 0x0207, // set the back porch and front porch + 0x0009, 0x0000, // set non-display area refresh cycle ISC[3:0] + 0x000A, 0x0000, // FMARK function + 0x000C, 0x0000, // RGB interface setting + 0x000D, 0x0000, // Frame marker Position + 0x000F, 0x0000, // RGB interface polarity + // ----------- Power On sequence ----------- // + 0x0010, 0x0000, // SAP, BT[3:0], AP, DSTB, SLP, STB + 0x0011, 0x0007, // DC1[2:0], DC0[2:0], VC[2:0] + 0x0012, 0x0000, // VREG1OUT voltage + 0x0013, 0x0000, // VDV[4:0] for VCOM amplitude + 0x0007, 0x0001, + TFTLCD_DELAY, 200, // Dis-charge capacitor power voltage + 0x0010, 0x1690, // SAP, BT[3:0], AP, DSTB, SLP, STB + 0x0011, 0x0227, // Set DC1[2:0], DC0[2:0], VC[2:0] + TFTLCD_DELAY, 50, // wait_ms 50ms + 0x0012, 0x000D, // 0012 + TFTLCD_DELAY, 50, // wait_ms 50ms + 0x0013, 0x1200, // VDV[4:0] for VCOM amplitude + 0x0029, 0x000A, // 04 VCM[5:0] for VCOMH + 0x002B, 0x000D, // Set Frame Rate + TFTLCD_DELAY, 50, // wait_ms 50ms + 0x0020, 0x0000, // GRAM horizontal Address + 0x0021, 0x0000, // GRAM Vertical Address + // ----------- Adjust the Gamma Curve ----------// + + 0x0030, 0x0000, + 0x0031, 0x0404, + 0x0032, 0x0003, + 0x0035, 0x0405, + 0x0036, 0x0808, + 0x0037, 0x0407, + 0x0038, 0x0303, + 0x0039, 0x0707, + 0x003C, 0x0504, + 0x003D, 0x0808, + + //------------------ Set GRAM area ---------------// + 0x0050, 0x0000, // Horizontal GRAM Start Address + 0x0051, 0x00EF, // Horizontal GRAM End Address + 0x0052, 0x0000, // Vertical GRAM Start Address + 0x0053, 0x013F, // Vertical GRAM Start Address + 0x0060, 0x2700, // Gate Scan Line GS=0 [0xA700] + 0x0061, 0x0001, // NDL,VLE, REV .kbv + 0x006A, 0x0000, // set scrolling line + //-------------- Partial Display Control ---------// + 0x0080, 0x0000, + 0x0081, 0x0000, + 0x0082, 0x0000, + 0x0083, 0x0000, + 0x0084, 0x0000, + 0x0085, 0x0000, + //-------------- Panel Control -------------------// + 0x0090, 0x0010, + 0x0092, 0x0000, + 0x0007, 0x0133, // 262K color and display ON + }; + init_table16(ILI9325_regValues, sizeof(ILI9325_regValues)); + break; + case 0x9327: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS; + static const uint8_t ILI9327_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + 0x28, 0, //Display Off + // 0xE0, 1, 0x20, //NV Memory Write [00] + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 100, + 0xB0, 1, 0x00, //Disable Protect for cmds B1-DF, E0-EF, F0-FF + // 0xD1, 3, 0x00, 0x71, 0x19, //VCOM control [00 40 0F] + // 0xD0, 3, 0x07, 0x01, 0x08, //Power Setting [07 04 8C] + 0xC1, 4, 0x10, 0x10, 0x02, 0x02, //Display Timing [10 10 02 02] + 0xC0, 6, 0x00, 0x35, 0x00, 0x00, 0x01, 0x02, //Panel Drive [00 35 00 00 01 02 REV=0,GS=0,SS=0 + 0xC5, 1, 0x04, //Frame Rate [04] + 0xD2, 2, 0x01, 0x04, //Power Setting [01 44] + // 0xC8, 15, 0x04, 0x67, 0x35, 0x04, 0x08, 0x06, 0x24, 0x01, 0x37, 0x40, 0x03, 0x10, 0x08, 0x80, 0x00, + // 0xC8, 15, 0x00, 0x77, 0x77, 0x04, 0x04, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xCA, 1, 0x00, //DGC LUT ??? + 0xEA, 1, 0x80, //3-Gamma Function Enable + // 0xB0, 1, 0x03, //Enable Protect + 0x36, 1, 0x48, // Memory Access + 0x3A, 1, 0x55, //Pixel read=565, write=565 + 0x2A, 4, 0x00, 0x00, 0x00, 0xEF, // wid: 0, 239 + 0x2B, 4, 0x00, 0x00, 0x01, 0x8F, // ht: 0, 399 + 0x30, 4, 0x00, 0x00, 0x01, 0x8F, // Partial Area: 0, 399 + 0x29, 0, //Display On + }; + init_table(ILI9327_regValues, sizeof(ILI9327_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 400; + p16 = (int16_t *) & WIDTH; + *p16 = 240; + break; + case 0x9302: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS; + goto common_9329; + case 0x9329: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS; + common_9329: + static const uint8_t ILI9329_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 50, // .kbv will power up with ONLY reset, sleep out, display on + 0x28, 0, //Display Off + // 0xF6, 3, 0x01, 0x01, 0x00, //Interface Control needs EXTC=1 MX_EOR=1, TM=0, RIM=0 + 0xB6, 3, 0x0A, 0x22, 0x27, //Display Function [0A 82 27] ILI9329: REV=0, SS=1 + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel read=565, write=565 + }; + init_table(ILI9329_regValues, sizeof(ILI9329_regValues)); + break; + case 0x9341: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS; + static const uint8_t ILI9341_regValues_2_4[] PROGMEM = { // BOE 2.4" + 0x01, 0, // software reset + TFTLCD_DELAY8, 50, // .kbv will power up with ONLY reset, sleep out, display on + 0x28, 0, //Display Off + 0xF6, 3, 0x01, 0x01, 0x00, //Interface Control needs EXTC=1 MV_EOR=0, TM=0, RIM=0 + 0xCF, 3, 0x00, 0x81, 0x30, //Power Control B [00 81 30] + 0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power On Seq [55 01 23 01] + 0xE8, 3, 0x85, 0x10, 0x78, //Driver Timing A [04 11 7A] + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power Control A [39 2C 00 34 02] + 0xF7, 1, 0x20, //Pump Ratio [10] + 0xEA, 2, 0x00, 0x00, //Driver Timing B [66 00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] + // 0xB6, 2, 0x0A, 0xA2, 0x27, //Display Function [0A 82 27 XX] .kbv SS=1 + 0xB4, 1, 0x00, //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1 + 0xC0, 1, 0x21, //Power Control 1 [26] + 0xC1, 1, 0x11, //Power Control 2 [00] + 0xC5, 2, 0x3F, 0x3C, //VCOM 1 [31 3C] + 0xC7, 1, 0xB5, //VCOM 2 [C0] + 0x36, 1, 0x48, //Memory Access [00] + 0xF2, 1, 0x00, //Enable 3G [02] + 0x26, 1, 0x01, //Gamma Set [01] + 0xE0, 15, 0x0f, 0x26, 0x24, 0x0b, 0x0e, 0x09, 0x54, 0xa8, 0x46, 0x0c, 0x17, 0x09, 0x0f, 0x07, 0x00, + 0xE1, 15, 0x00, 0x19, 0x1b, 0x04, 0x10, 0x07, 0x2a, 0x47, 0x39, 0x03, 0x06, 0x06, 0x30, 0x38, 0x0f, + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; + static const uint8_t ILI9341_regValues_ada[] PROGMEM = { // Adafruit_TFTLCD only works with EXTC=0 + 0x01, 0, // software reset + TFTLCD_DELAY8, 50, + 0x28, 0, //Display Off + // 0xF6, 3, 0x00, 0x01, 0x00, //Interface Control needs EXTC=1 TM=0, RIM=0 + // 0xF6, 3, 0x01, 0x01, 0x03, //Interface Control needs EXTC=1 RM=1, RIM=1 + 0xF6, 3, 0x09, 0x01, 0x03, //Interface Control needs EXTC=1 RM=0, RIM=1 + 0xB0, 1, 0x40, //RGB Signal [40] RCM=2 + 0xB4, 1, 0x00, //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1 + 0xC0, 1, 0x23, //Power Control 1 [26] + 0xC1, 1, 0x10, //Power Control 2 [00] + 0xC5, 2, 0x2B, 0x2B, //VCOM 1 [31 3C] + 0xC7, 1, 0xC0, //VCOM 2 [C0] + 0x36, 1, 0x88, //Memory Access [00] + 0xB1, 2, 0x00, 0x1B, //Frame Control [00 1B] + 0xB7, 1, 0x07, //Entry Mode [00] + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 150, + 0x29, 0, //Display On + 0x3A, 1, 0x55, //Pixel Format [66] + }; +#if !defined(USE_SERIAL) + if (readReg32(0xD3) == 0x0000) { //weird DealExtreme EXTC=0 shield + init_table(ILI9341_regValues_ada, sizeof(ILI9341_regValues_ada)); + _lcd_capable |= REV_SCREEN | READ_BGR; + } else +#endif + { + init_table(ILI9341_regValues_2_4, sizeof(ILI9341_regValues_2_4)); // + } + break; + case 0x9481: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_BGR; + static const uint8_t ILI9481_regValues[] PROGMEM = { // Atmel MaxTouch + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 50, + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 20, + 0xD0, 3, 0x07, 0x42, 0x18, //Set Power + 0xD1, 3, 0x00, 0x07, 0x10, // Set VCOM + 0xD2, 2, 0x01, 0x02, // Set Power for Normal Mode + 0xC0, 5, 0x10, 0x3B, 0x00, 0x02, 0x11, //Set Panel Driving + 0xC5, 1, 0x08, //Frame Rate + 0xC8, 12, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00, + 0x36, 1, 0x0A, //Memory Access [00] + 0x3A, 1, 0x55, //Interlace Pixel Format [XX] + + 0x2A, 4, 0x00, 0x00, 0x01, 0x3F, + 0x2B, 4, 0x00, 0x00, 0x01, 0xE0, + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 120, + 0x29, 0, //Display On + TFTLCD_DELAY8, 25, + }; + init_table(ILI9481_regValues, sizeof(ILI9481_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 320; + break; + case 0x9486: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN; + static const uint8_t ILI9486_regValues[] PROGMEM = { + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 50, + 0x28, 0, //Display Off + 0xC0, 2, 0x0d, 0x0d, //Power Control 1 [0x0E0E] + 0xC1, 2, 0x43, 0x00, //Power Control 2 [0x4300] + 0xC2, 1, 0x00, //Power Control 3 + 0xC5, 4, 0x00, 0x48, 0x00, 0x48, //VCOM Control 1 [0x00400040] + 0xB4, 1, 0x00, //Inversion Control + 0xB6, 3, 0x00, 0x02, 0x3B, // Display Function Control .kbv GS=0,SS=0 + 0xE0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00, + 0xE1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f, + 0x20, 0, // Display Inversion OFF + 0x36, 1, 0x0A, //Memory Access + 0x3A, 1, 0x55, //Interlace Pixel + // 0x21, 0, //Invert display !!! + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 50, + 0x29, 0, //Display On + }; + init_table(ILI9486_regValues, sizeof(ILI9486_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 320; + break; + case 0x9488: + _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS; + static const uint8_t ILI9488_regValues_max[] PROGMEM = { // Atmel MaxTouch + 0x01, 0, //Soft Reset + TFTLCD_DELAY8, 50, + 0x28, 0, //Display Off + 0xC0, 2, 0x10, 0x10, //Power Control 1 [0E 0E] + 0xC1, 1, 0x41, //Power Control 2 [43] + 0xC5, 4, 0x00, 0x22, 0x80, 0x40, //VCOM Control 1 [00 40 00 40] + 0x36, 1, 0x68, //Memory Access [00] + 0xB0, 1, 0x00, //Interface [00] + 0xB1, 2, 0xB0, 0x11, //Frame Rate Control [B0 11] + 0xB4, 1, 0x02, //Inversion Control [02] + 0xB6, 3, 0x02, 0x02, 0x3B, // Display Function Control [02 02 3B] .kbv NL=480 + 0xB7, 1, 0xC6, //Entry Mode [06] + 0x3A, 1, 0x55, //Interlace Pixel Format [XX] + 0xF7, 4, 0xA9, 0x51, 0x2C, 0x82, //Adjustment Control 3 [A9 51 2C 82] + 0x11, 0, //Sleep Out + TFTLCD_DELAY8, 150, + 0x29, 0, //Display On + }; + init_table(ILI9488_regValues_max, sizeof(ILI9488_regValues_max)); + p16 = (int16_t *) & HEIGHT; + *p16 = 480; + p16 = (int16_t *) & WIDTH; + *p16 = 320; + break; + case 0xB505: //R61505V + case 0xC505: //R61505W + _lcd_capable = 0 | REV_SCREEN | READ_LOWHIGH; + static const uint16_t R61505V_regValues[] PROGMEM = { + 0x0000, 0x0000, + 0x0000, 0x0000, + 0x0000, 0x0000, + 0x0000, 0x0001, + 0x00A4, 0x0001, //CALB=1 + TFTLCD_DELAY, 10, + 0x0060, 0x2700, //NL + 0x0008, 0x0808, //FP & BP + 0x0030, 0x0214, //Gamma settings + 0x0031, 0x3715, + 0x0032, 0x0604, + 0x0033, 0x0E16, + 0x0034, 0x2211, + 0x0035, 0x1500, + 0x0036, 0x8507, + 0x0037, 0x1407, + 0x0038, 0x1403, + 0x0039, 0x0020, + 0x0090, 0x0015, //DIVI & RTNI + 0x0010, 0x0410, //BT,AP + 0x0011, 0x0237, //VC,DC0,DC1 + 0x0029, 0x0046, //VCM1 + 0x002A, 0x0046, //VCMSEL,VCM2 + // Sleep mode IN sequence + 0x0007, 0x0000, + //0x0012, 0x0000, //PSON=0,PON=0 + // Sleep mode EXIT sequence + 0x0012, 0x0189, //VRH=9,VCMR=1,PSON=0,PON=0 + 0x0013, 0x1100, //VDV + TFTLCD_DELAY, 150, + 0x0012, 0x01B9, //VRH=9,VCMR=1,PSON=1,PON=1 [018F] + 0x0001, 0x0100, //SS=1 Other mode settings + 0x0002, 0x0200, //BC0=1--Line inversion + 0x0003, 0x1030, + 0x0009, 0x0001, //ISC=1 [0000] + 0x000A, 0x0000, // [0000] + // 0x000C, 0x0001, //RIM=1 [0000] + 0x000D, 0x0000, // [0000] + 0x000E, 0x0030, //VEM=3 VCOM equalize [0000] + 0x0050, 0x0000, //Display window area setting + 0x0051, 0x00EF, + 0x0052, 0x0000, + 0x0053, 0x013F, + 0x0061, 0x0001, + 0x006A, 0x0000, + 0x0080, 0x0000, + 0x0081, 0x0000, + 0x0082, 0x005F, + 0x0092, 0x0100, + 0x0093, 0x0701, + TFTLCD_DELAY, 80, + 0x0007, 0x0100, //BASEE=1--Display On + }; + init_table16(R61505V_regValues, sizeof(R61505V_regValues)); + break; + case 0xB509: + _lcd_capable = REV_SCREEN; + static const uint16_t R61509V_regValues[] PROGMEM = { + 0x0000, 0x0000, + 0x0000, 0x0000, + 0x0000, 0x0000, + 0x0000, 0x0000, + TFTLCD_DELAY, 15, + 0x0400, 0x6200, //NL=0x31 (49) i.e. 400 rows + 0x0008, 0x0808, + //gamma + 0x0300, 0x0C00, + 0x0301, 0x5A0B, + 0x0302, 0x0906, + 0x0303, 0x1017, + 0x0304, 0x2300, + 0x0305, 0x1700, + 0x0306, 0x6309, + 0x0307, 0x0C09, + 0x0308, 0x100C, + 0x0309, 0x2232, + + 0x0010, 0x0016, //69.5Hz 0016 + 0x0011, 0x0101, + 0x0012, 0x0000, + 0x0013, 0x0001, + + 0x0100, 0x0330, //BT,AP + 0x0101, 0x0237, //DC0,DC1,VC + 0x0103, 0x0D00, //VDV + 0x0280, 0x6100, //VCM + 0x0102, 0xC1B0, //VRH,VCMR,PSON,PON + TFTLCD_DELAY, 50, + + 0x0001, 0x0100, + 0x0002, 0x0100, + 0x0003, 0x1030, //1030 + 0x0009, 0x0001, + 0x000C, 0x0000, + 0x0090, 0x8000, + 0x000F, 0x0000, + + 0x0210, 0x0000, + 0x0211, 0x00EF, + 0x0212, 0x0000, + 0x0213, 0x018F, //432=01AF,400=018F + 0x0500, 0x0000, + 0x0501, 0x0000, + 0x0502, 0x005F, //??? + 0x0401, 0x0001, //REV=1 + 0x0404, 0x0000, + TFTLCD_DELAY, 50, + + 0x0007, 0x0100, //BASEE + TFTLCD_DELAY, 50, + + 0x0200, 0x0000, + 0x0201, 0x0000, + }; + init_table16(R61509V_regValues, sizeof(R61509V_regValues)); + p16 = (int16_t *) & HEIGHT; + *p16 = 400; + break; + } + _lcd_rev = ((_lcd_capable & REV_SCREEN) != 0); + setRotation(0); //PORTRAIT + invertDisplay(false); +} diff --git a/MCUFRIEND_kbv.h b/MCUFRIEND_kbv.h new file mode 100644 index 0000000..a754fcc --- /dev/null +++ b/MCUFRIEND_kbv.h @@ -0,0 +1,50 @@ +#ifndef MCUFRIEND_KBV_H_ +#define MCUFRIEND_KBV_H_ 281 + +//#define USE_KEIL +//#define USE_SERIAL + +#if ARDUINO < 165 +#define USE_GFX_KBV +#include "ADA_GFX_kbv.h" +#else +#include "Adafruit_GFX.h" +#endif + +class MCUFRIEND_kbv : public Adafruit_GFX { + + public: +#if defined USE_GFX_KBV + MCUFRIEND_kbv(); +#else + MCUFRIEND_kbv(int CS=A3, int RS=A2, int WR=A1, int RD=A0, int RST=A4); +#endif + void reset(void); // you only need the constructor + void begin(uint16_t ID = 0x9341); // you only need the constructor + virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // and these three + void WriteCmdData(uint16_t cmd, uint16_t dat); // ?public methods !!! + uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } + uint16_t readID(void); + virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { fillRect(x, y, 1, h, color); } + virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { fillRect(x, y, w, 1, color); } + virtual void fillScreen(uint16_t color) { fillRect(0, 0, _width, _height, color); } + virtual void setRotation(uint8_t r); + virtual void invertDisplay(boolean i); + + uint16_t readReg(uint16_t reg); + uint32_t readReg32(uint16_t reg); + int16_t readGRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h); + uint16_t readPixel(int16_t x, int16_t y) { uint16_t color; readGRAM(x, y, &color, 1, 1); return color; } + void setAddrWindow(int16_t x, int16_t y, int16_t x1, int16_t y1); + void pushColors(uint16_t *block, int16_t n, bool first); + void pushColors(uint8_t *block, int16_t n, bool first); + void pushColors(const uint8_t *block, int16_t n, bool first); + void vertScroll(int16_t top, int16_t scrollines, int16_t offset); + + private: + uint16_t _lcd_ID, _lcd_rev, _lcd_madctl, _lcd_drivOut, _MC, _MP, _MW, _SC, _EC, _SP, _EP; + uint16_t _lcd_xor, _lcd_capable; +}; + +#endif diff --git a/TFT_HX8357GLUE.h b/TFT_HX8357GLUE.h new file mode 100644 index 0000000..7d802fc --- /dev/null +++ b/TFT_HX8357GLUE.h @@ -0,0 +1,146 @@ +// NOT FOR PUBLIC USE + +#define HX8357_BLACK 0x0000 +#define HX8357_BLUE 0x001F +#define HX8357_RED 0xF800 +#define HX8357_GREEN 0x07E0 +#define HX8357_CYAN 0x07FF +#define HX8357_MAGENTA 0xF81F +#define HX8357_YELLOW 0xFFE0 +#define HX8357_WHITE 0xFFFF + +#include // Core graphics library +#include // Hardware-specific library + +#include +#include +#include +#include +#include + +const GFXfont *Fonts[] = { + NULL, + NULL, + &FreeSans9pt7b, + NULL, + &FreeSans12pt7b, + NULL, + &FreeSans18pt7b, + &FreeSerifItalic12pt7b, + &FreeMonoBold24pt7b, +}; +#define TFT_BLACK 0x0000 +#define TFT_NAVY 0x000F +#define TFT_DARKGREEN 0x03E0 +#define TFT_DARKCYAN 0x03EF +#define TFT_MAROON 0x7800 +#define TFT_PURPLE 0x780F +#define TFT_OLIVE 0x7BE0 +#define TFT_LIGHTGREY 0xC618 +#define TFT_DARKGREY 0x7BEF +#define TFT_BLUE 0x001F +#define TFT_GREEN 0x07E0 +#define TFT_CYAN 0x07FF +#define TFT_RED 0xF800 +#define TFT_MAGENTA 0xF81F +#define TFT_YELLOW 0xFFE0 +#define TFT_WHITE 0xFFFF +#define TFT_ORANGE 0xFD20 +#define TFT_GREENYELLOW 0xAFE5 +#define TFT_PINK 0xF81F + +class TFT_HX8357GLUE : public MCUFRIEND_kbv +{ + public: + TFT_HX8357GLUE() {} + void begin(void) { + init(); + } + void init(void) + { + MCUFRIEND_kbv::reset(); + _ID = MCUFRIEND_kbv::readID(); +// if (_ID == 0x00D3 || ID == 0xD3D3) + _ID = 0x9481; + MCUFRIEND_kbv::begin(_ID); + MCUFRIEND_kbv::setRotation(1); + _first = true; + } + void setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1) + { + MCUFRIEND_kbv::setAddrWindow(x0, y0, x1, y1); + _first = true; + } + + void pushColors(uint8_t *data, uint16_t len) + { + MCUFRIEND_kbv::pushColors((uint8_t*)data, len, _first); + _first = false; + } + + void pushColors(uint16_t *data, uint8_t len) + { + MCUFRIEND_kbv::pushColors((uint16_t*)data, len, _first); + _first = false; + } + + void pushColor(uint16_t color) + { + uint16_t c = color; + MCUFRIEND_kbv::pushColors(&c, 1, _first); + _first = false; + } + + void setCursor(int16_t x, int16_t y) + { + setCursor(x, y, _font); + } + + void setCursor(int16_t x, int16_t y, uint8_t idx) + { + + const GFXfont *f = Fonts[idx]; + MCUFRIEND_kbv::setFont(f); +// MCUFRIEND_kbv::setCursor(x, y + f->glyph->height); + + MCUFRIEND_kbv::setCursor(x, y); + } + + void setTextFont(uint8_t font) + { + _font = font; + MCUFRIEND_kbv::setFont(Fonts[_font]); + } + + int16_t drawNumber(long long_num, int16_t poX, int16_t poY, int16_t idx) + { + char buf[12]; + ltoa(long_num, buf, 10); + return drawString(buf, poX, poY, idx); + } + + int16_t drawChar(char c, int16_t poX, int16_t poY, int16_t idx) + { + char buf[2]; + buf[0] = c; + buf[1] = 0; + return drawString(buf, poX, poY, idx); + } + + int16_t drawString(char *string, int16_t poX, int16_t poY, int16_t idx) + { + int16_t x1, y1; + uint16_t w, h; + setFont(Fonts[_font = idx]); + getTextBounds(string, poX, poY, &x1, &y1, &w, &h); + fillRect(x1, y1 + h, w, h, 0x0000); + MCUFRIEND_kbv::setCursor(poX, poY + h); + print(string); + return w; + } + + private: + uint16_t _ID; + uint8_t _font, _first; +}; + diff --git a/UTFTGLUE.h b/UTFTGLUE.h new file mode 100644 index 0000000..3df5c24 --- /dev/null +++ b/UTFTGLUE.h @@ -0,0 +1,119 @@ +/* + * utftglue.h + * + * Created: 02/03/2013 14:25:06 + * Author: David Prentice + */ + + +#ifndef UTFTGLUE_H_ +#define UTFTGLUE_H_ + +#define LEFT 0 +#define RIGHT 9999 +#define CENTER 9998 + +#define PORTRAIT 0 +#define LANDSCAPE 1 + +#include + +struct _current_font +{ + uint8_t* font; + uint8_t x_size; + uint8_t y_size; + uint8_t offset; + uint8_t numchars; +}; + +class UTFTGLUE : public MCUFRIEND_kbv +{ + public: +// UTFTGLUE() : MCUFRIEND_kbv() {} + UTFTGLUE(byte model, int RS, int WR,int CS, int RST, int RD = A0) : MCUFRIEND_kbv(CS, RS, WR, RD, RST) {} + void InitLCD(byte orientation=LANDSCAPE) { + MCUFRIEND_kbv::reset(); + uint16_t ID = MCUFRIEND_kbv::readID(); + if (ID == 0) ID = 0x9341; //DealExtreme with EXTC=0 +// if (ID == 0x0089 || ID == 0x8989) ID = 0x1289; + if (ID == 0x00D3 || ID == 0xD3D3) ID = 0x9481; //write-only controller +// if (ID == 0x00D3 || ID == 0xD3D3) ID = 0x9486; //write-only controller +// if (ID == 0x9327 && orientation == LANDSCAPE) orientation = 3; + MCUFRIEND_kbv::begin(ID); + MCUFRIEND_kbv::setRotation(_orient = orientation); + _radius = 4; + } + void clrScr() { MCUFRIEND_kbv::fillScreen(0x0000);} + void drawPixel(int x, int y) { MCUFRIEND_kbv::drawPixel(x, y, _fcolor);} + void drawLine(int x1, int y1, int x2, int y2) { MCUFRIEND_kbv::drawLine(x1, y1, x2, y2, _fcolor);} + void fillScr(byte r, byte g, byte b) { MCUFRIEND_kbv::fillScreen(setrgb(r, g, b));} + void drawRect(int x1, int y1, int x2, int y2) { + int w = x2 - x1 + 1, h = y2 - y1 + 1; + if (w < 0) { x1 = x2; w = -w; } + if (h < 0) { y1 = y2; h = -h; } + MCUFRIEND_kbv::drawRect(x1, y1, w, h, _fcolor); + } + void drawRoundRect(int x1, int y1, int x2, int y2) { + int w = x2 - x1 + 1, h = y2 - y1 + 1; + if (w < 0) { x1 = x2; w = -w; } + if (h < 0) { y1 = y2; h = -h; } + MCUFRIEND_kbv::drawRoundRect(x1, y1, w, h, _radius, _fcolor); + } + void fillRect(int x1, int y1, int x2, int y2) { + int w = x2 - x1 + 1, h = y2 - y1 + 1; + if (w < 0) { x1 = x2; w = -w; } + if (h < 0) { y1 = y2; h = -h; } + MCUFRIEND_kbv::fillRect(x1, y1, w, h, _fcolor); + } + void fillRoundRect(int x1, int y1, int x2, int y2) { + int w = x2 - x1 + 1, h = y2 - y1 + 1; + if (w < 0) { x1 = x2; w = -w; } + if (h < 0) { y1 = y2; h = -h; } + MCUFRIEND_kbv::fillRoundRect(x1, y1, w, h, _radius, _fcolor); + } + void drawCircle(int x, int y, int radius) { MCUFRIEND_kbv::drawCircle(x, y, radius, _fcolor);} + void fillCircle(int x, int y, int radius) { MCUFRIEND_kbv::fillCircle(x, y, radius, _fcolor);} + void setColor(byte r, byte g, byte b) { MCUFRIEND_kbv::setTextColor(_fcolor = setrgb(r, g, b), _bcolor);} + void setBackColor(byte r, byte g, byte b) { MCUFRIEND_kbv::setTextColor(_fcolor, _bcolor = setrgb(r, g, b));} + void print(const char *st, int x, int y, int deg=0) { + settextcursor((char*)st, x, y); MCUFRIEND_kbv::print(st);} + void print(char *st, int x, int y, int deg=0) { + settextcursor(st, x, y); MCUFRIEND_kbv::print(st);} + void print(String st, int x, int y, int deg=0) { + MCUFRIEND_kbv::print(st);} + void printNumI(long num, int x, int y, int length=0, char filler=' ') { + char buf[16]; ltoa(num, buf, 10); + settextcursor(buf, x, y); MCUFRIEND_kbv::print(buf);} + void printNumF(double num, byte dec, int x, int y, char divider='.', int length=0, char filler=' ') { + settextcursor((char*)"", x, y); MCUFRIEND_kbv::print(num, dec);} + void setFont(uint8_t* font) { MCUFRIEND_kbv::setTextSize(1);} + +// void drawBitmap(int x, int y, int sx, int sy, bitmapdatatype data, int scale=1) { +// MCUFRIEND_kbv::drawBitmap(x, y, (const uint8_t*)data, sx, sy, _fcolor);} +// void drawBitmap(int x, int y, int sx, int sy, bitmapdatatype data, int deg, int rox, int roy); +// void lcdOff(); +// void lcdOn(); +// void setContrast(char c); + int getDisplayXSize() { return MCUFRIEND_kbv::width(); } + int getDisplayYSize() { return MCUFRIEND_kbv::height(); } +// void LCD_Write_DATA(char VH,char VL); + // void dispBitmap(File inFile); + protected: + uint16_t _fcolor; + uint16_t _bcolor; + uint8_t _radius; + uint8_t _orient; + void settextcursor(char *st, int x, int y) { + int pos; + if (x == CENTER || x == RIGHT) { + pos = (MCUFRIEND_kbv::width() - strlen(st) * 6); + if (x == CENTER) x = pos/2; + else x = pos; + } + MCUFRIEND_kbv::setCursor(x, y); + } + uint16_t setrgb(byte r, byte g, byte b) { return ((r&0xF8) << 8) | ((g&0xFC) << 3) | (b>>3);} +}; + +#endif /* UTFTGLUE_H_ */ \ No newline at end of file diff --git a/bitmaps/miniwoof.bmp b/bitmaps/miniwoof.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d5045d5a03c7aba2df6499a910f6cb60d67b1405 GIT binary patch literal 57654 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 z

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 +//#include // this header is not needed +#include // class methods are in here +//UTFTGLUE myGLCD; // use for default shield +//UTFTGLUE myGLCD(0x9320,A2,A1,A3,A4,A0); +//UTFTGLUE myGLCD(0x9325,A2,A1,A3,A4,A0); +//UTFTGLUE myGLCD(0x7783,A2,A1,A3,A4,A0); +//UTFTGLUE myGLCD(0x1289,A1,A2,A0,0,A3); // this might choose the pins +UTFTGLUE myGLCD(0x0154,A2,A1,A3,A4,A0); + +/* +#include +//#include +//UTFT myGLCD(ILI9325C,A2,A1,A3,A4); // Remember to change the model parameter to suit your display module! +//UTFT myGLCD(ILI9325D_8,A2,A1,A3,A4); // Remember to change the model parameter to suit your display module! +UTFT myGLCD(SSD1289_8,A1,A2,A0,A3); // Remember to change the model parameter to suit your display module! +*/ + +// Uncomment the next line for Arduino 2009/Uno +// UTFT(byte model, int RS, int WR,int CS,int RD) +//UTFT myGLCD(ILI9325C,A2,A1,A3,A0); // Remember to change the model parameter to suit your display module! +//Adafruit_UTFT myGLCD; + +// Declare which fonts we will be using +extern uint8_t SmallFont[]; + +void setup() +{ + randomSeed(analogRead(0)); + pinMode(A0, OUTPUT); + digitalWrite(A0, HIGH); + +// Setup the LCD + myGLCD.InitLCD(); + myGLCD.setFont(SmallFont); +} + +void loop() +{ + int buf[318]; + int x, x2; + int y, y2; + int r; + +// Clear the screen and draw the frame + myGLCD.clrScr(); + + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, 319, 13); + myGLCD.setColor(64, 64, 64); + myGLCD.fillRect(0, 226, 319, 239); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("* Universal Color TFT Display Library *", CENTER, 1); + myGLCD.setBackColor(64, 64, 64); + myGLCD.setColor(255,255,0); + myGLCD.print("", CENTER, 227); + + myGLCD.setColor(0, 0, 255); + myGLCD.drawRect(0, 14, 319, 225); + +// Draw crosshairs + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(159, 15, 159, 224); + myGLCD.drawLine(1, 119, 318, 119); + for (int i=9; i<310; i+=10) + myGLCD.drawLine(i, 117, i, 121); + for (int i=19; i<220; i+=10) + myGLCD.drawLine(157, i, 161, i); + +// Draw sin-, cos- and tan-lines + myGLCD.setColor(0,255,255); + myGLCD.print("Sin", 5, 15); + for (int i=1; i<318; i++) + { + myGLCD.drawPixel(i,119+(sin(((i*1.13)*3.14)/180)*95)); + } + + myGLCD.setColor(255,0,0); + myGLCD.print("Cos", 5, 27); + for (int i=1; i<318; i++) + { + myGLCD.drawPixel(i,119+(cos(((i*1.13)*3.14)/180)*95)); + } + + myGLCD.setColor(255,255,0); + myGLCD.print("Tan", 5, 39); + for (int i=1; i<318; i++) + { + myGLCD.drawPixel(i,119+(tan(((i*1.13)*3.14)/180))); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(159, 15, 159, 224); + myGLCD.drawLine(1, 119, 318, 119); + +// Draw a moving sinewave + x=1; + for (int i=1; i<(318*20); i++) + { + x++; + if (x==319) + x=1; + if (i>319) + { + if ((x==159)||(buf[x-1]==119)) + myGLCD.setColor(0,0,255); + else + myGLCD.setColor(0,0,0); + myGLCD.drawPixel(x,buf[x-1]); + } + myGLCD.setColor(0,255,255); + y=119+(sin(((i*1.1)*3.14)/180)*(90-(i / 100))); + myGLCD.drawPixel(x,y); + buf[x-1]=y; + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some filled rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRect(70+(i*20), 30+(i*20), 130+(i*20), 90+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some filled, rounded rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRoundRect(190-(i*20), 30+(i*20), 250-(i*20), 90+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some filled circles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillCircle(100+(i*20),60+(i*20), 30); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some lines in a pattern + myGLCD.setColor (255,0,0); + for (int i=15; i<224; i+=5) + { + myGLCD.drawLine(1, i, (i*1.44)-10, 224); + } + myGLCD.setColor (255,0,0); + for (int i=224; i>15; i-=5) + { + myGLCD.drawLine(318, i, (i*1.44)-11, 15); + } + myGLCD.setColor (0,255,255); + for (int i=224; i>15; i-=5) + { + myGLCD.drawLine(1, i, 331-(i*1.44), 15); + } + myGLCD.setColor (0,255,255); + for (int i=15; i<224; i+=5) + { + myGLCD.drawLine(318, i, 330-(i*1.44), 224); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,225); + +// Draw some random circles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=32+random(256); + y=45+random(146); + r=random(30); + myGLCD.drawCircle(x, y, r); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some random rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(316); + y=16+random(207); + x2=2+random(316); + y2=16+random(207); + myGLCD.drawRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + +// Draw some random rounded rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(316); + y=16+random(207); + x2=2+random(316); + y2=16+random(207); + myGLCD.drawRoundRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(316); + y=16+random(209); + x2=2+random(316); + y2=16+random(209); + myGLCD.drawLine(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,318,224); + + for (int i=0; i<10000; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + myGLCD.drawPixel(2+random(316), 16+random(209)); + } + + delay(2000); + + myGLCD.fillScr(0, 0, 255); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRoundRect(80, 70, 239, 169); + + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("That's it!", CENTER, 93); + myGLCD.print("Restarting in a", CENTER, 119); + myGLCD.print("few seconds...", CENTER, 132); + + myGLCD.setColor(0, 255, 0); + myGLCD.setBackColor(0, 0, 255); + myGLCD.print("Runtime: (msecs)", CENTER, 210); + myGLCD.printNumI(millis(), CENTER, 225); + + delay (10000); +} + diff --git a/examples/GLUE_Demo_400x240/GLUE_Demo_400x240.ino b/examples/GLUE_Demo_400x240/GLUE_Demo_400x240.ino new file mode 100644 index 0000000..3507581 --- /dev/null +++ b/examples/GLUE_Demo_400x240/GLUE_Demo_400x240.ino @@ -0,0 +1,337 @@ +// UTFT_Demo_400x240 (C)2012 Henning Karlsen +// web: http://www.henningkarlsen.com/electronics +// +// This program is a demo of how to use most of the functions +// of the library with a supported display modules. +// +// This demo was made for modules with a screen resolution +// of 400x240 pixels. +// +// This program requires the UTFT library. +// + +#include +//#include +#include +#include +//UTFTGLUE myGLCD; // use for default shield +UTFTGLUE myGLCD(0x9327,A2,A1,A3,A4,A0); +extern uint8_t SmallFont[]; + +/* +#include + +// Declare which fonts we will be using +extern uint8_t SmallFont[]; + +// Uncomment the next line for Arduino 2009/Uno +UTFT myGLCD(ITDB32WD,19,18,17,16); // Remember to change the model parameter to suit your display module! + +// Uncomment the next line for Arduino Mega +//UTFT myGLCD(ITDB32WD,38,39,40,41); // Remember to change the model parameter to suit your display module! +*/ + +void setup() +{ + randomSeed(analogRead(0)); + +// Setup the LCD + myGLCD.InitLCD(); + myGLCD.setFont(SmallFont); +} + +void loop() +{ + int buf[398]; + int x, x2; + int y, y2; + int r; + +// Clear the screen and draw the frame + myGLCD.clrScr(); + + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, 399, 13); + myGLCD.setColor(64, 64, 64); + myGLCD.fillRect(0, 226, 399, 239); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("*** Universal Color TFT Display Library ***", CENTER, 1); + myGLCD.setBackColor(64, 64, 64); + myGLCD.setColor(255,255,0); + myGLCD.print("< http://electronics.henningkarlsen.com >", CENTER, 227); + + myGLCD.setColor(0, 0, 255); + myGLCD.drawRect(0, 14, 399, 225); + +// Draw crosshairs + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(199, 15, 199, 224); + myGLCD.drawLine(1, 119, 398, 119); + for (int i=9; i<390; i+=10) + myGLCD.drawLine(i, 117, i, 121); + for (int i=19; i<220; i+=10) + myGLCD.drawLine(197, i, 201, i); + +// Draw sin-, cos- and tan-lines + myGLCD.setColor(0,255,255); + myGLCD.print("Sin", 5, 15); + for (int i=1; i<398; i++) + { + myGLCD.drawPixel(i,119+(sin(((i*0.9)*3.14)/180)*95)); + } + + myGLCD.setColor(255,0,0); + myGLCD.print("Cos", 5, 27); + for (int i=1; i<398; i++) + { + myGLCD.drawPixel(i,119+(cos(((i*0.9)*3.14)/180)*95)); + } + + myGLCD.setColor(255,255,0); + myGLCD.print("Tan", 5, 39); + for (int i=1; i<398; i++) + { + y=119+(tan(((i*0.9)*3.14)/180)); + if ((y>15) && (y<224)) + myGLCD.drawPixel(i,y); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(199, 15, 199, 224); + myGLCD.drawLine(1, 119, 398, 119); + +// Draw a moving sinewave + x=1; + for (int i=1; i<(398*20); i++) + { + x++; + if (x==399) + x=1; + if (i>399) + { + if ((x==199)||(buf[x-1]==119)) + myGLCD.setColor(0,0,255); + else + myGLCD.setColor(0,0,0); + myGLCD.drawPixel(x,buf[x-1]); + } + myGLCD.setColor(0,255,255); + y=119+(sin(((i)*3.14)/180)*(90-(i / 100))); + myGLCD.drawPixel(x,y); + buf[x-1]=y; + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some filled rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRect(110+(i*20), 30+(i*20), 170+(i*20), 90+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some filled, rounded rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRoundRect(230-(i*20), 30+(i*20), 290-(i*20), 90+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some filled circles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillCircle(110+(i*30),60+(i*20), 30); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some lines in a pattern + myGLCD.setColor (255,0,0); + for (int i=15; i<224; i+=5) + { + myGLCD.drawLine(1, i, (i*1.77)-10, 224); + } + myGLCD.setColor (255,0,0); + for (int i=224; i>15; i-=5) + { + myGLCD.drawLine(398, i, (i*1.77)-11, 15); + } + myGLCD.setColor (0,255,255); + for (int i=224; i>15; i-=5) + { + myGLCD.drawLine(1, i, 411-(i*1.77), 15); + } + myGLCD.setColor (0,255,255); + for (int i=15; i<224; i+=5) + { + myGLCD.drawLine(398, i, 410-(i*1.77), 224); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some random circles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=32+random(336); + y=45+random(146); + r=random(30); + myGLCD.drawCircle(x, y, r); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some random rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(396); + y=16+random(207); + x2=2+random(396); + y2=16+random(207); + myGLCD.drawRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + +// Draw some random rounded rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(396); + y=16+random(207); + x2=2+random(396); + y2=16+random(207); + myGLCD.drawRoundRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(396); + y=16+random(209); + x2=2+random(396); + y2=16+random(209); + myGLCD.drawLine(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,398,224); + + for (int i=0; i<10000; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + myGLCD.drawPixel(2+random(396), 16+random(209)); + } + + delay(2000); + + myGLCD.fillScr(0, 0, 255); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRoundRect(120, 70, 279, 169); + + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("That's it!", CENTER, 93); + myGLCD.print("Restarting in a", CENTER, 119); + myGLCD.print("few seconds...", CENTER, 132); + + myGLCD.setColor(0, 255, 0); + myGLCD.setBackColor(0, 0, 255); + myGLCD.print("Runtime: (msecs)", CENTER, 210); + myGLCD.printNumI(millis(), CENTER, 225); + + delay (10000); +} + diff --git a/examples/GLUE_Demo_480x320/GLUE_Demo_480x320.ino b/examples/GLUE_Demo_480x320/GLUE_Demo_480x320.ino new file mode 100644 index 0000000..4aa4b40 --- /dev/null +++ b/examples/GLUE_Demo_480x320/GLUE_Demo_480x320.ino @@ -0,0 +1,333 @@ +// UTFT_Demo_480x320 (C)2013 Henning Karlsen +// web: http://www.henningkarlsen.com/electronics +// +// This program is a demo of how to use most of the functions +// of the library with a supported display modules. +// +// This demo was made for modules with a screen resolution +// of 480x320 pixels. +// +// This program requires the UTFT library. +// + +#include +//#include +#include +//UTFTGLUE myGLCD; // use for default shield +UTFTGLUE myGLCD(0x9488,A2,A1,A3,A4,A0); +extern uint8_t SmallFont[]; + +/* +#include +// Declare which fonts we will be using +extern uint8_t SmallFont[]; + +// Uncomment the next line for Arduino 2009/Uno +//UTFT myGLCD(CTE32HR,19,18,17,16); // Remember to change the model parameter to suit your display module! + +// Uncomment the next line for Arduino Mega +UTFT myGLCD(CTE32HR,38,39,40,41); // Remember to change the model parameter to suit your display module! +*/ + +void setup() +{ + randomSeed(analogRead(0)); + +// Setup the LCD + myGLCD.InitLCD(); + myGLCD.setFont(SmallFont); +} + +void loop() +{ + int buf[478]; + int x, x2; + int y, y2; + int r; + +// Clear the screen and draw the frame + myGLCD.clrScr(); + + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, 479, 13); + myGLCD.setColor(64, 64, 64); + myGLCD.fillRect(0, 306, 479, 319); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("* Universal Color TFT Display Library *", CENTER, 1); + myGLCD.setBackColor(64, 64, 64); + myGLCD.setColor(255,255,0); + myGLCD.print("", CENTER, 307); + + myGLCD.setColor(0, 0, 255); + myGLCD.drawRect(0, 14, 479, 305); + +// Draw crosshairs + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(239, 15, 239, 304); + myGLCD.drawLine(1, 159, 478, 159); + for (int i=9; i<470; i+=10) + myGLCD.drawLine(i, 157, i, 161); + for (int i=19; i<220; i+=10) + myGLCD.drawLine(237, i, 241, i); + +// Draw sin-, cos- and tan-lines + myGLCD.setColor(0,255,255); + myGLCD.print("Sin", 5, 15); + for (int i=1; i<478; i++) + { + myGLCD.drawPixel(i,159+(sin(((i*1.13)*3.14)/180)*95)); + } + + myGLCD.setColor(255,0,0); + myGLCD.print("Cos", 5, 27); + for (int i=1; i<478; i++) + { + myGLCD.drawPixel(i,159+(cos(((i*1.13)*3.14)/180)*95)); + } + + myGLCD.setColor(255,255,0); + myGLCD.print("Tan", 5, 39); + for (int i=1; i<478; i++) + { + myGLCD.drawPixel(i,159+(tan(((i*1.13)*3.14)/180))); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + myGLCD.setColor(0, 0, 255); + myGLCD.setBackColor(0, 0, 0); + myGLCD.drawLine(239, 15, 239, 304); + myGLCD.drawLine(1, 159, 478, 159); + +// Draw a moving sinewave + x=1; + for (int i=1; i<(478*15); i++) + { + x++; + if (x==479) + x=1; + if (i>479) + { + if ((x==239)||(buf[x-1]==159)) + myGLCD.setColor(0,0,255); + else + myGLCD.setColor(0,0,0); + myGLCD.drawPixel(x,buf[x-1]); + } + myGLCD.setColor(0,255,255); + y=159+(sin(((i*0.7)*3.14)/180)*(90-(i / 100))); + myGLCD.drawPixel(x,y); + buf[x-1]=y; + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some filled rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRect(150+(i*20), 70+(i*20), 210+(i*20), 130+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some filled, rounded rectangles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillRoundRect(270-(i*20), 70+(i*20), 330-(i*20), 130+(i*20)); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some filled circles + for (int i=1; i<6; i++) + { + switch (i) + { + case 1: + myGLCD.setColor(255,0,255); + break; + case 2: + myGLCD.setColor(255,0,0); + break; + case 3: + myGLCD.setColor(0,255,0); + break; + case 4: + myGLCD.setColor(0,0,255); + break; + case 5: + myGLCD.setColor(255,255,0); + break; + } + myGLCD.fillCircle(180+(i*20),100+(i*20), 30); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some lines in a pattern + myGLCD.setColor (255,0,0); + for (int i=15; i<304; i+=5) + { + myGLCD.drawLine(1, i, (i*1.6)-10, 304); + } + myGLCD.setColor (255,0,0); + for (int i=304; i>15; i-=5) + { + myGLCD.drawLine(478, i, (i*1.6)-11, 15); + } + myGLCD.setColor (0,255,255); + for (int i=304; i>15; i-=5) + { + myGLCD.drawLine(1, i, 491-(i*1.6), 15); + } + myGLCD.setColor (0,255,255); + for (int i=15; i<304; i+=5) + { + myGLCD.drawLine(478, i, 490-(i*1.6), 304); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some random circles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=32+random(416); + y=45+random(226); + r=random(30); + myGLCD.drawCircle(x, y, r); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some random rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(476); + y=16+random(289); + x2=2+random(476); + y2=16+random(289); + myGLCD.drawRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + +// Draw some random rounded rectangles + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(476); + y=16+random(289); + x2=2+random(476); + y2=16+random(289); + myGLCD.drawRoundRect(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + + for (int i=0; i<100; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + x=2+random(476); + y=16+random(289); + x2=2+random(476); + y2=16+random(289); + myGLCD.drawLine(x, y, x2, y2); + } + + delay(2000); + + myGLCD.setColor(0,0,0); + myGLCD.fillRect(1,15,478,304); + + for (int i=0; i<10000; i++) + { + myGLCD.setColor(random(255), random(255), random(255)); + myGLCD.drawPixel(2+random(476), 16+random(289)); + } + + delay(2000); + + myGLCD.fillScr(0, 0, 255); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRoundRect(160, 70, 319, 169); + + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("That's it!", CENTER, 93); + myGLCD.print("Restarting in a", CENTER, 119); + myGLCD.print("few seconds...", CENTER, 132); + + myGLCD.setColor(0, 255, 0); + myGLCD.setBackColor(0, 0, 255); + myGLCD.print("Runtime: (msecs)", CENTER, 290); + myGLCD.printNumI(millis(), CENTER, 305); + + delay (10000); +} + diff --git a/examples/LCD_ID_readreg/LCD_ID_readreg.ino b/examples/LCD_ID_readreg/LCD_ID_readreg.ino new file mode 100644 index 0000000..1eedb37 --- /dev/null +++ b/examples/LCD_ID_readreg/LCD_ID_readreg.ino @@ -0,0 +1,257 @@ +// adapted from LCD_ID_Reader from http://misc.ws/lcd_information +// controllers either read as 16-bit or as a sequence of 8-bit values + +//-- Arduino UNO or Mega 2560 Plugged as shield +#define LCD_RST A4 +#define LCD_CS A3 +#define LCD_RS A2 +#define LCD_WR A1 +#define LCD_RD A0 + +#define LCD_D0 8 +#define LCD_D1 9 +#define LCD_D2 2 +#define LCD_D3 3 +#define LCD_D4 4 +#define LCD_D5 5 +#define LCD_D6 6 +#define LCD_D7 7 + +void setup() +{ + Serial.begin(9600); + while (!Serial) ; + Serial.println("Read Registers on MCUFRIEND UNO shield"); + Serial.println("controllers either read as single 16-bit"); + Serial.println("e.g. the ID is at readReg(0)"); + Serial.println("or as a sequence of 8-bit values"); + Serial.println("in special locations (first is dummy)"); + Serial.println(""); + lcdInit(); + lcdReset(); //ensures that controller is in default state + readReg(0x00, 2, "ID: ILI9320, ILI9325, ILI9335, ..."); + readReg(0x04, 4, "Manufacturer ID"); + readReg(0x09, 5, "Status Register"); + readReg(0x61, 2, "RDID1 HX8347-G"); + readReg(0x62, 2, "RDID2 HX8347-G"); + readReg(0x63, 2, "RDID3 HX8347-G"); + readReg(0x64, 2, "RDID1 HX8347-A"); + readReg(0x65, 2, "RDID2 HX8347-A"); + readReg(0x66, 2, "RDID3 HX8347-A"); + readReg(0x67, 2, "RDID Himax HX8347-A"); + readReg(0x70, 2, "Panel Himax HX8347-A"); + readReg(0xA1, 5, "RD_DDB SSD1963"); + readReg(0xB0, 2, "RGB Interface Signal Control"); + readReg(0xB4, 2, "Inversion Control"); + readReg(0xB6, 5, "Display Control"); + readReg(0xB7, 2, "Entry Mode Set"); + readReg(0xBF, 6, "ILI9481, HX8357-B"); + readReg(0xC0, 6, "Panel Control"); + readReg(0xCC, 2, "Panel Control"); + readReg(0xD0, 3, "Power Control"); + readReg(0xD2, 5, "NVM Read"); + readReg(0xD3, 4, "ILI9341, ILI9488"); + readReg(0xDA, 2, "RDID1"); + readReg(0xDB, 2, "RDID2"); + readReg(0xDC, 2, "RDID3"); + readReg(0xEF, 6, "ILI9327"); + readReg(0xF2, 12, "Adjust Control 2"); + readReg(0xF6, 4, "Interface Control"); +} + +void loop() +{ + // put your main code here, to run repeatedly: + +} + +void printhex(uint8_t val) +{ + if (val < 0x10) Serial.print("0"); + Serial.print(val, HEX); +} + +void readReg(uint16_t reg, uint8_t n, const char *msg) +{ + uint8_t val8; + lcdReset(); + lcdSetWriteDir(); +/* + lcdWriteCommand(0xF6); + lcdWriteData(0x01); + lcdWriteData(0x01); + lcdWriteData(0x03); +*/ + lcdWriteCommand(reg); + Serial.print("reg(0x"); + printhex(reg >> 8); + printhex(reg); + Serial.print(")"); + lcdSetReadDir(); + while (n--) { + val8 = lcdReadData8(); + Serial.print(" "); + printhex(val8); + } + lcdSetWriteDir(); + Serial.print("\t"); + Serial.println(msg); +} + +void lcdInit() +{ + pinMode(LCD_CS, OUTPUT); + digitalWrite(LCD_CS, HIGH); + pinMode(LCD_RS, OUTPUT); + digitalWrite(LCD_RS, HIGH); + pinMode(LCD_WR, OUTPUT); + digitalWrite(LCD_WR, HIGH); + pinMode(LCD_RD, OUTPUT); + digitalWrite(LCD_RD, HIGH); + pinMode(LCD_RST, OUTPUT); + digitalWrite(LCD_RST, HIGH); +} + +void lcdReset() +{ + digitalWrite(LCD_RST, LOW); + delay(2); + digitalWrite(LCD_RST, HIGH); + delay(10); //allow controller to re-start +} + +void lcdWrite8(uint16_t data) +{ + digitalWrite(LCD_D0, data & 1); + digitalWrite(LCD_D1, (data & 2) >> 1); + digitalWrite(LCD_D2, (data & 4) >> 2); + digitalWrite(LCD_D3, (data & 8) >> 3); + digitalWrite(LCD_D4, (data & 16) >> 4); + digitalWrite(LCD_D5, (data & 32) >> 5); + digitalWrite(LCD_D6, (data & 64) >> 6); + digitalWrite(LCD_D7, (data & 128) >> 7); +} + +uint16_t lcdRead8() +{ + uint16_t result = digitalRead(LCD_D7); + result <<= 1; + result |= digitalRead(LCD_D6); + result <<= 1; + result |= digitalRead(LCD_D5); + result <<= 1; + result |= digitalRead(LCD_D4); + result <<= 1; + result |= digitalRead(LCD_D3); + result <<= 1; + result |= digitalRead(LCD_D2); + result <<= 1; + result |= digitalRead(LCD_D1); + result <<= 1; + result |= digitalRead(LCD_D0); + + return result; +} + +void lcdSetWriteDir() +{ + pinMode(LCD_D0, OUTPUT); + pinMode(LCD_D1, OUTPUT); + pinMode(LCD_D2, OUTPUT); + pinMode(LCD_D3, OUTPUT); + pinMode(LCD_D4, OUTPUT); + pinMode(LCD_D5, OUTPUT); + pinMode(LCD_D6, OUTPUT); + pinMode(LCD_D7, OUTPUT); +} + + +void lcdSetReadDir() +{ + pinMode(LCD_D0, INPUT); + pinMode(LCD_D1, INPUT); + pinMode(LCD_D2, INPUT); + pinMode(LCD_D3, INPUT); + pinMode(LCD_D4, INPUT); + pinMode(LCD_D5, INPUT); + pinMode(LCD_D6, INPUT); + pinMode(LCD_D7, INPUT); +} + +void lcdWriteData(uint16_t data) +{ + lcdSetWriteDir(); + digitalWrite(LCD_CS, LOW); + digitalWrite(LCD_RS, HIGH); + digitalWrite(LCD_RD, HIGH); + digitalWrite(LCD_WR, HIGH); + + lcdWrite8(data >> 8); + + digitalWrite(LCD_WR, LOW); + delayMicroseconds(10); + digitalWrite(LCD_WR, HIGH); + + lcdWrite8(data); + + digitalWrite(LCD_WR, LOW); + delayMicroseconds(10); + digitalWrite(LCD_WR, HIGH); + + digitalWrite(LCD_CS, HIGH); +} + +void lcdWriteCommand(uint16_t command) +{ + lcdSetWriteDir(); + digitalWrite(LCD_CS, LOW); + digitalWrite(LCD_RS, LOW); + digitalWrite(LCD_RD, HIGH); + digitalWrite(LCD_WR, HIGH); + lcdWrite8(command >> 8); + digitalWrite(LCD_WR, LOW); + delayMicroseconds(10); + digitalWrite(LCD_WR, HIGH); + lcdWrite8(command); + digitalWrite(LCD_WR, LOW); + delayMicroseconds(10); + digitalWrite(LCD_WR, HIGH); + digitalWrite(LCD_CS, HIGH); +} + +uint8_t lcdReadData8() +{ + uint8_t result; + lcdSetReadDir(); + digitalWrite(LCD_CS, LOW); + digitalWrite(LCD_RS, HIGH); + digitalWrite(LCD_RD, HIGH); + digitalWrite(LCD_WR, HIGH); + + digitalWrite(LCD_RD, LOW); + delayMicroseconds(10); + result = lcdRead8(); + digitalWrite(LCD_RD, HIGH); + + delayMicroseconds(10); + + return result; +} + + +uint16_t lcdReadData16() +{ + uint16_t result; + result = lcdReadData8() << 8; + result |= lcdReadData8(); + return result; +} + + +void lcdWriteRegister(uint16_t addr, uint16_t data) +{ + lcdWriteCommand(addr); + lcdWriteData(data); +} + + diff --git a/examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino b/examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino new file mode 100644 index 0000000..2d4b5e3 --- /dev/null +++ b/examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino @@ -0,0 +1,364 @@ +// TouchScreen_Calibr_kbv for MCUFRIEND UNO Display Shields +// adapted by David Prentice +// for Adafruit's Resistive Touch Screen Library +// from Henning Karlsen's original program. Many Thanks. + +// UTouch_Calibration (C)2013-2014 Henning Karlsen +// web: http://www.henningkarlsen.com/electronics +// +// This program can be used to calibrate the touchscreen +// of the display modules. +// +// It is assumed that the display module is connected to an +// appropriate shield or that you know how to change the pin +// numbers in the setup. +// +// Instructions will be given on the display. + +#define TOUCH_ORIENTATION PORTRAIT +#define TITLE "TouchScreen.h Calibration" + +#include +#include //we are using UTFT display methods +UTFTGLUE myGLCD(0x9341, A2, A1, A3, A4, A0); + +#include //Adafruit Library + +// MCUFRIEND UNO shield shares pins with the TFT. Due does NOT work +#define YP A1 //[A1], A3 for ILI9320, A2 for ST7789V +#define YM 7 //[ 7], 9 , 7 +#define XM A2 //[A2], A2 for ILI9320, A1 for ST7789V +#define XP 6 //[ 6], 8 , 6 + +TouchScreen myTouch(XP, YP, XM, YM, 300); +TSPoint tp; //Touchscreen_due branch uses Point + +void readResistiveTouch(void) +{ + tp = myTouch.getPoint(); + pinMode(YP, OUTPUT); //restore shared pins + pinMode(XM, OUTPUT); + digitalWrite(YP, HIGH); //because TFT control pins + digitalWrite(XM, HIGH); +} + +bool ISPRESSED(void) +{ + // .kbv this was too sensitive !! + // now touch has to be stable for 50ms + int count = 0; + bool state, oldstate; + while (count < 10) { + readResistiveTouch(); + state = tp.z > 20 && tp.z < 1000; + if (state == oldstate) count++; + else count = 0; + oldstate = state; + delay(5); + } + return oldstate; +} + +void showpoint(void) +{ + Serial.print("\r\nx="); Serial.print(tp.x); + Serial.print(" y="); Serial.print(tp.y); + Serial.print(" z="); Serial.print(tp.z); +} + +// ************************************ +// DO NOT EDIT ANYTHING BELOW THIS LINE +// ************************************ + +// Declare which fonts we will be using +extern uint8_t SmallFont[]; + +uint32_t cx, cy; +uint32_t rx[8], ry[8]; +int32_t clx, crx, cty, cby; +float px, py; +int dispx, dispy, text_y_center, swapxy; +uint32_t calx, caly, cals; +char buf[13]; + +void setup() +{ + Serial.begin(9600); + Serial.println(TITLE); + digitalWrite(A0, HIGH); + pinMode(A0, OUTPUT); + myGLCD.InitLCD(TOUCH_ORIENTATION); + myGLCD.clrScr(); + myGLCD.setFont(SmallFont); + dispx = myGLCD.getDisplayXSize(); + dispy = myGLCD.getDisplayYSize(); + text_y_center = (dispy / 2) - 6; +} + +void drawCrossHair(int x, int y) +{ + myGLCD.drawRect(x - 10, y - 10, x + 10, y + 10); + myGLCD.drawLine(x - 5, y, x + 5, y); + myGLCD.drawLine(x, y - 5, x, y + 5); +} + +void readCoordinates() +{ + int iter = 5000; + int failcount = 0; + int cnt = 0; + uint32_t tx = 0; + uint32_t ty = 0; + boolean OK = false; + + while (OK == false) + { + myGLCD.setColor(255, 255, 255); + myGLCD.print("* PRESS *", CENTER, text_y_center); + while (ISPRESSED() == false) {} + myGLCD.print("* HOLD! *", CENTER, text_y_center); + cnt = 0; + iter = 400; + do + { + readResistiveTouch(); + // showpoint(tp); + if (tp.z > 20 && tp.z < 1000) + { + tx += tp.x; + ty += tp.y; + cnt++; + } + else + failcount++; + } while ((cnt < iter) && (failcount < 10000)); + if (cnt >= iter) + { + OK = true; + } + else + { + tx = 0; + ty = 0; + cnt = 0; + } + if (failcount >= 10000) + fail(); + } + + cx = tx / iter; + cy = ty / iter; +} + +void calibrate(int x, int y, int i) +{ + myGLCD.setColor(255, 255, 255); + drawCrossHair(x, y); + myGLCD.setBackColor(255, 0, 0); + readCoordinates(); + myGLCD.setColor(255, 255, 255); + myGLCD.print("* RELEASE *", CENTER, text_y_center); + myGLCD.setColor(80, 80, 80); + drawCrossHair(x, y); + rx[i] = cx; + ry[i] = cy; + Serial.print("\r\ncx="); Serial.print(cx); + Serial.print(" cy="); Serial.print(cy); + while (ISPRESSED() == true) {} +} + +void waitForTouch() +{ + while (ISPRESSED() == true) {} + while (ISPRESSED() == false) {} + while (ISPRESSED() == true) {} +} + +void toHex(uint32_t num) +{ + buf[0] = '0'; + buf[1] = 'x'; + buf[10] = 'U'; + buf[11] = 'L'; + buf[12] = 0; + for (int zz = 9; zz > 1; zz--) + { + if ((num & 0xF) > 9) + buf[zz] = (num & 0xF) + 55; + else + buf[zz] = (num & 0xF) + 48; + num = num >> 4; + } +} + +void startup() +{ + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print(TITLE, CENTER, 1); + myGLCD.setBackColor(0, 0, 0); + + myGLCD.print("Use a stylus or something", LEFT, 30); + myGLCD.print("similar to touch as close", LEFT, 42); + myGLCD.print("to the center of the", LEFT, 54); + myGLCD.print("highlighted crosshair as", LEFT, 66); + myGLCD.print("possible. Keep as still as", LEFT, 78); + myGLCD.print("possible and keep holding", LEFT, 90); + myGLCD.print("until the highlight is", LEFT, 102); + myGLCD.print("removed. Repeat for all", LEFT, 114); + myGLCD.print("crosshairs in sequence.", LEFT, 126); + myGLCD.print("Touch screen to continue", CENTER, 162); + + waitForTouch(); + myGLCD.clrScr(); +} + +void showNumI(char *msg, uint32_t val, int x, int y) +{ + myGLCD.print(msg, x, y); + myGLCD.printNumI(val, x + 50, y); +} + +void done() +{ + uint16_t TS_LEFT, TS_RT, TS_TOP, TS_BOT, TS_WID, TS_HT, TS_SWAP; + int16_t tmp; + myGLCD.clrScr(); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print(TITLE, CENTER, 1); + myGLCD.setBackColor(0, 0, 0); + myGLCD.print("To use the new calibration", LEFT, 30); + myGLCD.print("settings you must map the values", LEFT, 42); + myGLCD.print("from Point p = ts.getPoint() e.g. ", LEFT, 54); + myGLCD.print("x = map(p.x, LEFT, RT, 0, tft.width());", LEFT, 66); + myGLCD.print("y = map(p.y, TOP, BOT, 0, tft.height());", LEFT, 78); + myGLCD.print("swap p.x and p.y if diff ORIENTATION", LEFT, 90); + + //.kbv show human values + TS_LEFT = (calx >> 14) & 0x3FFF; + TS_RT = (calx >> 0) & 0x3FFF; + TS_TOP = (caly >> 14) & 0x3FFF; + TS_BOT = (caly >> 0) & 0x3FFF; + TS_WID = ((cals >> 12) & 0x0FFF) + 1; + TS_HT = ((cals >> 0) & 0x0FFF) + 1; + TS_SWAP = (cals >> 31); + if (TOUCH_ORIENTATION != 0) { + myGLCD.print("Sketch is LANDSCAPE", 0, 126); + myGLCD.printNumI(TS_WID, 150, 126); + myGLCD.print("x", 174, 126); + myGLCD.printNumI(TS_HT, 186, 126); + showNumI("LEFT ", TS_LEFT, 0, 138); + showNumI("RT ", TS_RT, 100, 138); + showNumI("TOP ", TS_TOP, 0, 150); + showNumI("BOT ", TS_BOT, 100, 150); + switch (TOUCH_ORIENTATION) { + case 1: + tmp = TS_LEFT, TS_LEFT = TS_TOP, TS_TOP = TS_RT, TS_RT = TS_BOT, TS_BOT = tmp; + tmp = TS_WID, TS_WID = TS_HT, TS_HT = tmp; + break; + } + } + myGLCD.print("PORTRAIT CALIBRATION", 0, 174); + myGLCD.printNumI(TS_WID, 150, 174); + myGLCD.print("x", 174, 174); + myGLCD.printNumI(TS_HT, 186, 174); + showNumI("LEFT ", TS_LEFT, 0, 186); + showNumI("RT ", TS_RT, 100, 186); + myGLCD.printNumF(((float)TS_RT - TS_LEFT) / TS_WID, 2, 200, 186); + showNumI("TOP ", TS_TOP, 0, 198); + showNumI("BOT ", TS_BOT, 100, 198); + myGLCD.printNumF(((float)TS_BOT - TS_TOP) / TS_HT, 2, 200, 198); + myGLCD.print("Touch Pin Wiring is ", 0, 222); + myGLCD.print((cals >> 31) ? "SWAPXY" : "PORTRAIT", 170, 222); + +} + +void fail() +{ + myGLCD.clrScr(); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print("Touch Calibration FAILED", CENTER, 1); + myGLCD.setBackColor(0, 0, 0); + + myGLCD.print("Unable to read the position", LEFT, 30); + myGLCD.print("of the press. This is a", LEFT, 42); + myGLCD.print("hardware issue and can", LEFT, 54); + myGLCD.print("not be corrected in", LEFT, 66); + myGLCD.print("software.", LEFT, 78); + myGLCD.print("check XP, XM pins with a multimeter", LEFT, 102); + myGLCD.print("check YP, YM pins with a multimeter", LEFT, 114); + myGLCD.print("should be about 300 ohms", LEFT, 126); + + while (true) {}; +} + +void loop() +{ + startup(); + + myGLCD.setColor(80, 80, 80); + drawCrossHair(dispx - 11, 10); + drawCrossHair(dispx / 2, 10); + drawCrossHair(10, 10); + drawCrossHair(dispx - 11, dispy / 2); + drawCrossHair(10, dispy / 2); + drawCrossHair(dispx - 11, dispy - 11); + drawCrossHair(dispx / 2, dispy - 11); + drawCrossHair(10, dispy - 11); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("***********", CENTER, text_y_center - 12); + myGLCD.print("***********", CENTER, text_y_center + 12); + + calibrate(10, 10, 0); + calibrate(10, dispy / 2, 1); + calibrate(10, dispy - 11, 2); + calibrate(dispx / 2, 10, 3); + calibrate(dispx / 2, dispy - 11, 4); + calibrate(dispx - 11, 10, 5); + calibrate(dispx - 11, dispy / 2, 6); + calibrate(dispx - 11, dispy - 11, 7); + + cals = (long(dispx - 1) << 12) + (dispy - 1); + if (TOUCH_ORIENTATION == PORTRAIT) swapxy = rx[2] - rx[0]; + else swapxy = ry[2] - ry[0]; + swapxy = (swapxy < -500 || swapxy > 500); + if ((TOUCH_ORIENTATION == PORTRAIT) ^ (swapxy != 0)) { + clx = (rx[0] + rx[1] + rx[2]) / 3; + crx = (rx[5] + rx[6] + rx[7]) / 3; + cty = (ry[0] + ry[3] + ry[5]) / 3; + cby = (ry[2] + ry[4] + ry[7]) / 3; + } else { + clx = (ry[0] + ry[1] + ry[2]) / 3; + crx = (ry[5] + ry[6] + ry[7]) / 3; + cty = (rx[0] + rx[3] + rx[5]) / 3; + cby = (rx[2] + rx[4] + rx[7]) / 3; + } + px = float(crx - clx) / (dispx - 20); + py = float(cby - cty) / (dispy - 20); + // px = 0; + clx -= px * 10; + crx += px * 10; + cty -= py * 10; + cby += py * 10; + + calx = (long(clx) << 14) + long(crx); + caly = (long(cty) << 14) + long(cby); + if (swapxy) + cals |= (1L << 31); + + done(); + while (true) {} +} + diff --git a/examples/Touch_shield_kbv/Touch_shield_kbv.ino b/examples/Touch_shield_kbv/Touch_shield_kbv.ino new file mode 100644 index 0000000..c817de8 --- /dev/null +++ b/examples/Touch_shield_kbv/Touch_shield_kbv.ino @@ -0,0 +1,290 @@ +// the regular Adafruit "TouchScreen.h" library only works on AVRs + +// different mcufriend shields have Touchscreen on different pins +// and rotation. +// Run the UTouch_calibr_kbv sketch for calibration of your shield + +#include // Core graphics library +//#include // Hardware-specific library +//Adafruit_TFTLCD tft(A3, A2, A1, A0, A4); +#include +MCUFRIEND_kbv tft; // hard-wired for UNO shields anyway. +#include + +#if defined(__SAM3X8E__) +#undef __FlashStringHelper::F(string_literal) +#define F(string_literal) string_literal +#endif + +// These are the pins for some typical shields! +// S6D0154: YP=A1, XM=A2, YM=7, XP=6 +// ST7783 : YP=A2, XM=A1, YM=6, XP=7 +// ILI9320: YP=A2, XM=A3, YM=8, XP=9 +// ILI9325: YP=A1, XM=A2, YM=7, XP=6 +// ILI9325BG: YP=A2, XM=A1, YM=6, XP=7 +// ILI9341: YP=A2, XM=A1, YM=7, XP=6 +// ILI9488: YP=A1, XM=A2, YM=7, XP=6 +// R65109V: YP=A2, XM=A1, YM=6, XP=7 + +// most mcufriend shields use these pins and Portrait mode: +uint8_t YP = A1; // must be an analog pin, use "An" notation! +uint8_t XM = A2; // must be an analog pin, use "An" notation! +uint8_t YM = 7; // can be a digital pin +uint8_t XP = 6; // can be a digital pin +uint8_t SwapXY = 0; + +uint16_t TS_LEFT = 920; +uint16_t TS_RT = 150; +uint16_t TS_TOP = 940; +uint16_t TS_BOT = 120; +char *name = "Unknown controller"; + +// For better pressure precision, we need to know the resistance +// between X+ and X- Use any multimeter to read it +// For the one we're using, its 300 ohms across the X plate +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); +TSPoint tp; + +#define MINPRESSURE 20 +#define MAXPRESSURE 1000 + +#define SWAP(a, b) {uint16_t tmp = a; a = b; b = tmp;} + +int16_t BOXSIZE; +int16_t PENRADIUS = 3; +uint16_t identifier, oldcolor, currentcolor; +uint8_t Orientation = 0; //PORTRAIT + +// Assign human-readable names to some common 16-bit color values: +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +void show_Serial(void) +{ + Serial.print(F("Found ")); + Serial.print(name); + Serial.println(F(" LCD driver")); + Serial.print(F("ID=0x")); + Serial.println(identifier, HEX); + Serial.println("Screen is " + String(tft.width()) + "x" + String(tft.height())); + Serial.println("Calibration is: "); + Serial.println("LEFT = " + String(TS_LEFT) + " RT = " + String(TS_RT)); + Serial.println("TOP = " + String(TS_TOP) + " BOT = " + String(TS_BOT)); + Serial.print("Wiring is: "); + Serial.println(SwapXY ? "SWAPXY" : "PORTRAIT"); + Serial.println("YP=" + String(YP) + " XM=" + String(XM)); + Serial.println("YM=" + String(YM) + " XP=" + String(XP)); +} + +void show_tft(void) +{ + tft.setCursor(0, 0); + tft.setTextSize(2); + tft.print(F("Found ")); + tft.print(name); + tft.println(F(" LCD")); + tft.setTextSize(1); + tft.print(F("ID=0x")); + tft.println(identifier, HEX); + tft.println("Screen is " + String(tft.width()) + "x" + String(tft.height())); + tft.println("Calibration is: "); + tft.println("LEFT = " + String(TS_LEFT) + " RT = " + String(TS_RT)); + tft.println("TOP = " + String(TS_TOP) + " BOT = " + String(TS_BOT)); + tft.print("\nWiring is: "); + if (SwapXY) { + tft.setTextColor(CYAN); + tft.setTextSize(2); + } + tft.println(SwapXY ? "SWAPXY" : "PORTRAIT"); + tft.println("YP=" + String(YP) + " XM=" + String(XM)); + tft.println("YM=" + String(YM) + " XP=" + String(XP)); + tft.setTextSize(2); + tft.setTextColor(RED); + tft.setCursor((tft.width() - 48) / 2, (tft.height() * 2) / 4); + tft.print("EXIT"); + tft.setTextColor(YELLOW, BLACK); + tft.setCursor(0, (tft.height() * 6) / 8); + tft.print("Touch screen for loc"); + while (1) { + tp = ts.getPoint(); + pinMode(XM, OUTPUT); + pinMode(YP, OUTPUT); + pinMode(XP, OUTPUT); + pinMode(YM, OUTPUT); + if (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) continue; + if (tp.x > 450 && tp.x < 570 && tp.y > 450 && tp.y < 570) break; + tft.setCursor(0, (tft.height() * 3) / 4); + tft.print("tp.x=" + String(tp.x) + " tp.y=" + String(tp.y) + " "); + } +} + + +void setup(void) +{ + uint16_t tmp; + tft.begin(9600); + + tft.reset(); + identifier = tft.readID(); + // if (identifier == 0) identifier = 0x9341; + if (0) { + } else if (identifier == 0x0154) { + name = "S6D0154"; + TS_LEFT = 914; TS_RT = 181; TS_TOP = 957; TS_BOT = 208; + } else if (identifier == 0x7783) { + name = "ST7781"; + TS_LEFT = 865; TS_RT = 155; TS_TOP = 942; TS_BOT = 153; + SwapXY = 1; + } else if (identifier == 0x7789) { + name = "ST7789V"; + YP = A2; XM = A1; YM = 7; XP = 6; + TS_LEFT = 906; TS_RT = 169; TS_TOP = 161; TS_BOT = 919; + } else if (identifier == 0x9320) { + name = "ILI9320"; + YP = A3; XM = A2; YM = 9; XP = 8; + TS_LEFT = 902; TS_RT = 137; TS_TOP = 941; TS_BOT = 134; + } else if (identifier == 0x9325) { + name = "ILI9325"; + TS_LEFT = 900; TS_RT = 103; TS_TOP = 96; TS_BOT = 904; + } else if (identifier == 0x9325) { + name = "ILI9325 Green Dog"; + TS_LEFT = 900; TS_RT = 130; TS_TOP = 940; TS_BOT = 130; + } else if (identifier == 0x9327) { + name = "ILI9327"; + TS_LEFT = 899; TS_RT = 135; TS_TOP = 935; TS_BOT = 79; + SwapXY = 1; + } else if (identifier == 0x9329) { + name = "ILI9329"; + TS_LEFT = 143; TS_RT = 885; TS_TOP = 941; TS_BOT = 131; + SwapXY = 1; + } else if (identifier == 0x9341) { + name = "ILI9341 BLUE"; + TS_LEFT = 920; TS_RT = 139; TS_TOP = 944; TS_BOT = 150; + SwapXY = 0; + } else if (identifier == 0) { + name = "ILI9341 DealExtreme"; + TS_LEFT = 893; TS_RT = 145; TS_TOP = 930; TS_BOT = 135; + SwapXY = 1; + } else if (identifier == 0 || identifier == 0x9341) { + name = "ILI9341"; + TS_LEFT = 128; TS_RT = 911; TS_TOP = 105; TS_BOT = 908; + SwapXY = 1; + } else if (identifier == 0x9486) { + name = "ILI9486"; + TS_LEFT = 904; TS_RT = 170; TS_TOP = 950; TS_BOT = 158; + } else if (identifier == 0x9488) { + name = "ILI9488"; + TS_LEFT = 904; TS_RT = 170; TS_TOP = 950; TS_BOT = 158; + } else if (identifier == 0xB509) { + name = "R61509V"; + TS_LEFT = 889; TS_RT = 149; TS_TOP = 106; TS_BOT = 975; + SwapXY = 1; + } else { + name = "unknown"; + } + switch (Orientation) { // adjust for different aspects + case 0: break; //no change, calibrated for PORTRAIT + case 1: tmp = TS_LEFT, TS_LEFT = TS_BOT, TS_BOT = TS_RT, TS_RT = TS_TOP, TS_TOP = tmp; break; + case 2: SWAP(TS_LEFT, TS_RT); SWAP(TS_TOP, TS_BOT); break; + case 3: tmp = TS_LEFT, TS_LEFT = TS_TOP, TS_TOP = TS_RT, TS_RT = TS_BOT, TS_BOT = tmp; break; + } + + Serial.begin(9600); + ts = TouchScreen(XP, YP, XM, YM, 300); //call the constructor AGAIN with new values. + tft.begin(identifier); + show_Serial(); + tft.setRotation(Orientation); + tft.fillScreen(BLACK); + show_tft(); + + BOXSIZE = tft.width() / 6; + tft.fillScreen(BLACK); + + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED); + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW); + tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN); + tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN); + tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE); + tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA); + + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE); + currentcolor = RED; + delay(1000); +} + +void loop() +{ + uint16_t xpos, ypos; //screen coordinates + tp = ts.getPoint(); //tp.x, tp.y are ADC values + + // if sharing pins, you'll need to fix the directions of the touchscreen pins + pinMode(XM, OUTPUT); + pinMode(YP, OUTPUT); + pinMode(XP, OUTPUT); + pinMode(YM, OUTPUT); + // digitalWrite(XM, HIGH); + // digitalWrite(YP, HIGH); + // we have some minimum pressure we consider 'valid' + // pressure of 0 means no pressing! + + if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { + // is controller wired for Landscape ? or are we oriented in Landscape? + if (SwapXY != (Orientation & 1)) SWAP(tp.x, tp.y); + // scale from 0->1023 to tft.width i.e. left = 0, rt = width + // most mcufriend have touch (with icons) that extends below the TFT + // screens without icons need to reserve a space for "erase" + // scale the ADC values from ts.getPoint() to screen values e.g. 0-239 + xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width()); + ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height()); + + // are we in top color box area ? + if (ypos < BOXSIZE) { //draw white border on selected color box + oldcolor = currentcolor; + + if (xpos < BOXSIZE) { + currentcolor = RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE); + } else if (xpos < BOXSIZE * 2) { + currentcolor = YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE); + } else if (xpos < BOXSIZE * 3) { + currentcolor = GREEN; + tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, WHITE); + } else if (xpos < BOXSIZE * 4) { + currentcolor = CYAN; + tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, WHITE); + } else if (xpos < BOXSIZE * 5) { + currentcolor = BLUE; + tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, WHITE); + } else if (xpos < BOXSIZE * 6) { + currentcolor = MAGENTA; + tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, WHITE); + } + + if (oldcolor != currentcolor) { //rub out the previous white border + if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED); + if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW); + if (oldcolor == GREEN) tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN); + if (oldcolor == CYAN) tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN); + if (oldcolor == BLUE) tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE); + if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA); + } + } + // are we in drawing area ? + if (((ypos - PENRADIUS) > BOXSIZE) && ((ypos + PENRADIUS) < tft.height())) { + tft.fillCircle(xpos, ypos, PENRADIUS, currentcolor); + } + // are we in erase area ? + if (ypos > tft.height() - 10) { + // press the bottom of the screen to erase + tft.fillRect(0, BOXSIZE, tft.width(), tft.height() - BOXSIZE, BLACK); + } + } +} + diff --git a/examples/UTouch_Calibr_kbv/UTouch_Calibr_kbv.ino b/examples/UTouch_Calibr_kbv/UTouch_Calibr_kbv.ino new file mode 100644 index 0000000..c9b3afe --- /dev/null +++ b/examples/UTouch_Calibr_kbv/UTouch_Calibr_kbv.ino @@ -0,0 +1,376 @@ +// TouchScreen_Calibr_kbv for MCUFRIEND UNO Display Shields +// adapted by David Prentice +// for Adafruit's Resistive Touch Screen Library +// from Henning Karlsen's original program. Many Thanks. + +// UTouch_Calibration (C)2013-2014 Henning Karlsen +// web: http://www.henningkarlsen.com/electronics +// +// This program can be used to calibrate the touchscreen +// of the display modules. +// This program requires the UTFT library and a touch +// screen module that is compatible with UTFT. +// +// It is assumed that the display module is connected to an +// appropriate shield or that you know how to change the pin +// numbers in the setup. +// +// Instructions will be given on the display. + +#define TOUCH_ORIENTATION PORTRAIT +#define USE_UTOUCH 0 + +#if !(USE_UTOUCH) +#define TITLE "TouchScreen.h Calibration" +#include +#include //we are using UTFT display methods +UTFTGLUE myGLCD(0x9341, A2, A1, A3, A4, A0); + +#include + +// MCUFRIEND UNO shield shares pins with the TFT. Due does NOT work +#define YP A1 //A3 for ILI9320 +#define YM 7 //9 +#define XM A2 +#define XP 6 //8 + +TouchScreen myTouch(XP, YP, XM, YM, 300); +TSPoint tp; //Touchscreen_due branch uses Point + +void readResistiveTouch(void) +{ + tp = myTouch.getPoint(); + pinMode(YP, OUTPUT); //restore shared pins + pinMode(XM, OUTPUT); + digitalWrite(YP, HIGH); + digitalWrite(XM, HIGH); +} + +bool ISPRESSED(void) +{ + readResistiveTouch(); + return tp.z > 20 && tp.z < 1000; +} + +void showpoint(void) +{ + Serial.print("\r\nx="); Serial.print(tp.x); + Serial.print(" y="); Serial.print(tp.y); + Serial.print(" z="); Serial.print(tp.z); +} +#else +#define TITLE "UTouch.h Calibration" +#include +#include +#include +UTFT myGLCD(ILI9486, 38, 39, 40, 41); +UTouch myTouch( 6, 5, 4, 3, 2); + +#define ISPRESSED() myTouch.dataAvailable() +extern void fail(); + +#endif + +// ************************************ +// DO NOT EDIT ANYTHING BELOW THIS LINE +// ************************************ + +// Declare which fonts we will be using +extern uint8_t SmallFont[]; + +uint32_t cx, cy; +uint32_t rx[8], ry[8]; +int32_t clx, crx, cty, cby; +float px, py; +int dispx, dispy, text_y_center, swapxy; +uint32_t calx, caly, cals; +char buf[13]; + +void setup() +{ + Serial.begin(9600); + Serial.println("UTouch_Calibr_kbv"); + digitalWrite(A0, HIGH); + pinMode(A0, OUTPUT); + myGLCD.InitLCD(TOUCH_ORIENTATION); + myGLCD.clrScr(); + myGLCD.setFont(SmallFont); +#if (USE_UTOUCH) + myTouch.InitTouch(TOUCH_ORIENTATION); +#endif + dispx = myGLCD.getDisplayXSize(); + dispy = myGLCD.getDisplayYSize(); + text_y_center = (dispy / 2) - 6; +} + +void drawCrossHair(int x, int y) +{ + myGLCD.drawRect(x - 10, y - 10, x + 10, y + 10); + myGLCD.drawLine(x - 5, y, x + 5, y); + myGLCD.drawLine(x, y - 5, x, y + 5); +} + +void readCoordinates() +{ + int iter = 5000; + int failcount = 0; + int cnt = 0; + uint32_t tx = 0; + uint32_t ty = 0; + boolean OK = false; + + while (OK == false) + { + myGLCD.setColor(255, 255, 255); + myGLCD.print("* PRESS *", CENTER, text_y_center); + while (ISPRESSED() == false) {} + myGLCD.print("* HOLD! *", CENTER, text_y_center); +#if (USE_UTOUCH) + while ((ISPRESSED() == true) && (cnt < iter) && (failcount < 10000)) + { + myTouch.calibrateRead(); + if (!((myTouch.TP_X == 65535) || (myTouch.TP_Y == 65535))) + { + tx += myTouch.TP_X; + ty += myTouch.TP_Y; + cnt++; + } + else + failcount++; + } +#else + cnt = 0; + iter = 400; + do + { + readResistiveTouch(); + // showpoint(tp); + if (tp.z > 20 && tp.z < 1000) + { + tx += tp.x; + ty += tp.y; + cnt++; + } + else + failcount++; + } while ((cnt < iter) && (failcount < 10000)); +#endif + if (cnt >= iter) + { + OK = true; + } + else + { + tx = 0; + ty = 0; + cnt = 0; + } + if (failcount >= 10000) + fail(); + } + + cx = tx / iter; + cy = ty / iter; +} + +void calibrate(int x, int y, int i) +{ + myGLCD.setColor(255, 255, 255); + drawCrossHair(x, y); + myGLCD.setBackColor(255, 0, 0); + readCoordinates(); + myGLCD.setColor(255, 255, 255); + myGLCD.print("* RELEASE *", CENTER, text_y_center); + myGLCD.setColor(80, 80, 80); + drawCrossHair(x, y); + rx[i] = cx; + ry[i] = cy; + Serial.print("\r\ncx="); Serial.print(cx); + Serial.print(" cy="); Serial.print(cy); + while (ISPRESSED() == true) {} +} + +void waitForTouch() +{ + while (ISPRESSED() == true) {} + while (ISPRESSED() == false) {} + while (ISPRESSED() == true) {} +} + +void toHex(uint32_t num) +{ + buf[0] = '0'; + buf[1] = 'x'; + buf[10] = 'U'; + buf[11] = 'L'; + buf[12] = 0; + for (int zz = 9; zz > 1; zz--) + { + if ((num & 0xF) > 9) + buf[zz] = (num & 0xF) + 55; + else + buf[zz] = (num & 0xF) + 48; + num = num >> 4; + } +} + +void startup() +{ + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print(TITLE, CENTER, 1); + myGLCD.setBackColor(0, 0, 0); + + myGLCD.print("Use a stylus or something", LEFT, 30); + myGLCD.print("similar to touch as close", LEFT, 42); + myGLCD.print("to the center of the", LEFT, 54); + myGLCD.print("highlighted crosshair as", LEFT, 66); + myGLCD.print("possible. Keep as still as", LEFT, 78); + myGLCD.print("possible and keep holding", LEFT, 90); + myGLCD.print("until the highlight is", LEFT, 102); + myGLCD.print("removed. Repeat for all", LEFT, 114); + myGLCD.print("crosshairs in sequence.", LEFT, 126); + myGLCD.print("Touch screen to continue", CENTER, 162); + + waitForTouch(); + myGLCD.clrScr(); +} + +void showNumI(char *msg, uint32_t val, int x, int y) +{ + myGLCD.print(msg, x, y); + myGLCD.printNumI(val, x + 50, y); +} + +void done() +{ + myGLCD.clrScr(); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print(TITLE, CENTER, 1); + myGLCD.setBackColor(0, 0, 0); +#if (USE_UTOUCH) + myGLCD.print("To use the new calibration", LEFT, 30); + myGLCD.print("settings you must edit the", LEFT, 42); + myGLCD.setColor(160, 160, 255); + myGLCD.print("UTouchCD.h", LEFT, 54); + myGLCD.setColor(255, 255, 255); + myGLCD.print("file and change", 88, 54); + myGLCD.print("the following values. The", LEFT, 66); + myGLCD.print("values are located right", LEFT, 78); + myGLCD.print("below the opening comment.", LEFT, 90); + myGLCD.print("CAL_X", LEFT, 110); + myGLCD.print("CAL_Y", LEFT, 122); + myGLCD.print("CAL_S", LEFT, 134); + toHex(calx); + myGLCD.print(buf, 75, 110); + toHex(caly); + myGLCD.print(buf, 75, 122); + toHex(cals); + myGLCD.print(buf, 75, 134); +#else + myGLCD.print("To use the new calibration", LEFT, 30); + myGLCD.print("settings you must map the values", LEFT, 42); + myGLCD.print("from Point p = ts.getPoint() e.g. ", LEFT, 54); + myGLCD.print("x = map(p.x, LEFT, RT, 0, tft.width());", LEFT, 66); + myGLCD.print("y = map(p.y, TOP, BOT, 0, tft.height());", LEFT, 78); + myGLCD.print("swap p.x and p.y if diff ORIENTATION", LEFT, 90); +#endif + //.kbv show human values + showNumI("LEFT ", (calx >> 14) & 0x3FFF, 0, 186); + showNumI("RT ", (calx) & 0x3FFF, 100, 186); + myGLCD.printNumF(px, 2, 200, 186); + showNumI("TOP ", (caly >> 14) & 0x3FFF, 0, 198); + showNumI("BOT ", (caly) & 0x3FFF, 100, 198); + myGLCD.printNumF(py, 2, 200, 198); + showNumI("WID ", (cals >> 12) & 0xFFF, 0, 210); + showNumI("HT ", (cals) & 0xFFF, 100, 210); + myGLCD.print("Touch Controller is ", 0, 222); + myGLCD.print((cals >> 31) ? "LANDSCAPE" : "PORTRAIT", 170, 222); + +} + +void fail() +{ + myGLCD.clrScr(); + myGLCD.setColor(255, 0, 0); + myGLCD.fillRect(0, 0, dispx - 1, 13); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.drawLine(0, 14, dispx - 1, 14); + myGLCD.print("Touch Calibration FAILED", CENTER, 1); + myGLCD.setBackColor(0, 0, 0); + + myGLCD.print("Unable to read the position", LEFT, 30); + myGLCD.print("of the press. This is a", LEFT, 42); + myGLCD.print("hardware issue and can", 88, 54); + myGLCD.print("not be corrected in", LEFT, 66); + myGLCD.print("software.", LEFT, 78); + + while (true) {}; +} + +void loop() +{ + startup(); + + myGLCD.setColor(80, 80, 80); + drawCrossHair(dispx - 11, 10); + drawCrossHair(dispx / 2, 10); + drawCrossHair(10, 10); + drawCrossHair(dispx - 11, dispy / 2); + drawCrossHair(10, dispy / 2); + drawCrossHair(dispx - 11, dispy - 11); + drawCrossHair(dispx / 2, dispy - 11); + drawCrossHair(10, dispy - 11); + myGLCD.setColor(255, 255, 255); + myGLCD.setBackColor(255, 0, 0); + myGLCD.print("***********", CENTER, text_y_center - 12); + myGLCD.print("***********", CENTER, text_y_center + 12); + + calibrate(10, 10, 0); + calibrate(10, dispy / 2, 1); + calibrate(10, dispy - 11, 2); + calibrate(dispx / 2, 10, 3); + calibrate(dispx / 2, dispy - 11, 4); + calibrate(dispx - 11, 10, 5); + calibrate(dispx - 11, dispy / 2, 6); + calibrate(dispx - 11, dispy - 11, 7); + + cals = (long(dispx - 1) << 12) + (dispy - 1); + if (TOUCH_ORIENTATION == PORTRAIT) swapxy = rx[2] - rx[0]; + else swapxy = ry[2] - ry[0]; + swapxy = (swapxy < -500 || swapxy > 500); + if ((TOUCH_ORIENTATION == PORTRAIT) ^ (swapxy != 0)) { + clx = (rx[0] + rx[1] + rx[2]) / 3; + crx = (rx[5] + rx[6] + rx[7]) / 3; + cty = (ry[0] + ry[3] + ry[5]) / 3; + cby = (ry[2] + ry[4] + ry[7]) / 3; + } else { + clx = (ry[0] + ry[1] + ry[2]) / 3; + crx = (ry[5] + ry[6] + ry[7]) / 3; + cty = (rx[0] + rx[3] + rx[5]) / 3; + cby = (rx[2] + rx[4] + rx[7]) / 3; + } + px = float(crx - clx) / (dispx - 20); + py = float(cby - cty) / (dispy - 20); + // px = 0; + clx -= px * 10; + crx += px * 10; + cty -= py * 10; + cby += py * 10; + + calx = (long(clx) << 14) + long(crx); + caly = (long(cty) << 14) + long(cby); + if (swapxy) + cals |= (1L << 31); + + done(); + while (true) {} +} diff --git a/examples/aspect_kbv/aspect_kbv.ino b/examples/aspect_kbv/aspect_kbv.ino new file mode 100644 index 0000000..1de1ae3 --- /dev/null +++ b/examples/aspect_kbv/aspect_kbv.ino @@ -0,0 +1,40 @@ +#include // Hardware-specific library +#include +MCUFRIEND_kbv tft; + +void setup() +{ + // put your setup code here, to run once: + Serial.begin(9600); + tft.reset(); + uint16_t identifier = tft.readID(); + Serial.print("ID = 0x"); + Serial.println(identifier, HEX); + if (identifier == 0xEFEF) identifier = 0x9486; + tft.begin(identifier); + // tft.fillScreen(BLACK); +} + +char *msg[] = { "PORTRAIT", "LANDSCAPE", "PORTRAIT_REV", "LANDSCAPE_REV" }; +uint8_t aspect; + +void loop() +{ + // put your main code here, to run repeatedly: + uint16_t x = 50, y = 100; + tft.setRotation(aspect); + tft.fillScreen(0x0000); + tft.setCursor(0, 0); + tft.setTextSize(2); + tft.println(msg[aspect]); + tft.setCursor(x, y); + tft.println("[x=" + String(x) + ",y=" + String(y) + "]"); + delay(5000); + tft.println("INVERT ON"); + tft.invertDisplay(true); + delay(1000); + tft.invertDisplay(false); + tft.println("INVERT OFF"); + delay(1000); + if (++aspect >= 4) aspect = 0; +} diff --git a/examples/graphictest_kbv/graphictest_kbv.ino b/examples/graphictest_kbv/graphictest_kbv.ino new file mode 100644 index 0000000..f55f25e --- /dev/null +++ b/examples/graphictest_kbv/graphictest_kbv.ino @@ -0,0 +1,569 @@ +// All the mcufriend.com UNO shields have the same pinout. +// i.e. control pins A0-A4. Data D2-D9. microSD D10-D13. +// Touchscreens are normally A1, A2, D7, D6 but the order varies +// +// This demo should work with most Adafruit TFT libraries +// If you are not using a shield, use a full Adafruit constructor() +// e.g. Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); + +#define LCD_CS A3 // Chip Select goes to Analog 3 +#define LCD_CD A2 // Command/Data goes to Analog 2 +#define LCD_WR A1 // LCD Write goes to Analog 1 +#define LCD_RD A0 // LCD Read goes to Analog 0 +#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin + +#include // f.k. for Arduino-1.5.2 +#include "Adafruit_GFX.h"// Hardware-specific library +#include +MCUFRIEND_kbv tft; +//#include +//Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); + +// Assign human-readable names to some common 16-bit color values: +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +void setup(void); +void loop(void); +unsigned long testFillScreen(); +unsigned long testText(); +unsigned long testLines(uint16_t color); +unsigned long testFastLines(uint16_t color1, uint16_t color2); +unsigned long testRects(uint16_t color); +unsigned long testFilledRects(uint16_t color1, uint16_t color2); +unsigned long testFilledCircles(uint8_t radius, uint16_t color); +unsigned long testCircles(uint8_t radius, uint16_t color); +unsigned long testTriangles(); +unsigned long testFilledTriangles(); +unsigned long testRoundRects(); +unsigned long testFilledRoundRects(); +void progmemPrint(const char *str); +void progmemPrintln(const char *str); + +void runtests(void); + +uint16_t g_identifier; + +extern const uint8_t hanzi[]; +void showhanzi(unsigned int x, unsigned int y, unsigned char index) +{ + uint8_t i, j, c, first = 1; + uint8_t *temp = (uint8_t*)hanzi; + uint16_t color; + tft.setAddrWindow(x, y, x + 31, y + 31); //设置区域 + temp += index * 128; + for (j = 0; j < 128; j++) + { + c = pgm_read_byte(temp); + for (i = 0; i < 8; i++) + { + if ((c & (1 << i)) != 0) + { + color = RED; + } + else + { + color = BLACK; + } + tft.pushColors(&color, 1, first); + first = 0; + } + temp++; + } +} + +void setup(void) { + Serial.begin(9600); + uint32_t when = millis(); + // while (!Serial) ; //hangs a Leonardo until you connect a Serial + if (!Serial) delay(5000); //allow some time for Leonardo + Serial.println("Serial took " + String((millis() - when)) + "ms to start"); + static uint16_t identifier; + // tft.reset(); //we can't read ID on 9341 until begin() + g_identifier = tft.readID(); // + Serial.print("ID = 0x"); + Serial.println(g_identifier, HEX); + if (g_identifier == 0x00D3 || g_identifier == 0xD3D3) g_identifier = 0x9595; // write-only shield + if (g_identifier == 0xFFFF) g_identifier = 0x9341; // serial +// g_identifier = 0x9329; // force ID + tft.begin(g_identifier); +} + +#if defined(MCUFRIEND_KBV_H_) +uint16_t scrollbuf[320]; // my biggest screen is 320x480 +#define READGRAM(x, y, buf, w, h) tft.readGRAM(x, y, buf, w, h) +#else +uint16_t scrollbuf[320]; // Adafruit only does 240x320 +// Adafruit can read a block by one pixel at a time +int16_t READGRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h) +{ + uint16_t *p; + for (int row = 0; row < h; row++) { + p = block + row * w; + for (int col = 0; col < w; col++) { + *p++ = tft.readPixel(x + col, y + row); + } + } +} +#endif + +void windowScroll(int16_t x, int16_t y, int16_t wid, int16_t ht, int16_t dx, int16_t dy, uint16_t *buf) +{ + if (dx) for (int16_t row = 0; row < ht; row++) { + READGRAM(x, y + row, buf, wid, 1); + tft.setAddrWindow(x, y + row, x + wid - 1, y + row); + tft.pushColors(buf + dx, wid - dx, 1); + tft.pushColors(buf + 0, dx, 0); + } + if (dy) for (int16_t col = 0; col < wid; col++) { + READGRAM(x + col, y, buf, 1, ht); + tft.setAddrWindow(x + col, y, x + col, y + ht - 1); + tft.pushColors(buf + dy, ht - dy, 1); + tft.pushColors(buf + 0, dy, 0); + } +} + +void loop(void) { + uint8_t aspect; + uint16_t pixel; + char *aspectname[] = { + "PORTRAIT", "LANDSCAPE", "PORTRAIT_REV", "LANDSCAPE_REV" + }; + char *colorname[] = { "BLUE", "GREEN", "RED", "GRAY" }; + uint16_t colormask[] = { 0x001F, 0x07E0, 0xF800, 0xFFFF }; + uint16_t dx, rgb, n, wid, ht; + tft.setRotation(0); +// for (uint8_t i = 0; i < 2; i++) showhanzi(0, 0, i), delay(1000); + runtests(); + delay(2000); + if (tft.height() > 64) { + for (uint8_t cnt = 0; cnt < 4; cnt++) { + aspect = (cnt + 0) & 3; + tft.setRotation(aspect); + wid = tft.width(); + ht = tft.height(); + testText(); + dx = wid / 32; + for (n = 0; n < 32; n++) { + rgb = n * 8; + rgb = tft.color565(rgb, rgb, rgb); + tft.fillRect(n * dx, 48, dx, 64, rgb & colormask[aspect]); + } + tft.setTextSize(2); + tft.setTextColor(colormask[aspect], BLACK); + tft.setCursor(0, 72); + tft.print(colorname[aspect]); + tft.setTextColor(WHITE); + tft.println(" COLOR GRADES"); + tft.setTextColor(WHITE, BLACK); + tft.setCursor(0, 184); + tft.println(aspectname[aspect]); + delay(1000); + tft.drawPixel(0, 0, YELLOW); + pixel = tft.readPixel(0, 0); +#if defined(MCUFRIEND_KBV_H_) + extern const uint8_t penguin[]; + tft.setAddrWindow(wid - 40 - 40, 20 + 0, wid - 1 - 40, 20 + 39); + tft.pushColors(penguin, 1600, 1); + tft.setTextColor(WHITE, BLACK); + tft.println("VERTICAL SCROLL UP"); + uint16_t maxscroll; + if (tft.getRotation() & 1) maxscroll = wid; + else maxscroll = ht; + for (uint16_t i = 1; i <= maxscroll; i++) { + tft.vertScroll(0, maxscroll, i); + delay(10); + } + tft.vertScroll(0, maxscroll, 0); + tft.setCursor(0, 200); + tft.println("VERTICAL SCROLL DN"); + for (uint16_t i = 1; i <= maxscroll; i++) { + tft.vertScroll(0, maxscroll, 0 - (int16_t)i); + delay(10); + } + delay(1000); + tft.vertScroll(0, maxscroll, 0); + if ((aspect & 1) == 0) { //Portrait + tft.setCursor(0, 200); + tft.setTextColor(BLUE, BLACK); + tft.println("ONLY THE COLOR BAND"); + for (uint16_t i = 1; i <= 64; i++) { + tft.vertScroll(48, 64, i); + delay(20); + } + delay(1000); + tft.vertScroll(0, maxscroll, 0); + } +#endif + tft.setCursor(0, 200); + tft.setTextColor(YELLOW, BLACK); + if (pixel == YELLOW) { + tft.println("SOFTWARE SCROLL "); +#if 0 + for (int16_t i = 45, dx = 2, dy = 1; i > 0; i -= dx) { + windowScroll(24, 8, 90, 40, dx, dy, scrollbuf); + } +#else + // scroll a whole width of the screen + n = (wid > 320) ? 320 : wid; + for (int16_t i = n, dx = 4, dy = 0; i > 0; i -= dx) { + windowScroll(0, 200, n, 16, dx, dy, scrollbuf); + } +#endif + } + else if (pixel == CYAN) + tft.println("readPixel() reads as BGR"); + else if ((pixel & 0xF8F8) == 0xF8F8) + tft.println("readPixel() should be 24-bit"); + else { + tft.print("readPixel() reads 0x"); + tft.println(pixel, HEX); + } + delay(5000); + } + } + tft.println("INVERT DISPLAY"); + tft.invertDisplay(true); + delay(2000); + tft.invertDisplay(false); +} + +typedef struct { + PGM_P msg; + uint32_t ms; +} TEST; +TEST result[12]; + +#define RUNTEST(n, str, test) { result[n].msg = PSTR(str); result[n].ms = test; delay(500); } + +void runtests(void) +{ + uint8_t i, len = 24, cnt; + uint32_t total; + RUNTEST(0, "FillScreen ", testFillScreen()); + RUNTEST(1, "Text ", testText()); + RUNTEST(2, "Lines ", testLines(CYAN)); + RUNTEST(3, "Horiz/Vert Lines ", testFastLines(RED, BLUE)); + RUNTEST(4, "Rectangles (outline) ", testRects(GREEN)); + RUNTEST(5, "Rectangles (filled) ", testFilledRects(YELLOW, MAGENTA)); + RUNTEST(6, "Circles (filled) ", testFilledCircles(10, MAGENTA)); + RUNTEST(7, "Circles (outline) ", testCircles(10, WHITE)); + RUNTEST(8, "Triangles (outline) ", testTriangles()); + RUNTEST(9, "Triangles (filled) ", testFilledTriangles()); + RUNTEST(10, "Rounded rects (outline) ", testRoundRects()); + RUNTEST(11, "Rounded rects (filled) ", testFilledRoundRects()); + + tft.fillScreen(BLACK); + tft.setTextColor(GREEN); + tft.setCursor(0, 0); + uint16_t wid = tft.width(); + if (wid > 176) { + tft.setTextSize(2); +#if defined(MCUFRIEND_KBV_H_) + tft.print("MCUFRIEND "); +#if MCUFRIEND_KBV_H_ != 0 + tft.print(0.01 * MCUFRIEND_KBV_H_, 1); +#else + tft.print("for"); +#endif + tft.println(" UNO"); +#else + tft.println("Adafruit-Style Tests"); +#endif + } else len = wid / 6 - 8; + tft.setTextSize(1); + total = 0; + for (i = 0; i < 12; i++) { + PGM_P str = result[i].msg; + char c; + if (len > 24) { + if (i < 10) tft.print(" "); + tft.print(i); + tft.print(": "); + } + uint8_t cnt = len; + while ((c = pgm_read_byte(str++)) && cnt--) tft.print(c); + tft.print(" "); + tft.println(result[i].ms); + total += result[i].ms; + } + tft.setTextSize(2); + tft.print("Total:"); + tft.print(0.000001 * total); + tft.println("sec"); + g_identifier = tft.readID(); + tft.print("ID: 0x"); + tft.println(tft.readID(), HEX); + tft.print("Reg(00):0x"); + tft.println(tft.readReg(0x00), HEX); + tft.print("F_CPU:"); + tft.print(0.000001 * F_CPU); +#if defined(__OPTIMIZE_SIZE__) + tft.println("MHz -Os"); +#else + tft.println("MHz"); +#endif + + delay(10000); +} + +// Standard Adafruit tests. will adjust to screen size + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(BLACK); + tft.fillScreen(RED); + tft.fillScreen(GREEN); + tft.fillScreen(BLUE); + tft.fillScreen(BLACK); + return micros() - start; +} + +unsigned long testText() { + unsigned long start; + tft.fillScreen(BLACK); + start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(WHITE); tft.setTextSize(1); + tft.println("Hello World!"); + tft.setTextColor(YELLOW); tft.setTextSize(2); + tft.println(123.45); + tft.setTextColor(RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(GREEN); + tft.setTextSize(5); + tft.println("Groop"); + tft.setTextSize(2); + tft.println("I implore thee,"); + tft.setTextSize(1); + tft.println("my foonting turlingdromes."); + tft.println("And hooptiously drangle me"); + tft.println("with crinkly bindlewurdles,"); + tft.println("Or I will rend thee"); + tft.println("in the gobberwarts"); + tft.println("with my blurglecruncheon,"); + tft.println("see if I don't!"); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(BLACK); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = w - 1; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t = micros() - start; // fillScreen doesn't count against timing + + tft.fillScreen(BLACK); + + x1 = w - 1; + y1 = 0; + y2 = h - 1; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = 0; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t += micros() - start; + + tft.fillScreen(BLACK); + + x1 = 0; + y1 = h - 1; + y2 = 0; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = w - 1; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t += micros() - start; + + tft.fillScreen(BLACK); + + x1 = w - 1; + y1 = h - 1; + y2 = 0; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = 0; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + + return micros() - start; +} + +unsigned long testFastLines(uint16_t color1, uint16_t color2) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(); + + tft.fillScreen(BLACK); + start = micros(); + for (y = 0; y < h; y += 5) tft.drawFastHLine(0, y, w, color1); + for (x = 0; x < w; x += 5) tft.drawFastVLine(x, 0, h, color2); + + return micros() - start; +} + +unsigned long testRects(uint16_t color) { + unsigned long start; + int n, i, i2, + cx = tft.width() / 2, + cy = tft.height() / 2; + + tft.fillScreen(BLACK); + n = min(tft.width(), tft.height()); + start = micros(); + for (i = 2; i < n; i += 6) { + i2 = i / 2; + tft.drawRect(cx - i2, cy - i2, i, i, color); + } + + return micros() - start; +} + +unsigned long testFilledRects(uint16_t color1, uint16_t color2) { + unsigned long start, t = 0; + int n, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + n = min(tft.width(), tft.height()); + for (i = n; i > 0; i -= 6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx - i2, cy - i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx - i2, cy - i2, i, i, color2); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(BLACK); + start = micros(); + for (x = radius; x < w; x += r2) { + for (y = radius; y < h; y += r2) { + tft.fillCircle(x, y, radius, color); + } + } + + return micros() - start; +} + +unsigned long testCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, r2 = radius * 2, + w = tft.width() + radius, + h = tft.height() + radius; + + // Screen is not cleared for this one -- this is + // intentional and does not affect the reported time. + start = micros(); + for (x = 0; x < w; x += r2) { + for (y = 0; y < h; y += r2) { + tft.drawCircle(x, y, radius, color); + } + } + + return micros() - start; +} + +unsigned long testTriangles() { + unsigned long start; + int n, i, cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + n = min(cx, cy); + start = micros(); + for (i = 0; i < n; i += 5) { + tft.drawTriangle( + cx , cy - i, // peak + cx - i, cy + i, // bottom left + cx + i, cy + i, // bottom right + tft.color565(0, 0, i)); + } + + return micros() - start; +} + +unsigned long testFilledTriangles() { + unsigned long start, t = 0; + int i, cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + start = micros(); + for (i = min(cx, cy); i > 10; i -= 5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i, i)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i, i, 0)); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, red, step, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + red = 0; + step = (256 * 6) / w; + for (i = 0; i < w; i += 6) { + i2 = i / 2; + red += step; + tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(red, 0, 0)); + } + + return micros() - start; +} + +unsigned long testFilledRoundRects() { + unsigned long start; + int i, i2, green, step, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + start = micros(); + green = 256; + step = (256 * 6) / min(tft.width(), tft.height()); + for (i = min(tft.width(), tft.height()); i > 20; i -= 6) { + i2 = i / 2; + green -= step; + tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, green, 0)); + } + + return micros() - start; +} + diff --git a/examples/graphictest_kbv/icons.c b/examples/graphictest_kbv/icons.c new file mode 100644 index 0000000..97edda8 --- /dev/null +++ b/examples/graphictest_kbv/icons.c @@ -0,0 +1,408 @@ +#include + +const unsigned char PROGMEM penguin[3200] = { /* 0X00,0X10,0X28,0X00,0X28,0X00,0X01,0X1B, */ + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, + 0XBA, 0XD6, 0XB6, 0XB5, 0XF3, 0X9C, 0XB2, 0X94, 0XB3, 0X9C, 0XB2, 0X94, 0X34, 0XA5, 0XF7, 0XBD, + 0XFB, 0XDE, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XFB, 0XDE, 0XF3, 0X9C, 0XCB, 0X5A, + 0XC7, 0X39, 0X04, 0X21, 0X82, 0X10, 0X42, 0X10, 0X42, 0X10, 0X41, 0X08, 0X83, 0X18, 0X45, 0X29, + 0XC7, 0X39, 0X0C, 0X63, 0X75, 0XAD, 0X3C, 0XE7, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0XB2, 0X94, 0X08, 0X42, 0XC3, 0X18, 0X82, 0X10, + 0X04, 0X21, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X86, 0X31, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X82, 0X10, 0X41, 0X08, 0XC3, 0X18, 0X08, 0X42, 0XF3, 0X9C, 0X3C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XDE, 0X0C, 0X63, 0XC3, 0X18, 0XC3, 0X18, 0X45, 0X29, 0XC7, 0X39, + 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0XC7, 0X39, 0XC7, 0X39, + 0X86, 0X31, 0X86, 0X31, 0X04, 0X21, 0X41, 0X08, 0X82, 0X10, 0XCB, 0X5A, 0XBA, 0XD6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFB, 0XDE, 0XCB, 0X5A, 0X82, 0X10, 0X45, 0X29, 0XC7, 0X39, 0X08, 0X42, 0X08, 0X42, + 0X09, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X08, 0X42, 0XC7, 0X39, + 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X83, 0X18, 0X00, 0X00, 0XC8, 0X41, 0X38, 0XC6, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X7D, 0XEF, 0X8E, 0X73, 0X82, 0X10, 0X45, 0X29, 0XC7, 0X39, 0X08, 0X42, 0X09, 0X4A, 0X8A, 0X52, + 0X30, 0X84, 0XCF, 0X7B, 0X8A, 0X52, 0X49, 0X4A, 0X4A, 0X52, 0X49, 0X4A, 0XCB, 0X5A, 0XCF, 0X7B, + 0X0C, 0X63, 0X08, 0X42, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, 0X00, 0X00, 0X49, 0X4A, + 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XF3, 0X9C, 0XC3, 0X18, 0X04, 0X21, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X72, 0X94, + 0X7D, 0XEF, 0X7D, 0XEF, 0XB2, 0X94, 0X4A, 0X52, 0X49, 0X4A, 0X8A, 0X52, 0X75, 0XAD, 0XBE, 0XF7, + 0XBA, 0XD6, 0X4D, 0X6B, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, 0X41, 0X08, + 0XCF, 0X7B, 0X7C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBA, 0XD6, + 0X08, 0X42, 0X82, 0X10, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8E, 0X73, 0XFB, 0XDE, + 0XFF, 0XFF, 0XBE, 0XF7, 0XBA, 0XD6, 0X8E, 0X73, 0X08, 0X42, 0X30, 0X84, 0X3C, 0XE7, 0X7D, 0XEF, + 0XFF, 0XFF, 0XB6, 0XB5, 0X49, 0X4A, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, 0X41, 0X08, + 0X45, 0X29, 0XB6, 0XB5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0X71, 0X8C, + 0X41, 0X08, 0X45, 0X29, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X52, 0XB2, 0X94, 0XBE, 0XF7, + 0XBE, 0XF7, 0XB2, 0X94, 0XCF, 0X7B, 0XCF, 0X7B, 0X49, 0X4A, 0XB6, 0XB5, 0XF3, 0X9C, 0X0C, 0X63, + 0X38, 0XC6, 0XBA, 0XD6, 0X0C, 0X63, 0X87, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, + 0X41, 0X08, 0X30, 0X84, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0XCB, 0X5A, + 0X41, 0X08, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X4A, 0X52, 0X8A, 0X52, 0XF3, 0X9C, 0XFF, 0XFF, + 0X7D, 0XEF, 0XC7, 0X39, 0XC3, 0X18, 0X0C, 0X63, 0XCB, 0X5A, 0XB6, 0XB5, 0XB2, 0X94, 0XCB, 0X5A, + 0X75, 0XAD, 0XFA, 0XD6, 0X4D, 0X6B, 0X87, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X41, 0X08, 0X8A, 0X52, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X38, 0XC6, 0X86, 0X31, + 0X04, 0X21, 0XC8, 0X41, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X52, 0X49, 0X4A, 0XB1, 0X8C, 0XBE, 0XF7, + 0XBE, 0XF7, 0XB2, 0X94, 0XCF, 0X7B, 0XCF, 0X7B, 0X49, 0X4A, 0X74, 0XA5, 0X7D, 0XEF, 0X7C, 0XE7, + 0XBE, 0XF7, 0X79, 0XCE, 0X0C, 0X63, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X82, 0X10, 0X45, 0X29, 0X75, 0XAD, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X34, 0XA5, 0X82, 0X10, + 0X86, 0X31, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8A, 0X52, 0X49, 0X4A, 0X4D, 0X6B, 0XBA, 0XD6, + 0XFF, 0XFF, 0XFF, 0XFF, 0X79, 0XCE, 0X0D, 0X63, 0XC7, 0X39, 0XCF, 0X7B, 0X7D, 0XEF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X75, 0XAD, 0X08, 0X42, 0X86, 0X31, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0XC3, 0X18, 0XC3, 0X18, 0XB2, 0X94, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XB2, 0X8C, 0X41, 0X08, + 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8A, 0X52, 0X8A, 0X52, 0X4A, 0X4A, 0XD0, 0X7B, + 0X7A, 0XC6, 0X7B, 0XBE, 0X90, 0X6B, 0XC9, 0X39, 0X88, 0X31, 0XC9, 0X39, 0XB3, 0X84, 0XBB, 0XC6, + 0XF8, 0XB5, 0XCC, 0X5A, 0X86, 0X31, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0XC4, 0X20, 0X41, 0X08, 0X30, 0X84, 0X3C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0X8A, 0X4A, 0XC3, 0X10, + 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X4A, 0X4A, 0X42, 0X09, 0X3A, 0X08, 0X4A, + 0X09, 0X6B, 0X49, 0X7B, 0XC6, 0X7A, 0X05, 0X83, 0X46, 0X83, 0XC5, 0X7A, 0XC6, 0X72, 0X09, 0X7B, + 0X48, 0X5A, 0X87, 0X31, 0X88, 0X21, 0X88, 0X29, 0X86, 0X31, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0X04, 0X21, 0X41, 0X08, 0X4A, 0X4A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF7, 0XC5, 0X82, 0X50, 0X05, 0X41, + 0XC7, 0X29, 0X08, 0X42, 0X49, 0X4A, 0X4A, 0X42, 0X49, 0X4A, 0X09, 0X7B, 0X88, 0X9B, 0XC6, 0XB3, + 0X21, 0XD4, 0XA0, 0XDC, 0XE1, 0XE4, 0X61, 0XED, 0X61, 0XED, 0X21, 0XED, 0XA0, 0XE4, 0X20, 0XDC, + 0X80, 0XCB, 0X43, 0XAB, 0XC4, 0X82, 0X06, 0X5A, 0X47, 0X21, 0X46, 0X29, 0X45, 0X29, 0X04, 0X29, + 0X04, 0X19, 0X82, 0X10, 0X82, 0X18, 0XF3, 0X9C, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X4D, 0X93, 0X00, 0XA0, 0X82, 0XB8, + 0XC7, 0X31, 0X09, 0X32, 0X49, 0X4A, 0X86, 0X7A, 0X43, 0XC3, 0X6B, 0XED, 0XF4, 0XF6, 0XEB, 0XFD, + 0X20, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X20, 0XFD, + 0XE0, 0XFC, 0XA0, 0XFC, 0X60, 0XF4, 0XC1, 0XDB, 0X83, 0X9A, 0XC5, 0X49, 0X45, 0X29, 0X04, 0X19, + 0XC4, 0X20, 0X82, 0X38, 0X00, 0X50, 0XCB, 0X6A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XEE, 0X04, 0XA1, 0X00, 0XC0, 0X00, 0XF0, + 0XC3, 0XA0, 0XC8, 0X41, 0X49, 0X42, 0X05, 0X9B, 0X20, 0XFC, 0XA4, 0XFC, 0X69, 0XFD, 0XE8, 0XFD, + 0X63, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0XE0, 0XFC, + 0XE0, 0XFC, 0XA0, 0XFC, 0X60, 0XFC, 0X20, 0XFC, 0X41, 0XD3, 0XC5, 0X49, 0X45, 0X19, 0XC4, 0X38, + 0X82, 0X68, 0X41, 0X88, 0X00, 0X70, 0X49, 0X5A, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XF6, 0X82, 0XC0, 0X00, 0XD0, 0X86, 0XC1, + 0X46, 0XF1, 0X41, 0XC8, 0X45, 0X79, 0X89, 0X52, 0X88, 0X62, 0X86, 0X6A, 0XC6, 0X7A, 0XC4, 0XBB, + 0XE1, 0XFC, 0X60, 0XFD, 0X60, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XE0, 0XFC, + 0X60, 0XE4, 0X03, 0X93, 0X84, 0X72, 0X44, 0X6A, 0XC5, 0X41, 0X45, 0X29, 0XC3, 0X58, 0X41, 0XA8, + 0X40, 0X98, 0X00, 0XB0, 0X00, 0X60, 0X0C, 0X6B, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0XCE, 0X83, 0X82, 0X88, 0X00, 0XF8, 0XC4, 0XD8, + 0X0C, 0XF3, 0X8A, 0XFA, 0X82, 0XE8, 0X82, 0XB0, 0X45, 0X69, 0XC7, 0X51, 0X08, 0X42, 0X08, 0X3A, + 0X86, 0X5A, 0X83, 0X9B, 0XA2, 0XBC, 0X22, 0XCD, 0X21, 0XCD, 0XA1, 0XC4, 0X22, 0XB4, 0XC4, 0X7A, + 0X06, 0X3A, 0X86, 0X29, 0X45, 0X29, 0X05, 0X31, 0XC4, 0X50, 0X41, 0X90, 0X00, 0XC0, 0X00, 0XA8, + 0X00, 0XA0, 0X00, 0XA8, 0X00, 0X30, 0X4A, 0X4A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X8E, 0X73, 0XC3, 0X18, 0X05, 0X39, 0X82, 0XA8, 0X00, 0XF8, + 0XC3, 0XF8, 0X4D, 0XFB, 0X4D, 0XFB, 0XC7, 0XF9, 0XC3, 0XF0, 0X82, 0XD8, 0XC3, 0XB0, 0X04, 0X81, + 0X45, 0X61, 0X46, 0X51, 0X86, 0X49, 0X86, 0X49, 0X46, 0X41, 0X45, 0X41, 0X45, 0X41, 0X45, 0X41, + 0X05, 0X49, 0X04, 0X61, 0X82, 0X90, 0X41, 0XB0, 0X00, 0XD0, 0X00, 0XC8, 0X00, 0XA8, 0X00, 0XA8, + 0X00, 0XB8, 0X41, 0X58, 0X82, 0X10, 0X82, 0X10, 0XB2, 0X94, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0XCF, 0X7B, 0X82, 0X10, 0X04, 0X21, 0X86, 0X29, 0X86, 0X41, 0X04, 0X99, + 0X40, 0XE8, 0X41, 0XF8, 0X86, 0XF9, 0XCB, 0XFA, 0X49, 0XFA, 0X82, 0XF8, 0X00, 0XF8, 0X00, 0XF0, + 0X00, 0XE8, 0X41, 0XD8, 0X41, 0XD0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC8, + 0X00, 0XD0, 0X00, 0XE0, 0X00, 0XE0, 0X00, 0XD8, 0X00, 0XD0, 0X00, 0XB8, 0X00, 0XA8, 0X41, 0X88, + 0X82, 0X48, 0X82, 0X10, 0X82, 0X10, 0X00, 0X00, 0X45, 0X29, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0XF3, 0X9C, 0X82, 0X10, 0XC3, 0X18, 0X45, 0X29, 0X86, 0X31, 0XC7, 0X31, 0X30, 0X7C, + 0XF3, 0XDC, 0X86, 0XE1, 0X00, 0XF0, 0X00, 0XF8, 0X41, 0XF8, 0X41, 0XF8, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XE8, 0X00, 0XE0, 0X00, 0XE0, 0X00, 0XD8, 0X00, 0XC8, 0X41, 0XA0, 0X8A, 0X9A, 0X0C, 0X63, + 0X04, 0X11, 0X82, 0X10, 0X82, 0X10, 0X41, 0X08, 0X00, 0X00, 0X4D, 0X6B, 0X7D, 0XEF, 0XFF, 0XFF, + 0XFB, 0XDE, 0X08, 0X42, 0X42, 0X10, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X49, 0X4A, 0X38, 0XBE, + 0XFF, 0XFF, 0X38, 0XD6, 0X86, 0XA9, 0X00, 0XC8, 0X00, 0XE0, 0X00, 0XF0, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF0, 0X00, 0XF0, + 0X00, 0XE8, 0X00, 0XE0, 0X00, 0XD0, 0XC3, 0X98, 0X8A, 0X8A, 0XB2, 0XA4, 0XBA, 0XC6, 0XF7, 0XB5, + 0X08, 0X42, 0X41, 0X08, 0X82, 0X10, 0X41, 0X08, 0X00, 0X00, 0X45, 0X29, 0XF7, 0XBD, 0XFF, 0XFF, + 0X71, 0X8C, 0X41, 0X08, 0X04, 0X21, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X0C, 0X63, 0X3C, 0XE7, + 0XFF, 0XFF, 0X79, 0XD6, 0X46, 0XB9, 0X00, 0XE0, 0X42, 0XC8, 0X82, 0XA8, 0X82, 0XB0, 0X41, 0XD8, + 0X82, 0XE8, 0X82, 0XF0, 0X41, 0XE8, 0X41, 0XE8, 0X41, 0XE8, 0X41, 0XF0, 0X41, 0XE8, 0X41, 0XD8, + 0X04, 0XC1, 0X08, 0X92, 0X4D, 0X8B, 0X34, 0XA5, 0XFB, 0XC6, 0XFB, 0XD6, 0XBA, 0XCE, 0X3C, 0XE7, + 0X30, 0X84, 0XC3, 0X18, 0X41, 0X08, 0X41, 0X08, 0X00, 0X00, 0X41, 0X08, 0XCF, 0X7B, 0X7D, 0XEF, + 0X49, 0X4A, 0X00, 0X00, 0X04, 0X21, 0X45, 0X29, 0X46, 0X31, 0X86, 0X31, 0X30, 0X84, 0XFF, 0XFF, + 0XFF, 0XF7, 0XF7, 0XDD, 0X09, 0XDA, 0X83, 0XF8, 0X01, 0XF0, 0X42, 0XC0, 0X82, 0X98, 0X49, 0X9A, + 0XF3, 0XB4, 0XF3, 0XCC, 0X71, 0XBC, 0X8E, 0XBB, 0X8E, 0XBB, 0X30, 0XBC, 0X71, 0XBC, 0XF3, 0XBC, + 0XB6, 0XBD, 0XFB, 0XCE, 0XBE, 0XE7, 0X7D, 0XE7, 0X3B, 0XDF, 0XBA, 0XD6, 0X79, 0XCE, 0XFB, 0XDE, + 0X75, 0XAD, 0X86, 0X31, 0X41, 0X08, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0X49, 0X4A, 0XFB, 0XDE, + 0X04, 0X21, 0X41, 0X08, 0X04, 0X21, 0X45, 0X29, 0X45, 0X29, 0X87, 0X39, 0XB2, 0X94, 0XFF, 0XFF, + 0XBE, 0XF7, 0X34, 0XDD, 0X0C, 0XEB, 0X09, 0XFA, 0X00, 0XF0, 0X01, 0XD8, 0X00, 0XD8, 0X8B, 0XD2, + 0X7D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XFF, 0X7D, 0XEF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, + 0X78, 0XC6, 0XC7, 0X39, 0X00, 0X00, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0XC7, 0X39, 0X79, 0XCE, + 0X00, 0X00, 0X82, 0X10, 0XC3, 0X18, 0X04, 0X21, 0X05, 0X29, 0X86, 0X31, 0XB3, 0X9C, 0XFF, 0XFF, + 0XFF, 0XF7, 0X75, 0XDD, 0XC7, 0XE9, 0XC7, 0XF9, 0X01, 0XF8, 0X01, 0XF0, 0X00, 0XE8, 0X49, 0XE2, + 0XFB, 0XEE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, + 0XB9, 0XCE, 0X08, 0X42, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XC7, 0X39, 0X38, 0XC6, + 0X00, 0X00, 0X82, 0X10, 0X82, 0X10, 0X04, 0X21, 0X04, 0X21, 0X45, 0X29, 0X30, 0X84, 0XFF, 0XFF, + 0XFF, 0XFF, 0X38, 0XDE, 0XC4, 0XD0, 0X00, 0XF0, 0X01, 0XF8, 0X00, 0XF8, 0X00, 0XF0, 0X08, 0XD2, + 0XFB, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XBA, 0XD6, + 0X79, 0XCE, 0XC7, 0X39, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X86, 0X31, 0X38, 0XC6, + 0X00, 0X00, 0X00, 0X00, 0XC3, 0X18, 0XCB, 0X5A, 0X86, 0X31, 0XC3, 0X18, 0XCB, 0X5A, 0X7D, 0XEF, + 0XFF, 0XFF, 0X7D, 0XEF, 0XCF, 0XBB, 0XC3, 0XB0, 0X41, 0XD0, 0X41, 0XD0, 0X82, 0XB8, 0X4D, 0XB3, + 0X7D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0XBE, 0XF7, 0X3D, 0XEF, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XFA, 0XD6, + 0XF7, 0XBD, 0X04, 0X21, 0X86, 0X31, 0X04, 0X21, 0X00, 0X00, 0X00, 0X00, 0X86, 0X31, 0X38, 0XC6, + 0X86, 0X31, 0XC3, 0X18, 0XCB, 0X5A, 0X75, 0XAD, 0XCF, 0X7B, 0X41, 0X08, 0X86, 0X31, 0XF7, 0XBD, + 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XEF, 0X74, 0XB5, 0X30, 0X9C, 0X30, 0X9C, 0X72, 0XA4, 0XBB, 0XD6, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0X3C, 0XE7, + 0X71, 0X8C, 0X81, 0X08, 0X0C, 0X63, 0XCF, 0X7B, 0X82, 0X10, 0X00, 0X00, 0X8A, 0X52, 0X38, 0XC6, + 0X75, 0XAD, 0X71, 0X8C, 0XB6, 0XB5, 0X3C, 0XE7, 0XFB, 0XDE, 0XC7, 0X39, 0X00, 0X00, 0XCF, 0X73, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, + 0X7D, 0XEF, 0X7D, 0XEF, 0X3B, 0XDF, 0XFA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XFB, 0XDE, 0XB9, 0XCE, + 0XC7, 0X39, 0XC4, 0X20, 0X71, 0X8C, 0XBA, 0XD6, 0X71, 0X8C, 0XCB, 0X5A, 0XB2, 0X94, 0XBA, 0XD6, + 0XFF, 0XFF, 0X7D, 0XEF, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XB6, 0XB5, 0X46, 0X29, 0X05, 0X19, + 0X75, 0XA5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, + 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, 0XFC, 0XDE, 0X4E, 0X63, + 0X42, 0X08, 0X0C, 0X63, 0XF7, 0XBD, 0XBE, 0XF7, 0XFF, 0XFF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBE, 0XF7, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF4, 0X9C, 0X04, 0X21, + 0X05, 0X21, 0XB6, 0XA5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, + 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XFB, 0XDE, 0XBB, 0XD6, 0XD1, 0X73, 0X83, 0X18, + 0X86, 0X39, 0X34, 0X9D, 0XBD, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XFF, 0X35, 0XD6, 0XEB, 0XCC, 0X43, 0XB3, + 0X40, 0X51, 0X05, 0X19, 0XF5, 0X8C, 0XBE, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X3C, 0XE7, + 0XFB, 0XDE, 0XBA, 0XDE, 0XBA, 0XD6, 0X3C, 0XDF, 0X3A, 0XBE, 0X4F, 0X63, 0X82, 0X49, 0X40, 0XA3, + 0X23, 0XB4, 0XCC, 0X83, 0X3A, 0XBE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBF, 0XF7, 0XB5, 0XBD, 0X82, 0X92, 0X20, 0XF4, 0XA0, 0XFC, + 0X60, 0XE4, 0X40, 0X82, 0X84, 0X41, 0X8F, 0X6B, 0X77, 0XAD, 0X3D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFE, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, + 0XFB, 0XDE, 0X3D, 0XE7, 0XBB, 0XCE, 0X36, 0X9D, 0X0B, 0X6B, 0X41, 0X6A, 0X60, 0XC4, 0X20, 0XFE, + 0X60, 0XF5, 0X00, 0X8B, 0XC7, 0X6A, 0X38, 0XC6, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X4B, 0X7B, 0X80, 0XB2, 0XA0, 0XFC, 0XA0, 0XFC, + 0XE0, 0XFC, 0XE0, 0XFC, 0XC0, 0XCB, 0XC1, 0X8A, 0X45, 0X62, 0X4D, 0X6B, 0XB3, 0X94, 0XF7, 0XBD, + 0X3D, 0XDF, 0XFF, 0XF7, 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X7D, 0XE7, 0X3D, 0XDF, + 0XBA, 0XC6, 0X75, 0XA5, 0X8D, 0X7B, 0X84, 0X7A, 0X40, 0XB3, 0XE0, 0XEC, 0XE0, 0XFD, 0XE0, 0XFD, + 0X60, 0XF5, 0X20, 0XE5, 0XA0, 0XD4, 0X0A, 0X6B, 0XFB, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0XCC, 0X93, 0X40, 0XEB, 0X60, 0XFC, 0XA0, 0XFC, + 0XE0, 0XFC, 0X20, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XD4, 0XC0, 0XBB, 0X42, 0X9B, 0X45, 0X8B, + 0X6B, 0X9C, 0XAE, 0X9C, 0X71, 0X8C, 0XB3, 0X94, 0X33, 0X9D, 0X34, 0XA5, 0XF2, 0XA4, 0XF0, 0XB4, + 0XCA, 0X9B, 0X04, 0X9B, 0X40, 0XBB, 0X20, 0XE4, 0X20, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XE0, 0XFD, + 0XE0, 0XFD, 0XE0, 0XFD, 0X20, 0XC4, 0X88, 0X5A, 0X38, 0XBE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X78, 0XD6, 0X46, 0XAB, 0X40, 0XDB, 0X20, 0XF4, + 0X60, 0XFC, 0XA0, 0XFC, 0XE0, 0XFC, 0X60, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XDC, + 0XC0, 0XB3, 0XC0, 0X51, 0X86, 0X29, 0X0D, 0X63, 0X8F, 0X7B, 0X0D, 0X5B, 0XC7, 0X41, 0X01, 0X82, + 0X00, 0XC3, 0XC0, 0XE3, 0X60, 0XFC, 0XA0, 0XFC, 0XE0, 0XFC, 0XE0, 0XFC, 0X60, 0XF5, 0X60, 0XF5, + 0X20, 0XE5, 0X80, 0X9B, 0X86, 0X62, 0X30, 0X84, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X38, 0XC6, 0X2D, 0X9C, 0X05, 0X93, + 0X43, 0XA3, 0X82, 0XB3, 0XC2, 0XBB, 0XC2, 0XBB, 0X22, 0XB4, 0X82, 0XA3, 0X42, 0X93, 0XC3, 0X7A, + 0X85, 0X62, 0X0B, 0X63, 0X71, 0X84, 0XB6, 0XB5, 0X79, 0XCE, 0X79, 0XC6, 0XB5, 0XAD, 0X70, 0X94, + 0X4A, 0X8B, 0X06, 0X83, 0X04, 0X93, 0X04, 0X9B, 0X43, 0X9B, 0X43, 0X9B, 0X43, 0X93, 0X04, 0X83, + 0X08, 0X73, 0X8D, 0X73, 0XB3, 0X94, 0X79, 0XCE, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XDF, 0X38, 0XBE, + 0X75, 0XB5, 0X33, 0XA5, 0X33, 0XA5, 0XF3, 0X9C, 0XF3, 0X9C, 0XF3, 0X9C, 0XF3, 0X94, 0XF3, 0X9C, + 0X35, 0XA5, 0XF8, 0XBD, 0XFB, 0XDE, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7E, 0XEF, + 0XBB, 0XD6, 0XF8, 0XBD, 0XB6, 0XAD, 0X75, 0XAD, 0X34, 0XA5, 0X33, 0X9D, 0X34, 0X9D, 0X35, 0XA5, + 0XB7, 0XAD, 0X79, 0XC6, 0X3C, 0XE7, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, +}; + +const unsigned char PROGMEM icon_40x40[3200] = { /* 0X00,0X10,0X28,0X00,0X28,0X00,0X01,0X1B, */ + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5D, 0XEF, 0X71, 0X8C, 0X31, 0X84, 0X31, 0X84, + 0X93, 0XC5, 0X92, 0XCD, 0X91, 0XCD, 0X91, 0XD5, 0X91, 0XD5, 0X91, 0XCD, 0X72, 0XCD, 0X72, 0XC5, + 0X56, 0XDE, 0XBE, 0XFF, 0XDB, 0XDE, 0XFB, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XCE, 0X7B, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X5A, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0XE0, 0XD4, 0XA0, 0XD4, + 0X61, 0XA3, 0XA7, 0X39, 0XE5, 0X18, 0X05, 0X21, 0X92, 0X94, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XF9, 0XEE, 0XEB, 0X9B, 0XA1, 0X18, 0X23, 0X73, 0X81, 0XC5, 0X21, 0X9C, + 0X61, 0X39, 0X81, 0XEE, 0X40, 0XFF, 0XE0, 0XFE, 0XE0, 0XFE, 0XE0, 0XFE, 0X40, 0XFF, 0XC0, 0XF6, + 0XC0, 0X49, 0XA0, 0X18, 0X00, 0X42, 0X60, 0X18, 0X00, 0X00, 0X74, 0XB5, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X93, 0XCD, 0XC3, 0XBB, 0XA0, 0X51, 0XE1, 0X39, 0XC2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0X63, 0XBD, 0X61, 0XE6, 0X40, 0XFF, 0XE0, 0XFE, 0XE0, 0XFE, 0XC0, 0XFE, 0X60, 0XFF, 0X21, 0X73, + 0XE1, 0X28, 0X81, 0XEE, 0X61, 0XFF, 0X21, 0XEE, 0XA0, 0X41, 0X20, 0X08, 0X90, 0XCD, 0XDE, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5C, 0XF7, + 0X0B, 0XAC, 0XC0, 0XB3, 0XA1, 0XEE, 0XC3, 0X5A, 0X22, 0X8C, 0XE1, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0XC0, 0XFF, 0X80, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0X20, 0XFF, 0XA1, 0XAC, + 0X21, 0XC5, 0X20, 0XFF, 0X60, 0XFE, 0X00, 0XFF, 0X02, 0XDE, 0XE0, 0X20, 0X40, 0X82, 0X49, 0XBC, + 0X3B, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5C, 0XF7, 0X67, 0X9B, + 0XE0, 0XB3, 0X81, 0XFF, 0XC3, 0XFF, 0X83, 0X9C, 0X82, 0XDE, 0XC0, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0XE0, 0XFE, 0XA2, 0XB4, 0X41, 0XBC, 0X20, 0XCC, + 0X87, 0XA3, 0XB8, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X9D, 0XF7, 0XA8, 0XA3, 0X60, 0XBC, + 0XA2, 0XFF, 0XA5, 0XFF, 0X44, 0XFF, 0XA1, 0XFF, 0XA0, 0XFF, 0X60, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, + 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X60, 0XFE, 0X20, 0XFE, 0X40, 0XFE, + 0XE0, 0XCB, 0XE3, 0X92, 0X7C, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X4C, 0XAC, 0XC0, 0XB3, 0XA4, 0XFF, + 0XA6, 0XFF, 0X45, 0XFF, 0X62, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X20, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0X00, 0XFE, + 0XE0, 0XFD, 0XE0, 0XC3, 0X2A, 0XAC, 0X7D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XD4, 0XD5, 0X40, 0XAB, 0X43, 0XFF, 0XA8, 0XFF, + 0X67, 0XFF, 0X62, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, + 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0XE0, 0XFD, + 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XA2, 0X11, 0XBD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XDA, 0XE6, 0XE4, 0X9A, 0XE1, 0XE5, 0XE8, 0XFF, 0X69, 0XFF, + 0X65, 0XFF, 0X60, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0X00, 0XFF, 0X20, 0XFF, 0XE0, 0XFE, 0X60, 0XFE, 0X20, 0XFE, 0X00, 0XFE, + 0XC0, 0XFD, 0XE0, 0XFD, 0XE0, 0XE4, 0X85, 0XAB, 0XFA, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X2B, 0XB4, 0XC0, 0XB3, 0XC8, 0XFF, 0X8C, 0XFF, 0X68, 0XFF, + 0X61, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE1, 0XFF, 0XA1, 0XDE, 0X61, 0XEF, + 0XE1, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X60, 0XFF, 0XC0, 0XFF, 0X61, 0XDE, 0X00, 0XE6, 0X80, 0XFE, 0X40, 0XFE, 0X00, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0XE0, 0XFD, 0XC0, 0XC3, 0XE9, 0XAB, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X5D, 0XEF, 0XA3, 0XAB, 0XA3, 0XF6, 0XCC, 0XFF, 0X4C, 0XFF, 0X64, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0X61, 0XEF, 0X22, 0X6B, 0X82, 0X5A, 0X82, 0XB5, + 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0XA0, 0XFF, 0XE1, 0XFF, 0X42, 0X8C, 0XC1, 0X41, 0X21, 0XA4, 0XA0, 0XFE, 0X80, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0X20, 0XF5, 0XC0, 0X9A, 0X35, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X51, 0XC5, 0X60, 0XBC, 0XC9, 0XFF, 0X8E, 0XFF, 0X6A, 0XFF, 0X61, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE1, 0XFF, 0XE1, 0X62, 0X80, 0X10, 0X05, 0XE7, 0XA4, 0XF7, + 0XE4, 0XFF, 0XE3, 0XFF, 0XE2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XC1, 0XFF, 0XE2, 0X83, 0X40, 0X08, 0X22, 0XCE, 0X60, 0XF7, 0XA0, 0XFE, 0X60, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0XA0, 0XFD, 0XA0, 0XC3, 0XAC, 0XBC, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XDE, 0XFF, 0XA7, 0XAB, 0X81, 0XDD, 0XED, 0XFF, 0XB0, 0XFF, 0X69, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0X61, 0XD6, 0X22, 0X29, 0XA6, 0X31, 0XE3, 0X7B, 0X46, 0XEF, + 0XE6, 0XFF, 0XE4, 0XFF, 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X81, 0XD6, 0XA0, 0X18, 0XC4, 0X18, 0XA1, 0X62, 0XC1, 0XCD, 0X40, 0XFF, 0X60, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0XA0, 0XEC, 0X48, 0XBC, 0XDF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XF9, 0XE6, 0XE3, 0X9A, 0X67, 0XEE, 0XD1, 0XFF, 0XB0, 0XFF, 0X86, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0X60, 0X94, 0X91, 0X73, 0XD9, 0XBD, 0X00, 0X00, 0X05, 0X84, + 0XE8, 0XFF, 0XE5, 0XFF, 0XE3, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X20, 0XAD, 0XE9, 0X41, 0XB7, 0XB5, 0X01, 0X00, 0X60, 0X62, 0X21, 0XFF, 0X80, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XE3, 0XBB, 0XD9, 0XE6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XD3, 0XCD, 0X40, 0XA3, 0X2B, 0XF7, 0XD3, 0XFF, 0XB0, 0XFF, 0X63, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA0, 0X9C, 0X30, 0X6B, 0X97, 0XB5, 0X00, 0X00, 0X83, 0X52, + 0XC6, 0XFF, 0XE5, 0XFF, 0XE3, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X20, 0XAD, 0XEA, 0X41, 0X77, 0XAD, 0X01, 0X00, 0XC0, 0X49, 0XE0, 0XF6, 0XA0, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0XA0, 0XBB, 0XD3, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X00, 0XB4, 0X8E, 0XFF, 0XF4, 0XFF, 0XB0, 0XFF, 0X42, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA1, 0XDE, 0X01, 0X21, 0X00, 0X00, 0X00, 0X00, 0X25, 0X8C, + 0XE5, 0XFF, 0XE3, 0XFF, 0XE2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0XE1, 0XDE, 0X01, 0X21, 0X00, 0X00, 0X00, 0X00, 0X61, 0X5A, 0X20, 0XFF, 0X80, 0XFE, 0X20, 0XFE, + 0X00, 0XFE, 0XE0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XC0, 0XCB, 0X71, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X40, 0XC4, 0XB0, 0XFF, 0XF5, 0XFF, 0X8F, 0XFF, 0X41, 0XFF, 0X80, 0XFF, + 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE1, 0XFF, 0X21, 0X8C, 0X60, 0X10, 0X43, 0X6B, 0X44, 0XEF, + 0XE2, 0XFF, 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0XE1, 0XFF, 0XC1, 0XA4, 0XC2, 0X18, 0XA2, 0X39, 0XA1, 0XCD, 0X20, 0XFF, 0X60, 0XFE, 0X20, 0XFE, + 0XC0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XE0, 0XCB, 0X91, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X40, 0XC4, 0XD2, 0XFF, 0XF7, 0XFF, 0XAF, 0XFF, 0X01, 0XFF, 0X00, 0XFF, + 0X00, 0XFF, 0X40, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA1, 0XFF, 0X82, 0XD6, 0XC2, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0XC1, 0XFF, 0X82, 0XDE, 0XC2, 0XEE, 0X61, 0XFF, 0X80, 0XFE, 0XC0, 0XFD, 0X20, 0XFD, + 0XA1, 0XFC, 0X61, 0XFC, 0X61, 0XFC, 0XC0, 0XFC, 0X60, 0XFD, 0XE0, 0XCB, 0X51, 0XC5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X60, 0XC4, 0XD4, 0XFF, 0XF9, 0XFF, 0X2D, 0XFF, 0X00, 0XFE, 0XC0, 0XFD, + 0XA1, 0XFD, 0X21, 0XFE, 0XE0, 0XFE, 0XC0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X40, 0XFF, 0X80, 0XFF, 0X20, 0XFF, 0XA0, 0XFE, 0X20, 0XFE, 0X01, 0XFD, 0X01, 0XFC, + 0X62, 0XFB, 0X42, 0XFB, 0X82, 0XFB, 0X21, 0XFC, 0X20, 0XFD, 0X00, 0XD4, 0X71, 0XC5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X20, 0XC4, 0XD4, 0XFF, 0XBA, 0XFF, 0X2E, 0XFE, 0XE1, 0XFC, 0X61, 0XFC, + 0X61, 0XFC, 0X01, 0XFD, 0X01, 0XFE, 0X20, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, + 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X80, 0XFD, 0X61, 0XFC, 0X62, 0XFB, + 0XA3, 0XFA, 0XA3, 0XFA, 0X42, 0XFB, 0X01, 0XFC, 0XE0, 0XFC, 0XE0, 0XCB, 0X71, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0XC0, 0XB3, 0XB3, 0XFF, 0X7A, 0XFF, 0X91, 0XFD, 0X03, 0XFC, 0X02, 0XFB, + 0X22, 0XFB, 0X62, 0XFC, 0X81, 0XFD, 0XC0, 0XFE, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X20, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0XA0, 0XFE, 0X60, 0XFE, 0X60, 0XFD, 0X41, 0XFC, 0X62, 0XFB, + 0XC3, 0XFA, 0XA3, 0XFA, 0X42, 0XFB, 0X01, 0XFC, 0X20, 0XFD, 0XC0, 0XCB, 0X91, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X14, 0XD6, 0X20, 0XAB, 0X51, 0XF7, 0XBE, 0XFF, 0X17, 0XFE, 0X65, 0XFC, 0X61, 0XFB, + 0XA2, 0XFB, 0XA1, 0XFC, 0XC1, 0XFD, 0X00, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X20, 0XFF, + 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0XC0, 0XFD, 0XC0, 0XFC, 0X41, 0XFC, + 0XC1, 0XFB, 0XA2, 0XFB, 0X01, 0XFC, 0XA0, 0XFC, 0X40, 0XFD, 0XA0, 0XC3, 0XF4, 0XD5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X5B, 0XEF, 0X24, 0X9B, 0X49, 0XE6, 0XB8, 0XFF, 0X92, 0XFE, 0X25, 0XFD, 0XA0, 0XFC, + 0X02, 0XFD, 0XE1, 0XFD, 0XE0, 0XFE, 0X40, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X00, 0XFF, + 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X40, 0XFE, 0X00, 0XFE, 0X80, 0XFD, 0X01, 0XF5, + 0X41, 0XFD, 0X01, 0XFD, 0XC0, 0XFC, 0X40, 0XFD, 0X00, 0XF5, 0XC4, 0XBB, 0XFA, 0XE6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X2A, 0XB4, 0XA0, 0XD4, 0XA2, 0XFE, 0X20, 0XFE, 0XE0, 0XFD, 0X00, 0XFE, + 0X80, 0XFE, 0X21, 0XEE, 0X41, 0XE6, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, + 0XA0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X00, 0XFE, 0X00, 0XFE, 0X00, 0XFE, 0X40, 0XCC, + 0XE1, 0XAB, 0XC1, 0XED, 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XE4, 0X29, 0XB4, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X15, 0XD6, 0XE0, 0XBB, 0X60, 0XFE, 0XC8, 0XFE, 0XC8, 0XFE, 0X02, 0XFF, + 0X60, 0XDD, 0X40, 0XA3, 0XA1, 0XDD, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, + 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0XC0, 0XFE, 0XA0, 0XFE, + 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X40, 0XED, + 0XC0, 0X9A, 0X40, 0XA3, 0X80, 0XF5, 0X60, 0XFD, 0X60, 0XBB, 0XEE, 0XBC, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XDF, 0XFF, 0X63, 0XAB, 0X42, 0XE5, 0XB4, 0XFF, 0X97, 0XFF, 0XAA, 0XF6, + 0X80, 0XAB, 0XA0, 0X92, 0XA1, 0XDD, 0X41, 0XFF, 0X40, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, + 0XC0, 0XFE, 0X80, 0XFE, 0X61, 0XFE, 0X00, 0XFE, 0XA0, 0XED, 0X20, 0XE5, 0X21, 0XCC, 0X80, 0XB3, + 0X00, 0XBC, 0XE0, 0XC3, 0X40, 0XED, 0XC0, 0XEC, 0X60, 0X92, 0X97, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X0F, 0XC5, 0X00, 0XA3, 0XAA, 0XF6, 0X93, 0XFF, 0X2D, 0XEE, + 0X63, 0XDD, 0X80, 0XD5, 0X42, 0XB4, 0X82, 0XCC, 0X00, 0XCD, 0X40, 0XD5, 0XA0, 0XDD, 0XE1, 0XE5, + 0XC1, 0XE5, 0XC1, 0XE5, 0XC1, 0XE5, 0XC1, 0XE5, 0X80, 0XDD, 0X60, 0XDD, 0X20, 0XD5, 0XC0, 0XCC, + 0XA0, 0XCC, 0X61, 0XC4, 0X21, 0XC4, 0X01, 0XBC, 0X01, 0XBC, 0XE0, 0XBB, 0XC0, 0XBB, 0X60, 0XD4, + 0X80, 0XFD, 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XBB, 0X2B, 0XAC, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X9D, 0XF7, 0X87, 0XA3, 0X60, 0XD4, 0X0A, 0XFF, 0XCF, 0XFE, + 0XC9, 0XFE, 0XC0, 0XFE, 0XC0, 0XF6, 0X40, 0XE6, 0X41, 0XCD, 0X42, 0XB4, 0XC1, 0XAB, 0X60, 0XA3, + 0X60, 0XA3, 0X80, 0XA3, 0X80, 0XA3, 0X80, 0XA3, 0XA0, 0XAB, 0XC1, 0XAB, 0XE1, 0XB3, 0X22, 0XB4, + 0X82, 0XC4, 0XC0, 0XCC, 0X00, 0XD5, 0X60, 0XE5, 0X81, 0XED, 0X80, 0XF5, 0X80, 0XFD, 0X80, 0XFD, + 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XE4, 0X85, 0XAB, 0X5C, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFA, 0XE6, 0X23, 0XA3, 0XE0, 0XE4, 0XE8, 0XFE, + 0X6A, 0XFE, 0X05, 0XFE, 0X40, 0XFE, 0XA0, 0XFE, 0XC0, 0XFE, 0XE1, 0XFE, 0XA0, 0XF6, 0XA0, 0XF6, + 0XA0, 0XF6, 0XA0, 0XF6, 0X80, 0XF6, 0X80, 0XF6, 0X80, 0XF6, 0X60, 0XF6, 0X61, 0XFE, 0X81, 0XFE, + 0X61, 0XFE, 0X20, 0XFE, 0X00, 0XFE, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X20, 0XFD, 0X20, 0XFD, + 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XA2, 0XB4, 0XCD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X52, 0XC5, 0XE0, 0XA2, 0XA1, 0XF5, + 0X86, 0XFE, 0X06, 0XFE, 0XE2, 0XFD, 0XE0, 0XFD, 0X00, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, + 0X40, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X00, 0XFE, 0XE0, 0XFD, 0XE0, 0XFD, 0XC0, 0XFD, + 0XA0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X40, 0XFD, + 0X60, 0XFD, 0X60, 0XBB, 0X6C, 0XB4, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X92, 0XCD, 0XC0, 0XA2, + 0X20, 0XED, 0X22, 0XFE, 0XC1, 0XFD, 0XA0, 0XFD, 0XC0, 0XFD, 0XE0, 0XFD, 0XE0, 0XFD, 0XE0, 0XFD, + 0XE0, 0XFD, 0XE0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0X80, 0XFD, + 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0X40, 0XFD, + 0X20, 0XB3, 0XEA, 0XA3, 0X9D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X8E, 0XBC, + 0XE1, 0XA2, 0X00, 0XE5, 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, + 0XC0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0X60, 0XFD, + 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X80, 0XFD, 0X00, 0XF5, 0X40, 0XBB, + 0X2B, 0XAC, 0X9D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X35, 0XD6, 0XE2, 0X9A, 0XA0, 0XC3, 0XA0, 0XFD, 0XE0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X80, 0XFD, + 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XFD, + 0X20, 0XFD, 0X20, 0XFD, 0X40, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X00, 0XD4, 0XC1, 0X9A, 0X10, 0XC5, + 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X98, 0XDE, 0X2B, 0XAC, 0X40, 0XB3, 0X00, 0XD4, 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XFD, + 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, + 0X40, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XDC, 0X80, 0XBB, 0XE8, 0XAB, 0X57, 0XDE, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XDF, 0XFF, 0X37, 0XD6, 0X86, 0XA3, 0XC0, 0X9A, 0XE0, 0XCB, 0X80, 0XEC, + 0XE0, 0XF4, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X00, 0XF5, + 0XA0, 0XEC, 0X00, 0XD4, 0X40, 0XB3, 0X03, 0X9B, 0X92, 0XC5, 0XBD, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XF5, 0XCD, 0XAD, 0XBC, 0X69, 0XBC, + 0X05, 0XBC, 0X03, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0XE2, 0XC3, 0X24, 0XC4, + 0X68, 0XBC, 0XAC, 0XBC, 0XD3, 0XCD, 0X9E, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X5B, 0XEF, 0X98, 0XDE, 0X56, 0XD6, 0X57, 0XD6, 0X57, 0XD6, 0X56, 0XD6, 0X77, 0XDE, 0X1B, 0XEF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, +}; + diff --git a/examples/graphictest_slim/graphictest_slim.ino b/examples/graphictest_slim/graphictest_slim.ino new file mode 100644 index 0000000..e552137 --- /dev/null +++ b/examples/graphictest_slim/graphictest_slim.ino @@ -0,0 +1,21 @@ +#include // f.k. for Arduino-1.5.2 +#include "Adafruit_GFX.h"// Hardware-specific library +#include + +/* + * an empty Leonardo sketch uses 3.5kB + 4kB bootloader + * + * this C++ program avoids Serial and f-p. + * so it just fits in the Flash. + * + * This is a complete dummy sketch. + * its only purpose is to tell the IDE which libraries to use + * + * The actual program is in the graphictest_v25.cpp + * + * This enables me to build an identical AS7 project + * + * Edit the HOW_SLIM macro to build for other chips + * + */ + diff --git a/examples/graphictest_slim/graphictest_v25.cpp b/examples/graphictest_slim/graphictest_v25.cpp new file mode 100644 index 0000000..b2bf3f7 --- /dev/null +++ b/examples/graphictest_slim/graphictest_v25.cpp @@ -0,0 +1,552 @@ +#if defined(__AVR_ATmega32U4__) //Leonardo +#define HOW_SLIM 3 +#else +#define HOW_SLIM 0 //no slimming measures +#endif + +// All the mcufriend.com UNO shields have the same pinout. +// i.e. control pins A0-A4. Data D2-D9. microSD D10-D13. +// Touchscreens are normally A1, A2, D7, D6 but the order varies +// +// This demo should work with most Adafruit TFT libraries +// If you are not using a shield, use a full Adafruit constructor() +// e.g. Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); + +#define LCD_CS A3 // Chip Select goes to Analog 3 +#define LCD_CD A2 // Command/Data goes to Analog 2 +#define LCD_WR A1 // LCD Write goes to Analog 1 +#define LCD_RD A0 // LCD Read goes to Analog 0 +#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin + +#if ARDUINO < 165 +#define USE_GFX_KBV +#include "ADA_GFX_kbv.h" +#else +#include "Adafruit_GFX.h" +#endif +#include +MCUFRIEND_kbv tft; +//#include +//Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); + +// Assign human-readable names to some common 16-bit color values: +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +void setup(void); +void loop(void); +unsigned long testFillScreen(); +unsigned long testText(); +unsigned long testLines(uint16_t color); +unsigned long testFastLines(uint16_t color1, uint16_t color2); +unsigned long testRects(uint16_t color); +unsigned long testFilledRects(uint16_t color1, uint16_t color2); +unsigned long testFilledCircles(uint8_t radius, uint16_t color); +unsigned long testCircles(uint8_t radius, uint16_t color); +unsigned long testTriangles(); +unsigned long testFilledTriangles(); +unsigned long testRoundRects(); +unsigned long testFilledRoundRects(); +void progmemPrint(const char *str); +void progmemPrintln(const char *str); + +void runtests(void); + +uint16_t g_identifier; + +void setup(void) { +#if HOW_SLIM < 1 + Serial.begin(9600); + uint32_t when = millis(); + // while (!Serial) ; //hangs a Leonardo until you connect a Serial + if (!Serial) delay(5000); //allow some time for Leonardo + Serial.println("Serial took " + String((millis() - when)) + "ms to start"); +#endif + static uint16_t identifier; + tft.reset(); //we can't read ID on 9341 until begin() + g_identifier = tft.readID(); // +#if HOW_SLIM < 1 + Serial.print("ID = 0x"); + Serial.println(g_identifier, HEX); +#endif + if (g_identifier == 0x00D3) g_identifier = 0x9481; // write-only shield + if (g_identifier == 0xFFFF) g_identifier = 0x9341; // serial + // g_identifier = 0x7789; // force ID + tft.begin(g_identifier); +} + +#if defined(MCUFRIEND_KBV_H_) +uint16_t scrollbuf[480]; // my biggest screen is 320x480 +#define READGRAM(x, y, buf, w, h) tft.readGRAM(x, y, buf, w, h) +#else +uint16_t scrollbuf[320]; // Adafruit only does 240x320 +// Adafruit can read a block by one pixel at a time +int16_t READGRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h) +{ + uint16_t *p; + for (int row = 0; row < h; row++) { + p = block + row * w; + for (int col = 0; col < w; col++) { + *p++ = tft.readPixel(x + col, y + row); + } + } +} +#endif + +void windowScroll(int16_t x, int16_t y, int16_t wid, int16_t ht, int16_t dx, int16_t dy, uint16_t *buf) +{ + if (dx) for (int16_t row = 0; row < ht; row++) { + READGRAM(x, y + row, buf, wid, 1); + tft.setAddrWindow(x, y + row, x + wid - 1, y + row); + tft.pushColors(buf + dx, wid - dx, 1); + tft.pushColors(buf + 0, dx, 0); + } + if (dy) for (int16_t col = 0; col < wid; col++) { + READGRAM(x + col, y, buf, 1, ht); + tft.setAddrWindow(x + col, y, x + col, y + ht - 1); + tft.pushColors(buf + dy, ht - dy, 1); + tft.pushColors(buf + 0, dy, 0); + } +} + +void loop(void) { + uint8_t aspect; + uint16_t pixel; + char *aspectname[] = { + "PORTRAIT", "LANDSCAPE", "PORTRAIT_REV", "LANDSCAPE_REV" + }; + char *colorname[] = { "BLUE", "GREEN", "RED", "GRAY" }; + uint16_t colormask[] = { 0x001F, 0x07E0, 0xF800, 0xFFFF }; + uint16_t dx, rgb, n, wid, ht; + tft.setRotation(1); + runtests(); + delay(2000); + if (tft.height() > 64) { + for (uint8_t cnt = 0; cnt < 4; cnt++) { + aspect = (cnt + 0) & 3; + tft.setRotation(aspect); + wid = tft.width(); + ht = tft.height(); + testText(); + dx = wid / 32; + for (n = 0; n < 32; n++) { + rgb = n * 8; + rgb = tft.color565(rgb, rgb, rgb); + tft.fillRect(n * dx, 48, dx, 64, rgb & colormask[aspect]); + } + tft.setTextSize(2); + tft.setTextColor(colormask[aspect], BLACK); + tft.setCursor(0, 72); + tft.print(colorname[aspect]); + tft.setTextColor(WHITE); + tft.println(" COLOR GRADES"); + tft.setTextColor(WHITE, BLACK); + tft.setCursor(0, 184); + tft.println(aspectname[aspect]); + delay(1000); + tft.drawPixel(0, 0, YELLOW); + pixel = tft.readPixel(0, 0); +#if defined(MCUFRIEND_KBV_H_) +#if HOW_SLIM < 3 + extern const uint8_t penguin[]; + tft.setAddrWindow(wid - 40 - 40, 20 + 0, wid - 1 - 40, 20 + 39); + tft.pushColors(penguin, 1600, 1); +#endif + tft.setTextColor(WHITE, BLACK); + tft.println("VERTICAL SCROLL UP"); + uint16_t maxscroll; + if (tft.getRotation() & 1) maxscroll = wid; + else maxscroll = ht; + for (uint16_t i = 1; i <= maxscroll; i++) { + tft.vertScroll(0, maxscroll, i); + delay(10); + } + tft.vertScroll(0, maxscroll, 0); + tft.setCursor(0, 200); + tft.println("VERTICAL SCROLL DN"); + for (uint16_t i = 1; i <= maxscroll; i++) { + tft.vertScroll(0, maxscroll, 0 - (int16_t)i); + delay(10); + } + delay(1000); + tft.vertScroll(0, maxscroll, 0); + if ((aspect & 1) == 0) { //Portrait + tft.setCursor(0, 200); + tft.setTextColor(BLUE, BLACK); + tft.println("ONLY THE COLOR BAND"); + for (uint16_t i = 0; i < 64; i++) { + tft.vertScroll(48, 64, i + 1); + delay(20); + } + delay(1000); + tft.vertScroll(0, maxscroll, 0); + } +#endif + tft.setCursor(0, 200); + tft.setTextColor(YELLOW, BLACK); + if (pixel == YELLOW) { + tft.println("SOFTWARE SCROLL "); +#if 1 + for (int16_t i = 45, dx = 2, dy = 1; i > 0; i -= dx) { + windowScroll(24, 8, 90, 40, dx, dy, scrollbuf); + } +#else + // scroll a whole width of the screen + for (int16_t i = wid, dx = 4, dy = 0; i > 0; i -= dx) { + windowScroll(0, 200, wid, 16, dx, dy, scrollbuf); + } +#endif + } + else if (pixel == CYAN) + tft.println("readPixel() reads as BGR"); + else if (pixel == 0xFFFF) + tft.println("readPixel() should be 24-bit"); + else { + tft.print("readPixel() reads 0x"); + tft.println(pixel, HEX); + } + delay(5000); + } + } + tft.println("INVERT DISPLAY"); + tft.invertDisplay(true); + delay(2000); + tft.invertDisplay(false); +} + +typedef struct { + PGM_P msg; + uint32_t ms; +} TEST; +TEST result[12]; + +#define RUNTEST(n, str, test) { result[n].msg = PSTR(str); result[n].ms = test; delay(500); } + +void runtests(void) +{ + uint8_t i; + uint32_t total; + RUNTEST(0, "FillScreen ", testFillScreen()); + RUNTEST(1, "Text ", testText()); + RUNTEST(2, "Lines ", testLines(CYAN)); + RUNTEST(3, "Horiz/Vert Lines ", testFastLines(RED, BLUE)); + RUNTEST(4, "Rectangles (outline) ", testRects(GREEN)); + RUNTEST(5, "Rectangles (filled) ", testFilledRects(YELLOW, MAGENTA)); + RUNTEST(6, "Circles (filled) ", testFilledCircles(10, MAGENTA)); + RUNTEST(7, "Circles (outline) ", testCircles(10, WHITE)); + RUNTEST(8, "Triangles (outline) ", testTriangles()); + RUNTEST(9, "Triangles (filled) ", testFilledTriangles()); + RUNTEST(10, "Rounded rects (outline) ", testRoundRects()); + RUNTEST(11, "Rounded rects (filled) ", testFilledRoundRects()); + + tft.setRotation(1); + tft.fillScreen(BLACK); + tft.setCursor(0, 0); + tft.setTextSize(2); + tft.println("MCUFRIEND for UNO"); + + tft.setTextSize(1); + total = 0; + for (i = 0; i < 12; i++) { + PGM_P str = result[i].msg; + char c; + if (i < 10) tft.print(" "); + tft.print(i); + tft.print(": "); + while (c = pgm_read_byte(str++)) tft.print(c); + tft.println(result[i].ms); + total += result[i].ms; + } + tft.setTextSize(2); + tft.print("Total:"); +#if HOW_SLIM < 2 + tft.print(0.000001 * total); + tft.println("sec"); +#else + tft.print(total / 1000, DEC); + tft.println(" ms"); +#endif + g_identifier = tft.readID(); + tft.print("ID: 0x"); + tft.println(tft.readID(), HEX); + tft.print("Reg(00):0x"); + tft.println(tft.readReg(0x00), HEX); + tft.print("F_CPU:"); +#if HOW_SLIM < 2 + tft.print(0.000001 * F_CPU); +#else + tft.print((int)(F_CPU/1000000)); +#endif +#if defined(__OPTIMIZE_SIZE__) + tft.println("MHz -Os"); +#else + tft.println("MHz"); +#endif + + delay(10000); +} + +// Standard Adafruit tests. will adjust to screen size + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(BLACK); + tft.fillScreen(RED); + tft.fillScreen(GREEN); + tft.fillScreen(BLUE); + tft.fillScreen(BLACK); + return micros() - start; +} + +unsigned long testText() { + unsigned long start; + tft.fillScreen(BLACK); + start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(WHITE); tft.setTextSize(1); + tft.println("Hello World!"); + tft.setTextColor(YELLOW); tft.setTextSize(2); +#if HOW_SLIM < 2 + tft.println(123.45); +#else + tft.println("456.78"); +#endif + tft.setTextColor(RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(GREEN); + tft.setTextSize(5); + tft.println("Groop"); + tft.setTextSize(2); + tft.println("I implore thee,"); + tft.setTextSize(1); + tft.println("my foonting turlingdromes."); + tft.println("And hooptiously drangle me"); + tft.println("with crinkly bindlewurdles,"); + tft.println("Or I will rend thee"); + tft.println("in the gobberwarts"); + tft.println("with my blurglecruncheon,"); + tft.println("see if I don't!"); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(BLACK); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = w - 1; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t = micros() - start; // fillScreen doesn't count against timing + + tft.fillScreen(BLACK); + + x1 = w - 1; + y1 = 0; + y2 = h - 1; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = 0; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t += micros() - start; + + tft.fillScreen(BLACK); + + x1 = 0; + y1 = h - 1; + y2 = 0; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = w - 1; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + t += micros() - start; + + tft.fillScreen(BLACK); + + x1 = w - 1; + y1 = h - 1; + y2 = 0; + start = micros(); + for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); + x2 = 0; + for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); + + return micros() - start; +} + +unsigned long testFastLines(uint16_t color1, uint16_t color2) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(); + + tft.fillScreen(BLACK); + start = micros(); + for (y = 0; y < h; y += 5) tft.drawFastHLine(0, y, w, color1); + for (x = 0; x < w; x += 5) tft.drawFastVLine(x, 0, h, color2); + + return micros() - start; +} + +unsigned long testRects(uint16_t color) { + unsigned long start; + int n, i, i2, + cx = tft.width() / 2, + cy = tft.height() / 2; + + tft.fillScreen(BLACK); + n = min(tft.width(), tft.height()); + start = micros(); + for (i = 2; i < n; i += 6) { + i2 = i / 2; + tft.drawRect(cx - i2, cy - i2, i, i, color); + } + + return micros() - start; +} + +unsigned long testFilledRects(uint16_t color1, uint16_t color2) { + unsigned long start, t = 0; + int n, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + n = min(tft.width(), tft.height()); + for (i = n; i > 0; i -= 6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx - i2, cy - i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx - i2, cy - i2, i, i, color2); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(BLACK); + start = micros(); + for (x = radius; x < w; x += r2) { + for (y = radius; y < h; y += r2) { + tft.fillCircle(x, y, radius, color); + } + } + + return micros() - start; +} + +unsigned long testCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, r2 = radius * 2, + w = tft.width() + radius, + h = tft.height() + radius; + + // Screen is not cleared for this one -- this is + // intentional and does not affect the reported time. + start = micros(); + for (x = 0; x < w; x += r2) { + for (y = 0; y < h; y += r2) { + tft.drawCircle(x, y, radius, color); + } + } + + return micros() - start; +} + +unsigned long testTriangles() { + unsigned long start; + int n, i, cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + n = min(cx, cy); + start = micros(); + for (i = 0; i < n; i += 5) { + tft.drawTriangle( + cx , cy - i, // peak + cx - i, cy + i, // bottom left + cx + i, cy + i, // bottom right + tft.color565(0, 0, i)); + } + + return micros() - start; +} + +unsigned long testFilledTriangles() { + unsigned long start, t = 0; + int i, cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + start = micros(); + for (i = min(cx, cy); i > 10; i -= 5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i, i)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i, i, 0)); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, red, step, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + red = 0; + step = (256 * 6) / w; + for (i = 0; i < w; i += 6) { + i2 = i / 2; + red += step; + tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(red, 0, 0)); + } + + return micros() - start; +} + +unsigned long testFilledRoundRects() { + unsigned long start; + int i, i2, green, step, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(BLACK); + start = micros(); + green = 256; + step = (256 * 6) / min(tft.width(), tft.height()); + for (i = min(tft.width(), tft.height()); i > 20; i -= 6) { + i2 = i / 2; + green -= step; + tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, green, 0)); + } + + return micros() - start; +} + diff --git a/examples/graphictest_slim/icons.c b/examples/graphictest_slim/icons.c new file mode 100644 index 0000000..97edda8 --- /dev/null +++ b/examples/graphictest_slim/icons.c @@ -0,0 +1,408 @@ +#include + +const unsigned char PROGMEM penguin[3200] = { /* 0X00,0X10,0X28,0X00,0X28,0X00,0X01,0X1B, */ + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, + 0XBA, 0XD6, 0XB6, 0XB5, 0XF3, 0X9C, 0XB2, 0X94, 0XB3, 0X9C, 0XB2, 0X94, 0X34, 0XA5, 0XF7, 0XBD, + 0XFB, 0XDE, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XFB, 0XDE, 0XF3, 0X9C, 0XCB, 0X5A, + 0XC7, 0X39, 0X04, 0X21, 0X82, 0X10, 0X42, 0X10, 0X42, 0X10, 0X41, 0X08, 0X83, 0X18, 0X45, 0X29, + 0XC7, 0X39, 0X0C, 0X63, 0X75, 0XAD, 0X3C, 0XE7, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0XB2, 0X94, 0X08, 0X42, 0XC3, 0X18, 0X82, 0X10, + 0X04, 0X21, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X86, 0X31, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X82, 0X10, 0X41, 0X08, 0XC3, 0X18, 0X08, 0X42, 0XF3, 0X9C, 0X3C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XDE, 0X0C, 0X63, 0XC3, 0X18, 0XC3, 0X18, 0X45, 0X29, 0XC7, 0X39, + 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0X08, 0X42, 0XC7, 0X39, 0XC7, 0X39, + 0X86, 0X31, 0X86, 0X31, 0X04, 0X21, 0X41, 0X08, 0X82, 0X10, 0XCB, 0X5A, 0XBA, 0XD6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFB, 0XDE, 0XCB, 0X5A, 0X82, 0X10, 0X45, 0X29, 0XC7, 0X39, 0X08, 0X42, 0X08, 0X42, + 0X09, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X49, 0X4A, 0X08, 0X42, 0XC7, 0X39, + 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X83, 0X18, 0X00, 0X00, 0XC8, 0X41, 0X38, 0XC6, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X7D, 0XEF, 0X8E, 0X73, 0X82, 0X10, 0X45, 0X29, 0XC7, 0X39, 0X08, 0X42, 0X09, 0X4A, 0X8A, 0X52, + 0X30, 0X84, 0XCF, 0X7B, 0X8A, 0X52, 0X49, 0X4A, 0X4A, 0X52, 0X49, 0X4A, 0XCB, 0X5A, 0XCF, 0X7B, + 0X0C, 0X63, 0X08, 0X42, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, 0X00, 0X00, 0X49, 0X4A, + 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XF3, 0X9C, 0XC3, 0X18, 0X04, 0X21, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X72, 0X94, + 0X7D, 0XEF, 0X7D, 0XEF, 0XB2, 0X94, 0X4A, 0X52, 0X49, 0X4A, 0X8A, 0X52, 0X75, 0XAD, 0XBE, 0XF7, + 0XBA, 0XD6, 0X4D, 0X6B, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, 0X41, 0X08, + 0XCF, 0X7B, 0X7C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBA, 0XD6, + 0X08, 0X42, 0X82, 0X10, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8E, 0X73, 0XFB, 0XDE, + 0XFF, 0XFF, 0XBE, 0XF7, 0XBA, 0XD6, 0X8E, 0X73, 0X08, 0X42, 0X30, 0X84, 0X3C, 0XE7, 0X7D, 0XEF, + 0XFF, 0XFF, 0XB6, 0XB5, 0X49, 0X4A, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, 0X41, 0X08, + 0X45, 0X29, 0XB6, 0XB5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0X71, 0X8C, + 0X41, 0X08, 0X45, 0X29, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X52, 0XB2, 0X94, 0XBE, 0XF7, + 0XBE, 0XF7, 0XB2, 0X94, 0XCF, 0X7B, 0XCF, 0X7B, 0X49, 0X4A, 0XB6, 0XB5, 0XF3, 0X9C, 0X0C, 0X63, + 0X38, 0XC6, 0XBA, 0XD6, 0X0C, 0X63, 0X87, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0XC3, 0X18, + 0X41, 0X08, 0X30, 0X84, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0XCB, 0X5A, + 0X41, 0X08, 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X4A, 0X52, 0X8A, 0X52, 0XF3, 0X9C, 0XFF, 0XFF, + 0X7D, 0XEF, 0XC7, 0X39, 0XC3, 0X18, 0X0C, 0X63, 0XCB, 0X5A, 0XB6, 0XB5, 0XB2, 0X94, 0XCB, 0X5A, + 0X75, 0XAD, 0XFA, 0XD6, 0X4D, 0X6B, 0X87, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X41, 0X08, 0X8A, 0X52, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X38, 0XC6, 0X86, 0X31, + 0X04, 0X21, 0XC8, 0X41, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X52, 0X49, 0X4A, 0XB1, 0X8C, 0XBE, 0XF7, + 0XBE, 0XF7, 0XB2, 0X94, 0XCF, 0X7B, 0XCF, 0X7B, 0X49, 0X4A, 0X74, 0XA5, 0X7D, 0XEF, 0X7C, 0XE7, + 0XBE, 0XF7, 0X79, 0XCE, 0X0C, 0X63, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X04, 0X21, + 0X82, 0X10, 0X45, 0X29, 0X75, 0XAD, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X34, 0XA5, 0X82, 0X10, + 0X86, 0X31, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8A, 0X52, 0X49, 0X4A, 0X4D, 0X6B, 0XBA, 0XD6, + 0XFF, 0XFF, 0XFF, 0XFF, 0X79, 0XCE, 0X0D, 0X63, 0XC7, 0X39, 0XCF, 0X7B, 0X7D, 0XEF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X75, 0XAD, 0X08, 0X42, 0X86, 0X31, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0XC3, 0X18, 0XC3, 0X18, 0XB2, 0X94, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XB2, 0X8C, 0X41, 0X08, + 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X8A, 0X52, 0X8A, 0X52, 0X4A, 0X4A, 0XD0, 0X7B, + 0X7A, 0XC6, 0X7B, 0XBE, 0X90, 0X6B, 0XC9, 0X39, 0X88, 0X31, 0XC9, 0X39, 0XB3, 0X84, 0XBB, 0XC6, + 0XF8, 0XB5, 0XCC, 0X5A, 0X86, 0X31, 0XC7, 0X39, 0XC7, 0X39, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0XC4, 0X20, 0X41, 0X08, 0X30, 0X84, 0X3C, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XE7, 0X8A, 0X4A, 0XC3, 0X10, + 0XC7, 0X39, 0X08, 0X42, 0X49, 0X4A, 0X49, 0X4A, 0X4A, 0X4A, 0X4A, 0X42, 0X09, 0X3A, 0X08, 0X4A, + 0X09, 0X6B, 0X49, 0X7B, 0XC6, 0X7A, 0X05, 0X83, 0X46, 0X83, 0XC5, 0X7A, 0XC6, 0X72, 0X09, 0X7B, + 0X48, 0X5A, 0X87, 0X31, 0X88, 0X21, 0X88, 0X29, 0X86, 0X31, 0X86, 0X31, 0X45, 0X29, 0X45, 0X29, + 0X04, 0X21, 0X41, 0X08, 0X4A, 0X4A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF7, 0XC5, 0X82, 0X50, 0X05, 0X41, + 0XC7, 0X29, 0X08, 0X42, 0X49, 0X4A, 0X4A, 0X42, 0X49, 0X4A, 0X09, 0X7B, 0X88, 0X9B, 0XC6, 0XB3, + 0X21, 0XD4, 0XA0, 0XDC, 0XE1, 0XE4, 0X61, 0XED, 0X61, 0XED, 0X21, 0XED, 0XA0, 0XE4, 0X20, 0XDC, + 0X80, 0XCB, 0X43, 0XAB, 0XC4, 0X82, 0X06, 0X5A, 0X47, 0X21, 0X46, 0X29, 0X45, 0X29, 0X04, 0X29, + 0X04, 0X19, 0X82, 0X10, 0X82, 0X18, 0XF3, 0X9C, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X4D, 0X93, 0X00, 0XA0, 0X82, 0XB8, + 0XC7, 0X31, 0X09, 0X32, 0X49, 0X4A, 0X86, 0X7A, 0X43, 0XC3, 0X6B, 0XED, 0XF4, 0XF6, 0XEB, 0XFD, + 0X20, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X20, 0XFD, + 0XE0, 0XFC, 0XA0, 0XFC, 0X60, 0XF4, 0XC1, 0XDB, 0X83, 0X9A, 0XC5, 0X49, 0X45, 0X29, 0X04, 0X19, + 0XC4, 0X20, 0X82, 0X38, 0X00, 0X50, 0XCB, 0X6A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XEE, 0X04, 0XA1, 0X00, 0XC0, 0X00, 0XF0, + 0XC3, 0XA0, 0XC8, 0X41, 0X49, 0X42, 0X05, 0X9B, 0X20, 0XFC, 0XA4, 0XFC, 0X69, 0XFD, 0XE8, 0XFD, + 0X63, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0XE0, 0XFC, + 0XE0, 0XFC, 0XA0, 0XFC, 0X60, 0XFC, 0X20, 0XFC, 0X41, 0XD3, 0XC5, 0X49, 0X45, 0X19, 0XC4, 0X38, + 0X82, 0X68, 0X41, 0X88, 0X00, 0X70, 0X49, 0X5A, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XF6, 0X82, 0XC0, 0X00, 0XD0, 0X86, 0XC1, + 0X46, 0XF1, 0X41, 0XC8, 0X45, 0X79, 0X89, 0X52, 0X88, 0X62, 0X86, 0X6A, 0XC6, 0X7A, 0XC4, 0XBB, + 0XE1, 0XFC, 0X60, 0XFD, 0X60, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XE0, 0XFC, + 0X60, 0XE4, 0X03, 0X93, 0X84, 0X72, 0X44, 0X6A, 0XC5, 0X41, 0X45, 0X29, 0XC3, 0X58, 0X41, 0XA8, + 0X40, 0X98, 0X00, 0XB0, 0X00, 0X60, 0X0C, 0X6B, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0XCE, 0X83, 0X82, 0X88, 0X00, 0XF8, 0XC4, 0XD8, + 0X0C, 0XF3, 0X8A, 0XFA, 0X82, 0XE8, 0X82, 0XB0, 0X45, 0X69, 0XC7, 0X51, 0X08, 0X42, 0X08, 0X3A, + 0X86, 0X5A, 0X83, 0X9B, 0XA2, 0XBC, 0X22, 0XCD, 0X21, 0XCD, 0XA1, 0XC4, 0X22, 0XB4, 0XC4, 0X7A, + 0X06, 0X3A, 0X86, 0X29, 0X45, 0X29, 0X05, 0X31, 0XC4, 0X50, 0X41, 0X90, 0X00, 0XC0, 0X00, 0XA8, + 0X00, 0XA0, 0X00, 0XA8, 0X00, 0X30, 0X4A, 0X4A, 0XBA, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X8E, 0X73, 0XC3, 0X18, 0X05, 0X39, 0X82, 0XA8, 0X00, 0XF8, + 0XC3, 0XF8, 0X4D, 0XFB, 0X4D, 0XFB, 0XC7, 0XF9, 0XC3, 0XF0, 0X82, 0XD8, 0XC3, 0XB0, 0X04, 0X81, + 0X45, 0X61, 0X46, 0X51, 0X86, 0X49, 0X86, 0X49, 0X46, 0X41, 0X45, 0X41, 0X45, 0X41, 0X45, 0X41, + 0X05, 0X49, 0X04, 0X61, 0X82, 0X90, 0X41, 0XB0, 0X00, 0XD0, 0X00, 0XC8, 0X00, 0XA8, 0X00, 0XA8, + 0X00, 0XB8, 0X41, 0X58, 0X82, 0X10, 0X82, 0X10, 0XB2, 0X94, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0XCF, 0X7B, 0X82, 0X10, 0X04, 0X21, 0X86, 0X29, 0X86, 0X41, 0X04, 0X99, + 0X40, 0XE8, 0X41, 0XF8, 0X86, 0XF9, 0XCB, 0XFA, 0X49, 0XFA, 0X82, 0XF8, 0X00, 0XF8, 0X00, 0XF0, + 0X00, 0XE8, 0X41, 0XD8, 0X41, 0XD0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC0, 0X41, 0XC8, + 0X00, 0XD0, 0X00, 0XE0, 0X00, 0XE0, 0X00, 0XD8, 0X00, 0XD0, 0X00, 0XB8, 0X00, 0XA8, 0X41, 0X88, + 0X82, 0X48, 0X82, 0X10, 0X82, 0X10, 0X00, 0X00, 0X45, 0X29, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0XF3, 0X9C, 0X82, 0X10, 0XC3, 0X18, 0X45, 0X29, 0X86, 0X31, 0XC7, 0X31, 0X30, 0X7C, + 0XF3, 0XDC, 0X86, 0XE1, 0X00, 0XF0, 0X00, 0XF8, 0X41, 0XF8, 0X41, 0XF8, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XE8, 0X00, 0XE0, 0X00, 0XE0, 0X00, 0XD8, 0X00, 0XC8, 0X41, 0XA0, 0X8A, 0X9A, 0X0C, 0X63, + 0X04, 0X11, 0X82, 0X10, 0X82, 0X10, 0X41, 0X08, 0X00, 0X00, 0X4D, 0X6B, 0X7D, 0XEF, 0XFF, 0XFF, + 0XFB, 0XDE, 0X08, 0X42, 0X42, 0X10, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X49, 0X4A, 0X38, 0XBE, + 0XFF, 0XFF, 0X38, 0XD6, 0X86, 0XA9, 0X00, 0XC8, 0X00, 0XE0, 0X00, 0XF0, 0X00, 0XF8, 0X00, 0XF8, + 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF8, 0X00, 0XF0, 0X00, 0XF0, + 0X00, 0XE8, 0X00, 0XE0, 0X00, 0XD0, 0XC3, 0X98, 0X8A, 0X8A, 0XB2, 0XA4, 0XBA, 0XC6, 0XF7, 0XB5, + 0X08, 0X42, 0X41, 0X08, 0X82, 0X10, 0X41, 0X08, 0X00, 0X00, 0X45, 0X29, 0XF7, 0XBD, 0XFF, 0XFF, + 0X71, 0X8C, 0X41, 0X08, 0X04, 0X21, 0X45, 0X29, 0X86, 0X31, 0X86, 0X31, 0X0C, 0X63, 0X3C, 0XE7, + 0XFF, 0XFF, 0X79, 0XD6, 0X46, 0XB9, 0X00, 0XE0, 0X42, 0XC8, 0X82, 0XA8, 0X82, 0XB0, 0X41, 0XD8, + 0X82, 0XE8, 0X82, 0XF0, 0X41, 0XE8, 0X41, 0XE8, 0X41, 0XE8, 0X41, 0XF0, 0X41, 0XE8, 0X41, 0XD8, + 0X04, 0XC1, 0X08, 0X92, 0X4D, 0X8B, 0X34, 0XA5, 0XFB, 0XC6, 0XFB, 0XD6, 0XBA, 0XCE, 0X3C, 0XE7, + 0X30, 0X84, 0XC3, 0X18, 0X41, 0X08, 0X41, 0X08, 0X00, 0X00, 0X41, 0X08, 0XCF, 0X7B, 0X7D, 0XEF, + 0X49, 0X4A, 0X00, 0X00, 0X04, 0X21, 0X45, 0X29, 0X46, 0X31, 0X86, 0X31, 0X30, 0X84, 0XFF, 0XFF, + 0XFF, 0XF7, 0XF7, 0XDD, 0X09, 0XDA, 0X83, 0XF8, 0X01, 0XF0, 0X42, 0XC0, 0X82, 0X98, 0X49, 0X9A, + 0XF3, 0XB4, 0XF3, 0XCC, 0X71, 0XBC, 0X8E, 0XBB, 0X8E, 0XBB, 0X30, 0XBC, 0X71, 0XBC, 0XF3, 0XBC, + 0XB6, 0XBD, 0XFB, 0XCE, 0XBE, 0XE7, 0X7D, 0XE7, 0X3B, 0XDF, 0XBA, 0XD6, 0X79, 0XCE, 0XFB, 0XDE, + 0X75, 0XAD, 0X86, 0X31, 0X41, 0X08, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0X49, 0X4A, 0XFB, 0XDE, + 0X04, 0X21, 0X41, 0X08, 0X04, 0X21, 0X45, 0X29, 0X45, 0X29, 0X87, 0X39, 0XB2, 0X94, 0XFF, 0XFF, + 0XBE, 0XF7, 0X34, 0XDD, 0X0C, 0XEB, 0X09, 0XFA, 0X00, 0XF0, 0X01, 0XD8, 0X00, 0XD8, 0X8B, 0XD2, + 0X7D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XFF, 0X7D, 0XEF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, + 0X78, 0XC6, 0XC7, 0X39, 0X00, 0X00, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0XC7, 0X39, 0X79, 0XCE, + 0X00, 0X00, 0X82, 0X10, 0XC3, 0X18, 0X04, 0X21, 0X05, 0X29, 0X86, 0X31, 0XB3, 0X9C, 0XFF, 0XFF, + 0XFF, 0XF7, 0X75, 0XDD, 0XC7, 0XE9, 0XC7, 0XF9, 0X01, 0XF8, 0X01, 0XF0, 0X00, 0XE8, 0X49, 0XE2, + 0XFB, 0XEE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, + 0XB9, 0XCE, 0X08, 0X42, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XC7, 0X39, 0X38, 0XC6, + 0X00, 0X00, 0X82, 0X10, 0X82, 0X10, 0X04, 0X21, 0X04, 0X21, 0X45, 0X29, 0X30, 0X84, 0XFF, 0XFF, + 0XFF, 0XFF, 0X38, 0XDE, 0XC4, 0XD0, 0X00, 0XF0, 0X01, 0XF8, 0X00, 0XF8, 0X00, 0XF0, 0X08, 0XD2, + 0XFB, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XBA, 0XD6, + 0X79, 0XCE, 0XC7, 0X39, 0X41, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X86, 0X31, 0X38, 0XC6, + 0X00, 0X00, 0X00, 0X00, 0XC3, 0X18, 0XCB, 0X5A, 0X86, 0X31, 0XC3, 0X18, 0XCB, 0X5A, 0X7D, 0XEF, + 0XFF, 0XFF, 0X7D, 0XEF, 0XCF, 0XBB, 0XC3, 0XB0, 0X41, 0XD0, 0X41, 0XD0, 0X82, 0XB8, 0X4D, 0XB3, + 0X7D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0XBE, 0XF7, 0X3D, 0XEF, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XFA, 0XD6, + 0XF7, 0XBD, 0X04, 0X21, 0X86, 0X31, 0X04, 0X21, 0X00, 0X00, 0X00, 0X00, 0X86, 0X31, 0X38, 0XC6, + 0X86, 0X31, 0XC3, 0X18, 0XCB, 0X5A, 0X75, 0XAD, 0XCF, 0X7B, 0X41, 0X08, 0X86, 0X31, 0XF7, 0XBD, + 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XEF, 0X74, 0XB5, 0X30, 0X9C, 0X30, 0X9C, 0X72, 0XA4, 0XBB, 0XD6, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XBE, 0XF7, 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0X3C, 0XE7, + 0X71, 0X8C, 0X81, 0X08, 0X0C, 0X63, 0XCF, 0X7B, 0X82, 0X10, 0X00, 0X00, 0X8A, 0X52, 0X38, 0XC6, + 0X75, 0XAD, 0X71, 0X8C, 0XB6, 0XB5, 0X3C, 0XE7, 0XFB, 0XDE, 0XC7, 0X39, 0X00, 0X00, 0XCF, 0X73, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, + 0X7D, 0XEF, 0X7D, 0XEF, 0X3B, 0XDF, 0XFA, 0XD6, 0X79, 0XCE, 0X79, 0XCE, 0XFB, 0XDE, 0XB9, 0XCE, + 0XC7, 0X39, 0XC4, 0X20, 0X71, 0X8C, 0XBA, 0XD6, 0X71, 0X8C, 0XCB, 0X5A, 0XB2, 0X94, 0XBA, 0XD6, + 0XFF, 0XFF, 0X7D, 0XEF, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XB6, 0XB5, 0X46, 0X29, 0X05, 0X19, + 0X75, 0XA5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, + 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XBA, 0XD6, 0XFC, 0XDE, 0X4E, 0X63, + 0X42, 0X08, 0X0C, 0X63, 0XF7, 0XBD, 0XBE, 0XF7, 0XFF, 0XFF, 0XFB, 0XDE, 0XFB, 0XDE, 0XBE, 0XF7, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF4, 0X9C, 0X04, 0X21, + 0X05, 0X21, 0XB6, 0XA5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, + 0X3C, 0XE7, 0XFB, 0XDE, 0XBA, 0XD6, 0X79, 0XCE, 0XFB, 0XDE, 0XBB, 0XD6, 0XD1, 0X73, 0X83, 0X18, + 0X86, 0X39, 0X34, 0X9D, 0XBD, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XFF, 0X35, 0XD6, 0XEB, 0XCC, 0X43, 0XB3, + 0X40, 0X51, 0X05, 0X19, 0XF5, 0X8C, 0XBE, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X3C, 0XE7, + 0XFB, 0XDE, 0XBA, 0XDE, 0XBA, 0XD6, 0X3C, 0XDF, 0X3A, 0XBE, 0X4F, 0X63, 0X82, 0X49, 0X40, 0XA3, + 0X23, 0XB4, 0XCC, 0X83, 0X3A, 0XBE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBF, 0XF7, 0XB5, 0XBD, 0X82, 0X92, 0X20, 0XF4, 0XA0, 0XFC, + 0X60, 0XE4, 0X40, 0X82, 0X84, 0X41, 0X8F, 0X6B, 0X77, 0XAD, 0X3D, 0XE7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFE, 0XFF, 0XBE, 0XF7, 0XBE, 0XF7, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X3C, 0XE7, 0XFB, 0XDE, + 0XFB, 0XDE, 0X3D, 0XE7, 0XBB, 0XCE, 0X36, 0X9D, 0X0B, 0X6B, 0X41, 0X6A, 0X60, 0XC4, 0X20, 0XFE, + 0X60, 0XF5, 0X00, 0X8B, 0XC7, 0X6A, 0X38, 0XC6, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0X4B, 0X7B, 0X80, 0XB2, 0XA0, 0XFC, 0XA0, 0XFC, + 0XE0, 0XFC, 0XE0, 0XFC, 0XC0, 0XCB, 0XC1, 0X8A, 0X45, 0X62, 0X4D, 0X6B, 0XB3, 0X94, 0XF7, 0XBD, + 0X3D, 0XDF, 0XFF, 0XF7, 0XFF, 0XFF, 0XBE, 0XF7, 0X7D, 0XEF, 0X7D, 0XEF, 0X7D, 0XE7, 0X3D, 0XDF, + 0XBA, 0XC6, 0X75, 0XA5, 0X8D, 0X7B, 0X84, 0X7A, 0X40, 0XB3, 0XE0, 0XEC, 0XE0, 0XFD, 0XE0, 0XFD, + 0X60, 0XF5, 0X20, 0XE5, 0XA0, 0XD4, 0X0A, 0X6B, 0XFB, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7D, 0XEF, 0XCC, 0X93, 0X40, 0XEB, 0X60, 0XFC, 0XA0, 0XFC, + 0XE0, 0XFC, 0X20, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XD4, 0XC0, 0XBB, 0X42, 0X9B, 0X45, 0X8B, + 0X6B, 0X9C, 0XAE, 0X9C, 0X71, 0X8C, 0XB3, 0X94, 0X33, 0X9D, 0X34, 0XA5, 0XF2, 0XA4, 0XF0, 0XB4, + 0XCA, 0X9B, 0X04, 0X9B, 0X40, 0XBB, 0X20, 0XE4, 0X20, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XE0, 0XFD, + 0XE0, 0XFD, 0XE0, 0XFD, 0X20, 0XC4, 0X88, 0X5A, 0X38, 0XBE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X78, 0XD6, 0X46, 0XAB, 0X40, 0XDB, 0X20, 0XF4, + 0X60, 0XFC, 0XA0, 0XFC, 0XE0, 0XFC, 0X60, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XDC, + 0XC0, 0XB3, 0XC0, 0X51, 0X86, 0X29, 0X0D, 0X63, 0X8F, 0X7B, 0X0D, 0X5B, 0XC7, 0X41, 0X01, 0X82, + 0X00, 0XC3, 0XC0, 0XE3, 0X60, 0XFC, 0XA0, 0XFC, 0XE0, 0XFC, 0XE0, 0XFC, 0X60, 0XF5, 0X60, 0XF5, + 0X20, 0XE5, 0X80, 0X9B, 0X86, 0X62, 0X30, 0X84, 0X79, 0XCE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X38, 0XC6, 0X2D, 0X9C, 0X05, 0X93, + 0X43, 0XA3, 0X82, 0XB3, 0XC2, 0XBB, 0XC2, 0XBB, 0X22, 0XB4, 0X82, 0XA3, 0X42, 0X93, 0XC3, 0X7A, + 0X85, 0X62, 0X0B, 0X63, 0X71, 0X84, 0XB6, 0XB5, 0X79, 0XCE, 0X79, 0XC6, 0XB5, 0XAD, 0X70, 0X94, + 0X4A, 0X8B, 0X06, 0X83, 0X04, 0X93, 0X04, 0X9B, 0X43, 0X9B, 0X43, 0X9B, 0X43, 0X93, 0X04, 0X83, + 0X08, 0X73, 0X8D, 0X73, 0XB3, 0X94, 0X79, 0XCE, 0X7D, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3C, 0XDF, 0X38, 0XBE, + 0X75, 0XB5, 0X33, 0XA5, 0X33, 0XA5, 0XF3, 0X9C, 0XF3, 0X9C, 0XF3, 0X9C, 0XF3, 0X94, 0XF3, 0X9C, + 0X35, 0XA5, 0XF8, 0XBD, 0XFB, 0XDE, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7E, 0XEF, + 0XBB, 0XD6, 0XF8, 0XBD, 0XB6, 0XAD, 0X75, 0XAD, 0X34, 0XA5, 0X33, 0X9D, 0X34, 0X9D, 0X35, 0XA5, + 0XB7, 0XAD, 0X79, 0XC6, 0X3C, 0XE7, 0XBE, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, +}; + +const unsigned char PROGMEM icon_40x40[3200] = { /* 0X00,0X10,0X28,0X00,0X28,0X00,0X01,0X1B, */ + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5D, 0XEF, 0X71, 0X8C, 0X31, 0X84, 0X31, 0X84, + 0X93, 0XC5, 0X92, 0XCD, 0X91, 0XCD, 0X91, 0XD5, 0X91, 0XD5, 0X91, 0XCD, 0X72, 0XCD, 0X72, 0XC5, + 0X56, 0XDE, 0XBE, 0XFF, 0XDB, 0XDE, 0XFB, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XCE, 0X7B, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X5A, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0X20, 0XDD, 0XE0, 0XD4, 0XA0, 0XD4, + 0X61, 0XA3, 0XA7, 0X39, 0XE5, 0X18, 0X05, 0X21, 0X92, 0X94, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XF9, 0XEE, 0XEB, 0X9B, 0XA1, 0X18, 0X23, 0X73, 0X81, 0XC5, 0X21, 0X9C, + 0X61, 0X39, 0X81, 0XEE, 0X40, 0XFF, 0XE0, 0XFE, 0XE0, 0XFE, 0XE0, 0XFE, 0X40, 0XFF, 0XC0, 0XF6, + 0XC0, 0X49, 0XA0, 0X18, 0X00, 0X42, 0X60, 0X18, 0X00, 0X00, 0X74, 0XB5, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X93, 0XCD, 0XC3, 0XBB, 0XA0, 0X51, 0XE1, 0X39, 0XC2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0X63, 0XBD, 0X61, 0XE6, 0X40, 0XFF, 0XE0, 0XFE, 0XE0, 0XFE, 0XC0, 0XFE, 0X60, 0XFF, 0X21, 0X73, + 0XE1, 0X28, 0X81, 0XEE, 0X61, 0XFF, 0X21, 0XEE, 0XA0, 0X41, 0X20, 0X08, 0X90, 0XCD, 0XDE, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5C, 0XF7, + 0X0B, 0XAC, 0XC0, 0XB3, 0XA1, 0XEE, 0XC3, 0X5A, 0X22, 0X8C, 0XE1, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0XC0, 0XFF, 0X80, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0X20, 0XFF, 0XA1, 0XAC, + 0X21, 0XC5, 0X20, 0XFF, 0X60, 0XFE, 0X00, 0XFF, 0X02, 0XDE, 0XE0, 0X20, 0X40, 0X82, 0X49, 0XBC, + 0X3B, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X5C, 0XF7, 0X67, 0X9B, + 0XE0, 0XB3, 0X81, 0XFF, 0XC3, 0XFF, 0X83, 0X9C, 0X82, 0XDE, 0XC0, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0XE0, 0XFE, 0XA2, 0XB4, 0X41, 0XBC, 0X20, 0XCC, + 0X87, 0XA3, 0XB8, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X9D, 0XF7, 0XA8, 0XA3, 0X60, 0XBC, + 0XA2, 0XFF, 0XA5, 0XFF, 0X44, 0XFF, 0XA1, 0XFF, 0XA0, 0XFF, 0X60, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, + 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X60, 0XFE, 0X20, 0XFE, 0X40, 0XFE, + 0XE0, 0XCB, 0XE3, 0X92, 0X7C, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X4C, 0XAC, 0XC0, 0XB3, 0XA4, 0XFF, + 0XA6, 0XFF, 0X45, 0XFF, 0X62, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X20, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0X00, 0XFE, + 0XE0, 0XFD, 0XE0, 0XC3, 0X2A, 0XAC, 0X7D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XD4, 0XD5, 0X40, 0XAB, 0X43, 0XFF, 0XA8, 0XFF, + 0X67, 0XFF, 0X62, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, + 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0XE0, 0XFD, + 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XA2, 0X11, 0XBD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XDA, 0XE6, 0XE4, 0X9A, 0XE1, 0XE5, 0XE8, 0XFF, 0X69, 0XFF, + 0X65, 0XFF, 0X60, 0XFF, 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0X00, 0XFF, 0X20, 0XFF, 0XE0, 0XFE, 0X60, 0XFE, 0X20, 0XFE, 0X00, 0XFE, + 0XC0, 0XFD, 0XE0, 0XFD, 0XE0, 0XE4, 0X85, 0XAB, 0XFA, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X2B, 0XB4, 0XC0, 0XB3, 0XC8, 0XFF, 0X8C, 0XFF, 0X68, 0XFF, + 0X61, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE1, 0XFF, 0XA1, 0XDE, 0X61, 0XEF, + 0XE1, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X60, 0XFF, 0XC0, 0XFF, 0X61, 0XDE, 0X00, 0XE6, 0X80, 0XFE, 0X40, 0XFE, 0X00, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0XE0, 0XFD, 0XC0, 0XC3, 0XE9, 0XAB, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X5D, 0XEF, 0XA3, 0XAB, 0XA3, 0XF6, 0XCC, 0XFF, 0X4C, 0XFF, 0X64, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0X61, 0XEF, 0X22, 0X6B, 0X82, 0X5A, 0X82, 0XB5, + 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0XA0, 0XFF, 0XE1, 0XFF, 0X42, 0X8C, 0XC1, 0X41, 0X21, 0XA4, 0XA0, 0XFE, 0X80, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0X20, 0XF5, 0XC0, 0X9A, 0X35, 0XD6, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X51, 0XC5, 0X60, 0XBC, 0XC9, 0XFF, 0X8E, 0XFF, 0X6A, 0XFF, 0X61, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XE1, 0XFF, 0XE1, 0X62, 0X80, 0X10, 0X05, 0XE7, 0XA4, 0XF7, + 0XE4, 0XFF, 0XE3, 0XFF, 0XE2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XC1, 0XFF, 0XE2, 0X83, 0X40, 0X08, 0X22, 0XCE, 0X60, 0XF7, 0XA0, 0XFE, 0X60, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0XA0, 0XFD, 0XA0, 0XC3, 0XAC, 0XBC, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XDE, 0XFF, 0XA7, 0XAB, 0X81, 0XDD, 0XED, 0XFF, 0XB0, 0XFF, 0X69, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0X61, 0XD6, 0X22, 0X29, 0XA6, 0X31, 0XE3, 0X7B, 0X46, 0XEF, + 0XE6, 0XFF, 0XE4, 0XFF, 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X81, 0XD6, 0XA0, 0X18, 0XC4, 0X18, 0XA1, 0X62, 0XC1, 0XCD, 0X40, 0XFF, 0X60, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0XA0, 0XEC, 0X48, 0XBC, 0XDF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XF9, 0XE6, 0XE3, 0X9A, 0X67, 0XEE, 0XD1, 0XFF, 0XB0, 0XFF, 0X86, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0X60, 0X94, 0X91, 0X73, 0XD9, 0XBD, 0X00, 0X00, 0X05, 0X84, + 0XE8, 0XFF, 0XE5, 0XFF, 0XE3, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X20, 0XAD, 0XE9, 0X41, 0XB7, 0XB5, 0X01, 0X00, 0X60, 0X62, 0X21, 0XFF, 0X80, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X20, 0XF5, 0XE3, 0XBB, 0XD9, 0XE6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XD3, 0XCD, 0X40, 0XA3, 0X2B, 0XF7, 0XD3, 0XFF, 0XB0, 0XFF, 0X63, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA0, 0X9C, 0X30, 0X6B, 0X97, 0XB5, 0X00, 0X00, 0X83, 0X52, + 0XC6, 0XFF, 0XE5, 0XFF, 0XE3, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0X20, 0XAD, 0XEA, 0X41, 0X77, 0XAD, 0X01, 0X00, 0XC0, 0X49, 0XE0, 0XF6, 0XA0, 0XFE, 0X20, 0XFE, + 0XE0, 0XFD, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0XA0, 0XBB, 0XD3, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X00, 0XB4, 0X8E, 0XFF, 0XF4, 0XFF, 0XB0, 0XFF, 0X42, 0XFF, 0X60, 0XFF, + 0X80, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA1, 0XDE, 0X01, 0X21, 0X00, 0X00, 0X00, 0X00, 0X25, 0X8C, + 0XE5, 0XFF, 0XE3, 0XFF, 0XE2, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, + 0XE1, 0XDE, 0X01, 0X21, 0X00, 0X00, 0X00, 0X00, 0X61, 0X5A, 0X20, 0XFF, 0X80, 0XFE, 0X20, 0XFE, + 0X00, 0XFE, 0XE0, 0XFD, 0XA0, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XC0, 0XCB, 0X71, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X40, 0XC4, 0XB0, 0XFF, 0XF5, 0XFF, 0X8F, 0XFF, 0X41, 0XFF, 0X80, 0XFF, + 0XA0, 0XFF, 0XC0, 0XFF, 0XE0, 0XFF, 0XE1, 0XFF, 0X21, 0X8C, 0X60, 0X10, 0X43, 0X6B, 0X44, 0XEF, + 0XE2, 0XFF, 0XE2, 0XFF, 0XE1, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0XE1, 0XFF, 0XC1, 0XA4, 0XC2, 0X18, 0XA2, 0X39, 0XA1, 0XCD, 0X20, 0XFF, 0X60, 0XFE, 0X20, 0XFE, + 0XC0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0XE0, 0XCB, 0X91, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X40, 0XC4, 0XD2, 0XFF, 0XF7, 0XFF, 0XAF, 0XFF, 0X01, 0XFF, 0X00, 0XFF, + 0X00, 0XFF, 0X40, 0XFF, 0XA0, 0XFF, 0XE0, 0XFF, 0XA1, 0XFF, 0X82, 0XD6, 0XC2, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0XC1, 0XFF, 0X82, 0XDE, 0XC2, 0XEE, 0X61, 0XFF, 0X80, 0XFE, 0XC0, 0XFD, 0X20, 0XFD, + 0XA1, 0XFC, 0X61, 0XFC, 0X61, 0XFC, 0XC0, 0XFC, 0X60, 0XFD, 0XE0, 0XCB, 0X51, 0XC5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X60, 0XC4, 0XD4, 0XFF, 0XF9, 0XFF, 0X2D, 0XFF, 0X00, 0XFE, 0XC0, 0XFD, + 0XA1, 0XFD, 0X21, 0XFE, 0XE0, 0XFE, 0XC0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, 0XE0, 0XFF, + 0XE0, 0XFF, 0XE0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, + 0X40, 0XFF, 0X40, 0XFF, 0X80, 0XFF, 0X20, 0XFF, 0XA0, 0XFE, 0X20, 0XFE, 0X01, 0XFD, 0X01, 0XFC, + 0X62, 0XFB, 0X42, 0XFB, 0X82, 0XFB, 0X21, 0XFC, 0X20, 0XFD, 0X00, 0XD4, 0X71, 0XC5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0X20, 0XC4, 0XD4, 0XFF, 0XBA, 0XFF, 0X2E, 0XFE, 0XE1, 0XFC, 0X61, 0XFC, + 0X61, 0XFC, 0X01, 0XFD, 0X01, 0XFE, 0X20, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XC0, 0XFF, 0XC0, 0XFF, + 0XC0, 0XFF, 0XC0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X80, 0XFD, 0X61, 0XFC, 0X62, 0XFB, + 0XA3, 0XFA, 0XA3, 0XFA, 0X42, 0XFB, 0X01, 0XFC, 0XE0, 0XFC, 0XE0, 0XCB, 0X71, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X50, 0XCD, 0XC0, 0XB3, 0XB3, 0XFF, 0X7A, 0XFF, 0X91, 0XFD, 0X03, 0XFC, 0X02, 0XFB, + 0X22, 0XFB, 0X62, 0XFC, 0X81, 0XFD, 0XC0, 0XFE, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, 0XA0, 0XFF, + 0XA0, 0XFF, 0XA0, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X20, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0XA0, 0XFE, 0X60, 0XFE, 0X60, 0XFD, 0X41, 0XFC, 0X62, 0XFB, + 0XC3, 0XFA, 0XA3, 0XFA, 0X42, 0XFB, 0X01, 0XFC, 0X20, 0XFD, 0XC0, 0XCB, 0X91, 0XCD, 0XFF, 0XFF, + 0XFF, 0XFF, 0X14, 0XD6, 0X20, 0XAB, 0X51, 0XF7, 0XBE, 0XFF, 0X17, 0XFE, 0X65, 0XFC, 0X61, 0XFB, + 0XA2, 0XFB, 0XA1, 0XFC, 0XC1, 0XFD, 0X00, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, + 0X80, 0XFF, 0X80, 0XFF, 0X80, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X20, 0XFF, + 0X00, 0XFF, 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0XC0, 0XFD, 0XC0, 0XFC, 0X41, 0XFC, + 0XC1, 0XFB, 0XA2, 0XFB, 0X01, 0XFC, 0XA0, 0XFC, 0X40, 0XFD, 0XA0, 0XC3, 0XF4, 0XD5, 0XFF, 0XFF, + 0XFF, 0XFF, 0X5B, 0XEF, 0X24, 0X9B, 0X49, 0XE6, 0XB8, 0XFF, 0X92, 0XFE, 0X25, 0XFD, 0XA0, 0XFC, + 0X02, 0XFD, 0XE1, 0XFD, 0XE0, 0XFE, 0X40, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X00, 0XFF, + 0XC0, 0XFE, 0XA0, 0XFE, 0X80, 0XFE, 0X40, 0XFE, 0X40, 0XFE, 0X00, 0XFE, 0X80, 0XFD, 0X01, 0XF5, + 0X41, 0XFD, 0X01, 0XFD, 0XC0, 0XFC, 0X40, 0XFD, 0X00, 0XF5, 0XC4, 0XBB, 0XFA, 0XE6, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X2A, 0XB4, 0XA0, 0XD4, 0XA2, 0XFE, 0X20, 0XFE, 0XE0, 0XFD, 0X00, 0XFE, + 0X80, 0XFE, 0X21, 0XEE, 0X41, 0XE6, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, + 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, + 0XA0, 0XFE, 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X00, 0XFE, 0X00, 0XFE, 0X00, 0XFE, 0X40, 0XCC, + 0XE1, 0XAB, 0XC1, 0XED, 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XE4, 0X29, 0XB4, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0X15, 0XD6, 0XE0, 0XBB, 0X60, 0XFE, 0XC8, 0XFE, 0XC8, 0XFE, 0X02, 0XFF, + 0X60, 0XDD, 0X40, 0XA3, 0XA1, 0XDD, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, + 0X20, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, 0XC0, 0XFE, 0XC0, 0XFE, 0XA0, 0XFE, + 0X80, 0XFE, 0X60, 0XFE, 0X40, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X40, 0XED, + 0XC0, 0X9A, 0X40, 0XA3, 0X80, 0XF5, 0X60, 0XFD, 0X60, 0XBB, 0XEE, 0XBC, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XDF, 0XFF, 0X63, 0XAB, 0X42, 0XE5, 0XB4, 0XFF, 0X97, 0XFF, 0XAA, 0XF6, + 0X80, 0XAB, 0XA0, 0X92, 0XA1, 0XDD, 0X41, 0XFF, 0X40, 0XFF, 0X60, 0XFF, 0X60, 0XFF, 0X60, 0XFF, + 0X60, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X40, 0XFF, 0X20, 0XFF, 0X20, 0XFF, 0X00, 0XFF, 0XE0, 0XFE, + 0XC0, 0XFE, 0X80, 0XFE, 0X61, 0XFE, 0X00, 0XFE, 0XA0, 0XED, 0X20, 0XE5, 0X21, 0XCC, 0X80, 0XB3, + 0X00, 0XBC, 0XE0, 0XC3, 0X40, 0XED, 0XC0, 0XEC, 0X60, 0X92, 0X97, 0XE6, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X0F, 0XC5, 0X00, 0XA3, 0XAA, 0XF6, 0X93, 0XFF, 0X2D, 0XEE, + 0X63, 0XDD, 0X80, 0XD5, 0X42, 0XB4, 0X82, 0XCC, 0X00, 0XCD, 0X40, 0XD5, 0XA0, 0XDD, 0XE1, 0XE5, + 0XC1, 0XE5, 0XC1, 0XE5, 0XC1, 0XE5, 0XC1, 0XE5, 0X80, 0XDD, 0X60, 0XDD, 0X20, 0XD5, 0XC0, 0XCC, + 0XA0, 0XCC, 0X61, 0XC4, 0X21, 0XC4, 0X01, 0XBC, 0X01, 0XBC, 0XE0, 0XBB, 0XC0, 0XBB, 0X60, 0XD4, + 0X80, 0XFD, 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XBB, 0X2B, 0XAC, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X9D, 0XF7, 0X87, 0XA3, 0X60, 0XD4, 0X0A, 0XFF, 0XCF, 0XFE, + 0XC9, 0XFE, 0XC0, 0XFE, 0XC0, 0XF6, 0X40, 0XE6, 0X41, 0XCD, 0X42, 0XB4, 0XC1, 0XAB, 0X60, 0XA3, + 0X60, 0XA3, 0X80, 0XA3, 0X80, 0XA3, 0X80, 0XA3, 0XA0, 0XAB, 0XC1, 0XAB, 0XE1, 0XB3, 0X22, 0XB4, + 0X82, 0XC4, 0XC0, 0XCC, 0X00, 0XD5, 0X60, 0XE5, 0X81, 0XED, 0X80, 0XF5, 0X80, 0XFD, 0X80, 0XFD, + 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XE4, 0X85, 0XAB, 0X5C, 0XEF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFA, 0XE6, 0X23, 0XA3, 0XE0, 0XE4, 0XE8, 0XFE, + 0X6A, 0XFE, 0X05, 0XFE, 0X40, 0XFE, 0XA0, 0XFE, 0XC0, 0XFE, 0XE1, 0XFE, 0XA0, 0XF6, 0XA0, 0XF6, + 0XA0, 0XF6, 0XA0, 0XF6, 0X80, 0XF6, 0X80, 0XF6, 0X80, 0XF6, 0X60, 0XF6, 0X61, 0XFE, 0X81, 0XFE, + 0X61, 0XFE, 0X20, 0XFE, 0X00, 0XFE, 0XC0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X20, 0XFD, 0X20, 0XFD, + 0X60, 0XFD, 0X20, 0XF5, 0XA0, 0XA2, 0XB4, 0XCD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X52, 0XC5, 0XE0, 0XA2, 0XA1, 0XF5, + 0X86, 0XFE, 0X06, 0XFE, 0XE2, 0XFD, 0XE0, 0XFD, 0X00, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, + 0X40, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X20, 0XFE, 0X00, 0XFE, 0XE0, 0XFD, 0XE0, 0XFD, 0XC0, 0XFD, + 0XA0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X40, 0XFD, + 0X60, 0XFD, 0X60, 0XBB, 0X6C, 0XB4, 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X92, 0XCD, 0XC0, 0XA2, + 0X20, 0XED, 0X22, 0XFE, 0XC1, 0XFD, 0XA0, 0XFD, 0XC0, 0XFD, 0XE0, 0XFD, 0XE0, 0XFD, 0XE0, 0XFD, + 0XE0, 0XFD, 0XE0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0X80, 0XFD, + 0X80, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X60, 0XFD, 0X40, 0XFD, + 0X20, 0XB3, 0XEA, 0XA3, 0X9D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X8E, 0XBC, + 0XE1, 0XA2, 0X00, 0XE5, 0XE0, 0XFD, 0XC0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, + 0XC0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0XA0, 0XFD, 0X80, 0XFD, 0X80, 0XFD, 0X60, 0XFD, + 0X40, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X80, 0XFD, 0X00, 0XF5, 0X40, 0XBB, + 0X2B, 0XAC, 0X9D, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X35, 0XD6, 0XE2, 0X9A, 0XA0, 0XC3, 0XA0, 0XFD, 0XE0, 0XFD, 0X80, 0XFD, 0X60, 0XFD, 0X80, 0XFD, + 0X80, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XFD, + 0X20, 0XFD, 0X20, 0XFD, 0X40, 0XFD, 0X60, 0XFD, 0X60, 0XFD, 0X00, 0XD4, 0XC1, 0X9A, 0X10, 0XC5, + 0XDE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0X98, 0XDE, 0X2B, 0XAC, 0X40, 0XB3, 0X00, 0XD4, 0X40, 0XFD, 0X80, 0XFD, 0X80, 0XFD, + 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, 0X40, 0XFD, + 0X40, 0XFD, 0X60, 0XFD, 0X40, 0XFD, 0X40, 0XDC, 0X80, 0XBB, 0XE8, 0XAB, 0X57, 0XDE, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XDF, 0XFF, 0X37, 0XD6, 0X86, 0XA3, 0XC0, 0X9A, 0XE0, 0XCB, 0X80, 0XEC, + 0XE0, 0XF4, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X20, 0XFD, 0X00, 0XF5, + 0XA0, 0XEC, 0X00, 0XD4, 0X40, 0XB3, 0X03, 0X9B, 0X92, 0XC5, 0XBD, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBE, 0XF7, 0XF5, 0XCD, 0XAD, 0XBC, 0X69, 0XBC, + 0X05, 0XBC, 0X03, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0X01, 0XC4, 0XE2, 0XC3, 0X24, 0XC4, + 0X68, 0XBC, 0XAC, 0XBC, 0XD3, 0XCD, 0X9E, 0XF7, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0X5B, 0XEF, 0X98, 0XDE, 0X56, 0XD6, 0X57, 0XD6, 0X57, 0XD6, 0X56, 0XD6, 0X77, 0XDE, 0X1B, 0XEF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, +}; + diff --git a/examples/readpixel_kbv/readpixel_kbv.ino b/examples/readpixel_kbv/readpixel_kbv.ino new file mode 100644 index 0000000..0fea603 --- /dev/null +++ b/examples/readpixel_kbv/readpixel_kbv.ino @@ -0,0 +1,135 @@ +#define LCD_CS A3 // Chip Select goes to Analog 3 +#define LCD_CD A2 // Command/Data goes to Analog 2 +#define LCD_WR A1 // LCD Write goes to Analog 1 +#define LCD_RD A0 // LCD Read goes to Analog 0 +#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin + +#include // Hardware-specific library +#include +MCUFRIEND_kbv tft; + +//#include // Hardware-specific library +//Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); +//Adafruit_TFTLCD tft; + +// Assign human-readable names to some common 16-bit color values: +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +void setup(void); +void loop(void); + +uint16_t g_identifier; + +void setup(void) { + tft.reset(); + g_identifier = tft.readID(); + + Serial.begin(9600); + Serial.print("readID = 0x"); + Serial.println(g_identifier, HEX); + if (g_identifier == 0xFFFF) g_identifier = 0x9341; + if (g_identifier == 0) { + Serial.println("Unknown ID"); + while (1); + } + + tft.begin(g_identifier); + tft.setRotation(0); +} + +uint16_t colors[] = { + BLACK, BLUE +}; + +void colordump(uint16_t x, uint16_t y) +{ + uint16_t pixel, pixels[32]; + char i, j, buf[20], dirty; + uint8_t wid = (tft.width() - 9 * 6)/ (5 * 6), ht = (tft.height() / 8) - 1; + tft.setTextColor(WHITE); + tft.setTextSize(1); + for (j = 0; j < ht; j++) { + sprintf(buf, "%3d,%3d:", x, y + j); + tft.print(buf); + dirty = 1; + for (i = 0; i < wid; i++) { +#if 1 && defined(MCUFRIEND_KBV_H_) + if (dirty) tft.readGRAM(x, y + j, pixels, wid, 1); + dirty = 0; + pixel = pixels[i]; +#else + pixel = tft.readPixel(x + i, y + j); +#endif + tft.print(" "); + if (pixel == WHITE) tft.setTextColor(GREEN); + sprintf(buf, "%04X", pixel); + tft.print(buf); + tft.setTextColor(WHITE); + } + tft.println(); + } +} + +uint16_t bgr(uint16_t color) +{ + return ((color & 0xF800) >> 11) | (color & 0x7E0) | (color & 0x1F) << 11; +} + +void duffcolor(uint16_t color) +{ + uint16_t pixel, x, y; + char done, buf[20]; + uint16_t BGR = bgr(color); + for (done = 0, y = 0; y < 320 && !done; y++) { + for (x= 0; x < 240; x++) { + // pixel = readxy(x, y); + pixel = tft.readPixel(x, y); + if (pixel != BGR) { + done = 1; + sprintf(buf, "0x%04X @ %d, %d", pixel, x, y); + tft.println(buf); + break; + } + } + } +} + +uint8_t aspect; +char *aspectname[] = { + "PORTRAIT", "LANDSCAPE", "PORTRAIT_REV", "LANDSCAPE_REV" +}; + +void loop(void) +{ + uint16_t iter, color; + char buf[80]; + aspect = (aspect + 1) & 3; + tft.setRotation(aspect); + for (iter = 0; iter < sizeof(colors) / sizeof(uint16_t); iter++) { + color = colors[iter]; + tft.fillScreen(color); + tft.setTextColor(WHITE); + tft.setTextSize(1); + tft.setCursor(0, 0); + sprintf(buf, "ID=0x%04X Background=%04X %s", + tft.readID(), color, aspectname[aspect]); + tft.println(buf); + colordump(6 * 6, 0); + // duffcolor(color); + delay(5000); + } +} + + + + + + + diff --git a/examples/scroll_kbv/scroll_kbv.ino b/examples/scroll_kbv/scroll_kbv.ino new file mode 100644 index 0000000..a92db93 --- /dev/null +++ b/examples/scroll_kbv/scroll_kbv.ino @@ -0,0 +1,49 @@ +#include // Hardware-specific library +#include +MCUFRIEND_kbv tft; + +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +// work in line numbers. Font height in ht +int16_t ht = 16, top = 3, line, lines = 15, scroll; + +void setup() +{ + tft.reset(); + uint16_t id = tft.readID(); + tft.begin(id); + tft.setRotation(0); //Portrait + tft.fillScreen(BLACK); + tft.setTextColor(WHITE, BLACK); + tft.setTextSize(2); // System font is 8 pixels. ht = 8*2=16 + tft.setCursor(100, 0); + tft.print("ID = 0x"); + tft.println(id, HEX); + if (id == 0x9320 || id == 0x9325 || id == 0xB509) { + top = 0; // these controllers scroll full screen + lines = tft.height() / ht; // we are in portrait mode + } + if (id == 0x7783) { + tft.println("can NOT scroll"); + while (1); // die. + } + tft.setCursor(0, 0); + for (line = 1; line < 21; line++) tft.println(String(line) + ": "); +} + +void loop() +{ + tft.setCursor(0, (scroll + top) * ht); + if (++scroll >= lines) scroll = 0; + tft.vertScroll(top * ht, lines * ht, (scroll) * ht); + tft.println(String(line) + ": [" + String(scroll) + "] "); + delay(100); + line++; +} diff --git a/examples/testcard_kbv/testcard_kbv.ino b/examples/testcard_kbv/testcard_kbv.ino new file mode 100644 index 0000000..27101a4 --- /dev/null +++ b/examples/testcard_kbv/testcard_kbv.ino @@ -0,0 +1,183 @@ +/* + * generate testcard similar to BMP + */ + +#include +#if defined(_GFXFONT_H_) //are we using the new library? +#include +#define ADJ_BASELINE 11 //new fonts setCursor to bottom of letter +#else +#define ADJ_BASELINE 0 //legacy setCursor to top of letter +#endif +#include +MCUFRIEND_kbv tft; + +#define BLACK 0x0000 +#define BLUE 0x001F +#define RED 0xF800 +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF + +#define GREY 0x7BEF + +#include + +uint16_t ID; +uint8_t hh, mm, ss; //containers for current time + +uint8_t conv2d(const char* p) +{ + uint8_t v = 0; + if ('0' <= *p && *p <= '9') v = *p - '0'; + return 10 * v + *++p - '0'; +} + +void setup(void) +{ + Serial.begin(9600); + tft.reset(); + ID = tft.readID(); + Serial.print("TFT ID = 0x"); + Serial.println(ID, HEX); + // if (ID == 0x00D3) ID = 0x9481; // write-only shield + if (ID == 0x00D3) ID = 0x9486; // write-only shield + tft.begin(ID); + tft.setRotation(1); + tft.fillScreen(BLACK); +#if defined(_GFXFONT_H_) + tft.setFont(&FreeSans9pt7b); +#endif + hh = conv2d(__TIME__); + mm = conv2d(__TIME__ + 3); + ss = conv2d(__TIME__ + 6); + +} + +void loop(void) +{ + int16_t x, y, dx, dy, idx; + uint16_t w, h, len, mask; + uint16_t colors[8] = { BLACK, WHITE, YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE }; + uint16_t height, width; + width = tft.width(); + height = tft.height(); + tft.fillRect(0, 0, 7, 3, WHITE); + tft.fillRect(313, 0, 7, 3, WHITE); + tft.fillRect(0, 237, 7, 3, WHITE); + tft.fillRect(313, 237, 7, 3, WHITE); + for (y = 0, w = 18, h = 3; y < 240; y += 13 * w + h) { + for (x = 25; x < 320 - 18; x += 2 * w) { + tft.fillRect(x, y, w, h, WHITE); + } + } + for (x = 0, w = 7, h = 18; x < 320; x += 17 * h + w) { + for (y = 21; y < 240 - 18; y += 2 * h) { + tft.fillRect(x, y, w, h, WHITE); + } + } + tft.fillRect(7, 3, 17 * 18, 13 * 18, GREY); + for (x = 7, y = 0, w = 1, h = 240; x < 320; x += 18) { + tft.fillRect(x, y, w, h, WHITE); + } + for (x = 0, y = 3, w = 320, h = 1; y < 240; y += 18) { + tft.fillRect(x, y, w, h, WHITE); + } + tft.fillRect(26, 22, 17, 99, tft.color565(0, 128, 64)); //turq + tft.fillRect(26, 120, 17, 99, tft.color565(255, 128, 192)); //pink + tft.fillRect(44, 22, 17, 35, tft.color565(0, 128, 255)); //blue + tft.fillRect(44, 184, 17, 35, tft.color565(255, 128, 64)); //orng + tft.fillRect(260, 22, 17, 35, tft.color565(0, 128, 255)); //blue + tft.fillRect(260, 184, 17, 35, tft.color565(255, 128, 64)); //orng + tft.fillRect(278, 22, 17, 99, tft.color565(128, 128, 0)); //grn + tft.fillRect(278, 120, 17, 99, tft.color565(128, 0, 255)); //purp + + for (dx = 111; dx > -111; dx--) { + w = sqrt(111 * 111 - dx * dx); + y = 120 - dx; + dy = (y - 3) / 18; + mask = 7; + switch (dy) { + case 0: + case 1: idx = 1; len = 0; break; + case 2: idx = 0; len = 0; break; + case 3: idx = 0; len = 13; mask = 1; break; + case 4: + case 5: idx = 2; len = 38; break; + case 6: + case 7: + case 8: idx = 0; len = 0; break; + case 9: for (idx = 2; idx < 8; idx++) { + dy = 0xFF >> (7 - idx); + colors[idx] = tft.color565(dy, dy, dy); + } + idx = 2; len = 38; break; + case 10: idx = 1; len = 0; break; + case 11: + case 12: colors[2] = YELLOW; idx = 2; len = 0; break; + } + if (len == 0) + tft.fillRect(160 - w, y, w * 2, 1, colors[idx]); + + else { + if (mask == 1) idx = 1 + (w) / len; + dy = w % len; + for (x = 160 - w; x < 160 + w; idx++) { + tft.fillRect(x, y, dy, 1, colors[idx & mask]); + x += dy; + if (x + len > 160 + w) dy = w % len; + else dy = len; + } + } + + } + for (x = 72, y = 129, dx = 5, dy = 0; dx > 0; x += 2 * dx) { + tft.fillRect(x, y, dx, 36, WHITE); + dy += dx * 2; + if (dy >= 36) { + dy = 0; + dx--; + } + } + tft.fillRect(160 - 8, 5 * 18 + 3, 17, 3 * 18, BLACK); + for (x = 3 * 18 + 7, y = 6 * 18 + 3, w = 1, h = 18; x < 160 + 108; x += 18) { + tft.fillRect(x, y, w, h, WHITE); + } + tft.fillRect(160 - 108, 120, 108 * 2, 1, WHITE); + tft.fillRect(160, 5 * 18 + 3, 1, 3 * 18, WHITE); + tft.fillRect(108, 2 * 18 + 3, 6 * 18, 18, WHITE); + // tft.fillRect(108, 10 * 18 + 3, 6 * 18, 18, BLACK); + tft.fillRect(160 - 8, 11 * 18 + 3, 17, 31, RED); + tft.setCursor(160 - 36, 24 + ADJ_BASELINE); + tft.setTextColor(BLACK); + tft.setTextSize(1); + tft.print("320x240"); + tft.setCursor(109, 43 + ADJ_BASELINE); + tft.setTextColor(BLACK); + tft.setTextSize(1); + tft.print("ID=0x"); + tft.print(tft.readID(), HEX); + tft.setTextColor(WHITE, BLACK); + // tft.setFont(NULL); + // tft.setTextSize(2); + while (1) { + if (++ss > 59) { + ss = 0; + mm++; + if (mm > 59) { + mm = 0; + hh++; + if (hh > 23) hh = 0; + } + } + char buf[20]; + sprintf(buf, "%02d:%02d:%02d", hh, mm, ss); + tft.fillRect(108, 10 * 18 + 3, 6 * 18, 18, BLACK); + tft.setCursor(128, 187 + ADJ_BASELINE); + tft.print(buf); + delay(1000); + } +} + diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..e13ddc1 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,67 @@ +####################################### +# Syntax Coloring Map For Mcufriend_kbv +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +MCUFRIEND_kbv KEYWORD1 +#UTFTGLUE KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +#InitLCD KEYWORD2 +#LCD_Write_DATA KEYWORD2 +WriteCmdData KEYWORD2 +begin KEYWORD2 +#clrScr KEYWORD2 +color565 KEYWORD2 +#dispBitmap KEYWORD2 +#drawBitmap KEYWORD2 +drawCircle KEYWORD2 +drawFastHLine KEYWORD2 +drawFastVLine KEYWORD2 +drawLine KEYWORD2 +drawPixel KEYWORD2 +drawRect KEYWORD2 +drawRoundRect KEYWORD2 +fillCircle KEYWORD2 +fillRect KEYWORD2 +fillRoundRect KEYWORD2 +#fillScr KEYWORD2 +fillScreen KEYWORD2 +#getDisplayXSize KEYWORD2 +#getDisplayYSize KEYWORD2 +height KEYWORD2 +invertDisplay KEYWORD2 +#lcdOff KEYWORD2 +#lcdOn KEYWORD2 +#ltoa KEYWORD2 +#print KEYWORD2 +#printNumF KEYWORD2 +#printNumI KEYWORD2 +#println KEYWORD2 +pushColors KEYWORD2 +readGRAM KEYWORD2 +readID KEYWORD2 +readPixel KEYWORD2 +readReg KEYWORD2 +readReg32 KEYWORD2 +reset KEYWORD2 +setAddrWindow KEYWORD2 +#setBackColor KEYWORD2 +#setColor KEYWORD2 +#setContrast KEYWORD2 +setCursor KEYWORD2 +#setFont KEYWORD2 +setRotation KEYWORD2 +#setrgb KEYWORD2 +setTextColor KEYWORD2 +setTextSize KEYWORD2 +#settextcursor KEYWORD2 +vertScroll KEYWORD2 +width KEYWORD2 +#write_data_block KEYWORD2 diff --git a/mcufriend_kbv_2_8.txt b/mcufriend_kbv_2_8.txt new file mode 100644 index 0000000..aced41d --- /dev/null +++ b/mcufriend_kbv_2_8.txt @@ -0,0 +1,148 @@ +1. Install library from GitHub into your User libraries folder if not already there. + +2. Unzip the attached "MCUFRIEND_kbv.zip" into your User libraries folder. + +3. Insert your Mcufriend style display shield into UNO. + +4. Start your Arduino IDE. + +5. Build any of the Examples from the File->Examples->Mcufriend_kbv menu. +Most of them will write some text to the Serial window (9600 baud). The BMP examples require you to copy the pictures from the bitmaps/ folder to your microSD (root directory) + +6. This library is only intended for UNO and these specific Shields. It will work on a MEGA2560 but not very fast. + +7. The constructor takes no arguments (because it only works with these shields) + +8. The examples are the standard Adafruit ones. You can see my edits by searching for "kbv" + +9. Any Adafruit sketch should work with the MCUFRIEND_kbv constructor() but should allow extra ID values +An Adafruit constructor(cs, rs, wr, rd, rst) IGNORES any arguments. i.e. it only uses the shield control pins + +10. It currently supports UNO shields with "mcufriend.com" pcbs with controllers: +----- HX8347-A 240x320 ID=0x8347 new Untested +ILI9320 240x320 ID=0x9320 +ILI9325 240x320 ID=0x9325 +ILI9327 240x400 ID=0x9327 +ILI9329 240x320 ID=0x9329 +ILI9335 240x320 ID=0x9335 +ILI9341 240x320 ID=0x9341 +ILI9481 320x480 ID=0x9481 +ILI9486 320x480 ID=0x9486 +ILI9488 320x480 ID=0x9488 +LGDP4535 240x320 ID=0x4535 +RM68090 240x320 ID=0x6809 +R61505V 240x320 ID=0xB505 +R61505W 240x320 ID=0xC505 new Untested +R61509V 240x400 ID=0xB509 +----- S6D0139 240x320 ID=0x0139 removed due to lack of tester +S6D0154 240x320 ID=0x0154 +SPFD5408 240x320 ID=0x5408 +----- SSD1963 800x480 ID=0x1963 new Untested +SSD1289 240x320 ID=0x1289 +ST7781 240x320 ID=0x7783 +ST7789V 240x320 ID=0x7789 + +11. It should run on a UNO, MEGA2560, LEONARDO, DUE, ZERO and M0-PRO. + +12. These Mcufriend-style shields tend to have a resistive TouchScreen on A1, 7, A2, 6 but are not always the same rotation of direction. +Run the TouchScreen_Calibr_kbv.ino sketch to diagnose your model and then scale the result from TouchScreen.h methods() +The Resistive TouchScreen does not work on the Due. It seems to be upset by sharing pins. I have discovered why. +(You need a new Touch library.) + +13. The aspect_kbv.ino sketch should show the 4 different rotations. Please report the results for an ILI9335, ILI9327. + +14. The scroll_kbv.ino sketch should scroll a window or subwindow for most chips. Not all chips can scroll. + +15. The readpixel_kbv.ino sketch should display memory in each aspect. + +16. The GLUE_Demo_320x240.ino sketch uses a "GLUE" class to display a UTFT sketch on supported mcufriend shields. + It is NOT perfect. Please report any problems. It is designed as a CONVENIENCE for legacy UTFT code. + Please use MCUFRIEND_kbv method()s in new code. + +CHANGE HISTORY: + +Will Never Happen: + ILI9327 vertical scroll will ALWAYS be limited in Landscape and Portrait_Rev + ST7781 vert scroll is not implemented + ILI9320, 9325, ... can never vert scroll sub-window + Itead CPLD with ID=0x3082 ... will never work + +To Be Fixed: + GLUE Demo does not work with Due and IDE v1.6.6 + +v2.8: posted 26 February 2016 + MCUFRIEND_kbv.cpp: LANDSCAPE is now 90 degrees instead of 270 degrees + methods branch on MIPI / 9320 style + Added SPFD5408 + Added R61505W Untested + Added HX8347-A Untested + Added SSD1963 Untested + graphictest_kbv.ino: smaller buffer for Software Scroll. Just fits in Uno Flash + TouchScreen_Calibr_kbv: wait for consistent Touch + LCD_ID_readreg: Added some more registers + +v2.7: posted ........ NOT YET +v2.6: posted ........ NOT YET + MCUFRIEND_kbv.cpp: + Added R65105V + +v2.5: posted 11 January 2016 + MCUFRIEND_kbv.cpp: + Added ST7789V + Added RM68090 + Added ILI9481 + Added pushColors() from Flash + Improved downward Vertical Scroll. API is changed. + ILI9327 should work in all aspects. vertical scroll in PORT/LAND_REV + S6D0154 should vertical scroll a subwindow + + graphictest_kbv.ino: smooth colour gradation on rounded rectangle tests on bigger displays + added colour grading range. + added vertical scroll down + improve messages + + graphictest_slim.ino: reduced-fat version of graphictest_kbv.ino + testcard_kbv.ino: drawn version of common BMP photo. + scroll_kbv.ino: changed vertScroll() call for new API + + UTFTGLUE.h: improve calculate width and height of rectangles from coordinates. + +v2.4: posted 10 December 2015 + MCUFRIEND_kbv.cpp: LGDP4535 initialisation table fixed - UNTESTED + +v2.3: posted 8 December 2015 + MCUFRIEND_kbv.cpp: added S6D0139 UNTESTED + detect EXTC=0 ILI9341 shield from DX with ID == 0x0000. drive in RGB mode + ILI9327 should Vertical Scroll now. UNTESTED + UTFTGLUE.h: extra print(const char*) method to avoid warning messages + + graphictest_kbv.ino: software scroll a smaller block at top of screen + GLUE_Demo_320x240: removed unnecessary "include Adafruit_TFTLCD.h" + aspect_kbv.ino: invert display when in different aspects + readpixel_kbv.ino: support smaller geometries + LCD_ID_readreg.ino: report some more regs + TouchScreen_Calibr_kbv: for resistive Touch screens like on Mcufriend shields + UTouch_Calibr_kbv: can use UTouch.h library for hardware Touch Controllers (and UTFT) + +v2.2: posted 15 November 2015 + MCUFRIEND_kbv.cpp: changed readGRAM() for ILI9327, ILI9486, + added REV_SCREEN flag to _lcd_capable + implement invertDisplay() + added LGDP4535 + ILI9327: set Partial Area to 0, 399 + MCUFRIEND_kbv.h: USE_GFX_KBV default argument: println(char *s="") + MCUFRIEND_shield.h: regular Uno shield drivers for Uno, Mega, Leonardo, Due, Zero + MCUFRIEND_special.h: experimental drivers + UTFTGLUE.h: identity kludges for non-UNO shields + LCD_ID_readreg.ino: report reg(0x09) + +v2.1: posted 9 November 2015 + MCUFRIEND_kbv.cpp: return 0x9327 / 0x9481 in readID() + MCUFRIEND_shield.h: increase low pulse width in RD_STROBE + EXAMPLES/: add scroll_kbv.ino sketch + edit readpixel_kbv_ino, aspect_kbv.ino + +v2.0: posted 8 November 2015 + Massive changes from v1.0 + + diff --git a/mcufriend_serial.h b/mcufriend_serial.h new file mode 100644 index 0000000..93720ec --- /dev/null +++ b/mcufriend_serial.h @@ -0,0 +1,243 @@ +#if ARDUINO >= 165 +#include +#endif + +#if 0 +#elif defined(__AVR_ATmega328P__) + +#define SPI_INIT() { DDRB |= (1<<5)|(1<<3)|(1<<2); SPCR = (1<>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { dst = xchg8(0); } +#define READ_16(dst) { dst = xchg8(0); dst = (dst << 8) | xchg8(0); } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) +#elif defined(__SAMD21G18A__) + +#define SPI_INIT() { SPI.begin(); SPI.setDataMode(SPI_MODE0); SPI.setClockDivider(6); } + +#define CD_PORT PORT->Group[0] +#define CD_PIN 7 +#define CS_PORT PORT->Group[0] +#define CS_PIN 18 +#define RESET_PORT PORT->Group[0] +#define RESET_PIN 6 +#define RD_IDLE +#define WR_IDLE + + +uint8_t running; +static inline void write8(uint8_t c) +{ + running = 1; + while( SERCOM1->SPI.INTFLAG.bit.DRE == 0) ; + SERCOM1->SPI.DATA.bit.DATA = c; // Writing data into Data register +} + +static inline void flush(void) +{ + if (running) while( SERCOM1->SPI.INTFLAG.bit.TXC == 0) ; + running = 0; +} + +static inline uint8_t xchg8(uint8_t c) +{ +// flush(); + while( SERCOM1->SPI.INTFLAG.bit.RXC != 0) SERCOM1->SPI.DATA.bit.DATA; //eat up + while( SERCOM1->SPI.INTFLAG.bit.DRE == 0) ; + SERCOM1->SPI.DATA.bit.DATA = c; // Writing data into Data register + while( SERCOM1->SPI.INTFLAG.bit.RXC == 0) ; + return SERCOM1->SPI.DATA.bit.DATA; +} + + +#define setWriteDir() { } +#define setReadDir() { } +//#define flush() +//#define write8(x) xchg8(x) +//#define xchg8(x) SPI.transfer(x) +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { dst = xchg8(0); } +#define READ_16(dst) { dst = xchg8(0); dst = (dst << 8) | xchg8(0); } + +// Shield Control macros. +#define PIN_LOW(port, pin) (port).OUTCLR.reg = (1<<(pin)) +#define PIN_HIGH(port, pin) (port).OUTSET.reg = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port).DIR.reg |= (1<<(pin)) + +#elif defined(__AVR_ATxmega128A1__) //3.49s @ 32MHz -O2 + #define CD_PORT VPORT2 + #define CD_PIN 1 + #define CS_PORT VPORT3 + #define CS_PIN 4 + #define RESET_PORT VPORT2 + #define RESET_PIN 0 +#define SPCRVAL (USART_CLK2X_bm | USART_RXEN_bm | USART_TXEN_bm) +#define SETDDR {VPORT3.DIR |= (1<<4)|(1<<5)|(1<<7); VPORT2.DIR |= 0x03; } +#define SPI_INIT() { PORTCFG.VPCTRLB=PORTCFG_VP3MAP_PORTF_gc | PORTCFG_VP2MAP_PORTC_gc; CS_IDLE; RESET_IDLE; SETDDR; spi_init(); } + +void spi_init(void) +{ + SPIF.CTRL=SPI_ENABLE_bm | SPI_MODE_3_gc | (1<>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { dst = xchg8(0); } +#define READ_16(dst) { dst = xchg8(0); dst = (dst << 8) | xchg8(0); } + +#define PIN_LOW(p, b) (p).OUT &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p).OUT |= (1<<(b)) +#define PIN_OUTPUT(p, b) (p).DIR |= (1<<(b)) + +#endif + +#define CD_COMMAND {flush(); PIN_LOW(CD_PORT, CD_PIN); } +#define CD_DATA {flush(); PIN_HIGH(CD_PORT, CD_PIN); } +#define CD_OUTPUT PIN_OUTPUT(CD_PORT, CD_PIN) +#define CS_ACTIVE PIN_LOW(CS_PORT, CS_PIN) +#define CS_IDLE {flush(); PIN_HIGH(CS_PORT, CS_PIN); } +#define CS_OUTPUT PIN_OUTPUT(CS_PORT, CS_PIN) +#define RESET_ACTIVE PIN_LOW(RESET_PORT, RESET_PIN) +#define RESET_IDLE PIN_HIGH(RESET_PORT, RESET_PIN) +#define RESET_OUTPUT PIN_OUTPUT(RESET_PORT, RESET_PIN) + +// General macros. IOCLR registers are 1 cycle when optimised. + +#define CTL_INIT() { CD_OUTPUT; CS_OUTPUT; RESET_OUTPUT; SPI_INIT(); } +#define WriteCmd(x) { CD_COMMAND; write8(x); } +#define WriteData(x) { CD_DATA; write16(x); } diff --git a/mcufriend_shield.h b/mcufriend_shield.h new file mode 100644 index 0000000..3ddcb25 --- /dev/null +++ b/mcufriend_shield.h @@ -0,0 +1,262 @@ +#define USE_SPECIAL //check for custom drivers +#if defined(USE_SPECIAL) +#include "mcufriend_special.h" +#if !defined(USE_SPECIAL_FAIL) +#warning WE ARE USING A SPECIAL CUSTOM DRIVER +#endif +#endif +#if !defined(USE_SPECIAL) || defined (USE_SPECIAL_FAIL) + +#if 0 +#elif defined(__AVR_ATmega328P__) //regular UNO shield on UNO +#define RD_PORT PORTC +#define RD_PIN 0 +#define WR_PORT PORTC +#define WR_PIN 1 +#define CD_PORT PORTC +#define CD_PIN 2 +#define CS_PORT PORTC +#define CS_PIN 3 +#define RESET_PORT PORTC +#define RESET_PIN 4 + +#define DMASK 0x03 +#define NMASK ~DMASK +#define write_8(x) { PORTB = (PORTB & NMASK) | ((x) & DMASK); PORTD = (PORTD & DMASK) | ((x) & NMASK); } +#define read_8() ( (PINB & DMASK) | (PIND & NMASK) ) +#define setWriteDir() { DDRB = (DDRB & NMASK) | DMASK; DDRD = (DDRD & DMASK) | NMASK; } +#define setReadDir() { DDRB = (DDRB & NMASK) & NMASK; DDRD = (DDRD & DMASK) & DMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATmega2560__) //regular UNO shield on MEGA2560 +#define RD_PORT PORTF +#define RD_PIN 0 +#define WR_PORT PORTF +#define WR_PIN 1 +#define CD_PORT PORTF +#define CD_PIN 2 +#define CS_PORT PORTF +#define CS_PIN 3 +#define RESET_PORT PORTF +#define RESET_PIN 4 + +#define EMASK 0x38 +#define GMASK 0x20 +#define HMASK 0x78 +#define write_8(x) { PORTH &= ~HMASK; PORTG &= ~GMASK; PORTE &= ~EMASK; \ + PORTH |= (((x) & (3<<0)) << 5); \ + PORTE |= (((x) & (3<<2)) << 2); \ + PORTG |= (((x) & (1<<4)) << 1); \ + PORTE |= (((x) & (1<<5)) >> 2); \ + PORTH |= (((x) & (3<<6)) >> 3); \ + } + +#define read_8() ( ((PINH & (3<<5)) >> 5)\ + | ((PINE & (3<<4)) >> 2)\ + | ((PING & (1<<5)) >> 1)\ + | ((PINE & (1<<3)) << 2)\ + | ((PINH & (3<<3)) << 3)\ + ) +#define setWriteDir() { DDRH |= HMASK; DDRG |= GMASK; DDRE |= EMASK; } +#define setReadDir() { DDRH &= ~HMASK; DDRG &= ~GMASK; DDRE &= ~EMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__SAMD21G18A__) //regular UNO shield on ZERO or M0_PRO +#include "sam.h" + // configure macros for the control pins +#define RD_PORT PORT->Group[0] +#define RD_PIN 2 +#define WR_PORT PORT->Group[1] +#define WR_PIN 8 +#define CD_PORT PORT->Group[1] +#define CD_PIN 9 +#define CS_PORT PORT->Group[0] +#define CS_PIN 4 +#define RESET_PORT PORT->Group[0] +#define RESET_PIN 5 + // configure macros for data bus +#define DMASK 0x0030C3C0 + // #define write_8(x) PORT->Group[0].OUT.reg = (PORT->Group[0].OUT.reg & ~DMASK)|(((x) & 0x0F) << 6)|(((x) & 0x30) << 10)|(((x) & 0xC0)<<14) +#if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_ZERO) // American ZERO +#define write_8(x) {\ + PORT->Group[0].OUTCLR.reg = DMASK;\ + PORT->Group[0].OUTSET.reg = (((x) & 0x0B) << 6)\ + |(((x) & (1<<2)) << 12)\ + |(((x) & (1<<4)) << 4)\ + |(((x) & (1<<5)) << 10)\ + |(((x) & 0xC0) << 14);\ + } +#define read_8() (((PORT->Group[0].IN.reg >> 6) & 0x0B)\ + |((PORT->Group[0].IN.reg >> 12) & (1<<2))\ + |((PORT->Group[0].IN.reg >> 4) & (1<<4))\ + |((PORT->Group[0].IN.reg >> 10) & (1<<5))\ + |((PORT->Group[0].IN.reg >> 14) & 0xC0)) +#else //default to an M0_PRO on v1.6.5 or 1.7.6 +#define write_8(x) {\ + PORT->Group[0].OUTCLR.reg = DMASK;\ + PORT->Group[0].OUTSET.reg = (((x) & 0x0F) << 6)\ + |(((x) & 0x30) << 10)\ + |(((x) & 0xC0) << 14);\ + } +#define read_8() (((PORT->Group[0].IN.reg >> 6) & 0x0F)|((PORT->Group[0].IN.reg >> 10) & 0x30)|((PORT->Group[0].IN.reg >> 14) & 0xC0)) +#endif +#define setWriteDir() { PORT->Group[0].DIRSET.reg = DMASK; \ + PORT->Group[0].WRCONFIG.reg = (DMASK & 0xFFFF) | (0<<22) | (1<<28) | (1<<30); \ + PORT->Group[0].WRCONFIG.reg = (DMASK>>16) | (0<<22) | (1<<28) | (1<<30) | (1<<31); \ + } +#define setReadDir() { PORT->Group[0].DIRCLR.reg = DMASK; \ + PORT->Group[0].WRCONFIG.reg = (DMASK & 0xFFFF) | (1<<17) | (1<<28) | (1<<30); \ + PORT->Group[0].WRCONFIG.reg = (DMASK>>16) | (1<<17) | (1<<28) | (1<<30) | (1<<31); \ + } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + // Shield Control macros. +#define PIN_LOW(port, pin) (port).OUTCLR.reg = (1<<(pin)) +#define PIN_HIGH(port, pin) (port).OUTSET.reg = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port).DIR.reg |= (1<<(pin)) + +#elif defined(__SAM3X8E__) //regular UNO shield on DUE + // configure macros for the control pins +#define RD_PORT PIOA +#define RD_PIN 16 +#define WR_PORT PIOA +#define WR_PIN 24 +#define CD_PORT PIOA +#define CD_PIN 23 +#define CS_PORT PIOA +#define CS_PIN 22 +#define RESET_PORT PIOA +#define RESET_PIN 6 + // configure macros for data bus +#define BMASK (1<<25) +#define CMASK (0xBF << 21) +#define write_8(x) { PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; \ + PIOC->PIO_SODR = (((x) & (1<<0)) << 22); \ + PIOC->PIO_SODR = (((x) & (1<<1)) << 20); \ + PIOB->PIO_SODR = (((x) & (1<<2)) << 23); \ + PIOC->PIO_SODR = (((x) & (1<<3)) << 25); \ + PIOC->PIO_SODR = (((x) & (1<<4)) << 22); \ + PIOC->PIO_SODR = (((x) & (1<<5)) << 20); \ + PIOC->PIO_SODR = (((x) & (1<<6)) << 18); \ + PIOC->PIO_SODR = (((x) & (1<<7)) << 16); \ + } + +#define read_8() ( ((PIOC->PIO_PDSR & (1<<22)) >> 22)\ + | ((PIOC->PIO_PDSR & (1<<21)) >> 20)\ + | ((PIOB->PIO_PDSR & (1<<25)) >> 23)\ + | ((PIOC->PIO_PDSR & (1<<28)) >> 25)\ + | ((PIOC->PIO_PDSR & (1<<26)) >> 22)\ + | ((PIOC->PIO_PDSR & (1<<25)) >> 20)\ + | ((PIOC->PIO_PDSR & (1<<24)) >> 18)\ + | ((PIOC->PIO_PDSR & (1<<23)) >> 16)\ + ) +#define setWriteDir() { PIOB->PIO_OER = BMASK; PIOC->PIO_OER = CMASK; } +#define setReadDir() { \ + PMC->PMC_PCER0 = (1 << ID_PIOB)|(1 << ID_PIOC);\ + PIOB->PIO_ODR = BMASK; PIOC->PIO_ODR = CMASK;\ + } +#define write8(x) { write_8(x); WR_ACTIVE; WR_STROBE; WR_IDLE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; RD_ACTIVE; dst = read_8(); RD_IDLE; RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + // Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) + +#elif defined(__AVR_ATmega32U4__) //regular UNO shield on Leonardo +#define RD_PORT PORTF +#define RD_PIN 7 +#define WR_PORT PORTF +#define WR_PIN 6 +#define CD_PORT PORTF +#define CD_PIN 5 +#define CS_PORT PORTF +#define CS_PIN 4 +#define RESET_PORT PORTF +#define RESET_PIN 1 + +#define BMASK (3<<4) +#define CMASK (1<<6) +#define DMASK ((1<<7)|(1<<4)|(3<<0)) +#define EMASK (1<<6) +static inline //hope we use r24 +void write_8(uint8_t x) +{ + PORTB &= ~BMASK; + PORTC &= ~CMASK; + PORTD &= ~DMASK; + PORTE &= ~EMASK; + PORTB |= (((x) & (3 << 0)) << 4); + PORTD |= (((x) & (1 << 2)) >> 1); + PORTD |= (((x) & (1 << 3)) >> 3); + PORTD |= (((x) & (1 << 4)) << 0); + PORTC |= (((x) & (1 << 5)) << 1); + PORTD |= (((x) & (1 << 6)) << 1); + PORTE |= (((x) & (1 << 7)) >> 1); +} + +#define read_8() ( ((PINB & (3<<4)) >> 4)\ +| ((PIND & (1<<1)) << 1)\ +| ((PIND & (1<<0)) << 3)\ +| ((PIND & (1<<4)) >> 0)\ +| ((PINC & (1<<6)) >> 1)\ +| ((PIND & (1<<7)) >> 1)\ +| ((PINE & (1<<6)) << 1)\ +) +#define setWriteDir() { DDRB |= BMASK; DDRC |= CMASK; DDRD |= DMASK; DDRE |= EMASK; } +#define setReadDir() { DDRB &= ~BMASK; DDRC &= ~CMASK; DDRD &= ~DMASK; DDRE &= ~EMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#else +#error MCU unsupported +#endif // regular UNO shields on Arduino boards + +#endif //!defined(USE_SPECIAL) || defined (USE_SPECIAL_FAIL) + +#define RD_ACTIVE PIN_LOW(RD_PORT, RD_PIN) +#define RD_IDLE PIN_HIGH(RD_PORT, RD_PIN) +#define RD_OUTPUT PIN_OUTPUT(RD_PORT, RD_PIN) +#define WR_ACTIVE PIN_LOW(WR_PORT, WR_PIN) +#define WR_IDLE PIN_HIGH(WR_PORT, WR_PIN) +#define WR_OUTPUT PIN_OUTPUT(WR_PORT, WR_PIN) +#define CD_COMMAND PIN_LOW(CD_PORT, CD_PIN) +#define CD_DATA PIN_HIGH(CD_PORT, CD_PIN) +#define CD_OUTPUT PIN_OUTPUT(CD_PORT, CD_PIN) +#define CS_ACTIVE PIN_LOW(CS_PORT, CS_PIN) +#define CS_IDLE PIN_HIGH(CS_PORT, CS_PIN) +#define CS_OUTPUT PIN_OUTPUT(CS_PORT, CS_PIN) +#define RESET_ACTIVE PIN_LOW(RESET_PORT, RESET_PIN) +#define RESET_IDLE PIN_HIGH(RESET_PORT, RESET_PIN) +#define RESET_OUTPUT PIN_OUTPUT(RESET_PORT, RESET_PIN) + + // General macros. IOCLR registers are 1 cycle when optimised. +#define WR_STROBE { WR_ACTIVE; WR_IDLE; } //PWLW=TWRL=50ns +#define RD_STROBE RD_IDLE, RD_ACTIVE, RD_ACTIVE, RD_ACTIVE //PWLR=TRDL=150ns, tDDR=100ns + +#define CTL_INIT() { RD_OUTPUT; WR_OUTPUT; CD_OUTPUT; CS_OUTPUT; RESET_OUTPUT; } +#define WriteCmd(x) { CD_COMMAND; write16(x); } +#define WriteData(x) { CD_DATA; write16(x); } diff --git a/mcufriend_special.h b/mcufriend_special.h new file mode 100644 index 0000000..3319c87 --- /dev/null +++ b/mcufriend_special.h @@ -0,0 +1,680 @@ +#define SSD1289_JUMPERS 2 //Uno Shield with VERY different pin-out to Mcufriend +// only define one "USE_XXX" macro at any time +//#define USE_SSD1289_SHIELD_UNO +//#define USE_SSD1289_SHIELD_MEGA +//#define USE_SSD1289_SHIELD_DUE +//#define USE_MEGA_8BIT_PROTOSHIELD +#define USE_MEGA_16BIT_SHIELD //RD on PL6 (D43) +//#define USE_BLD_BST_MEGA32U4 +//#define USE_BLD_BST_MEGA2560 +//#define USE_DUE_8BIT_PROTOSHIELD +//#define USE_DUE_16BIT_SHIELD //RD on PA15 (D24) + +#if 0 +#elif defined(__AVR_ATmega328P__) && defined(USE_SSD1289_SHIELD_UNO) //on UNO +#warning using SSD1289 Shield for mega328 +#define RD_PORT PORTC +#define RD_PIN 3 +#define WR_PORT PORTC +#define WR_PIN 2 +#define CD_PORT PORTC +#define CD_PIN 1 +#define CS_PORT PORTC +#define CS_PIN 0 +#define RESET_PORT PORTB +#define RESET_PIN 1 //actually SD_CS + +// SSD1289 shield has LCD_D0 on RXD0. Fine for write-only +// For any Read operations, put jumper from D0 to D8, Switch #2 to OFF. +// If using Serial, jumper D1 to A5, Switch #1 to OFF +#if SSD1289_JUMPERS == 0 +#warning no jumpers. Switch #1=ON, #2=ON +#define BMASK 0x00 //0x00 for output, 0x01 for Read + Serial +#define CMASK 0x00 //0x20 for Read + Serial +#define DMASK (~BMASK) +#define write8(x) { PORTD = x; WR_STROBE; } +#define read_8() ( PIND ) +#elif SSD1289_JUMPERS == 1 +#warning jumper D0 to D8. Switch #1=ON, #2=OFF +#define BMASK 0x01 //0x00 for output, 0x01 for Read + Serial +#define CMASK 0x00 //0x20 for Read + Serial +#define DMASK (~BMASK) +#define write8(x) { PORTD = (PORTD & ~DMASK) | (x & DMASK); PORTB = (PORTB & ~BMASK) | (x & BMASK); WR_STROBE; } +#define read_8() ( (PIND & DMASK)|(PINB & BMASK) ) +#elif SSD1289_JUMPERS == 2 +#warning jumper D0 to D8, D1 to A5. Switch #1=OFF, #2=OFF +#define BMASK (1<<0) //0x00 for output, 0x01 for Read + Serial +#define CMASK (1<<5) //0x20 for Read + Serial +#define DMASK (0xFC) +#define write8(x) { PORTC = (PORTC & ~CMASK) | ((x<<4) & CMASK);\ + PORTD = (PORTD & ~DMASK) | (x & DMASK);\ + PORTB = (PORTB & ~BMASK) | (x & BMASK); WR_STROBE; } +#define read_8() ( ((PINC & CMASK)>>4)|(PIND & DMASK)|(PINB & BMASK) ) +#endif +#define setWriteDir() { DDRC |= CMASK; DDRD |= DMASK; DDRB |= BMASK; } +#define setReadDir() { DDRC &= ~CMASK; DDRD &= ~DMASK; DDRB &= ~BMASK; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATxmega128A1__) // Home made shield with Xplained +#warning Home made shield with Xplained +#define RD_PORT VPORT3 +#define RD_PIN 0 +#define WR_PORT VPORT3 +#define WR_PIN 1 +#define CD_PORT VPORT3 +#define CD_PIN 2 +#define CS_PORT VPORT3 +#define CS_PIN 3 +#define RESET_PORT VPORT3 +#define RESET_PIN 4 + +// VPORTs are very fast. CBI, SBI are only one cycle. Hence all those RD_ACTIVEs +// ILI9320 data sheet says tDDR=100ns. We need 218ns to read REGs correctly. +#define write_8(x) { VPORT2.OUT = x; } +#define read_8() ( VPORT2.IN ) +#define setWriteDir() { PORTCFG.VPCTRLB=PORTCFG_VP3MAP_PORTF_gc | PORTCFG_VP2MAP_PORTC_gc; VPORT2.DIR = 0xFF; } +#define setReadDir() { VPORT2.DIR = 0x00; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p).OUT &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p).OUT |= (1<<(b)) +#define PIN_OUTPUT(p, b) (p).DIR |= (1<<(b)) +#elif defined(__AVR_ATxmega32A4U__) // Home made shield with Batsocks module +#warning Home made shield with Batsocks module +#define RD_PORT VPORT3 +#define RD_PIN 0 +#define WR_PORT VPORT3 +#define WR_PIN 1 +#define CD_PORT VPORT3 +#define CD_PIN 2 +#define CS_PORT VPORT3 +#define CS_PIN 3 +#define RESET_PORT PORTE +#define RESET_PIN 0 + +// VPORTs are very fast. CBI, SBI are only one cycle. Hence all those RD_ACTIVEs +// ILI9320 data sheet says tDDR=100ns. We need 218ns to read REGs correctly. +// S6D0154 data sheet says tDDR=250ns. We need ~500ns to read REGs correctly. +#define write_8(x) { VPORT2.OUT = x; } +#define read_8() ( VPORT2.IN ) +#define setWriteDir() { PORTCFG.VPCTRLB=PORTCFG_VP13MAP_PORTB_gc | PORTCFG_VP02MAP_PORTC_gc; VPORT2.DIR = 0xFF; } +#define setReadDir() { VPORT2.DIR = 0x00; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } + +#define PIN_LOW(p, b) (p).OUT &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p).OUT |= (1<<(b)) +#define PIN_OUTPUT(p, b) (p).DIR |= (1<<(b)) + +#elif defined(__AVR_ATmega2560__) && defined(USE_BLD_BST_MEGA2560) //regular UNO shield on MEGA2560 using BLD/BST +#warning regular UNO shield on MEGA2560 using BLD/BST +#define RD_PORT PORTF +#define RD_PIN 0 +#define WR_PORT PORTF +#define WR_PIN 1 +#define CD_PORT PORTF +#define CD_PIN 2 +#define CS_PORT PORTF +#define CS_PIN 3 +#define RESET_PORT PORTF +#define RESET_PIN 4 + +#define EMASK 0x38 +#define GMASK 0x20 +#define HMASK 0x78 +static inline void write_8(uint8_t val) +{ + asm volatile("lds __tmp_reg__,0x0102" "\n\t" + "BST %0,0" "\n\t" "BLD __tmp_reg__,5" "\n\t" + "BST %0,1" "\n\t" "BLD __tmp_reg__,6" "\n\t" + "BST %0,6" "\n\t" "BLD __tmp_reg__,3" "\n\t" + "BST %0,7" "\n\t" "BLD __tmp_reg__,4" "\n\t" + "sts 0x0102,__tmp_reg__" : : "a" (val)); + asm volatile("in __tmp_reg__,0x0E" "\n\t" + "BST %0,2" "\n\t" "BLD __tmp_reg__,4" "\n\t" + "BST %0,3" "\n\t" "BLD __tmp_reg__,5" "\n\t" + "BST %0,5" "\n\t" "BLD __tmp_reg__,3" "\n\t" + "out 0x0E,__tmp_reg__" : : "a" (val)); + asm volatile("in __tmp_reg__,0x14" "\n\t" + "BST %0,4" "\n\t" "BLD __tmp_reg__,5" "\n\t" + "out 0x14,__tmp_reg__" : : "a" (val)); +} + +#define read_8() ( ((PINH & (3<<5)) >> 5)\ +| ((PINE & (3<<4)) >> 2)\ +| ((PING & (1<<5)) >> 1)\ +| ((PINE & (1<<3)) << 2)\ +| ((PINH & (3<<3)) << 3)\ +) +#define setWriteDir() { DDRH |= HMASK; DDRG |= GMASK; DDRE |= EMASK; } +#define setReadDir() { DDRH &= ~HMASK; DDRG &= ~GMASK; DDRE &= ~EMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { RD_STROBE; dst = read_8(); RD_IDLE; RD_STROBE; dst = (dst<<8) | read_8(); RD_IDLE; } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATmega2560__) && defined(USE_SSD1289_SHIELD_MEGA) //on MEGA2560 +#warning using SSD1289 Shield for mega2560 +#define RD_PORT PORTF +#define RD_PIN 3 //A3 +#define WR_PORT PORTF +#define WR_PIN 2 //A2 +#define CD_PORT PORTF +#define CD_PIN 1 //A1 +#define CS_PORT PORTF +#define CS_PIN 0 //A0 +#define RESET_PORT PORTH +#define RESET_PIN 6 //D9 DS_CS, D10=T_CS, D9=SD_CS, D8=n.c. + +// only for SSD1289 data bus on D2..D9 UNTESTED +#if (SSD1289_JUMPERS == 0) //Switch #1=ON, #2=ON +#warning no jumpers Switch #1=ON, #2=ON +#define EMASK 0x3B +#define FMASK 0x00 +#define HMASK 0x18 +#define GMASK 0x20 +#define write_8(x) { PORTH &= ~HMASK; PORTG &= ~GMASK; PORTE &= ~EMASK; \ + PORTE |= (((x) & (1<<0)) << 0); \ + PORTE |= (((x) & (1<<1)) << 0); \ + PORTE |= (((x) & (3<<2)) << 2); \ + PORTG |= (((x) & (1<<4)) << 1); \ + PORTE |= (((x) & (1<<5)) >> 2); \ + PORTH |= (((x) & (3<<6)) >> 3); \ +} + +#define read_8() ( ((PINE & (1<<0)) >> 0)\ + | ((PINE & (1<<1)) >> 0)\ + | ((PINE & (3<<4)) >> 2)\ + | ((PING & (1<<5)) >> 1)\ + | ((PINE & (1<<3)) << 2)\ + | ((PINH & (3<<3)) << 3)\ + ) +#elif (SSD1289_JUMPERS == 1) //jumper D0 to D8. Switch #1=ON, #2=OFF +#warning jumper D0 to D8. Switch #1=ON, #2=OFF +#define EMASK 0x3A +#define FMASK 0x00 +#define HMASK 0x38 +#define GMASK 0x20 +#define write_8(x) { PORTH &= ~HMASK; PORTG &= ~GMASK; PORTE &= ~EMASK; \ + PORTH |= (((x) & (1<<0)) << 5); \ + PORTE |= (((x) & (1<<1)) << 0); \ + PORTE |= (((x) & (3<<2)) << 2); \ + PORTG |= (((x) & (1<<4)) << 1); \ + PORTE |= (((x) & (1<<5)) >> 2); \ + PORTH |= (((x) & (3<<6)) >> 3); \ +} + +#define read_8() ( ((PINH & (1<<5)) >> 5)\ + | ((PINE & (1<<1)) >> 0)\ + | ((PINE & (3<<4)) >> 2)\ + | ((PING & (1<<5)) >> 1)\ + | ((PINE & (1<<3)) << 2)\ + | ((PINH & (3<<3)) << 3)\ + ) +#elif (SSD1289_JUMPERS == 2) //jumper D0 to D8, D1 to A5. Switch #1=OFF, #2=OFF +#warning jumper D0 to D8, D1 to A5. Switch #1=OFF, #2=OFF +#define FMASK 0x20 +#define EMASK 0x38 +#define HMASK 0x38 +#define GMASK 0x20 +#define write_8(x) { PORTH &= ~HMASK; PORTG &= ~GMASK; PORTF &= ~FMASK; PORTE &= ~EMASK; \ + PORTH |= (((x) & (1<<0)) << 5); \ + PORTF |= (((x) & (1<<1)) << 4); \ + PORTE |= (((x) & (3<<2)) << 2); \ + PORTG |= (((x) & (1<<4)) << 1); \ + PORTE |= (((x) & (1<<5)) >> 2); \ + PORTH |= (((x) & (3<<6)) >> 3); \ +} + +#define read_8() ( ((PINH & (1<<5)) >> 5)\ + | ((PINF & (1<<5)) >> 4)\ + | ((PINE & (3<<4)) >> 2)\ + | ((PING & (1<<5)) >> 1)\ + | ((PINE & (1<<3)) << 2)\ + | ((PINH & (3<<3)) << 3)\ + ) +#endif +#define setWriteDir() { DDRH |= HMASK; DDRG |= GMASK; DDRF |= FMASK; DDRE |= EMASK; } +#define setReadDir() { DDRH &= ~HMASK; DDRG &= ~GMASK; DDRF &= ~FMASK; DDRE &= ~EMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { RD_STROBE; dst = read_8(); RD_IDLE; RD_STROBE; dst = (dst<<8) | read_8(); RD_IDLE; } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATmega2560__) && defined(USE_MEGA_16BIT_SHIELD) +#warning USE_MEGA_16BIT_SHIELD +#define RD_PORT PORTL +#define RD_PIN 6 //PL6 (D43). Graham has PA15 (D24) on Due Shield +#define WR_PORT PORTG +#define WR_PIN 2 //D39 CTE +#define CD_PORT PORTD +#define CD_PIN 7 //D38 CTE +#define CS_PORT PORTG +#define CS_PIN 1 //D40 CTE +#define RESET_PORT PORTG +#define RESET_PIN 0 //D41 CTE + +#define write_8(x) { PORTC = x; } +#define write_16(x) { PORTA = (x) >> 8; PORTC = x; } + +#define read_16() ( (PINA<<8) | (PINC) ) +#define setWriteDir() { DDRC = 0xFF; DDRA = 0xff; } +#define setReadDir() { DDRC = 0x00; DDRA = 0x00; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { write_16(x); WR_STROBE; } +#define READ_16(dst) { RD_STROBE; dst = read_16(); RD_IDLE; } +#define READ_8(dst) { READ_16(dst); dst &= 0xFFFF; } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATmega2560__) && defined(USE_MEGA_8BIT_PROTOSHIELD) +#warning USE_MEGA_8BIT_PROTOSHIELD +#define RD_PORT PORTF +#define RD_PIN 0 +#define WR_PORT PORTF +#define WR_PIN 1 +#define CD_PORT PORTF +#define CD_PIN 2 +#define CS_PORT PORTF +#define CS_PIN 3 +#define RESET_PORT PORTF +#define RESET_PIN 4 + +#define write_8(x) { PORTA = x;} + +#define read_8() ( PINA ) +#define setWriteDir() { DDRA = 0xFF; } +#define setReadDir() { DDRA = 0x00; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { RD_STROBE; dst = read_8(); RD_IDLE; RD_STROBE; dst = (dst<<8) | read_8(); RD_IDLE; } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__AVR_ATmega32U4__) && defined(USE_BLD_BST_MEGA32U4) //regular UNO shield on Leonardo using BST/BLD +#warning regular UNO shield on Leonardo using BST/BLD +#define RD_PORT PORTF +#define RD_PIN 7 +#define WR_PORT PORTF +#define WR_PIN 6 +#define CD_PORT PORTF +#define CD_PIN 5 +#define CS_PORT PORTF +#define CS_PIN 4 +#define RESET_PORT PORTF +#define RESET_PIN 1 + +#define BMASK (3<<4) +#define CMASK (1<<6) +#define DMASK ((1<<7)|(1<<4)|(3<<0)) +#define EMASK (1<<6) +static inline void write_8(uint8_t val) +{ + asm volatile("in __tmp_reg__,0x05" "\n\t" + "BST %0,0" "\n\t" "BLD __tmp_reg__,4" "\n\t" + "BST %0,1" "\n\t" "BLD __tmp_reg__,5" "\n\t" + "out 0x05,__tmp_reg__" : : "a" (val)); + asm volatile("in __tmp_reg__,0x0B" "\n\t" + "BST %0,2" "\n\t" "BLD __tmp_reg__,1" "\n\t" + "BST %0,3" "\n\t" "BLD __tmp_reg__,0" "\n\t" + "BST %0,4" "\n\t" "BLD __tmp_reg__,4" "\n\t" + "BST %0,6" "\n\t" "BLD __tmp_reg__,7" "\n\t" + "out 0x0B,__tmp_reg__" : : "a" (val)); + asm volatile("in __tmp_reg__,0x08" "\n\t" + "BST %0,5" "\n\t" "BLD __tmp_reg__,6" "\n\t" + "out 0x08,__tmp_reg__" : : "a" (val)); + asm volatile("in __tmp_reg__,0x0E" "\n\t" + "BST %0,7" "\n\t" "BLD __tmp_reg__,6" "\n\t" + "out 0x0E,__tmp_reg__" : : "a" (val)); +} +#define read_8() ( ((PINB & (3<<4)) >> 4)\ +| ((PIND & (1<<1)) << 1)\ +| ((PIND & (1<<0)) << 3)\ +| ((PIND & (1<<4)) >> 0)\ +| ((PINC & (1<<6)) >> 1)\ +| ((PIND & (1<<7)) >> 1)\ +| ((PINE & (1<<6)) << 1)\ +) +#define setWriteDir() { DDRB |= BMASK; DDRC |= CMASK; DDRD |= DMASK; DDRE |= EMASK; } +#define setReadDir() { DDRB &= ~BMASK; DDRC &= ~CMASK; DDRD &= ~DMASK; DDRE &= ~EMASK; } +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { RD_STROBE; dst = read_8(); RD_IDLE; RD_STROBE; dst = (dst<<8) | read_8(); RD_IDLE; } + +#define PIN_LOW(p, b) (p) &= ~(1<<(b)) +#define PIN_HIGH(p, b) (p) |= (1<<(b)) +#define PIN_OUTPUT(p, b) *(&p-1) |= (1<<(b)) + +#elif defined(__SAMD21J18A__) //regular UNO shield on D21_XPRO +#warning regular UNO shield on D21_XPRO +#include "samd21.h" +// configure macros for the control pins +#define RD_PORT PORT->Group[1] +#define RD_PIN 0 +#define WR_PORT PORT->Group[1] +#define WR_PIN 1 +#define CD_PORT PORT->Group[0] +#define CD_PIN 10 +#define CS_PORT PORT->Group[0] +#define CS_PIN 11 +#define RESET_PORT PORT->Group[0] +#define RESET_PIN 8 +// configure macros for data bus +#define AMASK 0x00220000 +#define BMASK 0x0000C0E4 +#define write_8(d) { \ + PORT->Group[0].OUT.reg = (PORT->Group[0].OUT.reg & ~AMASK) \ + | (((d) & (1<<5)) << 16) \ + | (((d) & (1<<7)) << 10); \ + PORT->Group[1].OUT.reg = (PORT->Group[1].OUT.reg & ~BMASK) \ + | (((d) & (3<<0)) << 6) \ + | (((d) & (1<<2)) << 12) \ + | (((d) & (1<<3)) >> 1) \ + | (((d) & (1<<4)) << 1) \ + | (((d) & (1<<6)) << 9); \ +} +#define read_8() ( (((PORT->Group[0].IN.reg & (1<<21)) >> 16) \ +| ((PORT->Group[0].IN.reg & (1<<17)) >> 10) \ +| ((PORT->Group[1].IN.reg & (3<<6)) >> 6) \ +| ((PORT->Group[1].IN.reg & (1<<14)) >> 12) \ +| ((PORT->Group[1].IN.reg & (1<<2)) << 1) \ +| ((PORT->Group[1].IN.reg & (1<<5)) >> 1) \ +| ((PORT->Group[1].IN.reg & (1<<15)) >> 9))) +#define setWriteDir() { \ + PORT->Group[0].DIRSET.reg = AMASK; \ + PORT->Group[1].DIRSET.reg = BMASK; \ + PORT->Group[0].WRCONFIG.reg = (AMASK>>16) | (0<<22) | (0<<28) | (1<<30) | (1<<31); \ + PORT->Group[1].WRCONFIG.reg = (BMASK & 0xFFFF) | (0<<22) | (0<<28) | (1<<30); \ +} +#define setReadDir() { \ + PORT->Group[0].DIRCLR.reg = AMASK; \ + PORT->Group[1].DIRCLR.reg = BMASK; \ + PORT->Group[0].WRCONFIG.reg = (AMASK>>16) | (1<<17) | (0<<28) | (1<<30) | (1<<31); \ + PORT->Group[1].WRCONFIG.reg = (BMASK & 0xFFFF) | (1<<17) | (0<<28) | (1<<30); \ +} + +#define write8(x) { write_8(x); WR_STROBE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; dst = read_8(); RD_IDLE; } +#define READ_16(dst) { RD_STROBE; dst = read_8(); RD_IDLE; RD_STROBE; dst = (dst<<8) | read_8(); RD_IDLE; } +// Shield Control macros. +#define PIN_LOW(port, pin) (port).OUTCLR.reg = (1<<(pin)) +#define PIN_HIGH(port, pin) (port).OUTSET.reg = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port).DIR.reg |= (1<<(pin)) + +#elif defined(__SAM3X8E__) && defined(USE_SSD1289_SHIELD_DUE) // on DUE +#warning USE_SSD1289_SHIELD_DUE +// configure macros for the control pins +#define RD_PORT PIOA +#define RD_PIN 22 //A3 +#define WR_PORT PIOA +#define WR_PIN 23 //A2 +#define CD_PORT PIOA +#define CD_PIN 24 //A1 +#define CS_PORT PIOA +#define CS_PIN 16 //A0 +#define RESET_PORT PIOC +#define RESET_PIN 21 //D9 Touch CS +// configure macros for data bus +// only for SSD1289 data bus on D2..D9 UNTESTED +#if SSD1289_JUMPERS == 0 +#warning no jumpers Switch #1=ON, #2=ON +#define AMASK (3<<8) +#define BMASK (1<<25) +#define CMASK (0xBC << 21) +#define write_8(x) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; \ + PIOA->PIO_SODR = (((x) & (1<<0)) << 8); \ + PIOA->PIO_SODR = (((x) & (1<<1)) << 8); \ + PIOB->PIO_SODR = (((x) & (1<<2)) << 23); \ + PIOC->PIO_SODR = (((x) & (1<<3)) << 25); \ + PIOC->PIO_SODR = (((x) & (1<<4)) << 22); \ + PIOC->PIO_SODR = (((x) & (1<<5)) << 20); \ + PIOC->PIO_SODR = (((x) & (1<<6)) << 18); \ + PIOC->PIO_SODR = (((x) & (1<<7)) << 16); \ +} + +#define read_8() ( ((PIOA->PIO_PDSR & (1<<8)) >> 8)\ + | ((PIOA->PIO_PDSR & (1<<9)) >> 8)\ + | ((PIOB->PIO_PDSR & (1<<25)) >> 23)\ + | ((PIOC->PIO_PDSR & (1<<28)) >> 25)\ + | ((PIOC->PIO_PDSR & (1<<26)) >> 22)\ + | ((PIOC->PIO_PDSR & (1<<25)) >> 20)\ + | ((PIOC->PIO_PDSR & (1<<24)) >> 18)\ + | ((PIOC->PIO_PDSR & (1<<23)) >> 16)\ + ) +#elif SSD1289_JUMPERS == 1 +#warning jumper D0 to D8. Switch #1=ON, #2=OFF +#define AMASK (1<<9) +#define BMASK (1<<25) +#define CMASK (0xBE << 21) +#define write_8(x) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; \ + PIOC->PIO_SODR = (((x) & (1<<0)) << 22); \ + PIOA->PIO_SODR = (((x) & (1<<1)) << 8); \ + PIOB->PIO_SODR = (((x) & (1<<2)) << 23); \ + PIOC->PIO_SODR = (((x) & (1<<3)) << 25); \ + PIOC->PIO_SODR = (((x) & (1<<4)) << 22); \ + PIOC->PIO_SODR = (((x) & (1<<5)) << 20); \ + PIOC->PIO_SODR = (((x) & (1<<6)) << 18); \ + PIOC->PIO_SODR = (((x) & (1<<7)) << 16); \ +} + +#define read_8() ( ((PIOC->PIO_PDSR & (1<<22)) >> 22)\ +| ((PIOA->PIO_PDSR & (1<<9)) >> 8)\ +| ((PIOB->PIO_PDSR & (1<<25)) >> 23)\ +| ((PIOC->PIO_PDSR & (1<<28)) >> 25)\ +| ((PIOC->PIO_PDSR & (1<<26)) >> 22)\ +| ((PIOC->PIO_PDSR & (1<<25)) >> 20)\ +| ((PIOC->PIO_PDSR & (1<<24)) >> 18)\ +| ((PIOC->PIO_PDSR & (1<<23)) >> 16)\ +) +#elif SSD1289_JUMPERS == 2 +#warning jumper D0 to D8, D1 to A5. Switch #1=OFF, #2=OFF +#define AMASK (1<<4) +#define BMASK (1<<25) +#define CMASK (0xBE << 21) +#define write_8(x) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; \ + PIOC->PIO_SODR = (((x) & (1<<0)) << 22); \ + PIOA->PIO_SODR = (((x) & (1<<1)) << 3); \ + PIOB->PIO_SODR = (((x) & (1<<2)) << 23); \ + PIOC->PIO_SODR = (((x) & (1<<3)) << 25); \ + PIOC->PIO_SODR = (((x) & (1<<4)) << 22); \ + PIOC->PIO_SODR = (((x) & (1<<5)) << 20); \ + PIOC->PIO_SODR = (((x) & (1<<6)) << 18); \ + PIOC->PIO_SODR = (((x) & (1<<7)) << 16); \ + } + +#define read_8() ( ((PIOC->PIO_PDSR & (1<<22)) >> 22)\ + | ((PIOA->PIO_PDSR & (1<<4)) >> 3)\ + | ((PIOB->PIO_PDSR & (1<<25)) >> 23)\ + | ((PIOC->PIO_PDSR & (1<<28)) >> 25)\ + | ((PIOC->PIO_PDSR & (1<<26)) >> 22)\ + | ((PIOC->PIO_PDSR & (1<<25)) >> 20)\ + | ((PIOC->PIO_PDSR & (1<<24)) >> 18)\ + | ((PIOC->PIO_PDSR & (1<<23)) >> 16)\ + ) +#endif +#define setWriteDir() { PIOA->PIO_OER = AMASK; PIOB->PIO_OER = BMASK; PIOC->PIO_OER = CMASK; } +#define setReadDir() { \ + PMC->PMC_PCER0 = (1 << ID_PIOA)|(1 << ID_PIOB)|(1 << ID_PIOC);\ + PIOA->PIO_ODR = AMASK; PIOB->PIO_ODR = BMASK; PIOC->PIO_ODR = CMASK;\ +} +#define write8(x) { write_8(x); WR_ACTIVE; WR_STROBE; WR_IDLE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_8(); RD_IDLE; RD_IDLE; RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } +// Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) + +#elif defined(__SAM3X8E__) && defined(USE_DUE_8BIT_PROTOSHIELD) //regular UNO shield on DUE +#warning USE_DUE_8BIT_PROTOSHIELD +// configure macros for the control pins + #define RD_PORT PIOA + #define RD_PIN 16 //A0 + #define WR_PORT PIOA + #define WR_PIN 24 //A1 + #define CD_PORT PIOA + #define CD_PIN 23 //A2 + #define CS_PORT PIOA + #define CS_PIN 22 //A3 + #define RESET_PORT PIOA + #define RESET_PIN 6 //A4 +// configure macros for data bus +#define DMASK (0xFF<<0) +#define write_8(x) { PIOD->PIO_CODR = DMASK; PIOD->PIO_SODR = x; } + +#define read_8() ( PIOD->PIO_PDSR & DMASK) + #define setWriteDir() { PIOD->PIO_OER = DMASK; PIOD->PIO_PER = DMASK; } + #define setReadDir() { PMC->PMC_PCER0 = (1 << ID_PIOD); PIOD->PIO_ODR = DMASK;} +#define write8(x) { write_8(x); WR_ACTIVE; WR_STROBE; WR_IDLE; WR_IDLE; } +#define write16(x) { uint8_t h = (x)>>8, l = x; write8(h); write8(l); } +#define READ_8(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_8(); RD_IDLE; RD_IDLE; RD_IDLE; } +#define READ_16(dst) { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); } +// Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) + +#elif defined(__SAM3X8E__) && defined(USE_DUE_16BIT_SHIELD) //regular CTE shield on DUE +#warning USE_DUE_16BIT_SHIELD +// configure macros for the control pins +#define RD_PORT PIOA +#define RD_PIN 15 //D24 Graham +#define WR_PORT PIOD +#define WR_PIN 1 //D26 +#define CD_PORT PIOD +#define CD_PIN 0 //D25 +#define CS_PORT PIOD +#define CS_PIN 2 //D27 +#define RESET_PORT PIOD +#define RESET_PIN 3 //D28 +// configure macros for data bus +// DB0..DB7 on PIOC1..PIOC8, DB8..DB15 on PIOC12..PIOC19 +// +#define CMASKH (0xFF00<<4) +#define CMASKL (0x00FF<<1) +#define CMASK (CMASKH | CMASKL) +#define write_8(x) { PIOC->PIO_CODR = CMASKL; PIOC->PIO_SODR = (((x)&0x00FF)<<1); } +#define write_16(x) { PIOC->PIO_CODR = CMASK; \ + PIOC->PIO_SODR = (((x)&0x00FF)<<1)|(((x)&0xFF00)<<4); } +#define read_16() (((PIOC->PIO_PDSR & CMASKH)>>4)|((PIOC->PIO_PDSR & CMASKL)>>1) ) +#define read_8() (read_16() & 0xFF) +#define setWriteDir() { PIOC->PIO_OER = CMASK; PIOC->PIO_PER = CMASK; } +#define setReadDir() { PMC->PMC_PCER0 = (1 << ID_PIOC); PIOC->PIO_ODR = CMASK; } +#define write8(x) { write16(x & 0xFF); } +#define write16(x) { write_16(x); WR_ACTIVE; WR_STROBE; WR_IDLE; WR_IDLE; } +#define READ_16(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_16(); RD_IDLE; RD_IDLE; RD_IDLE; } +#define READ_8(dst) { READ_16(dst); dst &= 0xFF; } + +// Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) + +#elif defined(__SAM3X8E__) && defined(USE_MEGA_16BIT_SHIELD) //regular CTE shield on DUE +#warning USE_MEGA_16BIT_SHIELD +// configure macros for the control pins +#define RD_PORT PIOA +#define RD_PIN 20 //D43 +#define WR_PORT PIOC +#define WR_PIN 7 //D39 +#define CD_PORT PIOC +#define CD_PIN 6 //D38 +#define CS_PORT PIOC +#define CS_PIN 8 //D40 +#define RESET_PORT PIOC +#define RESET_PIN 9 //D41 +// configure macros for data bus +// +#define AMASK ((1<<7)|(3<<14)) //PA7, PA14-PA15 +#define BMASK (1<<26) //PB26 +#define CMASK (31<<1) //PC1-PC5 +#define DMASK ((15<<0)|(1<<6)|(3<<9)) //PD0-PD3, PD6, PD9-PD10 + +#define write_16(x) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; PIOD->PIO_CODR = DMASK; \ + PIOA->PIO_SODR = (((x)&(1<<6))<<1)|(((x)&(3<<9))<<5); \ + PIOB->PIO_SODR = (((x)&(1<<8))<<18); \ + PIOC->PIO_SODR = (((x)&(1<<0))<<5); \ + PIOC->PIO_SODR = (((x)&(1<<1))<<3); \ + PIOC->PIO_SODR = (((x)&(1<<2))<<1); \ + PIOC->PIO_SODR = (((x)&(1<<3))>>1); \ + PIOC->PIO_SODR = (((x)&(1<<4))>>3); \ + PIOD->PIO_SODR = (((x)&(1<<7))<<2)|(((x)&(1<<5))<<5)|(((x)&(15<<11))>>11)|(((x)&(1<<15))>>9); \ + } + +/* +#define write_16(VL) { PIOA->PIO_CODR = AMASK; PIOC->PIO_CODR = CMASK; PIOD->PIO_CODR = DMASK; \ + REG_PIOA_SODR=((((VL)>>8) & 0x06)<<13) | ((VL & 0x40)<<1);\ + if ((VL)&(1<<8)) REG_PIOB_SODR=(1<<26); else REG_PIOB_CODR=(1<<26);\ + REG_PIOC_SODR=((VL & 0x01)<<5) | ((VL & 0x02)<<3) | ((VL & 0x04)<<1) | ((VL & 0x08)>>1) | ((VL & 0x10)>>3);\ + REG_PIOD_SODR=((((VL)>>8) & 0x78)>>3) | ((((VL)>>8) & 0x80)>>1) | ((VL & 0x20)<<5) | ((VL & 0x80)<<2);\ +} +*/ +#define read_16() ( 0\ + |((PIOC->PIO_PDSR & (1<<5))>>5)\ + |((PIOC->PIO_PDSR & (1<<4))>>3)\ + |((PIOC->PIO_PDSR & (1<<3))>>1)\ + |((PIOC->PIO_PDSR & (1<<2))<<1)\ + |((PIOC->PIO_PDSR & (1<<1))<<3)\ + |((PIOD->PIO_PDSR & (1<<10))>>5)\ + |((PIOA->PIO_PDSR & (1<<7))>>1)\ + |((PIOD->PIO_PDSR & (1<<9))>>2)\ + |((PIOB->PIO_PDSR & (1<<26))>>18)\ + |((PIOA->PIO_PDSR & (3<<14))>>5)\ + |((PIOD->PIO_PDSR & (15<<0))<<11)\ + |((PIOD->PIO_PDSR & (1<<6))<<9)\ + ) +#define read_8() (read_16() & 0xFF) +#define setWriteDir() {\ + PIOA->PIO_OER = AMASK; PIOA->PIO_PER = AMASK; \ + PIOB->PIO_OER = BMASK; PIOB->PIO_PER = BMASK; \ + PIOC->PIO_OER = CMASK; PIOC->PIO_PER = CMASK; \ + PIOD->PIO_OER = DMASK; PIOD->PIO_PER = DMASK; \ + } +#define setReadDir() { \ + PMC->PMC_PCER0 = (1 << ID_PIOA)|(1 << ID_PIOB)|(1 << ID_PIOC)|(1 << ID_PIOD); \ + PIOA->PIO_ODR = AMASK; \ + PIOB->PIO_ODR = BMASK; \ + PIOC->PIO_ODR = CMASK; \ + PIOD->PIO_ODR = DMASK; \ + } +#define write8(x) { write16(x & 0xFF); } +// ILI9486 is slower than ILI9481 +#define write16(x) { write_16(x); WR_ACTIVE; WR_ACTIVE; WR_STROBE; } +#define READ_16(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_16(); RD_IDLE; RD_IDLE; RD_IDLE; } +#define READ_8(dst) { READ_16(dst); dst &= 0xFF; } + +// Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) + +#else +#define USE_SPECIAL_FAIL +#endif diff --git a/mcufriend_special_2.h b/mcufriend_special_2.h new file mode 100644 index 0000000..45f624e --- /dev/null +++ b/mcufriend_special_2.h @@ -0,0 +1,77 @@ +#elif defined(__SAM3X8E__) && defined(USE_MEGA_16BIT_SHIELD) //regular CTE shield on DUE +#warning USE_MEGA_16BIT_SHIELD +// configure macros for the control pins +#define RD_PORT PIOA +#define RD_PIN 20 //D43 +#define WR_PORT PIOC +#define WR_PIN 7 //D39 +#define CD_PORT PIOC +#define CD_PIN 6 //D38 +#define CS_PORT PIOC +#define CS_PIN 8 //D40 +#define RESET_PORT PIOC +#define RESET_PIN 9 //D41 +// configure macros for data bus +// +#define AMASK ((1<<7)|(3<<14)) //PA7, PA14-PA15 +#define BMASK (1<<26) //PB26 +#define CMASK (31<<1) //PC1-PC5 +#define DMASK ((15<<0)|(1<<6)|(3<<9)) //PD0-PD3, PD6, PD9-PD10 + +#define write_16(x) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; PIOD->PIO_CODR = DMASK; \ + PIOA->PIO_SODR = (((x)&(1<<6))<<1)|(((x)&(3<<9))<<5); \ + PIOB->PIO_SODR = (((x)&(1<<8))<<18); \ + PIOC->PIO_SODR = (((x)&(1<<0))<<5); \ + PIOC->PIO_SODR = (((x)&(1<<1))<<3); \ + PIOC->PIO_SODR = (((x)&(1<<2))<<1); \ + PIOC->PIO_SODR = (((x)&(1<<3))>>1); \ + PIOC->PIO_SODR = (((x)&(1<<4))>>3); \ + PIOD->PIO_SODR = (((x)&(1<<7))<<2)|(((x)&(1<<5))<<5)|(((x)&(15<<11))>>11)|(((x)&(1<<15))>>9); \ + } + +/* +#define write_16(VL) { PIOA->PIO_CODR = AMASK; PIOB->PIO_CODR = BMASK; PIOC->PIO_CODR = CMASK; PIOD->PIO_CODR = DMASK; \ + REG_PIOA_SODR=(((((VL)>>8) & 0x06)<<13) | ((VL & 0x40)<<1);\ + (((VL)>>8) & 0x01) ? REG_PIOB_SODR = 0x4000000 : REG_PIOB_CODR = 0x4000000;\ + REG_PIOC_SODR=((VL & 0x01)<<5) | ((VL & 0x02)<<3) | ((VL & 0x04)<<1) | ((VL & 0x08)>>1) | ((VL & 0x10)>>3);\ + REG_PIOD_SODR=((((VL)>>8) & 0x78)>>3) | ((((VL)>>8) & 0x80)>>1) | ((VL & 0x20)<<5) | ((VL & 0x80)<<2);\ +} +*/ +#define read_16() ( 0\ + |((PIOC->PIO_PDSR & (1<<5))>>5)\ + |((PIOC->PIO_PDSR & (1<<4))>>3)\ + |((PIOC->PIO_PDSR & (1<<3))>>1)\ + |((PIOC->PIO_PDSR & (1<<2))<<1)\ + |((PIOC->PIO_PDSR & (1<<1))<<3)\ + |((PIOD->PIO_PDSR & (1<<10))>>5)\ + |((PIOA->PIO_PDSR & (1<<7))>>1)\ + |((PIOD->PIO_PDSR & (1<<9))>>2)\ + |((PIOB->PIO_PDSR & (1<<26))>>18)\ + |((PIOA->PIO_PDSR & (3<<14))>>5)\ + |((PIOD->PIO_PDSR & (15<<0))<<11)\ + |((PIOD->PIO_PDSR & (1<<6))<<9)\ + ) +#define read_8() (read_16() & 0xFF) +#define setWriteDir() {\ + PIOA->PIO_OER = AMASK; PIOA->PIO_PER = AMASK; \ + PIOB->PIO_OER = BMASK; PIOB->PIO_PER = BMASK; \ + PIOC->PIO_OER = CMASK; PIOC->PIO_PER = CMASK; \ + PIOD->PIO_OER = DMASK; PIOD->PIO_PER = DMASK; \ + } +#define setReadDir() { \ + PMC->PMC_PCER0 = (1 << ID_PIOA)|(1 << ID_PIOB)|(1 << ID_PIOC)|(1 << ID_PIOD); \ + PIOA->PIO_ODR = AMASK; \ + PIOB->PIO_ODR = BMASK; \ + PIOC->PIO_ODR = CMASK; \ + PIOD->PIO_ODR = DMASK; \ + } +#define write8(x) { write16(x & 0xFF); } +#define write16(x) { write_16(x); WR_ACTIVE; WR_STROBE; WR_IDLE; WR_IDLE; } +#define READ_16(dst) { RD_STROBE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; dst = read_16(); RD_IDLE; RD_IDLE; RD_IDLE; } +#define READ_8(dst) { READ_16(dst); dst &= 0xFF; } + +// Shield Control macros. +#define PIN_LOW(port, pin) (port)->PIO_CODR = (1<<(pin)) +#define PIN_HIGH(port, pin) (port)->PIO_SODR = (1<<(pin)) +#define PIN_OUTPUT(port, pin) (port)->PIO_OER = (1<<(pin)) +