2.4 DFS挂载到FAL分区测试
这里增加FAL flash抽象层,我们将elmfat文件系统挂载到W25Q128 flash设备的filesystem分区上,由于FAL管理的filesystem分区不是块设备,需要先使用FAL分区转BLK设备接口函数将filesystem分区转换为块设备,然后再将DFS elmfat文件系统挂载到filesystem块设备上。
我们接着修改fal_sample.c
文件,修改后代码:
/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-04-21 Wangyuqiang the first version */ #include "rtthread.h" #include "rtdevice.h" #include "board.h" #include "fal.h" #include <dfs_posix.h> #define FS_PARTITION_NAME "filesystem" #define BUF_SIZE 1024 static int fal_test(const char *partiton_name) { int ret; int i, j, len; uint8_t buf[BUF_SIZE]; const struct fal_flash_dev *flash_dev = RT_NULL; const struct fal_partition *partition = RT_NULL; if (!partiton_name) { rt_kprintf("Input param partition name is null!\n"); return -1; } partition = fal_partition_find(partiton_name); if (partition == RT_NULL) { rt_kprintf("Find partition (%s) failed!\n", partiton_name); ret = -1; return ret; } flash_dev = fal_flash_device_find(partition->flash_name); if (flash_dev == RT_NULL) { rt_kprintf("Find flash device (%s) failed!\n", partition->flash_name); ret = -1; return ret; } rt_kprintf("Flash device : %s " "Flash size : %dK \n" "Partition : %s " "Partition size: %dK\n", partition->flash_name, flash_dev->len/1024, partition->name, partition->len/1024); /* erase all partition */ ret = fal_partition_erase_all(partition); if (ret < 0) { rt_kprintf("Partition (%s) erase failed!\n", partition->name); ret = -1; return ret; } rt_kprintf("Erase (%s) partition finish!\n", partiton_name); /* read the specified partition and check data */ for (i = 0; i < partition->len;) { rt_memset(buf, 0x00, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_read(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) read failed!\n", partition->name); ret = -1; return ret; } for(j = 0; j < len; j++) { if (buf[j] != 0xFF) { rt_kprintf("The erase operation did not really succeed!\n"); ret = -1; return ret; } } i += len; } /* write 0x00 to the specified partition */ for (i = 0; i < partition->len;) { rt_memset(buf, 0x00, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_write(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) write failed!\n", partition->name); ret = -1; return ret; } i += len; } rt_kprintf("Write (%s) partition finish! Write size %d(%dK).\n", partiton_name, i, i/1024); /* read the specified partition and check data */ for (i = 0; i < partition->len;) { rt_memset(buf, 0xFF, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_read(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) read failed!\n", partition->name); ret = -1; return ret; } for(j = 0; j < len; j++) { if (buf[j] != 0x00) { rt_kprintf("The write operation did not really succeed!\n"); ret = -1; return ret; } } i += len; } ret = 0; return ret; } static void fal_sample(void) { /* 1- init */ fal_init(); if (fal_test("font") == 0) { rt_kprintf("Fal partition (%s) test success!\n", "font"); } else { rt_kprintf("Fal partition (%s) test failed!\n", "font"); } if (fal_test("download") == 0) { rt_kprintf("Fal partition (%s) test success!\n", "download"); } else { rt_kprintf("Fal partition (%s) test failed!\n", "download"); } } MSH_CMD_EXPORT(fal_sample, fal sample); static void fal_elmfat_sample(void) { int fd, size; struct statfs elm_stat; struct fal_blk_device *blk_dev; char str[] = "elmfat mount to W25Q flash.", buf[80]; /* fal init */ fal_init(); /* create block device */ blk_dev = (struct fal_blk_device *)fal_blk_device_create(FS_PARTITION_NAME); if(blk_dev == RT_NULL) rt_kprintf("Can't create a block device on '%s' partition.\n", FS_PARTITION_NAME); else rt_kprintf("Create a block device on the %s partition of flash successful.\n", FS_PARTITION_NAME); /* make a elmfat format filesystem */ if(dfs_mkfs("elm", FS_PARTITION_NAME) == 0) rt_kprintf("make elmfat filesystem success.\n"); /* mount elmfat file system to FS_PARTITION_NAME */ if(dfs_mount(FS_PARTITION_NAME, "/", "elm", 0, 0) == 0) rt_kprintf("elmfat filesystem mount success.\n"); /* Get elmfat file system statistics */ if(statfs("/", &elm_stat) == 0) rt_kprintf("elmfat filesystem block size: %d, total blocks: %d, free blocks: %d.\n", elm_stat.f_bsize, elm_stat.f_blocks, elm_stat.f_bfree); if(mkdir("/user", 0x777) == 0) rt_kprintf("make a directory: '/user'.\n"); rt_kprintf("Write string '%s' to /user/test.txt.\n", str); /* Open the file in create and read-write mode, create the file if it does not exist*/ fd = open("/user/test.txt", O_WRONLY | O_CREAT); if (fd >= 0) { if(write(fd, str, sizeof(str)) == sizeof(str)) rt_kprintf("Write data done.\n"); close(fd); } /* Open file in read-only mode */ fd = open("/user/test.txt", O_RDONLY); if (fd >= 0) { size = read(fd, buf, sizeof(buf)); close(fd); if(size == sizeof(str)) rt_kprintf("Read data from file test.txt(size: %d): %s \n", size, buf); } } MSH_CMD_EXPORT_ALIAS(fal_elmfat_sample, fal_elmfat,fal elmfat sample);
2.5 测试结果
测试结果如下:
3.Easyflash移植到FAL分区
3.1 简述EasyFlash
关于EasyFlash的来源我们已经讲过了,此处不再赘述。EasyFlash是一款开源的轻量级嵌入式Flash存储器库,方便开发者更加轻松的实现基于Flash存储器的常见应用开发。非常适合智能家居、可穿戴、工控、医疗、物联网等需要断电存储功能的产品,资源占用极低,支持各种 MCU 片上存储器。
EasyFlash不仅能够实现对产品的 设定参数 或 运行日志 等信息的掉电保存功能,还封装了简洁的 增加、删除、修改及查询 方法, 降低了开发者对产品参数的处理难度,也保证了产品在后期升级时拥有更好的扩展性。让Flash变为NoSQL(非关系型数据库)模型的小型键值(Key-Value)存储数据库。
3.2EasyFlash软件包使用
打开ENV进入路径:RT-Thread online packages → tools packages → EasyFlash: Lightweight embedded flash memory library.
,选择软件包版本为最新版。
配置后退出ENV,同时使用pkgs --update
下载软件包,然后再使用scons --target=mdk5
重新生成MDK5文件
3.3 移植easyflash
下载完easyflash软件包后,我们复制.\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\packages\EasyFlash-latest\ports\ef_fal_port.c
到目录.\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\board\ports\easyflash\ef_fal_port.c
,双击打开该文件,完成以下修改:
// 修改 FAL_EF_PART_NAME 为 easyflash #define FAL_EF_PART_NAME "easyflash"
// 修改环境变量内容为 {"boot_times", "0"},这里我们先只设置一个开机次数 static const ef_env default_env_set[] = { {"boot_times", "0"}, };
3.4 编写Easyflash测试用例
/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-04-21 Wangyuqiang the first version */ #include "rtthread.h" #include "rtdevice.h" #include "board.h" #include "fal.h" #include <dfs_posix.h> #include "easyflash.h" #include <stdlib.h> #define FS_PARTITION_NAME "filesystem" #define BUF_SIZE 1024 static int fal_test(const char *partiton_name) { int ret; int i, j, len; uint8_t buf[BUF_SIZE]; const struct fal_flash_dev *flash_dev = RT_NULL; const struct fal_partition *partition = RT_NULL; if (!partiton_name) { rt_kprintf("Input param partition name is null!\n"); return -1; } partition = fal_partition_find(partiton_name); if (partition == RT_NULL) { rt_kprintf("Find partition (%s) failed!\n", partiton_name); ret = -1; return ret; } flash_dev = fal_flash_device_find(partition->flash_name); if (flash_dev == RT_NULL) { rt_kprintf("Find flash device (%s) failed!\n", partition->flash_name); ret = -1; return ret; } rt_kprintf("Flash device : %s " "Flash size : %dK \n" "Partition : %s " "Partition size: %dK\n", partition->flash_name, flash_dev->len/1024, partition->name, partition->len/1024); /* erase all partition */ ret = fal_partition_erase_all(partition); if (ret < 0) { rt_kprintf("Partition (%s) erase failed!\n", partition->name); ret = -1; return ret; } rt_kprintf("Erase (%s) partition finish!\n", partiton_name); /* read the specified partition and check data */ for (i = 0; i < partition->len;) { rt_memset(buf, 0x00, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_read(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) read failed!\n", partition->name); ret = -1; return ret; } for(j = 0; j < len; j++) { if (buf[j] != 0xFF) { rt_kprintf("The erase operation did not really succeed!\n"); ret = -1; return ret; } } i += len; } /* write 0x00 to the specified partition */ for (i = 0; i < partition->len;) { rt_memset(buf, 0x00, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_write(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) write failed!\n", partition->name); ret = -1; return ret; } i += len; } rt_kprintf("Write (%s) partition finish! Write size %d(%dK).\n", partiton_name, i, i/1024); /* read the specified partition and check data */ for (i = 0; i < partition->len;) { rt_memset(buf, 0xFF, BUF_SIZE); len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i); ret = fal_partition_read(partition, i, buf, len); if (ret < 0) { rt_kprintf("Partition (%s) read failed!\n", partition->name); ret = -1; return ret; } for(j = 0; j < len; j++) { if (buf[j] != 0x00) { rt_kprintf("The write operation did not really succeed!\n"); ret = -1; return ret; } } i += len; } ret = 0; return ret; } static void fal_sample(void) { /* 1- init */ fal_init(); if (fal_test("font") == 0) { rt_kprintf("Fal partition (%s) test success!\n", "font"); } else { rt_kprintf("Fal partition (%s) test failed!\n", "font"); } if (fal_test("download") == 0) { rt_kprintf("Fal partition (%s) test success!\n", "download"); } else { rt_kprintf("Fal partition (%s) test failed!\n", "download"); } } MSH_CMD_EXPORT(fal_sample, fal sample); static void fal_elmfat_sample(void) { int fd, size; struct statfs elm_stat; struct fal_blk_device *blk_dev; char str[] = "elmfat mount to W25Q flash.", buf[80]; /* fal init */ fal_init(); /* create block device */ blk_dev = (struct fal_blk_device *)fal_blk_device_create(FS_PARTITION_NAME); if(blk_dev == RT_NULL) rt_kprintf("Can't create a block device on '%s' partition.\n", FS_PARTITION_NAME); else rt_kprintf("Create a block device on the %s partition of flash successful.\n", FS_PARTITION_NAME); /* make a elmfat format filesystem */ if(dfs_mkfs("elm", FS_PARTITION_NAME) == 0) rt_kprintf("make elmfat filesystem success.\n"); /* mount elmfat file system to FS_PARTITION_NAME */ if(dfs_mount(FS_PARTITION_NAME, "/", "elm", 0, 0) == 0) rt_kprintf("elmfat filesystem mount success.\n"); /* Get elmfat file system statistics */ if(statfs("/", &elm_stat) == 0) rt_kprintf("elmfat filesystem block size: %d, total blocks: %d, free blocks: %d.\n", elm_stat.f_bsize, elm_stat.f_blocks, elm_stat.f_bfree); if(mkdir("/user", 0x777) == 0) rt_kprintf("make a directory: '/user'.\n"); rt_kprintf("Write string '%s' to /user/test.txt.\n", str); /* Open the file in create and read-write mode, create the file if it does not exist*/ fd = open("/user/test.txt", O_WRONLY | O_CREAT); if (fd >= 0) { if(write(fd, str, sizeof(str)) == sizeof(str)) rt_kprintf("Write data done.\n"); close(fd); } /* Open file in read-only mode */ fd = open("/user/test.txt", O_RDONLY); if (fd >= 0) { size = read(fd, buf, sizeof(buf)); close(fd); if(size == sizeof(str)) rt_kprintf("Read data from file test.txt(size: %d): %s \n", size, buf); } } MSH_CMD_EXPORT_ALIAS(fal_elmfat_sample, fal_elmfat,fal elmfat sample); static void easyflash_sample(void) { /* fal init */ fal_init(); /* easyflash init */ if(easyflash_init() == EF_NO_ERR) { uint32_t i_boot_times = NULL; char *c_old_boot_times, c_new_boot_times[11] = {0}; /* get the boot count number from Env */ c_old_boot_times = ef_get_env("boot_times"); /* get the boot count number failed */ if (c_old_boot_times == RT_NULL) c_old_boot_times[0] = '0'; i_boot_times = atol(c_old_boot_times); /* boot count +1 */ i_boot_times ++; rt_kprintf("===============================================\n"); rt_kprintf("The system now boot %d times\n", i_boot_times); rt_kprintf("===============================================\n"); /* interger to string */ sprintf(c_new_boot_times, "%d", i_boot_times); /* set and store the boot count number to Env */ ef_set_env("boot_times", c_new_boot_times); ef_save_env(); } } MSH_CMD_EXPORT(easyflash_sample, easyflash sample);
3.5 测试结果
打开串口助手,输入命令:
msh />easyflash_sample
第一次命令调用:
第二次RESET开发板后调用:
4.结语
至此本博客就到此结束,经历从移植软件模拟spi框架到LPC55S69,到移植过程中遇到不断的问题,到最后解决所有问题并提供应用示例,完成开发日记、开发笔记及应用教学,这个过程确实使我受益良多,其中感受最深的就是当然也更加感谢的是一些前辈们的指点迷津和博文记录,就目前国内嵌入式这个领域,相关开发经验相比较其他计算机行业确实有些不够包容和开放,也希望未来的朋友们能够怀揣着一颗求知及授学之心,共同建设好这个领域!