查看: 1808|回复: 0
收起左侧

第二十六章:CH32V103应用教程——FATFS文件系统(SD卡)

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-25 21:27:05 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 17:10 编辑

    本章教程将使用FATFS文件系统来管理SD卡,实现对SD卡文件读写等基本功能。


    1、FATFS简介及相关函数介绍

    FATFS 是一种免费开源的、且面向小型嵌入式系统的一种通用FAT文件系统。其采用标准C语言编写并完全独立于底层I/O介质,具有良好的硬件平**立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM 等系列单片机上而只需做简单的修改。它支持 FATl2、FATl6和FAT32等格式,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。

    本章教程在上一章SD卡教程的基础上,将FATFS文件系统代码移植到SD卡工程中,并对其进行读写测试。关于FATFS文件系统源码可从FATFS官网进行下载。

    FATFS源码文件夹src文件夹主要包含以下几个文件:

    • option文件夹下文件为一些可选外部c文件,包含多语言支持需要用到的文件和转换函数;
    • diskio.c文件是 FATFS移植最关键的文件,它为文件系统提供了最底层的访问SD卡SPI接口的方法。其包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。
    • diskio.h定义了FATFS用到的宏,以及diskio.c文件内与底层硬件接口相关的函数声明。
    • integer.h文件中包含了一些数值类型定义。
    • ff.c文件是FATFS核心文件,是文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。
    • ffconf.h这个头文件包含了对FATFS功能配置的宏定义, 通过修改这些宏定义就可以裁剪FATFS的功能。

    关于FATFS文件系统模块的移植,我们只需把上述几个文件添加到SD卡工程中并进行一些修改即可。


    2、硬件设计

    本章教程主要在SD卡基础上进行FATFS文件系统模块的移植,所需资源与上一章一致。


    3、软件设计

    本章教程在上一章SD卡测试基础上进行FATFS文件系统模块的移植,将FATFS源码文件夹下文件添加工工程之后,只需进行以下修改即可:

    1、由于本款开发板芯片ROM容量限制原因,option文件夹中选用文件ccsbcs.c文件;

    2、对ffconf.h文件进行以下修改:

    • #define _USE_MKFS  1,这个用来定时是否使能格式化,本章需要用到,所以设置这里为1。
    • #define _CODE_PAGE 437,此选项指定要在目标系统上使用的OEM代码页,错误的代码页设置可能会导致文件打开失败,此处选择U.S.,语言类型选择为英文,437,此处需要和ccsbcs.c文件同步使用;
    • #define _USE_LFN   1,该选项用于设置是否支持长文件名(还需要_CODE_PAGE 支持),取值范围为 0~3。0,表示不支持长文件名,1~3 是支持长文件名,但是存储地方不一样,我们选择使用1,通过启用BSS上的静态工作缓冲区启用LFN;
    • #define _VOLUMES   2,用于设置FATFS支持的逻辑设备数目,我们设置为 2,即支持2个设备;
    • #define _MIN_SS    512,指定扇区缓冲最小值;
    • #define _MAX_SS   4096,指定扇区缓冲最大值。

    3、关于diskio.c文件,其具体程序如下:

    1. #include "diskio.h"
    2. #include "sd.h"
    3. #include "malloc.h"


    4. #define SD_CARD  0  //SD卡,卷标为0
    5. #define EX_FLASH 1  //外部flash,卷标为1

    6. #define FLASH_SECTOR_SIZE   512

    7. //初始化磁盘
    8. DSTATUS disk_initialize (
    9.     BYTE pdrv               /* Physical drive nmuber (0..) */
    10. )
    11. {
    12.     u8 res=0;
    13.     switch(pdrv)
    14.     {
    15.         case SD_CARD://SD卡
    16.             res = SD_Initialize();//SD_Initialize()
    17.             if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
    18.             {
    19.                 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
    20.             }
    21.             break;
    22.         case EX_FLASH://外部flash
    23.             break;
    24.         default:
    25.             res=1;
    26.     }
    27.     if(res)return  STA_NOINIT;
    28.     else return 0; //初始化成功
    29. }

    30. //获得磁盘状态
    31. DSTATUS disk_status (
    32.     BYTE pdrv       /* Physical drive nmuber (0..) */
    33. )
    34. {
    35.     return 0;
    36. }

    37. //读扇区
    38. //drv:磁盘编号0~9
    39. //*buff:数据接收缓冲首地址
    40. //sector:扇区地址
    41. //count:需要读取的扇区数
    42. DRESULT disk_read (
    43.     BYTE pdrv,      /* Physical drive nmuber (0..) */
    44.     BYTE *buff,     /* Data buffer to store read data */
    45.     DWORD sector,   /* Sector address (LBA) */
    46.     UINT count      /* Number of sectors to read (1..128) */
    47. )
    48. {
    49.     u8 res=0;
    50.     if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
    51.     switch(pdrv)
    52.     {
    53.         case SD_CARD://SD卡
    54.             res=SD_ReadDisk(buff,sector,count);
    55.             if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
    56.             {
    57.                 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
    58.             }
    59.             break;
    60.         case EX_FLASH://外部flash
    61.             res=0;
    62.             break;
    63.         default:
    64.             res=1;
    65.     }
    66.    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    67.     if(res==0x00)return RES_OK;
    68.     else return RES_ERROR;
    69. }

    70. //写扇区
    71. //drv:磁盘编号0~9
    72. //*buff:发送数据首地址
    73. //sector:扇区地址
    74. //count:需要写入的扇区数
    75. #if _USE_WRITE
    76. DRESULT disk_write (
    77.     BYTE pdrv,          /* Physical drive nmuber (0..) */
    78.     const BYTE *buff,   /* Data to be written */
    79.     DWORD sector,       /* Sector address (LBA) */
    80.     UINT count          /* Number of sectors to write (1..128) */
    81. )
    82. {
    83.     u8 res=0;
    84.     if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
    85.     switch(pdrv)
    86.     {
    87.         case SD_CARD://SD卡
    88.             res=SD_WriteDisk((u8*)buff,sector,count);
    89.             break;
    90.         case EX_FLASH://外部flash
    91.             res=0;
    92.             break;
    93.         default:
    94.             res=1;
    95.     }
    96.     //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    97.     if(res == 0x00)return RES_OK;
    98.     else return RES_ERROR;
    99. }
    100. #endif


    101. //其他表参数的获得
    102. //drv:磁盘编号0~9
    103. //ctrl:控制代码
    104. //*buff:发送/接收缓冲区指针
    105. #if _USE_IOCTL
    106. DRESULT disk_ioctl (
    107.     BYTE pdrv,      /* Physical drive nmuber (0..) */
    108.     BYTE cmd,       /* Control code */
    109.     void *buff      /* Buffer to send/receive control data */
    110. )
    111. {
    112.     DRESULT res;
    113.     if(pdrv==SD_CARD)//SD卡
    114.     {
    115.         switch(cmd)
    116.         {
    117.             case CTRL_SYNC:
    118.                 SD_CS_L;
    119.                 if(SD_WaitReady()==0)res = RES_OK;
    120.                 else res = RES_ERROR;
    121.                 SD_CS_H;
    122.                 break;
    123.             case GET_SECTOR_SIZE:
    124.                 *(WORD*)buff = 512;
    125.                 res = RES_OK;
    126.                 break;
    127.             case GET_BLOCK_SIZE:
    128.                 *(WORD*)buff = 8;
    129.                 res = RES_OK;
    130.                 break;
    131.             case GET_SECTOR_COUNT:
    132.                 *(DWORD*)buff = SD_GetSectorCount();
    133.                 res = RES_OK;
    134.                 break;
    135.             default:
    136.                 res = RES_PARERR;
    137.                 break;
    138.         }
    139.     }
    140.     else res=RES_ERROR;//其他的不支持
    141.     return res;
    142. }
    143. #endif
    144. //获得时间
    145. //User defined function to give a current time to fatfs module      */
    146. //31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
    147. //15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
    148. DWORD get_fattime (void)
    149. {
    150.     return 0;
    151. }
    复制代码
    diskio.c文件主要进行磁盘初始化以及进行获取磁盘状态和读写扇区等操作;

    4、关于main.c文件
    1. /********************************** (C) COPYRIGHT *******************************
    2. * File Name          : main.c
    3. * Author             : WCH
    4. * Version            : V1.0.0
    5. * Date               : 2020/04/30
    6. * Description        : Main program body.
    7. *******************************************************************************/
    8. #include "debug.h"
    9. #include "spi.h"
    10. #include "sd.h"
    11. #include "ff.h"


    12. //定义变量
    13. FATFS fs;                     /* FatFs文件系统对象 */
    14. FIL fnew;                     /* 文件对象 */
    15. FRESULT res_sd;               /* 文件操作结果 */
    16. UINT fnum;                    /* 文件成功读写数量 */
    17. BYTE ReadBuffer[1024]={0};    /* 读缓冲区 */
    18. BYTE WriteBuffer[] =          /* 写缓冲区*/
    19. "欢迎使用沁恒CH32V103开发板,新建文件系统测试文件\r\n";

    20. /*******************************************************************************
    21. * Function Name  : main
    22. * Description    : Main program.
    23. * Input          : None
    24. * Return         : None
    25. *******************************************************************************/
    26. int main(void)
    27. {
    28.     u32 sd_size;

    29.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    30.     Delay_Init();
    31.         USART_Printf_Init(115200);

    32.         printf("SystemClk:%d\r\n",SystemCoreClock);
    33.         printf("This is SD FATFS example\r\n");

    34.         if(SD_Detect()==0)
    35.         {
    36.             printf("未检测SD卡插入!\n");
    37.         }
    38.         else
    39.         {
    40.             printf("已检测SD卡插入!\n");

    41.             if(SD_Initialize())
    42.             {
    43.                 printf("SD卡初始化出错,请检查!!\n");
    44.                 Delay_Ms(500);
    45.             }
    46.             else
    47.             {
    48.                 printf("SD卡初始化完成!\n");
    49.                 sd_size=SD_GetSectorCount();//得到扇区数
    50.                 printf("SD Card Size(MB):%d\n",sd_size>>11);
    51.             }
    52.         }

    53.     //在外部SPI SD挂载文件系统,文件系统挂载时会对SPI设备初始化
    54.     res_sd = f_mount(&fs,"0:",1);

    55.     /*----------------------- 格式化测试 ---------------------------*/
    56.         /* 如果没有文件系统就格式化创建创建文件系统 */
    57.         if(res_sd == FR_NO_FILESYSTEM)
    58.         {
    59.             printf("》SD卡还没有文件系统,即将进行格式化...\r\n");
    60.         /* 格式化 */
    61.             res_sd=f_mkfs("0:",0,0);

    62.             if(res_sd == FR_OK)
    63.             {
    64.                 printf("》SD卡已成功格式化文件系统。\r\n");
    65.           /* 格式化后,先取消挂载 */
    66.                 res_sd = f_mount(NULL,"0:",1);
    67.           /* 重新挂载   */
    68.                 res_sd = f_mount(&fs,"0:",1);
    69.             }
    70.             else
    71.             {
    72.                 printf("《《格式化失败。》》res_sd =%d\r\n",res_sd);
    73.                 while(1);
    74.             }
    75.         }
    76.       else if(res_sd!=FR_OK)
    77.       {
    78.         printf("!!SD卡挂载文件系统失败。(%d)\r\n",res_sd);
    79.         printf("!!可能原因:SD卡初始化不成功。\r\n");
    80.             while(1);
    81.       }
    82.       else
    83.       {
    84.         printf("》文件系统挂载成功,可以进行读写测试\r\n");
    85.       }
    86.         /*----------------------- 文件系统测试:写测试 -----------------------------*/
    87.             /* 打开文件,如果文件不存在则创建它 */
    88.             printf("\r\n****** 即将进行文件写入测试... ******\r\n");
    89.             res_sd = f_open(&fnew, "0:FatFs读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
    90.             if ( res_sd == FR_OK )
    91.             {
    92.                 printf("》打开/创建FatFs读写测试文件.txt文件成功,向文件写入数据。\r\n");
    93.             /* 将指定存储区内容写入到文件内 */
    94.                 res_sd=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
    95.             if(res_sd==FR_OK)
    96.             {
    97.               printf("》文件写入成功,写入字节数据:%d\n",fnum);
    98.               printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer);
    99.             }
    100.             else
    101.             {
    102.               printf("!!文件写入失败:(%d)\n",res_sd);
    103.             }
    104.                 /* 不再读写,关闭文件 */
    105.             f_close(&fnew);
    106.             }
    107.             else
    108.             {
    109.                 printf("!!打开/创建文件失败。\r\n");
    110.             }

    111.         while(1)
    112.     {
    113.         }
    114. }

    复制代码
    main.c文件主要进行相关函数初始化以及读取输出相关信息。


    4、下载验证

    将编译好的程序下载到开发板并复位,当未插入SD卡时,串口打印情况具体如下:
    CH32V CH573单片机芯片-第二十六章:CH32V103应用教程——FATFS文件系统(SD卡)risc-v单片机中文社区(1)

    插入SD卡并复位后,串口打印情况如下:
    CH32V CH573单片机芯片-第二十六章:CH32V103应用教程——FATFS文件系统(SD卡)risc-v单片机中文社区(2)

    FATFS.rar附件下载
    CH32V CH573单片机芯片-第二十六章:CH32V103应用教程——FATFS文件系统(SD卡)risc-v单片机中文社区(3) 25、FATFS.rar (715.64 KB, 下载次数: 29)
    链接:https://pan.baidu.com/s/1jaXEXdeeosZ54ArMM3w5Hw
    提取码:y4x4
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第二十五章:CH32V103应用教程——SD卡测试
    下一篇:第二十七章:CH32V103应用教程——DMA(存储器到外设)
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-26 18:38 , Processed in 0.740701 second(s), 48 queries .

    快速回复 返回顶部 返回列表