Image from file, after use it not close file and it not open file before read

Description

I use lv_maixduino and i ensure update lvgl to latest version. (I clone lvgl master branch to src directory. i think this correct way for update lvgl to latest version.)

from old post ( FileSystem Open and then Read 4 bytes and then Close and then Open and then Read 4 bytes and then Close … ) i success for show picture in screen but when i use lv_img_set_src(); to change picture, picture not show on screen but in screen show No data

so i debug by enable show log info level and i see this in Serial Monitor:

Initializing SD card...Wiring is correct and a card is present.
INFO: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#108: image created
Open EN.3-4/img/8.bin OK !
File read
File close
INFO: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_cache.c#109: image draw: cache miss, cached to an empty entry
Open EN.3-4/img/8.bin OK !
File read
File close
Open EN.3-4/img/8.bin OK !
File seek
File read
File seek
File read
...
File seek
File read
File seek
File read
Set image to S:/EN.3-4/img/2.bin
Open EN.3-4/img/2.bin OK !
File read
File close
File seek
File read
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_decoder.c#521: Built-in image decoder read failed
File close
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#522: Image draw can't read the line
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#61: Image draw error
Set image to S:/EN.3-4/img/3.bin
Open EN.3-4/img/3.bin OK !
File read
File close
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_decoder.c#514: Built-in image decoder seek failed
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#522: Image draw can't read the line
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#61: Image draw error
Set image to S:/EN.3-4/img/4.bin
Open EN.3-4/img/4.bin OK !
File read
File close
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_decoder.c#514: Built-in image decoder seek failed
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#522: Image draw can't read the line
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#61: Image draw error
Set image to S:/EN.3-4/img/5.bin
Open EN.3-4/img/5.bin OK !
File read
File close
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_decoder.c#514: Built-in image decoder seek failed
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#522: Image draw can't read the line
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#61: Image draw error

OK, my log very long. i recomment you see this:

Open EN.3-4/img/8.bin OK !
File read
File close
...
File seek
File read
File seek
File read
Set image to S:/EN.3-4/img/2.bin
Open EN.3-4/img/2.bin OK !
File read
File close
File seek
File read
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_img_decoder.c#521: Built-in image decoder read failed
File close
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#522: Image draw can't read the line
WARNING: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_draw\lv_draw_img.c#61: Image draw error

you can see it open new file (EN.3-4/img/2.bin) before close file EN.3-4/img/8.bin.

Next, after file EN.3-4/img/2.bin opened it read header and then close file. and then it call seek and read … ? bacause file is close so in read_cb send back 0 byte for read.

To fixed it i remove file close function in close_cb and i add close file when before open new file.

static lv_fs_res_t lv_sd_open(lv_fs_drv_t * drv, void * file_p, const char * fn, lv_fs_mode_t mode)
{
  (void) drv; /*Unused*/

  if (f) {
    f.close();
  }
  
  if (!SD.exists(fn)) {
    Serial.print("File ");
    Serial.print(fn);
    Serial.println(" doesn't exist.");

    return LV_FS_RES_UNKNOWN;
  }

  f = SD.open(fn, mode == LV_FS_MODE_WR ? FILE_WRITE : FILE_READ);
  if (!f) {
    Serial.println("Open " + String(fn) + " fail");
    return LV_FS_RES_UNKNOWN;
  } else {
    Serial.println("Open " + String(fn) + " OK !");
    f.seek(0);

    /* 'file_p' is pointer to a file descriptor and
       we need to store our file descriptor here*/
    File *fp = (File*)file_p;        /*Just avoid the confusing casings*/
    *fp = f;
  }

  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_close(lv_fs_drv_t * drv, void * file_p)
{
  (void) drv; /*Unused*/

  Serial.println("File close");
  
  //File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  // f.close();
  return LV_FS_RES_OK;
}

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

K210, ArduinoIDE, My hardware design by self.

What do you experience?

It doesn’t work.

What do you expect?

Code to reproduce

#include <IOXGD.h>

#include <SPI.h>
#include <SD.h>

File f;

static lv_fs_res_t lv_sd_open(lv_fs_drv_t * drv, void * file_p, const char * fn, lv_fs_mode_t mode)
{
  (void) drv; /*Unused*/

  if (!SD.exists(fn)) {
    Serial.print("File ");
    Serial.print(fn);
    Serial.println(" doesn't exist.");

    return LV_FS_RES_UNKNOWN;
  }

  f = SD.open(fn, mode == LV_FS_MODE_WR ? FILE_WRITE : FILE_READ);
  if (!f) {
    Serial.println("Open " + String(fn) + " fail");
    return LV_FS_RES_UNKNOWN;
  } else {
    Serial.println("Open " + String(fn) + " OK !");
    f.seek(0);

    /* 'file_p' is pointer to a file descriptor and
       we need to store our file descriptor here*/
    File *fp = (File*)file_p;        /*Just avoid the confusing casings*/
    *fp = f;
  }

  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_close(lv_fs_drv_t * drv, void * file_p)
{
  (void) drv; /*Unused*/

  Serial.println("File close");
  
  //File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  f.close();
  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
  (void) drv; /*Unused*/

  Serial.println("File read");
  
  // File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  // Serial.println("Read " + String(btr) + " bytes");
  *br = f.read((uint8_t*)buf, btr);
  // Serial.println("Return " + String(*br) + " bytes");

  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos)
{
  (void) drv; /*Unused*/

  Serial.println("File seek");
  
  // File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  f.seek(pos);
  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
  (void) drv; /*Unused*/

  Serial.println("File tell");
  // File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  *pos_p = f.position();
  return LV_FS_RES_OK;
}

static lv_fs_res_t lv_sd_size(lv_fs_drv_t *drv, void *file_p, uint32_t *size_p) {
  (void) drv; /*Unused*/

  Serial.println("File size");
  // File* fp = (File*)file_p;        /*Just avoid the confusing casings*/
  *size_p = f.size();
  return LV_FS_RES_OK;
}

void my_log_cb(signed char level, const char * file, unsigned int line, const char * dsc)
{
  if(level == LV_LOG_LEVEL_ERROR) Serial.print("ERROR: ");
  if(level == LV_LOG_LEVEL_WARN)  Serial.print("WARNING: ");
  if(level == LV_LOG_LEVEL_INFO)  Serial.print("INFO: ");
  if(level == LV_LOG_LEVEL_TRACE) Serial.print("TRACE: ");
  
  Serial.print("File: ");
  Serial.print(file);
  
  char line_str[8];
  sprintf(line_str,"%d", line);
  Serial.print("#");
  Serial.print(line_str);
  
  Serial.print(": ");
  Serial.print(dsc);
  Serial.print("\n");
}

static uint32_t start = 0;

lv_obj_t * img_bin;
void setup() {
  Serial.begin(115200);

  gd.begin();
  
  lv_log_register_print_cb(my_log_cb);

  Serial.print("\nInitializing SD card...");
  if (!SD.begin(29)) {
    Serial.println("initialization failed.");
    while (1);
  } else {
    Serial.println("Wiring is correct and a card is present.");
  }

  lv_fs_drv_t drv;
  memset(&drv, 0, sizeof(lv_fs_drv_t));    /*Initialization*/

  drv.letter = 'S';                         /*An uppercase letter to identify the drive */
  drv.file_size = sizeof(File);   /*Size required to store a file object*/
  drv.open_cb = lv_sd_open;                 /*Callback to open a file */
  drv.close_cb = lv_sd_close;               /*Callback to close a file */
  drv.read_cb = lv_sd_read;                 /*Callback to read a file */
  drv.seek_cb = lv_sd_seek;                 /*Callback to seek in a file (Move cursor) */
  drv.tell_cb = lv_sd_tell;                 /*Callback to tell the cursor position  */
  drv.size_cb = lv_sd_size;                 /*Callback to tell a file's size */

  lv_fs_drv_register(&drv);                 /*Finally register the drive*/

  img_bin = lv_img_create(lv_scr_act(), NULL);
  lv_img_set_src(img_bin, "S:/EN.3-4/img/8.bin");
  lv_obj_align(img_bin, NULL, LV_ALIGN_CENTER, 0, 0);

  start = millis();
}

char buff[32];

void loop() {
  lv_task_handler();
  delay(5);

  
  if ((millis() - start) > 1000) {
   start = millis();

   // Serial.println("In loop");

   static int i = 2;
   sprintf(buff, "S:/EN.3-4/img/%d.bin", i);
   Serial.print("Set image to ");
   Serial.println(buff);
   lv_img_set_src(img_bin, buff);
   i++;
   if (i > 50) i = 2;
  }
}

Screenshot and/or video

You use a global file. This way you won’t be able to deal with multiple files. You should either use file_p paramter (see this as reference) or set LV_IMG_CACHE_DEF_SIZE 1 in lv_conf.h

Are you have example for pass Object to file_p paramiter ? i see fopen() return pointer not object but SD.open() return object.

I haven’t use the SD library so I don’t know much about it.
Probably better to go with LV_IMG_CACHE_DEF_SIZE 1

LV_IMG_CACHE_DEF_SIZE set to 1 already before i create this post :slight_smile:

Then try lv_img_cache_invalidate_src(NULL); before lv_img_set_src()

It work ! Thank you so much. and thanks for fast answer and do hard.

Great! :slight_smile:

But note that it’s just workaround. It’d be better to write a driver which can handle multiple files.