当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]使用SD卡将文件拷贝到QSPI FLASH(采用fatfs文件系统)

今天是过年放假的第一天(一共16天年假),但是说实话放不放假对我们做技术的人来说有放跟没放其实区别不大,因为自驱力是我们维持自身实力和饭碗的根本,16天的假期可以做很多事情学不少东西了,唯一的区别是终于可以好好睡个觉了,然后睡醒接着干就完了!想着小熊派板子上带了一个QSPI,有8MB的存储空间,那可不能浪费了呀!之前写的那些开源项目的图片资源其实放在这上面的,如何实现呢?方法如下:

  • 使用SD卡将文件拷贝到QSPI FLASH(采用fatfs文件系统)
  • 写一个QSPI FLASH MDK下载算法,直接将图片数据放在主程序中

接下来进入正文:

小熊派上自带了一个QSPI接口的8M大小的SPI_FLASH,如下图所示:

小熊派官方也提供了驱动编写的视频教程以及代码编写例程,关于怎么实现的,这里就不多说了,如果想详细了解原理,可以看看世伟兄以及小熊派之前写的文章:

STM32Cube-18 | 使用QSPI读写SPI Flash(W25Q64)

单片机基础 —— 使用QSPI读写SPI Flash(W25Q64)

今天我们主要来讲解下Fatfs系统功能的配置,在进入正题之前,我已经按上面的教程将QSPI Flash正常驱动起来了,接下来进入主题,如下图所示:

中间件的地方选择fatfs,然后再Mode处选择User-defined,因为这个不是官方默认支持的,需要用户自己去实现Fatfs关于底层的驱动接口。

1、功能参数配置

其中,关于功能参数的配置,主要是用到了才去配置,不用到的选项默认就行了,这部分请参考ST官网有关STM32cube Fatfs的应用开发文档,如下所示:

2、几个重要参数配置说明

CODE PAGE这个选项主要是提供编码格式的支持,根据个人需求配置,这里配置为简体中文:

USE_LFN这个选项主要是为了支持长文件名,并且当需要支持这个功能的时候需要提供缓存区存放,fatfs提供了BSS、STACK、HEAP三种方式。

根据个人需求选择存放在STACK中,因为存放在BSS上,则是带有静态工作缓冲区的LFN,不能进行动态分配,而存放在HEP上,则需要重写实现fatfs提供的ff_memalloc和ff_memfree函数,所以一般情况下就把它放在栈区即可。

MAX_SS这个选项配置为4096,为什么要配置为4096呢?请看W25Q64的手册描述:

如上,W25Q64这款芯片的最小擦除单位是4KB,也就是4096字节,为了提高擦写效率,一般情况下就直接写4096。

其余的参数用到的时候再去做进一步的配置,均系统默认即可。

由于对长文件名做了支持,缓存区是在栈区的,所以把堆栈加大一些,自己喜欢就好,只要不溢出就行,根据个人习惯随便填了两个参数,然后生成代码工程。

3、Fatfs驱动QSPI接口实现

对于fatfs,ST官方多封装了一层抽象接口给用户进行填写函数,这个文件是:user_diskio.c,主要提供了如下给用户编写的接口:

Diskio_drvTypeDef  USER_Driver =
{
  USER_initialize,  //初始化驱动盘
  USER_status,      //获取硬盘状态函数
  USER_read,        //读磁盘 #if  _USE_WRITE  USER_write,       //写磁盘 #endif  /* _USE_WRITE == 1 */ #if  _USE_IOCTL == 1 USER_ioctl,       //I/O操作 #endif /* _USE_IOCTL == 1 */ };

以上这些函数直接操作的就是以下fatfs原生的接口:

接下来我们需要依次实现它们:

初始化磁盘实现:

DSTATUS USER_initialize (
 BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
  /* USER CODE BEGIN INIT */
  uint32_t id ;
    id = hal_spi_flash_get_id(); if(0xEF4017 == id)
  { printf("读取ID:0x%x\n",id); return RES_OK;
  } else return RES_ERROR ;
  /* USER CODE END INIT */
}

磁盘状态函数实现(可以留空):

/**
  * @brief  Gets Disk Status
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status (
 BYTE pdrv       /* Physical drive number to identify the drive */
)
{
  /* USER CODE BEGIN STATUS */ return RES_OK;
  /* USER CODE END STATUS */
}

读磁盘函数实现:

/**
  * @brief  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_read (
 BYTE pdrv,      /* Physical drive nmuber to identify the drive */
 BYTE *buff,     /* Data buffer to store read data */
 DWORD sector,   /* Sector address in LBA */
 UINT count      /* Number of sectors to read */
)
{
  /* USER CODE BEGIN READ */
    // 以4K字节为单位
    hal_spi_flash_read(buff, count << 12, sector << 12); return RES_OK;
  /* USER CODE END READ */
}

写磁盘函数实现:

SPI_FLASH的特性,需要先擦除后写入。

/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */ #if _USE_WRITE == 1 DRESULT USER_write (
 BYTE pdrv,          /* Physical drive nmuber to identify the drive */
 const BYTE *buff,   /* Data to be written */
 DWORD sector,       /* Sector address in LBA */
 UINT count          /* Number of sectors to write */
)
{
  /* USER CODE BEGIN WRITE */
    /* USER CODE HERE */
    uint32_t write_addr;
    write_addr = sector << 12; // 以4K字节为单位 hal_spi_flash_erase_write((uint8_t *)buff, count << 12, write_addr); return RES_OK;
  /* USER CODE END WRITE */
} #endif /* _USE_WRITE == 1 */ 

磁盘命令操作实现:

/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */ #if _USE_IOCTL == 1 DRESULT USER_ioctl (
 BYTE pdrv,      /* Physical drive nmuber (0..) */
 BYTE cmd,       /* Control code */
 void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    switch (cmd)
    { case GET_SECTOR_COUNT:
            *(DWORD * )buff = 2048;  // 总的扇区数 break; case GET_SECTOR_SIZE :
            *(WORD * )buff = 4096;  // 定义一个扇区大小为4K break; case GET_BLOCK_SIZE :
            *(DWORD * )buff = 65536; // 定义一个块大小为64K break;
    } return RES_OK ;
  /* USER CODE END IOCTL */
} #endif /* _USE_IOCTL == 1 */ 

4、编写测试QSPI FLASH fatfs的程序

测试案例如下:

int main(void)
{
    /* USER CODE BEGIN 1 */
    uint8_t res ;
    uint32_t Total = 0; //读取FLASH总容量
    uint32_t Free = 0; //读取FLASH剩余容量
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
    MX_QUADSPI_Init();
    MX_FATFS_Init();
    /* USER CODE BEGIN 2 */
    Mount_Fatfs();
    f_GetTotal_Free((uint8_t*)"0:", &Total, &Free); //获取SD卡总容量和剩余容量 printf("当前Fatfs总容量:%dKB==>%dMB 剩余容量:%dKB==>%dMB\n", Total, Total / 1024, Free, Free / 1024);

    /*----------------------- 文件系统测试:写测试 -----------------------------*/ printf("\r\n****** 即将进行文件写入测试... ******\r\n");
    res = f_open(&USERFile, "0:BearPi.txt", FA_OPEN_ALWAYS | FA_WRITE); if(res == FR_OK)
    { printf("打开/创建BearPi.txt文件成功,向文件写入数据。\r\n");
        res = f_write(&USERFile, write_buf, strlen((const char *)write_buf), &count); if(res != FR_OK)
        { printf("f_write 发生错误,err = %d\r\n", res); printf("关闭打开的BearPi.txt文件\r\n");
            count = 0;
            f_close(&USERFile);
        } else { printf("文件写入成功,写入字节数据:%d\n", count); printf("向文件写入的数据为:\r\n%s\r\n", write_buf); printf("关闭打开的BearPi.txt文件\r\n");
            count = 0;
            f_close(&USERFile);
        }
    } else printf("打开/创建BearPi.txt文件失败,err = %d\r\n", res);

    /*------------------- 文件系统测试:读测试 ------------------------------------*/ printf("****** 即将进行文件读取测试... ******\r\n");
    res = f_open(&USERFile, "0:BearPi.txt", FA_OPEN_EXISTING | FA_READ); if(res == FR_OK)
    { printf("打开BearPi.txt文件成功\r\n");
        res = f_read(&USERFile, read_buf, sizeof(read_buf), &count); if(res != FR_OK)
        { printf("f_read 发生错误,err = %d\r\n", res); printf("关闭打开的BearPi.txt文件\r\n");
            f_close(&USERFile);
        } else { printf("文件读取成功,读取字节数据:%d\n", count); printf("向文件读取的数据为:\r\n%s\r\n", read_buf); printf("关闭打开的BearPi.txt文件\r\n");
            f_close(&USERFile);
        }
    } else printf("打开BearPi.txt文件失败,err = %d\r\n", res);



    /*------------------- 不再使用文件系统,取消挂载文件系统 ------------------------------------*/ printf("不再使用文件系统,取消挂载文件系统\r\n");
    res = f_mount(NULL, "0:", 1); if(res == FR_OK) printf("取消挂载文件系统成功\r\n"); else printf("取消挂载文件系统失败,err = %d\r\n", res); printf("文件系统测试结束\r\n");
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */ while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }

    /* USER CODE END 3 */
}

运行结果:

获取完整demo:

码云仓库:https://gitee.com/morixinguan/bear-pi/tree/master/19.QSPI_Fatfs

获取方法:

git clone https://gitee.com/morixinguan/bear-pi.git

即可获取本次实验工程全部代码。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

西班牙塞维利亚,2024年3月12日 — Teledyne Technologies旗下公司、全球成像解决方案创新者Teledyne e2v宣布扩展其Flash™ CMOS图像传感器系列,推出Flash 2K LSA,该...

关键字: 图像传感器 Flash 摄像机

在这篇文章中,小编将为大家带来JTAG接口与Flash的相关报道。如果你对本文即将要讲解的内容存在一定兴趣,不妨继续往下阅读哦。

关键字: JTAG Flash

近日,第11届EEVIA年度中国硬科技媒体论坛暨产业链研创趋势展望研讨会在深圳召开,兆易创新Flash事业部产品市场经理张静在会上发布了主题为“持续开拓,兆易新一代存储产品助力行业创新”的演讲。

关键字: 兆易创新 Flash 闪存

随着信息技术的快速发展,存储器的需求日益增长。Flash存储器作为一种非易失性存储器,具有重要的应用价值和广泛的应用领域。本文将详细介绍Flash存储器的基本原理、工作方式和作用,帮助读者更好地了解这一重要的存储器技术。

关键字: Flash 汽车 电子设备

随着信息时代的到来,数据存储成为了一项基本需求。Flash存储器成为了一种常见的存储设备,用于存储各种类型的数据,如文档、图片、视频等。本文将详细介绍如何使用Flash存储器以及如何写入数据,帮助读者了解Flash存储器...

关键字: Flash 存储器 数据

随着科技的不断发展,Flash存储器已经成为存储设备中最常用的一种类型。它具有非易失性、高密度、低功耗和快速读写等特点,广泛应用于各种领域,如移动设备、嵌入式系统和存储芯片等。本文将介绍Flash存储器的编程设计以及一些...

关键字: 存储器 Flash 嵌入式

(全球TMT2023年7月28日讯)2023年7月28日,江波龙上海总部项目封顶仪式在中国(上海)自由贸易试验区临港新片区举行。江波龙上海总部位于临港新片区滴水湖科创总部湾核心区,项目于2021年启动建设,占地面积约1...

关键字: 存储芯片 数据中心 芯片设计 Flash

昨天下午,中国市场监管总局附加限制性条件批准了美国半导体公司迈凌(MaxLinear)对全球最大 NAND Flash 控制芯片供应商慧荣科技(SMI)的收购。

关键字: 迈凌 慧荣 芯片 NAND Flash

Flash存储器,也称为闪存存储器,是一种非易失性存储器(Non-Volatile Memory,NVM),用于在设备断电后仍然能够保持存储的数据。它的名称来源于一种称为“闪存技术”的特殊电子存储技术。Flash存储器的...

关键字: Flash 存储器 电荷贮存器

据业内信息统计数据,2023 年第一季度 NAND-Flash 存储市场的营收或将持续下滑,除了传统的淡季影响之外,还和过去两年的市场影响以及双边制裁等因素有关。据悉,NAND-Flash 存储市场去年不断下跌,最后一个...

关键字: NAND Flash 闪存 三星 美光 SK 海力士 铠侠
关闭
关闭