一、前言
学习记录,已建好工程,已经配置好FAL、SFUD、硬件SPI、W25Q128、EasyFlash。在Flash上使用FatFs文件系统。
二、步骤
一)配置RT-thread Settings
双击 “RT-Thread Settings”打开配置页面,添加组件FatFs。打开配置项,修改“设置要处理的最大扇区大小”为“4096”。
设置好后,图形配置界面会点亮这两个驱动。
二)配置工程
1、添加文件
若编译时缺少某些文件,可在软件左上角的“导航器”中选择项目,在“rt_thrread”->“components”文件夹中寻找并添加构建。
2、文件系统格式化和挂载
在之前建立的“W25Qxx.c”文件中添加文件系统格式化和挂载函数,并在fal初始化函数后进行调用。
/*********************************************************************************/
#include <dfs_fs.h>
#define DBG_TAG "FatFs"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define FS_PARTITION_NAME "datafile" //必须与分区表内设置的名称相同
int dfs_mount_init(void)
{
/* 在 spi flash 中名为 "datafile" 的分区上创建一个块设备 */
struct rt_device *flash_dev = fal_blk_device_create(FS_PARTITION_NAME);
if (flash_dev == NULL)
{
LOG_E("Can't create a block device on '%s' partition.", FS_PARTITION_NAME);
}
else
{
LOG_D("Create a block device on the %s partition of flash successful.", FS_PARTITION_NAME);
}
/* 挂载 spi flash 中名为 "datafile" 的分区上的文件系统 */
if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0)
{
LOG_I("Filesystem initialized!");
}
else
{
LOG_E("Failed to initialize filesystem !");
LOG_D("Create a filesystem on the block device !");
int res = dfs_mkfs("elm", flash_dev->parent.name); //格式化
if(res == 0)
{
LOG_D("Create success !");
LOG_D("reboot ... !");
rt_thread_delay(200);
NVIC_SystemReset(); //重启设备,由于已格式化,所以重启直接能够挂载成功
}
else
{
LOG_E("Create fail !");
}
}
return 0;
}
/*********************************************************************************/
注意宏“FS_PARTITION_NAME”必须与分区表内设置的名称相同,否则创建块设备时无法找到分区名。分区表一般在“fal_cfg.h”文件中。
此时编译下载程序,可以在打印出的调试信息中看到块设备创建成功,文件系统已经初始化。
3、测试功能
在main函数中新建2个线程,1个信号量。在线程1中打开文件并写入内容,若不存在则创建文件,超过最大长度后删除文件再重新创建,在线程2中打开文件,获取文件长度并打印文件全部内容。
fal_init(); //fal初始化
easyflash_init(); //easyflash初始化
dfs_mount_init(); //文件系统格式化和挂载
env_load(); //环境变量载入
test_sem1 = rt_sem_create("sem1", 0, RT_IPC_FLAG_FIFO);
rt_thread_t thread1 = rt_thread_create("write", (void *)G_Write_entry, RT_NULL, 2048, 25, 100);
if (thread1 != RT_NULL)
{
rt_thread_startup(thread1);
}
rt_thread_t thread2 = rt_thread_create("read", (void *)G_Read_entry, RT_NULL, 2048, 25, 10);
if (thread2 != RT_NULL)
{
rt_thread_startup(thread2);
}
/*********************************************************************************/
void G_Write_entry(void)
{
char chartemp[15] = "file.txt";
char l_DataBuf_i8[100] = "";
uint8_t l_DataBuf_u8[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
// int data1 = 20;
// int data2 = 11;
int fd = 0;
while(1)
{
// rt_memset(chartemp, 0, sizeof(chartemp));
// itoa(++data1, chartemp, 10);
// ef_set_env("testdata1", chartemp); //存入env中
// LOG_I("write testdata1: %d", data1);
fd = open(chartemp, O_RDWR); //打开文件,成功则返回文件描述符,失败返回-1
if(fd < 0)
{
LOG_E("write/ File: '%s' not open! err %d.", chartemp, fd);
fd = open(chartemp, O_RDWR | O_CREAT); //新建文件
LOG_D("write/ create file : %s", chartemp);
}
int l_FileLen = lseek(fd, 0, SEEK_END); //获取文件长度
LOG_D("write/ file len : %d", l_FileLen);
if(l_FileLen >= 100)
{
LOG_W("File: '%s' is full !", chartemp);
close(fd); //关闭文件
rm(chartemp); //清除文件
fd = open(chartemp, O_RDWR | O_CREAT); //新建文件
LOG_D("create file : %s", chartemp);
}
if(fd > 0)
{
LOG_I("write/ open file succ.");
lseek(fd, 0, SEEK_END); //将指针置到文件尾
l_DataBuf_u8[0]++;
rt_memset(l_DataBuf_i8, 0, 100);
sprintf(l_DataBuf_i8, "%03d,%03d,%03d,%03d,%03d\r\n",\
l_DataBuf_u8[0],l_DataBuf_u8[1],l_DataBuf_u8[2],l_DataBuf_u8[3],l_DataBuf_u8[4]);
write(fd, l_DataBuf_i8, strlen(l_DataBuf_i8)); //写入文件,长度3 * 5 + 4 + 2 = 21
LOG_D("file write : %s.", l_DataBuf_i8);
LOG_I("file write succ.");
}
close(fd); //关闭文件
rt_sem_release(test_sem1);
rt_thread_delay(2000);
}
}
void G_Read_entry(void)
{
char chartemp[15] = "file.txt";
char l_DataBuf_i8[200] = "";
int fd = 0;
while(1)
{
rt_sem_take(test_sem1, RT_WAITING_FOREVER);
fd = open(chartemp, O_RDONLY); //打开文件,成功则返回文件描述符,失败返回-1
if(fd > 0)
{
int l_FileLen = lseek(fd, 0, SEEK_END); //获取文件长度
LOG_D("read/ file len : %d", l_FileLen);
rt_memset(l_DataBuf_i8, 0, 200);
lseek(fd, 0, SEEK_SET); //将指针移动到文件头
int l_ReadResult = read(fd, l_DataBuf_i8, l_FileLen); //读取文件内全部内容
if(l_ReadResult > 0) //成功
{
LOG_D("read/ file data : \r\n%s.", l_DataBuf_i8);
}
else
{
LOG_W("read file fail ! err : %d", l_ReadResult);
}
}
else
{
LOG_E("read/ open file fail ! err : %d", fd);
}
close(fd); //关闭文件
rt_thread_delay(50);
}
}
/*********************************************************************************/
编译下载后,可以看到线程1可以创建打开删除文件并写入内容,线程2可以获取文件长度并打印文件全部内容。因为创建或写入文件时需要获取时间,但工程未开启RTC,所以会打印警告。
三、工程代码
https://gitee.com/chongwang1013/stm32-l431_-test1.0/tree/FatFs/