How do I correctly make the SD Card work for image widgets on an ESP32 Dev Kit with LVGL v.8.3?

Description

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

ESP 32 Devkit on Arduino IDE

What LVGL version are you using?

8.3

What do you want to achieve?

Setup File system to be able to use an image on an SD Card for LVGL widgets

What have you tried so far?

Code to reproduce

/*Initialize your Storage device and File system.*/
static void fs_init(void)
{
    // E.g. for FatFS initialize the SD card and FatFS itself
    // SD Card Initialization

    if (!SD.begin()) {
      Serial.println("Card Mount Failed");
      return;
    }

    uint8_t cardType = SD.cardType();

    if (cardType == CARD_NONE) {
      Serial.println("No SD card attached");
      return;
    }

    Serial.print("SD Card Type: ");
    if (cardType == CARD_MMC) {
      Serial.println("MMC");
    } else if (cardType == CARD_SD) {
      Serial.println("SDSC");
    } else if (cardType == CARD_SDHC) {
      Serial.println("SDHC");
    } else {
      Serial.println("UNKNOWN");
    }
  
    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);
    
    Serial.println( "Setup done" );
}

static void * sd_fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
    File *fp = (File *)lv_mem_alloc(sizeof(File));
    if (fp == NULL)
      return NULL;
    File mySDfile = *fp;

    // Make the path relative to the current directory (the projects root folder)
    char buf[256];
    sprintf(buf, "/%s", path);

    if (mode == LV_FS_MODE_WR)
    {
      // Open a file for write
      mySDfile = SD.open(buf,  FILE_WRITE);
    }
    else if (mode == LV_FS_MODE_RD)
    {
      // Open a file for read
      mySDfile = SD.open(buf, FILE_READ);
    }
    else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
    {
      // Open a file for read and write
      mySDfile = SD.open(buf,  FILE_WRITE);
    }

    mySDfile = SD.open(buf);
    //make sure at the beginning
    mySDfile.seek(0);

    *fp = mySDfile;

    return fp;
}

static lv_fs_res_t sd_fs_close(lv_fs_drv_t *drv, void *file_p)
{
  File *fp = (File *)file_p;

  fp->close();

  delete (fp); // when close
  return LV_FS_RES_OK;
}

static lv_fs_res_t sd_fs_read(lv_fs_drv_t *drv, void *file_p, void *fileBuf, uint32_t btr, uint32_t *br)
{
    lv_fs_res_t res = LV_FS_RES_NOT_IMP;

    return res;
}

static lv_fs_res_t sd_fs_seek(lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence)
{
  lv_fs_res_t res = LV_FS_RES_OK;

  File *fp = (File *) file_p;

  // commented out because it is throwing an error
  /* if (whence == LV_FS_SEEK_SET)
  {
      fp->seek(pos, 0);
  }
  if (whence == LV_FS_SEEK_CUR)
  {
      fp->seek(pos, 1);
  }
  if (whence == LV_FS_SEEK_END)
  {
      fp->seek(pos, 2);
  } */
  
  fp->seek(pos);
  return res;
}

static lv_fs_res_t sd_fs_tell(lv_fs_drv_t *drv, void *file_p, uint32_t *pos_p)
{
  File *fp = (File *)file_p;
  *pos_p = fp->position();

  return LV_FS_RES_OK;
}

void sd_fs_init(void)
{
    fs_init();

    /*Add a simple drive to open images*/
    static lv_fs_drv_t fs_drv;
    lv_fs_drv_init(&fs_drv);

    /*Set up fields...
    To use files in image widgets the following callbacks are required:
    - open
    - close
    - read
    - seek
    - tell
    */

    fs_drv.letter = 'S';
    fs_drv.open_cb = sd_fs_open;
    fs_drv.close_cb = sd_fs_close;
    fs_drv.read_cb = sd_fs_read;
    fs_drv.seek_cb = sd_fs_seek;
    fs_drv.tell_cb = sd_fs_tell;
    fs_drv.write_cb = NULL;
    fs_drv.dir_close_cb = NULL;
    fs_drv.dir_open_cb = NULL;
    fs_drv.dir_read_cb = NULL;

    lv_fs_drv_register(&fs_drv);
    Serial.println("drv registered!");
}


void setup()
{
...


    sd_fs_init();

    lv_obj_t * img_bin = lv_img_create(lv_scr_act());
    lv_img_set_src(img_bin, "S:Baboon40.bin");
    lv_obj_align(img_bin, LV_ALIGN_CENTER, 0, 0);
...
}

Screenshot and/or video

This compiles with no errors but when uploaded to my ESP32, it goes into a boot loop with this logs:

SD Card Type: SDHC
SD Card Size: 14910MB
Setup done
drv registered!
Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x00000000  PS      : 0x00060230  A0      : 0x800ef870  A1      : 0x3ffb26e0  
A2      : 0x3ffc1348  A3      : 0x3ffc5044  A4      : 0x3ffb2788  A5      : 0x00000004  
A6      : 0x3ffb26f8  A7      : 0xff000000  A8      : 0x800d18cc  A9      : 0x3ffb26b0  
A10     : 0x3ffc5044  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x3f400e94  
A14     : 0x00000000  A15     : 0x3ffc4e48  SAR     : 0x0000001c  EXCCAUSE: 0x00000014  
EXCVADDR: 0x00000000  LBEG    : 0x40086518  LEND    : 0x40086523  LCOUNT  : 0xffffffff  


Backtrace:0xfffffffd:0x3ffb26e00x400ef86d:0x3ffb2700 0x400ddb17:0x3ffb2720 0x400de102:0x3ffb2750 0x400f513f:0x3ffb2770 0x400d1af1:0x3ffb27b0 0x400fee3a:0x3ffb2820 




ELF file SHA256: 0000000000000000

Rebooting...

Most of my references seem to be using older versions of lvgl and I’m having trouble making odds and ends of them.

Thank you!

PS: I’ve checked that the SD card works using the SD.h library example together with this tutorial:

and

I had to add a jumper to make it work (see 2nd video)

I forgot to mention that I am using an ST7796 TFT Screen

First of all install backtrace Plugin to IDE: https://github.com/me-no-dev/EspExceptionDecoder and you will see Error place.
Next: try to add check for successful file open in sd_fs_open():

    mySDfile = SD.open(buf);
+   if (!mySDfile) {
+       lv_mem_free(fp);
+       return NULL;
+    }
    //make sure at the beginning
    mySDfile.seek(0);

may be you file is not opened?

I tried using the ExceptionDecoder and here’s what it returned:

PC: 0x00000000
EXCVADDR: 0x00000000

Decoding stack results
0x400ef7e5: lv_fs_close at C:\Users\User\Documents\Arduino\libraries\lvgl\src\misc\lv_fs.c line 115
0x400dda8f: lv_img_decoder_built_in_info at C:\Users\User\Documents\Arduino\libraries\lvgl\src\draw\lv_img_decoder.c line 295
0x400de07a: lv_img_decoder_get_info at C:\Users\User\Documents\Arduino\libraries\lvgl\src\draw\lv_img_decoder.c line 99
0x400f50b7: lv_img_set_src at C:\Users\User\Documents\Arduino\libraries\lvgl\src\widgets\lv_img.c line 107
0x400d1afd: setup() at D:\clinikapps\repositories\tft_test/tft_test.ino line 271
0x400fe762: loopTask(void*) at C:\Users\User\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.4\cores\esp32\main.cpp line 42

may be you file is not opened?

How do I check this?

Does you apply my last diff?
Did you opening lv_fs.c at 115 line to chek what it doing?

I’ve decided to abandon the code I wrote and try out the “prepared drivers.”

So now I’m trying out POSIX, changed LV_USE_FS_POSIX to 1, LV_FS_POSIX_LETTER to 'S', and LV_FS_POSIX_PATH to "/".

I then ran the code, but the image is still not showing up. It’s not showing any errors though.

  lv_obj_t * img_bin = lv_img_create(lv_scr_act());
  lv_img_set_src(img_bin, "S:/Baboon40.bin");
  lv_obj_align(img_bin, LV_ALIGN_CENTER, 0, 0);
  lv_obj_set_size(img_bin, 320,480);

Coincidentally, I just completed a case recently, which contains a complete solution to your problem. Source code: https://github.com/100askTeam/esp-100ask-arduino-learn/blob/master/examples/08_integrated/01_lcd_sd_card_fc_joypad_fs_lv_lib_100ask/01_lcd_sd_card_fc_joypad_fs_lv_lib_100ask.ino
run output:

effect:

Hope this helps you.

Hello!

Thank you so much for sharing your code!

I do have questions:

  1. I was reading your project’s README fileWhy do you have different pins for your MISO, MOSI and SCK/CK for your TFT and SD Card reader? Is it ok to have them share or do I need to separate them? Here’s what my circuit looks like:

  1. Do I do this:
lv_img_set_src(img_bin, "S:/root/arduino.png");

or this:

lv_img_set_src(img_bin, "S:/arduino.png");

Once more, thank you so much for helping me out, I am a complete noob when it comes to hardware!

EDIT:

The error I’m getting now is a kernel panic, I think this is progress!

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608
entry 0x400805f0
Hello Arduino! V8.3.1
I am LVGL_Arduino
initializing sd fs init...
SD Card Type: SDHC
SD Card Size: 14910MB
Total space: 14902MB
Used space: 2MB
sd fs init done...

assert failed: xQueueSemaphoreTake queue.c:1549 (pxQueue->uxItemSize == 0)


Backtrace:0x40083595:0x3ffb1f000x400894a5:0x3ffb1f20 0x4008e215:0x3ffb1f40 0x4008a1f9:0x3ffb2070 0x400fd4e9:0x3ffb20b0 0x400d2d34:0x3ffb20d0 0x400d30a1:0x3ffb20f0 0x400d3111:0x3ffb2110 0x400d33ed:0x3ffb2130 0x400d341d:0x3ffb2150 0x4010a766:0x3ffb2170 0x4010a979:0x3ffb2190 0x4010c87b:0x3ffb21d0 0x4010ea2b:0x3ffb2440 0x40107b7a:0x3ffb25b0 0x40116a75:0x3ffb25d0 0x400d2857:0x3ffb25f0 0x400d2141:0x3ffb2670 0x400d1e5b:0x3ffb26a0 0x400efb31:0x3ffb26e0 0x400e7b87:0x3ffb2700 0x400de346:0x3ffb2750 0x400f51db:0x3ffb2770 0x400d1c3f:0x3ffb27b0 0x400fe92a:0x3ffb2820 




ELF file SHA256: 0000000000000000

Rebooting...

John

  1. I wrote these examples for teaching. At present, our smallest board is not convenient to connect bread board, so we adopted this wiring method.
  2. You can first test whether the file system interface works normally, such as: https://gitee.com/weidongshan/lvgl_100ask_course_materials/blob/master/02_%E7%A8%8B%E5%BA%8F%E6%BA%90%E7%A0%81/01_%E8%AF%BE%E5%A0%82%E4%BB%A3%E7%A0%81/lv_100ask_teach_demos/src/lv_100ask_demo_course_6_1_1/lv_100ask_demo_course_6_1_1.c

Key source code in the link:


// 要打开的文件
#define FILE_NAME	"D:/100ask/tmp/lv_fs_test.txt"
// 要读取的目录
#define DIR_PATH	"D:/100ask/tmp/"

/**********************
 *      TYPEDEFS
 **********************/


/**********************
 *  STATIC VARIABLES
 **********************/


/**********************
 *  STATIC PROTOTYPES
 **********************/
/* 通过LVGL文件系统接口统一不同的文件系统并读取文件 */
static void lv_fs_read_dir(char * fn);

/* 通过LVGL文件系统接口统一不同的文件系统并读取目录内容 */
static void lv_fs_read_file(char * path);


/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_100ask_demo_course_6_1_1(void)
{
#if 1
	// 读取文件	
	lv_fs_read_file(FILE_NAME);
#else
	// 读取目录内容
	lv_fs_read_dir(DIR_PATH);
#endif	

}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/* 通过LVGL文件系统接口统一不同的文件系统并读取文件 */
static void lv_fs_read_file(char * fn)
{
	lv_fs_file_t f;
	lv_fs_res_t res;

	// 打开文件有两个模式: LV_FS_MODE_RD(只读) 和 LV_FS_MODE_WR(写)
	res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
	// 如果一切正常会返回 LV_FS_RES_OK ,其他错误代码请看 lv_fs.h 中的 lv_fs_res_t 定义
	if(res != LV_FS_RES_OK) {
		LV_LOG_USER("Open error! Error code: %d", res);
		return;
	}

	/* 每次实际读取到的数据大小(byte) */
	uint32_t read_num;
	/* 数据缓冲区 */
	uint8_t buf[8];

	/* 读取整个文件并打印内容 */
	while (1) {
		res = lv_fs_read(&f, buf, 8, &read_num);
		if(res != LV_FS_RES_OK) {
			LV_LOG_USER("Read error! Error code: %d", res);
			break;
		}

		/* 将读取到数据打印出来 */
		printf("%s", buf);

		if (read_num != 8)	break;
	}

	lv_fs_close(&f);

}

/* 通过LVGL文件系统接口统一不同的文件系统并读取目录内容 */
static void lv_fs_read_dir(char * path)
{
	lv_fs_dir_t dir;
	lv_fs_res_t res;
	res = lv_fs_dir_open(&dir, path);
	if(res != LV_FS_RES_OK){
		LV_LOG_USER("Open DIR error! Error code: %d", res);
		return;
	}

	char fn[256];	// 缓冲区
	while(1) {
		res = lv_fs_dir_read(&dir, fn);
		if(res != LV_FS_RES_OK) {
			LV_LOG_USER("Read DIR error! Error code: %d", res);
			break;
		}

		/* 如果没有更多文件可以读取时 fn 就为空 */
		if(strlen(fn) == 0) {
			LV_LOG_USER("Fn is empty, if not more files to read.");
			break;
		}

		printf("%s\n", fn);
	}

	lv_fs_dir_close(&dir);

}


Hello! Just a bit of an update, I needed to uncomment #define SUPPORT_TRANSACTIONS and seems like that made this work!!! Thank you so much!

Now I just need to find a way to get rid of these lines. :smiley:

1 Like

One thing I noticed is that it works for .bin files but if it’s .png files, they are outputted as NO DATA.

Cheers!
This seems to be a screen driver problem. You should check the screen driver code.

When NO DATA. is displayed, check the output information of the console.

I was using TFT_eSPI for this, tried LovyanGFX and it still has the same problem with the lines. Strange…

Have you tested the screen and screen driver? For example, the full screen is brushed to a certain color.

Not yet, what do you mean by “brushed to a certain color”?

[SOLVED] The solution was found, I should enable LV_USE_FS_FATFS , inside my lv_conf.h
the _lv_indev_read warning was because of the touch input, which I am not using, and I have registered a dummy one, so removing the input device declaration solves the problem as well.