[应用相关] 【转】从 STM32Cube 库向标准外设库移植 FatFs 文件系统

[复制链接]
1627|26
 楼主| 从此不早朝 发表于 2022-5-5 14:24 | 显示全部楼层 |阅读模式
前言前言
在很多应用中,文件系统被用来在存储介质上进行存储和管理文件数据。 FatFs 作为面向小型嵌入式系统的一种通用 FAT 文
件系统,被广泛使用。在 STM32Cube 库中, Middleware 是包含有 FatFs 文件系统的,而且有相关的例程。但是在标准外设
库并没有相关的例程,这使得在使用标准外设库在开发项目中使用文件系统的话,需要自己再移植代码。其实,从
STM32Cube 库向标准外设库移植 FatFs 文件系统很方便,简单实用。下面我们以 STM32F4 系列为例,来介绍一下 SD 卡的
移植。  

 楼主| 从此不早朝 发表于 2022-5-5 14:25 | 显示全部楼层
STM32CubeF4 库中的 FatFs
大家都知道,进行 FatFs 移植主要就是在 diskio.c 中添加底层驱动代码。在 STM32CubeF4 库中,可以在
\STM32Cube_FW_F4_V1.11.0\Middlewares\Third_Party\FatFs\src 找到 FatFs R0.11 的代码,细心的工程师会发现,里边的
文件与从 FatFs 下载的 FatFs R0.11 不太一样,多了 ff_gen_drv.c 和 ff_gen_drv.h 两个文件,并且多了一个包含多种存储介
质驱动的 driver 文件夹。这是因为 ST 的工程师在 FatFs 的代码中,已经为大家添加了各种存储介质的驱动代码,以方便大家
使用,并使用 ff_gen_drv.c 来进行管理。所以, STM32CubeF4 的 FatFs 中间件模块架构如下:  

6196462736db1ce383.png
从架构图可知,在 STM32CubeF4 解决方案中,已经添加额外的接口层,可以动态地添加/删除 FatFs 模块的物理介质。如需
以底层磁盘 I/O 驱动来连接 FatFs 模块,用户可以使用 FATFS_LinkDriver()和 FATFS_UnLinkDriver() 动态地添加或者删除磁
盘 I/O 驱动;应用程序可能需要知道当前连接的磁盘 I/O 驱动数量,这一点可通过 FATFS_GetAttachedDriversNbr() API 来
实现。这让我们在管理物理介质更为方便。这三个函数就位于 ff_gen_drv.c 中。以 SD 卡为例,原本的“diskio.c”分化为
“diskio.c + ff_gen_drv.c + \drivers\sd_diskio.c”三个文件,虽然文件增加了,但是条理更加清晰。具体的介绍可以参考用户
手册 UM1721《在 STM32Cube 上开发 FatFs 相关应用》,这里不作详述。看完 UM1721,接下来可以开始动手实现了。


 楼主| 从此不早朝 发表于 2022-5-5 14:26 | 显示全部楼层
一 实现环境
2274062736e00a31de.png


 楼主| 从此不早朝 发表于 2022-5-5 14:27 | 显示全部楼层
二 实现步骤
1.1.在标准外设库上建立项目文件, 确保 SD 卡可正常工作
1) \STM32F4xx_DSP_StdPeriph_Lib_V1.6.1\Project 下复制 STM32F4xx_StdPeriph_Templates 并将文件夹更名为
FatFs_uSD
2) \STM32F4xx_DSP_StdPeriph_Lib_V1.6.1\Project\STM32F4xx_StdPeriph_Examples\SDIO\SDIO_uSDCard 下的文件
复制到
FatFs_uSD 替换掉原有文件
3) 打开 EWARM 下面的项目文件,在项目文件中添加\Utilities\STM32_EVAL\STM324x9I_EVAL 文件组,并加入
stm324x9i_eval.cstm324x9i_eval_ioe16.cstm324x9i_eval_sdio_sd.c,如图:
3834262736e210a873.png
4) 在 main.h 中将 include 中的代码加入 STM324x9I 的信息,更新为
  1. #if defined (USE_STM324xG_EVAL)
  2. #include "stm324xg_eval.h"
  3. #include "stm324xg_eval_sdio_sd.h"
  4. #elif defined (USE_STM324x7I_EVAL)
  5. #include "stm324x7i_eval.h"
  6. #include "stm324x7i_eval_sdio_sd.h"
  7. #elif defined (USE_STM324x9I_EVAL)
  8. #include "stm324x9i_eval.h"
  9. #include "stm324x9i_eval_sdio_sd.h"#else
  10. #error "Please select first the Evaluation board used in your application (in Project
  11. Options)"
  12. #endif
5) 编译,成功。下载运行,可见 LED1、 LED2 和 LED3 点亮,证明 SD 卡读写正常。此步骤的目的在于首先要确保 SDIO 读
写 SD 卡是正常的。



 楼主| 从此不早朝 发表于 2022-5-5 14:31 | 显示全部楼层
2.2.移植 FatFs 代码
1) 将\STM32Cube_FW_F4_V1.11.0\Middlewares\Third_Party\下的 FatFs 文件夹复制到
\STM32F4xx_DSP_StdPeriph_Lib_V1.6.1\Libraries
2) 打开之前的项目,在项目中添加 FatFs 文件组,加入\drivers\sd_diskio.c、 diskio.c、 ff.c 和 ff_gen_drv.c,如图: 9475462736ea219e22.png
3) 打开 Project Options,在 C/C++ Compiler 的 Preprocessor 页面添加 FatFs 使用的头文件的地址:
$PROJ_DIR$\..\..\..\Libraries\FatFs\src 和$PROJ_DIR$\..\..\..\Libraries\FatFs\src\drivers,如下:
786862736ec6220b7.png
4) 复制\STM32Cube_FW_F4_V1.11.0\Projects\STM324x9I_EVAL\Applications\FatFs\FatFs_uSD\Inc 下的 ffconf.h 到
\STM32F4xx_DSP_StdPeriph_Lib_V1.6.1\Project\Fatfs_uSDcard
5) 修改 ffconf.h,删掉第 15 行的 “ #include "stm32f4xx_hal.h"”,将第 18 行的“#include "stm324x9i_eval_sd.h"”改为
“#include "stm324x9i_eval_sdio_sd.h"”




 楼主| 从此不早朝 发表于 2022-5-5 14:32 | 显示全部楼层
6) 修改 sd_diskio.c,这是整个移植最关键的地方。
a. DSTATUS SD_initialize(BYTE lun)
STM32CubeF4 中的 BSP_SD_Init()对应于标准外设库的 SD_Init(), MSD_OK 对应于 SD_OK。此函数修改为:  

  1. DSTATUS SD_initialize(BYTE lun)
  2. {
  3. Stat = STA_NOINIT;
  4. /* Configure the uSD device */
  5. if(SD_Init() == SD_OK)
  6. {
  7. Stat &= ~STA_NOINIT;
  8. }
  9. return Stat;}


 楼主| 从此不早朝 发表于 2022-5-5 14:33 | 显示全部楼层
b. DSTATUS SD_status(BYTE lun)
STM32CubeF4 中的 BSP_SD_GetStatus ()对应于标准外设库的 SD_GetStatus() ()。此函数修改为:
  1. DSTATUS SD_status(BYTE lun)
  2. {
  3. Stat = STA_NOINIT;
  4. if(SD_GetStatus() == SD_TRANSFER_OK)
  5. {
  6. Stat &= ~STA_NOINIT;
  7. }
  8. return Stat;
  9. }




 楼主| 从此不早朝 发表于 2022-5-5 14:33 | 显示全部楼层
c. DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
在 STM32CubeF4 中, BSP_SD_ReadBlocks()函数调用 HAL_SD_ReadBlocks(),而 HAL_SD_ReadBlocks()已经
针对读取单个 Block 和多个 Block 进行了处理。而在标准外设库中没有这样的函数,单个 Block 的读取使用
SD_ReadBlock()函数,多个 Block 的读取使用 SD_ReadMultiBlocks()函数。所以,这个函数需要修改为:  

  1. DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
  2. {
  3. DRESULT res = RES_OK;
  4. if (count > 1)
  5. {
  6. /* Read multiple block */
  7. if(SD_ReadMultiBlocks((uint8_t *)buff,
  8. (uint64_t) (sector * BLOCK_SIZE),
  9. BLOCK_SIZE,
  10. count) != SD_OK)
  11. return RES_ERROR;
  12. /* Check if the Transfer is finished */
  13. if(SD_WaitReadOperation() != SD_OK)
  14. return RES_ERROR;
  15. while(SD_GetStatus() != SD_TRANSFER_OK);
  16. }
  17. else
  18. {
  19. /* Read block */
  20. if(SD_ReadBlock((uint8_t *)buff,
  21. (uint64_t) (sector * BLOCK_SIZE),
  22. BLOCK_SIZE) != SD_OK)
  23. return RES_ERROR;
  24. /* Check if the Transfer is finished */
  25. if(SD_WaitReadOperation() != SD_OK)
  26. return RES_ERROR;
  27. while(SD_GetStatus() != SD_TRANSFER_OK);
  28. }return res;
  29. }


 楼主| 从此不早朝 发表于 2022-5-5 14:34 | 显示全部楼层
d. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
SD_write()的修改和 SD_read()一样,需要分别对单个 Block 和多个 Block 进行处理。函数修改为:
  1. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
  2. {
  3. DRESULT res = RES_OK;
  4. if (count > 1)
  5. {
  6. /* Write multiple block */
  7. if(SD_WriteMultiBlocks((uint8_t *)buff,
  8. (uint64_t) (sector * BLOCK_SIZE),
  9. BLOCK_SIZE,
  10. count) != SD_OK)
  11. return RES_ERROR;
  12. /* Check if the Transfer is finished */
  13. if(SD_WaitWriteOperation() != SD_OK)
  14. return RES_ERROR;
  15. while(SD_GetStatus() != SD_TRANSFER_OK);
  16. }
  17. else
  18. {
  19. /* Write block */
  20. if(SD_WriteBlock((uint8_t *)buff,
  21. (uint64_t) (sector * BLOCK_SIZE),
  22. BLOCK_SIZE) != SD_OK)
  23. return RES_ERROR;
  24. /* Check if the Transfer is finished */
  25. if(SD_WaitWriteOperation() != SD_OK)
  26. return RES_ERROR;
  27. while(SD_GetStatus() != SD_TRANSFER_OK);
  28. }
  29. return res;
  30. }




 楼主| 从此不早朝 发表于 2022-5-5 14:34 | 显示全部楼层
e. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
STM32CubeF4 中的 BSP_SD_GetCardInfo()对应于标准外设库的 SD_GetCardInfo()。此函数修改为:
  1. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
  2. {
  3. DRESULT res = RES_ERROR;
  4. SD_CardInfo CardInfo;
  5. if (Stat & STA_NOINIT) return RES_NOTRDY;
  6. switch (cmd)
  7. {/* Make sure that no pending write process */
  8. case CTRL_SYNC :
  9. res = RES_OK;
  10. break;
  11. /* Get number of sectors on the disk (DWORD) */
  12. case GET_SECTOR_COUNT :
  13. SD_GetCardInfo(&CardInfo);
  14. *(DWORD*)buff = CardInfo.CardCapacity / BLOCK_SIZE;
  15. res = RES_OK;
  16. break;
  17. /* Get R/W sector size (WORD) */
  18. case GET_SECTOR_SIZE :
  19. *(WORD*)buff = BLOCK_SIZE;
  20. res = RES_OK;
  21. break;
  22. /* Get erase block size in unit of sector (DWORD) */
  23. case GET_BLOCK_SIZE :
  24. *(DWORD*)buff = BLOCK_SIZE;
  25. break;
  26. default:
  27. res = RES_PARERR;
  28. }
  29. return res;
  30. }
至此,编译可通过, FatFs 的移植已算完成。接下来,是修改测试代码。  


 楼主| 从此不早朝 发表于 2022-5-5 14:36 | 显示全部楼层
7) 修改 main.c。参考\STM32Cube_FW_F4_V1.11.0\Projects\STM324x9I_EVAL\Applications\FatFs\FatFs_uSD\Src\main.c,
修改此文件,如下:
  1. /* Includes ------------------------------------------------------------------*/
  2. #include "main.h"
  3. /** @addtogroup STM32F4xx_StdPeriph_Examples
  4. * @{
  5. */
  6. /** @addtogroup SDIO_uSDCard
  7. * @{
  8. */
  9. /* Private typedef -----------------------------------------------------------*/
  10. typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
  11. /* Private define ------------------------------------------------------------*/
  12. /* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/
  13. FATFS SDFatFs; /* File system object for SD card logical drive */
  14. FIL MyFile; /* File object */
  15. char SDPath[4]; /* SD card logical drive path */
  16. /* Private function prototypes -----------------------------------------------*/
  17. static void NVIC_Configuration(void);
  18. static void Error_Handler(void);
  19. /* Private functions ---------------------------------------------------------*/
  20. /**
  21. * [url=home.php?mod=space&uid=247401]@brief[/url] Main program
  22. * @param None
  23. * @retval None
  24. */
  25. int main(void)
  26. {
  27. /*!< At this stage the microcontroller clock setting is already configured,
  28. this is done through SystemInit() function which is called from startup
  29. files (startup_stm32f40_41xxx.s/startup_stm32f427_437xx.s)
  30. before to branch to application main. To reconfigure the default setting
  31. of SystemInit() function, refer to system_stm32f4xx.c file
  32. */
  33. FRESULT res; /* FatFs function common result
  34. code */
  35. uint32_t byteswritten, bytesread; /* File write/read counts */
  36. uint8_t wtext[] = "STM32 with FatFs demo [url=home.php?mod=space&uid=72445]@[/url] std lib"; /* File write buffer */
  37. uint8_t rtext[100]; /* File read buffer */
  38. /* Initialize LEDs available on EVAL board */
  39. STM_EVAL_LEDInit(LED1);
  40. STM_EVAL_LEDInit(LED3);
  41. /* NVIC Configuration */
  42. NVIC_Configuration();
  43. /*##-1- Link the micro SD disk I/O driver ##################################*/
  44. if(FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
  45. {
  46. /*##-2- Register the file system object to the FatFs module ##############*/
  47. if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) != FR_OK)
  48. {
  49. /* FatFs Initialization Error */
  50. Error_Handler();
  51. }
  52. else
  53. {
  54. /*##-3- Create a FAT file system (format) on the logical drive #########*//* WARNING: Formatting the uSD card will delete all content on the device */
  55. if(f_mkfs((TCHAR const*)SDPath, 0, 0) != FR_OK)
  56. {
  57. /* FatFs Format Error */
  58. Error_Handler();
  59. }
  60. else
  61. {
  62. /*##-4- Create and Open a new text file object with write access #####*/
  63. if(f_open(&MyFile, "STM32STD.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
  64. {
  65. /* 'STM32STD.TXT' file Open for write Error */
  66. Error_Handler();
  67. }
  68. else
  69. {
  70. /*##-5- Write data to the text file ################################*/
  71. res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);
  72. if((byteswritten == 0) || (res != FR_OK))
  73. {
  74. /* 'STM32STD.TXT' file Write or EOF Error */
  75. Error_Handler();
  76. }
  77. else
  78. {
  79. /*##-6- Close the open text file #################################*/
  80. f_close(&MyFile);
  81. /*##-7- Open the text file object with read access ###############*/
  82. if(f_open(&MyFile, "STM32STD.TXT", FA_READ) != FR_OK)
  83. {
  84. /* 'STM32STD.TXT' file Open for read Error */
  85. Error_Handler();
  86. }
  87. else
  88. {
  89. /*##-8- Read data from the text file ###########################*/
  90. res = f_read(&MyFile, rtext, sizeof(rtext), (UINT*)&bytesread);
  91. if((bytesread == 0) || (res != FR_OK))
  92. {
  93. /* 'STM32STD.TXT' file Read or EOF Error */
  94. Error_Handler();
  95. }
  96. else
  97. {
  98. /*##-9- Close the open text file #############################*/
  99. f_close(&MyFile);/*##-10- Compare read data with the expected data ############*/
  100. if((bytesread != byteswritten))
  101. {
  102. /* Read data is different from the expected data */
  103. Error_Handler();
  104. }
  105. else
  106. {
  107. /* Success of the demo: no error occurrence */
  108. STM_EVAL_LEDOn(LED1);
  109. }
  110. }
  111. }
  112. }
  113. }
  114. }
  115. }
  116. }
  117. /*##-11- Unlink the micro SD disk I/O driver ###############################*/
  118. FATFS_UnLinkDriver(SDPath);
  119. /* Infinite loop */
  120. while (1)
  121. {
  122. }
  123. }
  124. /**
  125. * @brief Configures SDIO IRQ channel.
  126. * @param None
  127. * @retval None
  128. */
  129. static void NVIC_Configuration(void)
  130. {
  131. NVIC_InitTypeDef NVIC_InitStructure;
  132. /* Configure the NVIC Preemption Priority Bits */
  133. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  134. NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
  135. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  136. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  137. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  138. NVIC_Init(&NVIC_InitStructure);
  139. NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;
  140. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  141. NVIC_Init(&NVIC_InitStructure);}
  142. /**
  143. * @brief This function is executed in case of error occurrence.
  144. * @param None
  145. * @retval None
  146. */
  147. static void Error_Handler(void)
  148. {
  149. /* Turn LED3 on */
  150. STM_EVAL_LEDOn(LED3);
  151. while(1)
  152. {
  153. }
  154. }
  155. #ifdef USE_FULL_ASSERT
  156. /**
  157. * @brief Reports the name of the source file and the source line number
  158. * where the assert_param error has occurred.
  159. * @param file: pointer to the source file name
  160. * @param line: assert_param error line source number
  161. * @retval None
  162. */
  163. void assert_failed(uint8_t* file, uint32_t line)
  164. {
  165. /* User can add his own implementation to report the file name and line number,
  166. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  167. /* Infinite loop */
  168. while (1)
  169. {
  170. }
  171. }
  172. #endif

还需要在 main.h 中加入:
  1. /* FatFs includes component */
  2. #include "ff_gen_drv.h"
  3. #include "sd_diskio.h"
此主函数实现功能为:创建 STM32STD.TXT 文件,并向其写入“ STM32 with FatFs demo @ std lib”
8) 编译,成功。



 楼主| 从此不早朝 发表于 2022-5-5 14:38 | 显示全部楼层
3.3.测试
1) 连接 STM32439I-EVAL PC
2) 打开工程,下载代码并运行, LED1 点亮,代表运行通过。
3) SD 卡从 STM32439I-EVAL 取出,放入 PC 进行读取,可见:
54493627370a8227b3.png
4) 打开 STM32STD.TXT,可见:
66038627370bc1bdd8.png
5) 测试结果:成功。



 楼主| 从此不早朝 发表于 2022-5-5 14:39 | 显示全部楼层
结论结论
此文档介绍从 STM32CubeF4 中将 FatFs 文件系统移植到标准外设库的实现过程。另外,对于时间接口函数,有需要的读者
可自行进行移植。
  

 楼主| 从此不早朝 发表于 2022-5-5 14:40 | 显示全部楼层
重要通知 - 请仔细阅读
意法半导体公司及其子公司(“ST”)保留随时对ST 产品和/ 或本文档进行变更、更正、增强、修改和改进的权利,恕不另行通知。买方在
订货之前应获取关于ST 产品的最新信息。ST 产品的销售依照订单确认时的相关ST 销售条款。
买方自行负责对ST 产品的选择和使用, ST 概不承担与应用协助或买方产品设计相关的任何责任。
ST 不对任何知识产权进行任何明示或默示的授权或许可。
转售的ST 产品如有不同于此处提供的信息的规定,将导致ST 针对该产品授予的任何保证失效。
ST 和ST 徽标是ST 的商标。所有其他产品或服务名称均为其各自所有者的财产。
本文档中的信息取代本文档所有早期版本中提供的信息。
© 2015 STMicroelectronics - 保留所有权利
  

Uriah 发表于 2022-10-7 09:14 | 显示全部楼层

访问时采用不同的指令,所以并不会占用 RAM 空间
Bblythe 发表于 2022-10-7 12:13 | 显示全部楼层

51 单片机不使用线性编址
Pulitzer 发表于 2022-10-7 15:12 | 显示全部楼层

128以上的某些地址为特殊寄存器使用,不能给程序用
vivilyly 发表于 2023-2-2 11:07 | 显示全部楼层
如何用stm32cubemx 设置 FLASH读写配置
bartonalfred 发表于 2023-2-4 14:33 | 显示全部楼层
FatFS文件系统中如何创建和批量命名文件?
cemaj 发表于 2023-2-5 13:46 | 显示全部楼层
STM32通过USB的方式控制tf卡原理是什么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

185

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部