RT-thread SPI SFUD读写W25Q128

本文档详细介绍了如何在STM32F091CC微控制器上使用RT-Thread Studio 2.2.1 IDE配置SPI2总线,并通过SFUD库进行W25Q128 SPI Flash的读写操作。首先,通过HAL库初始化SPI2的GPIO和时钟,然后挂载SPI Flash到SPI2总线,并使用RT-Thread的SPI驱动读取Flash的ID。接着,展示了使用SFUD库进行数据的写入和读取,提供了一种高效且可靠的SPI Flash操作方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

MCU:STM32F091CC
IDE:RT-Thread Studio 2.2.1
IO对应关系(SPI2):

功能IO
MISOPB14
MOSIPB15
SCKPB13
CSPB12

参考资料:
1.RTT官方SPI文档
2.在潘多拉上使用 SFUD 操作 Flash


一、SFUD 是什么?

SFUD (Serial Flash Universal Driver) 是一款开源的串行 SPI Flash 通用驱动库。

二、使用步骤

1.添加SPI2总线

  • 打开SPI及SFUD的驱动框架
    在这里插入图片描述
  • 在Board.h中定义SPI使用
    在这里插入图片描述
  • 在stm32f0xx_hal_conf.h中打开 HAL 库对 SPI 的支持
    在这里插入图片描述
  • 初始化IO及时钟
    使用CubeMX生成HAL_SPI_MspInit(),并将其复制到board.c中。
    备注:NSS使用软件控制。
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }
}
  • 下载运行
  • 可以看到SPI2添加成功了。
    在这里插入图片描述

2.W25Q128读写操作

  • 挂载 SPI FLASH W25Q128 到 SPI 总线:
static int rt_hw_spi_flash_init(void)
{
    __HAL_RCC_GPIOB_CLK_ENABLE();
    rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);

    if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi20"))
    {
        return -RT_ERROR;
    };

    return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
  • 读取 SPI FLASH W25Q128的ID :
#define W25Q_SPI_DEVICE_NAME     "spi20"

static void spi_w25q_sample(int argc, char *argv[])
{
    struct rt_spi_device *spi_dev_w25q;
    char name[RT_NAME_MAX];
    rt_uint8_t w25x_read_id = 0x90;
    rt_uint8_t id[5] = {0};

    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX);
    }

    /* 查找 spi 设备获取设备句柄 */
    spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name);
    if (!spi_dev_w25q)
    {
        rt_kprintf("spi sample run failed! can't find %s device!\n", name);
    }
    else
    {
        /* 方式1:使用 rt_spi_send_then_recv()发送命令读取ID */
        rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5);
        rt_kprintf("use rt_spi_send_then_recv() read w25q ID is:%x%x\n", id[3], id[4]);

        /* 方式2:使用 rt_spi_transfer_message()发送命令读取ID */
        struct rt_spi_message msg1, msg2;

        msg1.send_buf   = &w25x_read_id;
        msg1.recv_buf   = RT_NULL;
        msg1.length     = 1;
        msg1.cs_take    = 1;
        msg1.cs_release = 0;
        msg1.next       = &msg2;

        msg2.send_buf   = RT_NULL;
        msg2.recv_buf   = id;
        msg2.length     = 5;
        msg2.cs_take    = 0;
        msg2.cs_release = 1;
        msg2.next       = RT_NULL;

        rt_spi_transfer_message(spi_dev_w25q, &msg1);
        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]);

    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample);

读取成功如图
在这里插入图片描述

  • 使用SFUD写/读 W25Q128 :
#include "spi_flash.h"
#include "./sfud/inc/sfud.h"

static void spi_w25q_sf_sample(int argc, char *argv[])
{
    uint8_t *read_data;  // 读取到的数据
    uint8_t *write_data; // 将要写入的数据
    sfud_flash *sfud_dev = NULL;
    sfud_err ret;
    sfud_dev = rt_sfud_flash_find("spi20"); // 获取 sfud_dev
    // 或者 sfud_dev = rt_sfud_flash_find_by_dev_name("W25Q128");

    write_data = rt_malloc(32);
    rt_memset(write_data, '1', 32);
    ret = sfud_erase_write(sfud_dev, 0, 32, write_data); // 将数据 32 字节的 write_data 从 0 开始写入 flash
    if(ret == SFUD_SUCCESS)
    {
        rt_kprintf("sfud write data at 0 is:%s\n", write_data);
    }
    else
    {
        rt_kprintf("sfud write data failed\n");
    }
    read_data = rt_malloc(32);
    ret = sfud_read(sfud_dev, 0, 32, read_data);   // 读取从 0 开始的 32 字节,存入 read_data
    if(ret == SFUD_SUCCESS)
    {
        rt_kprintf("sfud read data at 0 is:%s\n", read_data);
    }
    else
    {
        rt_kprintf("sfud read data failed\n");
    }

}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(spi_w25q_sf_sample, spi w25q sf sample);

在这里插入图片描述


<think>嗯,用户想了解如何在RT-Thread中使用FAL组件与W25Q128闪存芯片进行交互。首先,我需要回忆一下FAL组件的基本概念。FAL(Flash Abstraction Layer)是RT-Thread中的一个抽象层,用于统一管理不同类型的Flash设备,包括片内Flash和片外SPI Flash。这样开发者可以通过统一的API进行读写操作,而不需要关心底层硬件的差异。 接下来,用户提到W25Q128,这是一款SPI接口的NOR Flash芯片,容量为16MB。使用它需要先通过SPI总线将其注册到RT-Thread的设备框架中。根据引用3的内容,用户需要编写初始化代码,使用SPI设备框架将W25Q128挂载到SPI总线上。这部分代码通常包括启用GPIO时钟、注册SPI设备,并通过rt_sfud_flash_probe函数探测设备。INIT_COMPONENT_EXPORT宏确保初始化函数在系统启动时自动执行。 然后,配置FAL组件。根据引用2,用户需要在工程中添加porting文件夹,并修改fal_cfg.h文件来定义Flash分区。对于STM32F407,可能需要同时配置片内Flash和W25Q128。每个分区需要指定名称、起始地址、大小以及所属的Flash设备。例如,片内Flash可能命名为"stm32_onchip",而W25Q128的分区可能命名为"filesystem"。 接下来,用户需要初始化FAL组件并调用fal_init()。之后,就可以使用FAL提供的API,如fal_partition_find()获取分区句柄,fal_partition_read()和fal_partition_write()进行读写操作。如果用户需要使用文件系统,还需要将分区挂载到elm或LittleFS,这通常通过DFS和MTD层来实现。 可能遇到的问题包括SPI设备初始化失败,需要检查硬件连接是否正确,SPI配置参数是否匹配W25Q128的规格。另外,分区配置错误可能导致读写异常,需要仔细检查fal_cfg.h中的地址和大小设置。用户可能还需要参考RT-Thread的文档和示例代码,确保所有步骤正确无误。 总结步骤:硬件连接、SPI设备注册、FAL配置、API使用。需要确保每个环节都正确配置,特别是SPI的引脚和时钟初始化,以及FAL分区的正确划分。此外,提供示例代码和参考链接能帮助用户更好地理解和实践。</think>### RT-Thread FAL组件与W25Q128交互教程 #### 一、硬件准备与驱动配置 1. **SPI设备挂载** 需通过RT-Thread SPI框架注册W25Q128设备,参考代码片段如下: ```c static int rt_hw_spi_flash_init(void) { __HAL_RCC_GPIOC_CLK_ENABLE(); // 启用SPI片选引脚时钟 rt_hw_spi_device_attach("spi1", "spi10", GPIOC, GPIO_PIN_0); // 挂载SPI设备 if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10")) { // 探测Flash设备 return -RT_ERROR; } return RT_EOK; } INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init); // 自动初始化 ``` 此代码将W25Q128注册为名为`W25Q128`的块设备[^3]。 2. **FAL组件移植** - 在工程中添加`porting`文件夹,包含`fal_cfg.h`配置文件 - 定义Flash设备表与分区表(示例): ```c /* fal_cfg.h */ static const fal_partition_t _fal_partitions[] = { /* 片内Flash */ {FAL_PART_MAGIC_WORD, "boot", "stm32_onchip", 0x08000000, 64*1024, 0}, {FAL_PART_MAGIC_WORD, "app", "stm32_onchip", 0x08010000, 512*1024, 0}, /* W25Q128分区 */ {FAL_PART_MAGIC_WORD, "param", "W25Q128", 0x00000000, 256*1024, 0}, {FAL_PART_MAGIC_WORD, "filesystem", "W25Q128", 0x00040000, 14*1024*1024, 0} }; ``` 此处`W25Q128`对应驱动注册的设备名[^2]。 #### 二、FAL组件初始化与API使用 1. **初始化流程** ```c #include <fal.h> int main(void) { fal_init(); // 初始化FAL组件 /* 后续操作... */ } ``` 2. **读写操作示例** ```c #define BUFFER_SIZE 256 void flash_ops_demo(void) { const struct fal_partition *fs_part = fal_partition_find("filesystem"); uint8_t write_buf[BUFFER_SIZE] = {0xA5}; uint8_t read_buf[BUFFER_SIZE]; /* 擦除->写入->读取验证 */ fal_partition_erase(fs_part, 0, BUFFER_SIZE); fal_partition_write(fs_part, 0, write_buf, BUFFER_SIZE); fal_partition_read(fs_part, 0, read_buf, BUFFER_SIZE); } ``` #### 三、文件系统集成(可选) 若需挂载文件系统到W25Q128: ```c #include <dfs_fs.h> int mnt_init(void) { if (dfs_mount("filesystem", "/", "elm", 0, 0) == 0) { rt_kprintf("Flash文件系统挂载成功\n"); } return RT_EOK; } INIT_ENV_EXPORT(mnt_init); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值