打印

百为STM32开发板教程之十七——SDIO

[复制链接]
10215|43
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xi_liang|  楼主 | 2013-10-19 09:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
百为STM32开发板教程之十七——SDIO

一、SD卡协议
1、SD卡系统的总线拓扑


SD总线包括以下信号:
CLK:  主机对SD卡发出的时钟信号
CMD:  命令/响应信号
DAT0 - DAT3:  数据信号
VDD, VSS1, VSS2:  电源,地信号

上电初始化时,主机发送命令检测卡,并分配地址给每个卡。这是时候的数据是单独发送给每个卡的。
初始化后,命令是同时发送到所有卡的,在每个命令里包含了卡的地址信息。

SD卡总线允许动态配置数据线的宽度,上电初始化时,SD默认采用DAT0传输数据。
初始化完成后,SD总线可以配置数据线的宽度。


2、SD总线协议
SD总线的通信是基于命令和数据位流的,开始于启动位,结束于停止位。
命令(Command):命令是在CMD线上串行传送的。
数据(Data):数据是通过DAT线传送。
响应(Response):响应是卡对从主机接收到的命令进行回应。响应是在CMD线上串行传送的。



卡寻址是通过一个会话地址来实现的,这个会话地址在初始化阶段分配给卡的。
命令、响应和数据块的结构如上图所示。
SD总线上的通信是命令/响应方式(参考上图)。
这种总线通信是直接在命令和响应里传输信息的,另外,有些操作带有数据。

传送到SD或从SD卡读出的数据是以块(block)的形式进行的。数据块是否发送成功是由CRC位决定的。
可以进行单块操作或多块操作。要注意的是,对于快速写入操作来说多块操作是更适合的。
当在CMD线上收到一个STOP命令后,多块操作将被终止。
数据传输可以由主机配置为使用单根数据线或多根数据线(只要卡支持)。

单/多块读操作:


单/多块写操作:
写操作在DATA0线使用一个简单的BUSY信号表明写的状态,而不管数据线是单根数据线或多根数据线。如下图示:


命令(Command)格式:
每个命令开始于0,结束于1。总长度是48位。每个命令有CRC校验,所以能检测到传输错误,并有可能会重发。


响应(Response)格式:
响应根据内容有四种不同格式。长度是48位或136位。这里的CRC检验是16为CCITT多项式。


在CMD线上,MSB位先传输,LSB位后传输。
当使用宽总线时,数据是一次传输4位的。起始位、停止位和CRC位,是单独在每根数据线上传输的。
CRC位是在每根数据线上独立计算和校验的。
CRC响应和BUSY忙指示信号是由卡在DAT0线上发送给主机的(此时DAT1~DAT3忽略)。

数据包(Data)格式:


3、SD管脚和寄存器
SD卡形状和接口:


SD卡管脚分配:

数据线(DAT1~DAT3)上电时只作为输入用,在设置了宽总线模式后作为数据线用。

每张卡有一组信息寄存器:


主机可以通过对卡重新上电来使其复位。每张卡有它自己的上电复位检测电路,使它上电后可以处于一个预先定义的状态。而不需要外接的复位信号。
卡也可以被GO_IDLE命令复位。


SD卡协议被设计为MMC卡协议的超集。主要增加的功能是宽总线模式和内容保护功能。
很容易设计主机系统来支持这两种类型的卡。这样做的目的是使应用程序设计者能够利用现有的基于MMC卡的应用程序,
除非系统离不开快速数据传输(宽总线)和卡内容安全。

SD卡和MMC卡的区别:


除了增加的命令,SD和MMC之间唯一不同的是总线拓扑和初始化协议。
所有MMC卡是统一连接到相同的总线上,是使用开漏输出的同步传输进行被识别的。
每张SD卡和主机是单独的一对一的连接,是串行地依次被识别的。

SD卡协议中的初始化程序主要是成功识别目前连接的卡是MMC卡还是SD卡。
检测到卡后,主机执行初始化程序,结束时返回识别的已知类型的卡。

一旦卡被初始化后,应用程序可以通过各个配置寄存器确定卡的功能,并决定是否使用它。

SD卡的外型尺寸比MMC卡厚(2.1mm VS 1.4mm)。但这样定义后,MMC卡可以很容易插到SD卡槽里去。

SD定义了三种不同的卡检测机制。通过WP开关的机械插入,通过DAT3数据线的上拉电阻的电气插入,或周期性地尝试初始化卡。
由于这几种方式在MMC卡不一定相同,所以建议不要依赖于最优先的卡检测方式。
主机应实现一种查询机制或允许请求卡的信息。

SD卡和MMC卡命令比较表:




沙发
xi_liang|  楼主 | 2013-10-19 09:41 | 只看该作者
4、SD卡功能描述
4.1、概述
卡和主机之间的所有通信是由主机控制的。主机发送的命令包括两种类型:广播命令,指定地址命令。

广播命令:
广播命令是面向所有卡的,有些命令要求返回响应。

指定地址命令:
指定地址命令发送到对应地址的卡,并由此卡返回响应。

SD卡系统定义了两种操作模式(主机和卡):
卡识别模式:
上电后或主机是处于卡识别模式,这时它会在总线上检测新卡。
卡上电后处于卡识别模式,直到它接收到SEND_RCA(CMD3)命令。(如果是MMC卡,则是SET_RCA命令)

数据传输模式:
一旦卡的RCA首次公布,卡会进入数据传输模式。
在识别了总线上的所有的卡后,主机会进入数据传输模式。

下面的表表明了卡的状态和操作模式的关系。每一个状态都对应着一个操作模式。


4.2、卡识别模式
在卡识别模式中,主机复位所有处于卡识别模式的卡,验证卡的电压操作范围,识别卡并请求卡返回RCA地址。
这个操作是在每个卡的CMD线上单独操作的。在卡识别模式中,所有数据通信只使用CMD线。

4.2.1、卡复位
GO_IDLE_STATE (CMD0)命令是软件复位命令,它会使每个卡进入空闲(Idle)状态而不管卡当前所处的状态。
处于不活动状态的卡不受此命令的影响。

由主机上电之后,所有卡处于空闲(Idle)状态(包括之前处于不活动状态的卡)。

在上电或接收到CMD0命令之后,所有卡的CMD线处于输入模式,等待下一个命令的起始位。
所有卡被初始化为默认的RCA地址(RCA=0x0000)和默认的驱动层寄存器设置(最低速率,最高电流驱动能力)。

4.2.2、操作电压范围验证
所有卡使用最大允许电压范围内的任何电压与主机建立通信。
所支持的最小和最大电压范围是在OCR(Operation Conditions Register)寄存器中定义,可能不覆盖所有卡的电压范围。
只有支持这些电压范围的卡,其CID和CSD数据才能被访问。这意味着,如果主机和卡具有不兼容的电压范围,那么卡的CID和CSD数据就不能被访问,也不能完成卡的识别过程。

因此,有一个命令SD_SEND_OP_COND (ACMD41)是特意设计来给主机识别和拒绝与主机期望的电压范围不匹配的卡的。
这是通过主机以一个电压范围为这个命令的参数,发送命令来实现的。
不支持此电压范围的卡将放弃总线并进入不活动状态。
卡所支持的电压范围是在OCR寄存器中定义的。见后面OCR详细介绍。
要注意的是ACMD41是应用程序特殊命令,发送ACMD41之前必须先发送APP_CMD(CMD55)。
在空闲状态下,CMD55所使用的RCA是卡的默认值RCA = 0x0000。

MMC卡不会回应ACMD41,实际上它是不回应ACMD41之前的APP_CMD(CMD55)。
MMC卡应依照MMC协议规范被使用SEND_OP_COND (CMD1)命令进行初始化。
主机应忽略MMC卡回应CMD3命令的ILLEGAL_COMMAND状态,因为这个ACMD41残留的状态。(CMD0,1,2不清除状态寄存器)。
实际中,主机将使用ACMD41命令和CMD1命令来识别系统中的SD卡和MMC卡。


卡识别模式流程图:

通过发送忽略电压范围的命令,主机可以查询每个卡,并在使不兼容卡进入非活动状态之前,确定通用电压范围。
主机可以选择一个通用的电压范围,或者期望不使用的卡的应用程序通知时,可以使用此查询。
总之,主机必须选择一个电压操作范围,并在这个条件下重发ACMD41命令,使不兼容卡进入非活动状态。

ACMD41命令的响应中的忙(busy)位,是卡用来告诉主机它正处于上电或复位状态,并且暂时不能通信。
在这种情况下,主机必须重复ACMD41命令,直到忙位被清除。

在初始化过程中,主机不允许改变电压操作范围。此类改变将会被卡忽略。
如果需要改变操作电压范围,主机必须用CMD0命令复位所有卡,并重新开始初始化流程。
并且,如果需要访问所有不活动状态的卡,必须进行硬复位(重新上电)。

GO_INACTIVE_STATE (CMD15) 命令可以用来使一个定址了的卡进入不活动状态。
这个命令可以在主机明确地需要使卡进入非活动状态的时候使用。(例如,主机正在改变电压范围,而已知道卡不在此电压范围内时)

4.2.3、卡的识别过程
主机以时钟速率fOD(后面会提到)开始卡识别流程。在SD卡中,CMD线是开漏输出。

总线启动后,主机要求卡返回它们的有效操作条件(在带参数RCA=0x0000的APP_CMD CMD55命令之后,发送ACMD41 )。
ACMD41命令的响应是OCR(operation condition register)。同样的命令将会发送到系统中所有的新卡。不兼容的卡将被发送进入不活动状态。
主机可以发送ALL_SEND_CID (CMD2)命令到每张卡,来获得卡的CID(unique card identification)。未被识别的卡(如处于就绪状态的卡)将在CMD线上发送其CID作为响应。
在发送了CID之后,卡进入鉴别状态。
然后主机发送SEND_RELATIVE_ADDR(CMD3),要求卡返回其RCA(relative card address)。这个RCA比CID短,并且将在后面的数据传输中用来对卡寻址(尤其是速率比fOD高的时候)。
一旦RCA被接收后,卡将进入待机状态。此时,如果主机需要另外一个RCA号,它会用同样的SEND_RELATIVE_ADDR(CMD3)命令要求卡返回一个新的RCA号码。最后返回的RCA号作为卡的实际RCA号。

主机重复上面的识别过程,反复发送CMD2,CMD3命令来识别每张卡。

在初始化完所有SD卡后,主机将使用MMC协议规范里的CMD2和CMD3来初始化系统中的MMC卡。要注意的是,在SD卡中,所有卡是单独连接的,所以MMC卡将被单独初始化。

4.3数据传输模式
在CSD寄存器的内容被主机知道之前,所有卡都是运行在速率fOD上,因为某些卡可能有操作频率限制。
主机发送SEND_CSD (CMD9) 来获得卡的CSD(Card Specific Data)寄存器内容,如块长度,卡存储容量,最大时钟速率等。

卡数据传输模式流程图:


广播命令SET_DSR (CMD4) 配置已识别卡的驱动层寄存器。它会将应用程序对应的总线长度,总线上卡的数量和卡的传输速率写入到DSR寄存器。
SET_DSR对于卡和主机是个可选的命令。

CMD7用来选中一张卡并使其进入传输状态。同一时刻只有一张卡处于传输状态。如果当前卡正在处于传输状态,它会断开与主机的连接,并进入待机状态。
如果CMD7命令是发送到RCA地址0x0000,则所有卡都进入待机状态。这个可以用在识别新卡之前(在不复位已初始化卡的情况下)。
在这种状态中,已经有RCA的卡,不会回应识别命令(如CMD41, CMD2, CMD3)。

在数据传输模式中,主机和选中卡的所有通信都是点对点的(使用定址命令)。所有定址命令由CMD线上的响应确认。

数据传输模式中的所有关系概括如下:
• 所有数据读命令可以被CMD12命令终止。数据传输将被终止,而卡将返回到传输状态。读命令是:块读(CMD17),多块读(CMD18),发送写保护 (CMD30),发送SCR(ACMD51),和读模式中的通用命令(CMD56)。
• 所有数据写命令可以被CMD12命令终止。写命令必须在CMD7命令(取消选中卡)之前终止。写命令是:块写(CMD24 and CMD25),写CID (CMD26),写CSD (CMD27),
锁定/解锁命令(CMD42),和写模式中的通用命令(CMD56)。
• 一旦传输完成,卡将会退出写状态,并进入编程状态(写成功)或传输状态(写失败)。
• 如果块写操作停止,并且块长度和最后一个块的CRC有效,则数据将被编程写入。
• 卡会为块写提供缓冲,因此当上一个块正在被编程的同时,下一个块的数据可以被发送到卡。如果所有写缓冲满了,只要卡是在编程状态,则DAT0线将保持低电平(BUSY)。
• 对于写CID,写CSD,写保护和擦除,是不支持缓冲的。这意味着,当卡处于忙状态时,这些命令是不能被接收的。只要卡是在编程状态,则DAT0线将保持低点平(BUSY)。
实际上,如果各卡的DAT0线是分开的,则主机可以仍然可以在其中一张卡处于忙时,访问另一张卡。
• 当卡正在编程时,参数设置命令是不允许的。参数设置命令是:设置块程度(CMD16),擦除块开始(CMD32),擦除块结束(CMD33)。
• 当卡正在编程时,读命令是不允许的。
• 使用CMD7命令将卡从待机状态切换到传输状态,不会终止擦除和编程操作。卡将切换到断开连接状态并释放DAT线。
• 在断开连接状态下,使用CMD7命令可以将卡取消选中。此时卡将进入编程状态,并恢复忙指示。
• 使用CMD0或CMD15命令复位卡,将终止任何正在进行的编程操作。这种情况可能会损坏卡的数据内容。主机应避免这样的操作。

4.3.1总线宽度选择
宽总线(4位总线宽度)操作模式可以通过ACMD6选择或取消选择。复位或GO_IDLE(CMD0)命令之后,默认的总线宽度是1bit。
ACMD6命令只在传输状态下有效。这意味着总线宽度只有在卡被CMD7命令选中之后才能被改变。

4.3.2读数据
当无数据传输时,DAT线被拉高为高电平。
数据传输开始于低电平(1或4位低电平),接着是连续的数据流。数据流包含有payload数据(包含错误校正位,如果使用了ECC),数据流以高电平结束(1或4位高电平)。
数据传输是以时钟信号同步的。基于块数据传输的payload是由1或4位CRC校验和保护的。

从SD读数据的操作会被关断电源中断。SD卡在任何情况下都会保护其数据内容不会被损坏(写操作和擦除操作除外),即使在突然断开电源或被移除的时候。

块读
块读是基于块的数据传输。数据传输的基本单位是块,其最大值定义在CSD (READ_BL_LEN)中。
起始地址和结束地址包含在一个物理块中的较小的块也可以被传输。
SD卡能传输512字节的块是个强制性的要求。

为确保数据传输的完整性,CMD17(READ_SINGLE_BLOCK)命令开始块读,并且传输完成后,进入传输状态。
CMD18 (READ_MULTIPLE_BLOCK)命令开始连续的块传输。块将被连续地传送,直到收到STOP_TRANSMISSION(CMD12)命令。
由于是串行的传输,这个停止命令有一个执行的延迟。在接收到停止命令的最后一位时,传输将停止。

如果主机正在使用部分块,其累计长度是不对齐的,并且块错位是不允许的。那么卡应该在第一个错位块的开始检测到错位,并设置状态寄存器中的ADDRESS_ERROR位,
取消传输,并在数据状态中等待停止命令。

4.3.3写数据
写数据的数据传输格式和读数据类似。基于块的数据写传输,CRC校验位被附加到每个数据块中。
在写入数据之前,卡为每个接收到的数据块提供1或4位的CRC奇偶校验。因此,可以防止错误传输数据的写入。

块写
在块写(CMD24 - 27,42,56(w))期间,一个或多个块数据被主机传送到卡,每个块的结尾由主机附加1位或4位的CRC校验。
支持快写的卡总是能接受由WRITE_BL_LEN定义长度的块数据和512字节及其倍数的数据。(例如写1024字节长的数据,那写1024字节的块和写512字节的块都是支持的)。
如果WRITE_BL_PARTIAL = 1,那么写更小的块甚至1字节,也是可以被使用的。
如果CRC错误,那么卡会在DAT线上标记错误;传输的数据将被丢弃而不写入,后面传输的块数据(在多块传输中)将被忽略。

为了使写操作更快速,应该使用多块写命令,而不是使用单块写命令连续写。

如果主机正在使用部分块,其累计长度是不对齐的,并且块错位是不允许的(CSD parameter WRITE_BLK_MISALIGN is not set)。那么卡应该在第一个错位块的开始检测到错位,并设置状态寄存器中的ADDRESS_ERROR位,取消传输,并在数据接收状态中等待停止命令。

如果主机在一个写保护块上写数据,写操作将会被取消。在这种情形下,卡会设置WP_VIOLATION位。

编程写入CID和CSD寄存器之前,不需要进行块长度的设置。这时传输的数据也是CRC保护的。
如果CID和CSD寄存器的一部分是存储在ROM中,那么这个不可改变的部分必须匹配在接收缓冲区中的相应部分。如果这个匹配失败,那么卡将会报告错误,并不改变任何寄存器内容。

某写卡写一个块的数据需要较长的和不确定的时间。接收到一个块数据并完成校验后,如果写缓冲区满,并且不能接受一个新的WRITE_BLOCK命令的数据时,卡将开始写入数据并把DAT0线保持为低电平。
主机可以在任何时刻通过SEND_STATUS(CMD13)命令查询卡的状态,卡将会返回它的状态。状态位READY_FOR_DATA表示卡可接受新数据或它正在写入数据。
主机可以发出CMD7命令取消选择卡(去选择另一个卡),它会使卡进入断开连接状态,并释放DAT线而不会打断写操作的进行。
当重新选择卡时,如果写入仍然在进行并且写缓冲区满,那它会把DAT线拉低恢复忙指示。
实际上,主机会对所有卡同时进行交错的写操作。交错写是通过在其他卡忙时单独地存取每张卡来实现的。这个过程是通过适当的CMD和DAT0~3线的操作来实现的。

多块写操作之前的预擦除
在写操作之前加上(ACMD23)命令设置块写的数量,会比没有加(ACMD23)命令写的速度要块。主机将使用这个命令来定义下一个写操作将要发送多少个块。
如果主机在所有数据被发送到卡之前终止写操作(使用停止命令),那么剩余未写块的内容是未知的(可能被擦除,也可能是旧的数据)。
如果主机要发送的块数量比ACMD23定义的要多,那么卡将会一块一块地擦除(和接收到新数据一样)。
在多块写完成后,这个数量将会复位到默认值(=1)。

建议在CMD25之前使用此命令,对于多块写操作来说速度将会更快。如果主机需要使用预擦除功能,则必须在写命令之前使用ACMD23命令。否则,其他命令执行时预擦除计数将被自动清零。

发送块写的数量
在使用管道机制的数据缓冲区的系统中,在某些情况下,如果在多块写操作的中间发生错误,是无法确定哪个块是最后被写入到闪存中的。卡将会响应ACMD22命令返回已写块的数量。

4.3.4擦除
通过同时擦除很多个要写入的块来提高数据传输量是可行的。
检验这些块写入是否完成用ERASE_WR_BLK_START(CMD32)和ERASE_WR_BLK_END(CMD33)命令。
主机必须按照以下的命令顺序进行:ERASE_WR_BLK_START,ERASE_WR_BLK_END 和ERASE (CMD38)。
如果擦除命令ERASE (CMD38),地址设置命令(CMD32)和(CMD33)不是按照顺序被接收,那么卡将会在状态寄存器中设置ERASE_SEQ_ERROR位,并复位整个顺序。

如果接收到一个未按顺序的命令(SEND_STATUS除外),卡将会设置状态寄存器中的ERASE_RESET位,复位擦除顺序,并执行最后一个命令。

如果擦除范围包括写保护扇区,那这些扇区将保持不变,只有非保护区才被擦除。同时状态寄存器中的WP_ERASE_SKIP位被设置。

地址设置命令(CMD32和CMD33)中的地址域是一个以字节为单位的块地址。卡将会忽略所有LSB小于WRITE_BLK_LEN大小的数据。

如之前对块写的描述,当擦除正在进**会将DAT0线拉低。实际擦除的时间可能会很长,主机可能会发出CMD7取消选择卡或将卡断开连接,如之前对块写的描述一样。

4.3.5应用程序特定命令
SD卡协议是定义为向前兼容MMC卡协议的。
SD卡是被设计为各种应用提供各种各样的接口的。
为了保持MMC卡标准和新SD卡专用命令的兼容性,SD卡使用应用程序特定命令来实现它的专用命令。
以下是APP_CMD 和GEN_CMD命令的定义。

应用程序特定命令 -  APP_CMD (CMD55)
当卡接收到此命令时,会导致卡将紧接着的下一个命令解析为应用程序特定命令,ACMD。
ACMD和标准的MMC卡命令一样具有一样的结构,并具有相同的CMD号。
只要这个命令是出现在APP_CMD之后,卡会将它标记为ACMD。

APP_CMD的效果是,如果紧接着的命令是有ACMD定义的,那么非标准的命令被使用(ACMD)。例如,卡有ACMD13定义,而没有ACMD7定义,
那么紧跟在APP_CMD命令后,命令13将认作为ACMD13非标准命令,而命令7将被认作为CMD7标准命令。
为了使用一个厂商特定ACMD,主机将会:
• 发送APP_CMD命令。响应将会有APP_CMD位设置返回给主机,表示卡期望接收ACMD命令。
• 发送期望的ACMD命令。响应将会有APP_CMD位设置,表示命令被看作为ACMD。如果一个非ACMD的命令被发送,那么它将会被认作为标准的SD卡命令,并且卡将会清除状态寄存器中的APP_CMD位。

如果一个非有效命令(既不是ACMD,也不是CMD)被发送,那么它将会被当作为标准SD卡非法命令错误处理。

从SD卡协议的角度来看,ACMD号被厂商定义是有一定限制的。以下的ACMD号是被SD卡协议保留的,而不能被厂商定义的:
ACMD6,ACMD13, ACMD17-25, ACMD38-49, ACMD51。

通用命令 - GEN_CMD (CMD56)
GEN_CMD命令的总线传输和块读或块写(CMD24 或 CMD17)命令是一样的。不同的是它的参数表示数据传输的方向而不是地址。数据块不是一个内存负载型的数据,但是有厂商定义的格式和意义。在发送CMD56命令之前,卡应被设置为传输状态。传输的数据块大小是由CMD16定义的BLOCK_LEN大小。 响应CMD56的是R1响应。

使用特权

评论回复
板凳
xi_liang|  楼主 | 2013-10-19 09:41 | 只看该作者


4.5错误条件
4.5.1 CRC和非法命令
所有命令是受CRC位保护的。如果定址卡的CRC校验失败,则卡不会返回响应并且命令不会被执**不会改变其状态,状态寄存器中的COM_CRC_ERROR位被设置。
类似地,如果卡接收到非法命令,卡不会改变其状态,不会返回响应,并且状态寄存器中的ILLEGAL_COMMAND位将被设置。
有各种不同的非法命令:
• 命令属于类,但卡不支持(如只读卡中的写命令)。
• 命令在当前状态中不允许(如传输状态中的CMD2)。
• 命令未定义(如CMD5)。

4.5.2读、写和擦除超时条件
读、写和擦除操作的超时时间是正常访问时间的100倍。卡必须在这个时间内完成命令或者取消并返回错误信息。如果主机在指定的时间内没有得到任何响应,则它会假设卡将不再返回响应,并尝试恢复(例如复位卡,电源周期,拒绝卡等)。正常访问时间定义如下:
• 读
正常读访问的时间是由CSD参数TAAC和NSAC给定的两个时间之和定义的。这些参数定义了读命令的结束位和块数据的开始位之间的延时。这些参数是因卡而异的,应被主机用来计算流读
的吞吐量和最大频率。
• 写
CSD中的R2W_FACTOR是用来计算正常的块编程时间的,通过将正常读访问时间乘以这个系数获得。它适用于所有的写/擦除命令(如SET(CLEAR)_WRITE_PROTECT, PROGRAM_CSD(CID)和块写命令)
• 擦除
擦除命令的持续时间是等于要擦除的块数量乘以块写的时间。

4.6命令
4.6.1命令类型
共定义有4种命令来控制SD卡的:
• 广播命令,无响应(bc)
• 广播命令,有响应(bcr)
• 定址命令,无数据在DAT上传输(ac)
• 定址命令,有数据在DAT上传输(adtc)
所有命令和响应都是在SD卡的CMD线上传输。

4.6.2命令格式
所有命令都有个固定的长度——48位。

一个命令总是以起始位'0'开始,接着一个方向位(主机='1'),然后6位表示命令的序号,这个值是一个二进制码(从0到63)。有些命令需要一个参数(如一个地址),这个是32位的。
所有命令都是受CRC保护的。每个命令都是终止位'1'结束。

4.6.3命令类集
SD卡的命令集被分为各种类集。每一个类支持一组卡功能。
命令类集0, 2, 4, 5 和 8是强制性的,必须被所有SD卡支持。其他类集是可选的。



4.6.4详细命令描述

基本命令(class 0):


基于块的读命令(class 2):

①  数据传输不能跨越物理块边界除非CSD中的READ_BLK_MISALIGN被设置。
基于块的写命令(class 4):

①  数据传输不能跨越物理块边界除非CSD中的WRITE_BLK_MISALIGN被设置。

基于块的写保护命令(class 6):


擦除命令(class 5):


锁卡命令(class 7):


应用程序特定命令(class 8):


以下表格描述SD卡支持/保留的所有应用程序特殊命令。所有ACMD命令都必须紧跟在APP_CMD (CMD55)命令之后。


4.7响应
所有响应都是在CMD线上被发送。响应的编码长度取决于响应的类型。
所有响应开始于起始位(通常为‘0’),接着一位表示传输的方向(card = ‘0’),所有响应(除开响应类型R3)是受CRC保护的。每个响应的编码结束于停止位(通常为‘1’)。
共有4种类型的响应,格式定义如下:
R1响应 正常的响应命令


R2响应 (CID, CSD 寄存器)


R3响应 (OCR寄存器)


R6响应 (发布RCA地址响应)


4.8 SD卡状态
SD卡支持两种卡状态如下:
Card Status:兼容MMC卡协议
SD_Status: 扩展512位状态域,支持SD专用特性和未来应用特性。

4.8.1 Card Status
响应格式R1包含有一个称为Card Status的32位域。这个域是用来传输卡的状态信息的(卡状态是存放在本地状态寄存器中的)。
如果没有指定,状态通常是对应之前发生的命令的。

各种不同的状态定义如下表
类型和清除条件域缩写如下:
类型
E:错误位
S:起始位
R:实际命令的响应的测检和设置
X:命令执行时的检测和设置。主机必须通过状态命令查询卡来读这些位。

清除条件
A:根据卡当前状态
B:通常与之前的命令相关。接收到一个有效的命令将会清除它。
C:读时清除





4.8.2 SD Status
SD Status包含有SD专有特性的状态位,并可以在将来的应用中使用。SD Status的大小是一个数据块512bit的大小。这个寄存器的内容是在DAT线上被发送到主机的,并附有16位CRC校验。
ACMD13只可以在传输状态(卡被选中)中被发送到卡。SD Status的结构定义如下:

使用特权

评论回复
地板
xi_liang|  楼主 | 2013-10-19 09:42 | 只看该作者
SDIO程序分析
/*
  * @file    stm32_eval_sdio_sd.c
  * @author  MCD Application Team
  * @version V4.4.0
*/

主要函数:
void SD_DeInit(void);
SD_Error SD_Init(void);
SDTransferState SD_GetStatus(void);
SDCardState SD_GetState(void);
uint8_t SD_Detect(void);
SD_Error SD_PowerON(void);
SD_Error SD_PowerOFF(void);
SD_Error SD_InitializeCards(void);
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo);
SD_Error SD_EnableWideBusOperation(uint32_t WideMode);
SD_Error SD_SetDeviceMode(uint32_t Mode);
SD_Error SD_SelectDeselect(uint32_t addr);
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
SDTransferState SD_GetTransferState(void);
SD_Error SD_StopTransfer(void);
SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
SD_Error SD_SendStatus(uint32_t *pcardstatus);
SD_Error SD_SendSDStatus(uint32_t *psdstatus);
SD_Error SD_ProcessIRQSrc(void);

下面对所有函数进行一一分析,首先是SD_Init函数。
这个函数用来初始化SD卡。
首先调用SD_LowLevel_Init函数初始化STM32的SDIO所使用的GPIO端口,SD卡插入检测端口,开启SDIO时钟,开启DMA2时钟。
然后调用SD_PowerON函数开启SDIO电源、时钟,复位卡到空闲状态,发送CMD55命令识别是MMC卡或SD卡,如果是SD卡,则发送ACMD41识别和拒绝与主机期望的电压范围不匹配的SD卡。
再调用SD_InitializeCards函数发送CMD2命令,获取卡的CID数据;发送CMD3命令,要求卡返回其RCA地址;发送CMD9命令,获取卡的CSD数据。
读取CSD,CID数据保存到结构体指针cardinfo中,选中卡,设置总线宽度,设置传输模式为DMA模式。
/**
  * @brief  Initializes the SD Card and put it into StandBy State (Ready for data
  *         transfer).
  * @param  None
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_Init(void)
{
  SD_Error errorstatus = SD_OK;
  
  /* SDIO外设底层初始化 */
  SD_LowLevel_Init();
  SDIO_DeInit();
  errorstatus = SD_PowerON();
  if (errorstatus != SD_OK)
  {
    /* CMD 响应超时 (等待CMDSENT标志) */
    return(errorstatus);
  }
  errorstatus = SD_InitializeCards();
  if (errorstatus != SD_OK)
  {
    /* CMD 响应超时 (等待CMDSENT标志) */
    return(errorstatus);
  }
  /* 配置SDIO外设 */
  /* SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
  SDIO_Init(&SDIO_InitStructure);
  
  if (errorstatus == SD_OK)
  {
    /*----------------- 读 CSD/CID 寄存器 ------------------*/
    errorstatus = SD_GetCardInfo(&SDCardInfo);
  }
  if (errorstatus == SD_OK)
  {
    /*----------------- 选中 Card --------------------------------*/
    errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));
  }
  if (errorstatus == SD_OK)
  {
    errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);
  }  
  /* 设置器件传输模式为DMA */
  if (errorstatus == SD_OK)
  {  
    errorstatus = SD_SetDeviceMode(SD_DMA_MODE);
  }
  
  return(errorstatus);
}

使用特权

评论回复
5
xi_liang|  楼主 | 2013-10-19 09:43 | 只看该作者
SD_LowLevel_Init函数初始化STM32的SDIO所使用的GPIO端口,SD卡插入检测端口,开启SDIO时钟,开启DMA2时钟
/**
  * @brief  Initializes the SD Card and put it into StandBy State (Ready for
  *         data transfer).
  * @param  None
  * @retval None
  */
void SD_LowLevel_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  /* 使能 GPIOC 和 GPIOD */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);
  /* 配置 PC.08, PC.09, PC.10, PC.11, PC.12 管脚: D0, D1, D2, D3, CLK 管脚 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  /* 配置 PD.02 CMD线 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  /* 配置 SD_SPI_DETECT_PIN 管脚: SD卡检测管脚 */
  GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);
  
  /* 使能 SDIO AHB 时钟 */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);
  /* 使能 DMA2 时钟 */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
}

使用特权

评论回复
6
xi_liang|  楼主 | 2013-10-19 09:43 | 只看该作者
SD_PowerON函数开启SDIO电源、时钟,复位卡到空闲状态,发送APP_CMD CMD55命令识别是MMC卡还是SD卡,
如果是SD卡,则发送ACMD41识别和拒绝与主机期望的电压范围不匹配的SD卡。
/**
  * @brief  Enquires cards about their operating voltage and configures
  *   clock controls.
  * @param  None
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_PowerON(void)
{
  SD_Error errorstatus = SD_OK;
  uint32_t response = 0, count = 0, validvoltage = 0;
  uint32_t SDType = SD_STD_CAPACITY;
  /*!< Power ON Sequence -----------------------------------------------------*/
  /* 配置SDIO外设 */
  /* SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) */
  /* 初始化的SDIO_CK 不能超过 400 KHz */  
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
  SDIO_Init(&SDIO_InitStructure);
  /* 开启SDIO电源 */
  SDIO_SetPowerState(SDIO_PowerState_ON);  //设置SDIO电源控制寄存器(SDIO_POWER)的值为SDIO_PowerState_ON(0x00000003),即上电状态。
  /* 使能SDIO时钟 */
  SDIO_ClockCmd(ENABLE);  //设置SDIO时钟控制寄存器(SDIO_CLKCR)第8位的值为1,即SDIO_CK使能。
  /* CMD0: 复位卡到空闲状态 ---------------------------------------------------*/
  /* No CMD response required */
  SDIO_CmdInitStructure.SDIO_Argument = 0x0;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdError();
  if (errorstatus != SD_OK)
  {
    /* CMD 响应超时 (等待 CMDSENT 标志) */
    return(errorstatus);
  }
  /* CMD8: SEND_IF_COND ----------------------------------------------------*/
  /* 发送 CMD8来检验卡接口操作条件*/
  /* 参数: - [31:12]: 保留 (应设为 '0')
               - [11:8]: 电源电压 (VHS) 0x1 (范围: 2.7-3.6 V)
               - [7:0]: 检查模式 (要求为 0xAA) */
  /* CMD 响应: R7 */
  SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp7Error();
  if (errorstatus == SD_OK)
  {
    CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /* SD Card 2.0 */
    SDType = SD_HIGH_CAPACITY;
  }
  else
  {
    /* APP_CMD CMD55应用程序特殊命令 */
    SDIO_CmdInitStructure.SDIO_Argument = 0x00;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
  }
  /* APP_CMD CMD55应用程序特殊命令 */
  SDIO_CmdInitStructure.SDIO_Argument = 0x00;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
  /* 如果 errorstatus 是 Command TimeOut,那么这个是 MMC 卡,因为MMC卡不会回应APP_CMD CMD55命令 */
  /* 如果 errorstatus 是 SD_OK ,那这个是SD卡: SD card 2.0 (电压范围缺失)或者 SD card 1.x */
  if (errorstatus == SD_OK)
  {
    /* SD CARD */
    /* 发送 ACMD41 SD_APP_OP_COND,参数为0x80100000 */
    while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
    {
      /* 发送 CMD55 APP_CMD ,参数 RCA 为 0 */
      SDIO_CmdInitStructure.SDIO_Argument = 0x00;
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);
      errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
      if (errorstatus != SD_OK)
      {
        return(errorstatus);
      }
      SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);
      errorstatus = CmdResp3Error();
      if (errorstatus != SD_OK)
      {
        return(errorstatus);
      }
      response = SDIO_GetResponse(SDIO_RESP1);
      validvoltage = (((response >> 31) == 1) ? 1 : 0);
      count++;
    }
    if (count >= SD_MAX_VOLT_TRIAL)
    {
      errorstatus = SD_INVALID_VOLTRANGE;
      return(errorstatus);
    }
    if (response &= SD_HIGH_CAPACITY)
    {
      CardType = SDIO_HIGH_CAPACITY_SD_CARD;
    }
  }/*!< else MMC Card */
  return(errorstatus);
}

使用特权

评论回复
7
xi_liang|  楼主 | 2013-10-19 09:43 | 只看该作者
SD_InitializeCards函数发送CMD2命令,获取卡的CID数据;发送CMD3命令,请求卡返回RCA地址;发送CMD9命令,获取卡的CSD数据。
/**
  * @brief  Intialises all cards or single card as the case may be Card(s) come
  *         into standby state.
  * @param  None
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_InitializeCards(void)
{
  SD_Error errorstatus = SD_OK;
  uint16_t rca = 0x01;
  if (SDIO_GetPowerState() == SDIO_PowerState_OFF)
  {
    errorstatus = SD_REQUEST_NOT_APPLICABLE;
    return(errorstatus);
  }
  if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)
  {
    /*发送 CMD2(ALL_SEND_CID)命令,获取卡的CID数据 */
    SDIO_CmdInitStructure.SDIO_Argument = 0x0;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp2Error();
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
    CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
    CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
    CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
    CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
  }
  if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) ||  (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) ||  (SDIO_SECURE_DIGITAL_IO_COMBO_CARD == CardType)
      ||  (SDIO_HIGH_CAPACITY_SD_CARD == CardType))
  {
    /* 发送 CMD3(SET_REL_ADDR)命令,参数为 0 */
    /* SD卡返回其RCA地址. */
    SDIO_CmdInitStructure.SDIO_Argument = 0x00;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca);
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
  }
  if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)
  {
    RCA = rca;
    /* 发送 CMD9(SEND_CSD)命令,获取卡的CSD数据,参数为卡的RCA地址 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp2Error();
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
    CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
    CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
    CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
    CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
  }
  errorstatus = SD_OK; /* 所有卡被初始化完毕 */
  return(errorstatus);
}

使用特权

评论回复
8
xi_liang|  楼主 | 2013-10-19 09:44 | 只看该作者
下面这几个函数只作简要介绍
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo); //这个函数是把获得的卡的所有信息存放到SD_CardInfo结构体指针cardinfo中。
SD_Error SD_EnableWideBusOperation(uint32_t WideMode);  //设置总线数据宽度为4位或1位(不支持8位),MMC卡不支持此特性。
SD_Error SD_SetDeviceMode(uint32_t Mode); //设置数据传输模式为DMA模式,中断模式或查询模式

SD_SelectDeselect函数选中卡,函数的参数为卡的地址
/**
  * @brief  Selects od Deselects the corresponding card.
  * @param  addr: Address of the Card to be selected.
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_SelectDeselect(uint32_t addr)
{
  SD_Error errorstatus = SD_OK;

  /* 发送 CMD7(SDIO_SEL_DESEL_CARD)命令 */
  SDIO_CmdInitStructure.SDIO_Argument =  addr;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEL_DESEL_CARD;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);

  errorstatus = CmdResp1Error(SD_CMD_SEL_DESEL_CARD);

  return(errorstatus);
}

使用特权

评论回复
9
xi_liang|  楼主 | 2013-10-19 09:45 | 只看该作者
/**
  * @摘要:  允许从卡中的指定地址读一个块的数据
  * @参数  readbuff: 指向存放接收到数据的buffer
  * @参数  ReadAddr: 将要读数据的地址
  * @参数  BlockSize: SD卡数据块的大小
  * @retval SD_Error: SD卡错误代码
  */
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize)
{
  SD_Error errorstatus = SD_OK;
  uint32_t count = 0, *tempbuff = (uint32_t *)readbuff;
  uint8_t power = 0;
  if (NULL == readbuff)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  TransferError = SD_OK;
  TransferEnd = 0;
  TotalNumberOfBytes = 0;
  /* 清除所有DPSM 配置 */
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 0;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  SDIO_DMACmd(DISABLE);
  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }
  
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    BlockSize = 512;
    ReadAddr /= 512;
  }
  if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
  {
    power = convert_from_bytes_to_power_of_two(BlockSize);
    /*设置SD卡的块大小 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
  SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  TotalNumberOfBytes = BlockSize;
  StopCondition = 0;
  DestBuffer = (uint32_t *)readbuff;
  /*发送 CMD17(READ_SINGLE_BLOCK)命令 */
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  /*如果是单块传输,不需要手动去停止传输*/
  if (DeviceMode == SD_POLLING_MODE)
  {
    /*查询模式 */
    while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))
    {
      if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)
      {
        for (count = 0; count < 8; count++)
        {
          *(tempbuff + count) = SDIO_ReadData();
        }
        tempbuff += 8;
      }
    }
    if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
      errorstatus = SD_DATA_TIMEOUT;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
      errorstatus = SD_DATA_CRC_FAIL;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
      errorstatus = SD_RX_OVERRUN;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_STBITERR);
      errorstatus = SD_START_BIT_ERR;
      return(errorstatus);
    }
    while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
    {
      *tempbuff = SDIO_ReadData();
      tempbuff++;
    }
    /*!< Clear all the static flags */
    SDIO_ClearFlag(SDIO_STATIC_FLAGS);
  }
  else if (DeviceMode == SD_INTERRUPT_MODE)
  {
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_RXFIFOHF | SDIO_IT_STBITERR, ENABLE);
    while ((TransferEnd == 0) && (TransferError == SD_OK))
    {}
    if (TransferError != SD_OK)
    {
      return(TransferError);
    }
  }
  else if (DeviceMode == SD_DMA_MODE)
  {
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
    SDIO_DMACmd(ENABLE);
    SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, BlockSize);
    while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
    {}
    if (TransferError != SD_OK)
    {
      return(TransferError);
    }
  }
  return(errorstatus);
}

使用特权

评论回复
10
xi_liang|  楼主 | 2013-10-19 09:45 | 只看该作者
/**
  * @摘要:  允许从卡中的指定地址读多个块的数据
  * @参数  readbuff: 指向存放接收到数据的buffer
  * @参数  ReadAddr: 将要读数据的地址
  * @参数  BlockSize: SD卡数据块的大小
  * @参数  NumberOfBlocks: 要读的块的数量
  * @返回值 SD_Error: SD卡错误代码
  */
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  SD_Error errorstatus = SD_OK;
  uint32_t count = 0, *tempbuff = (uint32_t *)readbuff;
  uint8_t power = 0;
  if (NULL == readbuff)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  TransferError = SD_OK;
  TransferEnd = 0;
  TotalNumberOfBytes = 0;
  /* 清除所有DPSM 配置 */
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 0;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  SDIO_DMACmd(DISABLE);
  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    BlockSize = 512;
    ReadAddr /= 512;
  }
  
  if ((BlockSize > 0) && (BlockSize <= 2048) && (0 == (BlockSize & (BlockSize - 1))))
  {
    power = convert_from_bytes_to_power_of_two(BlockSize);
    /*设置SD卡块的大小 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  if (NumberOfBlocks > 1)
  {
    /*!< Common to all modes */
    if (NumberOfBlocks * BlockSize > SD_MAX_DATA_LENGTH)
    {
      errorstatus = SD_INVALID_PARAMETER;
      return(errorstatus);
    }
    TotalNumberOfBytes = NumberOfBlocks * BlockSize;
    StopCondition = 1;
    DestBuffer = (uint32_t *)readbuff;
    SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
    SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
    SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
    SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
    SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
    SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
    SDIO_DataConfig(&SDIO_DataInitStructure);
    /* 发送 CMD18(READ_MULT_BLOCK)命令,参数为要读数据的地址 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_READ_MULT_BLOCK);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
    if (DeviceMode == SD_POLLING_MODE)
    {
      /* 查询模式 */
      while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DATAEND | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR)))
      {
        if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)
        {
          for (count = 0; count < SD_HALFFIFO; count++)
          {
            *(tempbuff + count) = SDIO_ReadData();
          }
          tempbuff += SD_HALFFIFO;
        }
      }
      if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
        errorstatus = SD_DATA_TIMEOUT;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
        errorstatus = SD_DATA_CRC_FAIL;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
        errorstatus = SD_RX_OVERRUN;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_STBITERR);
        errorstatus = SD_START_BIT_ERR;
        return(errorstatus);
      }
      while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
      {
        *tempbuff = SDIO_ReadData();
        tempbuff++;
      }
      if (SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)
      {
        /*如果发送STOP_TRANSMISSION命令 */
        if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType))
        {
          /*发送 CMD12(STOP_TRANSMISSION)命令 */
          SDIO_CmdInitStructure.SDIO_Argument = 0x0;
          SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
          SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
          SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
          SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
          SDIO_SendCommand(&SDIO_CmdInitStructure);
          errorstatus = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
          if (errorstatus != SD_OK)
          {
            return(errorstatus);
          }
        }
      }
      /*!< Clear all the static flags */
      SDIO_ClearFlag(SDIO_STATIC_FLAGS);
    }
    else if (DeviceMode == SD_INTERRUPT_MODE)
    {
      /* 中断模式 */
      SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_RXFIFOHF | SDIO_IT_STBITERR, ENABLE);
      while ((TransferEnd == 0) && (TransferError == SD_OK))
      {}
      if (TransferError != SD_OK)
      {
        return(TransferError);
      }
    }
    else if (DeviceMode == SD_DMA_MODE)
    {
      /* DMA模式 */
      SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
      SDIO_DMACmd(ENABLE);
      SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * BlockSize));
      while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
      {}
      if (TransferError != SD_OK)
      {
        return(TransferError);
      }
    }
  }
  return(errorstatus);
}

使用特权

评论回复
11
xi_liang|  楼主 | 2013-10-19 09:46 | 只看该作者
/**
  * @摘要:  允许从卡中的指定地址写一个块的数据
  * @参数  writebuff: 指向存放将要发送数据的buffer
  * @参数  WriteAddr: 将要写数据的地址
  * @参数  BlockSize: SD卡数据块的大小
  * @返回值 SD_Error: SD卡错误代码
  */
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize)
{
  SD_Error errorstatus = SD_OK;
  uint8_t  power = 0, cardstate = 0;
  uint32_t timeout = 0, bytestransferred = 0;
  uint32_t cardstatus = 0, count = 0, restwords = 0;
  uint32_t *tempbuff = (uint32_t *)writebuff;
  if (writebuff == NULL)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  TransferError = SD_OK;
  TransferEnd = 0;
  TotalNumberOfBytes = 0;
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 0;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  SDIO_DMACmd(DISABLE);
  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    BlockSize = 512;
    WriteAddr /= 512;
  }
  
  /*设置主机和卡的块的大小 */
  if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
  {
    power = convert_from_bytes_to_power_of_two(BlockSize);
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  /*等待卡准备好接收数据 */
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_SEND_STATUS);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  cardstatus = SDIO_GetResponse(SDIO_RESP1);
  timeout = SD_DATATIMEOUT;
  while (((cardstatus & 0x00000100) == 0) && (timeout > 0))
  {
    timeout--;
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SEND_STATUS);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
    cardstatus = SDIO_GetResponse(SDIO_RESP1);
  }
  if (timeout == 0)
  {
    return(SD_ERROR);
  }
  /*发送 CMD24(WRITE_SINGLE_BLOCK)命令 */
  SDIO_CmdInitStructure.SDIO_Argument = WriteAddr;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_WRITE_SINGLE_BLOCK);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  TotalNumberOfBytes = BlockSize;
  StopCondition = 0;
  SrcBuffer = (uint32_t *)writebuff;
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
  SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  /*如果是单块传输不需要停止命令*/
  if (DeviceMode == SD_POLLING_MODE)
  {
    /* 查询模式 */
    while (!(SDIO->STA & (SDIO_FLAG_DBCKEND | SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR)))
    {
      if (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)
      {
        if ((TotalNumberOfBytes - bytestransferred) < 32)
        {
          restwords = ((TotalNumberOfBytes - bytestransferred) % 4 == 0) ? ((TotalNumberOfBytes - bytestransferred) / 4) : (( TotalNumberOfBytes -  bytestransferred) / 4 + 1);
          for (count = 0; count < restwords; count++, tempbuff++, bytestransferred += 4)
          {
            SDIO_WriteData(*tempbuff);
          }
        }
        else
        {
          for (count = 0; count < 8; count++)
          {
            SDIO_WriteData(*(tempbuff + count));
          }
          tempbuff += 8;
          bytestransferred += 32;
        }
      }
    }
    if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
      errorstatus = SD_DATA_TIMEOUT;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
      errorstatus = SD_DATA_CRC_FAIL;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
      errorstatus = SD_TX_UNDERRUN;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_STBITERR);
      errorstatus = SD_START_BIT_ERR;
      return(errorstatus);
    }
  }
  else if (DeviceMode == SD_INTERRUPT_MODE)
  {
    /* 中断模式 */
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_FLAG_TXFIFOHE | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
    while ((TransferEnd == 0) && (TransferError == SD_OK))
    {}
    if (TransferError != SD_OK)
    {
      return(TransferError);
    }
  }
  else if (DeviceMode == SD_DMA_MODE)
  {
    /* DMA模式 */
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
    SD_LowLevel_DMA_TxConfig((uint32_t *)writebuff, BlockSize);
    SDIO_DMACmd(ENABLE);
    while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
    {}
    if (TransferError != SD_OK)
    {
      return(TransferError);
    }
  }
  /*!< Clear all the static flags */
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);
  /*等待卡退出编程状态 */
  errorstatus = IsCardProgramming(&cardstate);
  while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)))
  {
    errorstatus = IsCardProgramming(&cardstate);
  }
  return(errorstatus);
}

使用特权

评论回复
12
xi_liang|  楼主 | 2013-10-19 09:46 | 只看该作者
/**
  * @摘要  允许从卡中的指定地址写多个块的数据
  * @参数  WriteAddr: 将要写数据的地址
  * @参数  writebuff: 指向存放将要发送数据的buffer
  * @参数  BlockSize: SD卡数据块的大小
  * @参数  NumberOfBlocks: 要写的块的数量
  * @返回值l SD_Error: SD卡错误代码
  */
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  SD_Error errorstatus = SD_OK;
  uint8_t  power = 0, cardstate = 0;
  uint32_t bytestransferred = 0;
  uint32_t restwords = 0;
  uint32_t *tempbuff = (uint32_t *)writebuff;
  __IO uint32_t count = 0;
  
  if (writebuff == NULL)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  TransferError = SD_OK;
  TransferEnd = 0;
  TotalNumberOfBytes = 0;
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 0;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  SDIO_DMACmd(DISABLE);
  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    BlockSize = 512;
    WriteAddr /= 512;
  }
  
  /*设置主机和卡的块的大小 */
  if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
  {
    power = convert_from_bytes_to_power_of_two(BlockSize);
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }
  /*等待卡准备好接收数据 */
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_SEND_STATUS);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  if (NumberOfBlocks > 1)
  {
    /*!< Common to all modes */
    if (NumberOfBlocks * BlockSize > SD_MAX_DATA_LENGTH)
    {
      errorstatus = SD_INVALID_PARAMETER;
      return(errorstatus);
    }
    if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == CardType))
    {
      /*!< To improve performance */
      SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);

      errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
      if (errorstatus != SD_OK)
      {
        return(errorstatus);
      }
      /*!< To improve performance */
      SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)NumberOfBlocks;
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT;
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);
      errorstatus = CmdResp1Error(SD_CMD_SET_BLOCK_COUNT);
      if (errorstatus != SD_OK)
      {
        return(errorstatus);
      }
    }
    /*发送 CMD25(WRITE_MULT_BLOCK)命令, 参数为要写数据的地址 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)WriteAddr;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_WRITE_MULT_BLOCK);
    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
    TotalNumberOfBytes = NumberOfBlocks * BlockSize;
    StopCondition = 1;
    SrcBuffer = (uint32_t *)writebuff;
    SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
    SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
    SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
    SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
    SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
    SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
    SDIO_DataConfig(&SDIO_DataInitStructure);
    if (DeviceMode == SD_POLLING_MODE)
    {
      /* 查询模式 */
      while (!(SDIO->STA & (SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DATAEND | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR)))
      {
        if (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)
        {
          if (!((TotalNumberOfBytes - bytestransferred) < SD_HALFFIFOBYTES))
          {
            for (count = 0; count < SD_HALFFIFO; count++)
            {
              SDIO_WriteData(*(tempbuff + count));
            }
            tempbuff += SD_HALFFIFO;
            bytestransferred += SD_HALFFIFOBYTES;
          }
          else
          {
            restwords = ((TotalNumberOfBytes - bytestransferred) % 4 == 0) ? ((TotalNumberOfBytes - bytestransferred) / 4) :
                        ((TotalNumberOfBytes - bytestransferred) / 4 + 1);
            for (count = 0; count < restwords; count++, tempbuff++, bytestransferred += 4)
            {
              SDIO_WriteData(*tempbuff);
            }
          }
        }
      }
      if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
        errorstatus = SD_DATA_TIMEOUT;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
        errorstatus = SD_DATA_CRC_FAIL;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
        errorstatus = SD_TX_UNDERRUN;
        return(errorstatus);
      }
      else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
      {
        SDIO_ClearFlag(SDIO_FLAG_STBITERR);
        errorstatus = SD_START_BIT_ERR;
        return(errorstatus);
      }
      if (SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)
      {
       if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == CardType))
        {
          /*发送 CMD12(STOP_TRANSMISSION)命令 */
          SDIO_CmdInitStructure.SDIO_Argument = 0x0;
          SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
          SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
          SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
          SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
          SDIO_SendCommand(&SDIO_CmdInitStructure);

          errorstatus = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
          if (errorstatus != SD_OK)
          {
            return(errorstatus);
          }
        }
      }
    }
    else if (DeviceMode == SD_INTERRUPT_MODE)
    {
      /* 中断模式 */
      SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXFIFOHE | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
      while ((TransferEnd == 0) && (TransferError == SD_OK))
      {}
      if (TransferError != SD_OK)
      {
        return(TransferError);
      }
    }
    else if (DeviceMode == SD_DMA_MODE)
    {
     /* DMA模式 */
      SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
      SDIO_DMACmd(ENABLE);
      SD_LowLevel_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * BlockSize));
      while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
      {}
      if (TransferError != SD_OK)
      {
        return(TransferError);
      }
    }
  }
  /*!< Clear all the static flags */
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);
  
  /* 查询卡状态之前先延时一下 */
  for(count = 0; count < 0xFFFF; count++)
  {
  }
  /* 查询卡状态,等待卡退出编程状态 */
  errorstatus = IsCardProgramming(&cardstate);
  while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)))
  {
    errorstatus = IsCardProgramming(&cardstate);
  }
  return(errorstatus);
}

使用特权

评论回复
13
xi_liang|  楼主 | 2013-10-19 09:46 | 只看该作者
下面两个函数只作简单介绍
SDTransferState SD_GetTransferState(void);  //获取SDIO是否正在传输状态,这个函数没有被调用到
SD_Error SD_StopTransfer(void);  //发送CMD12(STOP_TRANSMISSION)命令停止传输

/**
  * @摘要  允许擦除卡指定的内存区域
  * @参数  startaddr: 起始地址
  * @参数  endaddr: 结束地址
  * @返回值 SD_Error: SD卡错误代码
  */
SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr)
{
  SD_Error errorstatus = SD_OK;
  uint32_t delay = 0;
  __IO uint32_t maxdelay = 0;
  uint8_t cardstate = 0;
  /* 检查卡命令集是否支持擦除命令 */
  if (((CSD_Tab[1] >> 20) & SD_CCCC_ERASE) == 0)
  {
    errorstatus = SD_REQUEST_NOT_APPLICABLE;
    return(errorstatus);
  }
  maxdelay = 120000 / ((SDIO->CLKCR & 0xFF) + 2);
  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    startaddr /= 512;
    endaddr /= 512;
  }
  
  /* 根据 sd-card spec 1.0,发送ERASE_GROUP_START (CMD32) 和 erase_group_end(CMD33)命令 */
  if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == CardType))
  {
    /* 发送CMD32(SD_ERASE_GRP_START)命令,参数为 startaddr */
    SDIO_CmdInitStructure.SDIO_Argument = startaddr;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_START;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_START);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
    /*发送CMD33 (SD_ERASE_GRP_END)命令,参数为endaddr  */
    SDIO_CmdInitStructure.SDIO_Argument = endaddr;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_END;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_END);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
  }
  /*发送 CMD38 (ERASE)命令 */
  SDIO_CmdInitStructure.SDIO_Argument = 0;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ERASE;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_ERASE);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  for (delay = 0; delay < maxdelay; delay++)
  {}
  /*等待卡退出编程状态 */
  errorstatus = IsCardProgramming(&cardstate);
  while ((errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate)))
  {
    errorstatus = IsCardProgramming(&cardstate);
  }
  return(errorstatus);
}

使用特权

评论回复
14
xi_liang|  楼主 | 2013-10-19 09:47 | 只看该作者
SD_Error SD_SendStatus(uint32_t *pcardstatus) //返回卡的状态寄存器
SD_Error SD_SendSDStatus(uint32_t *psdstatus) //这个函数没有被调用到

/**
  * @摘要  处理SD卡中断
  * @参数  无
  * @返回值 SD_Error:SD卡错误代码
  */
SD_Error SD_ProcessIRQSrc(void)
{
  uint32_t count = 0, restwords = 0;
  if (DeviceMode == SD_INTERRUPT_MODE)
  {
    /* 中断模式 */
    if (SDIO_GetITStatus(SDIO_IT_RXFIFOHF) != RESET)
    {
      for (count = 0; count < SD_HALFFIFO; count++)
      {
        *(DestBuffer + count) = SDIO_ReadData();
      }
      DestBuffer += SD_HALFFIFO;
      NumberOfBytes += SD_HALFFIFOBYTES;
    }
    else if (SDIO_GetITStatus(SDIO_IT_TXFIFOHE) != RESET)
    {
      if ((TotalNumberOfBytes - NumberOfBytes) < SD_HALFFIFOBYTES)
      {
        restwords = ((TotalNumberOfBytes - NumberOfBytes) %  4 == 0) ?
                    ((TotalNumberOfBytes - NumberOfBytes) / 4) :
                    ((TotalNumberOfBytes - NumberOfBytes) / 4 + 1);
        for (count = 0; count < restwords;  count++, SrcBuffer++, NumberOfBytes += 4)
        {
          SDIO_WriteData(*SrcBuffer);
        }
      }
      else
      {
        for (count = 0; count < SD_HALFFIFO; count++)
        {
          SDIO_WriteData(*(SrcBuffer + count));
        }
        SrcBuffer += SD_HALFFIFO;
        NumberOfBytes += SD_HALFFIFOBYTES;
      }
    }
  }
  if (SDIO_GetITStatus(SDIO_IT_DATAEND) != RESET)
  {
    if (DeviceMode != SD_DMA_MODE)
    {
      while ((SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)  &&  (NumberOfBytes < TotalNumberOfBytes))
      {
        *DestBuffer = SDIO_ReadData();
        DestBuffer++;
        NumberOfBytes += 4;
      }
    }
    if (StopCondition == 1)
    {
      TransferError = SD_StopTransfer();
    }
    else
    {
      TransferError = SD_OK;
    }
    SDIO_ClearITPendingBit(SDIO_IT_DATAEND);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    TransferEnd = 1;
    NumberOfBytes = 0;
    return(TransferError);
  }
  if (SDIO_GetITStatus(SDIO_IT_DCRCFAIL) != RESET)
  {
    SDIO_ClearITPendingBit(SDIO_IT_DCRCFAIL);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    NumberOfBytes = 0;
    TransferError = SD_DATA_CRC_FAIL;
    return(SD_DATA_CRC_FAIL);
  }
  if (SDIO_GetITStatus(SDIO_IT_DTIMEOUT) != RESET)
  {
    SDIO_ClearITPendingBit(SDIO_IT_DTIMEOUT);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    NumberOfBytes = 0;
    TransferError = SD_DATA_TIMEOUT;
    return(SD_DATA_TIMEOUT);
  }
  if (SDIO_GetITStatus(SDIO_IT_RXOVERR) != RESET)
  {
    SDIO_ClearITPendingBit(SDIO_IT_RXOVERR);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    NumberOfBytes = 0;
    TransferError = SD_RX_OVERRUN;
    return(SD_RX_OVERRUN);
  }
  if (SDIO_GetITStatus(SDIO_IT_TXUNDERR) != RESET)
  {
    SDIO_ClearITPendingBit(SDIO_IT_TXUNDERR);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    NumberOfBytes = 0;
    TransferError = SD_TX_UNDERRUN;
    return(SD_TX_UNDERRUN);
  }
  if (SDIO_GetITStatus(SDIO_IT_STBITERR) != RESET)
  {
    SDIO_ClearITPendingBit(SDIO_IT_STBITERR);
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |
                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |
                  SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE);
    NumberOfBytes = 0;
    TransferError = SD_START_BIT_ERR;
    return(SD_START_BIT_ERR);
  }
  return(SD_OK);
}

使用特权

评论回复
15
xi_liang|  楼主 | 2013-10-19 09:47 | 只看该作者
3.5固件库SDIO代码修改:
3.5固件库例程\STM32F10x_StdPeriph_Examples\SDIO\uSDCard

把V4.5.0的下面两个文件替换成V4.4.0的(可以从官方USB库里拷贝过来,USB库里的SDIO是没有问题的)
stm32_eval_sdio_sd.c
stm32_eval_sdio_sd.h

然后把用到下面两个函数的地方注释掉,因为V4.4.0没有这两个函数,也不需要用这两个函数。
//    /* Check if the Transfer is finished */
//    Status = SD_WaitReadOperation();
//    while(SD_GetStatus() != SD_TRANSFER_OK);

//    /* Check if the Transfer is finished */
//    Status = SD_WaitWriteOperation();
//    while(SD_GetStatus() != SD_TRANSFER_OK);

还要把时钟修改:
/* SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */
这里HCLK = 72Mhz,SDIO时钟SDIO_CK = 72Mhz/2 = 36Mhz太高了,改为72Mhz/3 = 24Mhz
/**
  * @brief  SDIO Data Transfer Frequency (25MHz max)
  */

#define SDIO_TRANSFER_CLK_DIV            ((uint8_t)0x00)
改为
#define SDIO_TRANSFER_CLK_DIV            ((uint8_t)0x01)

改好的程序已上传到网盘
百为STM32_SDIO测试程序.rar

使用特权

评论回复
16
outstanding| | 2013-10-19 11:02 | 只看该作者

使用特权

评论回复
17
闲来找无事| | 2013-10-19 17:10 | 只看该作者
mark

使用特权

评论回复
18
trumpxp| | 2013-10-19 19:57 | 只看该作者
帖子很详细   很好的学习帖子  楼主   比较有意思  谢谢了  楼主   顶一个

使用特权

评论回复
19
拿起书本| | 2013-10-19 20:10 | 只看该作者
还是很不错的贴子,需要花点时间好好钻研钻研,顶起来,感谢分享

使用特权

评论回复
20
YDCMAN| | 2013-10-19 21:10 | 只看该作者
写的不错,有PDF下载吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:http://baiweijishu.taobao.com/ 百为STM32开发板 兼容官方STM3210E-EVAL开发板 WM-G-MR-09 WIFI开发板

41

主题

285

帖子

10

粉丝