SDmmc驱动浅析

一、SDMMC简介

经过资料搜集,发现没有SDMMC卡或者是SDMMC接口,资料上出现SDMMC可能要表达的意思是SD/MMC,或者SDMMC是数字安全记忆卡(SecureDigital Memory Card)的简称,即SDMMC就是SD卡。因此介绍一下SD与MMC。

a、SD卡

SD卡,数字安全记忆卡(Secure Digital Memory Card),是用于移动设备的标准记忆卡。SD卡数据传送和物理规范由MMC发展而来,大小和下文提到的

MMC差不多。长宽和MMC一样,比MMC稍微厚了一点。兼容性方面SD卡向下兼容多媒体卡(Multi Media Card)。

SD有9pin:

SD卡也有SD和SPI两种工作模式,在各个工作模式下引脚定义如下:

引脚号

名称

功能(SD模式)

功能(SPI模式)

1

DAT3/CS

数据线3

片选

2

CMD/DI

命令线

片选/从选(SS)

3

VSS1

电源地

主出从入(MOSI)

4

VDD

电源

电源地

5

CLK

时钟

时钟(SCK)

6

VSS2

电源地

电源地

7

DAT0/DO

数据线0

主入从出(MISO)

8

DATI/IRQ

数据线 1

保留

9

DAT2/NC

数据线2

保留

b、MMC

MMC的全称是”MultiMediaCard”――所以也通常被叫做”多媒体卡”,是一种小巧大容量的快闪存储卡,特别应用于移动电话和数字影像及其他移动终端中。

MMC存贮卡只有7pin,可以支持MMC和SPI两种工作模式,或者换句话说:MMC是一种通信协议,支持两种模式SPI和MMC。MMC模式是标准的默认模式,具有MMC的全部特性。而SPI模式则是MMC存贮卡可选的第二种模式,这个模式是MMC协议的一个子集。

如下图为MMC在各个工作模式下的引脚定义:

二、SDMMC驱动(基于FMQL开发环境,ARM开发可参考)

2.1、SD/MMC初始化

首先配置好DMA(应该是可进行可不进行):

首先各个结构体初始化在主函数外进行

 FDmaPs_T g_DMA_dmac;
 FDmaPs_Param_T g_DMA_param;
 FDmaPs_Instance_T g_DMA_instance;

在初始化函数内配置指针指向句柄

FDmaPs_T *pDmac = &g_DMA_dmac;
FDmaPs_Instance_T *pInstance = &g_DMA_instance;
FDmaPs_Param_T *pParam = &g_DMA_param;
FDmaPs_Config *pDmaCfg;

2、初始化中断控制器,配置好中断:

FGicPs_SetupInterruptSystem(&IntcInstance);
FMSH_ExceptionRegisterHandler(FMSH_EXCEPTION_ID_IRQ_INT,        
(FMSH_ExceptionHandler)FGicPs_InterruptHandler_IRQ,&IntcInstance);

接下来就是查找设备ID,配置DMA等一系列操作最后设置SD/MMC工作模式为DMA。

3、为每个分区都挂载一下FAT文件系统

FAT是文件分配表 (FileAllocation table)的缩写,FAT32指的是 文件分配表 是采用32位二进制数记录管理的磁盘文件管理方式,因FAT类文件系统的核心是文件分配表。

接着进行物理驱动分区:

Res = f_fdisk(ulPhyDriveNo, plist, work);

里面的参数分别是物理磁盘号、指向每个分区的大小表的指针、指向工作缓冲区的指针(null:使用堆内存)。

为每个分区创建FAT32文件:

FRESULT f_mkfs (

const TCHAR* path, BYTE opt, DWORD au, void*work, UINT len)

里面参数分别是:逻辑盘号、格式选择、分配单元大小(集群)[byte]、指向工作缓冲区的指针(null:使用堆内存)、工作缓冲区的大小[字节]

挂载(或是卸载)逻辑盘驱动

FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt)

里面的参数分别是:指向文件系统对象(NULL: unmount)的指针、要挂载/卸载的逻辑驱动器号、模式选项(0:不挂载(延迟挂载),1:立即挂载)。

最后可以通过(void)show_partition_usage(ulPhyDriveNo,ulPartitionNum)

该函数可以查看各个磁盘的分区内存容量信息,前者是磁盘号后者是分区号。

2.2、文件扫描

1、创建并且打开目录的对象:

FRESULTf_opendir (DIR* dp, const TCHAR* path)

第一个参数是,指向目录的指针,第二个是目录路径的指针。

2、读取目录项:

FRESULTf_readdir ( DIR* dp, FILINFO* fno)

参数分别为指向打开目录对象的指针、返回指向文件信息的指针。

接下来判定读取到的内容。if (fno.fattrib & AM_DIR)。目录文件的属性位与文件属性位与操作(结果大于等于1时,为文件;否则为目录)。

读取到的是目录时以字符串的形式输出路径末尾文件名,读取到的是文件时输出文件参数信息。最后检索不到目录或者文件则关闭目录。

2.3、目录扫描

1、创建并且打开目录的对象:

FRESULT f_opendir (DIR* dp, const TCHAR* path)

第一个参数是,指向目录的指针,第二个是目录路径的指针。

2、读取目录项:

FRESULT f_readdir ( DIR* dp, FILINFO* fno)

参数分别为指向打开目录对象的指针、返回指向文件信息的指针。

接下来判定读取到的内容:if (fno.fattrib & AM_DIR)。目录文件的属性位与文件属性位与操作(结果大于等于1时,为目录;否则为文件)。

读取到的是目录时输出文件参数信息,以字符串的形式输出路径末尾文件名并且通过递归重新读取,读取到的是文件时不进行操作,最后关闭目录。

2.4、物理驱动创建分区表

使用FRESULT f_fdisk (BYTE pdrv,const DWORD* szt,void* work)划分物理磁盘。

参数:物理磁盘号、指向每个分区的表的容量的指针、指向工作缓冲区的指针(null:使用堆内存)

2.5、删除单个文件

使用FRESULT f_unlink(const TCHAR* path )删除指定文件。

参数:指向文件或目录路径的指针

2.6、删除某个目录及其子目录下的所有文件

1、首先将文件或目录路径写进设定好的缓冲区charpath_buf[]

strcpy(path_buf,path);

2、打开/生成目录文件,判断是否开启成功。

3、读取目录/文件。判断是否读取成功。

4、判断读取到的是文件还是目录,如果读取到的是目录将当前文件名输出到path_buf[]里

例如:从xx/dd/cc开始检索在cc下面检索到了mm那么便通过

i = strlen(path_buf);

sprintf(&path_buf[i], "/%s",fno.fname);

将存储写入path_buf末尾,里面也就成了xx/dd/cc/mm了,接下来就是目录检索喜闻乐见的递归啦,重新来过,继续检索,一直到最后读取到最后一个文件,删除,重复操作,最后目录里面啥也没有循环也就退出了,检索不到东西,读取函数读取失败,最终目录就关闭了,结束运行。

2.7、删除目录及其子目录

删除path指针指定的空目录及其子目录,确保目录下没有文件,否则会删除失败。

1、与2.6操作相同

TCHAR* pfname_buf = path_buf;

strcpy(pfname_buf,path);将路径写入字符串。

2、打开/生成目录文件,判断是否开启成功。

3、读取目录/文件。判断是否读取成功。

4、判定目录下为空:if(fno.fname[0]== 0)

关闭目录并且将该空目录删除:rc =f_unlink(pfname_buf);

如果还能检测到子目录:

if(fno.fattrib & AM_DIR)

{

i = strlen(pfname_buf);

sprintf(&pfname_buf[i],"/%s", fno.fname);

rc = rm_all_empty_dir(pfname_buf);

也是与2.6操作一致将文件名加到缓冲区,使用递归继续检索一直到目录打开失败也就是完全删除,退出循环,最后关闭目录。

2.8、逻辑分区的容量信息及剩余容量信息

首先给两个磁盘,一共8个分区编号:

TCHAR *Path[] = {"0:","1:","2:","3:","4:","5:","6:","7:"};

使用函数(函数功能:获取空闲簇的数目)

RESULT f_getfree (

onst TCHAR* path, DWORD* nclst, FATFS** fatfs)

函数参数:

逻辑驱动编号、指向一个变量的指针(该变量返回空闲集群的数量)、回指向相应文件系统对象指针的指针。

用该函数获取每个分区剩余的容量信息后:

得到总扇区数 tot_sect= (fs->n_fatent - 2) * fs->csize;

得到空闲扇区数 fre_sect = fre_clust * fs->csize;

fs->n_fatent– 2:所有簇的数量

csize: 每簇中的扇区数

fre_clust:空闲簇的数量

2.9、通过IAR jlink上传主机上的bin文件到sdmmc中指定的目录

1、以只读的形式打开二进制文件(如果该文件不存在则打开失败)fptr = fopen(host_file,"rb");

2、判断文件是否为空(空则退出)

使用函数intfseek(FILE *stream, long int offset, int whence)操作文件指针。

函数参数:

stream :这是指向 FILE 对象的指针,该 FILE 对象标识了流。

Offset :这是相对 whence 的偏移量,以字节为单位。

Whence :这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:

SEEK_SET 文件的开头

SEEK_CUR 文件指针的当前位置

SEEK_END 文件的末尾

使用fseek操作:

fseek(fptr,0,SEEK_END);

fileLen= ftell(fptr);(ftell:获取指针当前位置的函数。参数为文件对象指针。)

fseek(fptr,0,SEEK_SET);

这一步就是将指针移到末尾,使用ftell获取当前指针位置由于当前指针在文件末尾,返回值是相对于文件首地址的偏移量,这样就巧妙地获取了文件的大小,最后再通过fseek()函数把文件指针移回首地址。

3、照着host_file文件的大小申请一块内存空间,并且使用fread()函数将数据读到pbuf中:

pbuf= malloc(fileLen);

rdsize= fread(pbuf,1,fileLen,fptr);

size_t fread( void *buffer, size_tsize, size_t count, FILE *stream );

该函数从给定流stream 读取数据到buffer 所指向的数组中。

void*buffer 参数 : 将文件中的二进制数据读取到该缓冲区中 ;

size_tsize 参数 : 读取的 基本单元 字节大小 , 单位是字节 , 一般是buffer 缓冲的单位大小 ;

如果buffer 缓冲区是 char 数组, 则该参数的值是 sizeof(char) ;

如果buffer 缓冲区是 int 数组, 则该参数的值是 sizeof(int) ;

size_tcount 参数:读取的基本单元个数 ;

FILE*stream 参数:文件指针 ;

size_t返回值 : 实际从文件中读取的基本单元个数 ; 读取的字节数是基本单元数基本单元字节大小 ;

4、使用rc =f_open(fp, dst_path, FA_CREATE_ALWAYS|FA_WRITE)创建文件,其中的FA_CREATE_ALWAYS|FA_WRITE(f_open与fopen是有区别的:fopen是stdio下的文件io接口,f_open是fatFS的接口,主要用来操作FAT文件)

Rc不等于0则创建文件失败。

5、使用函数rc =f_write(fp,(void*)pbuf, fileLen, &ulbw);将数据写入fb

如果rc ==0 或者是数据长度不相等都是烧写失败。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值