打印
[其他ST产品]

【正点原子K210连载】第二十二章 FATFS实验《DNK210使用指南-SDK版》

[复制链接]
267|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
第二十二章 FATFS实验


上一章,我们学习了SD卡的使用,并实现了简单的读写扇区功能。在电脑上我们的资料常以文件的形式保存,通过文件名我们可以快速自己的文件数据等进行分类对于SD种容量可以达到非常大的存储介质,扇区去管理数据已经变得不方便,我希望片机也可以像电脑一样方便地用文件的形式去管理,在需要数据采集的场合也会加便利。
本章,我们将介绍FATFS软件工具,利用它在Kendryte K210上实现类似电脑上的文件管理功能,方便管理SD卡上的数据
本章分为如下几个小节:
22.1 FATFS简介
22.2 硬件设计
22.3 程序设计
22.4 运行验证


22.1 FATFS简介
FATFS是一个完全免费开源的FAT/exFAT文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C语言(ANSI C C89编写,所以具有良好的硬件平**立性,只需做简单的修改就可以移植到8051PICAVRARMZ80RX等系列单片机上。它支持FATl2FATl6FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。FATFS的特点有:
l Windows/dos系统兼容的FAT/exFAT文件系统
l 独立于硬件平台,方便跨硬件平台移植
l 代码量少、效率高
l 多种配置选项
l 支持多卷(物理驱动器或分区,最多10个卷)
l 多个ANSI/OEM代码页包括DBCS
l 支持长文件名、ANSI/OEM或Unicode
l 支持RTOS
l 支持多种扇区大小
l 只读、最小化的API和I/O缓冲区等
l 新版的exFAT文件系统,突破了原来FAT32对容量管理32Gb的上限可支持更巨大的存储
FATFS的这些特点,加上免费、开源的原则,使得FATFS应用非常广泛。FATFS模块的层次结构如图22.1.1所示
图22.1.1 FATFS层次结构图
最顶层是应用层,使用者无需理会FATFS的内部结构和复杂的FAT协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_openf_readf_writef_close等,就可以像在PC上读/写文件那样简单。
中间层FATFS模块,实现了FAT文件读/写协议。FATFS模块提供的是ff.cff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
需要我们编写移植代码的是FATFS模块提供的底层接口,它包括存储媒介读/写接口(diskI/O)和供给文件创建修改时间的实时时钟。
FATFS的源码及英文详述,大家可以在:http://elm-chan.org/fsw/ff/00index_e.html这个网站下载到,教程目前使用的版本为R0.15。本章我们就使用最新版本的FATFS作为介绍,下载最新版本的FATFS软件包,解压后可以得到两个文件夹:docsrcdoc里面主要是对FATFS的介绍,而src里面才是我们需要的源码。source文件夹详情表,如表22.1.1.1所示:
文件
作用简述
备注
diskio.h
FATFSdiskI/O模块公用的包含文件
与硬件平台无关
ff.c
FATFS模块
ff.h
FATFS和应用模块公用的包含文件
ffconf.h
FATFS模块配置文件,宏定义对应的功能,代码中都有说明,具体的配置范围可以见官方配置说明http://elm-chan.org/fsw/ff/doc/config.html
ffsystem.c
根据是否有操作系统修改这个文件
ffunicode.c
可选,根据ffconf.h的配置,进行Unicode编码转换
diskio.c
FATFSdiskI/O模块接口层文件,需要根据硬件修改这部分的代码
硬件平台相关代码
表22.1.1.1 FATFS的源码文件介绍
FATFS模块在移植的时候,我们一般只需要修改2个文件,即ffconf.hdiskio.cFATFS模块的所有配置项都是存放在ffconf.h里面,我们可以通过配置里面的一些选项,来满足自己的需求。接下来我们介绍几个重要的配置选项。
1        FF_FS_TINY。这个选项在R0.07版本中开始出现,之前的版本都是以独立的C文件出现(FATFSTinyFATFS),有了这个选项之后,两者整合在一起了,使用起来更方便。我们使用FATFS,所以把这个选项定义为0即可。
2        FF _FS_READONLY。这个用来配置是不是只读,本章我们需要读写都用,所以这里设置为0即可。
3        FF _USE_STRFUNC。这个用来设置是否支持字符串类操作,比如f_putcf_puts等,本章我们需要用到,故设置这里为1
4        FF _USE_MKFS。用来定时是否使能格式化,本章需要用到,所以设置这里为1
5        FF _USE_FASTSEEK。这个用来使能快速定位,我们设置为1,使能快速定位。
6        FF _USE_LABEL。这个用来设置是否支持磁盘盘符(磁盘名字)读取与设置。我们设置为1,使能,就可以通过相关函数读取或者设置磁盘的名字了。
7        FF _CODE_PAGE。这个用于设置语言类型,包括很多选项(见FATFS官网说明),我们这里设置为936,即简体中文(GBK码,同一个文件夹下的ffunicode.c根据这个宏选择对应的语言设置)。
8        FF_USE_LFN。该选项用于设置是否支持长文件名(还需要_CODE_PAGE支持),取值范围为0~30,表示不支持长文件名,1~3是支持长文件名,但是存储地方不一样,我们选择使用3,通过ff_memalloc函数来动态分配长文件名的存储区域。
9        FF_VOLUMES。用于设置FATFS支持的逻辑设备数目,我们设置为2,即支持2个设备。
10FF_MAX_SS。扇区缓冲的最大值,一般设置为512
11FF_FS_EXFAT。新版本增加的功能,使用exFAT文件系统,用支持32Gb大存储。它们使用的是exFAT文件系统,使用它时必须要根据设置FF_USE_LFN这个参数的值以决定exFATs系统使用的存来自栈还是静态数组。
其他配置项,我们这里就不一一介绍了,FATFS的说明文档里面有很详细的介绍,大家自己阅读http://elm-chan.org/fsw/ff/doc/config.html即可。下面我们来讲讲FATFS的移植,FATFS的移植主要分为3步:
数据类型:在integer.h里面去定义好数据的类型。这里需要了解你用的编译器的数据类型,并根据编译器定义好数据类型。
配置:通过ffconf.h配置FATFS的相关功能,以满足你的需要。
函数编写:打开diskio.c,进行底层驱动编写,需要编写5个接口函数,如下图所示:
图22.1.2 diskio需要实现的函数
通过以下三步,我们即可完成对FATFS的移植。
第一步,我们使用的是VSCode,数据类型和integer.h里面定义的一致,所以此步,我们不需要做任何改动。
第二步,关于ffconf.h里面的相关配置,我们几乎没有做任何修改,将FF_STR_VOLUME_ID配置为2FF_FS_NORTC配置为1即可,其他的配置用默认配置。
第三步,因为FATFS模块完全与磁盘I/O层分开,因此需要下面的函数来实现底层物理磁盘的读写与获取当前时间。底层磁盘I/O模块并不是FATFS的一部分,并且必须由用户提供。这些函数一般有5个,在diskio.c里面。
首先是disk_initialize函数,该函数介绍如表22.1.2所示:
函数名称
disk_initialize
函数原型
DSTATUS disk_initialize(BYTE Drive)
功能描述
初始化磁盘驱动器
函数参数
Drive:指定要初始化的逻辑驱动器号,即盘符,应当取值0~9
返回值
函数返回一个磁盘状态作为结果,对于磁盘状态的细节信息,请参考disk_status函数
所在文件
ff.c
实例
disk_initialize(0);                /* 初始化驱动器0 */
注意事项
disk_initialize函数初始化一个逻辑驱动器为读/写做准备,函数成功时,返回值的STA_NOINIT标志被清零;
应用程序不应调用此函数,否则卷上的FAT结构可能会损坏;
如果需要重新初始化文件系统,可使用f_mount函数;
FatFs模块上卷注册处理时调用该函数可控制设备的改变;
此函数在FatFs挂在卷时调用,应用程序不应该在FatFs活动时使用此函数
表22.1.2 disk_initialize函数介绍
二个函数是disk_status函数,该函数介绍如表22.1.3所示:
函数名称
disk_status
函数原型
DRESULT disk_status (BYTE Drive)
功能描述
返回当前磁盘驱动器的状态
函数参数
Drive:指定要确认的逻辑驱动器号,即盘符,应当取值0~9
返回值
磁盘状态返回下列标志的组合,FatFs只使用STA_NOINITSTA_PROTECTED
STA_NOINIT:表明磁盘驱动未初始化,下面列出了产生该标志置位或清零的原因:
        置位:系统复位,磁盘被移除和磁盘初始化函数失败
        清零:磁盘初始化函数成功
STA_NODISK:表明驱动器中没有设备,安装磁盘驱动器后总为0
STA_PROTECTED:表明设备被写保护,不支持写保护的设备总为0,当STA_NODISK置位时非法
所在文件
ff.c
实例
disk_status(0);                /* 获取驱动器0的状态 */
表22.1.3 disk_status函数介绍
第三个函数是disk_read函数,该函数介绍如表22.1.4所示:
函数名称
disk_read
函数原型
DRESULT disk_read (BYTE Drive, BYTE* Buffer, DWORD SectorNumber, BYTE SectorCount)
功能描述
从磁盘驱动器上读取扇区
函数参数
Drive:指定逻辑驱动器号,即盘符,应当取值0~9
Buffer:指向存储读取数据字节数组的指针,需要为所读取字节数的大小,扇区统计的扇区大小是需要的
(注:FaFts指定的内存地址并不总是字对齐的,如果硬件不支持不对齐的数据传输,函数里需要进行处理)
SectorNumber:指定起始扇区的逻辑块(LBA)上的地址
SectorCount:指定要读取的扇区数,取值1~128
返回值
RES_OK(0):函数成功
RES_ERROR:读操作期间产生了任何错误且不能恢复它
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件
ff.c
表22.1.4 disk_read函数介绍
第四个函数是disk_write函数,该函数介绍如表22.1.5所示:
函数名称
disk_write
函数原型
DRESULT disk_write (BYTE Drive, const BYTE* Buffer, DWORD SectorNumber, BYTE SectorCount)
功能描述
向磁盘写入一个或多个扇区
函数参数
Drive:指定逻辑驱动器号,即盘符,应当取值0~9
Buffer:指向要写入字节数组的指针
(注:FaFts指定的内存地址并不总是字对齐的,如果硬件不支持不对齐的数据传输,函数里需要进行处理)
SectorNumber:指定起始扇区的逻辑块(LBA)上的地址
SectorCount:指定要写入的扇区数,取值1~128
返回值
RES_OK(0):函数成功
RES_ERROR:写操作期间产生了任何错误且不能恢复它
RES_WRPER:媒体被写保护
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件
ff.c
注意事项
只读配置中不需要此函数
表22.1.5 disk_write函数介绍
第五个函数是disk_ioctl函数,该函数介绍如表22.1.6所示:
函数名称
disk_ioctl
函数原型
DRESULT disk_ioctl (BYTE Drive, BYTE Command, void* Buffer)
功能描述
控制设备指定特性和除了读/写外的杂项功能
函数参数
Drive:指定逻辑驱动器号,即盘符,应当取值0~9
Command:指定命令代码
Buffer:指向参数缓冲区的指针,取决于命令代码,不使用时,指定一个NULL指针
返回值
RES_OK(0):函数成功
RES_ERROR:写操作期间产生了任何错误且不能恢复它
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件
ff.c
注意事项
CTRL_SYNC:确保磁盘驱动器已经完成了写处理,当磁盘I/O有一个写回缓存,立即刷新原扇区,只读配置下不适用此命令
GET_SECTOR_SIZE:返回磁盘的扇区大小,只用于f_mkfs()
GET_SECTOR_COUNT:返回可利用的扇区数,_MAX_SS ≥ 1024时可用
GET_BLOCK_SIZE:获得擦除块大小,只用于f_mkfs()
CTRL_ERASE_SECTOR:强制擦除一块的扇区,_USE_ERASE 0时可用
表22.1.6 disk_ioctl函数介绍
以上五个函数,我们将在软件设计部分一一实现。通过以上3个步骤,我们就完成了对FATFS的移植,就可以在我们的代码里面使用FATFS了。
FATFS提供了很多API函数,这些函数FATFS的自带介绍文件里面都有详细的介绍(包括参考代码),我们这里就不多说了。这里需要注意的是,在使用FATFS的时候,必须先通过f_mount函数注册一个工作区,才能开始后续API的使用,关于FATFS的介绍,我们就介绍到这里。大家可以通过FATFS自带的介绍文件进一步了解和熟悉FATFS的使用。
22.2 硬件设计
22.2.1 例程功能
1.开机的时候初始化SD卡,为SD卡注册一个工作区,然后读取SD卡的根目录信息并通过USB串口打印,最后FATFS文件系统卸载SD卡工作区,LCD模块上显示相关信息。
22.2.2 硬件资源
1. SD CARD
TF_MISO - IO26
TF_SCK - IO27
TF_MOSI - IO28
        TF_CS - IO29
2. LCD
        LCD_RD - IO34
        LCD_BL - IO35
        LCD_CS - IO36
        LCD_RST - IO37
        LCD_RS - IO38
        LCD_WR - IO39
        LCD_D0~LCD_D7 - SPI0_D0~SPI0_D7
22.2.3 原理图
本章实验内容,主要讲解FATFS文件系统的使用,无需关注原理图。
22.3 程序设计
22.3.1 FATFS驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。
diskio.c/.h为我们提供了规定好的底层驱动接的返回值。个函数需要使用到我们的硬件接口,所以需要把使用到的硬件驱动的头文件包进来。
#include "ff.h"         /* Obtains integer types */
#include "diskio.h"     /* Declarations of disk functions */
#include "../SDCARD/sdcard.h"
按照23.1的描述接下来我们来对几个接口进行补充实现。本章,我们用FATFS管理了1个磁盘:SD卡,我们设置DEV_SD0,对应到disk_read/disk_write函数里面。
/* Definitions of physical drive number for each drive */
#define DEV_SD 0
另外,diskio.c里面的函数,我们用磁盘编号(盘符/卷标)所对应的具体设备,比如,我们要在SD卡操作数据,就用磁盘编号0,然后通过switch来判断和操作SD卡,同时也方便其他磁盘的扩展。
1. disk_initialize函数
要使用一个外设首先要对它进行初始化,所以先看sd卡的初始化函数,其声明如下:
DSTATUS disk_initialize ( BYTE pdrv)
l 函数描述:
初始化指定编号的磁盘磁盘所指定的存储区使用每个磁盘进行初始化,那代码中直接根据编号调用硬件的始化接口即可这样也能保证代码的扩展,硬件的顺序可以根据自己的喜定义
l 函数形参:
形参1是FATFS管理的磁盘编号pdrv : 磁盘编号0~9们配置FF_VOLUMES为1来支持,因此磁盘编号只有0
代码实现
DSTATUS disk_initialize (
    BYTE pdrv               /* Physical drive nmuber to identify the drive */
)
{
    DSTATUS stat;
    int result;
    switch (pdrv) {
    case DEV_SD :
        result = sd_init();
        // translate the reslut code here
        if (result == 0)
        {
            stat = 0;
        }
        else
        {
            stat = STA_NOINIT;
        }
        return stat;
    }
    return STA_NOINIT;
}
l 函数返回值:
DSTATUS枚举类型的值,FATFS规定了自己的返回值来管理各接口函数的操作结果,方便后续函数的操作和判断,我们的定义:
/* Status of Disk Functions */
typedef BYTE    DSTATUS;
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT      0x01            /* Drive not initialized */
#define STA_NODISK      0x02            /* No medium in the drive */
#define STA_PROTECT     0x04            /* Write protected */
义时也写出各个参数的含义根据ff.c中的调用实例可知操作返回0才正常的状态,其它情况发生的话就需要结合硬件进行分析
2. disk_status函数
要使用一个外设首先要对它进行初始化,所以先看sdio的初始化函数,其声明如下:
DSTATUS disk_status (BYTE pdrv)
l 函数描述:
可以随时查询对应SD卡的状态。我们硬件初始化后就
l 函数形参:
形参1FATFS管理的磁盘编号pdrv : 磁盘编号0~9,我们配置FF_VOLUMES1来支持一个磁盘,因此可选值为0
了简单测试,所以我们没有加入硬件状态判断代码也不贴出来了。
l 函数返回值:
直接返回RES_OK
3. disk_read函数
disk_read实现直接从硬件接口读取数据,这个接口FATFS的其它读操作接口函数调用,其声明如下:
DRESULT disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
l 函数描述:
初始化指定编号的磁盘磁盘所指定的存储区
l 函数形参:
形参1是FATFS管理的磁盘编号pdrv : 磁盘编号0~9们配置FF_VOLUMES为1来支持,因此值为0
形参2buff指向要保存数据的存区域指针为字节类型。
形参3:sector为实际物理操作时要访问的扇区地址。
4:count为本次要读取的数据量,最长为unsigned int,读到的数量为字节数。
代码实现如下要根据我们定义的设备标号在swich-case中添加对应硬件的驱动:
DRESULT disk_read (
    BYTE pdrv,      /* Physical drive nmuber to identify the drive */
    BYTE *buff,     /* Data buffer to store read data */
    LBA_t sector,   /* Start sector in LBA */
    UINT count      /* Number of sectors to read */
)
{
    DRESULT res;
    int result;
    switch (pdrv) {
    case DEV_SD :
        // translate the arguments here
        // result = sd_read_sector_dma(buff, sector, count);
        result = sd_read_sector(buff, sector, count);
        // translate the reslut code here
        if (result == 0)
        {
            res = RES_OK;
        }
        else
        {
            res = RES_ERROR;
        }
        return res;
    }
    return RES_PARERR;
}
l 函数返回
DRESULT为枚举,diskio.h中有其定义,我们也引用如下:
/* Results of Disk Functions */
typedef enum {
    RES_OK = 0,     /* 0: Successful */
    RES_ERROR,      /* 1: R/W Error */
    RES_WRPRT,      /* 2: Write Protected */
    RES_NOTRDY,     /* 3: Not Ready */
    RES_PARERR      /* 4: Invalid Parameter */
} DRESULT;
根据返回的含义确操作结果即可
4. disk_write函数
disk_write实现直接从硬件接口读取数据,这个接口为FATFS的其它写操作接口函数调用,其声明如下:
DRESULT disk_write ( BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
l 函数描述:
初始化指定编号的磁盘磁盘所指定的存储区
l 函数形参:
形参1是FATFS管理的磁盘编号pdrv : 磁盘编号0~9们配置FF_VOLUMES为1来支持,因此值为0
形参2:buff指向要保存数据的存区域指针为字节类型。
形参3:sector为实际物理操作时要访问的扇区地址。
4:count为本次要读取的数据量,最长为unsigned int,读到的数量为字节数。
代码实现如下要根据我们定义的设备标号在switch-case中添加对应硬件的驱动:
DRESULT disk_write (
    BYTE pdrv,          /* Physical drive nmuber to identify the drive */
    const BYTE *buff,   /* Data to be written */
    LBA_t sector,       /* Start sector in LBA */
    UINT count          /* Number of sectors to write */
)
{
    DRESULT res;
    int result;
    switch (pdrv) {
    case DEV_SD :
        // translate the arguments here
        // result = sd_write_sector_dma((uint8_t *)buff, sector, count);
        result = sd_write_sector((uint8_t *)buff, sector, count);
        // translate the reslut code here
        if (result == 0)
        {
            res = RES_OK;
        }
        else
        {
            res = RES_ERROR;
        }
        return res;
    }
    return RES_PARERR;
}
l 函数返回
DRESULT为枚举型,diskio.h中有其定义编写读函数时已经介绍了注意要把返回值转成这个举类型的参数。
5. disk_ioctl函数
disk_ioctl实现一些控制命令,这个接口为FATFS提供一些硬件操作信息,其声明如下:
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff)
l 函数描述:
初始化指定编号的磁盘磁盘所指定的存储区
l 函数形参:
形参1是FATFS管理的磁盘编号pdrv : 磁盘编号0~9们配置FF_VOLUMES为1来支持,因此值为0
形参2:cmdFATFS义好的一些宏,用于访问硬盘设备的一些状态。们实现几个简单的操作接口,用于获取磁盘容量基础信息diskio.h中已经定义好了),为方便,我们先只实现几个标准的应用接口关于SDIO/MMC的一些扩展命令我们再根据需要进行支持。
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC           0         /* 完成挂起的写入过程(当FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT   1         /* 获取磁盘扇区数(当FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE    2         /*获取磁盘存储空间大小 (当FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE     3         /* 每个扇区块的大小 (当FF_USE_MKFS == 1) */
面是http://elm-chan.org/fsw/ff/doc/dioctl.html到的参数实现效果,我们也可以参考原有的disk_ioctl的实现来理解这几个参数。
命令
说明
CTRL_SYNC
确保设备已完成挂起的写入过程。如果磁盘I/O层或存储设备具有回写缓存,则必须立即将缓存数据提交到介质。如果对介质的每个写入操作都正常完成,则命令无任何动作
GET_SECTOR_COUNT
返回对应标号的硬盘的可用扇区数。此命令由f_mkfs\f_fdisk函数用于确定要创建的卷/分区的大小。使用时需要设置FF_USE_MKFS1
GET_SECTOR_SIZE
将用于读/写函数的扇区大小检索到buff指向的WORD变量中。有效扇区大小为512102420484096。只有在FF_MAX_SS>FF_MIN_SS执行此命令时。当FF_MAX_SS=FF_MIN_SS时,将***不会使用此命令,并且读/写函数必须仅在FF_MAX_SSbytes/扇区中工作。
GET_BLOCK_SIZE
将扇区单位中闪存介质的块大小以DWORD针存到buff中。允许的值为132768。如果擦除块大小未知或非闪存介质,则返回1。此命令仅由f_mkfs函数使用,并尝试对齐擦除块边界上的数据区域。使用时需要设置FF_USE_MKFS1
形参3 buff为void指针,根据命令的格式需要,对应的值转成对应的形式传给它。
参考原有的disk_ioctl的实现,我的函数实现如下。
DRESULT disk_ioctl (
    BYTE pdrv,      /* Physical drive nmuber (0..) */
    BYTE cmd,       /* Control code */
    void *buff      /* Buffer to send/receive control data */
)
{
    DRESULT res;
    int result;
    switch (pdrv) {
    case DEV_SD :
        // Process of the command for the RAM drive
        switch (cmd)
        {
            case CTRL_SYNC:
                result = 0;
                break;
            case GET_SECTOR_COUNT:
                *(DWORD *)buff = (cardinfo.SD_csd.DeviceSize + 1) << 10;
                result = 0;
                break;
            case GET_SECTOR_SIZE:
                *(WORD *)buff = cardinfo.CardBlockSize;
                result = 0;
                break;
            case GET_BLOCK_SIZE:
                *(DWORD *)buff = cardinfo.CardBlockSize;
                result = 0;
                break;
            default:
                result = 0xFF;
                break;
        }
        
        if (result == 0)
        {
            res = RES_OK;
        }
        else
        {
            res = RES_ERROR;
        }
        return res;
    }
    return RES_PARERR;
}
l 函数返回
DRESULT为枚举型,diskio.h中有其定义编写读函数时已经介绍了注意要把返回值转成这个举类型的参数。
实现了我们22.1节提到的5个函数。
至此,我们已经可以直接使用FATFS下的ff.cf_mount的接口载磁盘,然后使用类似标准C的文件操作函数,可以实现文件操作
22.3.2 main.c代码
main.c中的代码如下所示:
int main(void)
{
    FRESULT res;
    FATFS f
    DIR dir
    FILINFO info;
    sysctl_pll_set_freq(SYSCTL_PLL0, 800000000)
    sysctl_pll_set_freq(SYSCTL_PLL1, 400000000);
    sysctl_pll_set_freq(SYSCTL_PLL2, 45158400);
    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
    sysctl_set_spi0_dvp_data(1);
    lcd_init();                             /* 初始化LCD */
    lcd_set_direction(DIR_YX_LRUD);
    /* Initialize SD card */
    if (sd_init() != 0)
    {
        printf("SD card initialization failed!\n");
        while (1);
    }
    printf("SD card initialization succeed!\n");
lcd_draw_string(10, 10, "SD card initialization succeed!", BLUE);         
/* 显示提示信息 */
    /* Filesystem mount SD card */
    res = f_mount(&fs, _T("/SD"), 1);
    if (res != FR_OK)
    {
        printf("SD card mount failed! Error code: %d\n", res);
        while (1);
    }
    printf("SD card mount succeed!\n");
    lcd_draw_string(10, 30, "SD card mount succeed!", BLUE);    /* 显示提示信息 */
    /* Open SD card root folder */
    res = f_opendir(&dir, _T("/SD"));
    if (res != FR_OK)
    {
        printf("SD card root folder open failed! Error code: %d\n", res);
        while (1);
    }
    printf("SD card root folder open succeed!\n");
    lcd_draw_string(10, 50, "SD card root folder open succeed!", BLUE);         /* 显示提示信息 */
    /* Read SD card root folder */
    while (1)
    {
        res = f_readdir(&dir, &info);
        if (res != FR_OK)
        {
            printf("SD card root folder read failed! Error code: %d\n", res);
            while (1);
        }
        if (info.fname[0] == '\0')
        {
            break;
        }
        printf("\t%s\n", info.fname);
    }
    printf("SD card root folder read succeed!\n");
    lcd_draw_string(10, 70, "SD card root folder read succeed!", BLUE);         /* 显示提示信息 */
    /* Close SD card root folder */
    res = f_closedir(&dir);
    if (res != FR_OK)
    {
        printf("SD card root folder close failed! Error code: %d\n", res);
        while (1);
    }
    printf("SD card root folder close succeed!\n");
    /* Filesystem unmount SD card */
    res = f_unmount(_T("/SD"));
    if (res != FR_OK)
    {
        printf("SD card unmount failed! Error code: %d\n", res);
        while (1);
    }
    printf("SD card unmount succeed!\n");
    lcd_draw_string(10, 90, "FATFS OK!", BLUE);         /* 显示提示信息 */
    while (1)
    {
        
    }
}
main函数代码具体流程大致是:首先完成系统级和LCD、SD卡初始化工作,然后注册SD卡工作区,注册成功后进入SD卡的根目录,读取SD卡根目录的文件信息并通过USB串口打印输出,最后FATFS文件系统卸载SD卡的工作区然后进入死循环中进行空操作。
22.4 运行验证
DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,可以看到LCD显示信息,LCD显示的内容如图22.4.1所示:
图22.4.1 FATFS实验程序运行效果图
等待LCD显示器显示FATFS OK!可通过串口调试助手查看SD卡根目录信息,得到如图22.4.2所示:

图22.4.2 串口调试助手信息

使用特权

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

本版积分规则

91

主题

92

帖子

1

粉丝