Problem with fs and drv and File pointer ESP32 bootloop

Hi first, I would like to thank you for all the work done.

I really like to use this library.

And sorry for my bad English.

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

I use ESP32 DOIT, and I compile on Arduino IDE my problem is like to SD card (SD. h and FS. h) and the File type.

What do you experience?

I tried to configure the drive for my sdcard I can read but when I use the “open_cb” method.
I can’t point void* file_p to a file type my esp boot loop and work only if I quote

*fp = f;

What do you expect?

I need to find a way to use images on my UI without overload the ram.

Code to reproduce

lv_fs_res_t open_cbsd (struct _lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  File f ;


  lv_fs_res_t res = LV_FS_RES_NOT_IMP;

  if (mode == LV_FS_MODE_WR)
{
    f = SD.open ("foo.txt", FILEWRITE);
    res = LV_FS_RES_OK; /
  }
  else if (mode == LV_FS_MODE_RD)
{
    f = SD.open ("foo.txt");
    res = LV_FS_RES_OK;
  }
  else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
{
    f = SD.open ("foo.txt");
    res = LV_FS_RES_OK;
  }
  File * fp = (File *) file_p;
  *fp = f;

  return res;
}

I don’t understand exactly what the problem is. What is the exact error you are getting? What are you trying to accomplish with these lines of code? Please be more specific than “using images”.

i try to use the file system abstraction module on littlevgl.

i follow the guide “page 89 on pdf” to add a driver and here on the website. and try to use the template gave in port folder. I just want to try this exemple.

lv_fs_file_t f;
lv_fs_res_t res;
res = lv_fs_open(&f, "S:/foo.txt", LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) my_error_handling();
uint32_t read_num;
uint8_t buf[8];
res = lv_fs_read(&f, buf, 8, &read_num);
if(res != LV_FS_RES_OK || read_num != 8) my_error_handling();
lv_fs_close(&f);

i overpass the path to try and i found SD.open need “/” before the name file like :

f = SD.open ("/foo.txt");

but when i try to put my File pointer into

void * file_p

like this


  File * fp = (File *) file_p;
  *fp = f;

the programe boot loop with panic core error

It’s still not clear to me exactly what goes wrong, aside from the fact that assigning to some pointer makes your system crash.

Please show the simplest code sample that can reproduce the issue, with just the required things. Make sure that you show all of the relevant functions though.

this is my code

#include <lvgl.h>
#include <Ticker.h>
#include <tft.h>
#include <SPI.h>
#include <SD.h>
#include <FS.h>
#include <AnalogMultiButton.h>



#define LVGL_TICK_PERIOD 20

#define TFT_CS        22    
#define TFT_DC        21    
#define SPI_MOSI      23
#define SPI_MISO      19
#define SPI_SCK       18
#define TP_IRQ         5
#define TP_CS         15
#define SD_CS          4




Ticker tick; /* timer for interrupt handler */

/*
   touch pad
*/
TFT tft(1); /* TFT instance */
TP tp(TP_CS, TP_IRQ);
uint16_t tp_x, tp_y;
bool released = true;



#if USE_LV_LOG != 0
/* Serial debugging */
void lv_log_register_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

  Serial.printf("%s@%d->%s\r\n", file, line, dsc);
  delay(100);
}
#endif

/*
   SD CARD
*/

lv_fs_res_t sd_open_cb(struct _lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  
  File f ; 
  char buf[256];

  sprintf(buf,"/%s",path);
  Serial.print("path : ");
  Serial.println(buf);


  if (mode == LV_FS_MODE_WR)
  {
    f = SD.open(buf,FILE_WRITE);
    res = LV_FS_RES_OK; 
  }
  else if (mode == LV_FS_MODE_RD)
  {
    f = SD.open(buf);
    res = LV_FS_RES_OK;
  }
  else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
  {
    f = SD.open(buf,FILE_WRITE);
    res = LV_FS_RES_OK;
  }
  File * fp = (File *) file_p; 
  *fp = f; // where the probleme come

  return res;
}


lv_fs_res_t sd_read_cb(struct _lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;

  res = LV_FS_RES_OK;
  return res;
}


lv_fs_res_t sd_close_cb(struct _lv_fs_drv_t * drv, void * file_p) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;

  return res;
}



/*
   Display flush
*/

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

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  static uint16_t temp[32];
  uint16_t c, old_c;
  int i = 0;

  tft.startWrite(); /* Start new TFT transaction */
  tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1), (area->y2 - area->y1 + 1)); /* set the working window */
  tft.writeCommand(0x22);
  for (int y = area->y1; y <= area->y2; y++) {
    for (int x = area->x1; x <= area->x2; x++) {
      temp[i] = color_p->full;
      i++;
      if (i < 32) {
        tft.writePixels(temp, i);
        i = 0;
      }
      color_p++;
    }
  }
  tft.endWrite(); /* terminate TFT transaction */
  lv_disp_flush_ready(disp); /* tell lvgl that flushing is done */
}

lv_obj_t * scr1;



/* Interrupt driven periodic handler */
static void lv_tick_handler(void)
{
  lv_tick_inc(LVGL_TICK_PERIOD);
}



/*driver for input tp*/

void tp_pressed(uint16_t x, uint16_t y) {
  tp_x = x;  tp_y = y;
  released = false;
}

void tp_released() {
  released = true;
}


/*input connection to LittleVgl*/




bool my_input_read_tp(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
  data->point.x = tp_x;
  data->point.y = tp_y;
  data->state = released ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
  return false; /*No buffering now so no more data read*/
}

/*********************************************************************************callback*************************************************************/


void btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
  if (event == LV_EVENT_CLICKED) {
    printf("Clicked\n");
  }
}

/************************************ Screen ****************************************************/



void scr_Menu_Start(void) {

  lv_obj_clean(scr1);
  lv_obj_t * btn_photo = lv_btn_create(scr1, NULL);     /*Add a button the current screen*/
  lv_obj_set_pos(btn_photo, 10, 10);                            /*Set its position*/
  lv_obj_set_size(btn_photo, 300, 60);                          /*Set its size*/
  lv_obj_set_event_cb(btn_photo, btn_event_cb);                 /*Assign a callback to the button*/

  lv_obj_t * labelb_photo = lv_label_create(btn_photo, NULL);          /*Add a label to the button*/
  lv_label_set_text(labelb_photo, "Photo");                     /*Set the labels text*/

  lv_obj_t * btn_Maint = lv_btn_create(scr1, NULL);    /*Add a button the current screen*/
  lv_obj_set_pos(btn_Maint, 10, 90);                            /*Set its position*/
  lv_obj_set_size(btn_Maint, 300, 60);                          /*Set its size*/
  lv_obj_set_event_cb(btn_Maint, btn_event_cb);                 /*Assign a callback to the button*/

  lv_obj_t * labelb_Maint = lv_label_create(btn_Maint, NULL);          /*Add a label to the button*/
  lv_label_set_text(labelb_Maint, "Maintenance");

  lv_obj_t * btn_Aide = lv_btn_create(scr1, NULL);    /*Add a button the current screen*/
  lv_obj_set_pos(btn_Aide, 10, 170);                            /*Set its position*/
  lv_obj_set_size(btn_Aide, 300, 60);                          /*Set its size*/
  lv_obj_set_event_cb(btn_Aide, btn_event_cb);                 /*Assign a callback to the button*/
  lv_obj_t * labelb_Aide = lv_label_create(btn_Aide, NULL);          /*Add a label to the button*/
  lv_label_set_text(labelb_Aide, "Aide");



}




void setup() {

  Serial.begin(115200); /* prepare for possible serial debug */


  lv_init();

  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
  tft.begin(); /* TFT init */
  tft.begin(TFT_CS, TFT_DC, SPI_MOSI, SPI_MISO, SPI_SCK);
  tft.setRotation(1); /* Landscape orientation */
  tp.setRotation(1);

   /*SD card init*/

  pinMode(SD_CS, OUTPUT); 
  Serial.print(F("Init SD card... "));
  if (!SD.begin(SD_CS)) {
    Serial.println(F("FAIL"));
    for (;;); //  RESET stuff
  }

/* create the drive */
  lv_fs_drv_t sd_drv;
  lv_fs_drv_init(&sd_drv);
  sd_drv.file_size = sizeof(File);
  sd_drv.letter = 'S';
  sd_drv.open_cb = sd_open_cb;
  sd_drv.close_cb = sd_close_cb;
  sd_drv.read_cb = sd_read_cb;
  lv_fs_drv_register(&sd_drv);

/*test the first function sd_open_cb*/

  lv_fs_file_t f;
  lv_fs_res_t res;
  res = lv_fs_open(&f, "S:foo.txt", LV_FS_MODE_RD); // system crash here
  if(res != LV_FS_RES_OK) Serial.print("don't work nothing open");

  File * ftest = (File *) f.file_d;
  Serial.print("name outside sd_open_cb : ");
  Serial.println(ftest->name()); 

/**********************************************************/


  lv_theme_t * th = lv_theme_night_init(210, NULL);     //Set a HUE value and a Font for the Night Theme
  lv_theme_set_current(th);                                           //Apply the theme
  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 = 320;
  disp_drv.ver_res = 240;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.buffer = &disp_buf;
  lv_disp_drv_register(&disp_drv);


  /*Initialize the touch pad*/
  lv_indev_drv_t indev_drv_tp;
  lv_indev_drv_init(&indev_drv_tp);
  indev_drv_tp.type = LV_INDEV_TYPE_POINTER;
  indev_drv_tp.read_cb = my_input_read_tp;
  lv_indev_drv_register(&indev_drv_tp);


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


  scr1 = lv_obj_create(NULL, NULL);
  lv_scr_load(scr1);
  scr_Menu_Start();


}

void loop() {
  tp.loop();

  lv_task_handler(); /* let the GUI do its work */
  delay(5);
}

How did you initialize the driver in LittlevGL? I mean the lv_fs_drv_t.

It seems ESP’s driver works similarly to POSIX API. If it’s really true take look at this driver as reference.

ok after a good night of sleep i found my problem !

/* create the drive */
  lv_fs_drv_t sd_drv;
  lv_fs_drv_init(&sd_drv);
  sd_drv.file_size = sizeof(File * ); // size of " File * " not a " File "!!
  sd_drv.letter = 'S';
  sd_drv.open_cb = sd_open_cb;
  sd_drv.close_cb = sd_close_cb;
  sd_drv.read_cb = sd_read_cb;
  lv_fs_drv_register(&sd_drv);

I will wrote a drive to share here !

thx a lot!

Strange, I thought File is also a pointer in the background. Else this wouldn’t work:

File f ;
f = SD.open ("foo.txt", FILEWRITE);

i’m ok to but when i try this :

  File  fp = (File ) file_p; 
  fp = f; 

i have :

In function 'lv_fs_res_t sd_open_cb(_lv_fs_drv_t*, void*, const char*, lv_fs_mode_t)':

cardsd.h:41:22: error: no matching function for call to 'fs::File::File(void*&)'

   File  fp = (File ) file_p; 

Ok, after try and retry i use to many memory …

I just want to add in my TFT a full screen image and two bouton “prec” and “next”.

So i change the way to do it .
I clean the screen

i use function inside the TFT library

  tft.drawJpgFile(SD, "/Wallpaper 320x240.jpg");

and add my bouton over.

void scr_photo(void) {
  binding = 1;

  lv_obj_clean(lv_scr_act());  // clean the screen
  tft.drawJpgFile(SD, "/Wallpaper 320x240.jpg"); //add my backgound file in the display not in memory


  lv_obj_t * btn_Ok = lv_btn_create(scr1, NULL);    //Add a buttons the current screen
  lv_obj_set_pos(btn_Ok, 20, 190);                           
  lv_obj_set_size(btn_Ok, 120, 40);                          
  lv_obj_set_event_cb(btn_Ok, btn_event_cb);                 
  lv_obj_t * labelb_OK = lv_label_create(btn_Ok, NULL);         
  lv_label_set_text(labelb_OK, "Ok");

  lv_obj_t * btn_Cancel = lv_btn_create(scr1, NULL);    
  lv_obj_set_pos(btn_Cancel, 180, 190);                           
  lv_obj_set_size(btn_Cancel, 120, 40);                         
  lv_obj_set_event_cb(btn_Cancel, btn_event_cb);                 
  lv_obj_t * labelb_Cancel = lv_label_create(btn_Cancel, NULL);         
  lv_label_set_text(labelb_Cancel, "Cancel");

}


But i obtain this. link here

That’s because by default you can’t mix LittlevGL and other graphics libraries (and you shouldn’t need to).

Why can’t you just convert the image using the image converter on the website?

cause when I try i obtain a no data with :

Warn: Image draw cannot open the image resource 	(C:\Users\ulric\Documents\Arduino\libraries\LittlevGL\src\src\lv_draw\lv_img_cache.c #118)
Warn: Image draw error 	(C:\Users\ulric\Documents\Arduino\libraries\LittlevGL\src\src\lv_draw\lv_draw_img.c #61)

or a boot loop.

i can give you my drive

 lv_fs_drv_t sd_drv;
  lv_fs_drv_init(&sd_drv);
  sd_drv.file_size = sizeof(File*) + 1;
  sd_drv.letter = 'S';
  sd_drv.open_cb = sd_open_cb;
  sd_drv.close_cb = sd_close_cb;
  sd_drv.read_cb = sd_read_cb;
  sd_drv.seek_cb = sd_seek_cb; /* Fonction de rappel pour se déplacer dans un fichier (déplacer le curseur) */
  sd_drv.tell_cb = sd_tell_cb; /* Fonction de rappel pour donner la position du curseur */
  lv_fs_drv_register(&sd_drv);

And the function linked :


lv_fs_res_t sd_open_cb(struct _lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;

  File f ;
  char buf[256];

  sprintf(buf, "/%s", path);
  Serial.print("path : ");
  Serial.println(buf);


  if (mode == LV_FS_MODE_WR)
  {
    f = SD.open(buf, FILE_WRITE);
    res = LV_FS_RES_OK;
  }
  else if (mode == LV_FS_MODE_RD)
  {
    f = SD.open(buf);
    res = LV_FS_RES_OK;
  }
  else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
  {
    f = SD.open(buf, FILE_WRITE);
    res = LV_FS_RES_OK;
  }
  if(!f) return LV_FS_RES_UNKNOWN;
  File * fp = (File *) file_p;
  *fp = f; // where the probleme come

  return res;
}


lv_fs_res_t sd_read_cb(struct _lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  File * fp = (File *) file_p;
  uint8_t * buffer = (uint8_t *) buf;

  Serial.print("name sd_read_cb : ");
  Serial.println(fp->name());
  *br = fp->read(buffer, btr);


  res = LV_FS_RES_OK;
  return res;
}

lv_fs_res_t sd_seek_cb(struct _lv_fs_drv_t * drv, void * file_p, uint32_t pos) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  File * fp = (File *) file_p;
  

  fp->seek(pos);
    Serial.print("name sd_seek_cb : ");
  Serial.println(fp->name());
  res = LV_FS_RES_OK;
  return res;
}

lv_fs_res_t sd_tell_cb(struct _lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  File * fp = (File *) file_p;
  

  * pos_p = fp->position();
  Serial.print("name in sd_tell_cb : ");
  Serial.println(fp->name());
  res = LV_FS_RES_OK;
  return res;

}



lv_fs_res_t sd_close_cb(struct _lv_fs_drv_t * drv, void * file_p) {
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
  File * fp = (File *) file_p;
  
  Serial.println("close");
  fp->close();
  res = LV_FS_RES_OK;
  return res;
}

i try it with a simple test with a foo.txt who contain :

hello world!!

my test :

  lv_fs_file_t f;
  lv_fs_res_t res;
  res = lv_fs_open(&f, "S:foo.txt", LV_FS_MODE_RD);
  if (res != LV_FS_RES_OK) Serial.print("don't work nothing open");

  File * ftest = (File *) f.file_d;
  Serial.print("name outside sd_open_cb : ");
  Serial.println(ftest->name());


  uint32_t read_num, readpos;
  uint8_t buf[8];

  lv_fs_seek(&f, 2);
  if (res != LV_FS_RES_OK) Serial.print("don't work nothing read");
  res = lv_fs_read(&f, buf, 3, &read_num);
  if (res != LV_FS_RES_OK || read_num != 3) Serial.print("don't work nothing read");
  lv_fs_tell(&f, &readpos);
  lv_fs_close(&f);

  Serial.println((char *) buf);
  Serial.println(readpos);

and it work.

path : /foo.txt
name outside sd_open_cb : /foo.txt
name sd_seek_cb : /foo.txt
name sd_read_cb : /foo.txt
name in sd_tell_cb : /foo.txt
close
llo
5

  lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
  lv_img_set_src(icon, "S:/image1.bin");

It looks like you are using the image converter to make a binary image. Why can’t you use the C array option?

Because i don’t want to use too much memory in my chip.

Usually the method you are using now consumes more memory, because it has to load the image into RAM and decode it. The other method only uses Flash (which there is usually more of)

i agree but i need more than 10 photo so it’s better with bin file.

i rather use 200kB then all my memory

In that case, you have the line numbers in your log. I suggest you do some debugging and figure out why it “cannot open the image resource”. I can’t really think of anything else that could be the problem.

that what i’m doing. but i don’t found anything

it’s look like this is the probleme but i don’t understand

#if LV_USE_FILESYSTEM
    else if(src_type == LV_IMG_SRC_FILE) {
        lv_fs_file_t file;
        lv_fs_res_t res;
        uint32_t rn;
        res = lv_fs_open(&file, src, LV_FS_MODE_RD);
        if(res == LV_FS_RES_OK) {
            res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
            lv_fs_close(&file);
        }

        lv_img_cf_t cf = ((lv_img_dsc_t *)src)->header.cf;
        if(cf < CF_BUILT_IN_FIRST || cf > CF_BUILT_IN_LAST) return LV_RES_INV; // <---here

    }

If you step through with a debugger you should find where the error is coming from.

in which type i need to read the file in my sd for a image ?