小熊派 LVGL 移植文件系统

6 篇文章 12 订阅
5 篇文章 0 订阅

小熊派 LVGL 移植文件系统

一、移植前言

之前使用小熊派实现了鸿蒙动画的开机界面,具体使用的技术栈为 STM32 + LiteOS + LVGL + FATFS +DMA 方式实现,刷新效率非常高,预览视频如下:

启动界面

关于这个的实现过程我会写一系列的教程分享出来,主要分为下面几个部分,本节为第三部分,给 LVGL 移植 FATFS 文件系统接口

  • 小熊派移植华为 LiteOS-M(基于MDK):链接
  • 小熊派基于 LiteOS 移植 LVGL 显示接口:链接
  • 小熊派基于 LiteOS 移植 LVGL 文件系统:链接
  • 小熊派实现鸿蒙开机界面(LiteOS+LVGL):链接

本节的教程基于上一节配置好的工程,使用 STM32CubeMX 进一步配置 SDIO 总线接口,同时移植 FATFS 文件系统,关于 CubeMX 配置 SDIO 的教程,可以参考 mculover666 大神的:

【STM32Cube_20】在SD卡上移植FATFS文件系统

二、CubeMX 开启 SDIO 接口

开启 SD 单线模式

20220117114031

配置 SDIO 参数(保持默认):

20220117114101

三、CubeMX 开启 FATFS

在开启 SD 卡后,我们添加 FATFS 的文件系统支持

20220117114244

参数保持默认,mculover666 教程中开启了 FATFS 对文件中文名称的支持,但会占据很大的 rom 空间(180k),所以我们就不开启了,直接使用英文名称

配置完成后生成代码,这里生成代码我们要修改一下栈的大小,因为 FATFS 和 LVGL 都使用到了栈,所以改大一些

20220117114727

生成代码,有个警告,就是有些没用到的参数没配置,我们不管他

20220117114754

四、LVGL对接FATFS

代码生成了,我们先编写个小 Demo 测试一下 FAT 有没有移植成功,主函数插入如下代码:

定义一个文件系统对象和返回值

/* USER CODE BEGIN PV */
FATFS   fs;			/* FATFS 文件系统对象 */
FRESULT fr; 		/* FATFS API 返回值 */
/* USER CODE END PV */

在初始化前添加如下代码

	/* USER CODE BEGIN 2 */
	printf("FATFS test...\r\n");
	/* 挂载SD卡 */
	fr = f_mount(&fs, "", 0);
	if(fr == FR_OK)
	{
			printf("SD card mount ok!\r\n");
	}
	else
	{
			printf("SD card mount error, error code:%d.\r\n",fr);
	}

编译下载,观察串口输出:

20220117160035

测试正常,有的时候运行程序时会出现内存分配不够的报错,可能是因为 LiteOS 内存管理设置没有配置好,导致 LVGL 的内存池不够分配 ,LiteOS 系统启动需要手动设置系统 SRAM 的起止地址以及空间大小,因为我使用的是 MDK IDE,LiteOS 不能获得芯片 RAM 大小,所以我们把它改成 64k 就行:

20220117223756

当 FATFS 测试成功后,下一个就是移植到 LVGL 上,移植文件系统过程和移植显示接口过程很相似,先使能 lv_port_fs.c 和 .h 里面的宏定义

20220117162156

同时在 lv_conf.h 里面开启文件系统使能

20220117162626

编译一下代码,通过

20220117164241

下面就是修改 fs 文件接口了,进入 lv_port_fs.c 文件,看到 lv_port_fs_init 函数,函数里面是有关文件系统的接口初始化,代码如下

void lv_port_fs_init(void)
{
    /*----------------------------------------------------
     * Initialize your storage device and File System
     * -------------------------------------------------*/
    fs_init();

    /*---------------------------------------------------
     * Register the file system interface in LVGL
     *--------------------------------------------------*/

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

    /*Set up fields...*/
    fs_drv.file_size = sizeof(file_t);
    fs_drv.letter = 'P';
    fs_drv.open_cb = fs_open;
    fs_drv.close_cb = fs_close;
    fs_drv.read_cb = fs_read;
    fs_drv.write_cb = fs_write;
    fs_drv.seek_cb = fs_seek;
    fs_drv.tell_cb = fs_tell;
    fs_drv.free_space_cb = fs_free;
    fs_drv.size_cb = fs_size;
    fs_drv.remove_cb = fs_remove;
    fs_drv.rename_cb = fs_rename;
    fs_drv.trunc_cb = fs_trunc;

    fs_drv.rddir_size = sizeof(dir_t);
    fs_drv.dir_close_cb = fs_dir_close;
    fs_drv.dir_open_cb = fs_dir_open;
    fs_drv.dir_read_cb = fs_dir_read;

    lv_fs_drv_register(&fs_drv);
}

fs_init() 是初始化 SD 卡和文件系统接口,这里初始化接口我们已经在 CubeMX 生成的代码中初始化过了,所以不用再初始化,只需要在改代码里面放上挂载 SD 卡设备代码就行,下面的代码就是建立一个文件系统驱动

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

然后配置驱动的函数入口

    /*Set up fields...*/
    fs_drv.file_size = sizeof(file_t);
    fs_drv.letter = 'P';
    fs_drv.open_cb = fs_open;
    fs_drv.close_cb = fs_close;
    fs_drv.read_cb = fs_read;
    fs_drv.write_cb = fs_write;
    fs_drv.seek_cb = fs_seek;
    fs_drv.tell_cb = fs_tell;
    fs_drv.free_space_cb = fs_free;
    fs_drv.size_cb = fs_size;
    fs_drv.remove_cb = fs_remove;
    fs_drv.rename_cb = fs_rename;
    fs_drv.trunc_cb = fs_trunc;

    fs_drv.rddir_size = sizeof(dir_t);
    fs_drv.dir_close_cb = fs_dir_close;
    fs_drv.dir_open_cb = fs_dir_open;
    fs_drv.dir_read_cb = fs_dir_read;

最后注册驱动

	lv_fs_drv_register(&fs_drv);

注册完成后,lvgl 会根据注册驱动的函数入口去执行对应的函数,我们只要修改对应的函数就行,这里我们先修改我们使用到的函数主要是

fs_open //打开文件
fs_close //关闭文件
fs_read //读文件
fs_write //写文件
fs_seek //重定位文件

下面修改这些函数,现在头部包含头文件,然后重新定义文件类型

添加头文件

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_fs.h"
#include "fatfs.h"
#include "usart.h"

覆盖掉原型的类型定义

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

typedef FIL file_t;		// 把FIL类型定义成file_t
typedef DIR dir_t; 		// 把DIR类型定义成dir_t

修改 fs_init() 函数

static void fs_init(void)
{

    /*E.g. for FatFS initialize the SD card and FatFS itself*/
		static FATFS  fs;			/* FATFS 文件系统对象 */
		FRESULT fr; 		/* FATFS API 返回值 */
		printf("LVGL FATFS INIT...\r\n");
		fr = f_mount(&fs, "", 0);
		if (fr != FR_OK) 
		{
				printf("SD Card mounted error: (%d)\r\n", fr);
		} else
			printf("SD Card mounted successfully!\r\n");
    /*You code here*/
}

修改打开文件函数:

static lv_fs_res_t fs_open (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;
	  FRESULT fr; 		/* FATFS API 返回值 */
	
    if(mode == LV_FS_MODE_WR)
    {
        /*Open a file for write*/
				fr = f_open((FIL*)file_p, path, LV_FS_MODE_WR);
				if(fr != FR_OK)
				{
					printf("open file \"%s\" error : %d\r\n", path, fr);
				}else
				res = LV_FS_RES_OK;
    }
    else if(mode == LV_FS_MODE_RD)
    {
        /*Open a file for read*/
				fr = f_open((FIL*)file_p, path, LV_FS_MODE_RD);
				if(fr != FR_OK)
				{
					printf("open file \"%s\" error : %d\r\n", path, fr);
				}else
					res = LV_FS_RES_OK;
		}
    else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
    {
        /*Open a file for read and write*/
				fr = f_open((FIL*)file_p, path, LV_FS_MODE_WR | LV_FS_MODE_RD);
				if(fr != FR_OK)
				{
					printf("open file \"%s\" error : %d\r\n", path, fr);
				}else
				res = LV_FS_RES_OK;
    }
    return res;
}

关闭文件接口

static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
    lv_fs_res_t res = LV_FS_RES_NOT_IMP;
		FRESULT fr; 		/* FATFS API 返回值 */
		printf("close file\r\n");
		/* 操作完成,关闭文件 */
		fr = f_close((FIL*)file_p);
		if(fr != FR_OK)
		{
			printf("close file error! error : %d\r\n", fr);
		}else
			res = LV_FS_RES_OK;
			return res;
}

定位文件接口

static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos)
{
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
	FRESULT fr; 		/* FATFS API 返回值 */
	fr = f_lseek((FIL*)file_p, pos);
  if (fr != FR_OK) 
	{
    printf("read file error! error : %d\r\n", fr);
  }else
	res = LV_FS_RES_OK;
	
  return res;
}

读写文件接口

static lv_fs_res_t fs_read (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;
	FRESULT fr; 		/* FATFS API 返回值 */

	fr = f_read((FIL*)file_p, buf, btr, br);
  if (fr != FR_OK) 
	{
    printf("read file error! error : %d\r\n", fr);
  }else
		res = LV_FS_RES_OK;
   return res;
}

static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
  lv_fs_res_t res = LV_FS_RES_NOT_IMP;
	FRESULT fr; 		/* FATFS API 返回值 */
	fr = f_write((FIL*)file_p, buf, btw, bw);
  if (fr != FR_OK) 
	{
    	printf("read file error! error : %d\r\n", fr);
  }else
	res = LV_FS_RES_OK;

  return res;
}

到此移植文件系统接口基本上完成,下面编写一个测试代码

五、测试代码

在lcd任务中添加如下代码,打开 SD 卡下面的 lvgl.txt 文件,写入 test 字符串

	lv_port_fs_init();
	
	lv_fs_file_t *file1 = lv_mem_alloc(sizeof(lv_fs_file_t *));
	fs_res=lv_fs_open(file1,"S:/lvgl.txt",LV_FS_MODE_WR | LV_FS_MODE_RD);
	if(fs_res != LV_FS_RES_OK)
		printf("open error! code:%d\r\n",fs_res);
	fs_res=lv_fs_write(file1,"test",4,NULL);
	if(fs_res != LV_FS_RES_OK)
		printf("write error! code:%d\r\n",fs_res);
	
	fs_res=lv_fs_close(file1);
	if(fs_res != LV_FS_RES_OK)
		printf("close error! code:%d\r\n",fs_res);
	lv_mem_free(file1);

下载编译

六、实验现象

串口返回写入成功:

20220118142952

打开sd卡下面的文件,观察写入情况,写入成功:

20220118143043

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Top嵌入式

投喂个鸡腿

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值