打印
[应用相关]

【转】从 STM32Cube 库向标准外设库移植 FatFs 文件系统

[复制链接]
951|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前言前言
在很多应用中,文件系统被用来在存储介质上进行存储和管理文件数据。 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 中间件模块架构如下:  


从架构图可知,在 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 | 只看该作者
一 实现环境



使用特权

评论回复
地板
从此不早朝|  楼主 | 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,如图:

4) 在 main.h 中将 include 中的代码加入 STM324x9I 的信息,更新为
#if defined (USE_STM324xG_EVAL)
#include "stm324xg_eval.h"
#include "stm324xg_eval_sdio_sd.h"
#elif defined (USE_STM324x7I_EVAL)
#include "stm324x7i_eval.h"
#include "stm324x7i_eval_sdio_sd.h"
#elif defined (USE_STM324x9I_EVAL)
#include "stm324x9i_eval.h"
#include "stm324x9i_eval_sdio_sd.h"#else
#error "Please select first the Evaluation board used in your application (in Project
Options)"
#endif
5) 编译,成功。下载运行,可见 LED1、 LED2 和 LED3 点亮,证明 SD 卡读写正常。此步骤的目的在于首先要确保 SDIO 读
写 SD 卡是正常的。



使用特权

评论回复
5
从此不早朝|  楼主 | 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,如图:
3) 打开 Project Options,在 C/C++ Compiler 的 Preprocessor 页面添加 FatFs 使用的头文件的地址:
$PROJ_DIR$\..\..\..\Libraries\FatFs\src 和$PROJ_DIR$\..\..\..\Libraries\FatFs\src\drivers,如下:

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"”




使用特权

评论回复
6
从此不早朝|  楼主 | 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。此函数修改为:  

DSTATUS SD_initialize(BYTE lun)
{
Stat = STA_NOINIT;
/* Configure the uSD device */
if(SD_Init() == SD_OK)
{
Stat &= ~STA_NOINIT;
}
return Stat;}


使用特权

评论回复
7
从此不早朝|  楼主 | 2022-5-5 14:33 | 只看该作者
b. DSTATUS SD_status(BYTE lun)
STM32CubeF4 中的 BSP_SD_GetStatus ()对应于标准外设库的 SD_GetStatus() ()。此函数修改为:
DSTATUS SD_status(BYTE lun)
{
Stat = STA_NOINIT;
if(SD_GetStatus() == SD_TRANSFER_OK)
{
Stat &= ~STA_NOINIT;
}
return Stat;
}




使用特权

评论回复
8
从此不早朝|  楼主 | 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()函数。所以,这个函数需要修改为:  

DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;
if (count > 1)
{
/* Read multiple block */
if(SD_ReadMultiBlocks((uint8_t *)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE,
count) != SD_OK)
return RES_ERROR;
/* Check if the Transfer is finished */
if(SD_WaitReadOperation() != SD_OK)
return RES_ERROR;
while(SD_GetStatus() != SD_TRANSFER_OK);
}
else
{
/* Read block */
if(SD_ReadBlock((uint8_t *)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE) != SD_OK)
return RES_ERROR;
/* Check if the Transfer is finished */
if(SD_WaitReadOperation() != SD_OK)
return RES_ERROR;
while(SD_GetStatus() != SD_TRANSFER_OK);
}return res;
}


使用特权

评论回复
9
从此不早朝|  楼主 | 2022-5-5 14:34 | 只看该作者
d. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
SD_write()的修改和 SD_read()一样,需要分别对单个 Block 和多个 Block 进行处理。函数修改为:
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;
if (count > 1)
{
/* Write multiple block */
if(SD_WriteMultiBlocks((uint8_t *)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE,
count) != SD_OK)
return RES_ERROR;
/* Check if the Transfer is finished */
if(SD_WaitWriteOperation() != SD_OK)
return RES_ERROR;
while(SD_GetStatus() != SD_TRANSFER_OK);
}
else
{
/* Write block */
if(SD_WriteBlock((uint8_t *)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE) != SD_OK)
return RES_ERROR;
/* Check if the Transfer is finished */
if(SD_WaitWriteOperation() != SD_OK)
return RES_ERROR;
while(SD_GetStatus() != SD_TRANSFER_OK);
}
return res;
}




使用特权

评论回复
10
从此不早朝|  楼主 | 2022-5-5 14:34 | 只看该作者
e. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
STM32CubeF4 中的 BSP_SD_GetCardInfo()对应于标准外设库的 SD_GetCardInfo()。此函数修改为:
DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
{
DRESULT res = RES_ERROR;
SD_CardInfo CardInfo;
if (Stat & STA_NOINIT) return RES_NOTRDY;
switch (cmd)
{/* Make sure that no pending write process */
case CTRL_SYNC :
res = RES_OK;
break;
/* Get number of sectors on the disk (DWORD) */
case GET_SECTOR_COUNT :
SD_GetCardInfo(&CardInfo);
*(DWORD*)buff = CardInfo.CardCapacity / BLOCK_SIZE;
res = RES_OK;
break;
/* Get R/W sector size (WORD) */
case GET_SECTOR_SIZE :
*(WORD*)buff = BLOCK_SIZE;
res = RES_OK;
break;
/* Get erase block size in unit of sector (DWORD) */
case GET_BLOCK_SIZE :
*(DWORD*)buff = BLOCK_SIZE;
break;
default:
res = RES_PARERR;
}
return res;
}
至此,编译可通过, FatFs 的移植已算完成。接下来,是修改测试代码。  


使用特权

评论回复
11
从此不早朝|  楼主 | 2022-5-5 14:36 | 只看该作者
7) 修改 main.c。参考\STM32Cube_FW_F4_V1.11.0\Projects\STM324x9I_EVAL\Applications\FatFs\FatFs_uSD\Src\main.c,
修改此文件,如下:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/** @addtogroup STM32F4xx_StdPeriph_Examples
* @{
*/
/** @addtogroup SDIO_uSDCard
* @{
*/
/* Private typedef -----------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/
FATFS SDFatFs; /* File system object for SD card logical drive */
FIL MyFile; /* File object */
char SDPath[4]; /* SD card logical drive path */
/* Private function prototypes -----------------------------------------------*/
static void NVIC_Configuration(void);
static void Error_Handler(void);
/* Private functions ---------------------------------------------------------*/
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Main program
* @param None
* @retval None
*/
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
files (startup_stm32f40_41xxx.s/startup_stm32f427_437xx.s)
before to branch to application main. To reconfigure the default setting
of SystemInit() function, refer to system_stm32f4xx.c file
*/
FRESULT res; /* FatFs function common result
code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "STM32 with FatFs demo [url=home.php?mod=space&uid=72445]@[/url] std lib"; /* File write buffer */
uint8_t rtext[100]; /* File read buffer */
/* Initialize LEDs available on EVAL board */
STM_EVAL_LEDInit(LED1);
STM_EVAL_LEDInit(LED3);
/* NVIC Configuration */
NVIC_Configuration();
/*##-1- Link the micro SD disk I/O driver ##################################*/
if(FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
{
/*##-2- Register the file system object to the FatFs module ##############*/
if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) != FR_OK)
{
/* FatFs Initialization Error */
Error_Handler();
}
else
{
/*##-3- Create a FAT file system (format) on the logical drive #########*//* WARNING: Formatting the uSD card will delete all content on the device */
if(f_mkfs((TCHAR const*)SDPath, 0, 0) != FR_OK)
{
/* FatFs Format Error */
Error_Handler();
}
else
{
/*##-4- Create and Open a new text file object with write access #####*/
if(f_open(&MyFile, "STM32STD.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
/* 'STM32STD.TXT' file Open for write Error */
Error_Handler();
}
else
{
/*##-5- Write data to the text file ################################*/
res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);
if((byteswritten == 0) || (res != FR_OK))
{
/* 'STM32STD.TXT' file Write or EOF Error */
Error_Handler();
}
else
{
/*##-6- Close the open text file #################################*/
f_close(&MyFile);
/*##-7- Open the text file object with read access ###############*/
if(f_open(&MyFile, "STM32STD.TXT", FA_READ) != FR_OK)
{
/* 'STM32STD.TXT' file Open for read Error */
Error_Handler();
}
else
{
/*##-8- Read data from the text file ###########################*/
res = f_read(&MyFile, rtext, sizeof(rtext), (UINT*)&bytesread);
if((bytesread == 0) || (res != FR_OK))
{
/* 'STM32STD.TXT' file Read or EOF Error */
Error_Handler();
}
else
{
/*##-9- Close the open text file #############################*/
f_close(&MyFile);/*##-10- Compare read data with the expected data ############*/
if((bytesread != byteswritten))
{
/* Read data is different from the expected data */
Error_Handler();
}
else
{
/* Success of the demo: no error occurrence */
STM_EVAL_LEDOn(LED1);
}
}
}
}
}
}
}
}
/*##-11- Unlink the micro SD disk I/O driver ###############################*/
FATFS_UnLinkDriver(SDPath);
/* Infinite loop */
while (1)
{
}
}
/**
* @brief Configures SDIO IRQ channel.
* @param None
* @retval None
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&NVIC_InitStructure);}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* Turn LED3 on */
STM_EVAL_LEDOn(LED3);
while(1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif

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



使用特权

评论回复
12
从此不早朝|  楼主 | 2022-5-5 14:38 | 只看该作者
3.3.测试
1) 连接 STM32439I-EVAL PC
2) 打开工程,下载代码并运行, LED1 点亮,代表运行通过。
3) SD 卡从 STM32439I-EVAL 取出,放入 PC 进行读取,可见:

4) 打开 STM32STD.TXT,可见:

5) 测试结果:成功。



使用特权

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

使用特权

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

使用特权

评论回复
15
Uriah| | 2022-10-7 09:14 | 只看该作者

访问时采用不同的指令,所以并不会占用 RAM 空间

使用特权

评论回复
16
Bblythe| | 2022-10-7 12:13 | 只看该作者

51 单片机不使用线性编址

使用特权

评论回复
17
Pulitzer| | 2022-10-7 15:12 | 只看该作者

128以上的某些地址为特殊寄存器使用,不能给程序用

使用特权

评论回复
18
vivilyly| | 2023-2-2 11:07 | 只看该作者
如何用stm32cubemx 设置 FLASH读写配置

使用特权

评论回复
19
bartonalfred| | 2023-2-4 14:33 | 只看该作者
FatFS文件系统中如何创建和批量命名文件?

使用特权

评论回复
20
cemaj| | 2023-2-5 13:46 | 只看该作者
STM32通过USB的方式控制tf卡原理是什么?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

185

帖子

0

粉丝