diff --git a/examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino b/examples/TouchScreen_Calibr_new/TouchScreen_Calibr_new.ino similarity index 71% rename from examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino rename to examples/TouchScreen_Calibr_new/TouchScreen_Calibr_new.ino index 5ec257f..aa201a1 100644 --- a/examples/TouchScreen_Calibr_kbv/TouchScreen_Calibr_kbv.ino +++ b/examples/TouchScreen_Calibr_new/TouchScreen_Calibr_new.ino @@ -1,3 +1,7 @@ +// https://forum.arduino.cc/index.php?topic=473885.msg3245748#msg3245748 +// file attached 03 May 2017 21:15 BST + + // TouchScreen_Calibr_kbv for MCUFRIEND UNO Display Shields // adapted by David Prentice // for Adafruit's Resistive Touch Screen Library @@ -15,6 +19,7 @@ // // Instructions will be given on the display. +//#define TOUCH_ORIENTATION LANDSCAPE #define TOUCH_ORIENTATION PORTRAIT #define TITLE "TouchScreen.h Calibration" @@ -25,10 +30,8 @@ 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 + +int YP = A1, YM = 7, XM = A2, XP = 7; //most comon configuration TouchScreen myTouch(XP, YP, XM, YM, 300); TSPoint tp; //Touchscreen_due branch uses Point @@ -86,10 +89,63 @@ int dispx, dispy, text_y_center, swapxy; uint32_t calx, caly, cals; char buf[13]; +void showpins(int A, int D, int value, const char *msg) +{ + char buf[40]; + sprintf(buf, "%s (A%d, D%d) = %d", msg, A - A0, D, value); + Serial.println(buf); +} + +boolean diagnose_pins() +{ + int i, j, value, Apins[2], Dpins[2], Values[2], found = 0; + // Serial.begin(9600); + Serial.println("Making all control and bus pins INPUT_PULLUP"); + Serial.println("Typical 30k Analog pullup with corresponding pin"); + Serial.println("would read low when digital is written LOW"); + Serial.println("e.g. reads ~25 for 300R X direction"); + Serial.println("e.g. reads ~30 for 500R Y direction"); + Serial.println(""); + for (i = A0; i < A5; i++) pinMode(i, INPUT_PULLUP); + for (i = 2; i < 10; i++) pinMode(i, INPUT_PULLUP); + for (i = A0; i < A4; i++) { + for (j = 5; j < 10; j++) { + pinMode(j, OUTPUT); + digitalWrite(j, LOW); + value = analogRead(i); // ignore first reading + value = analogRead(i); + if (value < 100) { + showpins(i, j, value, "Testing :"); + if (found < 2) { + Apins[found] = i; + Dpins[found] = j; + Values[found] = value; + found++; + } + } + pinMode(j, INPUT_PULLUP); + } + } + if (found == 2) { + Serial.println("Diagnosing as:-"); + int idx = Values[0] < Values[1]; + for (i = 0; i < 2; i++) { + showpins(Apins[i], Dpins[i], Values[i], + (Values[i] < Values[!i]) ? "XM,XP: " : "YP,YM: "); + } + XM = Apins[!idx]; XP = Dpins[!idx]; YP = Apins[idx]; YM = Dpins[idx]; + myTouch = TouchScreen(XP, YP, XM, YM, 300); + return true; + } + Serial.println("BROKEN TOUCHSCREEN"); + return false; +} + void setup() { Serial.begin(9600); Serial.println(TITLE); + bool ret = diagnose_pins(); digitalWrite(A0, HIGH); pinMode(A0, OUTPUT); myGLCD.InitLCD(TOUCH_ORIENTATION); @@ -98,6 +154,10 @@ void setup() dispx = myGLCD.getDisplayXSize(); dispy = myGLCD.getDisplayYSize(); text_y_center = (dispy / 2) - 6; + if (ret == false) { + myGLCD.print("BROKEN TOUCHSCREEN", CENTER, dispy / 2); + while (1); + } } void drawCrossHair(int x, int y) @@ -232,6 +292,7 @@ void done() { uint16_t TS_LEFT, TS_RT, TS_TOP, TS_BOT, TS_WID, TS_HT, TS_SWAP; int16_t tmp; + char buf[60]; myGLCD.clrScr(); myGLCD.setColor(255, 0, 0); myGLCD.fillRect(0, 0, dispx - 1, 13); @@ -255,35 +316,42 @@ void done() 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; - } + int y = 120; + Serial.println(""); + sprintf(buf, "Sketch is %s %d x %d", + TOUCH_ORIENTATION ? "LANDSCAPE" : "PORTRAIT", TS_WID, TS_HT); + myGLCD.print(buf, 0, y); + Serial.println(buf); + if (TOUCH_ORIENTATION == LANDSCAPE) { //always show PORTRAIT first + tmp = TS_LEFT, TS_LEFT = TS_BOT, TS_BOT = TS_RT, TS_RT = TS_TOP, TS_TOP = tmp; + tmp = TS_WID, TS_WID = TS_HT, TS_HT = tmp; } - 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); + sprintf(buf, "PORTRAIT CALIBRATION %d x %d", TS_WID, TS_HT); + myGLCD.print(buf, 0, y += 24); + Serial.println(buf); + sprintf(buf, "x = map(p.x, LEFT=%d, RT=%d, 0, %d)", TS_LEFT, TS_RT, TS_WID); + myGLCD.print(buf, 0, y += 12); + Serial.println(buf); + sprintf(buf, "y = map(p.y, TOP=%d, BOT=%d, 0, %d)", TS_TOP, TS_BOT, TS_HT); + myGLCD.print(buf, 0, y += 12); + Serial.println(buf); + sprintf(buf, "Touch Pin Wiring XP=%d XM=A%d YP=A%d YM=%d", + XP, XM - A0, YP - A0, YM); + myGLCD.print(buf, 0, y += 24); + Serial.println(buf); + 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; + + sprintf(buf, "LANDSCAPE CALIBRATION %d x %d", TS_WID, TS_HT); + myGLCD.print(buf, 0, y += 24); + Serial.println(buf); + sprintf(buf, "x = map(p.y, LEFT=%d, RT=%d, 0, %d)", TS_LEFT, TS_RT, TS_WID); + myGLCD.print(buf, 0, y += 12); + Serial.println(buf); + sprintf(buf, "y = map(p.x, TOP=%d, BOT=%d, 0, %d)", TS_TOP, TS_BOT, TS_HT); + myGLCD.print(buf, 0, y += 12); + Serial.println(buf); } void fail() diff --git a/examples/showBMP_kbv_as7/showBMP_kbv_as7.ino b/examples/showBMP_kbv_Uno/showBMP_kbv_Uno.ino similarity index 87% rename from examples/showBMP_kbv_as7/showBMP_kbv_as7.ino rename to examples/showBMP_kbv_Uno/showBMP_kbv_Uno.ino index 4e5235a..560897e 100644 --- a/examples/showBMP_kbv_as7/showBMP_kbv_as7.ino +++ b/examples/showBMP_kbv_Uno/showBMP_kbv_Uno.ino @@ -1,27 +1,28 @@ -// Simple BMP display on Uno -// library: 320x240x24 180x180x24 320x240x16 -// SDfat (SPI) 2146ms 845ms 1735ms -// SDfat (soft) 4095ms 1730ms 3241ms -// SD (SPI) 3046ms 1263ms 2441ms (7) -// SD (AS7) 16398ms 7384ms 12491ms (7) +// MCUFRIEND UNO shields have microSD on pins 10, 11, 12, 13 +// The official library only works on the hardware SPI pins +// e.g. 11, 12, 13 on a Uno (or STM32 Nucleo) // -// +// copy all your BMP files to the root directory on the microSD with your PC +// (or another directory) -#include // f.k. for Arduino-1.5.2 -#define USE_SDFAT -//#include -#include // Use the SdFat library -SdFat SD; // Use hardware SPI (or UNO with SD_SPI_CONFIGURATION==2) -//SdFatSoftSpi<12, 11, 13> SD; //Bit-Bang SD_SPI_CONFIGURATION==3 - -#include // Hardware-specific library +#include // f.k. for Arduino-1.5.2 +//#define USE_SDFAT +#include // Use the official SD library on hardware pins +#include // Hardware-specific library #include MCUFRIEND_kbv tft; -#define SD_CS 10 + +#define SD_CS 10 +//#define NAMEMATCH "" // "" matches any name +#define NAMEMATCH "tiger" // *tiger*.bmp +#define PALETTEDEPTH 0 // do not support Palette modes +//#define PALETTEDEPTH 8 // support 256-colour Palette + +//char namebuf[32] = "/"; //BMP files in root directory +char namebuf[32] = "/bitmaps/"; //BMP directory e.g. files in /bitmaps/*.bmp File root; -char namebuf[32] = "/bitmaps/"; int pathlen; void setup() @@ -34,7 +35,6 @@ void setup() if (ID == 0x0D3D3) ID = 0x9481; tft.begin(ID); tft.fillScreen(0x001F); - if (tft.height() > tft.width()) tft.setRotation(1); //LANDSCAPE tft.setTextColor(0xFFFF, 0x0000); bool good = SD.begin(SD_CS); if (!good) { @@ -59,7 +59,7 @@ void loop() #endif f.close(); strlwr(nm); - if (strstr(nm, ".bmp") != NULL && strstr(nm, "tiger") != NULL) { + if (strstr(nm, ".bmp") != NULL && strstr(nm, NAMEMATCH) != NULL) { Serial.print(namebuf); Serial.print(F(" - ")); tft.fillScreen(0); @@ -83,6 +83,9 @@ void loop() case 4: Serial.println(F("unsupported BMP format")); break; + case 5: + Serial.println(F("unsupported palette")); + break; default: Serial.println(F("unknown")); break; @@ -94,8 +97,7 @@ void loop() #define BMPIMAGEOFFSET 54 -#define PALETTEDEPTH 8 -#define BUFFPIXEL 20 +#define BUFFPIXEL 20 uint16_t read16(File& f) { uint16_t result; // read little-endian @@ -149,6 +151,7 @@ uint8_t showBMP(char *nm, int x, int y) if (bmpID != 0x4D42) ret = 2; // bad ID else if (n != 1) ret = 3; // too many planes else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565 + else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette else { bool first = true; is565 = (pos == 3); // ?already in 16-bit format diff --git a/examples/showBMP_not_Uno/showBMP_not_Uno.ino b/examples/showBMP_not_Uno/showBMP_not_Uno.ino new file mode 100644 index 0000000..b352891 --- /dev/null +++ b/examples/showBMP_not_Uno/showBMP_not_Uno.ino @@ -0,0 +1,264 @@ +// MCUFRIEND UNO shields have microSD on pins 10, 11, 12, 13 +// The official library only works on the hardware SPI pins +// e.g. 11, 12, 13 on a Uno +// e.g. 50, 51, 52 on a Mega2560 +// e.g. 74, 75, 76 on a Due +// +// if you are not using a UNO, you must use Software SPI: +// +// install v1.0.1 of the library with the Arduino Library Manager. +// edit the src/SdFatConfig.h file to #define ENABLE_SOFTWARE_SPI_CLASS 1 +// +// copy all your BMP files to the root directory on the microSD with your PC +// (or another directory) + +#include // f.k. for Arduino-1.5.2 +#define USE_SDFAT +#include // Use the SdFat library +SdFatSoftSpi<12, 11, 13> SD; //Bit-Bang on the Shield pins + +#include // Hardware-specific library +#include +MCUFRIEND_kbv tft; + +#define SD_CS 10 +#define NAMEMATCH "" // "" matches any name +//#define NAMEMATCH "tiger" // *tiger*.bmp +#define PALETTEDEPTH 8 // support 256-colour Palette + +char namebuf[32] = "/"; //BMP files in root directory +//char namebuf[32] = "/bitmaps/"; //BMP directory e.g. files in /bitmaps/*.bmp + +File root; +int pathlen; + +void setup() +{ + uint16_t ID; + Serial.begin(9600); + Serial.print("Show BMP files on TFT with ID:0x"); + ID = tft.readID(); + Serial.println(ID, HEX); + if (ID == 0x0D3D3) ID = 0x9481; + tft.begin(ID); + tft.fillScreen(0x001F); + tft.setTextColor(0xFFFF, 0x0000); + bool good = SD.begin(SD_CS); + if (!good) { + Serial.print(F("cannot start SD")); + while (1); + } + root = SD.open(namebuf); + pathlen = strlen(namebuf); +} + +void loop() +{ + char *nm = namebuf + pathlen; + File f = root.openNextFile(); + uint8_t ret; + uint32_t start; + if (f != NULL) { +#ifdef USE_SDFAT + f.getName(nm, 32 - pathlen); +#else + strcpy(nm, (char *)f.name()); +#endif + f.close(); + strlwr(nm); + if (strstr(nm, ".bmp") != NULL && strstr(nm, NAMEMATCH) != NULL) { + Serial.print(namebuf); + Serial.print(F(" - ")); + tft.fillScreen(0); + start = millis(); + ret = showBMP(namebuf, 5, 5); + switch (ret) { + case 0: + Serial.print(millis() - start); + Serial.println(F("ms")); + delay(5000); + break; + case 1: + Serial.println(F("bad position")); + break; + case 2: + Serial.println(F("bad BMP ID")); + break; + case 3: + Serial.println(F("wrong number of planes")); + break; + case 4: + Serial.println(F("unsupported BMP format")); + break; + case 5: + Serial.println(F("unsupported palette")); + break; + default: + Serial.println(F("unknown")); + break; + } + } + } + else root.rewindDirectory(); +} + +#define BMPIMAGEOFFSET 54 + +#define BUFFPIXEL 20 + +uint16_t read16(File& f) { + uint16_t result; // read little-endian + result = f.read(); // LSB + result |= f.read() << 8; // MSB + return result; +} + +uint32_t read32(File& f) { + uint32_t result; + result = f.read(); // LSB + result |= f.read() << 8; + result |= f.read() << 16; + result |= f.read() << 24; // MSB + return result; +} + +uint8_t showBMP(char *nm, int x, int y) +{ + File bmpFile; + int bmpWidth, bmpHeight; // W+H in pixels + uint8_t bmpDepth; // Bit depth (currently must be 24, 16, 8, 4, 1) + uint32_t bmpImageoffset; // Start of image data in file + uint32_t rowSize; // Not always = bmpWidth; may have padding + uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel) + uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL; + uint8_t bitmask, bitshift; + boolean flip = true; // BMP is stored bottom-to-top + int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx; + uint32_t pos; // seek position + boolean is565 = false; // + + uint16_t bmpID; + uint16_t n; // blocks read + uint8_t ret; + + if ((x >= tft.width()) || (y >= tft.height())) + return 1; // off screen + + bmpFile = SD.open(nm); // Parse BMP header + bmpID = read16(bmpFile); // BMP signature + (void) read32(bmpFile); // Read & ignore file size + (void) read32(bmpFile); // Read & ignore creator bytes + bmpImageoffset = read32(bmpFile); // Start of image data + (void) read32(bmpFile); // Read & ignore DIB header size + bmpWidth = read32(bmpFile); + bmpHeight = read32(bmpFile); + n = read16(bmpFile); // # planes -- must be '1' + bmpDepth = read16(bmpFile); // bits per pixel + pos = read32(bmpFile); // format + if (bmpID != 0x4D42) ret = 2; // bad ID + else if (n != 1) ret = 3; // too many planes + else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565 + else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette + else { + bool first = true; + is565 = (pos == 3); // ?already in 16-bit format + // BMP rows are padded (if needed) to 4-byte boundary + rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3; + if (bmpHeight < 0) { // If negative, image is in top-down order. + bmpHeight = -bmpHeight; + flip = false; + } + + w = bmpWidth; + h = bmpHeight; + if ((x + w) >= tft.width()) // Crop area to be loaded + w = tft.width() - x; + if ((y + h) >= tft.height()) // + h = tft.height() - y; + + if (bmpDepth <= PALETTEDEPTH) { // these modes have separate palette + bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54 + bitmask = 0xFF; + if (bmpDepth < 8) + bitmask >>= bmpDepth; + bitshift = 8 - bmpDepth; + n = 1 << bmpDepth; + lcdbufsiz -= n; + palette = lcdbuffer + lcdbufsiz; + for (col = 0; col < n; col++) { + pos = read32(bmpFile); //map palette to 5-6-5 + palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8); + } + } + + // Set TFT address window to clipped image bounds + tft.setAddrWindow(x, y, x + w - 1, y + h - 1); + for (row = 0; row < h; row++) { // For each scanline... + // Seek to start of scan line. It might seem labor- + // intensive to be doing this on every line, but this + // method covers a lot of gritty details like cropping + // and scanline padding. Also, the seek only takes + // place if the file position actually needs to change + // (avoids a lot of cluster math in SD library). + uint8_t r, g, b, *sdptr; + int lcdidx, lcdleft; + if (flip) // Bitmap is stored bottom-to-top order (normal BMP) + pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize; + else // Bitmap is stored top-to-bottom + pos = bmpImageoffset + row * rowSize; + if (bmpFile.position() != pos) { // Need seek? + bmpFile.seek(pos); + buffidx = sizeof(sdbuffer); // Force buffer reload + } + + for (col = 0; col < w; ) { //pixels in row + lcdleft = w - col; + if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz; + for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time + uint16_t color; + // Time to read more pixel data? + if (buffidx >= sizeof(sdbuffer)) { // Indeed + bmpFile.read(sdbuffer, sizeof(sdbuffer)); + buffidx = 0; // Set index to beginning + r = 0; + } + switch (bmpDepth) { // Convert pixel from BMP to TFT format + case 24: + b = sdbuffer[buffidx++]; + g = sdbuffer[buffidx++]; + r = sdbuffer[buffidx++]; + color = tft.color565(r, g, b); + break; + case 16: + b = sdbuffer[buffidx++]; + r = sdbuffer[buffidx++]; + if (is565) + color = (r << 8) | (b); + else + color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F); + break; + case 1: + case 4: + case 8: + if (r == 0) + b = sdbuffer[buffidx++], r = 8; + color = palette[(b >> bitshift) & bitmask]; + r -= bmpDepth; + b <<= bmpDepth; + break; + } + lcdbuffer[lcdidx] = color; + + } + tft.pushColors(lcdbuffer, lcdidx, first); + first = false; + col += lcdidx; + } // end cols + } // end rows + tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen + ret = 0; // good render + } + bmpFile.close(); + return (ret); +} + diff --git a/extras/bitmaps/tiger_178x160x4.bmp b/extras/bitmaps/tiger_178x160x4.bmp new file mode 100644 index 0000000..7779be6 Binary files /dev/null and b/extras/bitmaps/tiger_178x160x4.bmp differ diff --git a/extras/bitmaps/tiger_240x317x4.bmp b/extras/bitmaps/tiger_240x317x4.bmp new file mode 100644 index 0000000..4ac6d90 Binary files /dev/null and b/extras/bitmaps/tiger_240x317x4.bmp differ diff --git a/extras/bitmaps/tiger_320x200x24.bmp b/extras/bitmaps/tiger_320x200x24.bmp new file mode 100644 index 0000000..b43c057 Binary files /dev/null and b/extras/bitmaps/tiger_320x200x24.bmp differ