Can't load images from pendrive

What do you want to achieve?

Good evening. I would like to load images from my pendrive and display them on my arduino’s display. I only want to use tiny images, for example: 100x100. Unfortunately, the images wont get displayed. When it comes to arduino and c++ I’m a beginner.

What have you tried so far?

I’ve done the following edits in my lv_conf.h:

#define LV_USE_FS_POSIX 1
#define LV_FS_POSIX_LETTER ‘P’
#define LV_USE_LODEPNG 1
#define LV_CACHE_DEF_SIZE (256 * 1024U)

Later on I tried to use Claude to help me fix this problem. It didn’t really help.
While chatting with Claude I also checked the documentation.
Then I tried to find a solution on the web, but nothing.

I also didn’t receive any error and Claude recommended me to try to open my image with fopen, which was successful.

Code to reproduce

main.cpp

#include "../lib/BGL/src/BGL.h"

#include "../lib/CBOS/src/CBOS.h"



BGLImage* image = nullptr;



void setup() {

  Serial.begin(9600);

  Serial.println("Ready!");

  CStorage::InitUsbPort();

  BGLInit();


  image = new BGLImage("P:usb/mate.png");

}

void loop() {

  BGLUpdate();

  delay(80);

}

CStorage.cpp

#include "CStorage.h"



USBHostMSD msd;

mbed::FATFileSystem usb("usb");


void CStorage::InitUsbPort() {

    pinMode(PA_15, OUTPUT);

    digitalWrite(PA_15, HIGH);


    while (!msd.connect()) delay(500);

    int result = usb.mount(&msd);


    Serial.println(result == 0 ? "Successfully mounted USB!" : "Failed to mount USB!");

}

BGL.cpp

#include "BGL.h"

#include <Arduino_H7_Video.h>

#include <Arduino_GigaDisplayTouch.h>

#include <lvgl.h>



Arduino_H7_Video* Display = nullptr;   

Arduino_GigaDisplayTouch TouchDetector;



void BGLInit(uint16_t screenSizeX, uint16_t screenSizeY) {

    Display = new Arduino_H7_Video(screenSizeX, screenSizeY, GigaDisplayShield);

    Display->begin();

    TouchDetector.begin();



    lv_init();

    lv_lodepng_init();

}



void BGLUpdate() {

    lv_timer_handler();

}

}

I made BGLImage in order to customize how I and my code use image widgets and Im 100% sure that it works correctly.
The other files just help me to organize my code.

Environment

  • MCU/MPU/Board: Arduino Giga R1 Wifi
  • LVGL version: 9.5.0

Also I use VSC with PlatformIO for coding and Arduino IDE for installing libraries and I use Win11.

Hi @DanA ,

Thanks for starting this topic.

First of all, the lv_init() function has already called lv_loadepng_init, so I recommend removing it.

Secondly, after locating the file (P:your_image.), you need to create an image object, like this:

 lv_obj_t * screen = lv_screen_active();
 lv_obj_clean(screen);

 lv_obj_t * img = lv_image_create(screen);
 lv_image_set_src(img, "P:usb/mate.png");

Let me know if you have more questions.

Hello @halyssonJr, thank you for replying!

I removed the lv_loadepng_initfunction from my code. Honestly, I just wanted the image loading to work so I tried random ideas.

Also It seems like I forgot to post BGLImage.cpp, here is it:

#include "BGLImage.h"



BGLImage::BGLImage(const char filePath[]) {

    selfPointer = lv_image_create(lv_screen_active());



    if (filePath) lv_image_set_src(selfPointer, filePath);

}



BGLImage::BGLImage(BGLObjectInterface* parent) {

    selfPointer = lv_image_create(parent->GetPointer());

    Parent = parent;

}




BGLImage::BGLImage(BGLObjectInterface* parent, const char filePath[]) {

    selfPointer = lv_image_create(parent->GetPointer());

    Parent = parent;



    if (filePath) lv_image_set_src(selfPointer, filePath);

}

Hi @DanA,

I found a guide on the Arduino website that might help you.

Try creating an object the same size as the screen, there is no need to call lv_init(), as that function is likely already called internally.

  Display.begin();
  TouchDetector.begin();
  lv_obj_t* screen = lv_obj_create(lv_scr_act());
  lv_obj_set_size(screen, Display.width(), Display.height());

  lv_obj_t * img = lv_image_create(screen);
  lv_image_set_src(img, "P:usb/mate.png");

Maybe, before to create an image, check if the file exist.

Hello @halyssonJr

Thanks for the link! I checked it out, unfortunately it only mentioned how to display an image from a C binary. I also copied a piece of your code which you provided.

I checked my pendrive and the image is located at the root folder and the size of it’s is 139x138.

Here’s my code and the output:

#include "../lib/BGL/src/BGL.h"

#include "../lib/CBOS/src/CBOS.h"


lv_obj_t* screen = nullptr;

lv_obj_t * img = nullptr;



void doesFileExist(const char path[]) {

  FILE* f = fopen(path, "rb");



  Serial.print(path);

  Serial.print( f ? " -> exists" : " -> does not exists");



  fclose(f);

}




void setup() {

  Serial.begin(9600);

  delay(2000);

  Serial.println("Ready!");

  CStorage::InitUsbPort();

  BGLInit();

  //------------------------------//



  screen = lv_obj_create(lv_scr_act());

  lv_obj_set_size(screen, 480, 800);

  lv_obj_set_style_bg_color(screen, lv_color_hex(0x112233), LV_PART_MAIN);



  img = lv_image_create(screen);

  lv_image_set_src(img, "P:/usb/mate.png");

  lv_obj_set_size(img, 100, 100);

  lv_obj_set_style_border_width(img, 5, LV_PART_MAIN);

  lv_obj_set_style_border_color(img, lv_color_hex(0xff0000), LV_PART_MAIN);



  doesFileExist("/usb/mate.png");

}



void loop() {

  BGLUpdate();

  delay(80);

}

The output:

---- Opened the serial port COM3 ----
Successfully mounted USB!
/usb/mate.png -> exists
---- Closed the serial port COM3 ----

Now I can see where the image should be on the screen because of the red border. However, it is empty. I genuinely dont know what could be the problem.

You are using the incorrect file path. The LVGL filesystem path format uses the drive letter without a leading slash after the colon.

Thanks for the reply!

I removed the slash, but nothing.
I got suspicious about mate.png so I tried the display a different image which is only 20x20, but nothing changed.

Try another file type, BIN converted to screen format is the better to test, PNG is complex to load so first test if lvlg can load any files then try to load a PNG

Hi @AndreoBotelho, thanks for the reply!

As it turns out PlatformIO had created a different LVGL config file which I didn’t know of. After I enabled the logging module I saw that LVGL couldn’t find my image because the drive letter was unrecognized. I tried to enable POSIX, STDIO and FATFS (one at a time of course), but I always got an error. I will try to find a way to fix it tho I might need to write a custom driver. If you would know an easy fix for this, please tell me.

Here’s the error I get:

In file included from c:\users\scynthi.platformio\packages\toolchain-gccarmnoneeabi\arm-none-eabi\include\dirent.h:7:0,
from C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:16:
c:\users\scynthi.platformio\packages\toolchain-gccarmnoneeabi\arm-none-eabi\include\sys\dirent.h:10:2: error: #error "<dirent.h> not supported"
#error "<dirent.h> not supported"
^~~~~
Compiling .pio\build\giga_r1_m7\lib1bf\lvgl\libs\svg\lv_svg_token.c.o
Compiling .pio\build\giga_r1_m7\lib1bf\lvgl\libs\thorvg\tvgAccessor.cpp.o
Compiling .pio\build\giga_r1_m7\lib1bf\lvgl\libs\thorvg\tvgAnimation.cpp.o
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c: In function 'fs_dir_open':
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:271:18: warning: implicit declaration of function 'opendir'; did you mean 'openat'? [-Wimplicit-function-declaration]
void * dir = opendir(buf);
^~~~~~~
openat
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:271:18: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c: In function 'fs_dir_read':
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:296:17: warning: implicit declaration of function 'readdir'; did you mean 'readlink'? [-Wimplicit-function-declaration]
entry = readdir(dir_p);
^~~~~~~
readlink
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:296:15: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
entry = readdir(dir_p);
^
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:298:21: error: dereferencing pointer to incomplete type 'struct dirent'
if(entry->d_type == DT_DIR) lv_snprintf(fn, fn_len, "/%s", entry->d_name);
^~
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:298:33: error: 'DT_DIR' undeclared (first use in this function); did you mean 'EISDIR'?
if(entry->d_type == DT_DIR) lv_snprintf(fn, fn_len, "/%s", entry->d_name);
^~~~~~
EISDIR
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:298:33: note: each undeclared identifier is reported only once for each function it appears in
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c: In function 'fs_dir_close':
C:\Users\scynthi\Documents\Arduino\libraries\lvgl\src\libs\fsdrv\lv_fs_posix.c:319:15: warning: implicit declaration of function 'closedir'; did you mean 'close'? [-Wimplicit-function-declaration]
int ret = closedir(dir_p);
^~~~~~~~
close
*** [.pio\build\giga_r1_m7\lib1bf\lvgl\libs\fsdrv\lv_fs_posix.c.o] Error 1

Hi @DanA ,

Given that you are using Win32/64, the OS does not support the full POSIX API.

Hi @halyssonJr ,

Thanks for the link! I checked it out and I chose to make a custom driver. After it I had problems with lodepng, because it couldn’t allocate enough memory.

At the end I converted the image to a bin file and now it works!

Thank you so much for the help!