LVGL is not loading image file with FatFS - no data

LVGL is not loading image file with FatFS - no data

What MCU/Processor/Board and compiler are you using?

STM32F767ZI

What LVGL version are you using?

V8.3.2

What do you want to achieve?

I want to load images preloaded on to SPI flash using FatFS (ready to use driver)

What have you tried so far?

I’ve confirmed the files are there and I am able to see them: I can see LVGL is able to see the image file.
If I purposely direct to the wrong file / missing then no image box is drawn.

I’ve also tried loading the image direct using PNG decoder but to no avail

Code to reproduce

lv_config.h

/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
#define LV_USE_FS_FATFS 1
#if LV_USE_FS_FATFS
    #define LV_FS_FATFS_LETTER 'A'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
    #define LV_FS_FATFS_CACHE_SIZE 0    /*>0 to cache this number of bytes in lv_fs_read()*/
#endif

setup()

  if (!flash.begin())
  { // start the flash
    debugSerial.println(F("Error, failed to initialise flash chip!"));
    while (1)
      yield();
  }
  else
    debugSerial.println(F("flash chip initialised"));
  delay(100);

  FATFS fatfs;
  FIL fil; // File handle

  FRESULT r = f_mount(&fatfs, "0:", 1); // 0: mounts to the Flash
  if (r != FR_OK)
  {
    debugSerial.print(F("Error, f_mount failed with error code: "));
    debugSerial.println(r, DEC);
    while (1)
      yield();
  }
  else
    debugSerial.println(F("f_mount successful"));

 // Check the image file is there
  r = f_open(&fil, "favicon.bin", FA_READ);
  if (r != FR_OK) {
	debugSerial.printf("f_open error (%i)\r\n");
  } else
  debugSerial.printf("I was able to open 'favicon.bin' for reading!\r\n");
  f_close(&fil);

  /** Initialise LVGL FatFs Handler **/  
  lv_fs_fatfs_init();

Image load

void lv_example_bin_3(void)
{
    lv_obj_t * img;
    img = lv_img_create(lv_scr_act());
    lv_img_set_src(img, "A:favicon.bin");
    lv_obj_align(img, LV_ALIGN_RIGHT_MID, -20, 0);
}

Serial output - Logging ‘warn’ enabled

flash chip initialised
f_mount successful
I was able to open 'favicon.bin' for reading!

[Warn]  (0.276, +276)    _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.286, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.295, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.305, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.314, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.324, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.333, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.343, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.352, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.362, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.371, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.381, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.390, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.400, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.409, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.419, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.428, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.438, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.447, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.457, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.466, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.476, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.485, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.495, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.504, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.514, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.523, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.533, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.542, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.552, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)
[Warn]  (0.561, +9)      _lv_img_cache_open: Image draw cannot open the image resource  (in lv_img_cache.c line #125)
[Warn]  (0.571, +10)     lv_draw_img: Image draw error  (in lv_draw_img.c line #81)

Screenshot and/or video

converted image favicon.bin

The images on the SPI Flash all seemed to be copied over fine and its not corrupted but I’m unable to load the images using the standard image souce via the built in routine as stated in the documentation.
If I was to set an image sourced from a file, such as:
lv_img_set_src(img, "A:image.bin");
The image box is the correct width & height but has No data

Now if I manually preload the image source from a file using the below function:

lv_img_dsc_t* lv_img_dsc_load_src(const char* src)
{
    lv_fs_res_t res = LV_FS_RES_OK;

    lv_fs_file_t f;
    uint32_t fSize = 0;
    res = lv_fs_open(&f, src, LV_FS_MODE_RD);
    if (res != LV_FS_RES_OK)
    {
        LV_LOG_ERROR("[Preload] (%s) FS open failed.", src);
        return NULL;
    }
    res = lv_fs_seek(&f, 0, LV_FS_SEEK_END);
    if (res != LV_FS_RES_OK)
    {
        LV_LOG_ERROR("[Preload] (%s) Seek end failed.", src);
        lv_fs_close(&f);
        return NULL;
    }
    res = lv_fs_tell(&f, &fSize);
    if (res != LV_FS_RES_OK)
    {
        LV_LOG_ERROR("[Preload] (%s) Get size failed.", src);
        lv_fs_close(&f);
        return NULL;
    }
    res = lv_fs_seek(&f, 0, LV_FS_SEEK_SET);
    if (res != LV_FS_RES_OK)
    {
        LV_LOG_ERROR("[Preload] (%s) Seek start failed.", src);
        lv_fs_close(&f);
        return NULL;
    }
    uint32_t rd = 0;
    uint8_t* buf = (uint8_t*)lv_mem_alloc(fSize);
    res = lv_fs_read(&f, buf, fSize, &rd);
    if (res != LV_FS_RES_OK || rd != fSize)
    {
        LV_LOG_ERROR("[Preload] (%s) Read failed.", src);
        lv_fs_close(&f);
        return NULL;
    }

    lv_img_dsc_t* img_dsc = (lv_img_dsc_t*)buf;
    img_dsc->data_size = lv_img_buf_get_img_size(img_dsc->header.w, img_dsc->header.h, img_dsc->header.cf);
    img_dsc->data = (uint8_t*)buf + sizeof(lv_img_header_t);

    lv_fs_close(&f);

    return img_dsc;
}

and set the source of the image using:
lv_img_set_src(img, lv_img_dsc_load_src("A:image.bin"));

The image loads but depending on the size if it is too large >(~100px x ~100px) then the image will not load at all.

What am I doing wrong and why cant I call lv_img_set_src(img, "A:image.bin"); directly instead of preloading it?

Try

lv_img_set_src(img, "A:/image.bin");

@sukeshak thanks for the reply, I’ve tested lv_img_set_src(img, "A:/image.bin"); but unfortunately to no avail.

I really don’t understand why it partly works when I preload the image: it proves that the file systems is working with LVGL as the file system callbacks are used in the ‘preload’ function.

That’s how it works for me. It’s an ESP32 project though.

You are using directly here r = f_open(&fil, "favicon.bin", FA_READ); and not through the lvgl fs layer.
This means, your flash drive is working but not through lvgl fs layer.

You also have a mount point defined with 0:

FRESULT r = f_mount(&fatfs, "0:", 1); // 0: mounts to the Flash

so try something like A:/0:/favicon.bin and see if it works.

You can use lv_fs_is_ready API to check if drive (lvgl fs) is ready or not.

@sukeshak thanks for the reply and assistance.

r = f_open(&fil, "favicon.bin", FA_READ); is only used in the initial setup() just as a test for me to prove that FatFS is working correctly and mounted to my flash correctly: this is done all prior to initialising the LVGL fs layer so not quite related - I can remove it with no effect.

I have to mount my drive with FRESULT r = f_mount(&fatfs, "0:", 1); as the initialisation with my SPI flash, thereafter FatFS takes over from there and this is proven with the above f_read and also with LVGL fs layer.

I’ve proved the LVGL fs layer is working with preloading the image using the function I mentioned in my previous post lv_img_dsc_t* lv_img_dsc_load_src(const char* src) with the following:

res = lv_fs_open(&f, src, LV_FS_MODE_RD);
res = lv_fs_seek(&f, 0, LV_FS_SEEK_END);
res = lv_fs_tell(&f, &fSize);
res = lv_fs_read(&f, buf, fSize, &rd);

I will check out your ESP32 project as it may point to where I’m going wrong and I do really appreciate your help with this, thanks again.

Just to make sure you understand, I haven’t added fatfs yet.
Was only talking about the Drive letter format.

I am using SPIFF & SD Card for now. Was waiting for IDF 5.0 release to change it.
Working on it now. Will update here once I move SPIFF to FAT for my project.

Oh I see.

With regards to the drive lettering used on FatFs when I mount to 0:, that’s with regards to the SPI (or some other interface) setup in the initialisation.
If I had multiple flash on my MCU, I could have the ability to unmount and re-mount to say 1:, 2:, 3:, ...: I don’t believe you can mount to more than one drive at the same time.
My understanding of the LVGL fs layer, the drive lettering used on that is separate and purely for LVGL (different to how FatFs mounts to 0:, 1:, 2:, ...) and it is used to select between the built-in fs or custom fs callback used ie A: could be assigned to FatFs, B: could be assigned to STDIO, C: could be assigned to POSIX and D: could be assigned to a custom fs callback and so on:
lv_img_set_src(img, "A:/image.bin"); FatFs
lv_img_set_src(img, "B:/image.bin"); STDIO
lv_img_set_src(img, "C:/image.bin"); POSIX
lv_img_set_src(img, "D:/image.bin"); Custom
...

I could be wrong, I’m just going from studying their documentation and looking at the code of LVGL and how it utilises their file systems.