第四十三章 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不同而感到惊讶。
正点原子探索者STM32F407开发板购买地址:http://item.taobao.com/item.htm?id=41855882779
|