返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[MM32软件] 基于MM32F5270的SPI接口操作SD卡实现FatFs文件系统的移植

[复制链接]
3870|10
 楼主| 春娇霹雳娃 发表于 2023-6-21 17:08 | 显示全部楼层 |阅读模式
本帖最后由 春娇霹雳娃 于 2023-7-31 10:35 编辑

#申请原创# @21小跑堂
[payamount]10.00[/payamount]
[pay]
1.简介
本实验将展示如何基于MM32F5270的SPI接口操作SD卡,实现FatFs文件系统的移植
FatFs是一种可用于小型嵌入式系统的通用FAT/exFAT文件系统模块。FatFs模块是按照ANSIC(C89)编写的,并且与磁盘I/O层完全分开。FatFs独立于平台。可以并入资源有限的小型微控制器中。
FatFS官方下载网址:http://elm-chan.org/fsw/ff/00index_e.html

1.1 FatFs features
  • DOS / Windows兼容的FAT / exFAT文件系统。
  • 与平台无关,易于移植。
  • 程序代码和工作区的占用空间非常小
  • 支持以下各种配置选项:
  • ANSI / OEM或Unicode中的长文件名
  • exFAT文件系统,64位LBA和GPT可存储大量数据
  • RTOS的线程安全
  • 多个卷(物理驱动器和分区,最多10个卷)
  • 可变扇区大小
  • 多个代码页,包括DBCS
  • 只读,可选API,I / O缓冲区等

1.2 FatFs层级结构
  • 底层接口:包括存储媒介读/写接口和供给文件创建修改时间的实时时钟,需要根据平台和存储介质编写移植代码
  • 中间层 FatFs 模块:实现文件读/写协议,FatFs 模块提供 ff.c 和 ff.h ,一般不用修改,将头文件直接包含进去即可
  • 最顶层应用层
618506492c25161702.png

1.3 FatFs API
常用的函数如下表所示:
592116492cab981e92.png

1.2 设计思路
整个实验设计框架如下图所示:
616936492c03be74ca.png

2.实验环境
2.1 硬件环境
  • MM32F5277E9P开发板
  • JLink v11.0
  • SD卡 8GB一张
264056497dd29f2f44.png

2.2 软件环境
  • Tera Term串口终端软件
  • KEIL v5.37
  • SDK软件包

3.实验流程

3.1下载文件系统源文件
登录FatFS官网下载资源:
509066492c0e2cd05f.png

下载后解压文件夹,会有下图所示三个文件:
412276497db0a09335.png
  • documents文件夹是官方的文档文件
  • source文件是源文件

打开source文件夹可见下图所示内容:
755876498f238b999e.png

各文件功能如下图所示:
272286498f70de46b9.png

源文件:
  • diskio.c:包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。
  • ff.c:FatFs 核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。

3.2移植FatFs文件系统

将源文件放进componets组件中:
553806498fdfcdfbb9.png
KEIL工程添加ff14b组:
19576498ff5954ca4.png

将diskio_sdspi.c(原名diskio.c)放到板级:
581856498fff8bf7b2.png

KEIL中添加头文件路径:
250436498fefc13bf4.png

最终工程结构如下:
4971649904acc5210.png

适配diskio_sdspi.c文件:
  1. <font face="Arial">#include "ff.h"         /* Obtains integer types */
  2. #include "diskio.h"     /* Declarations of disk functions */
  3. #include "sdspi.h"

  4. /* Definitions of physical drive number for each drive */
  5. #define DEV_RAM     0   /* Example: Map Ramdisk to physical drive 0 */
  6. #define DEV_MMC     1   /* Example: Map MMC/SD card to physical drive 1 */
  7. #define DEV_USB     2   /* Example: Map USB MSD to physical drive 2 */

  8. SDSPI_ApiRetStatus_Type app_sdspi_ret;
  9. SDSPI_CardHandler_Type app_sdspi_card;
  10. extern const SDSPI_Interface_Type sdspi_if;
  11. /*-----------------------------------------------------------------------*/
  12. /* Get Drive Status                                                      */
  13. /*-----------------------------------------------------------------------*/
  14. DSTATUS disk_status (
  15.     BYTE pdrv       /* Physical drive nmuber to identify the drive */
  16. ){
  17.     DSTATUS stat = 0u;
  18.     //int result;
  19.     switch (pdrv) {
  20.     case DEV_RAM :
  21.         //result = RAM_disk_status();
  22.         //translate the reslut code here

  23.         return stat;

  24.     case DEV_MMC :
  25.         //result = MMC_disk_status();
  26.         stat = RES_OK;
  27.         // translate the reslut code here

  28.         return stat;

  29.     case DEV_USB :
  30.         //result = USB_disk_status();
  31.         // translate the reslut code here
  32.         return stat;}
  33.     return STA_NOINIT;}
  34. </font>

Inidialize a Drive,Read Sector(s),Write Sector(s)等函数,也做一样的修改。

4.样例
4.1fatfs sdspi basic样例

用户通过串口输入字符,根据字符决定装载,卸载 SD 卡,读写等内容。

主函数如下
  1. <font face="Arial">#include "board_init.h"
  2. #include "ffconf.h"
  3. #include "ff.h"

  4. FATFS fs;
  5. FIL fil;
  6. const TCHAR fs_drv[] = "1:/";
  7. const TCHAR filname[] = "1:/hello.txt";
  8. BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */
  9. UINT bw, br;
  10. #define FIL_BUFF_LEN 16u
  11. uint8_t fil_write_buff[FIL_BUFF_LEN];
  12. uint8_t fil_read_buff[FIL_BUFF_LEN];

  13. FRESULT fs_ret;

  14. uint8_t fil_write_seed = 0u;

  15. /*
  16. * Functions.
  17. */
  18. int main(void){
  19.     uint8_t c;

  20.     BOARD_Init();

  21.     printf("fatfs_basic\r\n");
  22.     printf("Press any key for help...\r\n");

  23.     while (1){
  24.         c = getchar();
  25.         switch (c){
  26.             case 'a':
  27.                 printf("a: f_mkfs().\r\n");
  28.             
  29.                 if ( !f_mkfs(fs_drv, 0u, work, sizeof(work)) ){
  30.                     printf("succ.\r\n");}
  31.                 else{
  32.                     printf("fail.\r\n");}
  33.                 break;

  34.             case 'b':
  35.                 printf("b: f_mount().\r\n");
  36.                 if( !f_mount(&fs, fs_drv ,1) ){
  37.                     printf("succ.\r\n");}
  38.                 else{
  39.                     printf("fail.\r\n");}
  40.                 break;

  41.             case 'c':
  42.                 printf("c: f_open() & f_write() & f_close().\r\n");
  43.                
  44.                 printf("f_open().\r\n");
  45.                 fs_ret = f_open(&fil, filname, FA_CREATE_NEW | FA_WRITE );
  46.                 if ( fs_ret != FR_OK ){
  47.                     printf("fail.\r\n");
  48.                     break;}
  49.                
  50.                 printf("f_write().\r\n");
  51.                
  52.                 sprintf((char *)fil_write_buff, "hi, %d\r\n", fil_write_seed++),

  53.                 fs_ret = f_write(&fil, fil_write_buff, FIL_BUFF_LEN, &bw);
  54.                 if (bw != FIL_BUFF_LEN){
  55.                     printf("fail.\r\n");
  56.                     
  57.                     f_close(&fil);
  58.                     break;}
  59.                
  60.                 printf("f_close().\r\n");
  61.                 f_close(&fil);
  62.                
  63.                 printf("succ.\r\n");

  64.                 break;
  65.                
  66.             case 'd':
  67.                 printf("d: f_open() & f_read() & f_close().\r\n");
  68.                
  69.                 printf("f_open().\r\n");
  70.                 fs_ret = f_open(&fil, filname, FA_READ );
  71.                 if ( fs_ret != FR_OK ){
  72.                     printf("fail.\r\n");
  73.                     break;}
  74.             
  75.                 printf("f_read()\r\n");
  76.                 fs_ret = f_read(&fil, fil_read_buff, FIL_BUFF_LEN, &br);
  77.                 if (br != FIL_BUFF_LEN){
  78.                     printf("fail.\r\n");
  79.                     
  80.                     f_close(&fil);
  81.                     break;}
  82.                
  83.                 for (uint32_t i  = 0u; i < FIL_BUFF_LEN; i++){
  84.                     printf("%c", fil_read_buff[i]);}
  85.                 printf("\r\n");
  86.                
  87.                 printf("f_close().\r\n");
  88.                 f_close(&fil);
  89.                 printf("succ.\r\n");
  90.                 break;
  91.                
  92.             case 'f':
  93.                 printf("f: f_unlink().\r\n");
  94.                 f_unlink(filname);
  95.                 printf("file removed.\r\n");

  96.                 break;
  97.                
  98.             default: /* help. */
  99.                 printf("\r\n");
  100.                 printf("a: f_mkfs().\r\n");
  101.                 printf("b: f_mount().\r\n");
  102.                 printf("c: f_open() & f_write() & f_close().\r\n");
  103.                 printf("d: f_open() & f_read() & f_close().\r\n");
  104.                 printf("f: f_unlink().\r\n");
  105.                 printf("\r\n");
  106.                 break;}}}</font>

串口可见输出结果:
18767649921dd47a5d.png

4.2fatfs sdspi listfiles样例

  • 装载 SD 卡
  • 显示文件列表
  • 显示文件大小

主函数如下:
  1. <font face="Arial">/*
  2. * Variables.
  3. */
  4. FATFS fs;
  5. const TCHAR fs_drv[] = "1:/";
  6. TCHAR fs_path[256] = "\0";

  7. /*
  8. * Declerations.
  9. */
  10. FRESULT app_fatfs_listfiles(const char * dir_path);

  11. /*
  12. * Functions.
  13. */
  14. int main(void){
  15.     BOARD_Init();

  16.     printf("\r\app_fatfs_listfiles() example.\r\n");
  17.    
  18.     /* f_mount().\r\n */
  19.     printf("f_mount(). ");
  20.     if( !f_mount(&fs, fs_drv ,1) ){
  21.         printf("succ.\r\n");}
  22.     else{
  23.         printf("fail.\r\n");
  24.         while (1)
  25.         {}}
  26.    
  27.     /* root dir. */
  28.     app_fatfs_listfiles(fs_drv);

  29.     /* dir0. */
  30.     fs_path[0] = '\0';
  31.     strcat(fs_path, fs_drv);
  32.     strcat(fs_path, "dir0/");
  33.     app_fatfs_listfiles(fs_path);

  34.     /* dir1. */
  35.     fs_path[0] = '\0';
  36.     strcat(fs_path, fs_drv);
  37.     strcat(fs_path, "dir1/");
  38.     app_fatfs_listfiles(fs_path);
  39.    
  40.     printf("app_fatfs_listfiles() done.\r\n");

  41.     while (1)
  42.     {}}

  43. /* list the file items under the indecated path. */
  44. FRESULT app_fatfs_listfiles(const char * dir_path){
  45.     FRESULT res;
  46.     FILINFO fno;
  47.     DIR dir;
  48.     char *fn;

  49.     printf("* %s ->\r\n", dir_path);

  50.     res = f_opendir(&dir, dir_path);
  51.     if (res != FR_OK){
  52.         return res;}

  53.     for (;;){
  54.         /* read iterator. */
  55.         res = f_readdir(&dir, &fno);
  56.         if ( (res != FR_OK) || (fno.fname[0] == 0) ){
  57.             break;}

  58.         /* skip the "self" and "father" dir item. */
  59.         if (fno.fname[0] == '.') {
  60.             continue;}

  61.         /* collect the dir or file name. */
  62.         fn = fno.fname;
  63.         if (fno.fattrib & AM_DIR) /* dir name. */{
  64.             printf("\t%s/\r\n", fn);}
  65.         else /* file name */{
  66.             printf("\t%s: %u B\r\n", fn, (unsigned)fno.fsize);}}

  67.     /* close the opened dir to reest the iterator. */
  68.     res = f_closedir(&dir);
  69.     return res;}
  70. </font>

串口可见输出结果:
342316499215a08bd9.png

5.配置SPI部分
源文件为软件SPI,如有需求可优化为硬件SPI。
5.1开启时钟
在clock_init.c中开启SPI3时钟
766746499255ca93f4.png

5.2配置引脚
在pin_init.c中配置SPI3引脚
67867649925ead9b4a.png

5.3配置sdspi_port.c文件
  1. #include "board_init.h"
  2. #include "sdspi.h"
  3. #include "hal_spi.h"

  4. SDSPI_ApiRetStatus_Type sdspi_spi_init(void);
  5. SDSPI_ApiRetStatus_Type sdspi_spi_freq(uint32_t hz);
  6. SDSPI_ApiRetStatus_Type sdspi_spi_xfer(uint8_t *in, uint8_t *out, uint32_t len);

  7. const SDSPI_Interface_Type board_sdspi_if ={
  8.     .baudrate = 1000000u, /* 1mhz. */
  9.     .spi_init = sdspi_spi_init,
  10.     .spi_freq = sdspi_spi_freq,
  11.     .spi_xfer = sdspi_spi_xfer};

  12. uint32_t board_sdspi_delay_count;
  13. static void board_sdspi_delay(uint32_t count){
  14.     for (uint32_t i = count; i > 0u; i--){
  15.         __NOP();}}

  16. SDSPI_ApiRetStatus_Type sdspi_spi_init(void){
  17.     GPIO_WriteBit(BOARD_SDSPI_CS_GPIO_PORT , BOARD_SDSPI_CS_GPIO_PIN , 1u);
  18.    
  19.     /* Setup SPI module. */
  20.     SPI_Master_Init_Type spi_init;
  21.     spi_init.ClockFreqHz = CLOCK_APB1_FREQ;
  22.     spi_init.BaudRate = SDMMC_CLOCK_400KHZ;
  23.     spi_init.XferMode = SPI_XferMode_TxRx;
  24.     spi_init.PolPha = SPI_PolPha_Alt2;
  25.     spi_init.DataWidth = SPI_DataWidth_8b;
  26.     spi_init.LSB = false;
  27.     spi_init.AutoCS = true;
  28.     SPI_InitMaster(SPI3, &spi_init);
  29.    
  30.     /* Enable SPI. */
  31.     SPI_Enable(SPI3, true);

  32. //    board_sdspi_delay_count = 100u;
  33.     return SDSPI_ApiRetStatus_Success;}

  34. void SPI_SetBaudRate(SPI_Type * SPIx, uint32_t src_clk, uint32_t baudrate){
  35.     uint32_t div = src_clk / baudrate;
  36.     if (div < 2u){
  37.         /* div = 0, 1 is not allowed. */
  38.         div = 2u;}

6.附件
fatfs sdspi listfiles样例: plus-f5270_fatfs_sdspi_basic_mdk.zip (3.21 MB, 下载次数: 9)
fatfs sdspi listfiles样例: plus-f5270_fatfs_sdspi_listfiles_mdk.zip (3.21 MB, 下载次数: 10)


[/pay]

  
  

打赏榜单

21小跑堂 打赏了 100.00 元 2023-06-28
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

基于MM32F5270的SPI接口操作SD卡实现FatFs文件系统的移植,原理介绍详细,实现过程完整,文章层次清晰,感谢分享  发表于 2023-6-28 10:34
xld0932 发表于 2023-6-28 10:39 | 显示全部楼层
woai32lala 发表于 2023-7-1 10:04 | 显示全部楼层
yangxiaor520 发表于 2023-7-1 11:19 来自手机 | 显示全部楼层
越来有ST的味道了
 楼主| 春娇霹雳娃 发表于 2023-7-1 12:41 | 显示全部楼层
 楼主| 春娇霹雳娃 发表于 2023-7-1 12:42 | 显示全部楼层
chenqianqian 发表于 2023-7-4 07:53 来自手机 | 显示全部楼层
学习了,讲解详细。
 楼主| 春娇霹雳娃 发表于 2023-7-4 09:54 | 显示全部楼层
lmn2005 发表于 2023-7-4 11:44 | 显示全部楼层
很不错,值得学习。
 楼主| 春娇霹雳娃 发表于 2023-7-4 11:54 | 显示全部楼层
lmn2005 发表于 2023-7-4 11:44
很不错,值得学习。

谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:灵动系统开发工程师
简介:none........

19

主题

154

帖子

3

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