About this how to
xyz-mIoT by itbrainpower.net shield shortcuts for integration with ILI9341 2.2 inch 240x320 TFT color display and/or SD card reader, using SPI, no mater what xyz-mIoT PN (with/wo LTE or GSM modem, with/wo sensors) used.

Shields used in this project: xyz-mIoT by itbrainpower.net + ILI9341 2.2 inch 240x320 TFT color display (having integrated TF/SD card reader) / stand alone SD card reader while label versions.
hardware integration (wiring), in a nut shell
ILI9431 TFT module wiring
In the images up-here, notice:
a. xyz-mIoT shield powering - please refer to xyz-mIoT documentation.
b. 3.3V power supply for the TFT module is provided by xyz-mIoT shield.
c. On ILI9341 TFT module: SPI signals in GREEN, digital signal required for TFT side in BLUE and digital signals for SD/TF side in PURPLE. The 3V3 in top-right and the GNtD are used for powering inputs for both TFT and SD/TF side. The second 3V3 wire is used for TFT backlight powering.
d. If you dont intend to use the SD/TF interface, do not wire the SD card interface wires.
standalone SD/TF reader module wiring
Standalone SD/TF card reader software how to
- open any of SD examples from Arduino menu, eg.: Listfiles.ino
- in setup() function, change "if (!SD.begin(4))" with "if (!SD.begin(8))" - remmember.. we wired SD chip select signal to digital port 8
- in order to use the debug functions replace ALL "Serial." with "SerialUSB." - xyz-mIoT have defined SerialUSB as debug port.
- done. Compile, upload and run the SD test code.
ILI9431 TFT module software section
We've used for this test the excellent Adafruit ILI9341 and GFX libraries. You may download them from: here
a. unzip the libraries and install both in Arduino libraries folder. Restart Arduino.
b. Make a folder named "test_ili9341_SD_xyz-mIoT".
c. Copy the code bellow, paste it one new file and save the file as "test_ili9341_SD_xyz-mIoT.ino" in the folder created in previous step. Alternate, you can
download from here (right click & save as): test ILI9341 TFT +SD/TF shield with xyz-mIoT shield - Arduino main code
test_ili9341_SD_xyz-mIoT.ino
| 1 | /*************************************************** |
| 2 | * Test example for white label ILI9341 TFT + SD/TF card reader shield wired to any version of xyz-mIoT by itbrainpower.net v2.09 shield. |
| 3 | * Wire the boards as bellow: |
| 4 | * |
| 5 | * xyz-mIoT by itbrainpower.net ILI9341 TFT + SD/TF card shield |
| 6 | * 3V3 VCC and LED |
| 7 | * GND GND |
| 8 | * D2 D/C (TFT_DC) |
| 9 | * D3 CS (TFT_CS) |
| 10 | * D4 RESET (TFT_RST) |
| 11 | * D8 SD_CS |
| 12 | * MISO SDO(TFT MISO) and SD_MISO |
| 13 | * MOSI SDI(TFT MOSI) and SD_MOSI |
| 14 | * SCK SCK(TFT SCK) and SD_SCK |
| 15 | * |
| 16 | * Examples based on Adafruit ILI9341 and GFX libraries. We've made just some surface |
| 17 | * adaptation in order to fix the debug port for xyz-mIoT shields and to add SD support. |
| 18 | * |
| 19 | * itbrainpower.net invests significant time and resources providing those how to and in design phase of our IoT products. |
| 20 | * Support us by purchasing our worldwide best LTE CATM1, NB IoT, 2G, 3G and 4G shields: |
| 21 | * xyz-mIoT by itbrainpower.net https://itbrainpower.net/order#xyz-mIoT |
| 22 | * u-GSM by itbrainpower.net https://itbrainpower.net/order#u-GSM |
| 23 | * |
| 24 | * |
| 25 | * We recomend you to use ILI9341 Breakout and Shield from Adafruit http://www.adafruit.com/products/1651 |
| 26 | * |
| 27 | * |
| 28 | * Dragos Iosub, Bucharest 2019 |
| 29 | */ |
| 30 | /*************************************************** |
| 31 | This is our GFX example for the Adafruit ILI9341 Breakout and Shield |
| 32 | ----> http://www.adafruit.com/products/1651 |
| 33 | |
| 34 | Check out the links above for our tutorials and wiring diagrams |
| 35 | These displays use SPI to communicate, 4 or 5 pins are required to |
| 36 | interface (RST is optional) |
| 37 | Adafruit invests time and resources providing this open source code, |
| 38 | please support Adafruit and open-source hardware by purchasing |
| 39 | products from Adafruit! |
| 40 | |
| 41 | Written by Limor Fried/Ladyada for Adafruit Industries. |
| 42 | MIT license, all text above must be included in any redistribution |
| 43 | ****************************************************/ |
| 44 | |
| 45 | |
| 46 | #include "SPI.h" |
| 47 | #include "Adafruit_GFX.h" |
| 48 | #include "Adafruit_ILI9341.h" |
| 49 | |
| 50 | #include "SD.h" |
| 51 | |
| 52 | File root; |
| 53 | |
| 54 | #define TFT_DC 2 |
| 55 | #define TFT_CS 3 |
| 56 | #define TFT_RST 4 |
| 57 | |
| 58 | #define SD_CS 8 |
| 59 | |
| 60 | |
| 61 | |
| 62 | String dataString = ""; |
| 63 | unsigned long cycle = 0; |
| 64 | |
| 65 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); |
| 66 | |
| 67 | void setup() { |
| 68 | delay(8000); |
| 69 | SerialUSB.begin(9600); |
| 70 | |
| 71 | pinMode(SD_CS, OUTPUT); |
| 72 | digitalWrite(SD_CS, HIGH); |
| 73 | |
| 74 | SerialUSB.print("Initializing SD card..."); |
| 75 | |
| 76 | if (!SD.begin(SD_CS)) { |
| 77 | SerialUSB.println("initialization failed!"); |
| 78 | } else |
| 79 | SerialUSB.println("initialization done."); |
| 80 | |
| 81 | SerialUSB.println("ILI9341 Test!"); |
| 82 | |
| 83 | tft.begin(); |
| 84 | |
| 85 | // read diagnostics (optional but can help debug problems) |
| 86 | uint8_t x = tft.readcommand8(ILI9341_RDMODE); |
| 87 | SerialUSB.print("Display Power Mode: 0x"); SerialUSB.println(x, HEX); |
| 88 | x = tft.readcommand8(ILI9341_RDMADCTL); |
| 89 | SerialUSB.print("MADCTL Mode: 0x"); SerialUSB.println(x, HEX); |
| 90 | x = tft.readcommand8(ILI9341_RDPIXFMT); |
| 91 | SerialUSB.print("Pixel Format: 0x"); SerialUSB.println(x, HEX); |
| 92 | x = tft.readcommand8(ILI9341_RDIMGFMT); |
| 93 | SerialUSB.print("Image Format: 0x"); SerialUSB.println(x, HEX); |
| 94 | x = tft.readcommand8(ILI9341_RDSELFDIAG); |
| 95 | SerialUSB.print("Self Diagnostic: 0x"); SerialUSB.println(x, HEX); |
| 96 | |
| 97 | SerialUSB.println(F("Benchmark Time (microseconds)")); |
| 98 | delay(10); |
| 99 | SerialUSB.print(F("Screen fill ")); |
| 100 | SerialUSB.println(testFillScreen()); |
| 101 | delay(500); |
| 102 | |
| 103 | SerialUSB.print(F("Text ")); |
| 104 | SerialUSB.println(testText()); |
| 105 | delay(3000); |
| 106 | |
| 107 | SerialUSB.print(F("Lines ")); |
| 108 | SerialUSB.println(testLines(ILI9341_CYAN)); |
| 109 | delay(500); |
| 110 | |
| 111 | SerialUSB.print(F("Horiz/Vert Lines ")); |
| 112 | SerialUSB.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); |
| 113 | delay(500); |
| 114 | |
| 115 | SerialUSB.print(F("Rectangles (outline) ")); |
| 116 | SerialUSB.println(testRects(ILI9341_GREEN)); |
| 117 | delay(500); |
| 118 | |
| 119 | SerialUSB.print(F("Rectangles (filled) ")); |
| 120 | SerialUSB.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); |
| 121 | delay(500); |
| 122 | |
| 123 | SerialUSB.print(F("Circles (filled) ")); |
| 124 | SerialUSB.println(testFilledCircles(10, ILI9341_MAGENTA)); |
| 125 | |
| 126 | SerialUSB.print(F("Circles (outline) ")); |
| 127 | SerialUSB.println(testCircles(10, ILI9341_WHITE)); |
| 128 | delay(500); |
| 129 | |
| 130 | SerialUSB.print(F("Triangles (outline) ")); |
| 131 | SerialUSB.println(testTriangles()); |
| 132 | delay(500); |
| 133 | |
| 134 | SerialUSB.print(F("Triangles (filled) ")); |
| 135 | SerialUSB.println(testFilledTriangles()); |
| 136 | delay(500); |
| 137 | |
| 138 | SerialUSB.print(F("Rounded rects (outline) ")); |
| 139 | SerialUSB.println(testRoundRects()); |
| 140 | delay(500); |
| 141 | |
| 142 | SerialUSB.print(F("Rounded rects (filled) ")); |
| 143 | SerialUSB.println(testFilledRoundRects()); |
| 144 | delay(500); |
| 145 | |
| 146 | SerialUSB.println(F("Done!")); |
| 147 | |
| 148 | } |
| 149 | |
| 150 | |
| 151 | void loop(void) { |
| 152 | for(uint8_t rotation=0; rotation<4; rotation++) { |
| 153 | tft.setRotation(rotation); |
| 154 | testText(); |
| 155 | //delay(5000); |
| 156 | |
| 157 | SerialUSB.println("Test SD"); |
| 158 | |
| 159 | root = SD.open("/"); |
| 160 | |
| 161 | printDirectory(root, 0); |
| 162 | |
| 163 | SerialUSB.println("done!"); |
| 164 | delay(250); |
| 165 | |
| 166 | |
| 167 | |
| 168 | //bellow write log |
| 169 | dataString = String(cycle++); |
| 170 | dataString += " >> whatever we will log here <<"; |
| 171 | writeToLog("datalog.txt"); |
| 172 | delay(50); |
| 173 | //dump log |
| 174 | SerialUSB.println("try read the log file"); |
| 175 | dumpLog("datalog.txt"); |
| 176 | |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | |
| 181 | void writeToLog(char* fileName){ |
| 182 | File dataFile = SD.open(fileName, FILE_WRITE); |
| 183 | if (dataFile) { |
| 184 | dataFile.println(dataString); |
| 185 | dataFile.close(); |
| 186 | |
| 187 | SerialUSB.println(dataString); |
| 188 | } |
| 189 | else{ |
| 190 | Serial.print("error opening "); |
| 191 | Serial.println(fileName); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | void dumpLog(char* fileName){ |
| 196 | File dataFile = SD.open(fileName); |
| 197 | |
| 198 | if (dataFile) { |
| 199 | while (dataFile.available()) { |
| 200 | SerialUSB.write(dataFile.read()); |
| 201 | } |
| 202 | dataFile.close(); |
| 203 | } |
| 204 | else{ |
| 205 | Serial.print("error opening "); |
| 206 | Serial.println(fileName); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | void printDirectory(File dir, int numTabs) { |
| 211 | while (true) { |
| 212 | |
| 213 | File entry = dir.openNextFile(); |
| 214 | if (! entry) { |
| 215 | // no more files |
| 216 | break; |
| 217 | } |
| 218 | for (uint8_t i = 0; i < numTabs; i++) { |
| 219 | SerialUSB.print('\t'); |
| 220 | } |
| 221 | SerialUSB.print(entry.name()); |
| 222 | if (entry.isDirectory()) { |
| 223 | SerialUSB.println("/"); |
| 224 | printDirectory(entry, numTabs + 1); |
| 225 | } else { |
| 226 | // files have sizes, directories do not |
| 227 | SerialUSB.print("\t\t"); |
| 228 | SerialUSB.println(entry.size(), DEC); |
| 229 | } |
| 230 | entry.close(); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | |
| 235 | unsigned long testFillScreen() { |
| 236 | unsigned long start = micros(); |
| 237 | tft.fillScreen(ILI9341_BLACK); |
| 238 | yield(); |
| 239 | tft.fillScreen(ILI9341_RED); |
| 240 | yield(); |
| 241 | tft.fillScreen(ILI9341_GREEN); |
| 242 | yield(); |
| 243 | tft.fillScreen(ILI9341_BLUE); |
| 244 | yield(); |
| 245 | tft.fillScreen(ILI9341_BLACK); |
| 246 | yield(); |
| 247 | return micros() - start; |
| 248 | } |
| 249 | |
| 250 | unsigned long testText() { |
| 251 | tft.fillScreen(ILI9341_BLACK); |
| 252 | unsigned long start = micros(); |
| 253 | tft.setCursor(0, 0); |
| 254 | tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); |
| 255 | tft.println("Hello World!"); |
| 256 | tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); |
| 257 | tft.println(1234.56); |
| 258 | tft.setTextColor(ILI9341_RED); tft.setTextSize(3); |
| 259 | tft.println(0xDEADBEEF, HEX); |
| 260 | tft.println(); |
| 261 | tft.setTextColor(ILI9341_GREEN); |
| 262 | tft.setTextSize(5); |
| 263 | tft.println("Groop"); |
| 264 | tft.setTextSize(2); |
| 265 | tft.println("I implore thee,"); |
| 266 | tft.setTextSize(1); |
| 267 | tft.println("my foonting turlingdromes."); |
| 268 | tft.println("And hooptiously drangle me"); |
| 269 | tft.println("with crinkly bindlewurdles,"); |
| 270 | tft.println("Or I will rend thee"); |
| 271 | tft.println("in the gobberwarts"); |
| 272 | tft.println("with my blurglecruncheon,"); |
| 273 | tft.println("see if I don't!"); |
| 274 | return micros() - start; |
| 275 | } |
| 276 | |
| 277 | unsigned long testLines(uint16_t color) { |
| 278 | unsigned long start, t; |
| 279 | int x1, y1, x2, y2, |
| 280 | w = tft.width(), |
| 281 | h = tft.height(); |
| 282 | |
| 283 | tft.fillScreen(ILI9341_BLACK); |
| 284 | yield(); |
| 285 | |
| 286 | x1 = y1 = 0; |
| 287 | y2 = h - 1; |
| 288 | start = micros(); |
| 289 | for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 290 | x2 = w - 1; |
| 291 | for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 292 | t = micros() - start; // fillScreen doesn't count against timing |
| 293 | |
| 294 | yield(); |
| 295 | tft.fillScreen(ILI9341_BLACK); |
| 296 | yield(); |
| 297 | |
| 298 | x1 = w - 1; |
| 299 | y1 = 0; |
| 300 | y2 = h - 1; |
| 301 | start = micros(); |
| 302 | for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 303 | x2 = 0; |
| 304 | for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 305 | t += micros() - start; |
| 306 | |
| 307 | yield(); |
| 308 | tft.fillScreen(ILI9341_BLACK); |
| 309 | yield(); |
| 310 | |
| 311 | x1 = 0; |
| 312 | y1 = h - 1; |
| 313 | y2 = 0; |
| 314 | start = micros(); |
| 315 | for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 316 | x2 = w - 1; |
| 317 | for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 318 | t += micros() - start; |
| 319 | |
| 320 | yield(); |
| 321 | tft.fillScreen(ILI9341_BLACK); |
| 322 | yield(); |
| 323 | |
| 324 | x1 = w - 1; |
| 325 | y1 = h - 1; |
| 326 | y2 = 0; |
| 327 | start = micros(); |
| 328 | for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 329 | x2 = 0; |
| 330 | for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); |
| 331 | |
| 332 | yield(); |
| 333 | return micros() - start; |
| 334 | } |
| 335 | |
| 336 | unsigned long testFastLines(uint16_t color1, uint16_t color2) { |
| 337 | unsigned long start; |
| 338 | int x, y, w = tft.width(), h = tft.height(); |
| 339 | |
| 340 | tft.fillScreen(ILI9341_BLACK); |
| 341 | start = micros(); |
| 342 | for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1); |
| 343 | for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2); |
| 344 | |
| 345 | return micros() - start; |
| 346 | } |
| 347 | |
| 348 | unsigned long testRects(uint16_t color) { |
| 349 | unsigned long start; |
| 350 | int n, i, i2, |
| 351 | cx = tft.width() / 2, |
| 352 | cy = tft.height() / 2; |
| 353 | |
| 354 | tft.fillScreen(ILI9341_BLACK); |
| 355 | n = min(tft.width(), tft.height()); |
| 356 | start = micros(); |
| 357 | for(i=2; i<n; i+=6) { |
| 358 | i2 = i / 2; |
| 359 | tft.drawRect(cx-i2, cy-i2, i, i, color); |
| 360 | } |
| 361 | |
| 362 | return micros() - start; |
| 363 | } |
| 364 | |
| 365 | unsigned long testFilledRects(uint16_t color1, uint16_t color2) { |
| 366 | unsigned long start, t = 0; |
| 367 | int n, i, i2, |
| 368 | cx = tft.width() / 2 - 1, |
| 369 | cy = tft.height() / 2 - 1; |
| 370 | |
| 371 | tft.fillScreen(ILI9341_BLACK); |
| 372 | n = min(tft.width(), tft.height()); |
| 373 | for(i=n; i>0; i-=6) { |
| 374 | i2 = i / 2; |
| 375 | start = micros(); |
| 376 | tft.fillRect(cx-i2, cy-i2, i, i, color1); |
| 377 | t += micros() - start; |
| 378 | // Outlines are not included in timing results |
| 379 | tft.drawRect(cx-i2, cy-i2, i, i, color2); |
| 380 | yield(); |
| 381 | } |
| 382 | |
| 383 | return t; |
| 384 | } |
| 385 | |
| 386 | unsigned long testFilledCircles(uint8_t radius, uint16_t color) { |
| 387 | unsigned long start; |
| 388 | int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; |
| 389 | |
| 390 | tft.fillScreen(ILI9341_BLACK); |
| 391 | start = micros(); |
| 392 | for(x=radius; x<w; x+=r2) { |
| 393 | for(y=radius; y<h; y+=r2) { |
| 394 | tft.fillCircle(x, y, radius, color); |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | return micros() - start; |
| 399 | } |
| 400 | |
| 401 | unsigned long testCircles(uint8_t radius, uint16_t color) { |
| 402 | unsigned long start; |
| 403 | int x, y, r2 = radius * 2, |
| 404 | w = tft.width() + radius, |
| 405 | h = tft.height() + radius; |
| 406 | |
| 407 | // Screen is not cleared for this one -- this is |
| 408 | // intentional and does not affect the reported time. |
| 409 | start = micros(); |
| 410 | for(x=0; x<w; x+=r2) { |
| 411 | for(y=0; y<h; y+=r2) { |
| 412 | tft.drawCircle(x, y, radius, color); |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | return micros() - start; |
| 417 | } |
| 418 | |
| 419 | unsigned long testTriangles() { |
| 420 | unsigned long start; |
| 421 | int n, i, cx = tft.width() / 2 - 1, |
| 422 | cy = tft.height() / 2 - 1; |
| 423 | |
| 424 | tft.fillScreen(ILI9341_BLACK); |
| 425 | n = min(cx, cy); |
| 426 | start = micros(); |
| 427 | for(i=0; i<n; i+=5) { |
| 428 | tft.drawTriangle( |
| 429 | cx , cy - i, // peak |
| 430 | cx - i, cy + i, // bottom left |
| 431 | cx + i, cy + i, // bottom right |
| 432 | tft.color565(i, i, i)); |
| 433 | } |
| 434 | |
| 435 | return micros() - start; |
| 436 | } |
| 437 | |
| 438 | unsigned long testFilledTriangles() { |
| 439 | unsigned long start, t = 0; |
| 440 | int i, cx = tft.width() / 2 - 1, |
| 441 | cy = tft.height() / 2 - 1; |
| 442 | |
| 443 | tft.fillScreen(ILI9341_BLACK); |
| 444 | start = micros(); |
| 445 | for(i=min(cx,cy); i>10; i-=5) { |
| 446 | start = micros(); |
| 447 | tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, |
| 448 | tft.color565(0, i*10, i*10)); |
| 449 | t += micros() - start; |
| 450 | tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, |
| 451 | tft.color565(i*10, i*10, 0)); |
| 452 | yield(); |
| 453 | } |
| 454 | |
| 455 | return t; |
| 456 | } |
| 457 | |
| 458 | unsigned long testRoundRects() { |
| 459 | unsigned long start; |
| 460 | int w, i, i2, |
| 461 | cx = tft.width() / 2 - 1, |
| 462 | cy = tft.height() / 2 - 1; |
| 463 | |
| 464 | tft.fillScreen(ILI9341_BLACK); |
| 465 | w = min(tft.width(), tft.height()); |
| 466 | start = micros(); |
| 467 | for(i=0; i<w; i+=6) { |
| 468 | i2 = i / 2; |
| 469 | tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0)); |
| 470 | } |
| 471 | |
| 472 | return micros() - start; |
| 473 | } |
| 474 | |
| 475 | unsigned long testFilledRoundRects() { |
| 476 | unsigned long start; |
| 477 | int i, i2, |
| 478 | cx = tft.width() / 2 - 1, |
| 479 | cy = tft.height() / 2 - 1; |
| 480 | |
| 481 | tft.fillScreen(ILI9341_BLACK); |
| 482 | start = micros(); |
| 483 | for(i=min(tft.width(), tft.height()); i>20; i-=6) { |
| 484 | i2 = i / 2; |
| 485 | tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); |
| 486 | yield(); |
| 487 | } |
| 488 | |
| 489 | return micros() - start; |
| 490 | } |
| 491 |
Hint:
- for other ILI9341 examples, do not forget to update the wiring pinout, the "tft" variable instantiating and to replace ALL "Serial." with "SerialUSB.".
Additional resources:
- xyz-mIoT shield pinout, port map and more pdf format or, in png format
- xyz-mIoT shield - block schematics rev 1.1
TUTORIAL PROVIDED WITHOUT ANY WARRANTY!!! USE IT AT YOUR OWN RISK!!!!