电子说
SD卡是嵌入式系统中最常见的存储器,不仅容量可以做的很大,并且接口通用,支持SPI/SDIO驱动,尺寸可供选择,能满足不同应用的要求。STM32F1系列自带了标准的4位SDIO接口,最高通信速度可达24MHz,最高每秒能传输12M字节的数据。
STM32F1的SDIO控制器包括2部分,SDIO适配器模块和AHB总线接口,功能框图如下图所示。
其中SDIO适配器模块主要用于实现所有MMC/SD卡的相关功能,如时钟的产生,命令和数据的传输,AHB总线接口则用于操作SDIO适配器模块中的寄存器并产生中断和DMA请求信号。复位后默认情况下SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度。
如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。MMC版本V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是MMC卡就设置为1位总线数据)。
如果一个SD卡接到了总线上,可以通过主机配置数据传输使用SDIO_D0或SDIO_D[3:0]。所有的数据线都工作在推挽模式。
SDIO_CMD有两种操作模式:
(1)用于初始化时的开路模式(仅用于MMC版本V3.31或之前版本)
(2)用于命令传输的推挽模式(SD卡和MMCV4.2在初始化时也使用推挽驱动)
从SDIO框图我们可以看到SDIO总共有3个时钟,分别是:
(1)卡时钟SDIO_CK:每个时钟周期在命令和数据线上传输1位命令或数据。对于多媒体卡V3.31协议,时钟频率可以在0MHz至20MHz间变化;对于多媒体卡V4.0/4.2协议,时钟频率可以在0MHz至48MHz间变化;对于SD卡,时钟频率可以在0MHz至25MHz间变化。
(2)SDIO适配器时钟SDIOCLK:该时钟用于驱动SDIO适配器,其频率等于AHB总线频率HCLK,并用于产生SDIO_CK时钟
(3)AHB总线接口时钟HCLK/2:该时钟用于驱动SDIO的AHB总线接口,其频率为HCLK/2。
我们的SD卡时钟SDIO_CK,根据卡的不同,可能有好几个区间,这就涉及到时钟频率的设置,SDIO_CK与SDIOCLK的关系为:
SDIO_CK=SDIOCLK/(2+CLKDIV)
其中,SDIOCLK为HCLK,一般是72MHz,而CLKDIV则是分配系数,可以通过SDIO的SDIO_CLKCR寄存器进行设置,确保SDIO_CK不超过卡的最大操作频率。
注:在SD卡刚刚初始化的时候,其时钟频率SDIO_CK不能超过400KHz,否则可能无法完成初始化。在初始化以后,就可以设置时钟频率到最大了,但不可超过SD卡的最大操作时钟频率。
SDIO的命令分为应用相关命令ACMD和通用命令CMD两部分,应用相关命令ACMD的发送,必须先发送通用命令CMD55,然后才能发送应用相关命令ACMD。SDIO的所有命令和响应都是通过SDIO_CMD引脚传输的,任何命令的长度都是固定为48位,SDIO的命令格式如下表所示。
Bit位 | 宽度 | 值 | 说明 |
---|---|---|---|
47 | 1 | 0 | 起始位 |
46 | 1 | 1 | 传输位 |
45:40 | 6 | - | 命令索引 |
39:8 | 32 | - | 参数 |
7:1 | 7 | - | CRC7 |
0 | 1 | 1 | 结束位 |
所有的命令都是由STM32F1发出,其中开始位、传输位、CRC7和结束位由SDIO硬件控制,我们需要设置的就只有命令索引和参数部分。其中命令索引在SDIO_CMD寄存器里面设置,命令参数则由寄存器SDIO_ARG设置。一般情况下,选中的SD卡在接收到命令之后,都会回复一个应答(但是CMD0无应答),这个应答我们称之为响应,响应也是在CMD线上串行传输的。STM32F1的SDIO控制器支持2种响应类型,48位的短响应和136位的长响应,这两种响应类型都带CRC错误检测,不带CRC的响应应该忽略CRC错误标志,如CMD1的响应。
短响应的格式如下表所示。
Bit位 | 宽度 | 值 | 说明 |
---|---|---|---|
47 | 1 | 0 | 起始位 |
46 | 1 | 0 | 传输位 |
45:40 | 6 | - | 命令索引 |
39:8 | 32 | - | 参数 |
7:1 | 7 | - | CRC7或者1111111 |
0 | 1 | 1 | 结束位 |
长响应的格式如下表所示。
Bit位 | 宽度 | 值 | 说明 |
---|---|---|---|
135 | 1 | 0 | 起始位 |
134 | 1 | 0 | 传输位 |
133:128 | 6 | 111111 | 保留 |
127:1 | 127 | - | CID或CSD(包括内部CRC7) |
0 | 1 | 1 | 结束位 |
硬件为我们滤除了开始位、传输位、CRC7以及结束位等信息,对于短响应,命令索引存放在SDIO_RESPCMD寄存器,参数则存放在SDIO_RESP1寄存器里面。对于长响应,则仅留CID/CSD位域,存放在SDIO_RESP1到SDIO_RESP4等4个寄存器。SD卡总共有5类响应(R1、R2、R3、R6、R7),这里以R1为例简单介绍一下。R1(普通响应命令)响应属于短响应,其长度为48位,R1响应的格式如下表所示。
Bit位 | 宽度 | 值 | 说明 |
---|---|---|---|
47 | 1 | 0 | 起始位 |
46 | 1 | 1 | 传输位 |
45:40 | 6 | X | 命令索引 |
39:8 | 32 | X | 参数 |
7:1 | 7 | X | CRC7 |
0 | 1 | 1 | 结束位 |
在收到R1响应后,我们可以从SDIO_RESPCMD寄存器和SDIO_RESP1寄存器分别读出命令索引和卡状态信息。
对于SD卡,数据是以数据块的形式传输的,我们常用的卡就是SD卡,所以不考虑MMC形式的读写操作,因为MMC卡数据以数据块或者数据流的形式传输。
从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带有CRC校验值,CRC由SDIO硬件自动处理,单个数据块读的时候,在收到1个数据块以后即可以停止了,不需要发送停止命令CMD12。但是多块数据读的时候,SD卡将一直发送数据给主机,直到接到主机发送的STOP命令CMD12。
SDIO多数据块的读操作如下图所示。
数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个忙判断,新的数据块必须在SD卡非忙的时候发送。这里的忙信号由SD卡拉低SDIO_D0,以表示忙,SDIO硬件自动控制,不需要我们软件处理。
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | CTRL |
Bit 1~Bit 0:电源控制位
00:电源关闭,卡的时钟停止
01:保留
10:保留的上电状态
11:上电状态,卡的时钟开启
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | HWFC_EN | NEGEDGE | WIDBUS | BYPASS | PWRSAV | CLKEN | CLKDIV |
Bit 14:硬件流控制使能
0:关闭硬件流控制
1:使能硬件流控制
Bit 13:SDIO_CK相位选择位
0:在主时钟SDIOCLK的上升沿产生SDIO_CK
1:在主时钟SDIOCLK的下降沿产生SDIO_CK
Bit 12~Bit 11:宽总线模式使能位
00:默认总线模式,使用SDIO_D0
01:4位总线模式,使用SDIO_D[3:0]
10:8位总线模式,使用SDIO_D[7:0]
Bit 10:旁路时钟分频器
0:关闭旁路:驱动SDIO_CK输出信号之前,依据CLKDIV数值对SDIOCLK分频
1:使能旁路:SDIOCLK直接驱动SDIO_CK输出信号
Bit 9:省电配置位(为了省电,当总线为空闲时,设置PWRSAV位可以关闭SDIO_CK时钟输出)
0:始终输出SDIO_CK
1:仅在有总线活动时才输出SDIO_CK
Bit 8:时钟使能位
0:SDIO_CK关闭
1:SDIO_CK使能
Bit 7~Bit 0:时钟分频系数
这个域定义了输入时钟(SDIOCLK)与输出时钟(SDIO_CK)间的分频系数:SDIO_CK频率=SDIOCLK/[CLKDIV+2]
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CMDARG[31:16] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CMDARG[16:0] |
Bit 31~Bit 0:命令参数
属于发送到卡中命令的一部分,如果一个命令包含一个参数,必须在写命令到命令寄存器之前加载这个寄存器
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | RESPCMD |
Bit 5~Bit 0:响应的命令索引
只读位,包含最后收到的命令响应中的命令索引
寄存器 | 短响应 | 长响应 |
---|---|---|
SDIO_RESP1 | 卡状态[31:0] | 卡状态[127:96] |
SDIO_RESP2 | 未使用 | 卡状态[95:64] |
SDIO_RESP3 | 未使用 | 卡状态[31:0] |
SDIO_RESP4 | 未使用 | 卡状态[31:0] |
注:总是先收到卡状态的最高位,SDIO_RESP3寄存器的最低位始终为0。
全部0条评论
快来发表一下你的评论吧 !