你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 1768|回复: 9

【HAL库每天一例】第049例:SPI-基于串行Flash的FatFS功能使用

[复制链接]

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
发表于 2016-6-23 09:12:33 | 显示全部楼层 |阅读模式
【HAL库每天一例】系列例程从今天开始持续更新。。。。。
我们将坚持每天至少发布一个基于YS-F1Pro开发板的HAL库例程,
该系列例程将带领大家从零开始使用HAL库,后面会持续添加模块应用例程。
同样的,我们还程序发布基于HAL库的指导文档和视频教程,欢迎持续关注,并提出改进意见。
例程下载:
资料包括程序、相关说明资料以及软件使用截图
链接:https://pan.baidu.com/s/1i574oPv
密码:r3s3

(硬石YS-F1Pro开发板HAL库例程持续更新\1. 软件设计之基本裸机例程(HAL库版本)\YSF1_HAL-049. SPI-基于串行Flash的FatFS功能使用

/**
  ******************************************************************************
  *                           硬石YS-F1Pro开发板例程功能说明
  *
  *  例程名称: YSF1_HAL-049. SPI-基于串行Flash的FatFS功能使用
  *   
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F1Pro使用。
  *
  * 淘宝:
  * 论坛:www ing10bbs com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */

【1】例程简介
  串行Flash用于存储数据。YS-F1Pro开发板集成了一个16M字节的W25Q128串行Flash芯片,可以
用于存放数据。该芯片使用SPI1通信接口
  FatFS是一个专门为嵌入式开发的开源小型文件系统。FatFS可以提供丰富的文件操作函数,方便
文件操作,我们可以在串行Flash空间上移植FatFS文件系统。
  
【2】跳线帽情况
******* 为保证例程正常运行,必须插入以下跳线帽 **********
丝印编号     IO端口      目标功能引脚        出厂默认设置
  JP1        PA10        TXD(CH340G)          已接入
  JP2        PA9         RXD(CH340G)          已接入
  
【3】操作及现象
使用开发板配套的MINI USB线连接到开发板标示“调试串口”字样的MIMI USB接口(需要安装驱
动),在电脑端打开串口调试助手工具,设置参数为115200 8-N-1。下载完程序之后,在串口调试
助手窗口可接收到信息。
/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

main.c文件内容
  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: main.c
  4.   * 作    者: 硬石嵌入式开发团队
  5.   * 版    本: V1.0
  6.   * 编写日期: 2015-10-04
  7.   * 功    能: 基于串行Flash的FatFS文件系统功能测试
  8.   ******************************************************************************
  9.   * 说明:
  10.   * 本例程配套硬石stm32开发板YS-F1Pro使用。
  11.   *
  12.   * 淘宝:
  13.   * 论坛:http://www.ing10bbs.com
  14.   * 版权归硬石嵌入式开发团队所有,请勿商用。
  15.   ******************************************************************************
  16.   */
  17. /* 包含头文件 ----------------------------------------------------------------*/
  18. #include "stm32f1xx_hal.h"
  19. #include "usart/bsp_debug_usart.h"
  20. #include "ff.h"
  21. #include "ff_gen_drv.h"
  22. #include "drivers\spiflash_diskio.h"
  23. #include "string.h"

  24. /* 私有类型定义 --------------------------------------------------------------*/
  25. /* 私有宏定义 ----------------------------------------------------------------*/
  26. /* 私有变量 ------------------------------------------------------------------*/
  27. char SPIFLASH_Path[4];            /* 串行Flash逻辑设备路径 */
  28. FATFS fs;                                                                                                        /* FatFs文件系统对象 */
  29. FIL file;                                                                                                        /* 文件对象 */
  30. FRESULT f_res;                    /* 文件操作结果 */
  31. UINT fnum;                                                      /* 文件成功读写数量 */
  32. char fpath[100];                  /* 保存当前扫描路径 */
  33. char readbuffer[512];
  34. DIR dir;

  35. /* 扩展变量 ------------------------------------------------------------------*/
  36. /* 私有函数原形 --------------------------------------------------------------*/
  37. static void printf_fatfs_error(FRESULT fresult);
  38. static FRESULT miscellaneous(void);
  39. static FRESULT file_check(void);
  40. static FRESULT scan_files (char* path);

  41. /* 函数体 --------------------------------------------------------------------*/
  42. /**
  43.   * 函数功能: 系统时钟配置
  44.   * 输入参数: 无
  45.   * 返 回 值: 无
  46.   * 说    明: 无
  47.   */
  48. void SystemClock_Config(void)
  49. {
  50.   RCC_OscInitTypeDef RCC_OscInitStruct;
  51.   RCC_ClkInitTypeDef RCC_ClkInitStruct;

  52.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;  // 外部晶振,8MHz
  53.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  54.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  55.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  56.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  57.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  // 9倍频,得到72MHz主时钟
  58.   HAL_RCC_OscConfig(&RCC_OscInitStruct);

  59.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  60.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  61.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;       // 系统时钟:72MHz
  62.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;              // AHB时钟:72MHz
  63.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;               // APB1时钟:36MHz
  64.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;               // APB2时钟:72MHz
  65.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

  66.         // HAL_RCC_GetHCLKFreq()/1000    1ms中断一次
  67.         // HAL_RCC_GetHCLKFreq()/100000         10us中断一次
  68.         // HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
  69.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);  // 配置并启动系统滴答定时器
  70.   /* 系统滴答定时器时钟源 */
  71.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
  72.   /* 系统滴答定时器中断优先级配置 */
  73.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  74. }

  75. /**
  76.   * 函数功能: 主函数.
  77.   * 输入参数: 无
  78.   * 返 回 值: 无
  79.   * 说    明: 无
  80.   */
  81. int main(void)
  82. {  
  83.   /* 复位所有外设,初始化Flash接口和系统滴答定时器 */
  84.   HAL_Init();
  85.   /* 配置系统时钟 */
  86.   SystemClock_Config();

  87.   /* 初始化串口并配置串口中断优先级 */
  88.   MX_DEBUG_USART_Init();
  89.   printf("****** 这是一个基于串行Flash的FatFS文件系统功能使用 ******\n");
  90.   
  91.   /* 注册一个FatFS设备:串行Flash */
  92.   if(FATFS_LinkDriver(&SPIFLASH_Driver, SPIFLASH_Path) == 0)
  93.   {
  94.     //在串行Flash挂载文件系统,文件系统挂载时会对串行Flash初始化
  95.     f_res = f_mount(&fs,(TCHAR const*)SPIFLASH_Path,1);
  96.     printf_fatfs_error(f_res);
  97.     if(f_res!=FR_OK)
  98.     {
  99.       printf("!!串行Flash挂载文件系统失败。\n");
  100.       while(1);
  101.     }
  102.     else
  103.     {
  104.       printf("》串行Flash文件系统挂载成功,可以进行测试。\n");   
  105.     }
  106.    
  107.     /* FatFs多项功能测试 */
  108.     f_res = miscellaneous();
  109.    
  110.     printf("\n*************** 文件信息获取测试 **************\r\n");
  111.     f_res = file_check();

  112.     printf("***************** 文件扫描测试 ****************\r\n");
  113.     strcpy(fpath,SPIFLASH_Path);
  114.     scan_files(fpath);
  115.    
  116.     /* 不再使用,取消挂载 */
  117.     f_res = f_mount(NULL,(TCHAR const*)SPIFLASH_Path,1);       
  118.   }  
  119.   
  120.   /* 注销一个FatFS设备:串行Flash */
  121.   FATFS_UnLinkDriver(SPIFLASH_Path);
  122.   
  123.   /* 无限循环 */
  124.   while (1)
  125.   {
  126.   }
  127. }

  128. /**
  129.   * 函数功能: FatFS文件系统操作结果信息处理.
  130.   * 输入参数: FatFS文件系统操作结果:FRESULT
  131.   * 返 回 值: 无
  132.   * 说    明: 无
  133.   */
  134. static void printf_fatfs_error(FRESULT fresult)
  135. {
  136.   switch(fresult)
  137.   {
  138.     case FR_OK:                   //(0)
  139.       printf("》操作成功。\n");
  140.     break;
  141.     case FR_DISK_ERR:             //(1)
  142.       printf("!!硬件输入输出驱动出错。\n");
  143.     break;
  144.     case FR_INT_ERR:              //(2)
  145.       printf("!!断言错误。\n");
  146.     break;
  147.     case FR_NOT_READY:            //(3)
  148.       printf("!!物理设备无法工作。\n");
  149.     break;
  150.     case FR_NO_FILE:              //(4)
  151.       printf("!!无法找到文件。\n");
  152.     break;
  153.     case FR_NO_PATH:              //(5)
  154.       printf("!!无法找到路径。\n");
  155.     break;
  156.     case FR_INVALID_NAME:         //(6)
  157.       printf("!!无效的路径名。\n");
  158.     break;
  159.     case FR_DENIED:               //(7)
  160.     case FR_EXIST:                //(8)
  161.       printf("!!拒绝访问。\n");
  162.     break;
  163.     case FR_INVALID_OBJECT:       //(9)
  164.       printf("!!无效的文件或路径。\n");
  165.     break;
  166.     case FR_WRITE_PROTECTED:      //(10)
  167.       printf("!!逻辑设备写保护。\n");
  168.     break;
  169.     case FR_INVALID_DRIVE:        //(11)
  170.       printf("!!无效的逻辑设备。\n");
  171.     break;
  172.     case FR_NOT_ENABLED:          //(12)
  173.       printf("!!无效的工作区。\n");
  174.     break;
  175.     case FR_NO_FILESYSTEM:        //(13)
  176.       printf("!!无效的文件系统。\n");
  177.     break;
  178.     case FR_MKFS_ABORTED:         //(14)
  179.       printf("!!因函数参数问题导致f_mkfs函数操作失败。\n");
  180.     break;
  181.     case FR_TIMEOUT:              //(15)
  182.       printf("!!操作超时。\n");
  183.     break;
  184.     case FR_LOCKED:               //(16)
  185.       printf("!!文件被保护。\n");
  186.     break;
  187.     case FR_NOT_ENOUGH_CORE:      //(17)
  188.       printf("!!长文件名支持获取堆空间失败。\n");
  189.     break;
  190.     case FR_TOO_MANY_OPEN_FILES:  //(18)
  191.       printf("!!打开太多文件。\n");
  192.     break;
  193.     case FR_INVALID_PARAMETER:    // (19)
  194.       printf("!!参数无效。\n");
  195.     break;
  196.   }
  197. }

  198. /* FatFs多项功能测试 */
  199. static FRESULT miscellaneous(void)
  200. {
  201.   FATFS *pfs;
  202.   DWORD fre_clust, fre_sect, tot_sect;
  203.   
  204.   printf("\n*************** 设备信息获取 ***************\r\n");
  205.   /* 获取设备信息和空簇大小 */
  206.   f_res = f_getfree((TCHAR const*)SPIFLASH_Path, &fre_clust, &pfs);

  207.   /* 计算得到总的扇区个数和空扇区个数 */
  208.   tot_sect = (pfs->n_fatent - 2) * pfs->csize;
  209.   fre_sect = fre_clust * pfs->csize;

  210.   /* 打印信息(4096 字节/扇区) */
  211.   printf("》设备总空间:%10lu KB。\n》可用空间:  %10lu KB。\n", tot_sect *4, fre_sect *4);
  212.   
  213.   printf("\n******** 文件定位和格式化写入功能测试 ********\r\n");
  214.   f_res = f_open(&file, "FatFs读写测试文件.txt",
  215.                             FA_OPEN_EXISTING|FA_WRITE|FA_READ );
  216.         if ( f_res == FR_OK )
  217.         {
  218.     /*  文件定位 */
  219.     f_res = f_lseek(&file,f_size(&file)-1);
  220.     if (f_res == FR_OK)
  221.     {
  222.       /* 格式化写入,参数格式类似printf函数 */
  223.       f_printf(&file,"\n在原来文件新添加一行内容\n");
  224.       f_printf(&file,"》设备总空间:%10lu KB。\n》可用空间:  %10lu KB。\n", tot_sect *4, fre_sect *4);
  225.       /*  文件定位到文件起始位置 */
  226.       f_res = f_lseek(&file,0);
  227.       /* 读取文件所有内容到缓存区 */
  228.       f_res = f_read(&file,readbuffer,f_size(&file),&fnum);
  229.       if(f_res == FR_OK)
  230.       {
  231.         printf("》文件内容:\n%s\n",readbuffer);
  232.       }
  233.     }
  234.     f_close(&file);   
  235.    
  236.     printf("\n********** 目录创建和重命名功能测试 **********\r\n");
  237.     /* 尝试打开目录 */
  238.     f_res=f_opendir(&dir,"TestDir");
  239.     if(f_res!=FR_OK)
  240.     {
  241.       /* 打开目录失败,就创建目录 */
  242.       f_res=f_mkdir("TestDir");
  243.     }
  244.     else
  245.     {
  246.       /* 如果目录已经存在,关闭它 */
  247.       f_res=f_closedir(&dir);
  248.       /* 删除文件 */
  249.       f_unlink("TestDir/testdir.txt");
  250.     }
  251.     if(f_res==FR_OK)
  252.     {
  253.       /* 重命名并移动文件 */
  254.       f_res=f_rename("FatFs读写测试文件.txt","TestDir/testdir.txt");      
  255.     }
  256.         }
  257.   else
  258.   {
  259.     printf("!! 打开文件失败:%d\n",f_res);
  260.     printf("!! 或许需要再次运行“FatFs移植与读写测试”工程\n");
  261.   }
  262.   return f_res;
  263. }


  264. /**
  265.   * 文件信息获取
  266.   */
  267. static FRESULT file_check(void)
  268. {  
  269.   static FILINFO finfo;
  270.   /* 获取文件信息 */
  271.   f_res=f_stat("TestDir/testdir.txt",&finfo);
  272.   if(f_res==FR_OK)
  273.   {
  274.     printf("“testdir.txt”文件信息:\n");
  275.     printf("》文件大小: %ld(字节)\n", finfo.fsize);
  276.     printf("》时间戳: %u/%02u/%02u, %02u:%02u\n",
  277.            (finfo.fdate >> 9) + 1980, finfo.fdate >> 5 & 15, finfo.fdate & 31,finfo.ftime >> 11, finfo.ftime >> 5 & 63);
  278.     printf("》属性: %c%c%c%c%c\n\n",
  279.            (finfo.fattrib & AM_DIR) ? 'D' : '-',      // 是一个目录
  280.            (finfo.fattrib & AM_RDO) ? 'R' : '-',      // 只读文件
  281.            (finfo.fattrib & AM_HID) ? 'H' : '-',      // 隐藏文件
  282.            (finfo.fattrib & AM_SYS) ? 'S' : '-',      // 系统文件
  283.            (finfo.fattrib & AM_ARC) ? 'A' : '-');     // 档案文件
  284.   }
  285.   return f_res;
  286. }

  287. /**
  288.   * @brief  scan_files 递归扫描FatFs内的文件
  289.   * @param  path:初始扫描路径
  290.   * @retval result:文件系统的返回值
  291.   */
  292. static FRESULT scan_files (char* path)
  293. {
  294.   FRESULT res;                 //部分在递归过程被修改的变量,不用全局变量       
  295.   FILINFO fno;  
  296.   int i;            
  297.   char *fn;        // 文件名       
  298.        
  299. #if _USE_LFN
  300.   /* 长文件名支持 */
  301.   /* 简体中文需要2个字节保存一个“字”*/
  302.   static char lfn[_MAX_LFN*2 + 1];        
  303.   fno.lfname = lfn;
  304.   fno.lfsize = sizeof(lfn);
  305. #endif
  306.   //打开目录
  307.   res = f_opendir(&dir, path);
  308.   if (res == FR_OK)
  309.         {
  310.     i = strlen(path);
  311.     for (;;)
  312.                 {
  313.       //读取目录下的内容,再读会自动读下一个文件
  314.       res = f_readdir(&dir, &fno);                                                                
  315.       //为空时表示所有项目读取完毕,跳出
  316.       if (res != FR_OK || fno.fname[0] == 0) break;        
  317. #if _USE_LFN
  318.       fn = *fno.lfname ? fno.lfname : fno.fname;
  319. #else
  320.       fn = fno.fname;
  321. #endif
  322.       //点表示当前目录,跳过                       
  323.       if (*fn == '.') continue;        
  324.       //目录,递归读取      
  325.       if (fno.fattrib & AM_DIR)         
  326.                         {                        
  327.         //合成完整目录名        
  328.         sprintf(&path[i], "/%s", fn);                
  329.         //递归遍历         
  330.         res = scan_files(path);       
  331.         path[i] = 0;         
  332.         //打开失败,跳出循环        
  333.         if (res != FR_OK)
  334.                                         break;
  335.       }
  336.                         else
  337.                         {
  338.                                 printf("%s/%s\n", path, fn);                                                                //输出文件名       
  339.         /* 可以在这里提取特定格式的文件路径 */        
  340.       }//else
  341.     } //for
  342.   }
  343.   return res;
  344. }

  345. /******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
复制代码
串口调试助手截图.jpg


<
回复

使用道具 举报

7

主题

12

回帖

0

蝴蝶豆

初级会员

最后登录
2016-7-7
发表于 2016-6-23 09:37:23 | 显示全部楼层
楼主 有内置FLASH 模拟U盘的示例么
回复 支持 反对

使用道具 举报

39

主题

934

回帖

45

蝴蝶豆

论坛元老

最后登录
2020-6-18
发表于 2016-6-23 09:56:46 | 显示全部楼层
顶一下~
回复 支持 反对

使用道具 举报

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
 楼主| 发表于 2016-6-23 10:47:15 | 显示全部楼层
FoNg0716 发表于 2016-6-23 09:37
楼主 有内置FLASH 模拟U盘的示例么

内置Flash的就没有啊
有内置Flash读写操作的例程,估计根据修改还是可以实现的
YSF1_HAL-061. CPU内部Flash读写.zip (4.66 MB, 下载次数: 34)
回复 支持 反对

使用道具 举报

7

主题

12

回帖

0

蝴蝶豆

初级会员

最后登录
2016-7-7
发表于 2016-6-23 13:05:22 | 显示全部楼层
haohao663 发表于 2016-6-23 10:47
内置Flash的就没有啊
有内置Flash读写操作的例程,估计根据修改还是可以实现的

谢谢,我看看。自身FLASH读写这个比较简单。
主要是cubemx生成的FATS-USE define
其中的USER_read和USER_write这部分不知道该如何实现。
以及USB驱动STORAGE_Read_FS和STORAGE_Write_FS这部分的实现
回复 支持 反对

使用道具 举报

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
 楼主| 发表于 2016-6-23 14:11:48 | 显示全部楼层
在上传一个例程给你
是串行Flash模拟U盘的,就是自定义的,把相关函数修改就好了吧
YSF1_HAL-060. USB-串行Flash模拟U盘.zip (6.16 MB, 下载次数: 31)
回复 支持 反对

使用道具 举报

47

主题

1636

回帖

7

蝴蝶豆

论坛元老

最后登录
2020-10-28
发表于 2016-6-23 21:18:56 | 显示全部楼层
看看           
回复 支持 反对

使用道具 举报

0

主题

153

回帖

0

蝴蝶豆

中级会员

最后登录
2020-1-5
发表于 2016-7-1 22:32:06 | 显示全部楼层
多谢分享
回复 支持 反对

使用道具 举报

1

主题

6

回帖

0

蝴蝶豆

新手上路

最后登录
2016-7-28
发表于 2016-7-13 18:12:39 | 显示全部楼层
求帮助! 我的sd iap现在移植到hal库了 可是在运行的时候会卡死在disk_read(),调试模式检查到移植在检测是否完成传输卡死 有没有什么思路解决?
回复 支持 反对

使用道具 举报

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
 楼主| 发表于 2016-7-13 20:11:21 | 显示全部楼层
你参考我们的SD文件系统里边对SD卡的操作方法
【HAL库每天一例】第044例: SDIO-基于SD卡FatFS文件系统
https://www.stmcu.org.cn/module/ ... &fromuid=331315
(出处: 意法半导体STM32/STM8技术社区)
之前在写液晶截屏时候,发现必须调低SDIO的时钟频率,或许你可以试试看
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版