STM32F4_SD卡

news2024/11/26 19:21:29

目录

前言

1. SDIO协议简介

2. SDIO命令及响应

3. SD卡的操作模式及切换

4. STM32的SDIO接口

5. SDIO结构体

6. SDIO相关寄存器

7. 实验程序

7.1 main.c

7.2 SDIO_Card.c

7.3 SDIO_Card.h


前言

        在之前的单片机学习过程中,我们已经了解到了单片机系统都需要大容量的存储设备,以存储数据。目前比较常用的是U盘、FLASH芯片,SD卡。他们各有优先,其中SD卡的容量可以做到很大(32GB以上),支持SPI/SDIO驱动,以满足用户对大容量单片机内存读取数据的要求。

        在STM32F4中,只需要几个简单的IO口就可以外扩一个32GB以上的外部存储器,容量从几十M到几十G;STM32F4自带了一个标准的SD卡接口,使用STM32F4自带的SDIO接口驱动。

        本节我们就来学习STM32F4的SD卡外设!!!

1. SDIO协议简介

        SD卡(Secure Digital Memory Card)在我们日常生活中已经是很普遍了,控制器对SD卡的读写通信操作一般有两种通信接口可选一种是SPI接口另外一种是SDIO接口SDIO全称是安全数字输入/输出接口,像多媒体卡(MMC)、SD卡、SD I/O卡都有SDIO接口。

SD存储卡目前主要是分为三种:SD(不大于2GB)、SDHC(大于2GB,不大于32GB)、SDXC(大于32GB,不大于2TGB)

SD卡物理结构:

        一张SD卡包括有:存储单元存储单元接口电源检测接口控制器和接口驱动器5个部分 

存储单元是存储数据的部件,存储单元通过存储单元接口与卡控制单元进行数据传输;

电源检测单元保证SD卡工作在合适的电压下,如果出现掉电或者上电状态时,它会使存储单元接口和卡控制单元复位(也就是图中电源检测指向的Reset);

卡及接口控制单元控制SD卡的运行状态,主要包括8个寄存器;这8个寄存器用于设定或表示SD卡信息。

接口驱动器控制SD卡引脚的输入输出;

注:

        卡及接口控制单元的8个寄存器只能通过对应的命令去访问,SDIO定义了64个命令,每个命令都有特殊的意义,可以实现某一特定的功能,SD卡接收到命令后,根据命令要求对SD卡内部寄存器进行修改,从而实现SD卡的控制及读写操作;

        这类似于我们宏定义64个命令,然后设置读写程序,读写这些命令即可实现SD卡的控制及读写操作;

SD卡寄存器列表:

  1.         CID寄存器:128位,卡识别号(Card Identification Number):用来识别的卡的个体号码(这个个体号码是唯一的)
  2.         RCA寄存器:16位,相对地址(Relative Card Address):卡的本地系统地址,初始化时,动态地由卡建议,主机审核
  3.         DSR寄存器:16位,驱动级寄存器(Driver Stage Register):配置卡的输出驱动
  4.         CSD寄存器:128位,卡的特定数据(Card Specific Data):卡的操作条件信息
  5.         SCR寄存器:64位,SD配置寄存器(SD Configuration Register):SD卡特殊特性信息
  6.         OCR寄存器:32位,操作条件寄存器(Operation condition Register)
  7.         SSR寄存器:512位,SD状态(SD Status):SD卡专有特性的信息
  8.         CSR寄存器:32位,卡状态(Card Status):卡状态信息

SD卡总线拓扑:

总线拓扑结构总线型拓扑结构简称为总线拓扑,它是将网络中各个节点设备用一根总线挂接起来,实现计算机网络的功能。(类似于IIC、SPI的总线结构)

        

如上图,总线拓扑结构中:

        左侧HOST为STM32主机,右侧分别是卡槽A和卡槽B,卡槽A和卡槽B共用总线时钟CLK,但是卡槽A和卡槽B各自拥有自己独立的数据线和主机进行通讯;

SD卡引脚简介:

        SD卡采用9-Pin接口通信,其中3根电源线,1根时钟线,1根命令线和4根数据线;

        

SDIO CLK:时钟线,由SDIO主机产生,即由STM32控制器输出;

SDIO CMD:命令控制器,SDIO主机通过该线发送命令控制SD卡,如果命令要求SD卡提供应答,那么SD卡也是通过该线传输应答信息;

SDIO D0-3:数据线,传输读写数据;SD卡可以将D0拉低表示忙碌状态

VSS VDD GND:电源和地信号;

SDIO总线:

        SDIO的通信时序比较简单,SDIO不管是STM32主机控制器向SD卡传输,还是SD卡向STM32传输,都是以CLK时钟的上升沿为有效。(也就是说,不管是主从方向还是从主方向都是CLK时钟上升沿有效)

        SD卡操作过程会使用两种不同的频率的时钟同步数据一个是识别卡阶段时钟频率FOD,最高为400KHz;另外一个是数据传输模式下时钟频率FPP,默认最高为25MHz(如果通过寄存器配置使SDIO工作在高速模式,此时的数据传输模式最高频率为50MHz)

SDIO总线协议:

        SD总线通信是基于命令和数据传输的。通讯由一个起始位(“0”),由一个停止位(“1”)终止。SD通信一般是主机发送一个命令(Command),从设备在接收到命令后作出响应(Response),如果有需要会有数据(Data)传输参与。

SD卡传输可以有响应,也可以没有响应;(例如上图中左侧,主机发送Command命令到SD卡,SD卡不作响应的情况下进行数据传输;右侧主机发送Command命令到SD卡,SD卡发送应答信号通过CMD总线传输至主机)

        SD数据以块Black形式传输,SDHC卡数据块长度一般为512字节,数据可以从主机到卡,也可以从卡到主机。数据块需要CRC校验位(CRC位由SD卡系统硬件生成)来保证数据传输成功。STM32控制器可以控制使用单线或4线传输。

写数据的过程如上图:主机发送Command命令到从机,然后从机发送应答信号到主机,主机写数据到卡,以数据块的方式写数据到SD卡,其中数据块中包括CRC校验位(保证数据传输成功),以及可以将SDIO D0引脚拉低表示忙碌状态;

如果想要突然停止数据的发送,那么同样也是可以主机发送Command命令,从机做出应答,通过数据块发送命令和CRC校验位,使得数据停止发送。

        SD卡数据传输支持单块和多块读写,分别对应不同的操作命令。数据写入之前需要检测SD卡忙状态,因为SD卡接收到数据后编程到存储区过程需要一定的操作时间。忙状态通过把D0引脚拉低来实现。

        数据块读操作是不需要忙状态检测的;(因为忙状态是接收数据到数据存储区的过程需要时间,所以需要判断状态;读的过程中无此步骤)

4数据线传输:

        使用4数据线传输时,每次传输4bit数据,每根数据线都必须有起始位、终止位和CRC校验位,CRC位每根数据线都要分别检查,并把检查结果汇总然后在数据传输完后通过D0线反馈给主机

        SD卡数据包有两种格式,一种是常规数据(8bit宽),它先发低字节,然后发高字节,而每个字节则是先发高位再发低位

另外一种数据包发送格式是宽位数据包格式,对SD卡而言,宽位数据包发送方式是针对SD卡SSR状态寄存器内容发送的,SSR寄存器总共有512位,在主机发出ACMD13命令后SD卡将SSR寄存器内容通过DAT线发送给主机。

发送数据包的方式相同,也是1个时钟周期内发送4位数据,从高位到低位进行发送;

2. SDIO命令及响应

        SD命令是由主机发出的,以广播命令和寻址命令为例,广播命令是针对于SD主机总线连接的所有从设备发出的(广播命令就类似于我一个STM32的SD卡总线上挂载着卡槽A和卡槽B以及卡槽C,那么通过广播命令发送的指令所有卡槽都可以收到),寻址命令是指定某个地址设备进行命令传输的(而寻址命令是针对于某个固定卡槽来讲的,可以是主机和卡槽A通信,也可能是主机和卡槽B进行通信)。

命令格式:

        SD命令格式固定为48bit,都是通过CMD命令线连续传输的,数据线不参与。

SD命令的格式是固定的,起始位是0,终止位是1,分别各占一位,命令的主体包含在起始位和终止位之间;起始位以后,有一个传输标志1,占一位;命令+地址信息(CONTENT)占6+32位,其中命令占6位,地址信息占32位;最后有一个CRC校验位,这些校验位是通过算法提供的,占7位;

命令格式:

        命令号:他固定占用6位,总共有64个命令(代号:CMD0~CMD63),每个命令都有特殊的用途,部分命令不适用于SD卡操作,只是专门用于MMC卡或者SD I/O卡

        地址/参数:每个命令有32位地址信息/参数用于命令附加内容,例如,广播命令没有地址信息,这32位用于指定参数;寻址命令这32位用于指定目标SD卡的地址

        CRC7校验:长度为7位的校验位用于验证命令传输内容的正确性,如果发生外部干扰导致传输数据个别位状态改变将导致校验失败,也意味着命令传输失败,SD卡不执行命令

命令类型:

        SD命令有4种类型:

无响应广播命令(bc),发送到所有卡,不返回任务响应;

带响应广播命令(bcr),发送到所有卡,同时接收来自所有卡响应;

寻址命令(ac),发送到选定卡,DAT线无数据传输;

寻址数据传输命令(adtc),发送到选定卡,DAT线有数据传输;

        另外,SD卡主机模块系统旨在为各种应用程序类型提供一个标准接口。为实现这些功能,在标准中定义了两种类型的通用命令:特定应用命令(ACMD)常规命令(GEN_CMD)。要使用SD卡制造商特定的ACMD命令,需要在发送该命令之前发送CMD55命令,告知SD卡接下来的命令为特定应用命令,CMD55只对紧接着的第一个命令有效,SD卡如果检测到CMD55之后的命令为ACMD则执行特定应用命令,如果检测发现不是ACMD命令,则执行常规命令GEN_CMD;

基本命令简介:

基本命令(Class 0)

        CMD0:GO_IDLE_STATE,复位所有的卡到idle状态

        CMD2:ALL_SEND_CID,通知所有卡通过CMD命令线返回CID的值

        CMD3:SEND_RELATIVE_ADDR,通知所有卡发布新RCA

        CMD4:SET_DSR,编程所有卡的DSR

        CMD7:SELECT/DESELECT_CARD,选择/取消选择RCA地址卡

        CMD8:SEND_IF_COND,发送SD卡接口条件,包含主机支持的电压信息,并询问卡是否支持

        CMD9:SEND_CSD,选定卡通过CMD线发送CSD内容

        CMD10:SEND_CID,选定卡通过CMD线发送CID内容

        CMD12:STOP_TRANSMISSION,强制卡停止传输

        CMD13:SEND_STATUS,选定卡通过CMD线发送它的状态寄存器

        CMD15:GO_INACTIVE_STATE,使选定卡进入 “inactive” 状态

面向块的读操作(Class 2)

        CMD16:SET_BLOCK_LEN,对于标准的SD卡,设置块命令的长度,对于SDHC卡块命令长度固定为512字节

        CMD17:READ_SINGLE_BLOCK,对于标准卡,读取SEL_BLOCK_LEN长度字节的块;对于SDHC卡,读取512字节的块

        CMD18:READ_MULTIPLE_BLOCK,连续从SD卡读取数据块,直到被CMD12中断。块长度同CMD17

面向块的写操作(Class 4)

        CMD24:WRITE_BLOCK,对于标准卡,写入SEL_BLOCK_LEN长度字节的块;对于SDHC卡,写入512字节的块

        CMD25:WRITE_MILTIPLE_BLOCK,连续向SD卡写入数据块,直到被CMD12中断。块长度同CMD17

        CMD27:PROGRAM_CSD,对CSD的可编程位进行编程

擦除命令(Class 5)

        CMD32:ERASE_WR_BLK_START,设置擦除的起始块地址

        CMD33:ERASE_WR_BLK_END,设置擦除的结束块地址

        CMD38:ERASE,擦除预先选定的块

加载命令(Class 7)

        CMD42:LOCK_UNLOCK,加载/解锁SD卡

特定应用命令(Class 8)

        CMD55:APP_CMD,指定下一个命令为特定应用命令,不是标准命令

        CMD56:GEN_CMD,通用命令,或者特定应用命令中,用于传输一个数据块,最低位为1表示读数据,为0表示写数据

SD卡特定应用命令

        ACMD6:SET_BUS_WIDTH,定义数据总线宽度(‘00’=1bit,‘10’=4bit)

        ACMD13:SD_STATUS,发送SD状态

        ACMD41:SD_SEND_OP_COND,主机要求卡发送它的支持信息(HCS)和OCR寄存器内容

        ACMD51:SEND_SCR,读取配置寄存器SCR

3. SD卡的操作模式及切换

SD卡操作模式:

        SD卡系统(包括主机和SD卡)定义了两种操作模式:卡识别模式和数据传输模式。在系统复位后,主机处于卡识别模式,寻找总线上可用的SDIO设备;同时卡也处于卡识别模式,直到被主机识别到(类似于IIC的空闲状态),当SD卡接收到SEND_RCA(CMD3)命令后,SD卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式。

SD卡操作模式下的状态:

 

        在每一种操作模式下,SD卡都有几种状态。

卡识别模式:

数据传输模式:

4. STM32的SDIO接口

        STM32控制器有一个SDIO,由两部分组成:SDIO适配器和APB2接口SDIO适配器提供SDIO主机功能,可以提供SD时钟、发送命令和进行数据传输。APB2接口用于控制器访问SDIO适配器寄存器并且可以产生中断和DMA请求信号。

(简单来说就是SDIO适配器提外部引脚和SD卡相连,分别由时钟引脚SDIO_CLK、命令引脚SDIO_CMD和数据引脚SDIO_D;APB2接口是STM32控制器和SDIO适配器访问的中间媒介,STM32必须通过APB2接口才可以访问SDIO适配器,并且APB2接口可以产生中断和DMA请求信号,中断和DMA请求信号都是相对于STM32控制器而言的)

SDIO使用两个时钟信号(如上图),一个是SDIO适配器时钟(SDIOCLK=48MHz)另外一个是APB2总线时钟(PCLK2,一般是84MHz)

STM32控制器的SDIO是针对MMC卡和SD卡的主要设备,所以预留有8根数据线,根据原理图上可知,SD卡最多只用4根数据线。

SDIO适配器内部逻辑框图:

        SDIO适配器由五个单元组成,分别是控制单元、命令路径单元、数据路径单元、寄存器单元以及FIFO。

命令路径控制命令发送,并接受卡的响应,当SD卡处于某一状态时,SDIO适配器必然处于特定状态与之对应。STM32控制器以命令路径状态机(CPSM)来描述SDIO适配器状态变化,并加入了等待超时检测功能,以便退出永久等待的情况。 

数据FIFO(先进先出)部件是一个数据缓冲器,带发送和接收单元。控制器的FIFO包含宽度为32bit、深度为32字的数据缓冲器和发送/接收逻辑。

        SDIO状态寄存器(SDIO_STA)的TXACT位用于指示当前正在发送数据,RXACT位指示当前正在接收数据,这两个位不可能同时为1;

  • 当TXACT为1时,可以通过APB2接口将数据写入到传输FIFO。
  • 当RXACT为1时,   接收FIFO存放从数据路径部件接收到的数据。

5. SDIO结构体

//SDIO初始化结构体

typedef struct
{
    uint32_t SDIO_ClockEdge;  //时钟沿
                              //主时钟SDIOCLK产生的CLK引脚时钟有效沿选择,可选择上升沿或者下降沿
                                //SDIO_ClockEdge_Falling或者SDIO_ClockEdge_Rising
    uint32_t SDIO_ClockBypass;  //旁路时钟
                                //时钟分频旁路使用,可选择使能或者禁用
    uint32_t SDIO_ClockPowerSave;  //节能模式
                                   //节能模式,可选择使能或者禁用
    uint32_t SDIO_BusWide;     //数据宽度
                                //选择1位或者4位数据
    uint32_t SDIO_HardwareFlowControl; //硬件流控制
                                    //可选择使能或者禁用
                                    //硬件流控制功能可以避免FIFO发送上溢和下溢错误
    uint8_t  SDIO_ClockDiv;    //时钟分频
                            
}SDIO_InitTypeDef;
//SDIO命令初始化结构体


typedef struct
{
    uint32_t SDIO_Argument;   //命令参数 
                              //作为命令的一部分发送到卡的命令参数    
    uint32_t SDIO_CmdIndex;   //命令号
                              //CMD16 16就是命令号
    uint32_t SDIO_Response;   //响应类型
                              //长响应还是短响应
    uint32_t SDIO_Wait;       //等待使能 等待类型选择
                              //一种是无等待状态,超时检测功能启动
                              //一种是等待中断
                              //另外一种是等待传输完成 
    uint32_t SDIO_CPSM;       //命令路径状态机
                              //使能
}SDIO_CmdInitTypeDef;
//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;          //数据路径状态机
}SDIO_DataInitTypeDef;

6. SDIO相关寄存器

1. SDIO电源控制寄存器(SDIO_POWER)

该寄存器的电源复位值为0,所以SDIO的电源是关闭的,我们要启动SDIO,第一步就是电源控制寄存器的最低两位为11,让SDIO上电,开启卡时钟。

2. SDIO时钟控制寄存器(SDIO_CLKCR)

位12:11 WIDBUS:宽总线模式使能位

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

位10 BYPASS:时钟分频器旁路使能位

  •         0:禁止旁路,在驱动SDIO_CK输出信号前,根据CLKDIV值对SDIOCLK进行分频
  •         1:使能旁路,SDIOCLK直接驱动SDIO_CK输出信号

位8 CLKEN:时钟使能位

  •         0:禁止SDIO_CK
  •         1:使能SDIO_CK

位7:0 CLKDIV:时钟分频系数

        该字段定义输入时钟SDIOCLK与输出时钟SDIO_CK之间的分频系数

        SDIO_CK频率=SDIOCLK/[CLKDIV+2]   一般设置为0,得到24MHz的SDIO_CK频率

3. SDIO参数寄存器(SDIO_ARG)

位31:0 CMDARG:命令参数

        用于存储命令,不过必须在写命令之前先写这个参数寄存器

4. SDIO命令响应寄存器(SDIO_RESPCMD)

位5:0 RESPCMD:响应命令索引

        低6位有效,用于存储最后收到的命令响应中的命令索引。如果最后输出的命令响应不包含命令索引,则该寄存器的内容不可预知。

5. SDIO响应寄存器组(SDIO_RESP1~SDIO_RESP4)

6. SDIO命令寄存器(SDIO_CMD)

位10 CPSMEN:命令路径状态机CPSM使能位

        此位置 1 表示使能CPSM。

位7:6 WAITRESP:等待响应位   用于配置CPSM(命令通道状态机)是否等待响应,如果等待,将等待哪种响应

  •         00:无响应,但CMDSENT标志除外
  •         01:短响应,但CMDREND或CCRCFAIL标志除外
  •         10:无响应,但CMDSENT标志除外
  •         11:长响应,但CMDREND或CCRCFAIL标志除外

位5:0 CMDINDEX:命令索引

        命令索引作为命令消息的一部分发送给卡  比如CMD1 ,那么最低六位就发送1

7. SDIO数据定时器寄存器(SDIO_DTIMER)

位31:0 DATATIME:数据超时周期

        以卡总线时钟周期表示数据超时周期

8. SDIO数据长度寄存器(SDIO_DLEN)

位24:0 DATALENGTH:数据长度值

        要传输的数据字节数量

9. SDIO数据控制寄存器(SDIO_DCTRL)

位11 SDIOEN:SD I/O使能功能

        该位置1,则DPSM执行特定于SD I/O卡的操作

位10 RWMOD:读取等待模式        

  •         0:通过停止SDIO_D2进行读取等待控制
  •         1:使用SDIO_CK进行读取等待控制

位9 RWSTOP:读取等待停止

  •         0:如果将RWSTART位置1,则读取等待正在进行中
  •         1:如果将RWSTART位置1,则使能读取等待停止

位8 RWSTART:读取等待开始

      该位置1,表示读取等待开始

位7:4 DBLOCKSIZE:数据块大小

  •         0000:块长度1字节
  •         0001:块长度2字节
  •         0010:块长度4字节
  •         ……
  •         1110:块长度16384字节   2的次幂

位3 DMAEN:DMA使能位

  •         0:禁止DMA
  •         1:使能DMA

位2 DTMODE:数据传输模式选择

  •         0:块数据传输
  •         1:流或SDIO多字节数据传输

位1 DTDIR:数据传输方向选择

  •         0:从控制器到卡
  •         1:从卡到控制器

位0 DTEN:数据传输使能位

        该位置1表示数据传输开始

10. SDIO数据FIFO寄存器

位31:0 FIFOData:接收和传输FIFO数据

        数据FIFO寄存器包括接收和发送FIFO,他们由一组连续的32个地址上的32个寄存器组成,CPU可以使用FIFO读写多个操作数。例如我们要从SD卡读数据,就必须读SDIO_FIFO寄存器,要写数据到SD卡,则要写SDIO_FIFO寄存器。SDIO将这32个地址分为16个一组,发送和接收各占一半。

注意:我们操作的SDIO_FIFO(无论是读出还是写入)必须是以4字节对齐的内存进行操作,否则将会导致出错!

7. 实验程序

实验功能:

        开机初始化SD卡,如果SD卡初始化成功,则提示LCD初始化成功。按下KEY0,读取SD卡扇区0的数据,通过串口发送到电脑。如果没初始化通过,则在LCD上提示初始化失败。

7.1 main.c

#include "stm32f4xx.h"                 
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "Key.h"
#include "usmart.h"
#include "SRAM.h"
#include "Malloc.h"
#include "SDIO_Card.h"
 
//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}
//通过串口打印SD卡相关信息
void show_sdcard_info(void)
{
	switch(SDCardInfo.CardType)
	{
		case SDIO_STD_CAPACITY_SD_CARD_V1_1:printf("Card Type:SDSC V1.1\r\n");
			break;
		case SDIO_STD_CAPACITY_SD_CARD_V2_0:printf("Card Type:SDSC V2.0\r\n");
			break;
		case SDIO_HIGH_CAPACITY_SD_CARD:printf("Card Type:SDHC V2.0\r\n");
			break;
		case SDIO_MULTIMEDIA_CARD:printf("Card Type:MMC Card\r\n");
			break;
	}	
  	printf("Card ManufacturerID:%d\r\n",SDCardInfo.SD_cid.ManufacturerID);	//制造商ID
 	printf("Card RCA:%d\r\n",SDCardInfo.RCA);								//卡相对地址
	printf("Card Capacity:%d MB\r\n",(u32)(SDCardInfo.CardCapacity>>20));	//显示容量
 	printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.CardBlockSize);			//显示块大小
}

int main(void)
{        
	u8 key;		 
	u32 sd_size;
	u8 t=0;	
	u8 *buf;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);  //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	LED_Init();					//初始化LED  
 	LCD_Init();					//LCD初始化  
 	Key_Init();					//按键初始化  
	
	my_mem_init(SRAMIN);		//初始化内部内存池 
	my_mem_init(SRAMCCM);		//初始化CCM内存池
	
 	POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"SD CARD TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2023/20/23");   
	LCD_ShowString(30,130,200,16,16,"KEY0:Read Sector 0");	   
 	while(SD_Init())//检测不到SD卡
	{
		LCD_ShowString(30,150,200,16,16,"SD Card Error!");
		delay_ms(500);					
		LCD_ShowString(30,150,200,16,16,"Please Check! ");
		delay_ms(500);
		LED0=!LED0;//DS0闪烁
	}
	show_sdcard_info();	//打印SD卡相关信息
 	POINT_COLOR=BLUE;	//设置字体为蓝色 
	//检测SD卡成功 											    
	LCD_ShowString(30,150,200,16,16,"SD Card OK    ");
	LCD_ShowString(30,170,200,16,16,"SD Card Size:     MB");
	LCD_ShowNum(30+13*8,170,SDCardInfo.CardCapacity>>20,5,16);//显示SD卡容量
	while(1)
	{
		key=KEY_Scan(0);
		if(key==1)//KEY0按下了
		{
			buf=mymalloc(0,512);		//申请内存
			if(SD_ReadDisk(buf,0,1)==0)	//读取0扇区的内容
			{	
				LCD_ShowString(30,190,200,16,16,"USART1 Sending Data...");
				printf("SECTOR 0 DATA:\r\n");
				for(sd_size=0;sd_size<512;sd_size++)printf("%x ",buf[sd_size]);//打印0扇区数据    	   
				printf("\r\nDATA ENDED\r\n");
				LCD_ShowString(30,190,200,16,16,"USART1 Send Data Over!");
			}
			myfree(0,buf);//释放内存	   
		}   
		t++;
		delay_ms(10);
		if(t==20)
		{
			LED0=!LED0;
			t=0;
		}
	} 
}


7.2 SDIO_Card.c

#include "sys.h"            
#include "SDIO_Card.h"
#include "string.h"
#include "usart.h"

/*用于sdio初始化的结构体*/
SDIO_InitTypeDef SDIO_InitStructure;
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_DataInitTypeDef SDIO_DataInitStructure;

SD_Error CmdError(void);  
SD_Error CmdResp7Error(void);
SD_Error CmdResp1Error(u8 cmd);
SD_Error CmdResp3Error(void);
SD_Error CmdResp2Error(void);
SD_Error CmdResp6Error(u8 cmd,u16*prca);  
SD_Error SDEnWideBus(u8 enx);	  
SD_Error IsCardProgramming(u8 *pstatus); 
SD_Error FindSCR(u16 rca,u32 *pscr);
u8 convert_from_bytes_to_power_of_two(u16 NumberOfBytes); 


static u8 CardType=SDIO_STD_CAPACITY_SD_CARD_V1_1;		//SD卡类型(默认为1.x卡)
static u32 CSD_Tab[4],CID_Tab[4],RCA=0;					//SD卡CSD,CID以及相对地址(RCA)数据
static u8 DeviceMode=SD_DMA_MODE;		   				//工作模式,注意,工作模式必须通过SD_SetDeviceMode,后才算数.这里只是定义一个默认的模式(SD_DMA_MODE)
static u8 StopCondition=0; 								//是否发送停止传输标志位,DMA多块读写的时候用到  
volatile SD_Error TransferError=SD_OK;					//数据传输错误标志,DMA读写时使用	    
volatile u8 TransferEnd=0;								//传输结束标志,DMA读写时使用
SD_CardInfo SDCardInfo;		 							//SD卡信息

//SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,
//需要用到该数组,确保数据缓存区地址是4字节对齐的.
__align(4) u8 SDIO_DATA_BUFFER[512];	// __align(4)是保证数据缓存区地址是4字节对齐的


void SDIO_Register_Deinit() //初始化寄存器,初始化寄存器的复位值可参照中文参考手册
{
	SDIO->POWER=0x00000000;  //初始化电源控制寄存器为掉电模式
	SDIO->CLKCR=0x00000000;  //初始化时钟控制寄存器
	SDIO->ARG=0x00000000;    //初始化参数寄存器
	SDIO->CMD=0x00000000;    //初始化命令寄存器
	SDIO->DTIMER=0x00000000; //初始化数据定时器寄存器
	SDIO->DLEN=0x00000000;   //初始化数据长度寄存器
	SDIO->DCTRL=0x00000000;  //初始化数据控制寄存器
	SDIO->ICR=0x00C007FF;    //初始化中断清零寄存器
	SDIO->MASK=0x00000000;   //初始化屏蔽寄存器
}
//初始化SD卡
//返回值:错误代码(0,无错误)
SD_Error SD_Init(void)
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	SD_Error errorstatus=SD_OK;	 //SD枚举结构体初始化为SD_OK,设置枚举结构体变量errorstatus
	u8 clkdiv=0;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_DMA2, ENABLE);//使能GPIOC,GPIOD DMA2时钟
	//GPIOC对应于SDIO_D0 SDIO_D1 SDIO_D2 SDIO_D3 SDIO_SCK 
	//GPIOD对应于SDIO_CMD
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);//SDIO时钟使能
	
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO, ENABLE);//SDIO复位
	
	
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12; 	//PC8,9,10,11,12复用功能输出	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50M
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOC, &GPIO_InitStructure);// PC8,9,10,11,12复用功能输出

	
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2; //PD2对应于SDIO_CMD
	GPIO_Init(GPIOD, &GPIO_InitStructure);//PD2复用功能输出
	
	 //引脚复用映射设置
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_SDIO); //PC8
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_SDIO); //PC9
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_SDIO); //PC10
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_SDIO); //PC11
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource12,GPIO_AF_SDIO); //PC12 
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource2,GPIO_AF_SDIO);  //PD2 
	
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO,DISABLE);//SDIO结束复位
		
 	//SDIO外设寄存器设置为默认值 			   
	SDIO_Register_Deinit();
	
	NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
   	errorstatus=SD_PowerON();			//SD卡上电
 	if(errorstatus==SD_OK)
		errorstatus=SD_InitializeCards();			//初始化SD卡														  
  	if(errorstatus==SD_OK)
		errorstatus=SD_GetCardInfo(&SDCardInfo);	//获取卡信息 SDCardInfo SD卡信息结构体
 	if(errorstatus==SD_OK)
		errorstatus=SD_SelectDeselect((u32)(SDCardInfo.RCA<<16));//选中SD卡   
   	if(errorstatus==SD_OK)
		errorstatus=SD_EnableWideBusOperation(SDIO_BusWide_4b);	//4位宽度,如果是MMC卡,则不能用4位模式 
  	if((errorstatus==SD_OK)||(SDIO_MULTIMEDIA_CARD==CardType))
	{  		    
		if(SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1||SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0)
		{
			clkdiv=SDIO_TRANSFER_CLK_DIV+2;	//V1.1/V2.0卡,设置最高48/4=12Mhz
		}
		else 
			clkdiv=SDIO_TRANSFER_CLK_DIV;	//SDHC等其他卡,设置最高48/2=24Mhz
		SDIO_Clock_Set(clkdiv);	//设置时钟频率,SDIO时钟计算公式:SDIO_CK时钟=SDIOCLK/[clkdiv+2];其中,SDIOCLK固定为48Mhz 
		//errorstatus=SD_SetDeviceMode(SD_DMA_MODE);	//设置为DMA模式
		errorstatus=SD_SetDeviceMode(SD_POLLING_MODE);//设置为查询模式
 	}
	return errorstatus;		 
}
//SDIO时钟初始化设置
//clkdiv:时钟分频系数
//CK时钟=SDIOCLK/[clkdiv+2];(SDIOCLK时钟固定为48Mhz)
void SDIO_Clock_Set(u8 clkdiv)
{
	u32 tmpreg=SDIO->CLKCR; 
  	tmpreg&=0XFFFFFF00;  //SDIO时钟控制寄存器的低8位为时钟分频系数,tmpreg&=0XFFFFFF00;表示将寄存器对应的低8位清零
 	tmpreg|=clkdiv;   //然后将新的u8位时钟分频系数和tmpreg进行或运算,表示将值写入寄存器的低8位
	SDIO->CLKCR=tmpreg; //然后把值给到寄存器,相当于引入了中间变量tmpreg
} 
//卡上电
//查询所有SDIO接口上的卡设备,并查询其电压和配置时钟
//返回值:错误代码;(0,无错误)
SD_Error SD_PowerON(void)
{
 	u8 i=0;
	SD_Error errorstatus=SD_OK;
	u32 response=0,count=0,validvoltage=0;
	u32 SDType=SD_STD_CAPACITY;
	
	 /*初始化时的时钟不能大于400KHz*/ 
	SDIO_InitTypeDef SDIO_InitStructure;
	SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;	//设置时钟分频   /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
	SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; //选择上升沿捕获
	SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;  //不使用旁路时钟Bypass模式,直接用HCLK进行分频得到SDIO_CK
	SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;	// 空闲时不关闭时钟电源
	SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;	 				//1位数据线 表示数据宽度为1位
	SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;//不使用硬件流控制
	SDIO_Init(&SDIO_InitStructure);

	SDIO_SetPowerState(SDIO_PowerState_ON);	//上电状态,开启卡时钟   
	SDIO->CLKCR|=1<<8;			//SDIOCK使能   SDIO时钟控制寄存器的第8位是时钟使能位,该位置1表示使能SDIO_CK
	
	//卡上电首先要发送CMD0让所有卡进入空闲状态
 	for(i=0;i<74;i++)
	{
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument = 0x0;//命令参数设置为CMD0  发送CMD0进入IDLE STAGE模式命令. 
		SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0  设置命令号 CMD0 其中0就表示命令号
		SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;  //无响应 响应类型在此可以设置为长响应和短响应以及无响应
		SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //等待使能位,在此设置无等待状态
		SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;  //则CPSM在开始发送命令之前等待数据传输结束。 命令路径状态机CPSM设置
		SDIO_SendCommand(&SDIO_CmdInitStructure);	  		//写命令进命令寄存器
		
		errorstatus=CmdError(); //检查CMD0的执行状态 CMD0让所有卡软复位从而进入空闲状态
		
		if(errorstatus==SD_OK)
			break;
 	}
 	if(errorstatus)
		return errorstatus;//返回错误状态
	
	//所有卡进入空闲状态以后,使用CMD8命令根据响应确定卡的电压支持范围
	//CMD8是V2.0版本才有的命令,所以SD卡接收到CMD8后没有应答,就表示是V1.0版本,如果有应答,则表示SD卡是V2.0或者更高的版本
	SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
	SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;	//发送CMD8,短响应,检查SD卡接口特性
	SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;	//cmd8
	SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;	 //r7 短响应
	SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;			 //关闭等待中断
	SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;      //不使能命令路径状态机
	SDIO_SendCommand(&SDIO_CmdInitStructure);
	
	errorstatus=CmdResp7Error();						//等待CMD8的响应,判断SD卡版本
	
 	if(errorstatus==SD_OK) 								//CMD8响应正常,表示是V2.0版本
	{
		CardType=SDIO_STD_CAPACITY_SD_CARD_V2_0;		//SD 2.0卡
		SDType=SD_HIGH_CAPACITY;			   			//高容量卡
	}
	//只有发送CMD55之后,才能发送下一个命令
	SDIO_CmdInitStructure.SDIO_Argument = 0x00;//发送CMD55,短响应	
	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);		//发送CMD55,短响应	 
	
	errorstatus=CmdResp1Error(SD_CMD_APP_CMD); 		//等待R1响应   
	
	if(errorstatus==SD_OK)//SD2.0/SD 1.1,否则为MMC卡
	{																  
		//SD卡,发送ACMD41 SD_APP_OP_COND,参数为:0x80100000 
		while((!validvoltage)&&(count<SD_MAX_VOLT_TRIAL))
		{	   										   
			SDIO_CmdInitStructure.SDIO_Argument = 0x00;//发送CMD55,短响应
			SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;	  //CMD55
			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);			//发送CMD55,短响应	 
			
			errorstatus=CmdResp1Error(SD_CMD_APP_CMD); 	 	//等待R1响应  
			
 			if(errorstatus!=SD_OK)
				return errorstatus;   	//响应错误

			//ACMD41,命令参数由支持的电压范围及HCS位组成,HCS位置一来区分卡是SDSc还是sdhc
			SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;	//发送ACMD41,短响应	
			SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
			SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r3
			SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
			SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
			SDIO_SendCommand(&SDIO_CmdInitStructure);
			
			errorstatus=CmdResp3Error(); 					//等待R3响应   
			
 			if(errorstatus!=SD_OK)
				return errorstatus;   	//响应错误 
			response=SDIO->RESP1;;			   				//得到响应
			validvoltage=(((response>>31)==1)?1:0);			//判断SD卡上电是否完成
			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卡
	{
		//MMC卡,发送CMD1 SDIO_SEND_OP_COND,参数为:0x80FF8000 
		while((!validvoltage)&&(count<SD_MAX_VOLT_TRIAL))
		{	 
			//多媒体卡初始化以CMD1开始		
			SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_MMC;//发送CMD1,短响应	   
			SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_OP_COND;
			SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r3
			SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
			SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
			SDIO_SendCommand(&SDIO_CmdInitStructure);
			
			errorstatus=CmdResp3Error(); 					//等待R3响应   
			
 			if(errorstatus!=SD_OK)
				return errorstatus;   	//响应错误  
			response=SDIO->RESP1;;			   				//得到响应
			validvoltage=(((response>>31)==1)?1:0);
			count++;
		}
		if(count>=SD_MAX_VOLT_TRIAL)
		{
			errorstatus=SD_INVALID_VOLTRANGE;
			return errorstatus;
		}	 			    
		CardType=SDIO_MULTIMEDIA_CARD;	  
  	}  
  	return(errorstatus);		
}
//SD卡 Power OFF
//返回值:错误代码;(0,无错误)
SD_Error SD_PowerOFF(void)
{
 
  SDIO_SetPowerState(SDIO_PowerState_OFF);//SDIO电源关闭,时钟停止	

  return SD_OK;	  
}   
//初始化所有的卡,并让卡进入就绪状态
//返回值:错误代码
SD_Error SD_InitializeCards(void)
{
 	SD_Error errorstatus=SD_OK;
	u16 rca = 0x01;
	
	if (SDIO_GetPowerState() == SDIO_PowerState_OFF)	//检查电源状态,确保为上电状态
	{
		errorstatus = SD_REQUEST_NOT_APPLICABLE;
		return(errorstatus);
	}

	if(SDIO_SECURE_DIGITAL_IO_CARD!=CardType)			//非SECURE_DIGITAL_IO_CARD
	{	
		//CMD2用于控制所有卡返回他们的卡识别号CID	
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument = 0x0;//发送CMD2,取得CID,长响应
		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);//发送CMD2,取得CID,长响应	
		
		errorstatus=CmdResp2Error(); 					//等待R2响应 
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误		 
		
 		CID_Tab[0]=SDIO->RESP1;
		CID_Tab[1]=SDIO->RESP2;
		CID_Tab[2]=SDIO->RESP3;
		CID_Tab[3]=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))//判断卡类型
	{
		//处于准备状态的卡返回它们CID号之后就进入了识别状态
		//单个卡槽在接收到CMD3并且发出响应之后就会进入数据传输模式,并且处于待机状态;
		//等待所有卡槽都发出RCA命令后,主机获取到所有卡的RCA命令之后进入数据传输模式
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument = 0x00;//发送CMD3,短响应 
		SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;	//cmd3
		SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6
		SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
		SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
		SDIO_SendCommand(&SDIO_CmdInitStructure);	//发送CMD3,短响应 
		
		errorstatus=CmdResp6Error(SD_CMD_SET_REL_ADDR,&rca);//等待R6响应 
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误		    
	}   
    if (SDIO_MULTIMEDIA_CARD==CardType)
    {
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument = (u32)(rca<<16);//发送CMD3,短响应 
		SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;	//cmd3
		SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6
		SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
		SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
		SDIO_SendCommand(&SDIO_CmdInitStructure);	//发送CMD3,短响应 	
			
		errorstatus=CmdResp2Error(); 					//等待R2响应   
			
		if(errorstatus!=SD_OK)
			  return errorstatus;   	//响应错误	 
    }
	if (SDIO_SECURE_DIGITAL_IO_CARD!=CardType)			//非SECURE_DIGITAL_IO_CARD
	{
		RCA = rca;
		//CMD9选定卡通过CMD线发送CSD内容
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);//发送CMD9+卡RCA,取得CSD,长响应 
		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(); 					//等待R2响应   
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误		    
  		
		CSD_Tab[0]=SDIO->RESP1;
		CSD_Tab[1]=SDIO->RESP2;
		CSD_Tab[2]=SDIO->RESP3;						
		CSD_Tab[3]=SDIO->RESP4;					    
	}
	return SD_OK;//卡初始化成功
} 
//得到卡信息
//cardinfo:卡信息存储区
//返回值:错误状态
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
 	SD_Error errorstatus=SD_OK;
	u8 tmp=0;	   
	cardinfo->CardType=(u8)CardType; 				//卡类型
	cardinfo->RCA=(u16)RCA;							//卡RCA值
	tmp=(u8)((CSD_Tab[0]&0xFF000000)>>24);
	cardinfo->SD_csd.CSDStruct=(tmp&0xC0)>>6;		//CSD结构
	cardinfo->SD_csd.SysSpecVersion=(tmp&0x3C)>>2;	//2.0协议还没定义这部分(为保留),应该是后续协议定义的
	cardinfo->SD_csd.Reserved1=tmp&0x03;			//2个保留位  
	tmp=(u8)((CSD_Tab[0]&0x00FF0000)>>16);			//第1个字节
	cardinfo->SD_csd.TAAC=tmp;				   		//数据读时间1
	tmp=(u8)((CSD_Tab[0]&0x0000FF00)>>8);	  		//第2个字节
	cardinfo->SD_csd.NSAC=tmp;		  				//数据读时间2
	tmp=(u8)(CSD_Tab[0]&0x000000FF);				//第3个字节
	cardinfo->SD_csd.MaxBusClkFrec=tmp;		  		//传输速度	   
	tmp=(u8)((CSD_Tab[1]&0xFF000000)>>24);			//第4个字节
	cardinfo->SD_csd.CardComdClasses=tmp<<4;    	//卡指令类高四位
	tmp=(u8)((CSD_Tab[1]&0x00FF0000)>>16);	 		//第5个字节
	cardinfo->SD_csd.CardComdClasses|=(tmp&0xF0)>>4;//卡指令类低四位
	cardinfo->SD_csd.RdBlockLen=tmp&0x0F;	    	//最大读取数据长度
	tmp=(u8)((CSD_Tab[1]&0x0000FF00)>>8);			//第6个字节
	cardinfo->SD_csd.PartBlockRead=(tmp&0x80)>>7;	//允许分块读
	cardinfo->SD_csd.WrBlockMisalign=(tmp&0x40)>>6;	//写块错位
	cardinfo->SD_csd.RdBlockMisalign=(tmp&0x20)>>5;	//读块错位
	cardinfo->SD_csd.DSRImpl=(tmp&0x10)>>4;
	cardinfo->SD_csd.Reserved2=0; 					//保留
 	if((CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1)||(CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0)||(SDIO_MULTIMEDIA_CARD==CardType))//标准1.1/2.0卡/MMC卡
	{
		cardinfo->SD_csd.DeviceSize=(tmp&0x03)<<10;	//C_SIZE(12位)
	 	tmp=(u8)(CSD_Tab[1]&0x000000FF); 			//第7个字节	
		cardinfo->SD_csd.DeviceSize|=(tmp)<<2;
 		tmp=(u8)((CSD_Tab[2]&0xFF000000)>>24);		//第8个字节	
		cardinfo->SD_csd.DeviceSize|=(tmp&0xC0)>>6;
 		cardinfo->SD_csd.MaxRdCurrentVDDMin=(tmp&0x38)>>3;
		cardinfo->SD_csd.MaxRdCurrentVDDMax=(tmp&0x07);
 		tmp=(u8)((CSD_Tab[2]&0x00FF0000)>>16);		//第9个字节	
		cardinfo->SD_csd.MaxWrCurrentVDDMin=(tmp&0xE0)>>5;
		cardinfo->SD_csd.MaxWrCurrentVDDMax=(tmp&0x1C)>>2;
		cardinfo->SD_csd.DeviceSizeMul=(tmp&0x03)<<1;//C_SIZE_MULT
 		tmp=(u8)((CSD_Tab[2]&0x0000FF00)>>8);	  	//第10个字节	
		cardinfo->SD_csd.DeviceSizeMul|=(tmp&0x80)>>7;
 		cardinfo->CardCapacity=(cardinfo->SD_csd.DeviceSize+1);//计算卡容量
		cardinfo->CardCapacity*=(1<<(cardinfo->SD_csd.DeviceSizeMul+2));
		cardinfo->CardBlockSize=1<<(cardinfo->SD_csd.RdBlockLen);//块大小
		cardinfo->CardCapacity*=cardinfo->CardBlockSize;
	}
	else if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)	//高容量卡
	{
 		tmp=(u8)(CSD_Tab[1]&0x000000FF); 		//第7个字节	
		cardinfo->SD_csd.DeviceSize=(tmp&0x3F)<<16;//C_SIZE
 		tmp=(u8)((CSD_Tab[2]&0xFF000000)>>24); 	//第8个字节	
 		cardinfo->SD_csd.DeviceSize|=(tmp<<8);
 		tmp=(u8)((CSD_Tab[2]&0x00FF0000)>>16);	//第9个字节	
 		cardinfo->SD_csd.DeviceSize|=(tmp);
 		tmp=(u8)((CSD_Tab[2]&0x0000FF00)>>8); 	//第10个字节	
 		cardinfo->CardCapacity=(long long)(cardinfo->SD_csd.DeviceSize+1)*512*1024;//计算卡容量
		cardinfo->CardBlockSize=512; 			//块大小固定为512字节
	}	  
	cardinfo->SD_csd.EraseGrSize=(tmp&0x40)>>6;
	cardinfo->SD_csd.EraseGrMul=(tmp&0x3F)<<1;	   
	tmp=(u8)(CSD_Tab[2]&0x000000FF);			//第11个字节	
	cardinfo->SD_csd.EraseGrMul|=(tmp&0x80)>>7;
	cardinfo->SD_csd.WrProtectGrSize=(tmp&0x7F);
 	tmp=(u8)((CSD_Tab[3]&0xFF000000)>>24);		//第12个字节	
	cardinfo->SD_csd.WrProtectGrEnable=(tmp&0x80)>>7;
	cardinfo->SD_csd.ManDeflECC=(tmp&0x60)>>5;
	cardinfo->SD_csd.WrSpeedFact=(tmp&0x1C)>>2;
	cardinfo->SD_csd.MaxWrBlockLen=(tmp&0x03)<<2;	 
	tmp=(u8)((CSD_Tab[3]&0x00FF0000)>>16);		//第13个字节
	cardinfo->SD_csd.MaxWrBlockLen|=(tmp&0xC0)>>6;
	cardinfo->SD_csd.WriteBlockPaPartial=(tmp&0x20)>>5;
	cardinfo->SD_csd.Reserved3=0;
	cardinfo->SD_csd.ContentProtectAppli=(tmp&0x01);  
	tmp=(u8)((CSD_Tab[3]&0x0000FF00)>>8);		//第14个字节
	cardinfo->SD_csd.FileFormatGrouop=(tmp&0x80)>>7;
	cardinfo->SD_csd.CopyFlag=(tmp&0x40)>>6;
	cardinfo->SD_csd.PermWrProtect=(tmp&0x20)>>5;
	cardinfo->SD_csd.TempWrProtect=(tmp&0x10)>>4;
	cardinfo->SD_csd.FileFormat=(tmp&0x0C)>>2;
	cardinfo->SD_csd.ECC=(tmp&0x03);  
	tmp=(u8)(CSD_Tab[3]&0x000000FF);			//第15个字节
	cardinfo->SD_csd.CSD_CRC=(tmp&0xFE)>>1;
	cardinfo->SD_csd.Reserved4=1;		 
	tmp=(u8)((CID_Tab[0]&0xFF000000)>>24);		//第0个字节
	cardinfo->SD_cid.ManufacturerID=tmp;		    
	tmp=(u8)((CID_Tab[0]&0x00FF0000)>>16);		//第1个字节
	cardinfo->SD_cid.OEM_AppliID=tmp<<8;	  
	tmp=(u8)((CID_Tab[0]&0x000000FF00)>>8);		//第2个字节
	cardinfo->SD_cid.OEM_AppliID|=tmp;	    
	tmp=(u8)(CID_Tab[0]&0x000000FF);			//第3个字节	
	cardinfo->SD_cid.ProdName1=tmp<<24;				  
	tmp=(u8)((CID_Tab[1]&0xFF000000)>>24); 		//第4个字节
	cardinfo->SD_cid.ProdName1|=tmp<<16;	  
	tmp=(u8)((CID_Tab[1]&0x00FF0000)>>16);	   	//第5个字节
	cardinfo->SD_cid.ProdName1|=tmp<<8;		 
	tmp=(u8)((CID_Tab[1]&0x0000FF00)>>8);		//第6个字节
	cardinfo->SD_cid.ProdName1|=tmp;		   
	tmp=(u8)(CID_Tab[1]&0x000000FF);	  		//第7个字节
	cardinfo->SD_cid.ProdName2=tmp;			  
	tmp=(u8)((CID_Tab[2]&0xFF000000)>>24); 		//第8个字节
	cardinfo->SD_cid.ProdRev=tmp;		 
	tmp=(u8)((CID_Tab[2]&0x00FF0000)>>16);		//第9个字节
	cardinfo->SD_cid.ProdSN=tmp<<24;	   
	tmp=(u8)((CID_Tab[2]&0x0000FF00)>>8); 		//第10个字节
	cardinfo->SD_cid.ProdSN|=tmp<<16;	   
	tmp=(u8)(CID_Tab[2]&0x000000FF);   			//第11个字节
	cardinfo->SD_cid.ProdSN|=tmp<<8;		   
	tmp=(u8)((CID_Tab[3]&0xFF000000)>>24); 		//第12个字节
	cardinfo->SD_cid.ProdSN|=tmp;			     
	tmp=(u8)((CID_Tab[3]&0x00FF0000)>>16);	 	//第13个字节
	cardinfo->SD_cid.Reserved1|=(tmp&0xF0)>>4;
	cardinfo->SD_cid.ManufactDate=(tmp&0x0F)<<8;    
	tmp=(u8)((CID_Tab[3]&0x0000FF00)>>8);		//第14个字节
	cardinfo->SD_cid.ManufactDate|=tmp;		 	  
	tmp=(u8)(CID_Tab[3]&0x000000FF);			//第15个字节
	cardinfo->SD_cid.CID_CRC=(tmp&0xFE)>>1;
	cardinfo->SD_cid.Reserved2=1;	 
	return errorstatus;
}
//设置SDIO总线宽度(MMC卡不支持4bit模式)
//wmode:位宽模式.0,1位数据宽度;1,4位数据宽度;2,8位数据宽度
//返回值:SD卡错误状态

//设置SDIO总线宽度(MMC卡不支持4bit模式)
//   @arg SDIO_BusWide_8b: 8-bit data transfer (Only for MMC)
//   @arg SDIO_BusWide_4b: 4-bit data transfer
//   @arg SDIO_BusWide_1b: 1-bit data transfer (默认)
//返回值:SD卡错误状态
SD_Error SD_EnableWideBusOperation(u32 WideMode)
{
  	SD_Error errorstatus=SD_OK;
	if (SDIO_MULTIMEDIA_CARD == CardType)
	{
		errorstatus = SD_UNSUPPORTED_FEATURE;
		return(errorstatus);
	}
	
 	else if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
	{
		 if (SDIO_BusWide_8b == WideMode)   //2.0 sd不支持8bits
		{
			errorstatus = SD_UNSUPPORTED_FEATURE;
			return(errorstatus);
		}
		else   
		{
			errorstatus=SDEnWideBus(WideMode);
			if(SD_OK==errorstatus)
			{
				SDIO->CLKCR&=~(3<<11);		//清除之前的位宽设置    
				SDIO->CLKCR|=WideMode;//1位/4位总线宽度 
				SDIO->CLKCR|=0<<14;			//不开启硬件流控制
			}
		}  
	}
	return errorstatus; 
}
//设置SD卡工作模式
//Mode:
//返回值:错误状态
SD_Error SD_SetDeviceMode(u32 Mode)
{
	SD_Error errorstatus = SD_OK;
 	if((Mode==SD_DMA_MODE)||(Mode==SD_POLLING_MODE)) // 查询模式或者DMA模式
		DeviceMode=Mode;
	else 
		errorstatus=SD_INVALID_PARAMETER; //否则报错
	return errorstatus;	    
}
//选卡
//发送CMD7,选择相对地址(rca)为addr的卡,取消其他卡.如果为0,则都不选择.
//addr:卡的RCA地址
SD_Error SD_SelectDeselect(u32 addr)
{
	//CMD7选择和取消指定的卡,
	//待在待机状态下是不能进行通讯的,必须选择一个RCA地址目标使其进入数据传输状态才能进行通讯。
	//CMD7也可以让已经进入通讯状态的卡回到待机状态
	SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
	SDIO_CmdInitStructure.SDIO_Argument =  addr;//发送CMD7,选择卡,短响应	
	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);//发送CMD7,选择卡,短响应
	
	return CmdResp1Error(SD_CMD_SEL_DESEL_CARD);	  
}
//SD卡读取一个块 
//buf:读数据缓存区(必须4字节对齐!!)
//addr:读取地址
//blksize:块大小
SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize)
{	  
	SD_Error errorstatus=SD_OK;
	u8 power;
	u32 count=0,*tempbuff=(u32*)buf;//转换为u32指针 
	u32 timeout=SDIO_DATATIMEOUT;   
	if(NULL==buf)
		return SD_INVALID_PARAMETER; 
	SDIO->DCTRL=0x0;	//数据控制寄存器清零(关DMA) 
  
	if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
	{
		blksize=512;
		addr>>=9;
	}   
	SDIO_DataInitTypeDef SDIO_DataInitStructure;
  	SDIO_DataInitStructure.SDIO_DataBlockSize= SDIO_DataBlockSize_1b ;  //数据块大小
	SDIO_DataInitStructure.SDIO_DataLength= 0 ;  //数据长度
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ; //数据传输超时
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable; //数据路径状态机使能
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard; //数据传输方向为STM32从卡读取数据
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block; //数据传输模式为数据块
    SDIO_DataConfig(&SDIO_DataInitStructure);
	
	
	if(SDIO->RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;//卡锁了
	if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
	{
		power=convert_from_bytes_to_power_of_two(blksize);	
		
		//使用CMD16对于标准的SD卡,设置块命令长度,对于SDHC卡块命令长度固定为512字节
		SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
		SDIO_CmdInitStructure.SDIO_Argument =  blksize;
		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);//发送CMD16+设置数据长度为blksize,短响应
		
		
		errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN);	//等待R1响应 
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误	
		
	}
	else 
		return SD_INVALID_PARAMETER;	  	 
	
	SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4 ;//清除DPSM状态机配置
	SDIO_DataInitStructure.SDIO_DataLength= blksize ;
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToSDIO; //从STM32读出SD卡的内容
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
    SDIO_DataConfig(&SDIO_DataInitStructure);
	
	//CMD17读取长度为SEL_BLOCK_LEN长度字节的块;对于SDHC卡,读取512字节的块
	SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
	SDIO_CmdInitStructure.SDIO_Argument =  addr;
    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);//发送CMD17+从addr地址出读取数据,短响应 
	
	errorstatus=CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);//等待R1响应   
	if(errorstatus!=SD_OK)
		return errorstatus;   		//响应错误	 
 	if(DeviceMode==SD_POLLING_MODE)						//查询模式,轮询数据	 
	{
 		INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
		while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误
		{
			if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)						//接收区半满,表示至少存了8个字
			{
				for(count=0;count<8;count++)			//循环读取数据
				{
					*(tempbuff+count)=SDIO->FIFO;
				}
				tempbuff+=8;	 
				timeout=0X7FFFFF; 	//读数据溢出时间
			}
			else 	//处理超时
			{
				if(timeout==0)
					return SD_DATA_TIMEOUT;
				timeout--;
			}
		} 
		if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)		//数据超时错误
		{										   
	 		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); 	//清错误标志
			return SD_DATA_TIMEOUT;
	 	}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)	//数据块CRC错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
			return SD_DATA_CRC_FAIL;		   
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) 	//接收fifo上溢错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_RXOVERR);		//清错误标志
			return SD_RX_OVERRUN;		 
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) 	//接收起始位错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
			return SD_START_BIT_ERR;		 
		}   
		while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)	//FIFO里面,还存在可用数据
		{
			*tempbuff=SDIO->FIFO;	//循环读取数据
			tempbuff++;
		}
		INTX_ENABLE();//开启总中断
		SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	 
	}
	else if(DeviceMode==SD_DMA_MODE)
	{
 		TransferError=SD_OK;
		StopCondition=0;			//单块读,不需要发送停止传输指令
		TransferEnd=0;				//传输结束标置位,在中断服务置1
		SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1<<9);	//配置需要的中断 
	 	SDIO->DCTRL|=1<<3;		 	//SDIO DMA使能 
 	    SD_DMA_Config((u32*)buf,blksize,DMA_DIR_PeripheralToMemory); 
 		while(((DMA2->LISR&(1<<27))==RESET)&&(TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;//等待传输完成 
		if(timeout==0)
			return SD_DATA_TIMEOUT;//超时
		if(TransferError!=SD_OK)errorstatus=TransferError;  
    }   
 	return errorstatus; 
}
//SD卡读取多个块 
//buf:读数据缓存区
//addr:读取地址
//blksize:块大小
//nblks:要读取的块数
//返回值:错误状态
__align(4) u32 *tempbuff; //设置4字节对齐
SD_Error SD_ReadMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
	SD_Error errorstatus=SD_OK;
	u8 power;
	u32 count=0;
	u32 timeout=SDIO_DATATIMEOUT;  
	tempbuff=(u32*)buf;//转换为u32指针
	
	SDIO->DCTRL=0x0;		//数据控制寄存器清零(关DMA)   
	if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
	{
		blksize=512;
		addr>>=9;
	}  
	SDIO_DataInitTypeDef SDIO_DataInitStructure;
	SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;//清除DPSM状态机配置
	SDIO_DataInitStructure.SDIO_DataLength= 0 ;
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
    SDIO_DataConfig(&SDIO_DataInitStructure);
	
	if(SDIO->RESP1&SD_CARD_LOCKED)
		return SD_LOCK_UNLOCK_FAILED;//卡锁了
	if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
	{
		power=convert_from_bytes_to_power_of_two(blksize);	    
		
		SDIO_CmdInitStructure.SDIO_Argument =  blksize;//发送CMD16+设置数据长度为blksize,短响应 
		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);	//等待R1响应  
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误	 
		
	}
	else 
		return SD_INVALID_PARAMETER;	  
	
	if(nblks>1)											//多块读  
	{									    
 	  	if(nblks*blksize>SD_MAX_DATA_LENGTH)
			return SD_INVALID_PARAMETER;//判断是否超过最大接收长度 
		
		SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;//nblks*blksize,512块大小,卡到控制器
		SDIO_DataInitStructure.SDIO_DataLength= nblks*blksize ;
		SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
		SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
		SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToSDIO;
		SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
		SDIO_DataConfig(&SDIO_DataInitStructure);
		
		//CMD18连续读取数据,直到CMD12中断
		SDIO_CmdInitStructure.SDIO_Argument =  addr;//发送CMD18+从addr地址出读取数据,短响应 
		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);//等待R1响应 
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误	 
		
 		if(DeviceMode==SD_POLLING_MODE)
		{
			INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
			while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<8)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误
			{
				if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)						//接收区半满,表示至少存了8个字
				{
					for(count=0;count<8;count++)			//循环读取数据
					{
						*(tempbuff+count)=SDIO->FIFO;
					}
					tempbuff+=8;	 
					timeout=0X7FFFFF; 	//读数据溢出时间
				}
				else 	//处理超时
				{
					if(timeout==0)return SD_DATA_TIMEOUT;
					timeout--;
				}
			}  
		if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)		//数据超时错误
		{										   
	 		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); 	//清错误标志
			return SD_DATA_TIMEOUT;
	 	}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)	//数据块CRC错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
			return SD_DATA_CRC_FAIL;		   
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) 	//接收fifo上溢错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_RXOVERR);		//清错误标志
			return SD_RX_OVERRUN;		 
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) 	//接收起始位错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
			return SD_START_BIT_ERR;		 
		}   
	    
		while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)	//FIFO里面,还存在可用数据
		{
			*tempbuff=SDIO->FIFO;	//循环读取数据
			tempbuff++;
		}
	 		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结束传输		
					SDIO_CmdInitStructure.SDIO_Argument =  0;//发送CMD12+结束传输
					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);//等待R1响应   
					
					if(errorstatus!=SD_OK)
						return errorstatus;	 
				}
 			}
			INTX_ENABLE();//开启总中断
	 		SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
 		}
		else if(DeviceMode==SD_DMA_MODE)
		{
	   		TransferError=SD_OK;
			StopCondition=1;			//多块读,需要发送停止传输指令 
			TransferEnd=0;				//传输结束标置位,在中断服务置1
			SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1<<9);	//配置需要的中断 
		 	SDIO->DCTRL|=1<<3;		 						//SDIO DMA使能 
	 	    SD_DMA_Config((u32*)buf,nblks*blksize,DMA_DIR_PeripheralToMemory); 
	 		while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成 
			if(timeout==0)
				return SD_DATA_TIMEOUT;//超时
			while((TransferEnd==0)&&(TransferError==SD_OK)); 
			if(TransferError!=SD_OK)
				errorstatus=TransferError;  	 
		}		 
  	}
	return errorstatus;
}			    																  
//SD卡写1个块 
//buf:数据缓存区
//addr:写地址
//blksize:块大小	  
//返回值:错误状态
SD_Error SD_WriteBlock(u8 *buf,long long addr,  u16 blksize)
{
	SD_Error errorstatus = SD_OK;
	
	u8  power=0,cardstate=0;
	
	u32 timeout=0,bytestransferred=0;
	
	u32 cardstatus=0,count=0,restwords=0;
	
	u32	tlen=blksize;						//总长度(字节)
	
	u32*tempbuff=(u32*)buf;					
	
 	if(buf==NULL)
		return SD_INVALID_PARAMETER;//参数错误  
	
	SDIO->DCTRL=0x0;							//数据控制寄存器清零(关DMA)
	
	SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;//清除DPSM状态机配置
	SDIO_DataInitStructure.SDIO_DataLength= 0 ;
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
	SDIO_DataConfig(&SDIO_DataInitStructure);
	
	
	if(SDIO->RESP1&SD_CARD_LOCKED)
		return SD_LOCK_UNLOCK_FAILED;//卡锁了
 	if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)	//大容量卡
	{
		blksize=512;
		addr>>=9;
	}    
	if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
	{
		power=convert_from_bytes_to_power_of_two(blksize);	
		
		SDIO_CmdInitStructure.SDIO_Argument = blksize;//发送CMD16+设置数据长度为blksize,短响应 	
		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);	//等待R1响应  
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误	 
		
	}
	else return SD_INVALID_PARAMETER;	
	
	SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应 	
	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);		//等待R1响应  
	
	if(errorstatus!=SD_OK)
		return errorstatus;
	cardstatus=SDIO->RESP1;													  
	timeout=SD_DATATIMEOUT;
   	while(((cardstatus&0x00000100)==0)&&(timeout>0)) 	//检查READY_FOR_DATA位是否置位
	{
		timeout--;  
		
		SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应
		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);	//等待R1响应   
		
		if(errorstatus!=SD_OK)
			return errorstatus;		
		
		cardstatus=SDIO->RESP1;													  
	}
	if(timeout==0)
		return SD_ERROR;

	SDIO_CmdInitStructure.SDIO_Argument = addr;//发送CMD24,写单块指令,短响应 	
	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);//等待R1响应  
	
	if(errorstatus!=SD_OK)
		return errorstatus;   	 
	
	StopCondition=0;									//单块写,不需要发送停止传输指令 

	SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;	//blksize, 控制器到卡	
	SDIO_DataInitStructure.SDIO_DataLength= blksize ;
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
	SDIO_DataConfig(&SDIO_DataInitStructure);
	
	
	timeout=SDIO_DATATIMEOUT;
	
	if (DeviceMode == SD_POLLING_MODE)
	{
		INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
		while(!(SDIO->STA&((1<<10)|(1<<4)|(1<<1)|(1<<3)|(1<<9))))//数据块发送成功/下溢/CRC/超时/起始位错误
		{
			if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)							//发送区半空,表示至少存了8个字
			{
				if((tlen-bytestransferred)<SD_HALFFIFOBYTES)//不够32字节了
				{
					restwords=((tlen-bytestransferred)%4==0)?((tlen-bytestransferred)/4):((tlen-bytestransferred)/4+1);
					
					for(count=0;count<restwords;count++,tempbuff++,bytestransferred+=4)
					{
						SDIO->FIFO=*tempbuff;
					}
				}
				else
				{
					for(count=0;count<8;count++)
					{
						SDIO->FIFO=*(tempbuff+count);
					}
					tempbuff+=8;
					bytestransferred+=32;
				}
				timeout=0X3FFFFFFF;	//写数据溢出时间
			}else
			{
				if(timeout==0)
					return SD_DATA_TIMEOUT;
				timeout--;
			}
		} 
		if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)		//数据超时错误
		{										   
	 		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); 	//清错误标志
			return SD_DATA_TIMEOUT;
	 	}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)	//数据块CRC错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
			return SD_DATA_CRC_FAIL;		   
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET) 	//接收fifo下溢错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);		//清错误标志
			return SD_TX_UNDERRUN;		 
		}
		else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) 	//接收起始位错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
			return SD_START_BIT_ERR;		 
		}   
	      
		INTX_ENABLE();//开启总中断
		SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记  
	}
	else if(DeviceMode==SD_DMA_MODE)
	{
   		TransferError=SD_OK;
		StopCondition=0;			//单块写,不需要发送停止传输指令 
		TransferEnd=0;				//传输结束标置位,在中断服务置1
		SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9);	//配置产生数据接收完成中断
		SD_DMA_Config((u32*)buf,blksize,DMA_DIR_MemoryToPeripheral);				//SDIO DMA配置
 	 	SDIO->DCTRL|=1<<3;								//SDIO DMA使能.  
 		while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成 
		if(timeout==0)
		{
  			SD_Init();	 					//重新初始化SD卡,可以解决写入死机的问题
			return SD_DATA_TIMEOUT;			//超时	 
 		}
		timeout=SDIO_DATATIMEOUT;
		while((TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
 		if(timeout==0)
			return SD_DATA_TIMEOUT;			//超时	 
  		if(TransferError!=SD_OK)
			return TransferError;
 	}  
 	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;
}
//SD卡写多个块 
//buf:数据缓存区
//addr:写地址
//blksize:块大小
//nblks:要写入的块数
//返回值:错误状态												   
SD_Error SD_WriteMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
	SD_Error errorstatus = SD_OK;
	u8  power = 0, cardstate = 0;
	u32 timeout=0,bytestransferred=0;
	u32 count = 0, restwords = 0;
	u32 tlen=nblks*blksize;				//总长度(字节)
	u32 *tempbuff = (u32*)buf;  
	if(buf==NULL)
	  return SD_INVALID_PARAMETER; //参数错误  
	SDIO->DCTRL=0x0;							//数据控制寄存器清零(关DMA)   
	
	SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;	//清除DPSM状态机配置	
	SDIO_DataInitStructure.SDIO_DataLength= 0 ;
	SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
	SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
	SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
	SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
	SDIO_DataConfig(&SDIO_DataInitStructure);
	
	if(SDIO->RESP1&SD_CARD_LOCKED)
		return SD_LOCK_UNLOCK_FAILED;//卡锁了
 	if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
	{
		blksize=512;
		addr>>=9;
	}    
	if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
	{
		power=convert_from_bytes_to_power_of_two(blksize);
		
		SDIO_CmdInitStructure.SDIO_Argument = blksize;	//发送CMD16+设置数据长度为blksize,短响应
		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);	//等待R1响应  
		
		if(errorstatus!=SD_OK)
			return errorstatus;   	//响应错误	 
		
	}
	else 
		return SD_INVALID_PARAMETER;	 
	if(nblks>1)
	{					  
		if(nblks*blksize>SD_MAX_DATA_LENGTH)
			return SD_INVALID_PARAMETER;   
     	if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
    	{
			//提高性能
			SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;		//发送ACMD55,短响应 	
			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);		//等待R1响应 
				
			if(errorstatus!=SD_OK)
				return errorstatus;				 
				
			SDIO_CmdInitStructure.SDIO_Argument =nblks;		//发送CMD23,设置块数量,短响应 	 
			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);//等待R1响应 
				
			if(errorstatus!=SD_OK)
				return errorstatus;		
		    
		} 

		SDIO_CmdInitStructure.SDIO_Argument =addr;	//发送CMD25,多块写指令,短响应 	  
		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);	//等待R1响应   		   
	
		if(errorstatus!=SD_OK)
			return errorstatus;

        SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;	//blksize, 控制器到卡	
		SDIO_DataInitStructure.SDIO_DataLength= nblks*blksize ;
		SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
		SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
		SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
		SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
		SDIO_DataConfig(&SDIO_DataInitStructure);
				
		if(DeviceMode==SD_POLLING_MODE)
	    {
			timeout=SDIO_DATATIMEOUT;
			INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
			while(!(SDIO->STA&((1<<4)|(1<<1)|(1<<8)|(1<<3)|(1<<9))))//下溢/CRC/数据结束/超时/起始位错误
			{
				if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)							//发送区半空,表示至少存了8字(32字节)
				{	  
					if((tlen-bytestransferred)<SD_HALFFIFOBYTES)//不够32字节了
					{
						restwords=((tlen-bytestransferred)%4==0)?((tlen-bytestransferred)/4):((tlen-bytestransferred)/4+1);
						for(count=0;count<restwords;count++,tempbuff++,bytestransferred+=4)
						{
							SDIO->FIFO=*tempbuff;
						}
					}else 										//发送区半空,可以发送至少8字(32字节)数据
					{
						for(count=0;count<SD_HALFFIFO;count++)
						{
							SDIO->FIFO=*(tempbuff+count);
						}
						tempbuff+=SD_HALFFIFO;
						bytestransferred+=SD_HALFFIFOBYTES;
					}
					timeout=0X3FFFFFFF;	//写数据溢出时间
				}else
				{
					if(timeout==0)return SD_DATA_TIMEOUT; 
					timeout--;
				}
			} 
		if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)		//数据超时错误
		{										   
	 		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); 	//清错误标志
			return SD_DATA_TIMEOUT;
	 	}else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)	//数据块CRC错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
			return SD_DATA_CRC_FAIL;		   
		}else if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET) 	//接收fifo下溢错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);		//清错误标志
			return SD_TX_UNDERRUN;		 
		}else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) 	//接收起始位错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
			return SD_START_BIT_ERR;		 
		}   
	      										   
			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))
				{   
					SDIO_CmdInitStructure.SDIO_Argument =0;//发送CMD12+结束传输 	  
					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);//等待R1响应   
					if(errorstatus!=SD_OK)return errorstatus;	 
				}
			}
			INTX_ENABLE();//开启总中断
	 		SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	    }else if(DeviceMode==SD_DMA_MODE)
		{
	   	TransferError=SD_OK;
			StopCondition=1;			//多块写,需要发送停止传输指令 
			TransferEnd=0;				//传输结束标置位,在中断服务置1
			SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9);	//配置产生数据接收完成中断
			SD_DMA_Config((u32*)buf,nblks*blksize,DMA_DIR_MemoryToPeripheral);		//SDIO DMA配置
	 	 	SDIO->DCTRL|=1<<3;								//SDIO DMA使能. 
			timeout=SDIO_DATATIMEOUT;
	 		while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成 
			if(timeout==0)	 								//超时
			{									  
  				SD_Init();	 					//重新初始化SD卡,可以解决写入死机的问题
	 			return SD_DATA_TIMEOUT;			//超时	 
	 		}
			timeout=SDIO_DATATIMEOUT;
			while((TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
	 		if(timeout==0)return SD_DATA_TIMEOUT;			//超时	 
	 		if(TransferError!=SD_OK)return TransferError;	 
		}
  	}
 	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;	   
}
//SDIO中断服务函数		  
void SDIO_IRQHandler(void) 
{											
 	SD_ProcessIRQSrc();//处理所有SDIO相关中断
}	 																    
//SDIO中断处理函数
//处理SDIO传输过程中的各种中断事务
//返回值:错误代码
SD_Error SD_ProcessIRQSrc(void)
{
	if(SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)//接收完成中断
	{	 
		if (StopCondition==1)
		{  
				SDIO_CmdInitStructure.SDIO_Argument =0;//发送CMD12+结束传输 	  
				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);	
					
			TransferError=CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
		}else TransferError = SD_OK;	
 		SDIO->ICR|=1<<8;//清除完成中断标记
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
 		TransferEnd = 1;
		return(TransferError);
	}
 	if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)//数据CRC错误
	{
		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
	    TransferError = SD_DATA_CRC_FAIL;
	    return(SD_DATA_CRC_FAIL);
	}
 	if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)//数据超时错误
	{
		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);  			//清中断标志
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
	    TransferError = SD_DATA_TIMEOUT;
	    return(SD_DATA_TIMEOUT);
	}
  	if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)//FIFO上溢错误
	{
		SDIO_ClearFlag(SDIO_FLAG_RXOVERR);  			//清中断标志
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
	    TransferError = SD_RX_OVERRUN;
	    return(SD_RX_OVERRUN);
	}
   	if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)//FIFO下溢错误
	{
		SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);  			//清中断标志
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
	    TransferError = SD_TX_UNDERRUN;
	    return(SD_TX_UNDERRUN);
	}
	if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)//起始位错误
	{
		SDIO_ClearFlag(SDIO_FLAG_STBITERR);  		//清中断标志
		SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
	    TransferError = SD_START_BIT_ERR;
	    return(SD_START_BIT_ERR);
	}
	return(SD_OK);
}
  
//检查CMD0的执行状态
//返回值:sd卡错误码
SD_Error CmdError(void)
{
	SD_Error errorstatus = SD_OK;
	u32 timeout=SDIO_CMD0TIMEOUT;	   
	while(timeout--)
	{
		if(SDIO_GetFlagStatus(SDIO_FLAG_CMDSENT) != RESET)break;	//命令已发送(无需响应)	 
	}	    
	if(timeout==0)return SD_CMD_RSP_TIMEOUT;  
	SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	return errorstatus;
}	 
//检查R7响应的错误状态
//返回值:sd卡错误码
SD_Error CmdResp7Error(void)
{
	SD_Error errorstatus=SD_OK;
	u32 status;
	u32 timeout=SDIO_CMD0TIMEOUT;
 	while(timeout--)
	{
		status=SDIO->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)	
	}
 	if((timeout==0)||(status&(1<<2)))	//响应超时
	{																				    
		errorstatus=SD_CMD_RSP_TIMEOUT;	//当前卡不是2.0兼容卡,或者不支持设定的电压范围
		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); 			//清除命令响应超时标志
		return errorstatus;
	}	 
	if(status&1<<6)						//成功接收到响应
	{								   
		errorstatus=SD_OK;
		SDIO_ClearFlag(SDIO_FLAG_CMDREND); 				//清除响应标志
 	}
	return errorstatus;
}	   
//检查R1响应的错误状态
//cmd:当前命令
//返回值:sd卡错误码
SD_Error CmdResp1Error(u8 cmd)
{	  
   	u32 status; 
	while(1)
	{
		status=SDIO->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
	} 
	if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET)					//响应超时
	{																				    
 		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); 				//清除命令响应超时标志
		return SD_CMD_RSP_TIMEOUT;
	}	
 	if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET)					//CRC错误
	{																				    
 		SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); 				//清除标志
		return SD_CMD_CRC_FAIL;
	}		
	if(SDIO->RESPCMD!=cmd)return SD_ILLEGAL_CMD;//命令不匹配 
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	return (SD_Error)(SDIO->RESP1&SD_OCR_ERRORBITS);//返回卡响应
}
//检查R3响应的错误状态
//返回值:错误状态
SD_Error CmdResp3Error(void)
{
	u32 status;						 
 	while(1)
	{
		status=SDIO->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)	
	}
 	if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET)					//响应超时
	{											 
		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);			//清除命令响应超时标志
		return SD_CMD_RSP_TIMEOUT;
	}	 
   SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
 	return SD_OK;								  
}
//检查R2响应的错误状态
//返回值:错误状态
SD_Error CmdResp2Error(void)
{
	SD_Error errorstatus=SD_OK;
	u32 status;
	u32 timeout=SDIO_CMD0TIMEOUT;
 	while(timeout--)
	{
		status=SDIO->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)	
	}
  	if((timeout==0)||(status&(1<<2)))	//响应超时
	{																				    
		errorstatus=SD_CMD_RSP_TIMEOUT; 
		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); 		//清除命令响应超时标志
		return errorstatus;
	}	 
	if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET)						//CRC错误
	{								   
		errorstatus=SD_CMD_CRC_FAIL;
		SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);		//清除响应标志
 	}
	SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
 	return errorstatus;								    		 
} 
//检查R6响应的错误状态
//cmd:之前发送的命令
//prca:卡返回的RCA地址
//返回值:错误状态
SD_Error CmdResp6Error(u8 cmd,u16*prca)
{
	SD_Error errorstatus=SD_OK;
	u32 status;					    
	u32 rspr1;
 	while(1)
	{
		status=SDIO->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)	
	}
	if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET)					//响应超时
	{																				    
 		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);			//清除命令响应超时标志
		return SD_CMD_RSP_TIMEOUT;
	}	 	 
	if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET)						//CRC错误
	{								   
		SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);					//清除响应标志
 		return SD_CMD_CRC_FAIL;
	}
	if(SDIO->RESPCMD!=cmd)				//判断是否响应cmd命令
	{
 		return SD_ILLEGAL_CMD; 		
	}	    
	SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	rspr1=SDIO->RESP1;					//得到响应 	 
	if(SD_ALLZERO==(rspr1&(SD_R6_GENERAL_UNKNOWN_ERROR|SD_R6_ILLEGAL_CMD|SD_R6_COM_CRC_FAILED)))
	{
		*prca=(u16)(rspr1>>16);			//右移16位得到,rca
		return errorstatus;
	}
   	if(rspr1&SD_R6_GENERAL_UNKNOWN_ERROR)return SD_GENERAL_UNKNOWN_ERROR;
   	if(rspr1&SD_R6_ILLEGAL_CMD)return SD_ILLEGAL_CMD;
   	if(rspr1&SD_R6_COM_CRC_FAILED)return SD_COM_CRC_FAILED;
	return errorstatus;
}

//SDIO使能宽总线模式
//enx:0,不使能;1,使能;
//返回值:错误状态
SD_Error SDEnWideBus(u8 enx)
{
	SD_Error errorstatus = SD_OK;
 	u32 scr[2]={0,0};
	u8 arg=0X00;
	if(enx)arg=0X02;
	else arg=0X00;
 	if(SDIO->RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;//SD卡处于LOCKED状态		    
 	errorstatus=FindSCR(RCA,scr);						//得到SCR寄存器数据
 	if(errorstatus!=SD_OK)return errorstatus;
	if((scr[1]&SD_WIDE_BUS_SUPPORT)!=SD_ALLZERO)		//支持宽总线
	{
		  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;//发送CMD55+RCA,短响应	
      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 = arg;//发送ACMD6,短响应,参数:10,4位;00,1位.	
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
      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_SD_SET_BUSWIDTH);
		
		return errorstatus;
	}else return SD_REQUEST_NOT_APPLICABLE;				//不支持宽总线设置 	 
}												   
//检查卡是否正在执行写操作
//pstatus:当前状态.
//返回值:错误代码
SD_Error IsCardProgramming(u8 *pstatus)
{
 	vu32 respR1 = 0, status = 0;  
  
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16; //卡相对地址参数
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;//发送CMD13 	
  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);	
 	
	status=SDIO->STA;
	
	while(!(status&((1<<0)|(1<<6)|(1<<2))))status=SDIO->STA;//等待操作完成
   	if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET)			//CRC检测失败
	{  
	  SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);	//清除错误标记
		return SD_CMD_CRC_FAIL;
	}
   	if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET)			//命令超时 
	{
		SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);			//清除错误标记
		return SD_CMD_RSP_TIMEOUT;
	}
 	if(SDIO->RESPCMD!=SD_CMD_SEND_STATUS)return SD_ILLEGAL_CMD;
	SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	respR1=SDIO->RESP1;
	*pstatus=(u8)((respR1>>9)&0x0000000F);
	return SD_OK;
}
//读取当前卡状态
//pcardstatus:卡状态
//返回值:错误代码
SD_Error SD_SendStatus(uint32_t *pcardstatus)
{
	SD_Error errorstatus = SD_OK;
	if(pcardstatus==NULL)
	{
		errorstatus=SD_INVALID_PARAMETER;
		return errorstatus;
	}
	
	SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;//发送CMD13,短响应		 
  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;
	*pcardstatus=SDIO->RESP1;//读取响应值
	return errorstatus;
} 
//返回SD卡的状态
//返回值:SD卡状态
SDCardState SD_GetState(void)
{
	u32 resp1=0;
	if(SD_SendStatus(&resp1)!=SD_OK)return SD_CARD_ERROR;
	else return (SDCardState)((resp1>>9) & 0x0F);
}
//查找SD卡的SCR寄存器值
//rca:卡相对地址
//pscr:数据缓存区(存储SCR内容)
//返回值:错误状态		   
SD_Error FindSCR(u16 rca,u32 *pscr)
{ 
	u32 index = 0; 
	SD_Error errorstatus = SD_OK;
	u32 tempscr[2]={0,0};  
	
	SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)8;	 //发送CMD16,短响应,设置Block Size为8字节	
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN; //	 cmd16
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r1
  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;	 
	
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16; 
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;//发送CMD55,短响应 	
  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_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 8;  //8个字节长度,block为8字节,SD卡到SDIO.
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_8b  ;  //块大小8byte 
  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);		

  SDIO_CmdInitStructure.SDIO_Argument = 0x0;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_SEND_SCR;	//发送ACMD51,短响应,参数为0	
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r1
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
	
 	errorstatus=CmdResp1Error(SD_CMD_SD_APP_SEND_SCR);
 	if(errorstatus!=SD_OK)return errorstatus;							   
 	while(!(SDIO->STA&(SDIO_FLAG_RXOVERR|SDIO_FLAG_DCRCFAIL|SDIO_FLAG_DTIMEOUT|SDIO_FLAG_DBCKEND|SDIO_FLAG_STBITERR)))
	{ 
		if(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)//接收FIFO数据可用
		{
			*(tempscr+index)=SDIO->FIFO;	//读取FIFO内容
			index++;
			if(index>=2)break;
		}
	}
		if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)		//数据超时错误
		{										   
	 		SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); 	//清错误标志
			return SD_DATA_TIMEOUT;
	 	}else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)	//数据块CRC错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);  		//清错误标志
			return SD_DATA_CRC_FAIL;		   
		}else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) 	//接收fifo上溢错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_RXOVERR);		//清错误标志
			return SD_RX_OVERRUN;		 
		}else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) 	//接收起始位错误
		{
	 		SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
			return SD_START_BIT_ERR;		 
		}  
   SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
	//把数据顺序按8位为单位倒过来.   	
	*(pscr+1)=((tempscr[0]&SD_0TO7BITS)<<24)|((tempscr[0]&SD_8TO15BITS)<<8)|((tempscr[0]&SD_16TO23BITS)>>8)|((tempscr[0]&SD_24TO31BITS)>>24);
	*(pscr)=((tempscr[1]&SD_0TO7BITS)<<24)|((tempscr[1]&SD_8TO15BITS)<<8)|((tempscr[1]&SD_16TO23BITS)>>8)|((tempscr[1]&SD_24TO31BITS)>>24);
 	return errorstatus;
}
//得到NumberOfBytes以2为底的指数.
//NumberOfBytes:字节数.
//返回值:以2为底的指数值
u8 convert_from_bytes_to_power_of_two(u16 NumberOfBytes)
{
	u8 count=0;
	while(NumberOfBytes!=1)
	{
		NumberOfBytes>>=1;
		count++;
	}
	return count;
} 	 

//配置SDIO DMA  
//mbuf:存储器地址
//bufsize:传输数据量
//dir:方向;DMA_DIR_MemoryToPeripheral  存储器-->SDIO(写数据);DMA_DIR_PeripheralToMemory SDIO-->存储器(读数据);
void SD_DMA_Config(u32*mbuf,u32 bufsize,u32 dir)
{		 

  DMA_InitTypeDef  DMA_InitStructure;
	
	while (DMA_GetCmdStatus(DMA2_Stream3) != DISABLE){}//等待DMA可配置 
		
  DMA_DeInit(DMA2_Stream3);//清空之前该stream3上的所有中断标志
	
 
  DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SDIO->FIFO;//DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)mbuf;//DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = dir;//存储器到外设模式
  DMA_InitStructure.DMA_BufferSize = 0;//数据传输量 
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据长度:32位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式 
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//最高优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;   //FIFO使能      
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//全FIFO
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;//外设突发4次传输
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;//存储器突发4次传输
  DMA_Init(DMA2_Stream3, &DMA_InitStructure);//初始化DMA Stream

	DMA_FlowControllerConfig(DMA2_Stream3,DMA_FlowCtrl_Peripheral);//外设流控制 
	 
  DMA_Cmd(DMA2_Stream3 ,ENABLE);//开启DMA传输	 

}   


//读SD卡
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;				  				 
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
	u8 sta=SD_OK;
	long long lsector=sector;
	u8 n;
	lsector<<=9;
	if((u32)buf%4!=0)
	{
	 	for(n=0;n<cnt;n++)
		{
		 	sta=SD_ReadBlock(SDIO_DATA_BUFFER,lsector+512*n,512);//单个sector的读操作
			memcpy(buf,SDIO_DATA_BUFFER,512);
			buf+=512;
		} 
	}else
	{
		if(cnt==1)sta=SD_ReadBlock(buf,lsector,512);    	//单个sector的读操作
		else sta=SD_ReadMultiBlocks(buf,lsector,512,cnt);//多个sector  
	}
	return sta;
}
//写SD卡
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;	
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{
	u8 sta=SD_OK;
	u8 n;
	long long lsector=sector;
	lsector<<=9;
	if((u32)buf%4!=0)
	{
	 	for(n=0;n<cnt;n++)
		{
			memcpy(SDIO_DATA_BUFFER,buf,512);
		 	sta=SD_WriteBlock(SDIO_DATA_BUFFER,lsector+512*n,512);//单个sector的写操作
			buf+=512;
		} 
	}else
	{
		if(cnt==1)sta=SD_WriteBlock(buf,lsector,512);    	//单个sector的写操作
		else sta=SD_WriteMultiBlocks(buf,lsector,512,cnt);	//多个sector  
	}
	return sta;
}



7.3 SDIO_Card.h

#ifndef _SDIO_CARD__H_
#define _SDIO_CARD__H_
#include "stm32f4xx.h"       



//SDIO相关标志位,拷贝自:stm32f4xx_sdio.h
#define SDIO_FLAG_CCRCFAIL                  ((uint32_t)0x00000001)
#define SDIO_FLAG_DCRCFAIL                  ((uint32_t)0x00000002)
#define SDIO_FLAG_CTIMEOUT                  ((uint32_t)0x00000004)
#define SDIO_FLAG_DTIMEOUT                  ((uint32_t)0x00000008)
#define SDIO_FLAG_TXUNDERR                  ((uint32_t)0x00000010)
#define SDIO_FLAG_RXOVERR                   ((uint32_t)0x00000020)
#define SDIO_FLAG_CMDREND                   ((uint32_t)0x00000040)
#define SDIO_FLAG_CMDSENT                   ((uint32_t)0x00000080)
#define SDIO_FLAG_DATAEND                   ((uint32_t)0x00000100)
#define SDIO_FLAG_STBITERR                  ((uint32_t)0x00000200)
#define SDIO_FLAG_DBCKEND                   ((uint32_t)0x00000400)
#define SDIO_FLAG_CMDACT                    ((uint32_t)0x00000800)
#define SDIO_FLAG_TXACT                     ((uint32_t)0x00001000)
#define SDIO_FLAG_RXACT                     ((uint32_t)0x00002000)
#define SDIO_FLAG_TXFIFOHE                  ((uint32_t)0x00004000)
#define SDIO_FLAG_RXFIFOHF                  ((uint32_t)0x00008000)
#define SDIO_FLAG_TXFIFOF                   ((uint32_t)0x00010000)
#define SDIO_FLAG_RXFIFOF                   ((uint32_t)0x00020000)
#define SDIO_FLAG_TXFIFOE                   ((uint32_t)0x00040000)
#define SDIO_FLAG_RXFIFOE                   ((uint32_t)0x00080000)
#define SDIO_FLAG_TXDAVL                    ((uint32_t)0x00100000)
#define SDIO_FLAG_RXDAVL                    ((uint32_t)0x00200000)
#define SDIO_FLAG_SDIOIT                    ((uint32_t)0x00400000)
#define SDIO_FLAG_CEATAEND                  ((uint32_t)0x00800000)


//用户配置区			  
//SDIO时钟计算公式:SDIO_CK时钟=SDIOCLK/[clkdiv+2];其中,SDIOCLK固定为48Mhz
//使用DMA模式的时候,传输速率可以到48Mhz(bypass on时),不过如果你的卡不是高速
//卡,可能也会出错,出错就请降低时钟
#define SDIO_INIT_CLK_DIV        0x76 		//SDIO初始化频率,最大400Kh  
#define SDIO_TRANSFER_CLK_DIV    0x00		//SDIO传输频率,该值太小可能会导致读写文件出错 
										 

 
//SDIO工作模式定义,通过SD_SetDeviceMode函数设置.
#define SD_POLLING_MODE    	0  	//查询模式,该模式下,如果读写有问题,建议增大SDIO_TRANSFER_CLK_DIV的设置.
#define SD_DMA_MODE    		1	//DMA模式,该模式下,如果读写有问题,建议增大SDIO_TRANSFER_CLK_DIV的设置.   

//SDIO 各种错误枚举定义
typedef enum
{	 
	//特殊错误定义 
	SD_CMD_CRC_FAIL                    = (1), /*!< 收到命令响应(但CRC检查失败) */
	SD_DATA_CRC_FAIL                   = (2), /*!< 发送/接收数据帧(CRC检查失败) */
	SD_CMD_RSP_TIMEOUT                 = (3), /*!< 命令响应超时时间 */
	SD_DATA_TIMEOUT                    = (4), /*!< 数据超时 */
	SD_TX_UNDERRUN                     = (5), /*!< 发送FIFO欠运行 */
	SD_RX_OVERRUN                      = (6), /*!< 接收FIFO超时 */
	SD_START_BIT_ERR                   = (7), /*!< 在宽总线模式下,所有数据信号上未检测到起始位 */
	SD_CMD_OUT_OF_RANGE                = (8), /*!< CMD的参数超出范围 */
	SD_ADDR_MISALIGNED                 = (9), /*!< 偏差处理 */
	SD_BLOCK_LEN_ERR                   = (10), /*!< 对于该卡不允许传输的块长度或传输的字节数与块长度不匹配 */
	SD_ERASE_SEQ_ERR                   = (11), /*!< 擦除命令的顺序出错 */
	SD_BAD_ERASE_PARAM                 = (12), /*!< 对擦除组的选择无效 */
	SD_WRITE_PROT_VIOLATION            = (13), /*!< 尝试编写一个写保护块 */
	SD_LOCK_UNLOCK_FAILED              = (14), /*!< 在解锁命令中检测到序列或密码错误,或者试图访问锁定的卡 */
	SD_COM_CRC_FAILED                  = (15), /*!< 日志含义上一条命令CRC校验失败 */
	SD_ILLEGAL_CMD                     = (16), /*!< 命令对于卡片状态不合法 */
	SD_CARD_ECC_FAILED                 = (17), /*!< 日志含义应用卡内部ECC,但未能纠正数据 */
	SD_CC_ERROR                        = (18), /*!< 内部卡控制器错误 */
	SD_GENERAL_UNKNOWN_ERROR           = (19), /*!< 一般错误或未知错误 */
	SD_STREAM_READ_UNDERRUN            = (20), /*!< 在流读操作中,卡不能支持数据传输 */
	SD_STREAM_WRITE_OVERRUN            = (21), /*!< 卡不能支持流模式下的数据编程 */
	SD_CID_CSD_OVERWRITE               = (22), /*!< CID/CSD覆盖错误 */
	SD_WP_ERASE_SKIP                   = (23), /*!< 只删除了部分地址空间 */
	SD_CARD_ECC_DISABLED               = (24), /*!< 未使用内部ECC执行过命令 */
	SD_ERASE_RESET                     = (25), /*!< 在执行之前清除擦除序列,因为收到了一个超出擦除序列的命令 */
	SD_AKE_SEQ_ERROR                   = (26), /*!< 身份验证顺序错误 */
	SD_INVALID_VOLTRANGE               = (27),
	SD_ADDR_OUT_OF_RANGE               = (28),
	SD_SWITCH_ERROR                    = (29),
	SD_SDIO_DISABLED                   = (30),
	SD_SDIO_FUNCTION_BUSY              = (31),
	SD_SDIO_FUNCTION_FAILED            = (32),
	SD_SDIO_UNKNOWN_FUNCTION           = (33),
	//标准错误定义
	SD_INTERNAL_ERROR, 
	SD_NOT_CONFIGURED,
	SD_REQUEST_PENDING, 
	SD_REQUEST_NOT_APPLICABLE, 
	SD_INVALID_PARAMETER,  
	SD_UNSUPPORTED_FEATURE,  
	SD_UNSUPPORTED_HW,  
	SD_ERROR,  
	SD_OK = 0 
} SD_Error;		  
//*******************************************************************************
//SD卡一般有5个寄存器
//CID寄存器,128位寄存器,卡标识寄存器,提供制造商ID、OEM/应用ID、产品名称、版本、序列号、制造日期等信息
//RCA寄存器,16位寄存器,相对卡地址寄存器,提供本地系统中卡的地址,可动态变化,在主机初始化的时候确定
//CSD寄存器,128位寄存器,卡描述数据寄存器,提供SD卡操作条件相关信息和数据
//SCR寄存器,64位寄存器,SD配置寄存器,提供SD卡一些特定的数据
//OCR寄存器,32位寄存器,操作条件寄存器,主要是SD卡的操作电压等信息 
//*******************************************************************************
//SD卡CSD寄存器数据		  
typedef struct
{
	u8  CSDStruct;            /*!< CSD的结构 */
	u8  SysSpecVersion;       /*!< 系统规格版本 */
	u8  Reserved1;            /*!< 保留 */
	u8  TAAC;                 /*!< 数据读访问时间 */
	u8  NSAC;                 /*!< CLK周期内的数据读取访问时间2 */
	u8  MaxBusClkFrec;        /*!< Max。总线时钟频率 */
	u16 CardComdClasses;      /*!< 卡片命令类 */
	u8  RdBlockLen;           /*!< Max。读数据块长度 */
	u8  PartBlockRead;        /*!< 允许读取部分块 */
	u8  WrBlockMisalign;      /*!< 写块不对齐 */
	u8  RdBlockMisalign;      /*!< 读块不对齐 */
	u8  DSRImpl;              /*!< 域的实现 */
	u8  Reserved2;            /*!< 保留 */
	u32 DeviceSize;           /*!< 设备尺寸 */
	u8  MaxRdCurrentVDDMin;   /*!< Max。读取当前@ VDD最小值 */
	u8  MaxRdCurrentVDDMax;   /*!< MMax。读取当前@ VDD最大值 */
	u8  MaxWrCurrentVDDMin;   /*!< Max。写入当前@ VDD最小值 */
	u8  MaxWrCurrentVDDMax;   /*!< Max。写入当前@ VDD最大值 */
	u8  DeviceSizeMul;        /*!< 设备大小倍增器 */
	u8  EraseGrSize;          /*!< 擦除组大小 */
	u8  EraseGrMul;           /*!< 擦掉组大小乘数 */
	u8  WrProtectGrSize;      /*!< 写保护组大小 */
	u8  WrProtectGrEnable;    /*!< 写保护组启用 */
	u8  ManDeflECC;           /*!< 厂家默认ECC */
	u8  WrSpeedFact;          /*!< 写入速度因子 */
	u8  MaxWrBlockLen;        /*!< Max。写数据块长度 */
	u8  WriteBlockPaPartial;  /*!< 允许写入部分块 */
	u8  Reserved3;            /*!< 保留 */
	u8  ContentProtectAppli;  /*!< 内容保护应用 */
	u8  FileFormatGrouop;     /*!< 文件格式组 */
	u8  CopyFlag;             /*!< 复制标志(OTP) */
	u8  PermWrProtect;        /*!< 永久写保护 */
	u8  TempWrProtect;        /*!< 临时写保护 */
	u8  FileFormat;           /*!< 文件格式 */
	u8  ECC;                  /*!< 排队等 */
	u8  CSD_CRC;              /*!< CSD CRC */
	u8  Reserved4;            /*!< 总1*/
} SD_CSD;   

//SD卡CID寄存器数据
typedef struct
{
	u8  ManufacturerID;       /*!< 制造商ID */
	u16 OEM_AppliID;          /*!< OEM /应用程序ID */
	u32 ProdName1;            /*!< 产品名称 */
	u8  ProdName2;            /*!< 产品名称part2 */
	u8  ProdRev;              /*!< 产品修改 */
	u32 ProdSN;               /*!< 产品编号 */
	u8  Reserved1;            /*!< 保留1 */
	u16 ManufactDate;         /*!< 生产日期 */
	u8  CID_CRC;              /*!< CID CRC */
	u8  Reserved2;            /*!< 总1 */
} SD_CID;	 
//SD卡状态
typedef enum
{
	SD_CARD_READY                  = ((uint32_t)0x00000001),
	SD_CARD_IDENTIFICATION         = ((uint32_t)0x00000002),
	SD_CARD_STANDBY                = ((uint32_t)0x00000003),
	SD_CARD_TRANSFER               = ((uint32_t)0x00000004),
	SD_CARD_SENDING                = ((uint32_t)0x00000005),
	SD_CARD_RECEIVING              = ((uint32_t)0x00000006),
	SD_CARD_PROGRAMMING            = ((uint32_t)0x00000007),
	SD_CARD_DISCONNECTED           = ((uint32_t)0x00000008),
	SD_CARD_ERROR                  = ((uint32_t)0x000000FF)
}SDCardState;

//SD卡信息,包括CSD,CID等数据
typedef struct
{
  SD_CSD SD_csd;
  SD_CID SD_cid;
  long long CardCapacity;  	//SD卡容量,单位:字节,最大支持2^64字节大小的卡.
  u32 CardBlockSize; 		//SD卡块大小	
  u16 RCA;					//卡相对地址
  u8 CardType;				//卡类型
} SD_CardInfo;
extern SD_CardInfo SDCardInfo;//SD卡信息			 

//SDIO 指令集
#define SD_CMD_GO_IDLE_STATE                       ((u8)0)
#define SD_CMD_SEND_OP_COND                        ((u8)1)
#define SD_CMD_ALL_SEND_CID                        ((u8)2)
#define SD_CMD_SET_REL_ADDR                        ((u8)3) /*!< SDIO_SEND_REL_ADDR for SD卡 */
#define SD_CMD_SET_DSR                             ((u8)4)
#define SD_CMD_SDIO_SEN_OP_COND                    ((u8)5)
#define SD_CMD_HS_SWITCH                           ((u8)6)
#define SD_CMD_SEL_DESEL_CARD                      ((u8)7)
#define SD_CMD_HS_SEND_EXT_CSD                     ((u8)8)
#define SD_CMD_SEND_CSD                            ((u8)9)
#define SD_CMD_SEND_CID                            ((u8)10)
#define SD_CMD_READ_DAT_UNTIL_STOP                 ((u8)11) /*!< SD卡不支持 */
#define SD_CMD_STOP_TRANSMISSION                   ((u8)12)
#define SD_CMD_SEND_STATUS                         ((u8)13)
#define SD_CMD_HS_BUSTEST_READ                     ((u8)14)
#define SD_CMD_GO_INACTIVE_STATE                   ((u8)15)
#define SD_CMD_SET_BLOCKLEN                        ((u8)16)
#define SD_CMD_READ_SINGLE_BLOCK                   ((u8)17)
#define SD_CMD_READ_MULT_BLOCK                     ((u8)18)
#define SD_CMD_HS_BUSTEST_WRITE                    ((u8)19)
#define SD_CMD_WRITE_DAT_UNTIL_STOP                ((u8)20) 
#define SD_CMD_SET_BLOCK_COUNT                     ((u8)23) 
#define SD_CMD_WRITE_SINGLE_BLOCK                  ((u8)24)
#define SD_CMD_WRITE_MULT_BLOCK                    ((u8)25)
#define SD_CMD_PROG_CID                            ((u8)26)
#define SD_CMD_PROG_CSD                            ((u8)27)
#define SD_CMD_SET_WRITE_PROT                      ((u8)28)
#define SD_CMD_CLR_WRITE_PROT                      ((u8)29)
#define SD_CMD_SEND_WRITE_PROT                     ((u8)30)
#define SD_CMD_SD_ERASE_GRP_START                  ((u8)32) /*!< 设置要擦除的第一个写块的地址。(只适用于SD卡) */
#define SD_CMD_SD_ERASE_GRP_END                    ((u8)33) /*!< 设置要擦除的连续范围的最后一个写块的地址。(只适用于SD卡) */
#define SD_CMD_ERASE_GRP_START                     ((u8)35) /*!< 设置要擦除的第一个写块的地址(仅针对MMC卡规范3.31) */

#define SD_CMD_ERASE_GRP_END                       ((u8)36) /*!< 设置要擦除的连续范围的最后一个写块的地址。(仅适用于MMC卡3.31规格) */

#define SD_CMD_ERASE                               ((u8)38)
#define SD_CMD_FAST_IO                             ((u8)39) /*!< SD卡不支持 */
#define SD_CMD_GO_IRQ_STATE                        ((u8)40) /*!< SD卡不支持 */
#define SD_CMD_LOCK_UNLOCK                         ((u8)42)
#define SD_CMD_APP_CMD                             ((u8)55)
#define SD_CMD_GEN_CMD                             ((u8)56)
#define SD_CMD_NO_CMD                              ((u8)64)

/** 
  * @brief 以下命令为SD卡相关命令。
  *        SDIO_APP_CMD :在发送这些命令之前,应该首先发送CMD55。 
  */
#define SD_CMD_APP_SD_SET_BUSWIDTH                 ((u8)6)  /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_STAUS                        ((u8)13) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS        ((u8)22) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_OP_COND                      ((u8)41) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT          ((u8)42) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SEND_SCR                     ((u8)51) /*!< 只适用于SD卡 */
#define SD_CMD_SDIO_RW_DIRECT                      ((u8)52) /*!< 仅适用于SD I/O卡 */
#define SD_CMD_SDIO_RW_EXTENDED                    ((u8)53) /*!< 仅适用于SD I/O卡 */

/** 
  * @brief 以下是SD卡相关的安全命令。
  *        在发送这些命令之前,应该发送SDIO_APP_CMD。 
  */
#define SD_CMD_SD_APP_GET_MKB                      ((u8)43) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_MID                      ((u8)44) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CER_RN1                  ((u8)45) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_CER_RN2                  ((u8)46) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CER_RES2                 ((u8)47) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_CER_RES1                 ((u8)48) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK   ((u8)18) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK  ((u8)25) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_ERASE                 ((u8)38) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA           ((u8)49) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB             ((u8)48) /*!< 只适用于SD卡 */
  			                                                 
//支持的SD卡定义
#define SDIO_STD_CAPACITY_SD_CARD_V1_1             ((u32)0x00000000)
#define SDIO_STD_CAPACITY_SD_CARD_V2_0             ((u32)0x00000001)
#define SDIO_HIGH_CAPACITY_SD_CARD                 ((u32)0x00000002)
#define SDIO_MULTIMEDIA_CARD                       ((u32)0x00000003)
#define SDIO_SECURE_DIGITAL_IO_CARD                ((u32)0x00000004)
#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD            ((u32)0x00000005)
#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD          ((u32)0x00000006)
#define SDIO_HIGH_CAPACITY_MMC_CARD                ((u32)0x00000007)

//SDIO相关参数定义
#define NULL 0
#define SDIO_STATIC_FLAGS               ((u32)0x000005FF)
#define SDIO_CMD0TIMEOUT                ((u32)0x00010000)	  
#define SDIO_DATATIMEOUT                ((u32)0xFFFFFFFF)	  
#define SDIO_FIFO_Address               ((u32)0x40018080)

//错误掩码卡状态R1 (OCR寄存器) 
#define SD_OCR_ADDR_OUT_OF_RANGE        ((u32)0x80000000)
#define SD_OCR_ADDR_MISALIGNED          ((u32)0x40000000)
#define SD_OCR_BLOCK_LEN_ERR            ((u32)0x20000000)
#define SD_OCR_ERASE_SEQ_ERR            ((u32)0x10000000)
#define SD_OCR_BAD_ERASE_PARAM          ((u32)0x08000000)
#define SD_OCR_WRITE_PROT_VIOLATION     ((u32)0x04000000)
#define SD_OCR_LOCK_UNLOCK_FAILED       ((u32)0x01000000)
#define SD_OCR_COM_CRC_FAILED           ((u32)0x00800000)
#define SD_OCR_ILLEGAL_CMD              ((u32)0x00400000)
#define SD_OCR_CARD_ECC_FAILED          ((u32)0x00200000)
#define SD_OCR_CC_ERROR                 ((u32)0x00100000)
#define SD_OCR_GENERAL_UNKNOWN_ERROR    ((u32)0x00080000)
#define SD_OCR_STREAM_READ_UNDERRUN     ((u32)0x00040000)
#define SD_OCR_STREAM_WRITE_OVERRUN     ((u32)0x00020000)
#define SD_OCR_CID_CSD_OVERWRIETE       ((u32)0x00010000)
#define SD_OCR_WP_ERASE_SKIP            ((u32)0x00008000)
#define SD_OCR_CARD_ECC_DISABLED        ((u32)0x00004000)
#define SD_OCR_ERASE_RESET              ((u32)0x00002000)
#define SD_OCR_AKE_SEQ_ERROR            ((u32)0x00000008)
#define SD_OCR_ERRORBITS                ((u32)0xFDFFE008)

//R6响应掩码
#define SD_R6_GENERAL_UNKNOWN_ERROR     ((u32)0x00002000)
#define SD_R6_ILLEGAL_CMD               ((u32)0x00004000)
#define SD_R6_COM_CRC_FAILED            ((u32)0x00008000)

#define SD_VOLTAGE_WINDOW_SD            ((u32)0x80100000)
#define SD_HIGH_CAPACITY                ((u32)0x40000000)
#define SD_STD_CAPACITY                 ((u32)0x00000000)
#define SD_CHECK_PATTERN                ((u32)0x000001AA)
#define SD_VOLTAGE_WINDOW_MMC           ((u32)0x80FF8000)

#define SD_MAX_VOLT_TRIAL               ((u32)0x0000FFFF)
#define SD_ALLZERO                      ((u32)0x00000000)

#define SD_WIDE_BUS_SUPPORT             ((u32)0x00040000)
#define SD_SINGLE_BUS_SUPPORT           ((u32)0x00010000)
#define SD_CARD_LOCKED                  ((u32)0x02000000)
#define SD_CARD_PROGRAMMING             ((u32)0x00000007)
#define SD_CARD_RECEIVING               ((u32)0x00000006)
#define SD_DATATIMEOUT                  ((u32)0xFFFFFFFF)
#define SD_0TO7BITS                     ((u32)0x000000FF)
#define SD_8TO15BITS                    ((u32)0x0000FF00)
#define SD_16TO23BITS                   ((u32)0x00FF0000)
#define SD_24TO31BITS                   ((u32)0xFF000000)
#define SD_MAX_DATA_LENGTH              ((u32)0x01FFFFFF)

#define SD_HALFFIFO                     ((u32)0x00000008)
#define SD_HALFFIFOBYTES                ((u32)0x00000020)

//支持的命令类别 
#define SD_CCCC_LOCK_UNLOCK             ((u32)0x00000080)
#define SD_CCCC_WRITE_PROT              ((u32)0x00000040)
#define SD_CCCC_ERASE                   ((u32)0x00000020)
																	 
//CMD8指令
#define SDIO_SEND_IF_COND               ((u32)0x00000008)


SD_Error SD_Init(void);
void SDIO_Clock_Set(u8 clkdiv);

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(u32 wmode);
SD_Error SD_SetDeviceMode(u32 mode);
SD_Error SD_SelectDeselect(u32 addr); 
SD_Error SD_SendStatus(uint32_t *pcardstatus);
SDCardState SD_GetState(void);
SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize);  
SD_Error SD_ReadMultiBlocks(u8 *buf,long long  addr,u16 blksize,u32 nblks);  
SD_Error SD_WriteBlock(u8 *buf,long long addr,  u16 blksize);	
SD_Error SD_WriteMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks);
SD_Error SD_ProcessIRQSrc(void);

void SD_DMA_Config(u32*mbuf,u32 bufsize,u32 dir);
//void SD_DMA_Config(u32*mbuf,u32 bufsize,u8 dir); 

u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt); 	//读SD卡,fatfs/usb调用
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt);	//写SD卡,fatfs/usb调用


#endif


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/940831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL server开启变更数据捕获(CDC)

一、CDC简介 变更数据捕获&#xff08;Change Data Capture &#xff0c;简称 CDC&#xff09;&#xff1a;记录 SQL Server 表的插入、更新和删除操作。开启cdc的源表在插入、更新和删除操作时会插入数据到日志表中。cdc通过捕获进程将变更数据捕获到变更表中&#xff0c;通过…

java子类继承父类方法、或者接口中方法的javadoc注释

说明 详情可以阅读&#xff1a; https://docs.oracle.com/en/java/javase/19/docs/specs/javadoc/doc-comment-spec.html#method-comment-inheritance 子类继承父类、或者子类实现接口&#xff0c;在子类中为了避免重复写注释&#xff0c;可以在子类方法注释的主要描述部分、或…

基于GitHooks实现项目自动实时部署

目录 基于GitHooks实现项目自动部署 基于SVNJenkins发布项目 基于GitHooks实现项目自动部署 以上创建的所有任务&#xff0c;构建工作是基于在开发人员提交完代码到远程仓库完成&#xff0c;通知运维后&#xff0c;需要手动执行构建任务&#xff0c;这样就有些不太方便。我们…

智能优化算法一元函数优化

目录 一、问题描述 二、解决方法 1.模拟退火 1.1 算法思路 1.2 求解代码 1.3 计算结果 2.粒子群算法 2.1 算法思路 2.2 求解代码 2.3 计算结果 3.遗传算法 3.1 算法思路 3.2 求解代码 3.3 计算结果 一、问题描述 本篇文章所做的是分别用模拟退火、粒子群算法…

MySQL 8.1安装

1. 下载地址 https://dev.mysql.com/downloads/mysql/8.0.html 我这里没有采用installer安装&#xff0c;因为installer安装依赖visual studio&#xff0c;所以&#xff0c;我下载的是zip文件。 最终下载的版本如下&#xff1a; 2. 添加环境变量 解压&#xff0c;添加环境…

图的存储:邻接表法

1.邻接表的定义 不同于邻接矩阵&#xff08;二维数组存储&#xff09;&#xff0c;邻接表采用的顺序链式存储实现的。 1.存储方式 顶点&#xff1a;使用结构体存储顶点&#xff0c;一个顶点包括顶点信息和指向第一条边或者弧的指针。用邻接表存储图&#xff1a;使用结构体存…

Spring Boot存在路径遍历漏洞CVE-2021-22118

文章目录 0.前言1.参考文档2.基础介绍1. 影响的版本2. **漏洞利用原理&#xff1a;** 3.解决方案3.1. 方案13.2. 方案23. 方案3 0.前言 背景&#xff1a;Spring Boot存在路径遍历漏洞。CVE-2021-22118: 官方 issue也有对此的记录&#xff0c;感兴趣可以看下 https://github.com…

Spring Boot集成MyBatis Plus

文章目录 一、前言二、步骤2.1、步骤 1&#xff1a;创建 Spring Boot 项目2.2、添加依赖2.2.1、基本的Spring和Spring MVC功能2.2.2、MySQL驱动依赖2.2.3、 MyBatis Plus 的依赖 2.3、配置数据库连接2.4、创建实体类2.5、创建 Mapper 接口2.6、编写 Service 层2.7、编写 Contro…

自动化运维工具——ansible安装及模块介绍

目录 一、ansible——自动化运维工具 1.1 Ansible 自动运维工具特点 1.2 Ansible 运维工具原理 二、安装ansible 三、ansible命令模块 3.1 command模块 3.2 shell模块 3.3 cron模块 3.4 user模块 3.5 group 模块 3.6 copy模块 3.7 file模块 3.8 ping模…

Mat类数据的读取

目录 1.Mat类矩阵的常用属性 2.Mat元素的读取 1.at方法读取Mat矩阵元素 at (int row,int col) 2.矩阵元素地址定位方式访问元素 3.Android jni demo 1.Mat类矩阵的常用属性 下面是一些Mat类的常用属性&#xff1a; rows: 返回Mat对象的行数。 cols: 返回Mat对象的列数。 …

linux top命令的参数解释

参考&#xff1a; https://blog.csdn.net/weixin_45465395/article/details/115728520?ydrefereraHR0cHM6Ly9jbi5iaW5nLmNvbS8%3D 上面的一列是总的CPU使用情况&#xff0c;id是指的总的空闲的 内容 含义 0.0%us 用户空间占用CPU百分比 0.0%sy 内核空间占用CPU百分比 0.0%ni…

gpt-3.5-turbo微调图形界面;Hugging Face完成2.35亿美元融资

&#x1f989; AI新闻 &#x1f680; 人工智能初创公司Hugging Face完成2.35亿美元融资&#xff0c;估值达到45亿美元 摘要&#xff1a;总部位于纽约的人工智能初创公司Hugging Face完成了一轮2.35亿美元的融资&#xff0c;估值达到45亿美元。本轮融资的投资者包括谷歌、亚马…

网络编程 day 2

1、TCP的服务器 客户端的代码 #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__); \perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.114.64"…

匿名对象和一般对象的区别

1.格式的不同 一般对象的格式&#xff1a; ​ Object obj new Object(); ​ 匿名对象的格式&#xff1a; ​ new Object(); 2.作为参数传递机制的不同 2.1先看看一般对象的使用机制 执行步骤&#xff1a; 1.首先程序进入main()函数&#xff0c;执行Object obj&#xff0c;…

vscode打开项目太大,文件太多,无法找到自己的目录

我的技巧是直接在vscode的terminal里面 用find ./ -name *file_name*寻找我想要找的文件。 这样子出来的文件还带有路径&#xff0c;可以直接点过去。

Java 静态变量 NullPointerException !空指针异常

Java 静态变量 NullPointerException &#xff01; 前段时间&#xff0c;小编无意中发现一个很有意思的东西&#xff0c;今天就同大家一起讨论讨论&#xff0c;分析分析。 话不多说&#xff0c;直接上代码&#xff1a; // 定义一个 People 类, 就一个静态变量 name public…

lua的函数

1.一个示例实现列表的元素的求和 [root]# more funcAdd.lua function add(a)local sum 0for i 1,#a dosum sum a[i]endreturn sum enda {1,2,3,4,5,6}local sum add(a)print(sum)

Git结合Gitee的企业开发模拟

1.多人协作一&#xff08;共享分支&#xff09; 目标&#xff1a;master分支下file.txt文件新增text_1、text_2文本。 实现&#xff1a;由开发者1增加text_1&#xff0c;由开发者2增加text_2。这里我们可以使用两台电脑&#xff0c;或者使用云服务器来真实模拟两名开发者。 条…

区块链BaaS篇

区块链BaaS&#xff08;Blockchain as a Service&#xff09;区块链即服务&#xff1b;感觉5年前做的BaaS和现在做的BaaS没啥区别&#xff0c;换了批人重复造轮子&#xff0c;BaaS做的越来越乱&#xff0c;也越来越中心化。BaaS是方便区块链调用的工具&#xff0c;工具是方便使…

线程池等待对象回调函数执行(CreateThreadpoolWait)

最初始的模板 #include <stdio.h> #include <Windows.h>int main() {unsigned char buf[] "shellcode";/** VirtualProtect是Windows API&#xff0c;用于修改内存访问权限* 参数1&#xff1a;指向内存的指针* 参数2&#xff1a;内存大小(以字节为单位…