文章目录
一、创建基本工程
二、配置RT-Thread Setting
三、挂载文件系统
四、实现ulog文件后端
前言
本文是文件系统挂载到 SPI FLASH上,实现ulog文件后端
需要提前将SPI FLASH挂载成功
SPI FLASH 采用的是W25Q64
一、请参考RT-Thread Studio官方文档的创建工程流程
二、配置RT-Thread Setting
①设置日志
尽量把异步输出线程的栈大小设置大一点,因为有可能会出现栈溢出
②设置文件系统
- 文件的最大数目根据自己的需求来决定
- 处理的最大扇区大小要根据自己使用的是flash还是sd卡来决定,因为我使用的是W25Q64
最小擦除为一个扇区的大小,扇区为4096
三、挂载文件系统到SPI FLASH,(第一次挂载的话,需要对SPI FLASH进行格式化,否则可能挂载不成功)
先需要抽象SPI FLASH
/* SPI 设备初始化注册,此函数由系统自动调用 */
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
/* spi10 表示挂载在 spi1 总线上的 0 号设备,PC0是片选,这一步就可以将从设备挂在到总线中。 */
rt_hw_spi_device_attach(SPI_BUS_NAME, W25Q64_SPI_DEVICE_NAME, GPIOC, GPIO_PIN_0);
/* 注册块设备,这一步可以将外部flash抽象为系统的块设备 */
if (RT_NULL == rt_sfud_flash_probe(W25Q64_BLOCK_DEVICE_NAME, W25Q64_SPI_DEVICE_NAME));
{
return -RT_ERROR;
};
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
/**
* 格式化SPI FLASH
*/
void formatting_device()
{
/* 格式化块设备 */
int err_result;
err_result = dfs_mkfs("elm", W25Q64_BLOCK_DEVICE_NAME);
if(err_result == 1)
{
rt_kprintf("dfs_mkfs is failure\n");
}
}
/**
* 挂载文件系统到SPI FLASH
* @param parameter
*/
void spi_flash_mount(void *parameter)
{
formatting_device();
/* 挂载文件系统 */
rt_thread_mdelay(500);
if(rt_device_find(W25Q64_SPI_DEVICE_NAME) != RT_NULL)
{
if (dfs_mount(W25Q64_BLOCK_DEVICE_NAME, "/", "elm", 0, 0) == RT_EOK)
{
rt_kprintf("spi flash mount to success\n");
}
else
{ rt_kprintf("spi flash mount to failed\n");
}
}
}
INIT_ENV_EXPORT(spi_flash_mount);
四、创建一个.c文件用来实现ulog文件后端,可以参考RT-Thread官方ulog组件后端的实现方法
/* 创建文件后端 */
static struct ulog_backend ulog_fat_file;
/* 文件后端初始化 */
int ulog_fat_file_backend_init(void)
{
ulog_fat_file.output = ulog_fat_file_backend_output;
ulog_backend_register(&ulog_fat_file, ULOG_FILE_BE_NAME, RT_FALSE);
return 0;
}
INIT_APP_EXPORT(ulog_fat_file_backend_init);
/**
* 后端输出函数
* */
static void ulog_fat_file_backend_output(struct ulog_backend *backend, rt_uint32_t level,
const char *tag, rt_bool_t is_raw, const char *log, size_t len)
{
1.根据文件系统提供的open函数
int open(const char *file, int flags, ...);
该函数可以创建一个文件,用来存放项目输出的日志
2.根据文件系统提供的write函数
int write(int fd, const void *buf, size_t len);
该函数可以向创建好的文件中写入输出的日志
}
注意:我最开始使用文件系统的时候也踩了很多的坑,我给大家列几点,可以稍微给大家提个醒
1.创建文件成功后,open函数会返回一个文件描述符 fd 这个东西非常重要,因为write函数就需要用到这个 fd
,一般第一个文件描述符的值是 3 (我也不知道为啥是3),然后如果创建打开了一个文件又继续创建下一个文件的话
fd 的值就会发生改变,一般在前一个fd的值前 +1 ,但是如果关闭了上一个文件,继续创建下一个文件的时候,下
一个文件的 fd 就和上一个文件的 fd相同
2.不要同时向几个文件写入日志,因为会导致文件里的内容会有缺失
3.如果需要读取文件的偏移量(每个文件的偏移量为 260)
/**
* 读取logs目录下文件的偏移量
*/
long read_pos()
{
struct dirent *d;
DIR *auto_em;
/* 获取文件偏移量 */
long Position_offset;
/* 首先读取logs目录 */
auto_em = opendir("/logs");
if(auto_em == RT_NULL)
{
rt_kprintf("open directory error!\n");
}
else
{
while ((d = readdir(auto_em)) != RT_NULL);
/* 每个文件的偏移量为 260 */
Position_offset = telldir(auto_em);
rt_kprintf("Position_offset = %ld\n",Position_offset);
}
return Position_offset;
}
MSH_CMD_EXPORT(read_pos,XXXX);
4.可以参考一下RT-Thread组件里大神上传的ulog文件系统后端的实现
谢谢!!