RTthread挂载外部Flash W25Q64并加入FATFS文件系统

     之前尝试移植FATFS以及在cubemx上使用FATFS组件但都失败了,痛苦了两星期,最近尝试用RTthread Studio对FATFS进行移植,发现过程还是很顺利的,因此决定记录一下:

硬件:正点原子miniV3.0开发板

软件:RTthread Studio

步骤按照这里的来就可以了:

4.RT-thread 项目实战--fatfs文件系统移植_rtthread fatfs-CSDN博客

我的由于是W25q64,程序有点不一样,如下:

#include "drv_spi.h"
#include "spi_flash_sfud.h"
#include "dfs_fs.h"
#include <dfs_posix.h>
#include <BSP_w25q64.h>

static int rt_hw_spi_flash_init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
    rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_2);// spi10 表示挂载在 spi1总线上的 0 号设备,PA2是片选,这一步就可以将从设备挂在到总线中。
    if (RT_NULL == rt_sfud_flash_probe("W25Q64", "spi10"))  //注册块设备,这一步可以将外部 flash抽象为系统的块设备
    {
        return -RT_ERROR;
    };

    return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);



int dfs_mount_init(void)
{
    dfs_mkfs("elm","W25Q64");
    if(dfs_mount("W25Q64", "/","elm",0,0) == 0)  //注册块设备,这一步可以将外部flash抽象为系统的块设备
    {
        return -RT_ERROR;
    }
    return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(dfs_mount_init);

这里说一下如果打印串口报如下错误的解决方法:

Warning: Read SFDP parameter header information failed. The W25Q64 is not support JEDEC SFDP.[0m
[32m[I/SFUD] Warning: This flash device is not found or not support.[0m
[32m[I/SFUD] Error: W25Q64 flash device is initialize fail.[0m
[31m[E/SFUD] ERROR: SPI flash probe failed by SPI device spi10.[0m

   这个说明RTthread的SFUD 组件在尝试初始化和识别 W25Q64 设备时遇到了问题,特别是与 JEDEC SFDP(Serial Flash Discoverable Parameters)相关的参数读取失败。这可能导致 SFUD 无法正确识别和初始化该 SPI Flash 设备。我一开始以为是W25Q64 设备不支持支持 SFDP。如果设备不支持 SFDP,就需要手动配置设备的参数,但是百度了一下是支持的,然后我就在RTthread里的cubemx中把片选引脚CS即PA2也初始化了,然后再次生成代码就可以了;(有个问题就是后面再取消cubemx的PA2初始化,生成代码后,仍然可以正常使用FATFS)

测试代码如下:

BSP_w25q64.c

// 测试文件操作
void test_file_operations(void)
{
   const char *dir_path = "/Test";

    // 创建并写入文件1
   create_and_write_file(FILE1_PATH, "This is file 1.\n");
   // 创建并写入文件2
   create_and_write_file(FILE2_PATH, "This is file 2.\n");

   // 读取文件1的内容
   read_file_content(FILE1_PATH);
   // 读取文件2的内容
   read_file_content(FILE2_PATH);

   //在根目录下创建一个文件夹Test
   create_folder(dir_path);
   // 创建并写入文件3
   create_and_write_file(FILE3_PATH, "This is file 3.\n");
   // 读取文件3的内容
   read_file_content(FILE3_PATH);
}



// 创建并写入文件
static void create_and_write_file(const char *file_path, const char *content)
{
    int fd;
    int bytes_written;

    // 打开文件,如果文件不存在则创建,如果文件存在则截断文件长度为0
    fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC);
    if (fd < 0)
    {
        rt_kprintf("Failed to open file for writing: %s\n", file_path);
        return;
    }

    // 写入文件
    bytes_written = write(fd, content, strlen(content));
    if (bytes_written < 0)
    {
        rt_kprintf("Failed to write to file: %s\n", file_path);
    }
    else
    {
        rt_kprintf("Wrote %d bytes to file: %s\n", bytes_written, file_path);
    }

    // 关闭文件
    close(fd);


}

// 读取文件内容
static void read_file_content(const char *file_path)
{
    int fd;
    char read_buffer[64];
    int bytes_read;

    // 打开文件
    fd = open(file_path, O_RDONLY);
    if (fd < 0)
    {
        rt_kprintf("Failed to open file for reading: %s\n", file_path);
        return;
    }

    // 读取文件内容
    //最多只能读sizeof(read_buffer) - 1是因为当数据超过sizeof(read_buffer) - 1大小时,read_buffer还能有一字节空间放'\0'
    bytes_read = read(fd, read_buffer, sizeof(read_buffer) - 1);
    if (bytes_read < 0)
    {
        rt_kprintf("Failed to read from file: %s\n", file_path);
    }
    else
    {
        read_buffer[bytes_read] = '\0'; // Null-terminate the string
        rt_kprintf("Read %d bytes from file: %s\n", bytes_read, file_path);
        rt_kprintf("File content: %s\n", read_buffer);
    }

    // 关闭文件
    close(fd);
}

// 创建新文件夹
int create_folder(const char *folder_path)
{

    if (mkdir(folder_path, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
    {
        rt_kprintf("Folder created successfully: %s\n", folder_path);
        return 0; // 成功返回 0
    }
    else
    {
        rt_kprintf("Failed to create folder: %s\n", folder_path);
        return -1; // 失败返回 -1
    }
}

BSP_w25q64.h

#ifndef BSP_BSP_W25Q64_H_
#define BSP_BSP_W25Q64_H_

#define FILE1_PATH "/file1.txt"
#define FILE2_PATH "/file2.txt"
#define FILE3_PATH "/Test/file3.txt"

void test_file_operations(void);

static void create_and_write_file(const char *file_path, const char *content);
static void read_file_content(const char *file_path);
int create_folder(const char *folder_path);

#endif /* BSP_BSP_W25Q64_H_ */

测试结果如下:

参考文章:4.RT-thread 项目实战--fatfs文件系统移植_rtthread fatfs-CSDN博客

### 如何在 QSPI 上挂载文件系统 对于 STM32F429 芯片而言,由于其不具备 QSPI 接口,在此场景下讨论如何通过 QSPI 挂载文件系统的常规流程仍具有指导意义。通常情况下,实现这一目标涉及几个重要环节。 #### 初始化外部 Flash 设备注册为块设备 首先需初始化 W25Q256 这样的外部 Flash 设备,将其注册成为 RT-Thread 中的块设备。尽管当前环境下的硬件不支持 QSPI 功能,但概念上相似的操作仍然适用。这一步骤确保了后续可以像访问磁盘一样来管理这块存储介质上的数据[^1]。 ```c #include "rtthread.h" #include "dfs_fs.h" // 假设已经完成对 W25Q256 的初始化以及作为块设备的注册过程 static struct rt_device *flash_dev; int main(void) { // 注册完成后获取该设备指针用于下一步操作 flash_dev = rt_device_find("w25q256"); if (!flash_dev) { rt_kprintf("Find w25q256 device failed.\n"); return -RT_ERROR; } } ``` #### 创建分区表与格式化 接着创建适合 ELM FATFS 文件系统的分区结构,对该区域执行格式化命令。即使是在不直接依赖 QSPI 接口的情况下,这些步骤也是必要的前置条件之一,以便能够顺利地构建起完整的文件系统框架。 ```bash # 使用 dfmkpart 工具定义新分区 (假设已安装相应工具链) dfmkpart /dev/w25q256 0x08000000 0x02000000 fatfs rootfs # 对指定位置进行格式化处理 mkfs.fat -F 32 /dev/w25q256p1 ``` #### 安装加载文件系统模块 最后则是将准备好的分区正式加入到操作系统内核当中去,使之成为一个可被应用程序所使用的标准路径节点。这里需要注意的是具体 API 或者配置项可能会依据不同版本有所差异,请参照最新官方文档说明来进行调整。 ```c if (dfs_mount("/dev/w25q256", "/", "elm", 0, 0) != RT_EOK){ rt_kprintf("Mount filesystem failed\n"); } else { rt_kprintf("File system mounted successfully!\n"); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值