分享

TB SD卡驱动移植实验

 kongzhou 2012-04-11

开发板原理图设计

SD卡座

TB SD卡座.png
没有插入SD卡时,SD_CD#和SD_WP都为高电平;当SD卡正确插入卡座后,SD_CD#和SD_WP都为低电平。
注意:Micro-SD没有SD_WP引脚。

与主芯片的连接

TB SDIO.pngTB SDIO2.png

[编辑] SDIO

[编辑] SDIO原理

[编辑] SDIO简介

SD/SDIO MMC卡主机模块(SDIO)在AHB外设总线和多媒体卡(MMC)、SD存储卡、SDIO卡和CE-ATA设备间提供了一个操作接口。

关于多媒体卡的详细描述,可参见MMCA技术委员会发布的多媒体卡系统规范(多媒体卡协会网站http://www./)。
关于SD存储卡和SD I/O卡的详细描述,可参见SD存储卡和SD I/O卡系统规范(SD卡协会网站http://www./home/)。
关于CE_ATA设备的详细描述,可参见CE_ATA系统规范(CE_ATA工作组网站http://www./)。

SDIO的主要特性如下:

  • 与多媒体卡系统规范4.2版本全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。
  • 与较早的多媒体卡系统规格版本全兼容(向前兼容)。
  • 与SD存储卡规范2.0版本全兼容。
  • 与SD I/O卡规范2.0版本全兼容:支持两种不同的数据总线模式:1位(默认)和4位。
  • 完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。
  • 8位总线模式下数据传输速率可达48MHz。
  • 数据和命令输出使能信号,用于控制外部双向驱动器。

注:

  1. SDIO没有SPI兼容的通信模式
  2. 在多媒体卡系统规范V2.11中定义,SD存储卡协议是多媒体卡协议的超集。只有I/O功能的SD卡或复合卡中的I/O部分不支持SD 存储设备所需的一些命令,其中有些命令在SD I/O设备中不起作用,如擦除命令,因此SDIO不支持这些命令。另外,SD存储卡和SD I/O卡中有些命令是不同的,SDIO也不支持这些命令。详情可以参考SD I/O卡规范V1.0。MMC接口使用现有的MMC命令机制,可以实现CE-ATA的支持。SDIO接口的电气和信号定义详见MMC参考资料。

多媒体卡/SD总线将所有卡与控制器相连。

当前版本的SDIO在同一时间里只能支持一个SD/SDIO/MMC 4.2的卡,但可以支持多个MMC版本4.1或以前版本的卡。

SDIO总线的通信是基于命令和数据的传输。
SDIO总线上的基本操作是命令/响应操作。这些总线操作类型在命令/响应结构间直接地传输它们的信息。另外,一些操作还有数据令牌。
SD/SDIO 存储卡的数据是以数据块的形式进行传输的。MMC的数据可以以块或流的形式进行传输。CE_ATA设备的数据也是以数据块的形式进行传输的。

[编辑] SDIO功能描述

SDIO包含2个部分:

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

(图)SDIO结构框图
TB SDIO结构框图.png

复位后默认情况下SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度。
如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。MMC V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0。
如果一个SD或SD I/O卡接到了总线上,可以通过主机配置数据传输使用SDIO_D0或SDIO_D[3:0]。所有的数据线都工作在推挽模式。

SDIO_CMD有两种操作模式:

用于初始化时的开漏模式(仅用于MMC V3.31或之前版本)
用于命令传输的推挽模式(SD/SD I/O卡和MMC V4.2在初始化时也使用推挽驱动)

SDIO_CK是卡的时钟:每个时钟周期在命令和数据线上传输1位命令或数据。对于MMC V3.31协议,时钟频率可达20MHz;对于MMC V4.0/4.2协议,时钟频率可达48MHz;对于SD或SD I/O卡,时钟频率可达25MHz。
SDIO使用两个时钟信号:

SDIO适配器时钟(SDIOCLK=HCLK)
AHB总线时钟(HCLK/2)

下表适用于多媒体卡/SD/SD I/O卡总线:
(表)SDIO引脚定义
SDIO引脚定义.png

[编辑] SDIO适配器

下图是简化的SDIO适配器框图:
(图)SDIO适配器
SDIO适配器.png

SDIO适配器是多媒体/加密数字存储卡总线的主设备(主机),用于连接一组多媒体卡或一个加密数字存储卡,它包含以下5个部分:

  • 适配器寄存器模块
  • 控制单元
  • 命令通道
  • 数据通道
  • 数据FIFO

注意:适配器寄存器和FIFO使用AHB总线一侧的时钟(HCLK/2),控制单元、命令通道和数据通道使用SDIO适配器一侧的时钟(SDIOCLK)。

[编辑] 适配器寄存器模块

适配器寄存器模块包含所有系统寄存器。该模块还产生清除多媒体卡中静态标志的信号,当在SDIO清除寄存器中的相应位写’1’时会产生清除信号。

[编辑] 控制单元

控制单元包含电源管理功能和为存储器卡提供的时钟分频。
共有三种电源阶段:

电源关闭
电源启动
电源打开

(图)SDIO适配器控制单元
TB SDIO适配器控制单元.png

上图为控制单元的框图,包括电源管理和时钟管理子单元。
在电源关闭和电源启动阶段,电源管理子单元会关闭卡总线上的输出信号。
时钟管理子单元产生和控制SDIO_CK信号。SDIO_CK输出可以使用时钟分频或时钟旁路模式。下述情况下没有时钟输出:

复位后
在电源关闭和电源启动阶段
当启动了省电模式并且卡总线处于空闲状态(命令通道和数据通道子单元进入空闲阶段后的8个时钟周期)
[编辑] 命令通道

命令通道单元向卡发送命令并从卡接收响应。

(图)SDIO适配器命令通道
TB SDIO适配器命令通道.png

命令通道状态机(CPSM)

当写入命令寄存器并设置了使能位,开始发送命令。命令发送完成时,命令通道状态机(CPSM)设置状态标志并在不需要响应时进入空闲状态,在需要响应时,则等待响应(见下图)。当收到响应后,接收到的CRC码将会与内部产生的CRC码比较,然后设置相应的状态标志。

(图)命令通道状态机CPSM
TB SDIO命令通道状态机CPSM.png

当进入等待(Wait)状态时,命令定时器开始运行;在CPSM进入接收(Receive)状态之前,如果产生了超时,则设置超时标志并进入空闲(Idle)状态。
注:命令超时固定为64个SDIO_CK时钟周期。
如果设置了命令寄存器中的中断位,则关闭定时器,并且CPSM等待某一个卡发出的中断请求。如果设置了命令寄存器中的挂起位,则CPSM进入挂起 (Pend)状态并等待数据通道子单元发出的CmdPend信号。当检测到CmdPend信号时,CPSM进入发送(Send)状态,这使得数据计数器去 触发停止命令的传输。
注:CPSM保持在空闲状态至少8个SDIO_CK周期,以满足NCC和NRC时序限制。NCC是两个主机命令间的最小间隔;NRC是主机命令与卡响应之间的最小间隔。

(图)SDIO命令传输
TB SDIO命令传输.png

命令和响应格式

命令:命令是用于开始一项操作。主机向一个指定的卡或所有的卡发出带地址的命令或广播命令(广播命令只适合于MMC V3.31或之前的版本)。命令在CMD线上串行传送。所有命令的长度固定为48位,下表给出了多媒体卡、SD存储卡和SDIO卡上一般的命令格式。 CE-ATA命令是MMC V4.2命令的扩充,所以具有相同的格式。

命令通道操作于半双工模式,这样命令和响应可以分别发送和接收。如果CPSM不处在发送状态,SDIO_CMD输出处于高阻状态,如上图所示。SDIO_CMD上的数据与SDIO_CK的上升沿同步。

(表)命令格式
TB SDIO命令格式.png

响应:响应是由一个被指定地址的卡发送到主机,对于MMC V3.31或以前版本所有的卡同时发送响应;响应是对先前接收到命令的一个应答。响应在CMD线上串行传送。
SDIO支持2种响应类型,2种类型都有CRC错误检测:

48位短响应
136位长响应

注:如果响应不包含CRC(如CMD1的响应),设备驱动应该忽略CRC失败状态。

(表)短响应格式
TB SDIO短响应格式.png

(表)长响应格式
TB SDIO长响应格式.png

命令寄存器包含命令索引(发至卡的6位)和命令类型;这决定了命令本身是否需要响应和响应的类型(48位还是136位)。下表列出了命令通道中的状态标志:

(表)命令通道状态标志
TB SDIO命令通道状态标志.png

CRC发生器

计算CRC码之前所有位的CRC校验和,包括开始位、发送位、命令索引和命令参数(或卡状态)。对于长响应格式,CRC校验和计算的是CID或CSD的前120位;注意,长响应格式中的开始位、传输位和6个保留位不参与CRC计算。
CRC校验和是一个7位的数值:

CRC[6:0] = 余数[(M(x) * x7) / G(x)]
G(x) = x7 + x3 + 1
M(x) = (开始位) * x39 + … + (CRC前的最后一位) * x0, 或
M(x) = (开始位) * x119 + … + (CRC前的最后一位) * x0
[编辑] 数据通道

数据通道子单元在主机与卡之间传输数据。下图是数据通道的框图。

(图)SDIO适配器数据通道
TB SDIO适配器数据通道.png

在时钟控制寄存器中可以配置卡的数据总线宽度。如果选择了4位总线模式,则每个时钟周期四条数据信号线(SDIO_D[3:0])上将传输 4位数据;如果选择了8位总线模式,则每个时钟周期八条数据信号线(SDIO_D[7:0])上将传输8位数据;如果没有选择宽总线模式,则每个时钟周期 只在SDIO_D0上传输1位数据。
如果数据通道状态机(DPSM)被使能,则它将根据传输的方向(发送或接收)进入Wait_S或Wait_R状态:

  • 发送:DPSM进入Wait_S状态。如果发送FIFO中有数据,则DPSM进入发送状态,同时数据通道子单元开始向卡发送数据。
  • 接收:DPSM进入Wait_R状态并等待开始位;当收到开始位时,DPSM进入接收状态,同时数据通道子单元开始从卡接收数据。
数据通道状态机(DPSM)

DPSM工作频率为SDIO_CK,卡总线信号线上的数据与SDIO_CK的上升沿同步。DPSM有6个状态,如下图所示:

(图)数据通道状态机(DPSM)
TB SDIO数据通道状态机(DPSM).png

  • 空闲(Idle):数据通道不工作,SDIO_D[7:0]输出处于高阻状态。当写入数据控制寄存器并设置使能位时,DPSM为数据计数器加载新的数值,并跟据数据方向位,进入Wait_S或Wait_R状态。
  • Wait_R:如果数据计数器等于0,当接收FIFO为空时DPSM进入到空闲(Idle)状态。如果数据计数器不等于0,DPSM等待 SDIO_D上的开始位。如果DPSM在超时之前接收到一个开始位,它会进入接收(Receive)状态并加载数据块计数器。如果DPSM在检测到一个开 始位前出现超时,或发生开始位错误,DPSM将进入空闲状态并设置超时状态标志。
  • 接收(Receive):接收到的串行数据被打包成字节并写入数据FIFO。根据数据控制寄存器中传输模式位的设置,数据传输模式可以是块传输或流传输:
─ 在块模式下,当数据块计数器达到0时,DPSM等待接收CRC码,如果接收到的代码与内部产生的CRC码匹配,则DPSM进入Wait_R状态,否则设置CRC失败状态标志,同时DPSM进入到空闲状态。
─ 在流模式下,当数据计数器不为0时,DPSM接收数据;当计数器为0时,将移位寄存器中的剩余数据写入数据FIFO,同时DPSM进入Wait_R状态。
如果产生了FIFO 上溢错误,DPSM设置FIFO的错误标志并进入空闲状态。
  • Wait_S:如果数据计数器为0,DPSM进入空闲状态;否则DPSM等待数据FIFO空标志消失后,进入发送状态。

注:DPSM会在Wait_S状态保持至少2个时钟周期,以满足NWR的时序要求,NWR是接收到卡的响应至主机开始数据传输的间隔。

  • 发送(Send):DPSM开始发送数据到卡设备。根据数据控制寄存器中传输模式位的设置,数据传输模式可以是块传输或流传输:
─ 在块模式下,当数据块计数器达到0时,DPSM发送内部产生的CRC码,然后是结束位,并进入繁忙状态。
─ 在流模式下,当使能位为高同时数据计数器不为0时,DPSM向卡设备发送数据,然后进入空闲状态。
如果产生了FIFO下溢错误,DPSM设置FIFO的错误标志并进入空闲状态。
  • 繁忙(Busy):DPSM等待CRC状态标志:
─ 如果没有接收到正确的CRC状态,则DPSM进入空闲状态并设置CRC失败状态标志。
─ 如果接收到正确的CRC状态,则当SDIO_D0不为低时(卡不繁忙)DPSM进入Wait_S状态。
当DPSM处于繁忙状态时发生了超时,则DPSM设置数据超时标志并进入空闲状态。
当DPSM处于Wait_R或繁忙状态时,如果数据定时器被使能,则产生数据超时错误:
─ 发送数据时,如果DPSM处于繁忙状态超过程序设置的超时间隔,则产生超时。
─ 接收数据时,如果未收完所有数据,并且DPSM处于Wait_R状态超过程序设置的超时间隔,则产生超时。
  • 数据:数据在数据线两端的主机和卡之间进行传输。数据存储在一个32字的FIFO中,每个字为32位宽。

(表)数据令牌格式
TB SDIO数据令牌格式.png

数据FIFO

数据FIFO(先进先出)子单元是一个具有发送和接收单元的数据缓冲区。
FIFO包含一个每字32位宽、共32个字的数据缓冲区,和发送与接收电路。因为数据FIFO工作的工作频率为AHB时钟(HCLK/2),所以,所有SDIO时钟(SDIOCLK)的信号都进行了重新同步。
跟据TXACT和RXACT标志,可以关闭FIFO、使能发送或使能接收。TXACT和RXACT由数据通道子单元设置而且是互斥的:

─ 当TXACT有效时,发送FIFO代表发送电路和数据缓冲区
─ 当RXACT有效时,接收FIFO代表接收电路和数据缓冲区
  • 发送FIFO:

当使能了SDIO的发送功能,数据可以通过AHB接口写入发送FIFO。
通过32个连续的地址可以访问发送FIFO。发送FIFO中有一个数据输出寄存器,包含读指针指向的数据字。当数据通道子单元装填了移位寄存器后,它移动读指针至下个数据并传输出数据。
如果未使能发送FIFO,所有的状态标志均被清除。当发送数据时,数据通道子单元设置TXACT为有效。

(表)发送FIFO状态标志
TB SDIO发送FIFO状态标志.png

  • 接收FIFO:

当数据通道子单元接收到一个数据字,它会把数据写入FIFO,写操作结束后,写指针自动加一;在另一端,有一个读指针始终指向FIFO中的当前数 据。如果关闭了接收FIFO,所有的状态标志均被清除,读写指针也被复位。当接收到数据时,数据通道子单元设置RXACT。下表列出了接收FIFO的状态 标志。通过32个连续的地址可以访问接收FIFO。

(表)接收FIFO状态标志
TB SDIO接收FIFO状态标志.png

[编辑] SDIO AHB接口

AHB接口产生中断和DMA请求,并访问SDIO适配器寄存器和数据FIFO。它包含一个数据通道、寄存器译码器和中断/DMA控制逻辑。

[编辑] SDIO中断

当至少有一个选中的状态标志为高时,中断控制逻辑产生中断请求。有一个屏蔽寄存器用于选择可以产生中断的条件,如果设置了相应的屏蔽标志,则对应的状态标志可以产生中断。

[编辑] SDIO/DMA接口:SDIO和存储器之间数据传输的过程

在下面的例子中,使用CMD24(WRITE_BLOCK)从SDIO主控制器传送512字节到MMC卡。DMA控制器用于从存储器向SDIO的FIFO填充数据。

1. 执行卡识别过程
2. 提高SDIO_CK频率
3. 发送CMD7命令选择卡
4. 按下述步骤配置DMA2:
a) 使能DMA2控制器并清除所有的中断标志位
b) 设置DMA2通道4的源地址寄存器为存储器缓冲区的基地址,DMA2通道4的目标地址寄存器为SDIO_FIFO寄存器的地址
c) 设置DMA2通道4控制寄存器(存储器递增,非外设递增,外设和源的数据宽度为字宽度)
d) 使能DMA2通道4
5. 发送CMD24(WRITE_BLOCK),操作如下:
a) 设置SDIO数据长度寄存器(SDIO数据时钟寄存器应该在执行卡识别过程之前设置好)
b) 设置SDIO参数寄存器为卡中需要传送数据的地址
c) 设置SDIO命令寄存器:CmdIndex置为24(WRITE_BLOCK);WaitResp置为1(SDIO卡主机等待响应);CPSMEN置为1(使能SDIO卡主机发送命令),保持其它域为他们的复位值。
d) 等待SDIO_STA[6]=CMDREND中断,然后设置SDIO数据寄存器:DTEN置为1(使能SDIO卡主机发送数据);DTDIR置为0(控制 器至卡方向);DTMODE置 为0(块数据传送);DMAEN置为1(使能DMA);DBLOCKSIZE置为0x9(512字节);其它域不用设置。
e) 等待SDIO_STA[10]=DBCKEND
6. 查询DMA通道的使能状态寄存器,确认没有通道仍处于使能状态。

[编辑] SDIO寄存器描述

下表列出了SDIO寄存器地址映射。必须以字(32位)的方式访问这些外设寄存器。
TB SDIO寄存器地址映射.png

[编辑] SDIO电源控制寄存器(SDIO_POWER)

TB SDIO POWER.png

位31:2 保留,始终读为0。
位1:0 PWRCTRL:电源控制位(Power supply control bits)

这些位用于定义卡时钟的当前功能状态:
00:电源关闭,卡的时钟停止。
01:保留
10:保留的电源启动
11:电源打开,卡的时钟开启。

注意:写数据后的7个HCLK时钟周期内,不能写入这个寄存器。

[编辑] SDIO时钟控制寄存器(SDIO_CLKCR)

SDIO_CLKCR寄存器控制SDIO_CK输出时钟。
TB SDIO CLKCR.png

位31:15 保留,始终读为0。

位14 HWFC_EN:硬件流控制使能(HW Flow Control enable)

0:关闭硬件流控制
1:使能硬件流控制
当使能硬件流控制后,关于TXFIFOE和RXFIFOF中断信号的意义请参考SDIO状态寄存器的定义。

位13 NEGEDGE:SDIO_CK相位选择位(SDIO_CK dephasing selection bit)

0:在主时钟SDIOCLK的上升沿产生SDIO_CK。
1:在主时钟SDIOCLK的下降沿产生SDIO_CK。

位12:11 WIDBUS:宽总线模式使能位(Wide bus mode enable bit)

00:默认总线模式,使用SDIO_D0。
01:4位总线模式,使用SDIO_D[3:0]。
10:8位总线模式,使用SDIO_D[7:0]。

位10 BYPASS:时钟分频器旁路使能位(Clock divider bypass enable bit)

0:关闭旁路:驱动SDIO_CK输出信号之前,依据CLKDIV数值对SDIOCLK分频。
1:使能旁路:SDIOCLK直接驱动SDIO_CK输出信号。

位9 PWRSAV:省电配置位(Power saving configuration bit)

为了省电,当总线为空闲时,设置PWRSAV位可以关闭SDIO_CK时钟输出。
0:始终输出SDIO_CK。
1:仅在有总线活动时才输出SDIO_CK。

位8 CLKEN:时钟使能位(Clock enable bit)

0:SDIO_CK关闭。
1:SDIO_CK使能。

位7:0 CLKDIV:时钟分频系数(Clock divide factor)

这个域定义了输入时钟(SDIOCLK)与输出时钟(SDIO_CK)间的分频系数:
SDIO_CK频率 = SDIOCLK/[CLKDIV + 2]。
注意:
  • 当SD/SDIO卡或多媒体卡在识别模式,SDIO_CK的频率必须低于400kHz。
  • 当所有卡都被赋予了相应的地址后,时钟频率可以改变到卡总线允许的最大频率。
  • 写数据后的7个HCLK时钟周期内不能写入这个寄存器。对于SD I/O卡,在读等待期间可以停止SDIO_CK,此时SDIO_CLKCR寄存器不控制SDIO_CK。
[编辑] SDIO参数寄存器(SDIO_ARG)

SDIO_ARG寄存器包含32位命令参数,它将作为命令的一部分发送到卡中。
TB SDIO ARG.png

位31:0 CMDARG:命令参数 (Command argument)

命令参数是发送到卡中命令的一部分,如果一个命令包含一个参数,必须在写命令到命令寄存器之前加载这个寄存器。
[编辑] SDIO命令寄存器(SDIO_CMD)

SDIO_CMD寄存器包含命令索引和命令类型位。命令索引是作为命令的一部分发送到卡中。命令类型位控制命令通道状态机(CPSM)。
TB SDIO CMD.png

位31:15 保留,始终读为0

位14 ATACMD:CE-ATA命令 (CE-ATA command)

如果设置该位,CPSM转至CMD61。

位13 nIEN:不使能中断 (not interrupt enable)

如果未设置该位,则使能CE-ATA设备的中断。

位12 ENCMDcompl:使能CMD完成 (Enable CMD completion)

如果设置该位,则使能命令完成信号。

位11 SDIOSuspend:SD I/O暂停命令 (SD I/O suspend command)

如果设置该位,则将要发送的命令是一个暂停命令(只能用于SDIO卡)。

位10 CPSMEN:命令通道状态机(CPSM)使能位 (Command path state machine (CPSM) Enable bit)

如果设置该位,则使能CPSM。

位9 WAITPEND:CPSM等待数据传输结束(CmdPend内部信号) (CPSM Waits for ends of data transfer (CmdPend internal signal))

如果设置该位,则CPSM在开始发送一个命令之前等待数据传输结束。

位8 WAITINT:CPSM等待中断请求(CPSM waits for interrupt request)

如果设置该位,则CPSM关闭命令超时控制并等待中断请求。

位7:6 WAITRESP:等待响应位(Wait for response bits)

这2位指示CPSM是否需要等待响应,如果需要等待响应,则指示响应类型。
00:无响应,期待CMDSENT标志
01:短响应,期待CMDREND或CCRCFAIL标志
10:无响应,期待CMDSENT标志
11:长响应,期待CMDREND或CCRCFAIL标志

位5:0 CMDINDEX:命令索引(Command index)

命令索引是作为命令的一部分发送到卡中。

注意:

  • 写数据后的7个HCLK时钟周期内不能写入这个寄存器。
  • 多媒体卡可以发送2种响应:48位长的短响应,或136位长的长响应。SD卡和SD I/O卡只能发送短响应,参数可以根据响应的类型而变化,软件将根据发送的命令区分响应的类型。CE-ATA设备只发送短响应。
[编辑] SDIO命令响应寄存器(SDIO_RESPCMD)

SDIO_RESPCMD寄存器包含最后收到的命令响应中的命令索引。如果传输的命令响应不包含命令索引(长响应或OCR响应),尽管它应该包含111111b(响应中的保留域值),但RESPCMD域的内容未知。
TB SDIO RESPCMD.png

位31:6 保留,始终读为0

位5:0 RESPCMD:响应的命令索引(Response command index)

只读位,包含最后收到的命令响应中的命令索引。
[编辑] SDIO响应1..4寄存器(SDIO_RESPx)

SDIO_RESP1/2/3/4寄存器包含卡的状态,即收到响应的部分信息。
SDIO RESPx.png

位31:0 CARDSTATUSx:见下表。

根据响应类型,卡的状态长度是32位或127位。
(表) 响应类型和SDIO_RESPx寄存器
TB 响应类型和SDIO RESPx寄存器.png
总是先收到卡状态的最高位,SDIO_RESP3寄存器的最低位始终为0。
[编辑] SDIO数据定时器寄存器(SDIO_DTIMER)

SDIO_DTIMER寄存器包含以卡总线时钟周期为单位的数据超时时间。
一个计数器从SDIO_DTIMER寄存器加载数值,并在数据通道状态机(DPSM)进入Wait_R或繁忙状态时进行递减计数,当DPSM处在这些状态时,如果计数器减为0,则设置超时标志。
TB SDIO DTIMER.png

位31:0 DATATIME:数据超时时间(Data timeout period)

以卡总线时钟周期为单位的数据超时时间。

注意:在写入数据控制寄存器进行数据传输之前,必须先写入数据定时器寄存器和数据长度寄存器。

[编辑] SDIO数据长度寄存器(SDIO_DLEN)

SDIO_DLEN寄存器包含需要传输的数据字节长度。当数据传输开始时,这个数值被加载到数据计数器中。
TB SDIO DLEN.png

位31:25 保留,始终读为0。

位24:0 DATALENGTH:数据长度(Data length value)

要传输的数据字节数目。

注意:对于块数据传输,数据长度寄存器中的数值必须是数据块长度(见SDIO_DCTRL)的倍数。在写入数据控制寄存器进行数据传输之前,必须先写入数据定时器寄存器和数据长度寄存器。

[编辑] SDIO数据控制寄存器(SDIO_DCTRL)

SDIO_DCTRL寄存器控制数据通道状态机(DPSM)。
TB SDIO DCTRL.png

位31:12 保留,始终读为0。

位11 SDIOEN:SD I/O使能功能(SD I/O enable functions)

如果设置了该位,则DPSM执行SD I/O卡特定的操作。

位10 RWMOD:读等待模式(Read wait mode)

0:停止SDIO_CK控制读等待;
1:使用SDIO_D2控制读等待。

位9 RWSTOP:读等待停止(Read wait stop)

0:如果设置了RWSTART,执行读等待;
1:如果设置了RWSTART,停止读等待。

位8 RWSTART:读等待开始(Read wait start)

设置该位开始读等待操作。

位7:4 DBLOCKSIZE:数据块长度(Data block size)

当选择了块数据传输模式,该域定义数据块长度:
0000:块长度 = 20 = 1字节; 1000:块长度 = 28 = 256字节;
0001:块长度 = 21 = 2字节; 1001:块长度 = 29 = 512字节;
0010:块长度 = 22 = 4字节; 1010:块长度 = 210 = 1024字节;
0011:块长度 = 23 = 8字节; 1011:块长度 = 211 = 2048字节;
0100:块长度 = 24 = 16字节; 1100:块长度 = 212 = 4096字节;
0101:块长度 = 25 = 32字节; 1101:块长度 = 213 = 8192字节;
0110:块长度 = 26 = 64字节; 1110:块长度 = 214 = 16384字节;
0111:块长度 = 27 = 128字节; 1111:保留。

位3 DMAEN:DMA使能位(DMA enable bit)

0:关闭DMA;
1:使能DMA。

位2 DTMODE:数据传输模式(Data transfer mode selection)

0:块数据传输;
1:流数据传输。

位1 DTDIR:数据传输方向(Data transfer direction selection)

0:控制器至卡;
1:卡至控制器。

位0 DTEN:数据传输使能位(Data transfer enabled bit)

如果设置该位为1,则开始数据传输。根据DTSIR方向位,DPSM进入Wait_S或Wait_R状态,如果在传输的一开始就设置了RWSTART位,则DPSM进入读等待状态。不需要在数据传输结束后清除使能位,但必须更改SDIO_DCTRL以允许新的数据传输。

注意:写数据后的7个HCLK时钟周期内不能写入这个寄存器。

[编辑] SDIO数据计数器寄存器(SDIO_DCOUNT)

当DPSM从空闲状态进入Wait_R或Wait_S状态时,SDIO_DCOUNT寄存器从数据长度寄存器加载数值(见SDIO_DLEN),在数据传输过程中,该计数器的数值递减直到减为0,然后DPSM进入空闲状态并设置数据状态结束标志DATAEND。
SDIO DCOUNT.png

位31:25 保留,始终读为0。

位24:0 DATACOUNT:数据计数数值(Data count value)

读这个寄存器时返回待传输的数据字节数,写这个寄存器无作用。

注意:只能在数据传输结束时读这个寄存器。

[编辑] SDIO状态寄存器(SDIO_STA)

SDIO_STA是一个只读寄存器,它包含两类标志:

  1. 静态标志(位[23:22、10:0]):保持为’1’,直到被清除 (见SDIO_ICR)
  2. 动态标志(位[21:11]):只取决于对应的硬件逻辑(例如:FIFO满和空标志变高或变低随FIFO的数据写入而变化)。

TB SDIO STA.png

位31:24 保留,始终读为0。
位23 CEATAEND:CMD61收到CE-ATA命令完成信号
位22 SDIOIT:收到SDIO中断
位21 RXDVAL:接收FIFO中的数据有效
位20 TXDVAL:发送FIFO中的数据有效
位19 RXFIFOE:接收FIFO空
位18 TXFIFOE:发送FIFO空

若使用了硬件流控制,当FIFO包含2个字时,TXFIFOE信号变为有效。

位17 RXFIFOF:接收FIFO满

若使用了硬件流控制,当FIFO还差2个字满时,RXFIFOF信号变为有效。

位16 TXFIFOF:发送FIFO满
位15 RXFIFOHF:接收FIFO半满:FIFO中至少还有8个字。
位14 TXFIFOHE:发送FIFO半空:FIFO中至少还可以写入8个字。
位13 RXACT:正在接收数据
位12 TXACT:正在发送数据
位11 CMDACT:正在传输命令
位10 DBCKEND:已发送/接收数据块(CRC校验成功)
位9 STBITERR:在宽总线模式下,在所有数据线上都没有检测到起始位
位8 DATAEND:数据结束(数据计数器SDIO_DCOUNT = 0)
位7 CMDSENT:已发送命令(不需要响应)
位6 CMDREND:已收到命令响应(CRC校验成功)
位5 RXOVERR:接收FIFO上溢错误
位4 TXUNDERR:发送FIFO下溢错误
位3 DTIMEOUT:数据超时
位2 CTIMEOUT:命令响应超时

命令超时时间是一个固定的值,为64个SDIO_CK时钟周期。

位1 DCRCFAIL:已发送/接收数据块(CRC校验失败)
位0 CCRCFAIL:已收到命令响应(CRC校验失败)

[编辑] SDIO中断清除寄存器(SDIO_ICR)

SDIO_ICR是一个只写寄存器,读该寄存器将返回复位值。在对应寄存器位写’1’将清除SDIO_STA状态寄存器中的对应位。
TB SDIO ICR.png

位31:24 保留,始终读为0 位21:11 保留,始终读为0(对应于11个不可清除的动态标志)

[编辑] SDIO屏蔽寄存器(SDIO_MASK)

将对应位置’1’,SDIO_MASK中断屏蔽寄存器决定哪一个状态位产生中断。
TB SDIO MASK.png

位31:24 保留,始终读为0

[编辑] SDIO FIFO计数器寄存器(SDIO_FIFOCNT)

SDIO_FIFOCNT寄存器包含还未写入FIFO或还未从FIFO读出的数据字数目。当在数据控制寄存器(SDIO_DCTRL)中设置了数据 传输使能位DTEN,并且DPSM处于空闲状态时,FIFO计数器从数据长度寄存器(见SDIO_DLEN)加载数值。如果数据长度未与字对齐(4的倍 数),则最后剩下的1~3个字节被当成一个字处理。
TB SDIO FIFOCNT.png

位31:24 保留,始终读为0
位23:0 FIFOCOUNT:还未写入FIFO或还未从FIFO读出的数据字数目。

[编辑] SDIO数据FIFO寄存器(SDIO_FIFO)

接收和发送FIFO是以32位宽度进行读写的一组寄存器,它包含32个地址连续的寄存器,CPU可以使用FIFO读写多个数据。
SDIO FIFO.png

位31:0 FIFODATA:接收的或发送的FIFO数据

FIFO数据占据32个32位的字,地址为:(SDIO基址 + 0x80) 至 (SDIO基址 + 0xFC)

[编辑] SDIO数据结构

[编辑] SDIO初始化结构类型定义

typedef struct
{
  uint32_t SDIO_ClockEdge; //指定位捕捉的时钟边沿
 
  uint32_t SDIO_ClockBypass; //指定是否使能SDIO时钟分频器旁路
 
  uint32_t SDIO_ClockPowerSave; //指定当总线空闲时,是否使能SDIO时钟输出
 
  uint32_t SDIO_BusWide; //指定SDIO总线宽度
 
  uint32_t SDIO_HardwareFlowControl; //指定是否使能SDIO硬件流控制
 
  uint8_t SDIO_ClockDiv; //指定SDIO控制器的时钟分频系数(0x00~0xFF)
} SDIO_InitTypeDef;
 
/* SDIO_Clock_Edge用于设置NEGEDGE位(SDIO_CLKCR[13]) */
#define SDIO_ClockEdge_Rising               ((uint32_t)0x00000000)
#define SDIO_ClockEdge_Falling              ((uint32_t)0x00002000)
 
/* SDIO_ClockBypass用于设置BYPASS位(SDIO_CLKCR[10]) */
#define SDIO_ClockBypass_Disable             ((uint32_t)0x00000000)
#define SDIO_ClockBypass_Enable              ((uint32_t)0x00000400)
 
/* SDIO_ClockPowerSave用于设置PWRSAV位(SDIO_CLKCR[9]) */
#define SDIO_ClockPowerSave_Disable         ((uint32_t)0x00000000)
#define SDIO_ClockPowerSave_Enable          ((uint32_t)0x00000200)
 
/* SDIO_BusWide用于设置WIDBUS位(SDIO_CLKCR[12:11]) */
#define SDIO_BusWide_1b                     ((uint32_t)0x00000000)
#define SDIO_BusWide_4b                     ((uint32_t)0x00000800)
#define SDIO_BusWide_8b                     ((uint32_t)0x00001000)
 
/* SDIO_HardWareFlowControl用于设置HWFC_EN位(SDIO_CLKCR[14]) */
#define SDIO_HardwareFlowControl_Disable    ((uint32_t)0x00000000)
#define SDIO_HardwareFlowControl_Enable     ((uint32_t)0x00004000)
 
/* SDIO_ClockDiv用于设置CLKDIV位(SDIO_CLKCR[7:0]) */

[编辑] SDIO命令初始化结构类型定义

typedef struct
{
  uint32_t SDIO_Argument; //指定命令参数
 
  uint32_t SDIO_CmdIndex; //指定命令索引
 
  uint32_t SDIO_Response; //指定响应类型
 
  uint32_t SDIO_Wait; //指定是否等待中断请求
 
  uint32_t SDIO_CPSM; //指定是否使能命令通道状态机(CPSM)
} SDIO_CmdInitTypeDef;
 
/* SDIO_Argument用于设置SDIO_ARG寄存器 */
 
/* SDIO_CmdIndex用于设置CMDINDEX位(SDIO_CMD[5:0]) */
#define IS_SDIO_CMD_INDEX(INDEX)            ((INDEX) < 0x40)
 
/* SDIO_Response用于设置WAITRESP位(SDIO_CMD[7:6]) */
#define SDIO_Response_No                    ((uint32_t)0x00000000)
#define SDIO_Response_Short                 ((uint32_t)0x00000040)
#define SDIO_Response_Long                  ((uint32_t)0x000000C0)
 
/* SDIO_Wait用于设置WAITPEND和WAITINT位(SDIO_CMD[9:8]) */
#define SDIO_Wait_No                        ((uint32_t)0x00000000) //不等待,允许超时
#define SDIO_Wait_IT                        ((uint32_t)0x00000100) //SDIO等待中断请求
#define SDIO_Wait_Pend                      ((uint32_t)0x00000200) //SDIO等待传输结束
 
/* SDIO_CPSM用于设置CPSMEN位(SDIO_CMD[10]) */
#define SDIO_CPSM_Disable                    ((uint32_t)0x00000000)
#define SDIO_CPSM_Enable                     ((uint32_t)0x00000400)

[编辑] SDIO数据初始化结构类型定义

typedef struct
{
  uint32_t SDIO_DataTimeOut; //指定数据超时时间
 
  uint32_t SDIO_DataLength; //指定待传输的数据字节长度
 
  uint32_t SDIO_DataBlockSize; //指定块传输的数据块长度
 
  uint32_t SDIO_TransferDir; //指定数据传输方向
 
  uint32_t SDIO_TransferMode; //指定数据传输模式
 
  uint32_t SDIO_DPSM; //指定是否使能数据通道状态机(DPSM)
} SDIO_DataInitTypeDef;
 
/* SDIO_DataTimeOut用于设置SDIO_DTIMER寄存器 */
 
/* SDIO_DataLength用于设置DATALENGTH位(SDIO_DLEN[24:0]) */
#define IS_SDIO_DATA_LENGTH(LENGTH) ((LENGTH) <= 0x01FFFFFF)
 
/* SDIO_DataBlockSize用于设置DBLOCKSIZE位(SDIO_DCTRL[7:4]) */
#define SDIO_DataBlockSize_1b               ((uint32_t)0x00000000)
#define SDIO_DataBlockSize_2b               ((uint32_t)0x00000010)
#define SDIO_DataBlockSize_4b               ((uint32_t)0x00000020)
#define SDIO_DataBlockSize_8b               ((uint32_t)0x00000030)
#define SDIO_DataBlockSize_16b              ((uint32_t)0x00000040)
#define SDIO_DataBlockSize_32b              ((uint32_t)0x00000050)
#define SDIO_DataBlockSize_64b              ((uint32_t)0x00000060)
#define SDIO_DataBlockSize_128b             ((uint32_t)0x00000070)
#define SDIO_DataBlockSize_256b             ((uint32_t)0x00000080)
#define SDIO_DataBlockSize_512b             ((uint32_t)0x00000090)
#define SDIO_DataBlockSize_1024b            ((uint32_t)0x000000A0)
#define SDIO_DataBlockSize_2048b            ((uint32_t)0x000000B0)
#define SDIO_DataBlockSize_4096b            ((uint32_t)0x000000C0)
#define SDIO_DataBlockSize_8192b            ((uint32_t)0x000000D0)
#define SDIO_DataBlockSize_16384b           ((uint32_t)0x000000E0)
 
/* SDIO_TransferDir用于设置DTDIR位(SDIO_DCTRL[1]) */
#define SDIO_TransferDir_ToCard             ((uint32_t)0x00000000)
#define SDIO_TransferDir_ToSDIO             ((uint32_t)0x00000002)
 
/* SDIO_TransferMode用于设置DTMODE位(SDIO_DCTRL[2]) */
#define SDIO_TransferMode_Block             ((uint32_t)0x00000000)
#define SDIO_TransferMode_Stream            ((uint32_t)0x00000004)
 
/* SDIO_DPSM用于设置DTEN位(SDIO_DCTRL[0]) */
#define SDIO_DPSM_Disable                    ((uint32_t)0x00000000)
#define SDIO_DPSM_Enable                     ((uint32_t)0x00000001)

[编辑] SDIO库函数

[编辑] 函数SDIO_Init

/**
  * 功能描述  根据SDIO_InitStruct中指定的参数初始化SDIO外设 
  * 输入参数  SDIO_InitStruct: 指向结构SDIO_InitTypeDef的指针,包含了SDIO外设的配置信息 
  * 返回值  无
  */
void SDIO_Init(SDIO_InitTypeDef* SDIO_InitStruct)
{
  uint32_t tmpreg = 0;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_CLOCK_EDGE(SDIO_InitStruct->SDIO_ClockEdge));
  assert_param(IS_SDIO_CLOCK_BYPASS(SDIO_InitStruct->SDIO_ClockBypass));
  assert_param(IS_SDIO_CLOCK_POWER_SAVE(SDIO_InitStruct->SDIO_ClockPowerSave));
  assert_param(IS_SDIO_BUS_WIDE(SDIO_InitStruct->SDIO_BusWide));
  assert_param(IS_SDIO_HARDWARE_FLOW_CONTROL(SDIO_InitStruct->SDIO_HardwareFlowControl)); 
 
/*---------------------------- SDIO CLKCR 配置 ------------------------*/  
  /* 获取 SDIO CLKCR 的值 */
  tmpreg = SDIO->CLKCR;
 
  /* 清除 CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN 位 */
  tmpreg &= CLKCR_CLEAR_MASK;
 
  /* 根据 SDIO_ClockDiv 的值设置 CLKDIV 位 */
  /* 根据 SDIO_ClockPowerSave 的值设置 PWRSAV 位 */
  /* 根据 SDIO_ClockBypass 的值设置 BYPASS 位 */
  /* 根据 SDIO_BusWide 的值设置 WIDBUS 位 */
  /* 根据 SDIO_ClockEdge 的值设置 NEGEDGE 位 */
  /* 根据 SDIO_HardwareFlowControl 的值设置 HWFC_EN 位 */
  tmpreg |= (SDIO_InitStruct->SDIO_ClockDiv  | SDIO_InitStruct->SDIO_ClockPowerSave |
             SDIO_InitStruct->SDIO_ClockBypass | SDIO_InitStruct->SDIO_BusWide |
             SDIO_InitStruct->SDIO_ClockEdge | SDIO_InitStruct->SDIO_HardwareFlowControl); 
 
  /* 回写 SDIO CLKCR */
  SDIO->CLKCR = tmpreg;
}

[编辑] 函数SDIO_ClockCmd

/**
  * 功能描述  使能或失能 SDIO 时钟
  * 输入参数  NewState:SDIO 时钟的新状态
  *     该参数可以是:
  *	    ENABLE
  * 	    DISABLE
  * 返回值  无
  */
void SDIO_ClockCmd(FunctionalState NewState)
{
  /* 检查输入参数 */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  /* 根据 NewState 设置或清除 SDIO_CLKCR 的 CLKEN 位 */
  *(__IO uint32_t *) CLKCR_CLKEN_BB = (uint32_t)NewState;
}

[编辑] 函数SDIO_SetPowerState

/**
  * 功能描述  设置控制器的电源状态
  * 输入参数  SDIO_PowerState:电源状态的新状态
  *     该参数可以使下列值之一:
  *     	    SDIO_PowerState_OFF
  *         SDIO_PowerState_ON
  * 返回值  无
  */
void SDIO_SetPowerState(uint32_t SDIO_PowerState)
{
  /* 检查输入参数 */
  assert_param(IS_SDIO_POWER_STATE(SDIO_PowerState));
  /* 清除当前的电源状态 */
  SDIO->POWER &= PWR_PWRCTRL_MASK;
  /* 根据 SDIO_PowerState 关闭或打开SDIO电源 */
  SDIO->POWER |= SDIO_PowerState;
}

[编辑] 函数SDIO_GetPowerState

/**
  * 功能描述  获取控制器的电源状态
  * 输入参数  无
  * 返回值  控制器的电源状态The returned value can
  *   	该返回值可能是下列值之一:
  * 	- 0x00: 电源关闭
  * 	- 0x02: 电源启动
  * 	- 0x03: 电源打开
  */
uint32_t SDIO_GetPowerState(void)
{
  return (SDIO->POWER & (~PWR_PWRCTRL_MASK));
}

[编辑] 函数SDIO_ITConfig

/**
  * 功能描述  使能或失能SDIO中断
  * 输入参数  SDIO_IT: 指定待使能或失能的 SDIO 中断源
  *   	该参数可以是下列值之一或任意组合:
  *     		SDIO_IT_CCRCFAIL: 已收到命令响应(CRC校验失败)中断
  *     		SDIO_IT_DCRCFAIL: 已发送/接收数据块(CRC校验失败)中断
  *     		SDIO_IT_CTIMEOUT: 命令响应超时中断
  *     		SDIO_IT_DTIMEOUT: 数据超时中断
  *     		SDIO_IT_TXUNDERR: 发送 FIFO 下溢错误中断
  *     		SDIO_IT_RXOVERR:  接收 FIFO 下溢错误中断
  *     		SDIO_IT_CMDREND:  已收到命令响应(CRC校验成功)中断
  *    		SDIO_IT_CMDSENT:  已发送命令(不需要响应)中断
  *     		SDIO_IT_DATAEND:  数据结束(数据计数器SDIDCOUNT为0)中断
  *     		SDIO_IT_STBITERR: 在宽总线模式下,在所有的数据线号上没有检测到起始位中断
  *     		SDIO_IT_DBCKEND:  已发送/接收数据块(CRC校验成功)中断
  *     		SDIO_IT_CMDACT:   正在传输命令中断
  *     		SDIO_IT_TXACT:    正在发送数据中断
  *     		SDIO_IT_RXACT:    正在接收数据中断
  *     		SDIO_IT_TXFIFOHE: 发送 FIFO 半空中断
  *     		SDIO_IT_RXFIFOHF: 接收 FIFO 半满中断
  *     		SDIO_IT_TXFIFOF:  发送 FIFO 满中断
  *     		SDIO_IT_RXFIFOF:  接收 FIFO 满中断
  *     		SDIO_IT_TXFIFOE:  发送 FIFO 空中断
  *     		SDIO_IT_RXFIFOE:  接收 FIFO 空中断
  *     		SDIO_IT_TXDAVL:   发送 FIFO 中的数据有效中断
  *     		SDIO_IT_RXDAVL:   接收 FIFO 中的数据有效中断
  *     		SDIO_IT_SDIOIT:   收到 SD I/O 中断中断
  *     		SDIO_IT_CEATAEND: CMD61 收到 CE-ATA 命令完成信号中断
  * 输入参数  NewState: 指定的SDIO中断的新状态
  *		该参数可以是:
  *			ENABLE
  * 		DISABLE
  * 返回值  无
  */
void SDIO_ITConfig(uint32_t SDIO_IT, FunctionalState NewState)
{
  /* 检查输入参数 */
  assert_param(IS_SDIO_IT(SDIO_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
 
  if (NewState != DISABLE)
  {
    /* 使能 SDIO 中断 */
    SDIO->MASK |= SDIO_IT;
  }
  else
  {
    /* 失能 SDIO 中断 */
    SDIO->MASK &= ~SDIO_IT;
  } 
}

[编辑] 函数SDIO_DMACmd

/**
  * 功能描述  使能或失能 SDIO DMA 请求
  * 输入参数  NewState: 选择的 SDIO DMA 请求的新状态
  *	该参数可以是:
  *	    ENABLE
  * 	    DISABLE
  * 返回值  无
  */
void SDIO_DMACmd(FunctionalState NewState)
{
  /* 检查输入参数 */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  /* 根据 NewState 设置或清除 SDIO_CLKCR 的 DMAEN 位 */
  *(__IO uint32_t *) DCTRL_DMAEN_BB = (uint32_t)NewState;
}

[编辑] 函数SDIO_SendCommand

/**
  * 功能描述  根据 SDIO_CmdInitStruct 中指定的参数初始化 SDIO 命令,并且发送命令
  * 输入参数  SDIO_CmdInitStruct:指向结构 SDIO_CmdInitTypeDef 的指针,包含了SDIO命令的配置信息
  * 返回值  无
  */
void SDIO_SendCommand(SDIO_CmdInitTypeDef *SDIO_CmdInitStruct)
{
  uint32_t tmpreg = 0;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_CMD_INDEX(SDIO_CmdInitStruct->SDIO_CmdIndex));
  assert_param(IS_SDIO_RESPONSE(SDIO_CmdInitStruct->SDIO_Response));
  assert_param(IS_SDIO_WAIT(SDIO_CmdInitStruct->SDIO_Wait));
  assert_param(IS_SDIO_CPSM(SDIO_CmdInitStruct->SDIO_CPSM));
 
/*---------------------------- SDIO 参数寄存器配置 ------------------------*/
  /* 根据SDIO_Argument的值设置SDIO参数寄存器 */
  SDIO->ARG = SDIO_CmdInitStruct->SDIO_Argument;
 
/*---------------------------- SDIO 命令寄存器配置 ------------------------*/  
  /* 获取SDIO命令寄存器的值 */
  tmpreg = SDIO->CMD;
  /* 清除 CMDINDEX, WAITRESP, WAITINT, WAITPEND, CPSMEN 位 */
  tmpreg &= CMD_CLEAR_MASK;
  /* 根据 SDIO_CmdIndex 的值设置 CMDINDEX 位 */
  /* 根据 SDIO_Response 的值设置 WAITRESP 位 */
  /* 根据 SDIO_Wait 的值设置 WAITINT 和 WAITPEND 位 */
  /* 根据 SDIO_CPSM 的值设置 CPSMEN 位 */
  tmpreg |= (uint32_t)SDIO_CmdInitStruct->SDIO_CmdIndex | SDIO_CmdInitStruct->SDIO_Response
           | SDIO_CmdInitStruct->SDIO_Wait | SDIO_CmdInitStruct->SDIO_CPSM;
 
  /* 回写SDIO命令寄存器 */
  SDIO->CMD = tmpreg;
}

[编辑] 函数SDIO_GetCommandResponse

/**
  * 功能描述  返回上一个收到响应的命令的命令索引
  * 输入参数  无
  * 返回值  返回上一个收到响应的命令的命令索引
  */
uint8_t SDIO_GetCommandResponse(void)
{
  return (uint8_t)(SDIO->RESPCMD);
}

[编辑] 函数SDIO_GetResponse

/**
  * 功能描述  返回上一个命令从卡收到的响应
  * 输入参数  SDIO_RESP: 指定SDIO响应寄存器 
  *     该参数可以是下列值之一:
  *     	    SDIO_RESP1: 响应寄存器 1
  *         SDIO_RESP2: 响应寄存器 2
  *         SDIO_RESP3: 响应寄存器 3
  *         SDIO_RESP4: 响应寄存器 4
  * 返回值  对应的响应寄存器的值
  */
uint32_t SDIO_GetResponse(uint32_t SDIO_RESP)
{
  __IO uint32_t tmp = 0;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_RESP(SDIO_RESP));
 
  tmp = SDIO_RESP_ADDR + SDIO_RESP;
 
  return (*(__IO uint32_t *) tmp); 
}

[编辑] 函数SDIO_DataConfig

/**
  * 功能描述  根据SDIO_DataInitStruct中指定的参数初始化SDIO数据通道
  * 输入参数  SDIO_DataInitStruct: 指向结构SDIO_DataInitTypeDef的指针,包含了SDIO数据的配置信息
  * 返回值  无
  */
void SDIO_DataConfig(SDIO_DataInitTypeDef* SDIO_DataInitStruct)
{
  uint32_t tmpreg = 0;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_DATA_LENGTH(SDIO_DataInitStruct->SDIO_DataLength));
  assert_param(IS_SDIO_BLOCK_SIZE(SDIO_DataInitStruct->SDIO_DataBlockSize));
  assert_param(IS_SDIO_TRANSFER_DIR(SDIO_DataInitStruct->SDIO_TransferDir));
  assert_param(IS_SDIO_TRANSFER_MODE(SDIO_DataInitStruct->SDIO_TransferMode));
  assert_param(IS_SDIO_DPSM(SDIO_DataInitStruct->SDIO_DPSM));
 
/*---------------------------- SDIO 数据定时器配置 ---------------------*/
  /* 设置SDIO数据超时时间 */
  SDIO->DTIMER = SDIO_DataInitStruct->SDIO_DataTimeOut;
 
/*---------------------------- SDIO 数据长度寄存器配置 -----------------------*/
  /* 设置SDIO数据长度 */
  SDIO->DLEN = SDIO_DataInitStruct->SDIO_DataLength;
 
/*---------------------------- SDIO 数据控制寄存器配置 ----------------------*/  
  /* 获取SDIO 数据控制寄存器的值 */
  tmpreg = SDIO->DCTRL;
  /* 清除 DEN, DTMODE, DTDIR 和 DBCKSIZE 位 */
  tmpreg &= DCTRL_CLEAR_MASK;
  /* 根据SDIO_DPSM的值设置DEN位 */
  /* 根据SDIO_TransferMode的值设置DTMODE位 */
  /* 根据SDIO_TransferDir的值设置DTDIR位 */
  /* 根据SDIO_DataBlockSize的值设置DBCKSIZE位 */
  tmpreg |= (uint32_t)SDIO_DataInitStruct->SDIO_DataBlockSize | SDIO_DataInitStruct->SDIO_TransferDir
           | SDIO_DataInitStruct->SDIO_TransferMode | SDIO_DataInitStruct->SDIO_DPSM;
 
  /* 回写SDIO数据控制寄存器 */
  SDIO->DCTRL = tmpreg;
}

[编辑] 函数SDIO_ReadData

/**
  * 功能描述  从接收FIFO读一个数据字
  * 输入参数  无
  * 返回值  收到的数据
  */
uint32_t SDIO_ReadData(void)
{ 
  return SDIO->FIFO;
}

[编辑] 函数SDIO_WriteData

/**
  * 功能描述  向发送FIFO写一个数据字
  * 输入参数  Data: 要写的32位数据字
  * 返回值  无
  */
void SDIO_WriteData(uint32_t Data)
{ 
  SDIO->FIFO = Data;
}

[编辑] 函数SDIO_GetFlagStatus

/**
  * 功能描述  检查指定的SDIO标志设置与否
  * 输入参数  SDIO_FLAG: 指定待检查的SDIO标志 
  *   	该参数可以是下列值之一:
  *     		SDIO_FLAG_CCRCFAIL: 命令响应已接收(CRC校验失败)
  *     		SDIO_FLAG_DCRCFAIL: 数据块已发送/接收(CRC校验失败)
  *     		SDIO_FLAG_CTIMEOUT: 命令响应超时
  *     		SDIO_FLAG_DTIMEOUT: 数据超时
  *     		SDIO_FLAG_TXUNDERR: 发送FIFO下溢错误
  *     		SDIO_FLAG_RXOVERR:  接收FIFO上溢
  *     		SDIO_FLAG_CMDREND:  命令响应已接收(CRC校验通过)
  *     		SDIO_FLAG_CMDSENT:  命令已发送(不需要响应)
  *     		SDIO_FLAG_DATAEND:  数据传输结束(数据计数器SDIDCOUNT为0)
  *     		SDIO_FLAG_STBITERR: 在宽总线模式下,所有数据线都没检测到起始位
  *     		SDIO_FLAG_DBCKEND:  数据块已发送/接收(CRC校验通过)
  *     		SDIO_FLAG_CMDACT:   正在传输命令
  *     		SDIO_FLAG_TXACT:    正在发送数据
  *     		SDIO_FLAG_RXACT:    正在接收数据
  *     		SDIO_FLAG_TXFIFOHE: 发送FIFO半空
  *     		SDIO_FLAG_RXFIFOHF: 接收FIFO半满
  *     		SDIO_FLAG_TXFIFOF:  发送FIFO满
  *     		SDIO_FLAG_RXFIFOF:  接收FIFO满
  *     		SDIO_FLAG_TXFIFOE:  发送FIFO空
  *     		SDIO_FLAG_RXFIFOE:  接收FIFO空
  *     		SDIO_FLAG_TXDAVL:   发送FIFO中的数据有效
  *     		SDIO_FLAG_RXDAVL:   接收FIFO中的数据有效
  *     		SDIO_FLAG_SDIOIT:   SD I/O 中断已接收
  *     		SDIO_FLAG_CEATAEND: CE-ATA命令CMD61的完成信号已接收
  * 返回值  SDIO标志的状态(SET 或 RESET).
  */
FlagStatus SDIO_GetFlagStatus(uint32_t SDIO_FLAG)
{ 
  FlagStatus bitstatus = RESET;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_FLAG(SDIO_FLAG));
 
  if ((SDIO->STA & SDIO_FLAG) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

[编辑] 函数SDIO_ClearFlag

/**
  * 功能描述  清除SDIO的挂起标志
  * 输入参数  SDIO_FLAG: 指定待清除的标志
  *   该参数可以是下列值之一:
  *     SDIO_FLAG_CCRCFAIL: 命令响应已接收(CRC校验失败)
  *     SDIO_FLAG_DCRCFAIL: 数据块已发送/接收(CRC校验失败)
  *     SDIO_FLAG_CTIMEOUT: 命令响应超时
  *     SDIO_FLAG_DTIMEOUT: 数据超时
  *     SDIO_FLAG_TXUNDERR: 发送FIFO下溢错误
  *     SDIO_FLAG_RXOVERR:  接收FIFO上溢错误
  *     SDIO_FLAG_CMDREND:  命令响应已接收(CRC校验通过)
  *     SDIO_FLAG_CMDSENT:  命令已发送(不需要响应)
  *     SDIO_FLAG_DATAEND:  数据传输结束(数据计数器SDIDCOUNT为0)
  *     SDIO_FLAG_STBITERR: 在宽总线模式下,所有数据线都没检测到起始位
  *     SDIO_FLAG_DBCKEND:  数据块已发送/接收(CRC校验通过)
  *     SDIO_FLAG_SDIOIT:   SD I/O 中断已接收
  *     SDIO_FLAG_CEATAEND: CE-ATA命令CMD61的完成信号已接收
  * 返回值  无
  */
void SDIO_ClearFlag(uint32_t SDIO_FLAG)
{ 
  /* 检查输入参数 */
  assert_param(IS_SDIO_CLEAR_FLAG(SDIO_FLAG));
 
  SDIO->ICR = SDIO_FLAG;
}

[编辑] 函数SDIO_GetITStatus

/**
  * 功能描述  检查指定的SDIO中断是否已发生
  * 输入参数  SDIO_IT: 指定待检查的SDIO中断
  *   该参数可以是下列值之一:
  *     SDIO_IT_CCRCFAIL: 命令响应已接收(CRC校验失败)中断
  *     SDIO_IT_DCRCFAIL: 数据块已发送/接收(CRC校验失败)中断
  *     SDIO_IT_CTIMEOUT: 命令响应超时中断
  *     SDIO_IT_DTIMEOUT: 数据超时中断
  *     SDIO_IT_TXUNDERR: 发送FIFO下溢错误中断
  *     SDIO_IT_RXOVERR:  接收FIFO上溢错误中断
  *     SDIO_IT_CMDREND:  命令响应已接收(CRC校验通过)中断
  *     SDIO_IT_CMDSENT:  命令已发送(不需要响应)中断
  *     SDIO_IT_DATAEND:  数据传输结束(数据计数器SDIDCOUNT为0)中断
  *     SDIO_IT_STBITERR: 在宽总线模式下,所有数据线都没检测到起始位中断
  *     SDIO_IT_DBCKEND:  数据块已发送/接收(CRC校验通过)中断
  *     SDIO_IT_CMDACT:   正在传输命令中断
  *     SDIO_IT_TXACT:    正在发送数据中断
  *     SDIO_IT_RXACT:    正在接收数据中断
  *     SDIO_IT_TXFIFOHE: 发送FIFO半空中断
  *     SDIO_IT_RXFIFOHF: 接收FIFO半满中断
  *     SDIO_IT_TXFIFOF:  发送FIFO满中断
  *     SDIO_IT_RXFIFOF:  接收FIFO满中断
  *     SDIO_IT_TXFIFOE:  发送FIFO空中断
  *     SDIO_IT_RXFIFOE:  接收FIFO空中断
  *     SDIO_IT_TXDAVL:   发送FIFO中的数据有效中断
  *     SDIO_IT_RXDAVL:   接收FIFO中的数据有效中断
  *     SDIO_IT_SDIOIT:   SD I/O 中断已接收中断
  *     SDIO_IT_CEATAEND: CE-ATA命令CMD61的完成信号已接收中断
  * 返回值  SDIO_IT的新状态(SET 或 RESET).
  */
ITStatus SDIO_GetITStatus(uint32_t SDIO_IT)
{ 
  ITStatus bitstatus = RESET;
 
  /* 检查输入参数 */
  assert_param(IS_SDIO_GET_IT(SDIO_IT));
  if ((SDIO->STA & SDIO_IT) != (uint32_t)RESET)  
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

[编辑] 函数SDIO_ClearITPendingBit

/**
  * 功能描述  清除SDIO的中断挂起位
  * 输入参数  SDIO_IT: 指定待清除的中断挂起位
  *   该参数可以是下列值的一个或任意组合:
  *     SDIO_IT_CCRCFAIL: 命令响应已接收(CRC校验失败)中断
  *     SDIO_IT_DCRCFAIL: 数据块已发送/接收(CRC校验失败)中断
  *     SDIO_IT_CTIMEOUT: 命令响应超时中断
  *     SDIO_IT_DTIMEOUT: 数据超时中断
  *     SDIO_IT_TXUNDERR: 发送FIFO下溢错误中断
  *     SDIO_IT_RXOVERR:  接收FIFO上溢错误中断
  *     SDIO_IT_CMDREND:  命令响应已接收(CRC校验通过)中断
  *     SDIO_IT_CMDSENT:  命令已发送(不需要响应)中断
  *     SDIO_IT_DATAEND:  数据传输结束(数据计数器SDIDCOUNT为0)中断
  *     SDIO_IT_STBITERR: 在宽总线模式下,所有数据线都没检测到起始位中断
  *     SDIO_IT_SDIOIT:   SD I/O 中断已接收中断
  *     SDIO_IT_CEATAEND: CE-ATA命令CMD61的完成信号已接收中断
  * 返回值  无
  */
void SDIO_ClearITPendingBit(uint32_t SDIO_IT)
{ 
  /* 检查输入参数 */
  assert_param(IS_SDIO_CLEAR_IT(SDIO_IT));
 
  SDIO->ICR = SDIO_IT;
}

[编辑] SDIO实例

SDIO实例分析

[编辑] 系统结构设计

TB SD卡驱动移植系统结构框图.png

[编辑] 程序设计分析

[编辑] 程序流程图

TB SD卡驱动移植程序流程图.png

[编辑] 代码实现及分析

上代码,初始化代码

[编辑] 实验操作及现象

使用Jlink或者Wiggler下载编译后生成的.hex文件
在没有插入SD卡的情况下,LED0是熄灭的
当正确插入SD卡后,LED0立即点亮

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多