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!!!!