前言:本文章部分代码参考自野火的例程
有纰漏请指出,转载请说明。
学习交流请发邮件 1280253714@qq.com
1 SD卡是什么
1.1 SDIO简介
STM32通过SDIO与SD 卡 (Secure Digital Memory Card)进行通信
用了SDIO接口的,一类是如今很少用的MMC卡,一类是专为轻薄笔记本硬盘设计的硬盘高速通讯 的CE-ATA ,用得比较多的是SDIO传输的外设(WiFi、GPS)和SD存储卡,本篇主要讲解SD存储卡。
STM32F10x 系列 控制器只支持 SD 卡规范版本 2.0,即只支持标准容量 SD 和高容量 SDHC 标准卡 ,故支持的最高卡容量是 32GB 。

1.2 SD卡的物理结构
一张SD卡包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器5个部分


1.3 SDIO的命令
SD卡总线,其中1根CMD命令线,4根DATA数据线。
STM32通过SDIO外设发送命令到SD卡,SD卡响应并执行相应操作(读、写、块擦除等),接着STM32发送命令查询SD卡当前状态,若SD卡忙则继续等待。(如:SD卡发送块擦除命令,SD卡收到后响应,并执行块擦除,之后STM32轮询SD卡状态,直到SD卡擦除完方可执行下一操作)

SD命令有4种类型:
无响应广播命令(bc),发送到所有卡,不返回任务响应;
带响应广播命令(bcr),发送到所有卡,同时接收来自所有卡响应;
寻址命令(ac),发送到选定卡,DAT线无数据传输;
寻址数据传输命令(adtc),发送到选定卡,DAT线有数据传输。
另外,SD卡主机模块系统旨在为各种应用程序类型提供一个标准接口。在此环境中,需要有特定的客户/应用程序功能。为实现这些功能,在标准中定义了两种类型的通用命令:特定应用命令(ACMD)和常规命令(GEN_CMD)。要使用SD卡制造商特定的ACMD命令如ACMD6,需要在发送该命令之前发送CMD55命令,告知SD卡接下来的命令为特定应用命令。CMD55命令只对紧接的第一个命令有效,SD卡如果检测到CMD55之后的第一条命令为ACMD则执行其特定应用功能,如果检测发现不是ACMD命令,则执行标准命令。
讲人话就是:SD命令有64个通用命令CMD,厂商还制定了若干特定应用命令ACMD,要发ACMD前先发CMD55。

感受一下就好,知道是怎么一回事
1.4 SD卡的响应
响应由SD卡向主机发出,部分命令要求SD卡作出响应,这些响应多用于反馈SD卡的状态。基本特性如下:
SDIO总共有7个响应类型(代号:R1~R7),其中SD卡没有R4、R5类型响应。特定的命令对应有特定的响应类型,比如当主机发送CMD3命令时,可以得到响应R6。
与命令一样,SD卡的响应也是通过CMD线连续传输的。
根据响应内容大小可以分为短响应和长响应。短响应是48bit长度,只有R2类型是长响应,其长度为136bit。
SD卡响应时,可能发送CID、CSD、OCR、RCA寄存器中的值,通过CMD线发给STM32,存储在STM32的SDIO_RESP寄存器中,需要查询响应时,通过SDIO_GetResponse 函数获取寄存器的值。
1.5 SD卡的操作模式及切换
SD卡系统(包括主机和SD卡)定义了两种操作模式:卡识别模式和数据传输模式。在系统复位后,主机处于卡识别模式,寻找总线上可用的SDIO设备;同时,SD卡也处于卡识别模式,直到被主机识别到,即当SD卡接收到SEND_RCA(CMD3)命令后,SD卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式。
按照下图进行编程


1.6 SDIO接口

AHB总线接口:操作SDIO适配器模块中的寄存器,并产生中断和DMA请求信号。
SDIO适配器模块:实现所有MMC/SD/SD I/O卡的相关功能,如时钟的产生、命令和数据的传送。

1.7 SDIO的状态机
命令通道状态机(CPSM)
当SD卡处于某一状态时,SDIO适配器必然处于特定状态与之对应。STM32控制器以命令路径状态机(CPSM)来描述SDIO适配器状态变化,并加入了等待超时检测功能,以便退出永久等待的情况。

数据通道状态机(DPSM)

2 SD卡的底层操作
2.1 几个结构体
SDIO_InitTypeDef
SDIO初始化结构体成员用于设置SDIO工作环境参数,并由SDIO相应初始化配置函数或功能函数调用,这些参数将会被写入到SDIO相应的寄存器,达到配置SDIO工作环境的目的。

SDIO_CmdInitTypeDef
SDIO命令初始化结构体用于设置命令相关内容,比如命令号、命令参数、响应类型等等。

SDIO_DataInitTypeDef
SDIO数据初始化结构体用于配置数据发送和接收参数,比如传输超时、数据长度、传输模式等等。

2.2 SD_Init()函数

2.3 SD卡数据操作
SD 卡数据操作一般包括数据读取、数据写入以及存储区擦除。数据读取和写入都可以分为单块
操作和多块操作。

这几个函数(主要)及SD卡初始化函数,作为下文diskio.c的接口函数
3 SD卡挂载FAT32文件系统
3.1 如何移植FAT32文件系统,要修改哪些部分?


跟在FLASH上挂载FAT32文件系统一样,只需要底层提供给FatFs组件层一些数据操作的相关接口函数(放在bsp板级支持包里,即SD卡初始化、读状态、数据擦除、数据读写),然后修改diskio.c的具体内容,包括以下几个函数,以适应用户层对文件的操作。

diskio.c
3.2 分层操作的思想
这种思想很值得学习:应用编写的软件工程师只需关心对文件如何操作(创建、删除目录,打开、关闭、读写文件等等),将底层与应用层联系起来的中间层函数(驱动,hal硬件抽象层、bsp板级支持包)交给嵌入式软件工程师来处理。
这种分层操作的思想,在程序移植时,更为方便,可屏蔽不同硬件的底层逻辑。不管是FLASH还是SD卡,都可以通过这种方式来挂载FAT32文件系统,方便对文件进行操作。
在操作系统中、计算机网络中,这种分层操作的也用得很多,一句话,即“向下屏蔽差异,向上提供统一的东西”。
更简单地理解分层思想:
在更为底层的硬件与驱动,例如:A板子的LED灯为PA5,B板子的LED灯为PB0,那么,将A板驱动LED点亮的程序移植到B板时,只需将
#define LED1_GPIO_PORT GPIOA /* GPIO端口 */
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOA/* GPIO端口时钟 */
#define LED1_GPIO_PINGPIO_Pin_5
改为
#define LED1_GPIO_PORT GPIOB /* GPIO端口 */
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB/* GPIO端口时钟 */
#define LED1_GPIO_PINGPIO_Pin_0
就可以了,点亮LED灯的相关函数无需更改。

3.3 应用层函数

C语言stdio.h包含的库函数

FAT32中ff.h的函数
3.4 发散联想
当我们在Windows上用鼠标双击文件时,具体的操作可能是用C#编写的桌面式应用程序通过操作系统调用了f_open函数,不得而知……