FileSystem Open and then Read 4 bytes and then Close and then Open and then Read 4 bytes and then Close ...

Describe the bug

Sorry for title is long too.

I use LittlevGL as Arduino and use FileSystem with SD Card. i think i found bug after upload sketch, LittlevGL call drv.open_cb and then drv.read_cb and then drv.close_cb and then drv.open_cb and then drv.read_cb and then drv.close_cb (plz see Screenshots)

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 (f) {
    return LV_FS_RES_OK;
  }

  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(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 setup() {
  Serial.begin(115200);

  gd.begin();

  Serial.print("\nInitializing SD card...");

  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!SD.begin(29)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    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*/

  lv_obj_t * 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);
}

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

note: gd.begin(); setup touch screen input and LCD and call lv_init();

Expected behavior

Now, picture not show on screen and after you help me. my screen will show correct picture.

Screenshots

Additional context

Thanks so much !

So the problem is you think LittlevGL open-read-close too often?
If yes is it happen infinitely?
A few calls are normal because LittlevGL reads the header of the image (width, height etc)

not infinity. after open-read-close often. it stop.

I think i convert image incorrect of type ?

lv_conf.h content:

/* Color depth:
 * - 1:  1 byte per pixel
 * - 8:  RGB233
 * - 16: RGB565
 * - 32: ARGB8888
 */
#define LV_COLOR_DEPTH     16

/* Swap the 2 bytes of RGB565 color.
 * Useful if the display has a 8 bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP   0

and this i config in Online Image to C Array Converter page

Are you want know other for fix it ? Thanks !

and this sample file content

Note: new member can put one image for same post =_=

“it stops” means MCU hangs or crashes, or the image is displayed correctly and no more open/read/close occurs?

“it stops” is other function in loop can do.

In loop function i change to:

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

  static uint16_t start = 0;
  if ((millis() - start) > 1000) {
   start = millis();

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

and result is

Video: https://photos.app.goo.gl/TBCQY2CvDkRjw3j89

  • What is the size of you display buffer in lv_disp_buf_init()?
  • What is the value of LV_IMG_CACHE_DEF_SIZE in lv_conf.h?

lv_conf.h(1)

/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX          (800)
#define LV_VER_RES_MAX          (480)

lv_conf.h(2)

/* Default image cache size. Image caching keeps the images opened.
 * If only the built-in image formats are used there is no real advantage of caching.
 * (I.e. no new image decoder is added)
 * With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
 * However the opened images might consume additional RAM.
 * LV_IMG_CACHE_DEF_SIZE must be >= 1 */
#define LV_IMG_CACHE_DEF_SIZE       1

gd.begin():

static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

void IOXGD::begin() {
    lcd.init();
    touch.init();
    EEPROM.begin();

    lv_init();

    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;
    disp_drv.flush_cb = disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /*Initialize the Input*/
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_pointer;
    lv_indev_drv_register(&indev_drv);

    /*Initialize the graphics library's tick*/
    tickLV.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);
}

Are you think memory of cache not enough ?

I’ve tested, and for me the image is opened only 3 times. (Two times to get some info, and once to read the image itself)

Please enable logging in lv_conf.h and add a print function. Hopefully we will see what is the problem.
See how logging works here: https://docs.littlevgl.com/en/html/porting/log.html?highlight=log

I see this:

Initializing SD card...Wiring is correct and a card is present.
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#58: image create started
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_core\lv_obj.c#215: Object create started
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
Read 4 bytes
Return 4 bytes
File close
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_misc\lv_task.c#67: lv_task_handler started
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_core\lv_indev.c#75: indev read task started
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_hal\lv_hal_indev.c#145: idnev read started
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_hal\lv_hal_indev.c#147: idnev read finished
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_core\lv_indev.c#123: indev read task finished
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_core\lv_refr.c#163: lv_refr_task: started
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#345: lv_img_design: start to draw image
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
Read 4 bytes
Return 4 bytes
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_cache.c#118: Image draw cannot open the image resource
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
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#345: lv_img_design: start to draw image
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
Read 4 bytes
Return 4 bytes
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_cache.c#118: Image draw cannot open the image resource
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
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#345: lv_img_design: start to draw image
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
Read 4 bytes
Return 4 bytes
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_cache.c#118: Image draw cannot open the image resource
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
TRACE: File: C:\Users\Max\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.10\libraries\lv_maixduino\src\src\lv_objx\lv_img.c#345: lv_img_design: start to draw image
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 !
.............

That’s the key:

WARNING: 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#118: Image draw cannot open the image resource

So LittlevGL can’t open the image. Be sure your driver is working.
Take a look at this topic. It seems @Ulric_Denis was using the same library:

I debug and i found i use LittlevGL old version. Now, this bug fixed (https://github.com/littlevgl/lvgl/commit/93357446a432189455fb4fcefb871e9aec70576a)

i use lv_maixduino it not update to LittlevGL latest version.

Thanks for help.

Glad you found the issue!

For the future, please keep in mind that the template instructs you to update to the latest version of LittlevGL before reporting a bug:

Before posting

  • Be sure to update lvgl from the latest version from the master branch.
1 Like

For lv_maixduino i use latest version (V6.0). in src directory can use submodules map to lvgl ? so version will update auto.

Unfortunately, the Arduino IDE doesn’t support submodules. You will have to manually update it yourself (which is quite simple).

Are you have a little bit of time for do some things “which is quite simple” ? plz update lv_maixduino to lvgl latest version.

Thank so much !

Please update it and send a Pull request. We can’t test it and it’s be add a tested version.

@embeddedt and I take care of core lvgl but we can not deal with all the projects. Therefore contribution is even more required and important in the hardware specific projects.

1 Like