RT-Thread Studio 外部flash挂载虚拟文件系统笔记

使用ATK-NANO STM32F411的开发板,实现外部flash挂载虚拟文件系统。
本文最终工程下载

参考基于 RT-Thread Studio 的 SPI 驱动开发文档,基于自己使用的芯片,创建空工程,实现hello world。

虽然rt-thread将hal库的接口驱动都放在了C:\RT-ThreadStudio\download\rt-thread-sdk\rt-thread-src\v4.0.2\bsp\stm32\libraries\HAL_Drivers目录下,但是该目录下的spi驱动最后更新日志都是2018年的,而且其中还有关于dma相关的配置;对于上手flash挂载虚拟文件系统,我们是不需要这些东西的。

所以可以直接在本地drivers目录下创建相应的drv_spi.cdrv_spi.h的空文件,再去github复制drv_spi.cdrv_spi.h中的内容到本地。

根据硬件设计原理图,知道使用的是SPI2接口:
在文件drivers/board.c中,添加使用SPI2的宏定义#define BSP_USING_SPI2
在文件drivers/stm32f4xx_hal_conf.h中,解注释#define HAL_SPI_MODULE_ENABLED以启用spi相关的函数。
此时编译应该是没有错误的。

drv_spi.c最后面,添加使用cubeMX生成的驱动代码:


void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(hspi->Instance == SPI2)
    {
        __HAL_RCC_SPI2_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();

        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_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
}

int rt_hw_spi_init(void)
{
    rt_hw_spi_bus_register(SPI2, "spi2");
    return 0;
}
INIT_BOARD_EXPORT(rt_hw_spi_init);

注意!!!!
这里的HAL_SPI_MspInit强烈建议根据自己的硬件电路设计从CubeMX生成!!!
因为对于使用标准库在STM32F103进行开发的时候(一般不使用重映射),我们习惯修改相应的引脚、GPIO时钟、总线时钟、总线名这些,一般就修改完了,但转到HAL库,我们极有可能会忽视一个变量:GPIO_InitStruct.Alternate
举个例子,我这里使用的是SPI2(PB13、PB14、PB15),如果你用的是使用的SPI3(PB3、PB4、PB5),那么除了需要修改引脚编号,把所有的SPI2改成SPI3,GPIO_InitStruct.Alternate也从GPIO_AF5_SPI2改成了GPIO_AF5_SPI3,但查看其宏定义,我们使用的还是AF5的功能!
在这里插入图片描述
而PB3、PB4、PB5的AF5复用实际上是SPI1,而不是SPI3!!!
参考数据手册,可以看到:
在这里插入图片描述
所以此时从代码整体上来看,我们会觉得没有问题,但实际上在SPI3总线上读不出来数据(因为引脚功能没复用到SPI3上去),虽然复用到了SPI1总线上,但由于没开SPI1的时钟,所以SPI1上也抓不到波形。

驱动配置完成后,就是软件层面的注册。
新建dfs_port.c文件,添加初始化相关的内容:

#include <rtthread.h>
#include <rtdevice.h>
#include "drv_spi.h"

static int rt_hw_spi_flash_init()
{
    __HAL_RCC_GPIOB_CLK_ENABLE();
    rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);
    if (NULL == rt_sfud_flash_probe("W25Q16", "spi20"))
    {
        rt_kprintf("spi flash probe failed!\n");
    }
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);

上述函数中rt_hw_spi_device_attach实现了spi20设备的注册(即我们可以通过对spi20这个名字访问W25Q16设备),而rt_sfud_flash_probe实现了W25Q16设备的解析(通过读取sfud信息,知道了它是一个spi flash设备,知道了它的容量,擦写大小那些),并把它挂载成一个块设备(Block Device),可直接以块为单位进行数据读写。
在这里插入图片描述
然后就是挂载文件管理系统:

static int mnt_init()
{
    //mkfs("elm", "W25Q16");
    if (dfs_mount("W25Q16", "/", "elm", 0, 0) == 0)
    {
        //rt_kprintf("dfs mount ok\n");
    }
    else
    {
        rt_kprintf("dfs mount failed\n");
    }
}
INIT_ENV_EXPORT(mnt_init);

对于一个存储设备,肯定有相应的文件系统,比如windows用的ntfs,linux使用的ext4,同时还有一个方比较小巧适合嵌入式设备使用的FAT32文件系统,这里的dfs_mount("spi20", "/", "elm", 0, 0)就实现了文件系统的挂载,其中elm代表的就是FAT32文件系统。
挂载文件系统的过程中,可能会出现以下提示:
The sector size of device is greater than the sector size of FAT.
在这里插入图片描述
这是因为实际设备中扇区的大小比文件系统的大小还要大。
工程目录\rt-thread\components\drivers\spi\sfud\inc\sfud_flash_def.h中,SFUD_FLASH_CHIP_TABLE定义了使用的W25Q16设备的扇区大小为4096(这个table是根据数据手册写的,所以不能改这里),那么需要修改工程中关于文件系统的参数:
在这里插入图片描述
如果还是格式化失败,可能是因为存储器设备没有FAT32文件系统的描述信息,可以使用mkfs("elm", "W25Q16");将设备重新格式化成FAT32格式。
此时可以使用ls指令查看文件系统下的文件,使用echo往文件写入字符串,使用cat查看文件内容:
在这里插入图片描述
至此,文件系统挂载完成。

发布了339 篇原创文章 · 获赞 78 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/qq_27508477/article/details/104898074