遇到的问题:移植完FATFS后调用FATFS的文件系统函数打开目录下的文件是可以的(我使用的是外置的SPI Flash,将文件存放到SPI Flash中,再读出来),查找目录下 的文件也是可以找到的,但是使用lv_img_set_src函数就是无法显示图片,代码一行一行地调试后,发现是lvgl层的文件系统没用,打开文件失败,下面详细介绍遇到的问题和解决办法。
一、进行FATFS文件系统的移植
这个网上有许多教程,就不多做介绍了。
二、LVGL的文件系统移植
首先打开lv_conf.h中的宏定义,开启文件系统。
/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
#define LV_USE_FS_FATFS 1 // 开启,置为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
LV_FS_FATFS_LETTER是用来设置盘符的,盘符可以在ffconf.h中查看,用哪个就填哪个如果用的是sd卡就设置为'1',我用的是spi,设置为'3'。
LV_FS_FATFS_CACHE_SIZE是用来设置缓存大小的,可以根据需求调整大小。
开启宏定义后,在lv_extra.c中会进行文件系统的初始化,lv_fs_fatfs_init()这个函数在lv_fs_fatfs.c里面,确保你的工程里面有这个文件,不然编译报错,找不到该文件。lv_fs_fatfs.c在LVGLv8后应该是自带的,不需要我们去编写了。这个文件会进行回调函数的注册,编写函数实现,实际就是对LVGL里面的文件函数定向到FATFS的文件函数。
现在就移植完了,我以为就结束了,可以显示图片了,没想到是我想的太简单了。
三、验证函数是否可以使用
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, "3:/image.bin", LV_FS_MODE_RD);
printf("res: %d\n", res);
打印结果res: 12,对应下图的LV_FS_RES_UNKNOWN,未知错误
追到函数内部查看什么情况返回的未知错误:
// lv_fs_open的函数实现
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
{
if(path == NULL) {
LV_LOG_WARN("Can't open file: path is NULL");
return LV_FS_RES_INV_PARAM;
}
char letter = path[0];
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
if(drv == NULL) {
LV_LOG_WARN("Can't open file (%s): unknown driver letter", path);
return LV_FS_RES_NOT_EX;
}
if(drv->ready_cb) {
if(drv->ready_cb(drv) == false) {
LV_LOG_WARN("Can't open file (%s): driver not ready", path);
return LV_FS_RES_HW_ERR;
}
}
if(drv->open_cb == NULL) {
LV_LOG_WARN("Can't open file (%s): open function not exists", path);
return LV_FS_RES_NOT_IMP;
}
const char * real_path = lv_fs_get_real_path(path);
void * file_d = drv->open_cb(drv, real_path, mode);
if(file_d == NULL || file_d == (void *)(-1)) {
return LV_FS_RES_UNKNOWN; // ------> 此处返回未知
}
file_p->drv = drv;
file_p->file_d = file_d;
if(drv->cache_size) {
file_p->cache = lv_mem_alloc(sizeof(lv_fs_file_cache_t));
LV_ASSERT_MALLOC(file_p->cache);
lv_memset_00(file_p->cache, sizeof(lv_fs_file_cache_t));
file_p->cache->start = UINT32_MAX; /*Set an invalid range by default*/
file_p->cache->end = UINT32_MAX - 1;
}
return LV_FS_RES_OK;
}
分析可知,当file_d这个变量为空或者为(void*)(-1)时返回未知,file_d的值是drv->open_cb(drv, real_path, mode)这个函数返回的,而这个回调函数实际是调用的lv_fs_fatfs.c中的fs_open函数,而这个函数是定向到FATFS的f_open函数,前面我也提到,我调用FATFS的函数打开文件是没有任何问题的,那么问题出在哪呢?通过debug后,查看这个函数内部的所有变量值,发现是文件路径的问题,我传入的路径是"3:/image.bin",而传入函数drv->open_cb中的是"/image.bin",盘符没了,导致打开失败。文件路径在lv_fs_get_real_path中修改了,函数实现如下:
好家伙,把我的盘符取消了,怪不得打不开。那么现在找到问题了,就开始解决吧。
四、解决方法
方法一:修改函数,
既然路径被lv_fs_get_real_path修改了,那么我们就吧这个函数注释掉,传入全部的路径
// const char * real_path = lv_fs_get_real_path(path);
void * file_d = drv->open_cb(drv, path, mode);
这样res就是0了。
方法二:修改FATFS的默认盘符
(有可能有的人的FATFS移植后就默认开启的,但是我的没有开启)
在FATFS源文件中,找到ffconf.h文件,找到FF_FS_RPATH:
打开宏定义,设置为1,启用f_chdir() and f_chdrive()用于设置默认盘符。在lv_fs_fatfs.c中,找到fs_init这个函数添加如下代码:
这样就OK了。
五、图片显示
主函数中加入如下代码,实现bin文件的图片显示
lv_obj_t *mainPage = lv_obj_create(lv_scr_act());
lv_obj_clear_flag(mainPage, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(mainPage, LV_HOR_RES, LV_VER_RES);
lv_obj_set_style_border_side(mainPage, LV_BORDER_SIDE_NONE, 0);
lv_obj_set_style_radius(mainPage, LV_STATE_DEFAULT, 0);
lv_obj_t * img = lv_img_create(mainPage);
lv_img_set_src(img, "3:/image.bin");
lv_obj_set_size(img, LV_HOR_RES, LV_VER_RES); // 屏幕的长宽
lv_obj_center(img);