第四十三章 SD卡实验
1.硬件平台:正点原子探索者STM32F407开发板 2.软件平台:MDK5.1 3.固件库版本:V1.4.0
很多单片机系统都需要大容量存储设备,以存储数据。目前常用的有
U盘,
FLASH芯片,
SD卡等。他们各有优点,综合比较,最适合单片机系统的莫过于
SD卡了,它不仅容量可以做到很大(
32GB以上),支持
SPI/SDIO驱动,而且有多种体积的尺寸可供选择(标准的
SD卡尺寸,以及
TF卡尺寸等),能满足不同应用的要求。
只需要少数几个
IO口即可外扩一个高达
32GB以上的外部存储器,容量从几十
M到几十
G选择尺度很大,更换也很方便,编程也简单,是单片机大容量外部存储器的首选。
ALIENTKE 探索者
STM32F4开发板自带了标准的
SD卡接口,使用
STM32F4自带的
SDIO接口驱动,
4位模式,最高通信速度可达
48Mhz(分频器旁路时),最高每秒可传输数据
24M字节,对于一般应用足够了。在本章中,我们将向大家介绍,如何在
ALIENTEK探索者
STM32F4开发板上实现
SD卡的读取。本章分为如下几个部分:
43.1 SDIO接口简介
43.2 硬件设计
43.3 软件设计
43.4 下载验证
43.1 SDIO简介
ALIENTEK探索者
STM32F4开发板自带
SDIO接口,本节,我们将简单介绍
STM32F4的
SDIO接口,包括:主要功能及框图、时钟、命令与响应和相关寄存器简介等,最后,我们将介绍
SD卡的初始化流程。
43.1.1 SDIO主要功能及框图
STM32F4的
SDIO控制器支持多媒体卡(
MMC卡)、
SD存储卡、
SD I/O卡和
CE-ATA设备等。
SDIO的主要功能如下:
? 与多媒体卡系统规格书版本4.2全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。
? 与较早的多媒体卡系统规格版本全兼容(向前兼容)。
? 与SD存储卡规格版本2.0全兼容。
? 与SD I/O卡规格版本2.0全兼容:支持良种不同的数据总线模式:1位(默认)和4位。
? 完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。
8位总线模式下数据传输速率可达48MHz(分频器旁路时)。
? 数据和命令输出使能信号,用于控制外部双向驱动器。
STM32F4的
SDIO控制器包含
2个部分:
SDIO适配器模块和
APB2总线接口,其功能框图如图
43.1.1.1所示:
图
43.1.1.1 STM32F4的
SDIO控制器功能框图
复位后默认情况下
SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度(通过
ACMD6命令设置)。
如果一个多媒体卡接到了总线上,则
SDIO_D0、
SDIO_D[3:0]或
SDIO_D[7:0]可以用于数据传输。
MMC版本
V3.31和之前版本的协议只支持
1位数据线,所以只能用
SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是
MMC卡就设置为
1位总线数据)。
如果一个
SD或
SD I/O卡接到了总线上,可以通过主机配置数据传输使用
SDIO_D0或
SDIO_D[3:0]。所有的数据线都工作在推挽模式。
SDIO_CMD有两种操作模式:
① 用于初始化时的开路模式
(仅用于
MMC版本
V3.31或之前版本
)
② 用于命令传输的推挽模式
(SD/SD I/O卡和
MMC V4.2在初始化时也使用推挽驱动
)
43.1.2 SDIO的时钟
从图
43.1.1.1我们可以看到
SDIO总共有
3个时钟,分别是:
卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输
1位命令或数据。对于多媒体卡
V3.31协议,时钟频率可以在
0MHz至
20MHz间变化;对于多媒体卡
V4.0/4.2协议,时钟频率可以在
0MHz至
48MHz间变化;对于
SD或
SD I/O卡,时钟频率可以在
0MHz至
25MHz间变化。
SDIO适配器时钟(SDIOCLK):该时钟用于驱动
SDIO适配器,来自
PLL48CK,一般为
48Mhz,并用于产生
SDIO_CK时钟。
APB2总线接口时钟(PCLK2):该时钟用于驱动
SDIO的
APB2总线接口,其频率为
HCLK/2,一般为
84Mhz。
前面提到,我们的
SD卡时钟(
SDIO_CK),根据卡的不同,可能有好几个区间,这就涉及到时钟频率的设置,
SDIO_CK与
SDIOCLK的关系(时钟分频器不旁路时)为:
SDIO_CK=SDIOCLK/(2+CLKDIV)
其中,
SDIOCLK为
PLL48CK,一般是
48Mhz,而
CLKDIV则是分配系数,可以通过
SDIO的
SDIO_CLKCR寄存器进行设置(确保
SDIO_CK不超过卡的最大操作频率)。注意,以上公式,是时钟分频器不旁路时的计算公式,当时钟分频器旁路时,
SDIO_CK直接等于
SDIOCLK。
这里要提醒大家,在
SD卡刚刚初始化的时候,其时钟频率(
SDIO_CK)是不能超过
400Khz的,否则可能无法完成初始化。在初始化以后,就可以设置时钟频率到最大了(但不可超过
SD卡的最大操作时钟频率)。
43.1.3 SDIO的命令与响应
SDIO的命令分为应用相关命令(
ACMD)和通用命令(
CMD)两部分,应用相关命令(
ACMD)的发送,必须先发送通用命令(
CMD55),然后才能发送应用相关命令(
ACMD)。
SDIO的所有命令和响应都是通过
SDIO_CMD引脚传输的,任何命令的长度都是固定为
48位,
SDIO的命令格式如表
43.1.3.1所示:
表
43.1.3.1 SDIO命令格式
所有的命令都是由
STM32F4发出,其中开始位、传输位、
CRC7和结束位由
SDIO硬件控制,我们需要设置的就只有命令索引和参数部分。其中命令索引(如
CMD0,
CMD1之类的)在
SDIO_CMD寄存器里面设置,命令参数则由寄存器
SDIO_ARG设置。
一般情况下,选中的
SD卡在接收到命令之后,都会回复一个应答(注意
CMD0是无应答的),这个应答我们称之为响应,响应也是在
CMD线上串行传输的。
STM32F4的
SDIO控制器支持
2种响应类型,即:短响应(
48位)和长响应(
136位),这两种响应类型都带
CRC错误检测(注意不带
CRC的响应应该忽略
CRC错误标志,如
CMD1的响应)。
短响应的格式如表
43.1.3.2所示:
表
43.1.3.2 SDIO命令格式
长响应的格式如表
43.1.3.3所示:
表
43.1.3.3 SDIO命令格式
同样,硬件为我们滤除了开始位、传输位、
CRC7以及结束位等信息,对于短响应,命令索引存放在
SDIO_RESPCMD寄存器,参数则存放在
SDIO_RESP1寄存器里面。对于长响应,则仅留
CID/CSD位域,存放在
SDIO_RESP1~SDIO_RESP4等
4个寄存器。
SD存储卡总共有
5类响应(
R1、
R2、
R3、
R6、
R7),我们这里以
R1为例简单介绍一下。
R1(普通响应命令)响应输入短响应,其长度为
48位,
R1响应的格式如表
43.1.3.4所示:
表
43.1.3.4 R1响应格式
在收到
R1响应后,我们可以从
SDIO_RESPCMD寄存器和
SDIO_RESP1寄存器分别读出命令索引和卡状态信息。关于其他响应的介绍,请大家参考光盘
:《
SD卡
2.0协议
.pdf》或《
STM32F4xx中文参考手册》第
28章。
最后,我们看看数据在
SDIO控制器与
SD卡之间的传输。对于
SDI/SDIO存储器,数据是以数据块的形式传输的,而对于
MMC卡,数据是以数据块或者数据流的形式传输。本节我们只考虑数据块形式的数据传输。
SDIO(多)数据块读操作,如图
43.1.3.1所示:
图
43.1.3.1 SDIO(多)数据块读操作
从上图,我们可以看出,从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带有
CRC校验值(
CRC由
SDIO硬件自动处理),单个数据块读的时候,在收到
1个数据块以后即可以停止了,不需要发送停止命令(
CMD12)。但是多块数据读的时候,
SD卡将一直发送数据给主机,直到接到主机发送的
STOP命令(
CMD12)。
SDIO(多)数据块写操作,如图
43.1.3.2所示:
图
43.1.3.2
SDIO(多)数据块写操作
数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个繁忙判断,新的数据块必须在
SD卡非繁忙的时候发送。这里的繁忙信号由
SD卡拉低
SDIO_D0,以表示繁忙,
SDIO硬件自动控制,不需要我们软件处理。
SDIO的命令与响应就为大家介绍到这里。
43.1.4 SDIO相关寄存器介绍
第一个,我们来看
SDIO电源控制寄存器(
SDIO_POWER),该寄存器定义如图
43.1.4.1所示:
图
43.1.4.1 SDIO_POWER寄存器位定义
该寄存器复位值为
0,所以
SDIO的电源是关闭的,我们要启用
SDIO,第一步就是要设置该寄存器最低
2个位均为
1,让
SDIO上电,开启卡时钟。
第二个,我们看
SDIO时钟控制寄存器(
SDIO_CLKCR),该寄存器主要用于设置
SDIO_CK的分配系数,开关等,并可以设置
SDIO的数据位宽,该寄存器的定义如图
43.1.4.2所示:
图
43.1.4.2 SDIO_CLKCR寄存器位定义
上图仅列出了部分我们要用到的位设置,
WIDBUS用于设置
SDIO总线位宽,正常使用的时候,设置为
1,即
4位宽度。
BYPASS用于设置分频器是否旁路,我们一般要使用分频器,所以这里设置为
0,禁止旁路。
CLKEN则用于设置是否使能
SDIO_CK,我们设置为
1。最后,
CLKDIV,则用于控制
SDIO_CK的分频,一般设置为
0,即可得到
24Mhz的
SDIO_CK频率。
第三个,我们要介绍的是
SDIO参数制寄存器(
SDIO_ARG),该寄存器比较简单,就是一个
32位寄存器,用于存储命令参数,不过需要注意的是,必须在写命令之前先写这个参数寄存器!
第四个,我们要介绍的是
SDIO命令响应寄存器(
SDIO_RESPCMD),该寄存器为
32位,但只有低
6位有效,比较简单,用于存储最后收到的命令响应中的命令索引。如果传输的命令响应不包含命令索引,则该寄存器的内容不可预知。
第五个,我们要介绍的是
SDIO响应寄存器组(
SDIO_RESP1~SDIO_RESP4),该寄存器组总共由
4个
32位寄存器组成,用于存放接收到的卡响应部分信息。如果收到短响应,则数据存放在
SDIO_RESP1寄存器里面,其他三个寄存器没有用到。而如果收到长响应,则依次存放在
SDIO_RESP1~ SDIO_RESP4里面,如表
43.1.4.1所示:
表
43.1.4.1 响应类型和
SDIO_RESPx寄存器
第七个,我们介绍
SDIO命令寄存器(
SDIO_CMD),该寄存器各位定义如图
43.1.4.3所示:
图
43.1.4.3 SDIO_CMD寄存器位定义
图中只列出了部分位的描述,其中低
6位为命令索引,也就是我们要发送的命令索引号(比如发送
CMD1,其值为
1,索引就设置为
1)。位
[7:6],用于设置等待响应位,用于指示
CPSM是否需要等待,以及等待类型等。这里的
CPSM,即命令通道状态机,我们就不详细介绍了,请参阅《
STM32F4xx中文参考手册》第
776页,有详细介绍。命令通道状态机我们一般都是开启的,所以位
10要设置为
1。
第八个,我们要介绍的是
SDIO数据定时器寄存器(
SDIO_DTIMER),该寄存器用于存储以卡总线时钟(
SDIO_CK)为周期的数据超时时间,一个计数器将从
SDIO_DTIMER寄存器加载数值,并在数据通道状态机
(DPSM)进入
Wait_R或繁忙状态时进行递减计数,当
DPSM处在这些状态时,如果计数器减为
0,则设置超时标志。这里的
DPSM,即数据通道状态机,类似
CPSM,详细请参考《
STM32F4xx中文参考手册》第
780页。注意:在写入数据控制寄存器,进行数据传输之前,必须先写入该寄存器(
SDIO_DTIMER)和数据长度寄存器(
SDIO_DLEN)!
第九个,我们要介绍的是
SDIO数据长度寄存器(
SDIO_DLEN),该寄存器低
25位有效,用于设置需要传输的数据字节长度。对于块数据传输,该寄存器的数值,必须是数据块长度(通过
SDIO_DCTRL设置)的倍数。
第十个,我们要介绍的是
SDIO数据控制寄存器(
SDIO_DCTRL),该寄存器各位定义如图
43.1.4.4所示:
图
43.1.4.4 SDIO_DCTRL寄存器位定义
该寄存器,用于控制数据通道状态机(
DPSM),包括数据传输使能、传输方向、传输模式、
DMA使能、数据块长度等信息,都是通过该寄存器设置。我们需要根据自己的实际情况,来配置该寄存器,才可正常实现数据收发。
接下来,我们介绍几个位定义十分类似的寄存器,他们是:状态寄存器(
SDIO_STA)、清除中断寄存器(
SDIO_ICR)和中断屏蔽寄存器(
SDIO_MASK),这三个寄存器每个位的定义都相同,只是功能各有不同。所以可以一起介绍,以状态寄存器(
SDIO_STA)为例,该寄存器各位定义如图
43.1.4.5所示:
图
43.1.4.5 SDIO_STA 寄存器位定义
状态寄存器可以用来查询
SDIO控制器的当前状态,以便处理各种事务。比如
SDIO_STA的位
2表示命令响应超时,说明
SDIO的命令响应出了问题。我们通过设置
SDIO_ICR的位
2则可以清除这个超时标志,而设置
SDIO_MASK的位
2,则可以开启命令响应超时中断,设置为
0关闭。其他位我们就不一一介绍了,请大家自行学习。
最后,我们向大家介绍
SDIO的数据
FIFO寄存器(
SDIO_FIFO),数据
FIFO寄存器包括接收和发送
FIFO,他们由一组连续的
32个地址上的
32个寄存器组成,
CPU可以使用
FIFO读写多个操作数。例如我们要从
SD卡读数据,就必须读
SDIO_FIFO寄存器,要写数据到
SD卡,则要写
SDIO_FIFO寄存器。
SDIO将这
32个地址分为
16个一组,发送接收各占一半。而我们每次读写的时候,最多就是读取发送
FIFO或写入接收
FIFO的一半大小的数据,也就是
8个字(
32个字节),
这里特别提醒,我们操作SDIO_FIFO(不论读出还是写入)必须是以4字节对齐的内存进行操作,否则将导致出错!
至此,
SDIO的相关寄存器介绍,我们就介绍完了。还有几个不常用的寄存器,我们没有介绍到,请大家参考《
STM32F4xx中文参考手册》第
28章相关章节。
43.1.5 SD卡初始化流程
最后,我们来看看
SD卡的初始化流程,要实现
SDIO驱动
SD卡,最重要的步骤就是
SD卡的初始化,只要
SD卡初始化完成了,那么剩下的(读写操作)就简单了,所以我们这里重点介绍
SD卡的初始化。从
SD卡
2.0协议(见光盘资料)文档,我们得到
SD卡初始化流程图如图
43.1.5.1所示:
图
43.1.5.1 SD卡初始化流程
从图中,我们看到,不管什么卡(这里我们将卡分为
4类:
SD2.0高容量卡(
SDHC,最大
32G),
SD2.0标准容量卡(
SDSC,最大
2G),
SD1.x卡和
MMC卡),首先我们要执行的是卡上电(需要设置
SDIO_POWER[1:0]=11),上电后发送
CMD0,对卡进行软复位,之后发送
CMD8命令,用于区分
SD卡
2.0,只有
2.0及以后的卡才支持
CMD8命令,
MMC卡和
V1.x的卡,是不支持该命令的。
CMD8的格式如表
43.1.5.1所示:
表
43.1.5.1 CMD8 命令格式
这里,我们需要在发送
CMD8的时候,通过其带的参数我们可以设置
VHS位,以告诉
SD卡,主机的供电情况,
VHS位定义如表
43.1.5.2所示:
表
43.1.5.2 VHS位定义
这里我们使用参数
0X1AA,即告诉
SD卡,主机供电为
2.7~3.6V之间,如果
SD卡支持
CMD8,且支持该电压范围,则会通过
CMD8的响应(
R7)将参数部分原本返回给主机,如果不支持
CMD8,或者不支持这个电压范围,则不响应。
在发送
CMD8后,发送
ACMD41(注意发送
ACMD41之前要先发送
CMD55),来进一步确认卡的操作电压范围,并通过
HCS位来告诉
SD卡,主机是不是支持高容量卡(
SDHC)。
ACMD41的命令格式如表
43.1.5.3所示:
表
43.1.5.3 ACMD41命令格式
ACMD41得到的响应(
R3)包含
SD卡
OCR寄存器内容,
OCR寄存器内容定义如表
43.1.5.4所示:
表
43.1.5.4 OCR寄存器定义
对于支持
CMD8指令的卡,主机通过
ACMD41的参数设置
HCS位为
1,来告诉
SD卡主机支
SDHC卡,如果设置为
0,则表示主机不支持
SDHC卡,
SDHC卡如果接收到
HCS为
0,则永远不会反回卡就绪状态。对于不支持
CMD8的卡,
HCS位设置为
0即可。
SD卡在接收到
ACMD41后,返回
OCR寄存器内容,如果是
2.0的卡,主机可以通过判断
OCR的
CCS位来判断是
SDHC还是
SDSC;如果是
1.x的卡,则忽略该位。
OCR寄存器的最后一个位用于告诉主机
SD卡是否上电完成,如果上电完成,该位将会被置
1。
对于
MMC卡,则不支持
ACMD41,不响应
CMD55,对
MMC卡,我们只需要在发送
CMD0后,在发送
CMD1(作用同
ACMD41),检查
MMC卡的
OCR寄存器,实现
MMC卡的初始化。
至此,我们便实现了对
SD卡的类型区分,图
43.1.5.1中,最后发送了
CMD2和
CMD3命令,用于获得卡
CID寄存器数据和卡相对地址(
RCA)。
CMD2,用于获得
CID寄存器的数据,
CID寄存器数据各位定义如表
43.1.5.5所示:
表
43.1.5.5 卡
CID寄存器位定义
SD卡在收到
CMD2后,将返回
R2长响应(
136位),其中包含
128位有效数据(
CID寄存器内容),存放在
SDIO_RESP1~4等
4个寄存器里面。通过读取这四个寄存器,就可以获得
SD卡的
CID信息。
CMD3,用于设置卡相对地址(
RCA,必须为非
0),对于
SD卡(非
MMC卡),在收到
CMD3后,将返回一个新的
RCA给主机,方便主机寻址。
RCA的存在允许一个
SDIO接口挂多个
SD卡,通过
RCA来区分主机要操作的是哪个卡。而对于
MMC卡,则不是由
SD卡自动返回
RCA,而是主机主动设置
MMC卡的
RCA,即通过
CMD3带参数(高
16位用于
RCA设置),实现
RCA设置。同样
MMC卡也支持一个
SDIO接口挂多个
MMC卡,不同于
SD卡的是所有的
RCA都是由主机主动设置的,而
SD卡的
RCA则是
SD卡发给主机的。
在获得卡
RCA之后,我们便可以发送
CMD9(带
RCA参数),获得
SD卡的
CSD寄存器内容,从
CSD寄存器,我们可以得到
SD卡的容量和扇区大小等十分重要的信息。
CSD寄存器我们在这里就不详细介绍了,关于
CSD寄存器的详细介绍,请大家参考《
SD卡
2.0协议
.pdf》。
至此,我们的
SD卡初始化基本就结束了,最后通过
CMD7命令,选中我们要操作的
SD卡,即可开始对
SD卡的读写操作了,
SD卡的其他命令和参数,我们这里就不再介绍了,请大家参考《
SD卡
2.0协议
.pdf》,里面有非常详细的介绍。
43.2 硬件设计
本章实验功能简介:开机的时候先初始化SD卡,如果SD卡初始化完成,则提示LCD初始化成功。按下KEY0,读取SD卡扇区0的数据,然后通过串口发送到电脑。如果没初始化通过,则在LCD上提示初始化失败。同样用DS0来指示程序正在运行。
本实验用到的硬件资源有:
1) 指示灯
DS0
2) KEY0按键
3) 串口
4) TFTLCD模块
5) SD卡
前面四部分,在之前的实例已经介绍过了,这里我们介绍一下探索者
STM32F4开发板板载的
SD卡接口和
STM32F4的连接关系,如图
43.2.1所示:
图43.2.1 SD卡接口与STM32F4连接原理图
探索者STM32F4开发板的SD卡座(SD_CARD),在PCB背面,SD卡座与STM32F4的连接在开发板上是直接连接在一起的,硬件上不需要任何改动。
43.3 软件设计
软件设计部分请直接打开附件的pdf和工程来对照学习
43.4 下载验证
在代码编译成功之后,我们通过下载代码到
ALIENTEK探索者
STM32F4开发板上,可以看到
LCD显示如图
43.4.1所示的内容(假设
SD卡已经插上了):
图
43.4.1 程序运行效果图
打开串口调试助手,按下
KEY0就可以看到从开发板发回来的数据了,如图
43.4.2所示:
图
43.4.2 串口收到的
SD卡扇区
0内容
这里请大家注意,不同的
SD卡,读出来的扇区
0是不尽相同的,所以不要因为你读出来的数据和图
43.4.2不同而感到惊讶。
实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm
正点原子探索者STM32F407开发板购买地址:http://item.taobao.com/item.htm?id=41855882779
一周热门 更多>