Skip to content

Commit bf22ac3

Browse files
Updated images + added settings for images
1 parent 5af9544 commit bf22ac3

File tree

4 files changed

+153
-13
lines changed

4 files changed

+153
-13
lines changed

content/hardware/10.mega/shields/giga-display-shield/tutorials/13.usb-display/content.md

Lines changed: 153 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: GIGA Display Shield emWin Guide
2+
title: GIGA Display Shield Display from USB guide
33
description: 'Learn to display RAW Images on the GIGA Display from USB Storage.'
44
author: Pedro Sousa Lima
55
tags: [Display, USB]
@@ -33,24 +33,29 @@ This guide explores how to read and display raw RGB565 images from a USB drive o
3333
## Preparing Your Image
3434

3535
To ensure your image is in the correct format (800x480, 16-bit RGB565), you can use an online converter such as the [**LVGL Image Converter**](https://lvgl.io/tools/imageconverter). Select **RGB565** as the output format and set the resolution to 800x480 before saving the file to your USB drive. Make sure the USB drive is formatted for FAT32.
36+
For testing we used the image:
37+
![Unprepared test image](assets/lupe800x480.jpg)
38+
39+
For image convertion we selected the following settings:
40+
![Image settings](assets/lvgl-converter-settings.png)
3641

3742
## Code Breakdown
3843

3944
### Setting Up USB Host and Display
4045

4146
With the following code the USB host is initialized, enabling support for mass storage devices. The display is also set up using the `Arduino_H7_Video` class.
4247

43-
```cpp
48+
```arduino
4449
USBHostMSD msd;
4550
mbed::FATFileSystem usb("usb");
4651
Arduino_H7_Video Display(800, 480, GigaDisplayShield);
4752
```
4853

4954
### Listing Files on USB Storage
5055

51-
Once mounted, the USB drive is scanned for available files:
56+
Once mounted, the USB drive is scanned for available files. Again, make sure the USB is in FAT32 format:
5257

53-
```cpp
58+
```arduino
5459
void listRootDirectory() {
5560
fileCount = 0;
5661
DIR* dir = opendir("/usb/");
@@ -69,7 +74,7 @@ void listRootDirectory() {
6974

7075
Users can enter a file number in the Serial Monitor to select an image for display.
7176

72-
```cpp
77+
```arduino
7378
void handleUserInput() {
7479
if (Serial.available() > 0) {
7580
int sel = Serial.parseInt();
@@ -84,12 +89,11 @@ void handleUserInput() {
8489

8590
### Reading and Displaying RAW Images
8691

87-
The file is read row-by-row (800 pixels per row, 2 bytes per pixel). If the entire image (800x480 pixels) were loaded into memory at once, it would require approximately 768 KB of RAM (800 \* 480 \* 2 bytes). However, by processing only one row at a time (800 * 2 bytes), the memory usage is reduced to just `1.6 KB`, making this approach much more efficient and feasible for devices with restricted memory (like GIGA). This approach minimizes memory usage by processing smaller chunks of the image at one time, avoiding large allocations that may exceed available RAM (512 KB for the GIGA).
88-
To manage this efficiently, we use `malloc()` and `free()` for dynamic memory allocation, ensuring that only the necessary amount of RAM is used rather than pre-allocating a large buffer. This approach helps optimize memory use while preventing fragmentation.
89-
Similarly, `fopen()` and `fclose()` are used for file management. `fopen()` allows us to open the image file and read data as needed, rather than loading everything at once. `fclose()` ensures that the file is properly closed after reading, freeing up system resources and preventing potential memory leaks.
92+
The file is read row-by-row (800 pixels per row, 2 bytes per pixel). If the entire image (800x480 pixels) were loaded into memory at once, it would require approximately 768 KB of RAM (800 \* 480 \* 2 bytes). However, by processing only one row at a time (800 * 2 bytes), the memory usage is reduced to just `1.6 KB`, making this approach much more efficient and feasible for devices with restricted memory (like the GIGA). This approach minimizes memory usage by processing smaller chunks of the image at one time, avoiding large allocations that may exceed available RAM (512 KB for the GIGA).
93+
We use, `fopen()` and `fclose()` are used for file management. `fopen()` allows us to open the image file and read data as needed, rather than loading everything at once. `fclose()` ensures that the file is properly closed after reading, freeing up system resources and preventing potential memory leaks.
9094

9195

92-
```cpp
96+
```arduino
9397
bool displayRawRowByRow(const char* path) {
9498
FILE* f = fopen(path, "rb");
9599
if (!f) return false;
@@ -116,9 +120,10 @@ bool displayRawRowByRow(const char* path) {
116120

117121
### Clearing the Display
118122

119-
Reset the display by entering `clear` in to the Serial Monitor.
123+
Users can reset the display by entering `clear` in the Serial Monitor.
124+
This simply fills all pixels with black.
120125

121-
```cpp
126+
```arduino
122127
void forceScreenClear() {
123128
Display.beginDraw();
124129
Display.fill(0x0000); // Fill with black
@@ -128,10 +133,145 @@ void forceScreenClear() {
128133

129134
### Full code
130135

131-
^C
136+
```arduino
137+
#include <Arduino_USBHostMbed5.h>
138+
#include <DigitalOut.h>
139+
#include <FATFileSystem.h>
140+
#include <Arduino_H7_Video.h>
141+
#include <ArduinoGraphics.h>
142+
143+
USBHostMSD msd;
144+
mbed::FATFileSystem usb("usb");
145+
146+
const int USB_HOST_ENABLE_PIN = PA_15;
147+
const int MAX_FILES = 50;
148+
const int MAX_NAME_LEN = 128;
149+
char fileNames[MAX_FILES][MAX_NAME_LEN];
150+
int fileCount = 0;
151+
const int MAX_CONNECTION_ATTEMPTS = 10;
152+
153+
Arduino_H7_Video Display(800, 480, GigaDisplayShield);
154+
const int IMG_WIDTH = 800;
155+
const int IMG_HEIGHT = 480;
156+
const uint32_t EXPECTED_FILE_SIZE = IMG_WIDTH * IMG_HEIGHT * 2;
157+
158+
uint8_t rowBuffer[IMG_WIDTH * 2]; // Static buffer
159+
160+
void setup() {
161+
Serial.begin(115200);
162+
pinMode(USB_HOST_ENABLE_PIN, OUTPUT);
163+
digitalWrite(USB_HOST_ENABLE_PIN, HIGH);
164+
while (!Serial) {}
165+
delay(1500);
166+
167+
Serial.println("=== USB File List ===");
168+
Display.begin();
169+
forceScreenClear();
170+
171+
if (!initUSBHost() || !mountUSB()) return;
172+
listRootDirectory();
173+
if (fileCount == 0) return;
174+
175+
printFileList();
176+
Serial.println("Select a file # to open as 800x480 .bin, or type 'clear' to reset the screen:");
177+
}
178+
179+
void loop() {
180+
if (fileCount > 0) handleUserInput();
181+
}
182+
183+
bool initUSBHost() {
184+
for (int i = 0; i < MAX_CONNECTION_ATTEMPTS; i++) {
185+
if (msd.connect()) {
186+
Serial.println("USB mass storage device connected!");
187+
return true;
188+
}
189+
Serial.println("USB device not detected, retrying...");
190+
delay(1000);
191+
}
192+
return false;
193+
}
194+
195+
bool mountUSB() {
196+
Serial.print("Mounting USB device... ");
197+
if (usb.mount(&msd)) {
198+
Serial.println("Failed to mount USB.");
199+
return false;
200+
}
201+
Serial.println("done.");
202+
return true;
203+
}
204+
205+
void listRootDirectory() {
206+
fileCount = 0;
207+
DIR* dir = opendir("/usb/");
208+
if (!dir) return;
209+
while (fileCount < MAX_FILES) {
210+
struct dirent* entry = readdir(dir);
211+
if (!entry) break;
212+
strncpy(fileNames[fileCount], entry->d_name, MAX_NAME_LEN - 1);
213+
fileNames[fileCount][MAX_NAME_LEN - 1] = '\0';
214+
fileCount++;
215+
}
216+
closedir(dir);
217+
}
218+
219+
void printFileList() {
220+
Serial.print("Found "); Serial.print(fileCount); Serial.println(" file(s) in /usb/:");
221+
for (int i = 0; i < fileCount; i++) {
222+
Serial.print(i + 1); Serial.print(") "); Serial.println(fileNames[i]);
223+
}
224+
}
225+
226+
void handleUserInput() {
227+
if (Serial.available() > 0) {
228+
String input = Serial.readStringUntil('\n');
229+
input.trim();
230+
231+
if (input.equalsIgnoreCase("clear")) {
232+
forceScreenClear();
233+
return;
234+
}
235+
236+
int sel = input.toInt();
237+
if (sel < 1 || sel > fileCount) return;
238+
239+
Serial.print("Displaying: /usb/");
240+
Serial.println(fileNames[sel - 1]);
241+
242+
displayRawRowByRow(fileNames[sel - 1]);
243+
}
244+
}
245+
246+
bool displayRawRowByRow(const char* fileName) {
247+
String path = "/usb/" + String(fileName);
248+
FILE* f = fopen(path.c_str(), "rb");
249+
if (!f) return false;
250+
251+
forceScreenClear();
252+
Display.beginDraw();
253+
254+
for (int y = 0; y < IMG_HEIGHT; y++) {
255+
if (fread(rowBuffer, 1, IMG_WIDTH * 2, f) != IMG_WIDTH * 2) break;
256+
Image rowImage(ENCODING_RGB16, rowBuffer, IMG_WIDTH, 1);
257+
Display.image(rowImage, 0, y);
258+
}
259+
260+
Display.endDraw();
261+
fclose(f);
262+
Serial.println("Image displayed successfully!");
263+
return true;
264+
}
265+
266+
void forceScreenClear() {
267+
Display.beginDraw();
268+
Display.fill(0x0000);
269+
Display.endDraw();
270+
}
271+
```
132272

133273
### Conclusion
134274

135-
This project demonstrates how to read and display **16-bit RGB565 images** from a USB drive onto the Arduino GIGA Display Shield. The row-by-row approach optimizes memory usage while ensuring smooth rendering. This technique is useful for **digital signage, interactive kiosks, and embedded GUI projects**.
275+
This project demonstrates how to read and display **16-bit RGB565 images** from a USB drive onto the Arduino GIGA Display. The row-by-row approach optimizes memory usage while ensuring smooth rendering.
136276

137277

0 commit comments

Comments
 (0)