Intro
This is the second installment of material that will contribute to a road test of the Arduino GIGA R1 and its LCD.
The Arduino web site has an example of how to display an image stored on a USB memory stick, but it needs the IDE serial monitor to work. I wanted to operate stand-alone using the touch screen to step to the next image.
Here is a short video showing the result:
Giga Touch USB Image Demo
The images stored on the USB memory need to be 800 x 480 in RGB565 format (binary). These images end up being 768 kbytes each so it is useful to store them on an external USB memory device.
Here is the firmware program:
Firmware
// Arduino GIGA R1 program to display images stored on a USB memory device // by Doug Wong 2025 // Touching the screen displays the next image // The image will roll over to thr first image after the last image // Image format should be 800 x 480 in RGB565 format - binary #include <Arduino_USBHostMbed5.h> #include <DigitalOut.h> #include <FATFileSystem.h> #include <Arduino_H7_Video.h> #include <ArduinoGraphics.h> #include "Arduino_GigaDisplayTouch.h" Arduino_GigaDisplayTouch touchDetector; USBHostMSD msd; mbed::FATFileSystem usb("usb"); const int USB_HOST_ENABLE_PIN = PA_15; const int MAX_FILES = 50; const int MAX_NAME_LEN = 128; char fileNames[MAX_FILES][MAX_NAME_LEN]; int fileCount = 0; const int MAX_CONNECTION_ATTEMPTS = 10; int filenum = 0; // file number selected Arduino_H7_Video Display(800, 480, GigaDisplayShield); const int IMG_WIDTH = 800; const int IMG_HEIGHT = 480; const uint32_t EXPECTED_FILE_SIZE = IMG_WIDTH * IMG_HEIGHT * 2; uint8_t rowBuffer[IMG_WIDTH * 2]; // Static buffer void setup() { Serial.begin(115200); touchDetector.begin(); pinMode(USB_HOST_ENABLE_PIN, OUTPUT); digitalWrite(USB_HOST_ENABLE_PIN, HIGH); while (!Serial) {} delay(1500); Serial.println("=== USB File List ==="); Display.begin(); forceScreenClear(); if (!initUSBHost() || !mountUSB()) return; listRootDirectory(); if (fileCount == 0) return; printFileList(); Serial.println("Select a file # to open as 800x480 .bin, or type 'clear' to reset the screen:"); } void loop() { if (fileCount > 0) handleUserInput(); uint8_t contacts; GDTpoint_t points[5]; contacts = touchDetector.getTouchPoints(points); //capture touches on touchscreen if (contacts > 0) { //Check for screen touch filenum++; //increment filenumber if (filenum > fileCount) filenum = 1; //handle rollover when filenum exceeds filecount displayRawRowByRow(fileNames[filenum-1]); //call image disply of file number } contacts = touchDetector.getTouchPoints(points); //check screen for touches - should br none at this time contacts = 0; //clear any touch count anyway delay (20); } bool initUSBHost() { for (int i = 0; i < MAX_CONNECTION_ATTEMPTS; i++) { if (msd.connect()) { Serial.println("USB mass storage device connected!"); return true; } Serial.println("USB device not detected, retrying..."); delay(1000); } return false; } bool mountUSB() { Serial.print("Mounting USB device... "); if (usb.mount(&msd)) { Serial.println("Failed to mount USB."); return false; } Serial.println("done."); return true; } void listRootDirectory() { fileCount = 0; DIR* dir = opendir("/usb/"); if (!dir) return; while (fileCount < MAX_FILES) { struct dirent* entry = readdir(dir); if (!entry) break; strncpy(fileNames[fileCount], entry->d_name, MAX_NAME_LEN - 1); fileNames[fileCount][MAX_NAME_LEN - 1] = '\0'; fileCount++; } closedir(dir); } void printFileList() { Serial.print("Found "); Serial.print(fileCount); Serial.println(" file(s) in /usb/:"); for (int i = 0; i < fileCount; i++) { Serial.print(i + 1); Serial.print(") "); Serial.println(fileNames[i]); } } void handleUserInput() { if (Serial.available() > 0) { String input = Serial.readStringUntil('\n'); input.trim(); if (input.equalsIgnoreCase("clear")) { forceScreenClear(); return; } int sel = input.toInt(); if (sel < 1 || sel > fileCount) return; Serial.print("Displaying: /usb/"); Serial.println(fileNames[sel - 1]); displayRawRowByRow(fileNames[sel - 1]); } } bool displayRawRowByRow(const char* fileName) { String path = "/usb/" + String(fileName); FILE* f = fopen(path.c_str(), "rb"); if (!f) return false; forceScreenClear(); Display.beginDraw(); for (int y = 0; y < IMG_HEIGHT; y++) { if (fread(rowBuffer, 1, IMG_WIDTH * 2, f) != IMG_WIDTH * 2) break; Image rowImage(ENCODING_RGB16, rowBuffer, IMG_WIDTH, 1); Display.image(rowImage, 0, y); } Display.endDraw(); fclose(f); Serial.println("Image displayed successfully!"); return true; } void forceScreenClear() { Display.beginDraw(); Display.fill(0x0000); Display.endDraw(); }
Discussion
The Arduino GIGA R1 has many individual features that can be combined to produce really impressive functionality. In the road test I want to go a bit beyond what is available in the already extensive set of demo examples. This demo uses the LCD, the touch screen, and the USB host interface to create a touch controlled slide show of images stored on an external USB memory device. I am blown away at how simple it is to create a demonstration with this level of complexity. I just needed to integrate a couple of demo programs and of course generate some nice images to display. Initially I had some extra touch events that caused images to flash by, but eventually I figured out how to obtain decent control. There are lots more features to explore....