3 This example code is in the Public Domain (or CC0 licensed, at your option.)
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
14 #include "freertos/FreeRTOS.h"
15 #include "freertos/task.h"
19 #include "spiffs_vfs.h"
21 #ifdef CONFIG_EXAMPLE_USE_WIFI
24 #include "freertos/event_groups.h"
27 #include "nvs_flash.h"
32 // ==========================================================
33 // Define which spi bus to use TFT_VSPI_HOST or TFT_HSPI_HOST
34 #define SPI_BUS TFT_HSPI_HOST
35 // ==========================================================
38 static int _demo_pass = 0;
39 static uint8_t doprint = 1;
40 static uint8_t run_gs_demo = 0; // Run gray scale demo if set to 1
41 static struct tm* tm_info;
42 static char tmp_buff[64];
43 static time_t time_now, time_last = 0;
44 static const char *file_fonts[3] = {"/spiffs/fonts/DotMatrix_M.fon", "/spiffs/fonts/Ubuntu.fon", "/spiffs/fonts/Grotesk24x48.fon"};
46 #define GDEMO_TIME 1000
47 #define GDEMO_INFO_TIME 5000
49 //==================================================================================
50 #ifdef CONFIG_EXAMPLE_USE_WIFI
52 static const char tag[] = "[TFT Demo]";
54 /* FreeRTOS event group to signal when we are connected & ready to make a request */
55 static EventGroupHandle_t wifi_event_group;
57 /* The event group allows multiple bits for each event,
58 but we only care about one event - are we connected
59 to the AP with an IP? */
60 const int CONNECTED_BIT = 0x00000001;
62 //------------------------------------------------------------
63 static esp_err_t event_handler(void *ctx, system_event_t *event)
65 switch(event->event_id) {
66 case SYSTEM_EVENT_STA_START:
69 case SYSTEM_EVENT_STA_GOT_IP:
70 xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
72 case SYSTEM_EVENT_STA_DISCONNECTED:
73 /* This is a workaround as ESP32 WiFi libs don't currently
76 xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
84 //-------------------------------
85 static void initialise_wifi(void)
88 wifi_event_group = xEventGroupCreate();
89 ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
90 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
91 ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
92 ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
93 wifi_config_t wifi_config = {
95 .ssid = CONFIG_WIFI_SSID,
96 .password = CONFIG_WIFI_PASSWORD,
99 ESP_LOGI(tag, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
100 ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
101 ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
102 ESP_ERROR_CHECK( esp_wifi_start() );
105 //-------------------------------
106 static void initialize_sntp(void)
108 ESP_LOGI(tag, "Initializing SNTP");
109 sntp_setoperatingmode(SNTP_OPMODE_POLL);
110 sntp_setservername(0, "pool.ntp.org");
114 //--------------------------
115 static int obtain_time(void)
119 xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
123 // wait for time to be set
125 const int retry_count = 20;
128 tm_info = localtime(&time_now);
130 while(tm_info->tm_year < (2016 - 1900) && ++retry < retry_count) {
131 //ESP_LOGI(tag, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
132 sprintf(tmp_buff, "Wait %0d/%d", retry, retry_count);
133 TFT_print(tmp_buff, CENTER, LASTY);
134 vTaskDelay(500 / portTICK_RATE_MS);
136 tm_info = localtime(&time_now);
138 if (tm_info->tm_year < (2016 - 1900)) {
139 ESP_LOGI(tag, "System time NOT set.");
143 ESP_LOGI(tag, "System time is set.");
146 ESP_ERROR_CHECK( esp_wifi_stop() );
150 #endif //CONFIG_EXAMPLE_USE_WIFI
151 //==================================================================================
154 //----------------------
155 static void _checkTime()
158 if (time_now > time_last) {
159 color_t last_fg, last_bg;
160 time_last = time_now;
161 tm_info = localtime(&time_now);
162 sprintf(tmp_buff, "%02d:%02d:%02d", tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
167 Font curr_font = tft_cfont;
171 tft_bg = (color_t){ 64, 64, 64 };
172 TFT_setFont(DEFAULT_FONT, NULL);
174 TFT_fillRect(1, tft_height-TFT_getfontheight()-8, tft_width-3, TFT_getfontheight()+6, tft_bg);
175 TFT_print(tmp_buff, CENTER, tft_height-TFT_getfontheight()-5);
177 tft_cfont = curr_font;
181 TFT_restoreClipWin();
186 //----------------------
187 static int _checkTouch()
190 if (TFT_read_touch(&tx, &ty, 0)) {
191 while (TFT_read_touch(&tx, &ty, 1)) {
192 vTaskDelay(20 / portTICK_RATE_MS);
200 //---------------------
201 static int Wait(int ms)
209 vTaskDelay(ms / portTICK_RATE_MS);
210 //if (_checkTouch()) return 0;
213 for (int n=0; n<ms; n += 50) {
214 vTaskDelay(50 / portTICK_RATE_MS);
215 if (tm) _checkTime();
216 //if (_checkTouch()) return 0;
222 //-------------------------------------------------------------------
223 static unsigned int rand_interval(unsigned int min, unsigned int max)
226 const unsigned int range = 1 + max - min;
227 const unsigned int buckets = RAND_MAX / range;
228 const unsigned int limit = buckets * range;
230 /* Create equal size buckets all in a row, then fire randomly towards
231 * the buckets until you land in one of them. All buckets are equally
232 * likely. If you land off the end of the line of buckets, try again. */
236 } while (r >= limit);
238 return min + (r / buckets);
241 // Generate random color
242 //-----------------------------
243 static color_t random_color() {
246 color.r = (uint8_t)rand_interval(8,252);
247 color.g = (uint8_t)rand_interval(8,252);
248 color.b = (uint8_t)rand_interval(8,252);
252 //---------------------
253 static void _dispTime()
255 Font curr_font = tft_cfont;
256 if (tft_width < 240) TFT_setFont(DEF_SMALL_FONT, NULL);
257 else TFT_setFont(DEFAULT_FONT, NULL);
260 time_last = time_now;
261 tm_info = localtime(&time_now);
262 sprintf(tmp_buff, "%02d:%02d:%02d", tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
263 TFT_print(tmp_buff, CENTER, tft_height-TFT_getfontheight()-5);
265 tft_cfont = curr_font;
268 //---------------------------------
269 static void disp_header(char *info)
271 TFT_fillScreen(TFT_BLACK);
275 tft_bg = (color_t){ 64, 64, 64 };
277 if (tft_width < 240) TFT_setFont(DEF_SMALL_FONT, NULL);
278 else TFT_setFont(DEFAULT_FONT, NULL);
279 TFT_fillRect(0, 0, tft_width-1, TFT_getfontheight()+8, tft_bg);
280 TFT_drawRect(0, 0, tft_width-1, TFT_getfontheight()+8, TFT_CYAN);
282 TFT_fillRect(0, tft_height-TFT_getfontheight()-9, tft_width-1, TFT_getfontheight()+8, tft_bg);
283 TFT_drawRect(0, tft_height-TFT_getfontheight()-9, tft_width-1, TFT_getfontheight()+8, TFT_CYAN);
285 TFT_print(info, CENTER, 4);
289 TFT_setclipwin(0,TFT_getfontheight()+9, tft_width-1, tft_height-TFT_getfontheight()-10);
292 //---------------------------------------------
293 static void update_header(char *hdr, char *ftr)
295 color_t last_fg, last_bg;
300 Font curr_font = tft_cfont;
304 tft_bg = (color_t){ 64, 64, 64 };
305 if (tft_width < 240) TFT_setFont(DEF_SMALL_FONT, NULL);
306 else TFT_setFont(DEFAULT_FONT, NULL);
309 TFT_fillRect(1, 1, tft_width-3, TFT_getfontheight()+6, tft_bg);
310 TFT_print(hdr, CENTER, 4);
314 TFT_fillRect(1, tft_height-TFT_getfontheight()-8, tft_width-3, TFT_getfontheight()+6, tft_bg);
315 if (strlen(ftr) == 0) _dispTime();
316 else TFT_print(ftr, CENTER, tft_height-TFT_getfontheight()-5);
319 tft_cfont = curr_font;
323 TFT_restoreClipWin();
326 //------------------------
327 static void test_times() {
330 uint32_t tstart, t1, t2;
331 disp_header("TIMINGS");
332 // ** Show Fill screen and send_line timings
334 TFT_fillWindow(TFT_BLACK);
335 t1 = clock() - tstart;
336 printf(" Clear screen time: %u ms\r\n", t1);
337 TFT_setFont(SMALL_FONT, NULL);
338 sprintf(tmp_buff, "Clear screen: %u ms", t1);
339 TFT_print(tmp_buff, 0, 140);
341 color_t *color_line = heap_caps_malloc((tft_width*3), MALLOC_CAP_DMA);
342 color_t *gsline = NULL;
343 if (tft_gray_scale) gsline = malloc(tft_width*3);
345 float hue_inc = (float)((10.0 / (float)(tft_height-1) * 360.0));
346 for (int x=0; x<tft_width; x++) {
347 color_line[x] = HSBtoRGB(hue_inc, 1.0, (float)x / (float)tft_width);
348 if (gsline) gsline[x] = color_line[x];
352 for (int n=0; n<1000; n++) {
353 if (gsline) memcpy(color_line, gsline, tft_width*3);
354 send_data(0 + TFT_STATIC_X_OFFSET, 40+(n&63) + TFT_STATIC_Y_OFFSET, tft_dispWin.x2-tft_dispWin.x1 + TFT_STATIC_X_OFFSET , 40+(n&63) + TFT_STATIC_Y_OFFSET, (uint32_t)(tft_dispWin.x2-tft_dispWin.x1+1), color_line);
355 wait_trans_finish(1);
357 t2 = clock() - tstart;
360 printf("Send color buffer time: %u us (%d pixels)\r\n", t2, tft_dispWin.x2-tft_dispWin.x1+1);
363 sprintf(tmp_buff, " Send line: %u us", t2);
364 TFT_print(tmp_buff, 0, 144+TFT_getfontheight());
366 Wait(GDEMO_INFO_TIME);
371 //-------------------------
372 static void disp_images() {
375 disp_header("JPEG IMAGES");
377 if (spiffs_is_mounted) {
378 // ** Show scaled (1/8, 1/4, 1/2 size) JPG images
379 TFT_jpg_image(CENTER, CENTER, 3, SPIFFS_BASE_PATH"/images/test1.jpg", NULL, 0);
382 TFT_jpg_image(CENTER, CENTER, 2, SPIFFS_BASE_PATH"/images/test2.jpg", NULL, 0);
385 TFT_jpg_image(CENTER, CENTER, 1, SPIFFS_BASE_PATH"/images/test4.jpg", NULL, 0);
388 // ** Show full size JPG image
390 TFT_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH"/images/test3.jpg", NULL, 0);
391 tstart = clock() - tstart;
392 if (doprint) printf(" JPG Decode time: %u ms\r\n", tstart);
393 sprintf(tmp_buff, "Decode time: %u ms", tstart);
394 update_header(NULL, tmp_buff);
395 Wait(-GDEMO_INFO_TIME);
398 update_header("BMP IMAGE", "");
399 for (int scale=5; scale >= 0; scale--) {
401 TFT_bmp_image(CENTER, CENTER, scale, SPIFFS_BASE_PATH"/images/tiger.bmp", NULL, 0);
402 tstart = clock() - tstart;
403 if (doprint) printf(" BMP time, scale: %d: %u ms\r\n", scale, tstart);
404 sprintf(tmp_buff, "Decode time: %u ms", tstart);
405 update_header(NULL, tmp_buff);
408 Wait(-GDEMO_INFO_TIME);
410 else if (doprint) printf(" No file system found.\r\n");
413 //---------------------
414 static void font_demo()
419 disp_header("FONT DEMO");
421 end_time = clock() + GDEMO_TIME;
423 while ((clock() < end_time) && (Wait(0))) {
425 for (int f=DEFAULT_FONT; f<FONT_7SEG; f++) {
426 tft_fg = random_color();
427 TFT_setFont(f, NULL);
428 TFT_print("Welcome to ESP32", 4, y);
429 y += TFT_getfontheight() + 4;
433 sprintf(tmp_buff, "%d STRINGS", n);
434 update_header(NULL, tmp_buff);
435 Wait(-GDEMO_INFO_TIME);
437 if (spiffs_is_mounted) {
438 disp_header("FONT FROM FILE DEMO");
441 for (int f=0; f<3; f++) {
442 TFT_fillWindow(TFT_BLACK);
443 update_header(NULL, "");
445 TFT_setFont(USER_FONT, file_fonts[f]);
446 if (f == 0) tft_font_line_space = 4;
447 end_time = clock() + GDEMO_TIME;
449 while ((clock() < end_time) && (Wait(0))) {
450 tft_fg = random_color();
451 TFT_print("Welcome to ESP32\nThis is user font.", 0, 8);
454 if ((tft_width < 240) || (tft_height < 240)) TFT_setFont(DEF_SMALL_FONT, NULL);
455 else TFT_setFont(DEFAULT_FONT, NULL);
457 TFT_print((char *)file_fonts[f], 0, (tft_dispWin.y2-tft_dispWin.y1)-TFT_getfontheight()-4);
459 tft_font_line_space = 0;
460 sprintf(tmp_buff, "%d STRINGS", n);
461 update_header(NULL, tmp_buff);
462 Wait(-GDEMO_INFO_TIME);
467 disp_header("ROTATED FONT DEMO");
469 end_time = clock() + GDEMO_TIME;
471 while ((clock() < end_time) && (Wait(0))) {
472 for (int f=DEFAULT_FONT; f<FONT_7SEG; f++) {
473 tft_fg = random_color();
474 TFT_setFont(f, NULL);
475 x = rand_interval(8, tft_dispWin.x2-8);
476 y = rand_interval(0, (tft_dispWin.y2-tft_dispWin.y1)-TFT_getfontheight()-2);
477 tft_font_rotate = rand_interval(0, 359);
479 TFT_print("Welcome to ESP32", x, y);
484 sprintf(tmp_buff, "%d STRINGS", n);
485 update_header(NULL, tmp_buff);
486 Wait(-GDEMO_INFO_TIME);
488 disp_header("7-SEG FONT DEMO");
492 uint32_t ctime = clock();
493 end_time = clock() + GDEMO_TIME*2;
495 while ((clock() < end_time) && (Wait(0))) {
497 ms = clock() - ctime;
499 tm_info = localtime(&time_now);
500 if (tm_info->tm_sec != last_sec) {
501 last_sec = tm_info->tm_sec;
507 sprintf(tmp_buff, "%02d:%02d:%03d", tm_info->tm_min, tm_info->tm_sec, ms);
508 TFT_setFont(FONT_7SEG, NULL);
509 if ((tft_width < 240) || (tft_height < 240)) set_7seg_font_atrib(8, 1, 1, TFT_DARKGREY);
510 else set_7seg_font_atrib(12, 2, 1, TFT_DARKGREY);
511 //TFT_clearStringRect(12, y, tmp_buff);
512 TFT_print(tmp_buff, CENTER, y);
516 y += TFT_getfontheight() + 12;
517 if ((tft_width < 240) || (tft_height < 240)) set_7seg_font_atrib(9, 1, 1, TFT_DARKGREY);
518 else set_7seg_font_atrib(14, 3, 1, TFT_DARKGREY);
519 sprintf(tmp_buff, "%02d:%02d", tm_info->tm_sec, ms / 10);
520 //TFT_clearStringRect(12, y, tmp_buff);
521 TFT_print(tmp_buff, CENTER, y);
524 tft_fg = random_color();
525 y += TFT_getfontheight() + 8;
526 set_7seg_font_atrib(6, 1, 1, TFT_DARKGREY);
527 getFontCharacters((uint8_t *)tmp_buff);
528 //TFT_clearStringRect(12, y, tmp_buff);
529 TFT_print(tmp_buff, CENTER, y);
532 sprintf(tmp_buff, "%d STRINGS", n);
533 update_header(NULL, tmp_buff);
534 Wait(-GDEMO_INFO_TIME);
536 disp_header("WINDOW DEMO");
540 TFT_drawRect(38, 48, (tft_width*3/4) - 36, (tft_height*3/4) - 46, TFT_WHITE);
541 TFT_setclipwin(40, 50, tft_width*3/4, tft_height*3/4);
543 if ((tft_width < 240) || (tft_height < 240)) TFT_setFont(DEF_SMALL_FONT, NULL);
544 else TFT_setFont(UBUNTU16_FONT, NULL);
546 end_time = clock() + GDEMO_TIME;
548 while ((clock() < end_time) && (Wait(0))) {
549 tft_fg = random_color();
550 TFT_print("This text is printed inside the window.\nLong line can be wrapped to the next line.\nWelcome to ESP32", 0, 0);
554 sprintf(tmp_buff, "%d STRINGS", n);
555 update_header(NULL, tmp_buff);
556 Wait(-GDEMO_INFO_TIME);
558 TFT_restoreClipWin();
561 //---------------------
562 static void rect_demo()
566 disp_header("RECTANGLE DEMO");
568 uint32_t end_time = clock() + GDEMO_TIME;
570 while ((clock() < end_time) && (Wait(0))) {
571 x = rand_interval(4, tft_dispWin.x2-4);
572 y = rand_interval(4, tft_dispWin.y2-2);
573 w = rand_interval(2, tft_dispWin.x2-x);
574 h = rand_interval(2, tft_dispWin.y2-y);
575 TFT_drawRect(x,y,w,h,random_color());
578 sprintf(tmp_buff, "%d RECTANGLES", n);
579 update_header(NULL, tmp_buff);
580 Wait(-GDEMO_INFO_TIME);
582 update_header("FILLED RECTANGLE", "");
583 TFT_fillWindow(TFT_BLACK);
584 end_time = clock() + GDEMO_TIME;
586 while ((clock() < end_time) && (Wait(0))) {
587 x = rand_interval(4, tft_dispWin.x2-4);
588 y = rand_interval(4, tft_dispWin.y2-2);
589 w = rand_interval(2, tft_dispWin.x2-x);
590 h = rand_interval(2, tft_dispWin.y2-y);
591 TFT_fillRect(x,y,w,h,random_color());
592 TFT_drawRect(x,y,w,h,random_color());
595 sprintf(tmp_buff, "%d RECTANGLES", n);
596 update_header(NULL, tmp_buff);
597 Wait(-GDEMO_INFO_TIME);
600 //----------------------
601 static void pixel_demo()
605 disp_header("DRAW PIXEL DEMO");
607 uint32_t end_time = clock() + GDEMO_TIME;
609 while ((clock() < end_time) && (Wait(0))) {
610 x = rand_interval(0, tft_dispWin.x2);
611 y = rand_interval(0, tft_dispWin.y2);
612 TFT_drawPixel(x,y,random_color(),1);
615 sprintf(tmp_buff, "%d PIXELS", n);
616 update_header(NULL, tmp_buff);
617 Wait(-GDEMO_INFO_TIME);
620 //---------------------
621 static void line_demo()
623 int x1, y1, x2, y2, n;
625 disp_header("LINE DEMO");
627 uint32_t end_time = clock() + GDEMO_TIME;
629 while ((clock() < end_time) && (Wait(0))) {
630 x1 = rand_interval(0, tft_dispWin.x2);
631 y1 = rand_interval(0, tft_dispWin.y2);
632 x2 = rand_interval(0, tft_dispWin.x2);
633 y2 = rand_interval(0, tft_dispWin.y2);
634 TFT_drawLine(x1,y1,x2,y2,random_color());
637 sprintf(tmp_buff, "%d LINES", n);
638 update_header(NULL, tmp_buff);
639 Wait(-GDEMO_INFO_TIME);
642 //----------------------
643 static void aline_demo()
645 int x, y, len, angle, n;
647 disp_header("LINE BY ANGLE DEMO");
649 x = (tft_dispWin.x2 - tft_dispWin.x1) / 2;
650 y = (tft_dispWin.y2 - tft_dispWin.y1) / 2;
651 if (x < y) len = x - 8;
654 uint32_t end_time = clock() + GDEMO_TIME;
656 while ((clock() < end_time) && (Wait(0))) {
657 for (angle=0; angle < 360; angle++) {
658 TFT_drawLineByAngle(x,y, 0, len, angle, random_color());
663 TFT_fillWindow(TFT_BLACK);
664 end_time = clock() + GDEMO_TIME;
665 while ((clock() < end_time) && (Wait(0))) {
666 for (angle=0; angle < 360; angle++) {
667 TFT_drawLineByAngle(x, y, len/4, len/4,angle, random_color());
670 for (angle=0; angle < 360; angle++) {
671 TFT_drawLineByAngle(x, y, len*3/4, len/4,angle, random_color());
675 sprintf(tmp_buff, "%d LINES", n);
676 update_header(NULL, tmp_buff);
677 Wait(-GDEMO_INFO_TIME);
680 //--------------------
681 static void arc_demo()
683 uint16_t x, y, r, th, n, i;
685 color_t color, fillcolor;
687 disp_header("ARC DEMO");
689 x = (tft_dispWin.x2 - tft_dispWin.x1) / 2;
690 y = (tft_dispWin.y2 - tft_dispWin.y1) / 2;
693 uint32_t end_time = clock() + GDEMO_TIME;
695 while ((clock() < end_time) && (Wait(0))) {
696 if (x < y) r = x - 4;
702 color = random_color();
703 TFT_drawArc(x, y, r, th, start, end, color, color);
707 end = start + (n*20);
711 sprintf(tmp_buff, "%d ARCS", i);
712 update_header(NULL, tmp_buff);
713 Wait(-GDEMO_INFO_TIME);
715 update_header("OUTLINED ARC", "");
716 TFT_fillWindow(TFT_BLACK);
718 end_time = clock() + GDEMO_TIME;
720 while ((clock() < end_time) && (Wait(0))) {
721 if (x < y) r = x - 4;
727 color = random_color();
728 fillcolor = random_color();
729 TFT_drawArc(x, y, r, th, start, end, color, fillcolor);
737 sprintf(tmp_buff, "%d ARCS", i);
738 update_header(NULL, tmp_buff);
739 Wait(-GDEMO_INFO_TIME);
742 //-----------------------
743 static void circle_demo()
747 disp_header("CIRCLE DEMO");
749 uint32_t end_time = clock() + GDEMO_TIME;
751 while ((clock() < end_time) && (Wait(0))) {
752 x = rand_interval(8, tft_dispWin.x2-8);
753 y = rand_interval(8, tft_dispWin.y2-8);
754 if (x < y) r = rand_interval(2, x/2);
755 else r = rand_interval(2, y/2);
756 TFT_drawCircle(x,y,r,random_color());
759 sprintf(tmp_buff, "%d CIRCLES", n);
760 update_header(NULL, tmp_buff);
761 Wait(-GDEMO_INFO_TIME);
763 update_header("FILLED CIRCLE", "");
764 TFT_fillWindow(TFT_BLACK);
765 end_time = clock() + GDEMO_TIME;
767 while ((clock() < end_time) && (Wait(0))) {
768 x = rand_interval(8, tft_dispWin.x2-8);
769 y = rand_interval(8, tft_dispWin.y2-8);
770 if (x < y) r = rand_interval(2, x/2);
771 else r = rand_interval(2, y/2);
772 TFT_fillCircle(x,y,r,random_color());
773 TFT_drawCircle(x,y,r,random_color());
776 sprintf(tmp_buff, "%d CIRCLES", n);
777 update_header(NULL, tmp_buff);
778 Wait(-GDEMO_INFO_TIME);
781 //------------------------
782 static void ellipse_demo()
786 disp_header("ELLIPSE DEMO");
788 uint32_t end_time = clock() + GDEMO_TIME;
790 while ((clock() < end_time) && (Wait(0))) {
791 x = rand_interval(8, tft_dispWin.x2-8);
792 y = rand_interval(8, tft_dispWin.y2-8);
793 if (x < y) rx = rand_interval(2, x/4);
794 else rx = rand_interval(2, y/4);
795 if (x < y) ry = rand_interval(2, x/4);
796 else ry = rand_interval(2, y/4);
797 TFT_drawEllipse(x,y,rx,ry,random_color(),15);
800 sprintf(tmp_buff, "%d ELLIPSES", n);
801 update_header(NULL, tmp_buff);
802 Wait(-GDEMO_INFO_TIME);
804 update_header("FILLED ELLIPSE", "");
805 TFT_fillWindow(TFT_BLACK);
806 end_time = clock() + GDEMO_TIME;
808 while ((clock() < end_time) && (Wait(0))) {
809 x = rand_interval(8, tft_dispWin.x2-8);
810 y = rand_interval(8, tft_dispWin.y2-8);
811 if (x < y) rx = rand_interval(2, x/4);
812 else rx = rand_interval(2, y/4);
813 if (x < y) ry = rand_interval(2, x/4);
814 else ry = rand_interval(2, y/4);
815 TFT_fillEllipse(x,y,rx,ry,random_color(),15);
816 TFT_drawEllipse(x,y,rx,ry,random_color(),15);
819 sprintf(tmp_buff, "%d ELLIPSES", n);
820 update_header(NULL, tmp_buff);
821 Wait(-GDEMO_INFO_TIME);
823 update_header("ELLIPSE SEGMENTS", "");
824 TFT_fillWindow(TFT_BLACK);
825 end_time = clock() + GDEMO_TIME;
828 while ((clock() < end_time) && (Wait(0))) {
829 x = rand_interval(8, tft_dispWin.x2-8);
830 y = rand_interval(8, tft_dispWin.y2-8);
831 if (x < y) rx = rand_interval(2, x/4);
832 else rx = rand_interval(2, y/4);
833 if (x < y) ry = rand_interval(2, x/4);
834 else ry = rand_interval(2, y/4);
835 TFT_fillEllipse(x,y,rx,ry,random_color(), (1<<k));
836 TFT_drawEllipse(x,y,rx,ry,random_color(), (1<<k));
840 sprintf(tmp_buff, "%d SEGMENTS", n);
841 update_header(NULL, tmp_buff);
842 Wait(-GDEMO_INFO_TIME);
845 //-------------------------
846 static void triangle_demo()
848 int x1, y1, x2, y2, x3, y3, n;
850 disp_header("TRIANGLE DEMO");
852 uint32_t end_time = clock() + GDEMO_TIME;
854 while ((clock() < end_time) && (Wait(0))) {
855 x1 = rand_interval(4, tft_dispWin.x2-4);
856 y1 = rand_interval(4, tft_dispWin.y2-2);
857 x2 = rand_interval(4, tft_dispWin.x2-4);
858 y2 = rand_interval(4, tft_dispWin.y2-2);
859 x3 = rand_interval(4, tft_dispWin.x2-4);
860 y3 = rand_interval(4, tft_dispWin.y2-2);
861 TFT_drawTriangle(x1,y1,x2,y2,x3,y3,random_color());
864 sprintf(tmp_buff, "%d TRIANGLES", n);
865 update_header(NULL, tmp_buff);
866 Wait(-GDEMO_INFO_TIME);
868 update_header("FILLED TRIANGLE", "");
869 TFT_fillWindow(TFT_BLACK);
870 end_time = clock() + GDEMO_TIME;
872 while ((clock() < end_time) && (Wait(0))) {
873 x1 = rand_interval(4, tft_dispWin.x2-4);
874 y1 = rand_interval(4, tft_dispWin.y2-2);
875 x2 = rand_interval(4, tft_dispWin.x2-4);
876 y2 = rand_interval(4, tft_dispWin.y2-2);
877 x3 = rand_interval(4, tft_dispWin.x2-4);
878 y3 = rand_interval(4, tft_dispWin.y2-2);
879 TFT_fillTriangle(x1,y1,x2,y2,x3,y3,random_color());
880 TFT_drawTriangle(x1,y1,x2,y2,x3,y3,random_color());
883 sprintf(tmp_buff, "%d TRIANGLES", n);
884 update_header(NULL, tmp_buff);
885 Wait(-GDEMO_INFO_TIME);
888 //---------------------
889 static void poly_demo()
891 uint16_t x, y, rot, oldrot;
893 uint8_t sides[6] = {3, 4, 5, 6, 8, 10};
894 color_t color[6] = {TFT_WHITE, TFT_CYAN, TFT_RED, TFT_BLUE, TFT_YELLOW, TFT_ORANGE};
895 color_t fill[6] = {TFT_BLUE, TFT_NAVY, TFT_DARKGREEN, TFT_DARKGREY, TFT_LIGHTGREY, TFT_OLIVE};
897 disp_header("POLYGON DEMO");
899 x = (tft_dispWin.x2 - tft_dispWin.x1) / 2;
900 y = (tft_dispWin.y2 - tft_dispWin.y1) / 2;
904 uint32_t end_time = clock() + GDEMO_TIME;
906 while ((clock() < end_time) && (Wait(0))) {
907 if (x < y) r = x - 4;
909 for (i=5; i>=0; i--) {
910 TFT_drawPolygon(x, y, sides[i], r, TFT_BLACK, TFT_BLACK, oldrot, 1);
911 TFT_drawPolygon(x, y, sides[i], r, color[i], color[i], rot, 1);
913 if (r <= 0) { break; };
918 rot = (rot + 15) % 360;
920 sprintf(tmp_buff, "%d POLYGONS", n);
921 update_header(NULL, tmp_buff);
922 Wait(-GDEMO_INFO_TIME);
924 update_header("FILLED POLYGON", "");
926 end_time = clock() + GDEMO_TIME;
928 while ((clock() < end_time) && (Wait(0))) {
929 if (x < y) r = x - 4;
931 TFT_fillWindow(TFT_BLACK);
932 for (i=5; i>=0; i--) {
933 TFT_drawPolygon(x, y, sides[i], r, color[i], fill[i], rot, 2);
935 if (r <= 0) { break; }
939 rot = (rot + 15) % 360;
941 sprintf(tmp_buff, "%d POLYGONS", n);
942 update_header(NULL, tmp_buff);
943 Wait(-GDEMO_INFO_TIME);
946 //----------------------
947 static void touch_demo()
950 int tx, ty, ltx, lty, doexit = 0;
952 disp_header("TOUCH DEMO");
953 TFT_setFont(DEFAULT_FONT, NULL);
955 TFT_print("Touch to draw", CENTER, 40);
956 TFT_print("Touch footer to clear", CENTER, 60);
961 if (TFT_read_touch(&tx, &ty, 0)) {
963 if (((tx >= tft_dispWin.x1) && (tx <= tft_dispWin.x2)) &&
964 ((ty >= tft_dispWin.y1) && (ty <= tft_dispWin.y2))) {
965 if ((doexit > 2) || ((abs(tx-ltx) < 5) && (abs(ty-lty) < 5))) {
966 if (((abs(tx-ltx) > 0) || (abs(ty-lty) > 0))) {
967 TFT_fillCircle(tx-tft_dispWin.x1, ty-tft_dispWin.y1, 4,random_color());
968 sprintf(tmp_buff, "%d,%d", tx, ty);
969 update_header(NULL, tmp_buff);
976 else if (ty > (tft_dispWin.y2+5)) TFT_fillWindow(TFT_BLACK);
979 if (doexit == 2) update_header(NULL, "---");
980 if (doexit > 50) return;
981 vTaskDelay(100 / portTICK_RATE_MS);
986 if (doexit == 2) update_header(NULL, "---");
987 if (doexit > 50) return;
988 vTaskDelay(100 / portTICK_RATE_MS);
1000 tft_font_transparent = 0;
1001 tft_font_forceFixed = 0;
1004 tft_image_debug = 0;
1008 switch (tft_disp_type) {
1009 case DISP_TYPE_ILI9341:
1010 sprintf(dtype, "ILI9341");
1012 case DISP_TYPE_ILI9488:
1013 sprintf(dtype, "ILI9488");
1015 case DISP_TYPE_ST7789V:
1016 sprintf(dtype, "ST7789V");
1018 case DISP_TYPE_ST7735:
1019 sprintf(dtype, "ST7735");
1021 case DISP_TYPE_ST7735R:
1022 sprintf(dtype, "ST7735R");
1024 case DISP_TYPE_ST7735B:
1025 sprintf(dtype, "ST7735B");
1028 sprintf(dtype, "Unknown");
1031 uint8_t disp_rot = PORTRAIT;
1036 TFT_setRotation(disp_rot);
1037 disp_header("ESP32 TFT DEMO");
1038 TFT_setFont(COMIC24_FONT, NULL);
1039 int tempy = TFT_getfontheight() + 4;
1040 tft_fg = TFT_ORANGE;
1041 TFT_print("ESP32", CENTER, (tft_dispWin.y2-tft_dispWin.y1)/2 - tempy);
1042 TFT_setFont(UBUNTU16_FONT, NULL);
1044 TFT_print("TFT Demo", CENTER, LASTY+tempy);
1045 tempy = TFT_getfontheight() + 4;
1046 TFT_setFont(DEFAULT_FONT, NULL);
1048 sprintf(tmp_buff, "Read speed: %5.2f MHz", (float)tft_max_rdclock/1000000.0);
1049 TFT_print(tmp_buff, CENTER, LASTY+tempy);
1055 if (_demo_pass == 8) doprint = 0;
1056 // Change gray scale mode on every 2nd pass
1057 tft_gray_scale = _demo_pass & 1;
1058 // change display rotation
1059 if ((_demo_pass % 2) == 0) {
1061 TFT_setRotation(disp_rot);
1067 if (_demo_pass == 4) doprint = 0;
1068 // change display rotation
1070 TFT_setRotation(disp_rot);
1076 if (disp_rot == 1) sprintf(tmp_buff, "PORTRAIT");
1077 if (disp_rot == 2) sprintf(tmp_buff, "LANDSCAPE");
1078 if (disp_rot == 3) sprintf(tmp_buff, "PORTRAIT FLIP");
1079 if (disp_rot == 0) sprintf(tmp_buff, "LANDSCAPE FLIP");
1080 printf("\r\n==========================================\r\nDisplay: %s: %s %d,%d %s\r\n\r\n",
1081 dtype, tmp_buff, tft_width, tft_height, ((tft_gray_scale) ? "Gray" : "Color"));
1084 disp_header("Welcome to ESP32");
1105 // ================== TEST SD CARD ==========================================
1107 #include "esp_vfs_fat.h"
1108 #include "driver/sdmmc_host.h"
1109 #include "driver/sdspi_host.h"
1110 #include "sdmmc_cmd.h"
1112 // This example can use SDMMC and SPI peripherals to communicate with SD card.
1115 // When testing SD and SPI modes, keep in mind that once the card has been
1116 // initialized in SPI mode, it can not be reinitialized in SD mode without
1117 // toggling power to the card.
1119 // Pin mapping when using SPI mode.
1120 // With this mapping, SD card can be used both in SPI and 1-line SD mode.
1121 // Note that a pull-up on CS line is required in SD mode.
1122 #define sdPIN_NUM_MISO 19
1123 #define sdPIN_NUM_MOSI 18
1124 #define sdPIN_NUM_CLK 5
1125 #define sdPIN_NUM_CS 14
1127 static const char *TAG = "SDCard test";
1129 void test_sd_card(void)
1131 printf("\n=======================================================\n");
1132 printf("===== Test using SD Card in SPI mode =====\n");
1133 printf("===== SD Card uses the same gpio's as TFT display =====\n");
1134 printf("=======================================================\n\n");
1135 ESP_LOGI(TAG, "Initializing SD card");
1136 ESP_LOGI(TAG, "Using SPI peripheral");
1138 sdmmc_host_t host = SDSPI_HOST_DEFAULT();
1139 sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
1140 slot_config.gpio_miso = sdPIN_NUM_MISO;
1141 slot_config.gpio_mosi = sdPIN_NUM_MOSI;
1142 slot_config.gpio_sck = sdPIN_NUM_CLK;
1143 slot_config.gpio_cs = sdPIN_NUM_CS;
1144 // This initializes the slot without card detect (CD) and write protect (WP) signals.
1145 // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
1147 // Options for mounting the filesystem.
1148 // If format_if_mount_failed is set to true, SD card will be partitioned and
1149 // formatted in case when mounting fails.
1150 esp_vfs_fat_sdmmc_mount_config_t mount_config = {
1151 .format_if_mount_failed = false,
1155 // Use settings defined above to initialize SD card and mount FAT filesystem.
1156 // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
1157 // Please check its source code and implement error recovery when developing
1158 // production applications.
1160 esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
1162 if (ret != ESP_OK) {
1163 if (ret == ESP_FAIL) {
1164 ESP_LOGE(TAG, "Failed to mount filesystem. "
1165 "If you want the card to be formatted, set format_if_mount_failed = true.");
1167 ESP_LOGE(TAG, "Failed to initialize the card (%d). "
1168 "Make sure SD card lines have pull-up resistors in place.", ret);
1173 // Card has been initialized, print its properties
1174 sdmmc_card_print_info(stdout, card);
1176 // Use POSIX and C standard library functions to work with files.
1177 // First create a file.
1178 ESP_LOGI(TAG, "Opening file");
1179 FILE* f = fopen("/sdcard/hello.txt", "w");
1181 ESP_LOGE(TAG, "Failed to open file for writing");
1184 fprintf(f, "Hello %s!\n", card->cid.name);
1186 ESP_LOGI(TAG, "File written");
1188 // Check if destination file exists before renaming
1190 if (stat("/sdcard/foo.txt", &st) == 0) {
1191 // Delete it if it exists
1192 unlink("/sdcard/foo.txt");
1195 // Rename original file
1196 ESP_LOGI(TAG, "Renaming file");
1197 if (rename("/sdcard/hello.txt", "/sdcard/foo.txt") != 0) {
1198 ESP_LOGE(TAG, "Rename failed");
1202 // Open renamed file for reading
1203 ESP_LOGI(TAG, "Reading file");
1204 f = fopen("/sdcard/foo.txt", "r");
1206 ESP_LOGE(TAG, "Failed to open file for reading");
1210 fgets(line, sizeof(line), f);
1213 char* pos = strchr(line, '\n');
1217 ESP_LOGI(TAG, "Read from file: '%s'", line);
1219 // All done, unmount partition and disable SDMMC or SPI peripheral
1220 esp_vfs_fat_sdmmc_unmount();
1221 ESP_LOGI(TAG, "Card unmounted");
1223 printf("===== SD Card test end ================================\n\n");
1226 // ================== TEST SD CARD ==========================================
1234 // ======== PREPARE DISPLAY INITIALIZATION =========
1238 // === SET GLOBAL VARIABLES ==========================
1240 // ===================================================
1241 // ==== Set maximum spi clock for display read ====
1242 // operations, function 'find_rd_speed()' ====
1243 // can be used after display initialization ====
1244 tft_max_rdclock = 8000000;
1245 // ===================================================
1247 // ====================================================================
1248 // === Pins MUST be initialized before SPI interface initialization ===
1249 // ====================================================================
1252 // ==== CONFIGURE SPI DEVICES(s) ====================================================================================
1254 spi_lobo_device_handle_t spi;
1256 spi_lobo_bus_config_t buscfg={
1257 .miso_io_num=PIN_NUM_MISO, // set SPI MISO pin
1258 .mosi_io_num=PIN_NUM_MOSI, // set SPI MOSI pin
1259 .sclk_io_num=PIN_NUM_CLK, // set SPI CLK pin
1262 .max_transfer_sz = 6*1024,
1264 spi_lobo_device_interface_config_t devcfg={
1265 .clock_speed_hz=8000000, // Initial clock out at 8 MHz
1266 .mode=0, // SPI mode 0
1267 .spics_io_num=-1, // we will use external CS pin
1268 .spics_ext_io_num=PIN_NUM_CS, // external CS pin
1269 .flags=LB_SPI_DEVICE_HALFDUPLEX, // ALWAYS SET to HALF DUPLEX MODE!! for display spi
1272 #if USE_TOUCH == TOUCH_TYPE_XPT2046
1273 spi_lobo_device_handle_t tsspi = NULL;
1275 spi_lobo_device_interface_config_t tsdevcfg={
1276 .clock_speed_hz=2500000, //Clock out at 2.5 MHz
1277 .mode=0, //SPI mode 0
1278 .spics_io_num=PIN_NUM_TCS, //Touch CS pin
1279 .spics_ext_io_num=-1, //Not using the external CS
1280 //.command_bits=8, //1 byte command
1282 #elif USE_TOUCH == TOUCH_TYPE_STMPE610
1283 spi_lobo_device_handle_t tsspi = NULL;
1285 spi_lobo_device_interface_config_t tsdevcfg={
1286 .clock_speed_hz=1000000, //Clock out at 1 MHz
1287 .mode=STMPE610_SPI_MODE, //SPI mode 0
1288 .spics_io_num=PIN_NUM_TCS, //Touch CS pin
1289 .spics_ext_io_num=-1, //Not using the external CS
1294 // ====================================================================================================================
1297 vTaskDelay(500 / portTICK_RATE_MS);
1298 printf("\r\n==============================\r\n");
1299 printf("TFT display DEMO, LoBo 11/2017\r\n");
1300 printf("==============================\r\n");
1301 printf("Pins used: miso=%d, mosi=%d, sck=%d, cs=%d\r\n", PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK, PIN_NUM_CS);
1302 #if USE_TOUCH > TOUCH_TYPE_NONE
1303 printf(" Touch CS: %d\r\n", PIN_NUM_TCS);
1305 printf("==============================\r\n\r\n");
1307 // ==================================================================
1308 // ==== Initialize the SPI bus and attach the LCD to the SPI bus ====
1310 ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &devcfg, &spi);
1311 assert(ret==ESP_OK);
1312 printf("SPI: display device added to spi bus (%d)\r\n", SPI_BUS);
1315 // ==== Test select/deselect ====
1316 ret = spi_lobo_device_select(spi, 1);
1317 assert(ret==ESP_OK);
1318 ret = spi_lobo_device_deselect(spi);
1319 assert(ret==ESP_OK);
1321 printf("SPI: attached display device, speed=%u\r\n", spi_lobo_get_speed(spi));
1322 printf("SPI: bus uses native pins: %s\r\n", spi_lobo_uses_native_pins(spi) ? "true" : "false");
1324 #if USE_TOUCH > TOUCH_TYPE_NONE
1325 // =====================================================
1326 // ==== Attach the touch screen to the same SPI bus ====
1328 ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &tsdevcfg, &tsspi);
1329 assert(ret==ESP_OK);
1330 printf("SPI: touch screen device added to spi bus (%d)\r\n", SPI_BUS);
1333 // ==== Test select/deselect ====
1334 ret = spi_lobo_device_select(tsspi, 1);
1335 assert(ret==ESP_OK);
1336 ret = spi_lobo_device_deselect(tsspi);
1337 assert(ret==ESP_OK);
1339 printf("SPI: attached TS device, speed=%u\r\n", spi_lobo_get_speed(tsspi));
1342 // ================================
1343 // ==== Initialize the Display ====
1345 printf("SPI: display init...\r\n");
1347 #ifdef TFT_START_COLORS_INVERTED
1348 TFT_invertDisplay(1);
1351 #if USE_TOUCH == TOUCH_TYPE_STMPE610
1353 vTaskDelay(10 / portTICK_RATE_MS);
1354 uint32_t tver = stmpe610_getID();
1355 printf("STMPE touch initialized, ver: %04x - %02x\r\n", tver >> 8, tver & 0xFF);
1358 // ---- Detect maximum read speed ----
1359 tft_max_rdclock = find_rd_speed();
1360 printf("SPI: Max rd speed = %u\r\n", tft_max_rdclock);
1362 // ==== Set SPI clock used for display operations ====
1363 spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK);
1364 printf("SPI: Changed speed to %u\r\n", spi_lobo_get_speed(spi));
1366 printf("\r\n---------------------\r\n");
1367 printf("Graphics demo started\r\n");
1368 printf("---------------------\r\n");
1370 tft_font_rotate = 0;
1372 tft_font_transparent = 0;
1373 tft_font_forceFixed = 0;
1375 TFT_setGammaCurve(DEFAULT_GAMMA_CURVE);
1376 TFT_setRotation(PORTRAIT);
1377 TFT_setFont(DEFAULT_FONT, NULL);
1380 #ifdef CONFIG_EXAMPLE_USE_WIFI
1382 ESP_ERROR_CHECK( nvs_flash_init() );
1384 // ===== Set time zone ======
1385 setenv("TZ", "CET-1CEST", 0);
1387 // ==========================
1389 disp_header("GET NTP TIME");
1392 tm_info = localtime(&time_now);
1394 // Is time set? If not, tm_year will be (1970 - 1900).
1395 if (tm_info->tm_year < (2016 - 1900)) {
1396 ESP_LOGI(tag, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
1398 TFT_print("Time is not set yet", CENTER, CENTER);
1399 TFT_print("Connecting to WiFi", CENTER, LASTY+TFT_getfontheight()+2);
1400 TFT_print("Getting time over NTP", CENTER, LASTY+TFT_getfontheight()+2);
1401 tft_fg = TFT_YELLOW;
1402 TFT_print("Wait", CENTER, LASTY+TFT_getfontheight()+2);
1403 if (obtain_time()) {
1405 TFT_print("System time is set.", CENTER, LASTY);
1409 TFT_print("ERROR.", CENTER, LASTY);
1412 update_header(NULL, "");
1417 disp_header("File system INIT");
1419 TFT_print("Initializing SPIFFS...", CENTER, CENTER);
1420 // ==== Initialize the file system ====
1422 vfs_spiffs_register();
1423 if (!spiffs_is_mounted) {
1425 TFT_print("SPIFFS not mounted !", CENTER, LASTY+TFT_getfontheight()+2);
1429 TFT_print("SPIFFS Mounted.", CENTER, LASTY+TFT_getfontheight()+2);