当前位置:首页 > 公众号精选 > 嵌入式云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获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

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

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭