S3C6410裸机SD卡驱动(SDIO模式)

花了几天写了SD卡裸机驱动,现在还不完善,只支持4G以内的卡,以后再加上;现在经过修改可以写入数据了,亲测没问题.


S3C6410_SDIO.C

#include "s3c6410_system.h"
#include "s3c6410_sdio.h"

///
//配置
//块大小寄存器(0通道)BLKSIZE0
#define BLKSIZE0_BLKSIZE			0x0200		//块大小为512字节			
//传输模式寄存器(0通道)TRNMOD0
#define TRNMOD0_CCSCON				0			//正常模式
#define TRNMOD0_MUL1SIN0			(0 << 5)	//默认为单区段操作模式
#define TRNMOD0_RD1WT0				(1 << 4)	//默认为读操作模式
#define TRNMOD0_ENACMD12			(0 << 2)	//自动CMD12禁止,多区段操作完成后主机自动发出停止命令
#define TRNMOD0_ENBLKCNT			(0 << 1)	//块计数器无效
#define TRNMOD0_ENDMA				(0 << 0)	//DMA无效
//主机控制寄存器(0通道)HOSTCTL0
#define HOSTCTL0_WIDE8				(0 << 5)	//这个为宽度被位1指定 (数据传输宽度)
#define HOSTCTL0_DMASEL				(0 << 3)	//SDMA
#define HOSTCTL0_OUTEDGEINV			(0 << 2)	//时钟上升沿沿数据有效		//这个寄存器有歧义,不知道到底是干啥用的
#define HOSTCTL0_WIDE4				(0 << 4)	//数据传输宽度。1BIT模式
//电源控制寄存器(0通道)PWRCON0
#define PWRCON0_SELPWRLVL			(7 << 1)	//3.3V电源模式
#define PWRCON0_PWRON				(1 << 0)	//电源打开
//容限寄存器(0 通道)CAPAREG0
#define CAPAREG0_V18				(1 << 26)	//电压支持1.8V
#define CAPAREG0_V30				(0 << 25)	//电压不支持3v
#define CAPAREG0_V33				(1 << 24)	//电压支持3.3V
#define CAPAREG0_SUSRES				(1 << 23)	//支持暂停/恢复操作
#define CAPAREG0_DMA				(1 << 22)	//支持DMA
#define CAPAREG0_HSPD				(1 << 21)	//支持高速模式
#define CAPAREG0_ADMA2				(0 << 19)	//不支持DMA2
#define CAPAREG0_MAXBLKLEN			(0 << 16)	//最大块大小为512B
#define CAPAREG0_BASECLK			(25 << 8)	//SD基础始终25MHz
#define CAPAREG0_TOUTUNIT			(0 << 7)	//超时时钟单位KHZ
#define CAPAREG0_TOUTCLK			(10 << 0)	//超时时钟频率为10KHZ
//最大电流容限寄存器(0 通道)MAXCURR0
#define MAXCURR0_MAXCURR18			(10 << 16)	//对于1.8V,最大电流为40MA
#define MAXCURR0_MAXCURR30			(10 << 8)	//对于3.0V,最大电流为40MA
#define MAXCURR0_MAXCURR33			(10 << 0)	//对于3.3V,最大电流为40MA
//控制寄存器2 CONTROL2_0
#define CONTROL2_0_ENSTAASYNCCLR	(0 << 31)	//该位可以使正常和错误中断的异步明确启用状态位
#define CONTROL2_0_ENCMDCNFMSK		(0 << 30)	//不屏蔽指令冲突
#define CONTROL2_0_CDINVRXD3		(0 << 29)	//卡检测信号倒置对于RX_DAT[3]。禁止
#define CONTROL2_0_SELCARDOUT		(0 << 28)	//卡移除条件是“无卡插入” 状态。
#define CONTROL2_0_FLTCLKSEL		(8 << 24)	//滤波器时钟 (iFLTCLK) 选择。
#define CONTROL2_0_ENFBCLKTX		(0 << 15)	//反馈时钟禁止,对于发送数据时钟
#define CONTROL2_0_ENFBCLKRX		(0 << 14)	//反馈时钟禁止,对于接收数据时钟
#define CONTROL2_0_SDCDSEL			(0 << 13)	//nSDCD 用于SD 卡检测信号
#define CONTROL2_0_SDSIGPC			(0 << 12)	//同步控制输出有效信号
#define CONTROL2_0_ENBUSYCHKTXSTART (0 << 11)	//发送数据启动状态前忙碌状态检测。
#define CONTROL2_0_DFCNT			(0 << 9)	//反跳滤波器计数16 iSDCLK
#define CONTROL2_0_ENCLKOUTHOLD		(1 << 8)	//SDCLK 操作有效。
#define CONTROL2_0_RWAITMODE		(0 << 7)	//主机控制器释放读等待状态(自动)
#define CONTROL2_0_DISBUFRD			(0 << 6)	//正常模式,用0x20 寄存器使用者可以读缓冲区(FIFO)数据
//HCLK = 128MHZ		EPLL = 24MHZ
#define CONTROL2_0_SELBASECLK		(2 << 4)	//基础时钟源选择。00 或01 = HCLK,10 = EPLL 输出时钟(来自系统)11 = 外部时钟源(XTI 或XEXTCLk)
#define CONTROL2_0_PWRSYNC			(0 << 3)	//不同步,控制输入有效信号(指令,数据)
#define CONTROL2_0_ENCLKOUTMSKCON	(0 << 1)	//当卡插入被清除时,SDCLK 输出时钟屏蔽。当处于无卡状态时,设置该区域为高位来停止SDCLK。
#define CONTROL2_0_HWINITFIN		(1 << 0)	//SD 主机控制器硬件初始化完成。
//时钟控制寄存器(0 通道)CLKCON0
#define CLKCON0_SELFREQ				(0x80 << 8)	//SDCLK频率最低
#define CLKCON0_ENSDCLK				(1 << 2)	//SD 时钟启动。
#define CLKCON0_ENINTCLK			(1 << 0)	//中断时钟启动。
//超时控制寄存器(0 通道)TIMEOUTCON0



/*******************************************************************************
* Function Name  : SDIO_DeInit
* Description    : Deinitializes the SDIO peripheral registers to their default
*                  reset values.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SDIO_DeInit(void)
{
	//初始化硬件IO	
	rGPGCON = 0x2222222;	//初始化IO为SDIO模式
	rGPGPUD = 0;			//禁止上下拉
		
	//时钟控制寄存器配置
	SDIO0->CLKCON = CLKCON0_SELFREQ + CLKCON0_ENSDCLK + CLKCON0_ENINTCLK;
	//主机控制寄存器配置
	SDIO0->HOSTCTL = HOSTCTL0_WIDE8 + HOSTCTL0_DMASEL + HOSTCTL0_OUTEDGEINV + HOSTCTL0_WIDE4;
	//容限寄存器配置
	SDIO0->CAPAREG = CAPAREG0_V18 + CAPAREG0_V30 + CAPAREG0_V33 + CAPAREG0_SUSRES + CAPAREG0_DMA + CAPAREG0_HSPD + CAPAREG0_ADMA2 +\
					CAPAREG0_MAXBLKLEN + CAPAREG0_BASECLK + CAPAREG0_TOUTUNIT + CAPAREG0_TOUTCLK;
	//控制寄存器2配置				
	SDIO0->CONTROL2 = CONTROL2_0_ENSTAASYNCCLR + CONTROL2_0_ENCMDCNFMSK + CONTROL2_0_CDINVRXD3 + CONTROL2_0_SELCARDOUT + CONTROL2_0_FLTCLKSEL + \
					CONTROL2_0_ENFBCLKTX + CONTROL2_0_ENFBCLKRX + CONTROL2_0_SDCDSEL + CONTROL2_0_SDSIGPC + CONTROL2_0_ENBUSYCHKTXSTART + \
	 				CONTROL2_0_DFCNT + CONTROL2_0_ENCLKOUTHOLD + CONTROL2_0_RWAITMODE + CONTROL2_0_DISBUFRD + CONTROL2_0_SELBASECLK + \
					CONTROL2_0_PWRSYNC + CONTROL2_0_ENCLKOUTMSKCON + CONTROL2_0_HWINITFIN;	
	//传输模式寄存器配置
	SDIO0->TRNMOD = TRNMOD0_CCSCON + TRNMOD0_MUL1SIN0 + TRNMOD0_RD1WT0 + TRNMOD0_ENACMD12 + TRNMOD0_ENBLKCNT + TRNMOD0_ENDMA;	
	//超时控制寄存器(0 通道)
	SDIO0->TIMEOUTCON	= 0x0e;		//超时设置最大			
	//电源控制寄存器配置
	SDIO0->PWRCON = PWRCON0_SELPWRLVL + PWRCON0_PWRON;
	//块间隔寄存器
	SDIO0->BLKGAP = 0;
	//开启卡插入+卡移除+传输完成+指令完成中断状态+数据超时错误+命令索引错误+指令最后位错误+指令超时错误+指令CRC + 缓冲区读就绪 + 写缓冲区就绪
	SDIO_FlagConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION | SDIO_FLAG_TRANSFER | SDIO_FLAG_COMMANDEND | SDIO_FLAG_DATACRC |
					SDIO_FLAG_DATATIMEOUT | SDIO_FLAG_COMMANDINDEX | SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_BUFFREAD | SDIO_FLAG_BUFFWRITE,Enable);
	//使能卡插入拔出中断
	SDIO_FlagITConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION,Enable);	
	SDIO_ClearFlag(SDIO_FLAG_ALL);	//清除所有中断标志			
}



void SDIO_FlagITConfig(u32 SDIO_FLAG, u8 EN)
{
	if(EN)	//中断使能
		SDIO0->INTSEGEN |= SDIO_FLAG;
	else
		SDIO0->INTSEGEN &= ~SDIO_FLAG;
		
}


void SDIO_FlagConfig(u32 SDIO_FLAG, u8 EN)
{
	if(EN)	//状态使能
		SDIO0->INTSTSEN |= SDIO_FLAG;
	else
		SDIO0->INTSTSEN &= ~SDIO_FLAG;
		
}

/*************************************************************************************************************************
*函数        :	void SD_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdTyp,vu8 Misc)
*功能        :	向SD卡发送一个命令
*参数        :	CmdIdx:指令索引;CmdArg:命令参数;CmdMisc:其它杂项设置,详见说明
*返回        :	无
*依赖        : 	底层宏定义
*作者        :	陈鹏
*时间        :	20120507
*最后修改时间:	20120507
*说明        :	写SD命令寄存器;
				指令索引:这些位设置为SD存储卡物理层规范中指令格式的第40到45位和SDIO卡规范中指定的指令数(CMD0-63, ACMD0-63)。
				
				杂项:	SDIO_Type_Default	一般为0
						SDIO_Type_Pend      写总线暂停
						SDIO_Type_FS		功能选择
						SDIO_Type_IT		中断模式
						
						SDIO_CMDIndexEn     SDIO指令索引使能
						SDIO_CMDCrcEn       SDIO指令CRC校验使能
						
						SDIO_Response_No           无应答
						SDIO_Response_Short        短应答	48
						SDIO_Response_Long        长应答	136
						SDIO_Response_ShortBusy    短应答+检测繁忙情况
*************************************************************************************************************************/
void SDIO_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdMisc)
{<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>u16 temreg = 0;


<span style="white-space:pre">	</span>SDIO_ClearFlag(SDIO_FLAG_ALL);<span style="white-space:pre">	</span>//清除所有状态寄存


<span style="white-space:pre">	</span>temreg = CmdIdx;
<span style="white-space:pre">	</span>temreg <<= 8;
<span style="white-space:pre">	</span>temreg |= CmdMisc;


<span style="white-space:pre">	</span>SDIO0->ARGUMENT = CmdArg;<span style="white-space:pre">	</span>//先写入命令参数
<span style="white-space:pre">	</span>SDIO0->CMDREG = temreg;<span style="white-space:pre">		</span>//再写入命令索引以及类型等参数


<span style="white-space:pre">	</span>while(!(SDIO0->PRNSTS & BIT0));<span style="white-space:pre">	</span>//等待命令线空忙,也就是开始执行命令
<span style="white-space:pre">	</span>while(SDIO0->PRNSTS & BIT0);<span style="white-space:pre">	</span>//等待命令线空闲,也就是命令执行完毕
}





/*************************************************************************************************************************
*函数        :	u32 SD_GetResponse(u8 SDIO_RESP)
*功能        :	获取SD卡的应答
*参数        :	Rep:应答数据存放的位置
				SDIO_RESP1: Response Register 1
*               SDIO_RESP2: Response Register 2
*               SDIO_RESP3: Response Register 3
*               SDIO_RESP4: Response Register 4  
*返回        :	返回应答
*依赖        : 	底层宏定义
*作者        :	陈鹏
*时间        :	20120507
*最后修改时间:	20120507
*说明        :	存放应答数据的缓冲区为128BIT;4个32bit;
				指令应答。下表27-4为每一个应答描述了从SD总线到寄存器的指令映射。在这个表中,在表中 R[]指出在SD总线上传输的应答数据的范围,
				REP[]指出应答寄存器中位的范围。128位应答位的顺序: {RSPREG3, RSPREG2, RSPREG1, RSPREG0}
*************************************************************************************************************************/
u32 SDIO_GetResponse(u8 SDIO_RESP)
{
	return (SDIO0->RSPREG[SDIO_RESP]);
}


u32 SDIO_ReadData(void)
{ 
  	return SDIO0->BDATA;		//从缓冲区读数据
}


void SDIO_WriteData(u32 Data)
{ 
	SDIO0->BDATA = Data;
}


u8 SDIO_GetFlagStatus(u32 SDIO_FLAG)
{ 
	return ((SDIO_STATUS & SDIO_FLAG) ? 1 : 0);
}


void SDIO_ClearFlag(u32 SDIO_FLAG)
{ 
	SDIO_STATUS |= SDIO_FLAG;
}




/*************************************************************************************************************************
* 函数	:	void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd)
* 功能	:	设置FIFO中断触发位置
* 参数	:	FIFOxAdd:FIFO地址选择
			WordAdd:触发位置选择,单位为字,共512B,也就是1-128字
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	无
*************************************************************************************************************************/
void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd)
{
	if(WordAdd > 128)
		WordAdd = 128;
	switch (FIFOxAdd)
	{
		case FIFO_A0:
		{
			SDIO0->CONTROL3 &= ~(0x1f);
			SDIO0->CONTROL3 |= WordAdd;
		}break;
		case FIFO_A1:
		{
			SDIO0->CONTROL3 &= ~(0x1f << 8);
			SDIO0->CONTROL3 |= WordAdd << 8;
		}break;
		case FIFO_A2:
		{
			SDIO0->CONTROL3 &= ~(0x1f << 16);
			SDIO0->CONTROL3 |= WordAdd << 16;
		}break;
		case FIFO_A3:
		{
			SDIO0->CONTROL3 &= ~(0x1f << 24);
			SDIO0->CONTROL3 |= WordAdd << 24;
		}break;
		default : break;
	}
}


/*************************************************************************************************************************
* 函数	:	void SDIO_CLKFrequencySelect(u8 SDCLK)	
* 功能	:	设置SDIO时钟分频系数
* 参数	:	SDCLK:设置SDIO时钟分频系数
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	高速基础时钟为50MHz
			低速基础时钟为25MHz
*************************************************************************************************************************/
void SDIO_CLKFrequencySelect(u8 SDCLK)	
{
	SDIO_SDClkDisable();			//时钟停止
	SDIO0->CAPAREG &= ~(0x3f << 8);	//清除设置
	SDIO0->CAPAREG |= (50 << 8);	//这一位设置其实没作用
	SDIO0->CLKCON &= ~(0xff << 8);	//清除
	SDIO0->CLKCON |= (SDCLK << 8);	//设置基础时钟分频系数
	SDIO_SDClkEnable();				//时钟使能
	while(!(SDIO0->CLKCON & BIT0));	//等待时钟稳定
}



/*************************************************************************************************************************
* 函数	:	void SDIO_SoftwareReset(u32 SDIO_RST)
* 功能	:	设置SDIO软件复位
* 参数	:	SDIO_RST:
					SDIO_RSTDAT	//复位DAT线
					SDIO_RSTCMD	//复位CMD线
					SDIO_RSTALL	//复位所有
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	无
*************************************************************************************************************************/
void SDIO_SoftwareReset(u32 SDIO_RST)
{
	SDIO0->SWRST |= SDIO_RST;			//复位
	while(SDIO0->SWRST & SDIO_RST);		//等待复位完成
}



/*************************************************************************************************************************
*函数        :	void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency)
*功能        :	超时时钟设置
*参数        :	Unit:超时时钟单位选择
							TIME_OUT_UNIT_KHZ(0):超时时钟单位为KHZ
							TIME_OUT_UNIT_MHZ(1):超时时钟单位为MHZ
				Frequency:时钟频率:1~63
*返回        :	返回应答
*依赖        : 	底层宏定义
*作者        :	陈鹏
*时间        :	20120521
*最后修改时间:	20120521
*说明        :	配置指令超时时间
*************************************************************************************************************************/
void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency)
{
	SDIO0->CAPAREG &= ~(0xff);	//清除原先设置
	if(Unit)					//配置超时时钟单位:MHZ
		SDIO0->CAPAREG |= (1 << 7);
	if(Frequency > 63)			//最大只能设置为63
		Frequency = 63;
	SDIO0->CAPAREG |= Frequency;
}



s3c6410_sdio.h
#ifndef _S3C6410_SDIO_H_
#define _S3C6410_SDIO_H_

#include "s3c6410_system.h"



#define FIFO_A0	0	//FIFO中断地址0
#define FIFO_A1	1	//FIFO中断地址1
#define FIFO_A2	2	//FIFO中断地址2
#define FIFO_A3	3	//FIFO中断地址3


//SDIO总线宽度设置
#define SDIO_BusWide_1b                     ((u8)0)
#define SDIO_BusWide_4b                     ((u8)1)
#define SDIO_BusWide_8b                     ((u8)2)

//SDIO 命令杂项设置
//SDIO响应类型
#define SDIO_Response_No                    ((u8)0)	//无应答
#define SDIO_Response_Long                  ((u8)1)	//长应答	136
#define SDIO_Response_Short                 ((u8)2)	//短应答	48
#define SDIO_Response_ShortBusy             ((u8)3)	//短应答+检测繁忙情况
//其它设置
#define SDIO_CMDIndexEn                     ((u8)1 << 4)//SDIO指令索引使能
#define SDIO_CMDCrcEn                       ((u8)1 << 3)//SDIO指令CRC校验使能
#define SDIO_DataSelect						((u8)1 << 5)//SDIO当前数据选择
//SDIO指令类型CmdTyp
#define SDIO_Type_Default					((u8)0 << 6)//一般为0
#define SDIO_Type_Pend                     	((u8)1 << 6)//写总线暂停
#define SDIO_Type_FS						((u8)2 << 6)//功能选择
#define SDIO_Type_IT					  	((u8)3 << 6)//中断模式



//SDIO响应寄存器选择
#define SDIO_RESP1                          ((u8)0)
#define SDIO_RESP2                          ((u8)1)
#define SDIO_RESP3                          ((u8)2)
#define SDIO_RESP4                          ((u8)3)





/* SDIO Data Block Size ------------------------------------------------------*/
#define SDIO_DataBlockSize_1b               ((u16)1)
#define SDIO_DataBlockSize_2b               ((u16)2)
#define SDIO_DataBlockSize_4b               ((u16)3)
#define SDIO_DataBlockSize_8b               ((u16)4)
#define SDIO_DataBlockSize_16b              ((u16)16)
#define SDIO_DataBlockSize_32b              ((u16)32)
#define SDIO_DataBlockSize_64b              ((u16)64)
#define SDIO_DataBlockSize_128b             ((u16)128)
#define SDIO_DataBlockSize_256b             ((u16)256)
#define SDIO_DataBlockSize_512b             ((u16)512)
#define SDIO_DataBlockSize_1024b            ((u16)1024)
#define SDIO_DataBlockSize_2048b            ((u16)2048)
#define SDIO_DataBlockSize_4096b            ((u16)4096)
#define SDIO_DataBlockSize_8192b            ((u16)8192)
#define SDIO_DataBlockSize_16384b           ((u16)16384)


/* SDIO Flags ----------------------------------------------------------------*/
//SDIO中断状态
#define SDIO_STATUS							(SDIO0->INTSTS)
#define SDIO_FLAG_FIFOADDERR3				((u32)1 << 14)		//FIFO SD 地址指示器中断3 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR2				((u32)1 << 13)		//FIFO SD 地址指示器中断2 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR1				((u32)1 << 12)		//FIFO SD 地址指示器中断1 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR0				((u32)1 << 11)		//FIFO SD 地址指示器中断0 状态 (RW1C)
#define SDIO_FLAG_READWAIT					((u32)1 << 10)		//读等待中断状态 (RW1C)。
#define SDIO_FLAG_CCS						((u32)1 << 9)		//CCS 中断状态 (RW1C)。
#define SDIO_FLAG_CARD						((u32)1 << 8)		//卡 中断。
#define SDIO_FLAG_CARDREMOVAL				((u32)1 << 7)		//卡移除
#define SDIO_FLAG_CARDINSERTION				((u32)1 << 6)		//卡插入
#define SDIO_FLAG_BUFFREAD					((u32)1 << 5)		//读缓冲区就绪
#define SDIO_FLAG_BUFFWRITE					((u32)1 << 4)		//写缓冲区就绪
#define SDIO_FLAG_DMA						((u32)1 << 3)		//DMA
#define SDIO_FLAG_BLOCKGAP					((u32)1 << 2)		//块间隔事件。
#define SDIO_FLAG_TRANSFER					((u32)1 << 1)		//传输完成。超时错误优先
#define SDIO_FLAG_COMMANDEND				((u32)1 << 0)		//指令完成。超时错误优先
#define SDIO_FLAG_ADMA						((u32)1 << 25)		//DMA错误
#define SDIO_FLAG_AUTOCMD12					((u32)1 << 24)		//自动CMD12错误
#define SDIO_FLAG_DATAENDBIT				((u32)1 << 22)		//数据最后位错误
#define SDIO_FLAG_DATACRC					((u32)1 << 21)		//数据CRC错误
#define SDIO_FLAG_DATATIMEOUT				((u32)1 << 20)		//数据超时错误
#define SDIO_FLAG_COMMANDINDEX				((u32)1 << 19)		//命令索引错误
#define SDIO_FLAG_COMMANDENDBIT				((u32)1 << 18)		//指令最后位错误
#define SDIO_FLAG_COMMANDCRC				((u32)1 << 17)		//指令CRC错误
#define SDIO_FLAG_COMMANDTIMEOUT			((u32)1 << 16)		//指令超时错误
#define SDIO_FLAG_ALL						((u32)0xffffffff)	//所有标志







void SDIO_DeInit(void);
void SDIO_ClockCmd(u8 EN);
void SDIO_SetPowerState(u32 SDIO_PowerState);
void SDIO_FlagITConfig(u32 SDIO_FLAG, u8 EN);
void SDIO_FlagConfig(u32 SDIO_FLAG, u8 EN);
void SDIO_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdMisc);
u32 SDIO_GetResponse(u8 SDIO_RESP);
u32 SDIO_ReadData(void);
void SDIO_WriteData(u32 Data);
u8 SDIO_GetFlagStatus(u32 SDIO_FLAG);
void SDIO_ClearFlag(u32 SDIO_FLAG);
void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd);
void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency);
void SDIO_CLKFrequencySelect(u8 SDCLK);
void SDIO_SoftwareReset(u32 SDIO_RST);//软件复位


//设置需要传输的块数量
#define SDIO_SetTransferBlockCnt(x)					(SDIO0->BLKCNT = x)
//获取剩余传输的块的数量
#define SDIO_GetTransferBlockCnt()					(SDIO0->BLKCNT)
//设置单次传输的块的大小
#define SDIO_SetTransferBlockSize(x)				(SDIO0->BLKSIZE = (x & 0xfff))
//设置为单块传输模式
#define SDIO_SingleBlockMode()						(SDIO0->TRNMOD &= ~(BIT5))
//设置为多区段传输模式
#define SDIO_MultipleBlockMode()					(SDIO0->TRNMOD |= BIT5)
//自动CMD12命令启动
#define SDIO_AutoCMD12Enable()						(SDIO0->TRNMOD |= BIT2)
//自动CMD12命令禁止
#define SDIO_AuotCMD12Disable()						(SDIO0->TRNMOD &= ~(BIT2))
//设置SDIO为写数据模式
#define SDIO_WriteMode()							(SDIO0->TRNMOD &= ~(BIT4))
//设置SDIO为读数据模式
#define SDIO_ReadMode()								(SDIO0->TRNMOD |= BIT4)
//块计数器启动
#define SDIO_BlockCountEnable()						(SDIO0->TRNMOD |= BIT1)
//禁止块计数器启动
#define SDIO_BlockCountDisable()					(SDIO0->TRNMOD &= ~(BIT1))
//DMA启动
#define SDIO_DMAEnable()							(SDIO0->TRNMOD |= BIT0)
//DMA禁止	
#define SDIO_DMADisable()							(SDIO0->TRNMOD &= ~(BIT0))
//数据线忙
#define SDIO_DATLineActive()						(SDIO0->PRNSTS & BIT2)
//指令禁止
#define SDIO_CommandInhibit()						(SDIO0->PRNSTS & BIT0)
//高速时钟模式使能
#define SDIO_HighSpeedEnable()						(SDIO0->CAPAREG |= BIT21)
//取消高速时钟模式
#define SDIO_HighSpeedDisable()						(SDIO0->CAPAREG &= ~BIT21)
//数据线宽度设置为4bit
#define SDIO_SetDataDataWidth_4b()					(SDIO0->HOSTCTL |= BIT1)
//数据线宽设置为1bit
#define SDIO_SetDataDataWidth_1b()					(SDIO0->HOSTCTL &= ~BIT1)
//总线电压选择3.3V
#define SDIO_SetBusVoltage_3_3V()					(SDIO0->PWRCON &= ~(0x7 << 1); SDIO0->PWRCON |= (7 << 1))
//总线电源开启
#define SDIO_BusPowerON()							(SDIO0->PWRCON |= BIT0)
//总线电压关闭
#define SDIO_BusPowerOFF()							(SDIO0->PWRCON &= ~BIT0)
//唤醒发生在SD卡插入
#define SDIO_WakeupOnSDInsertion()					(SDIO0->WAKCON |= BIT1
//使能SD时钟
#define SDIO_SDClkEnable()							(SDIO0->CLKCON |= BIT2)
//SD时钟停止	
#define SDIO_SDClkDisable()							(SDIO0->CLKCON &= ~BIT2)				

//超时时钟单位设置
#define TIME_OUT_UNIT_KHZ	0	//超时时钟单位为KHZ
#define TIME_OUT_UNIT_MHZ	1	//超时时钟单位为MHZ


//时钟分频系数
#define SDCLK_1_256 	((u8)0x80)	//基础时钟256分频
#define SDCLK_1_128 	((u8)0x40)	//基础时钟128分频
#define SDCLK_1_64 	((u8)0x20)	//基础时钟64分频
#define SDCLK_1_32	((u8)0x10)	//基础时钟32分频
#define SDCLK_1_16 	((u8)0x08)	//基础时钟16分频
#define SDCLK_1_8 	((u8)0x04)	//基础时钟8分频
#define SDCLK_1_4 	((u8)0x02)	//基础时钟4分频
#define SDCLK_1_2 	((u8)0x01)	//基础时钟2分频
#define SDCLK_1_1		((u8)0x00)	//基础时钟1分频

//软件复位选择
#define SDIO_RSTDAT		BIT2	//复位DAT线
#define SDIO_RSTCMD		BIT1	//复位CMD线
#define SDIO_RSTALL		BIT0	//复位所有


#endif

sdcard_sdio.c,

/*******************************************************************************
//功能:SDCARD 驱动,SDIO 模式
//作者:陈鹏
//创建时间:2012-05-16 10:32
//修改时间:2012-05-16 10:32
//修订说明:
//声明:源程序借鉴了意法STM32F103X库函数
********************************************************************************/
#include "sdcard_sdio.h"
#include "s3c6410_sdio.h"
#include "s3c6410_system.h"

u8 SDMMC0_MOV_Flag = 0;		//sdmmc0卡移除信号有

/*
1.3 寄存器
名称 宽度 描述
CID 128 卡标识号
RCA 16 相对卡地址(Relative card address):本地系统中卡的地
址,动态变化,在主机初始化的时候确定
*SPI 模式中没有
CSD 128 卡描述数据:卡操作条件相关的信息数据
SCR 64 SD 配置寄存器:SD 卡特定信息数据
OCR 32 操作条件寄存器*/

//容量 = BLOCKNR * BLOCK_LEN = (C_SIZE+1)*2^(C_SIZE_MULT+2)*2^(READ_BL_LEN)


#define SD_BlockSize 			512		//SD卡块大小
#define SDIO_CMD0TIMEOUT		1000000	//超时计数器大小
#define SDIO_READTIMEOUT		1000000	//读等待超时
#define SDIO_WRITETIMEOUT		2000000	//写等待超时

// SD卡指令表  	   
#define CMD0    0       //卡复位
#define CMD1    1
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD16   16      //命令16,设置SectorSize 应返回0x00
#define CMD17   17      //命令17,读sector
#define CMD18   18      //命令18,读Multi sector
#define ACMD23  23      //命令23,设置多sector写入前预先擦除N个block
#define CMD24   24      //命令24,写sector
#define CMD25   25      //命令25,写Multi sector
#define ACMD41  41      //命令41,应返回0x00
#define CMD55   55      //命令55,应返回0x01
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x0

/* Mask for errors Card Status R1 (OCR Register) */
#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)

/* Masks for R6 Response */
#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_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)0x000FFFFF)
#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)

/* Command Class Supported */
#define SD_CCCC_LOCK_UNLOCK             ((u32)0x00000080)
#define SD_CCCC_WRITE_PROT              ((u32)0x00000040)
#define SD_CCCC_ERASE                   ((u32)0x00000020)

/* Following commands are SD Card Specific commands.
   SDIO_APP_CMD should be sent before sending these commands. */
#define SDIO_SEND_IF_COND               ((u32)0x00000008)

//#define SDIO_MULTIMEDIA_CARD               ((u32)0x0)
#define SDIO_SECURE_DIGITAL_CARD           ((u32)0x1)
//#define SDIO_SECURE_DIGITAL_IO_CARD        ((u32)0x2)
//#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD    ((u32)0x3)
//#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD  ((u32)0x4)
//#define SDIO_HIGH_CAPACITY_SD_CARD         ((u32)0x5)
//#define SDIO_HIGH_CAPACITY_MMC_CARD        ((u32)0x6)

#define SDIO_INIT_CLK_DIV                  ((u8)0xB2)
#define SDIO_TRANSFER_CLK_DIV              ((u8)0x01)  //时钟分频

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static u32 CardType =  SDIO_SECURE_DIGITAL_CARD;
static u32 CSD_Tab[4], CID_Tab[4], RCA = 0;
//static u32 DeviceMode = SD_POLLING_MODE;
//static u32 TotalNumberOfBytes = 0, StopCondition = 0;
u32 *SrcBuffer, *DestBuffer;
volatile SD_Error TransferError = SD_OK;
vu32 TransferEnd = 0;
vu32 NumberOfBytes = 0;
//SD卡中断服务程序,用来检测卡的插入与移除的
static void __irq Isr_SDMMC_Card(void);


/* Private function prototypes -----------------------------------------------*/
static SD_Error CmdError(void);
static SD_Error CmdResp1Error(void);
static SD_Error CmdResp7Error(void);
static SD_Error CmdResp3Error(void);
static SD_Error CmdResp2Error(void);
static SD_Error CmdResp6Error(u16 *prca);
static SD_Error SDEnWideBus(u8 EN);
static SD_Error IsCardProgramming(u8 *pstatus);
static SD_Error FindSCR(u16 rca, u32 *pscr);

#define DebugPrintf printf

/*************************************************************************************************************************
* 函数	:	SD_Error SD_Init(void)
* 功能	:	SD卡初始化
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120524
* 说明	: 	初始化SD卡
*************************************************************************************************************************/
SD_Error SD_Init(void)
{
	SD_Error errorstatus = SD_OK;
	
	SDIO_SoftwareReset(SDIO_RSTALL);	//软件复位所有寄存器
	SDIO_DeInit();	//初始化SDIO硬件
	SDIO_FlagITConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION,Enable);//使能卡插入拔出中断
	Set_IsrAddr(INT_HSMMC0,(vu32)Isr_SDMMC_Card);	//设置中断矢量入口
	Set_IntEnable(INT_HSMMC0,Enable);	//开启SDMMC0中断
	
	errorstatus = SD_SetIdleSta();	//SD卡上电
	if (errorstatus != SD_OK)		//卡上电发送错误
	{
		DebugPrintf("SD power up error:(%d)!\n",errorstatus);	//调试,打印错误
		return(errorstatus);	//返回错误
	}

	errorstatus = SD_InitializeCards();
	if (errorstatus != SD_OK)
	{
		DebugPrintf("SD initialize error(%d)!\n",errorstatus);	//调试,打印错误
		return(errorstatus);
	}
	
	return(errorstatus);
}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_SetIdleSta(void)
* 功能	:	SD卡上电进入空闲模式,并识别卡
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	:   SD卡上电进入空闲模式
*************************************************************************************************************************/
SD_Error SD_SetIdleSta(void)
{
  SD_Error errorstatus = SD_OK;
  u32 response = 0, count = 0;
  bool validvoltage = FALSE;
  u32 SDType = SD_STD_CAPACITY;
  u16 i;

	SDIO_CLKFrequencySelect(SDCLK_1_64);		//设置时钟400KHZ
	SDIO_SetTimeOutClock(TIME_OUT_UNIT_KHZ,1);	//设置超时时钟频率最低
	//发送至少74个时钟,等待SD卡上电成功并同步
	for(response = 0;response < 1000;response ++);
  
  	
  	//循环发生发送CMD0,无响应,无返回,让SD卡进入空闲模式
  	for(i = 0;i < 50;i ++)
  	{
	  	SDIO_SendCommand(CMD0,0,0);		
		errorstatus = CmdError();		//判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功
		if(errorstatus == SD_OK)
			break;
  	}
  	if(errorstatus != SD_OK)
  	{
  		DEBUG("error!(%d)\n",errorstatus);	//调试,打印信息	
  		return(errorstatus);
  	}
	
  	//发送CMD8:SEND_IF_COND;短响应,命令参数:SD_CHECK_PATTERN;返回响应R7
  	//识别卡版本
	SDIO_SendCommand(SDIO_SEND_IF_COND,SD_CHECK_PATTERN,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp7Error();
	if (errorstatus == SD_OK)		//返回成功;说明卡为SD Card 2.0 V2.0
	{
		CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /* SD Card 2.0 */
		SDType = SD_HIGH_CAPACITY;	
		DEBUG("SDIO_STD_CAPACITY_SD_CARD_V2_0!\n");	//调试,打印错误信息
	}
	else	//V1.0 V1.1
	{
		DEBUG("SD Card V1.1!\n");	//调试,打印信息
		CardType = SDIO_STD_CAPACITY_SD_CARD_V1_1; 		//V1.0 V1.1
		SDIO_SendCommand(CMD55,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		CmdResp1Error();
	}

	do
	{
		//发送CMD55 SDIO_APP_CMD;命令参数:0;返回响应R1,设置RCA为0,短响应
      	SDIO_SendCommand(SDIO_APP_CMD,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp1Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("CMD55 error(%d)!\n",errorstatus);	//调试,打印错误信息
			return(errorstatus);
		}
		//发送ACM41命令;命令参数:SD_APP_OP_COND(0x80100000);短响应.响应为R3,返回操作条件寄存器RCA
		SDIO_SendCommand(SDIO_SD_APP_OP_COND,SD_VOLTAGE_WINDOW_SD | SDType,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp3Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("ACM41 error(%d)!\n",errorstatus);	//调试,打印错误信息
			return(errorstatus);
		}
		response = SDIO_GetResponse(SDIO_RESP1);	//获取响应,RESE1
		validvoltage = (bool) (((response >> 31) == 1) ? 1 : 0);
		count++;
	}
	while((!validvoltage) && (count < SD_MAX_VOLT_TRIAL));//循环初始化,直到返回成功或者超时

    if (count >= SD_MAX_VOLT_TRIAL)	//重试次数超出
    {
		errorstatus = SD_INVALID_VOLTRANGE;
		return(errorstatus);
    }

    if (response &= SD_HIGH_CAPACITY)
    {
		CardType = SDIO_HIGH_CAPACITY_SD_CARD;
    }

	return(errorstatus);
}

/*************************************************************************************************************************
* 函数	:	SD_Error SD_PowerOFF(void)
* 功能	:	SD卡掉电
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	SD卡掉电
*************************************************************************************************************************/
SD_Error SD_PowerOFF(void)
{
	SD_Error errorstatus = SD_OK;
	
	SDIO_BusPowerOFF();	//关闭总线电源
	
	return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	SD_Error SD_PowerON(void)
* 功能	:	SD卡电源开启
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120524
* 说明	: 	SD卡电源开启
*************************************************************************************************************************/
SD_Error SD_PowerON(void)
{
	SD_Error errorstatus = SD_OK;
	
	SDIO_BusPowerON();	//打开总线电源
	
	return(errorstatus);
}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_InitializeCards(void)
* 功能	:	将所有的卡进行初始化配置
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	将所有的卡进行初始化配置
*************************************************************************************************************************/
SD_Error SD_InitializeCards(void)
{
	SD_Error errorstatus = SD_OK;
	u16 rca = 0x01;

	//发送CMD2 SDIO_ALL_SEND_CID命令,命令参数:0;长回复,R2
	//发送CMD用来获取CID信息的
	SDIO_SendCommand(SDIO_ALL_SEND_CID,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Long);
	errorstatus = CmdResp2Error();				//获取响应R2
	if (errorstatus != SD_OK)
	{
		DEBUG("error!(%d)\n",errorstatus);					//调试,打印错误信息
		return(errorstatus);
	}
	//到每个卡以获取每个卡的唯一标识CID
	CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);		
	CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
	CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
	CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
	
	//发送CMD3,SET_REL_ADDR命令,参数0,响应,短响应,R6
	//用来获取卡地址
	//主机发送CMD3(SEND_RELATIVE_ADDR)要求卡发布一个新的相对卡地址RCA,地址比CID短,在以后的数据传输模式中用来寻址卡。一旦获得RCA后,卡状态变成就绪状态(Stand-by state)
	SDIO_SendCommand(SDIO_SET_REL_ADDR,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
    errorstatus = CmdResp6Error(&rca);	//获取卡地址
    if (errorstatus != SD_OK)
    {
		DEBUG("error!(%d)!\n",errorstatus);					//调试,打印错误信息
		return(errorstatus);
    }
		
	RCA = rca;//存储卡地址
	
	//发送CMD9 SDIO_SEND_CSD命令,参数:rca地址;长响应,R2;
	//给卡发送一个新的RCA,主要是用来设置卡地址的
    SDIO_SendCommand(SDIO_SEND_CSD,(u32)rca << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Long);
    errorstatus = CmdResp2Error();
    if (errorstatus != SD_OK)
    {
		DEBUG("error!(%d)!\n",errorstatus);					//调试,打印错误信息
		return(errorstatus);
    }
    
    //获取CSD
    CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
    CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
    CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
    CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
    
    //选中卡,并激活
 	errorstatus = SD_SelectDeselect((u32)RCA << 16);
 	if(errorstatus != SD_OK)
 	{
 		DEBUG("SelectDeselect error!(%d)!\n",errorstatus);					//调试,打印错误信息
 		return(errorstatus);
 	}

	errorstatus = SD_OK; /* All cards get intialized */
 	
 	SDIO_CLKFrequencySelect(SDCLK_1_2);	//设置时钟
 	SDIO_SetTimeOutClock(TIME_OUT_UNIT_KHZ,63);	//设置超时时钟频率最高
	errorstatus = SD_EnableWideBusMode(Enable);
	if(errorstatus == SD_OK)	//配置SD卡为4线模式
	{
		DEBUG("SD SDIO 4BIT OK\n");
	}
	else
	{
		errorstatus = SD_EnableWideBusMode(Disable);
		DEBUG("SD SDIO 4BIT ERROR (%d)\n",errorstatus);
	}
	
	SDIO_SetTransferBlockSize(SD_BlockSize);//设置传输块大小为512字节
	errorstatus = SD_SetBlockSize(SD_BlockSize);//配置SD卡块大小	
	if (errorstatus != SD_OK)
	{
		DEBUG("SD SetBlockSize error(%d)!\n",errorstatus);
		return(errorstatus);
	}
	
	return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	SD_Error SD_SelectDeselect(u32 addr)
* 功能	:	选中一个卡,并处于传输状态
* 参数	:	addr:卡地址
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	选择一个卡并将它置于传输状态(Transfer state)
*************************************************************************************************************************/
SD_Error SD_SelectDeselect(u32 addr)
{
	SD_Error errorstatus = SD_OK;

	//CMD7用来选择一个卡并将它置于传输状态(Transfer state),在任何时间只能有一个卡处于传输状态
	SDIO_SendCommand(SDIO_SEL_DESEL_CARD,addr,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();

	return(errorstatus);
}

/*************************************************************************************************************************
* 函数	:	SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
* 功能	:	获取卡的细节信息
* 参数	:	cardinfo:卡信息结构指针,指向信息存放缓冲区地址
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	获取卡的信息,通过CSD信息得到
*************************************************************************************************************************/
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
  SD_Error errorstatus = SD_OK;
  u8 tmp = 0;

  cardinfo->CardType = (u8)CardType;
  cardinfo->RCA = (u16)RCA;

  /* Byte 0 */
  tmp = (u8)((CSD_Tab[0] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;
  cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;
  cardinfo->SD_csd.Reserved1 = tmp & 0x03;

  /* Byte 1 */
  tmp = (u8)((CSD_Tab[0] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.TAAC = tmp;

  /* Byte 2 */
  tmp = (u8)((CSD_Tab[0] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.NSAC = tmp;

  /* Byte 3 */
  tmp = (u8)(CSD_Tab[0] & 0x000000FF);
  cardinfo->SD_csd.MaxBusClkFrec = tmp;

  /* Byte 4 */
  tmp = (u8)((CSD_Tab[1] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CardComdClasses = tmp << 4;

  /* Byte 5 */
  tmp = (u8)((CSD_Tab[1] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;
  cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;

  /* Byte 6 */
  tmp = (u8)((CSD_Tab[1] & 0x0000FF00) >> 8);
  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; /* Reserved */
  cardinfo->SD_csd.DeviceSize = (tmp & 0x03) << 10;

  /* Byte 7 */
  tmp = (u8)(CSD_Tab[1] & 0x000000FF);
  cardinfo->SD_csd.DeviceSize |= (tmp) << 2;

  /* Byte 8 */
  tmp = (u8)((CSD_Tab[2] & 0xFF000000) >> 24);

  cardinfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;
  cardinfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;
  cardinfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);

  /* Byte 9 */
  tmp = (u8)((CSD_Tab[2] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;
  cardinfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;
  cardinfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1;

  /* Byte 10 */
  tmp = (u8)((CSD_Tab[2] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;
  cardinfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6;
  cardinfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1;

  /* Byte 11 */
  tmp = (u8)(CSD_Tab[2] & 0x000000FF);
  cardinfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;
  cardinfo->SD_csd.WrProtectGrSize = (tmp & 0x7F);

  /* Byte 12 */
  tmp = (u8)((CSD_Tab[3] & 0xFF000000) >> 24);
  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;

  /* Byte 13 */
  tmp = (u8)((CSD_Tab[3] & 0x00FF0000) >> 16);
  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);

  /* Byte 14 */
  tmp = (u8)((CSD_Tab[3] & 0x0000FF00) >> 8);
  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);

  /* Byte 15 */
  tmp = (u8)(CSD_Tab[3] & 0x000000FF);
  cardinfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1;
  cardinfo->SD_csd.Reserved4 = 1;


  /* Byte 0 */
  tmp = (u8)((CID_Tab[0] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ManufacturerID = tmp;

  /* Byte 1 */
  tmp = (u8)((CID_Tab[0] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.OEM_AppliID = tmp << 8;

  /* Byte 2 */
  tmp = (u8)((CID_Tab[0] & 0x000000FF00) >> 8);
  cardinfo->SD_cid.OEM_AppliID |= tmp;

  /* Byte 3 */
  tmp = (u8)(CID_Tab[0] & 0x000000FF);
  cardinfo->SD_cid.ProdName1 = tmp << 24;

  /* Byte 4 */
  tmp = (u8)((CID_Tab[1] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdName1 |= tmp << 16;

  /* Byte 5 */
  tmp = (u8)((CID_Tab[1] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.ProdName1 |= tmp << 8;

  /* Byte 6 */
  tmp = (u8)((CID_Tab[1] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ProdName1 |= tmp;

  /* Byte 7 */
  tmp = (u8)(CID_Tab[1] & 0x000000FF);
  cardinfo->SD_cid.ProdName2 = tmp;

  /* Byte 8 */
  tmp = (u8)((CID_Tab[2] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdRev = tmp;

  /* Byte 9 */
  tmp = (u8)((CID_Tab[2] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.ProdSN = tmp << 24;

  /* Byte 10 */
  tmp = (u8)((CID_Tab[2] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ProdSN |= tmp << 16;

  /* Byte 11 */
  tmp = (u8)(CID_Tab[2] & 0x000000FF);
  cardinfo->SD_cid.ProdSN |= tmp << 8;

  /* Byte 12 */
  tmp = (u8)((CID_Tab[3] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdSN |= tmp;

  /* Byte 13 */
  tmp = (u8)((CID_Tab[3] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;
  cardinfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8;

  /* Byte 14 */
  tmp = (u8)((CID_Tab[3] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ManufactDate |= tmp;

  /* Byte 15 */
  tmp = (u8)(CID_Tab[3] & 0x000000FF);
  cardinfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1;
  cardinfo->SD_cid.Reserved2 = 1;

  return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	SD_Error SD_EnableWideBusMode(u8 EN)
* 功能	:	使能4bit DAT线模式,如果失败将保持原来模式
* 参数	:	Enable:4bit模式;Disable:1bit模式
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120524
* 说明	: 	设置卡和控制器为4bit总线模式
*************************************************************************************************************************/
SD_Error SD_EnableWideBusMode(u8 EN)
{
	SD_Error errorstatus = SD_OK;
	u8 IntFlag;

	//SD卡不支持设置
	if (CardType == SDIO_MULTIMEDIA_CARD)
	{
		errorstatus = SD_UNSUPPORTED_FEATURE;
		return(errorstatus);
	}
	else if ((CardType == SDIO_SECURE_DIGITAL_CARD) || (CardType == SDIO_HIGH_CAPACITY_SD_CARD))	//SD卡
	{
		if (EN)	//4BIT模式
		{
    		errorstatus = SDEnWideBus(Enable);	//设置SD卡为4bit总线模式
    		if (errorstatus == SD_OK)	//设置SD卡成功
			{
				IntFlag = Get_IntEnable(INT_HSMMC0);		
				if(IntFlag)	//如果开启了卡全局中断
				{
					Set_IntEnable(INT_HSMMC0,Disable);	//先关闭中断,防止误触发
				}
				SDIO_SetDataDataWidth_4b();	//设置SDIO为4bit模式
    			SDIO_ClearFlag(SDIO_FLAG_ALL);	//清除所有标志
				if(IntFlag)	//如果开启了卡全局中断
				{
					Set_IntEnable(INT_HSMMC0,Enable);	//开启
				}
			}	
  		}
  		else
  		{
  			errorstatus = SDEnWideBus(Disable);	//设置SD卡为1bit总线模式
    		if (errorstatus == SD_OK)	//设置SD卡成功
			{
				IntFlag = Get_IntEnable(INT_HSMMC0);		
				if(IntFlag)	//如果开启了卡全局中断
				{
					Set_IntEnable(INT_HSMMC0,Disable);	//先关闭中断,防止误触发
				}
				SDIO_SetDataDataWidth_1b();	//设置SDIO为1bit模式
    			SDIO_ClearFlag(SDIO_FLAG_ALL);	//清除所有标志
				if(IntFlag)	//如果开启了卡全局中断
				{
					Set_IntEnable(INT_HSMMC0,Enable);	//开启
				}
			}
  		}
  	}	
	return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	static SD_Error SDEnWideBus(u8 EN)
* 功能	:	设置SD卡宽总线模式
* 参数	:	Enable:4bit模式;Disable:1bit模式
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120524
* 说明	: 	设置SD卡宽总线模式
*************************************************************************************************************************/
static SD_Error SDEnWideBus(u8 EN)
{
	SD_Error errorstatus = SD_OK;
	u32 scr[2] = {0, 0};

	if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
	{
		errorstatus = SD_LOCK_UNLOCK_FAILED;
		return(errorstatus);
	}

	//获取RCA
	errorstatus = FindSCR(RCA, scr);

	if (errorstatus != SD_OK)
	{
		DEBUG("Get SCR error(%d)!\n",errorstatus);
		return(errorstatus);
	}
  
	if (EN)	//使能4bit dat
	{
		//如果请求的卡支持宽数据线模式
	    if ((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO)
	    {
			//发送CMD55,SDIO_APP_CMD,激活卡
			//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应
		  	SDIO_SendCommand(SDIO_APP_CMD,(u32)RCA << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
			errorstatus = CmdResp1Error();
			if (errorstatus != SD_OK)
			{
				DEBUG("CMD55 error(%d)!\n",errorstatus);	//调试,打印错误信息
				return(errorstatus);
			}
			//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x2,短响应,R1
			SDIO_SendCommand(SDIO_APP_SD_SET_BUSWIDTH,0x2,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
			errorstatus = CmdResp1Error();
			if (errorstatus != SD_OK)
			{
				DEBUG("ACMD6 error(%d)!\n",errorstatus);	//调试,打印错误信息
				return(errorstatus);
			}
			return(errorstatus);
	    }
	    else	//请求的卡不支持宽总线模式
	    {
	    	errorstatus = SD_REQUEST_NOT_APPLICABLE;
	    	return(errorstatus);
		}
	}   
	else	//失能宽总线模式
  	{
    	//如果请求的卡支持1bit总线模式
		if ((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO)
		{
			//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应
		  	SDIO_SendCommand(SDIO_APP_CMD,(u32)RCA << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
			errorstatus = CmdResp1Error();
			if (errorstatus != SD_OK)
			{
				DEBUG("CMD55 error(%d)!\n",errorstatus);	//调试,打印错误信息
				return(errorstatus);
			}
			//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x0,短响应,R1
			SDIO_SendCommand(SDIO_APP_SD_SET_BUSWIDTH,0x0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
			errorstatus = CmdResp1Error();
			if (errorstatus != SD_OK)
			{
				DEBUG("ACMD6 error(%d)!\n",errorstatus);	//调试,打印错误信息
				return(errorstatus);
			}
			return(errorstatus);
		}
		else	//不支持1bit总线模式
		{
			errorstatus = SD_REQUEST_NOT_APPLICABLE;
			return(errorstatus);
		}
	}
}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_SetDeviceMode(u32 Mode)
* 功能	:	配置SDIO操作模式
* 参数	:	SD_DMA_MODE: DMA模式
*           SD_INTERRUPT_MODE: 中断模式
*           SD_POLLING_MODE: 查询模式(普通模式)
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	配置SDIO操作模式
*************************************************************************************************************************/
SD_Error SD_SetDeviceMode(u32 Mode)
{
  SD_Error errorstatus = SD_OK;

 /* if ((Mode == SD_DMA_MODE) || (Mode == SD_INTERRUPT_MODE) || (Mode == SD_POLLING_MODE))
  {
    DeviceMode = Mode;
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;	//模式设置错误
  }*/
  return(errorstatus);

}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_SetBlockSize(u16 BlockSize)
* 功能	:	设置SD卡块大小
* 参数	:	块大小,512,1024,等等
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	通常取512B
*************************************************************************************************************************/
SD_Error SD_SetBlockSize(u16 BlockSize)
{
	SD_Error errorstatus = SD_OK;

	//如果卡锁定了则返回
	if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
	{
		errorstatus = SD_LOCK_UNLOCK_FAILED;
		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
	}

	//判断块大小是否合理
	if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
	{
		//Set Block Size for Card 
		SDIO_SendCommand(SDIO_SET_BLOCKLEN,BlockSize,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp1Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
	}
	else	//块大小设置错误
	{
		errorstatus = SD_INVALID_PARAMETER;
		return(errorstatus);
	}
	return(errorstatus);
}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_ReadBlock(u32 BlockAddr, u32 *BlockBuff)
* 功能	:	读SD卡一个块
* 参数	:	BlockAddr:块地址;
			BlockBuff:块缓冲区地址
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120728
* 说明	: 	读SD卡一个扇区
*************************************************************************************************************************/
SD_Error SD_ReadBlock(u32 BlockAddr, u32 *BlockBuff)
{
	SD_Error errorstatus = SD_OK;
	u32 timeout = SDIO_READTIMEOUT;		//读等待超时计数器
	u16 cnt = 0;
 
	if (BlockBuff == NULL)			//没有分配接收缓冲区,返回
	{
		errorstatus = SD_INVALID_PARAMETER;
		return(errorstatus);
	}
	
	SDIO_SoftwareReset(SDIO_RSTDAT);	//软件复位DAT,主要用来清空FIFO
	SDIO_SoftwareReset(SDIO_RSTCMD);	//软件复位DAT,主要用来清除状态以及命令
	SDIO_ReadMode();					//设置主机控制器为读模式
	SDIO_SetTransferBlockSize(SD_BlockSize);	//设置单次传输的块大小为SD_BlockSize
	SDIO_SingleBlockMode();				//设置为单块传输模式
	
	//发送CMD17 READ_SINGLE_BLOCK,块读取指令,参数:块地址,短回复,R1
	//此处花了我几天的时间调试,最终发现竟然是少了一条命令:SDIO_DataSelect;当前数据选择,少了这条命令DAT线上没有数据回来
	SDIO_SendCommand(SDIO_READ_SINGLE_BLOCK,(BlockAddr << 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();	//获取回复
	if (errorstatus != SD_OK)		//命令发送错误,返回
	{
		DEBUG("CMD17 error (%d)!\n",errorstatus);
		return(errorstatus);
	}
	
	while(((SDIO0->PRNSTS & BIT11) == 0) && timeout && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0))	//等待读缓冲区有效,或者等待超时
	{
		timeout --;
	}

	if (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) || (timeout == 0))	//超时
    {
		SDIO_ClearFlag(SDIO_FLAG_DATATIMEOUT);	//清除标志
 		errorstatus = SD_DATA_TIMEOUT;
 		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
    }
	
	//缓冲区大小SD_BlockSize字节,共SD_BlockSize/4字
	for(cnt = 0;cnt < SD_BlockSize / 4;cnt ++)
  	{
  		*(BlockBuff ++) = SDIO_ReadData();
	}
    //清除所有标志
    SDIO_ClearFlag(SDIO_FLAG_ALL);
 
	return(errorstatus);
}



/*************************************************************************************************************************
* 函数	:	SD_Error SD_ReadMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u32 NumberOfBlocks)
* 功能	:	读SD卡多个块
* 参数	:	BlockAddr:块地址;
			BlockBuff:块缓冲区地址
			NumberOfBlocks:块数量
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120728
* 说明	: 	读SD卡多个(大于1个)扇区
*************************************************************************************************************************/
SD_Error SD_ReadMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
{
	SD_Error errorstatus = SD_OK;
	u32 timeout = SDIO_READTIMEOUT;//读等待超时计数器
	u16 BlockCnt = NumberOfBlocks;	//需要传输的块计数
	u16 cnt = 0;

	if (BlockBuff == NULL)	//没有分配接收缓冲区,返回
	{
		errorstatus = SD_INVALID_PARAMETER;
		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
	}

	if (NumberOfBlocks > 1)	
	{
		if (NumberOfBlocks * SD_BlockSize > SD_MAX_DATA_LENGTH)//判定地址是否超出范围
		{
			errorstatus = SD_INVALID_PARAMETER;
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		SDIO_SoftwareReset(SDIO_RSTDAT);			//软件复位DAT,主要用来清空FIFO
		SDIO_SoftwareReset(SDIO_RSTCMD);	//软件复位DAT,主要用来清除状态以及命令
		SDIO_MultipleBlockMode();					//设置为多区段传输模式
		SDIO_SetTransferBlockCnt(NumberOfBlocks);	//设置传输块数量
		SDIO_SetTransferBlockSize(SD_BlockSize);	//设置单次传输的块大小为SD_BlockSize
		SDIO_ReadMode();							//设置为读数据模式
		SDIO_BlockCountEnable();					//块计数启动

	    //发送CMD18 SDIO_READ_MULT_BLOCK;多区段读命令,参数:开始地址,短返回,R1
	    SDIO_SendCommand(SDIO_READ_MULT_BLOCK,(BlockAddr << 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	    errorstatus = CmdResp1Error();
	    if (errorstatus != SD_OK)
	    {
	    	DEBUG("%d\r\n",errorstatus);
	    	return(errorstatus);
	    }
	    
	    do
	    {
	    	if(SDIO0->PRNSTS & BIT11)	//读缓冲区有效
	    	{
	    		SDIO_ClearFlag(SDIO_FLAG_BUFFREAD);		//清除读缓冲区有效标志
	    		//缓冲区大小SD_BlockSize字节,共SD_BlockSize/4字
	    		for(cnt = 0;cnt < SD_BlockSize / 4;cnt ++)
			  	{
			  		*(BlockBuff ++) = SDIO_ReadData();
				}
			  	BlockCnt --;	//读完了一块
			  	timeout = SDIO_READTIMEOUT;	//读完了一块,超时计数器重新开始计数
	    	}
	    	timeout --;
	    }while(BlockCnt && (timeout != 0) && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0));	//剩余块数量不为0,没超时
		
		//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1
		SDIO_SendCommand(SDIO_STOP_TRANSMISSION,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp1Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		if(timeout == 0)	//超时
		{
			errorstatus = SD_DATA_TIMEOUT;
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		SDIO_ClearFlag(SDIO_FLAG_ALL);	//清除所有中断标志
		
	}
	return(errorstatus);
}





/*************************************************************************************************************************
* 函数	:	SD_Error SD_WriteBlock(u32 BlockAddr, u32 *BlockBuff)
* 功能	:	写SD卡一个块
* 参数	:	BlockAddr:块地址;
			writebuff:写缓冲区地址
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120525
* 最后修改时间 : 20120728
* 说明	: 	写SD卡一个扇区
* 			20120728:修改了写入函数,现在可以成功写入数据
*************************************************************************************************************************/
SD_Error SD_WriteBlock(u32 BlockAddr, u32 *BlockBuff)
{
	SD_Error errorstatus = SD_OK;
	u32 timeout = SDIO_WRITETIMEOUT;		//写等待超时计数器
	u32 cardstatus = 0;
	u8 cardstate = 0;
	u16 cnt = 0;

	if (BlockBuff == NULL)
	{
		errorstatus = SD_INVALID_PARAMETER;
		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
	}

	SDIO_SoftwareReset(SDIO_RSTDAT);	//软件复位DAT,主要用来清空FIFO
	SDIO_SoftwareReset(SDIO_RSTCMD);	//软件复位DAT,主要用来清除状态以及命令
	SDIO_WriteMode();					//设置主机控制器为写模式
	SDIO_SetTransferBlockSize(SD_BlockSize);	//设置单次传输的块大小为SD_BlockSize
	SDIO_SingleBlockMode();				//设置为单块传输模式
	
	do
	{
		timeout --;
		//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;
		SDIO_SendCommand(SDIO_SEND_STATUS,(u32) RCA << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp1Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		cardstatus = SDIO_GetResponse(SDIO_RESP1);
	}
	while (((cardstatus & 0x00000100) == 0) && (timeout > 0));
	
	if (timeout == 0)
	{
		DEBUG("%d\r\n",errorstatus);
		return(SD_ERROR);
	}
	
	//发送CMD24,SDIO_WRITE_SINGLE_BLOCK,写命令,参数:地址,短响应,R1
	SDIO_SendCommand(SDIO_WRITE_SINGLE_BLOCK,(BlockAddr << 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();
	if (errorstatus != SD_OK)
	{
		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
	}
	timeout = SDIO_WRITETIMEOUT;		//写等待超时计数器
	//写缓冲区是否有效应该判断PRNSTS这个寄存器
	while(((SDIO0->PRNSTS & BIT10) == 0) && (SDIO_GetFlagStatus(SDIO_FLAG_BUFFWRITE) == 0) && timeout && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0))	//等待写缓冲区有效,或者等待超时
	{
		timeout --;
	}

	if (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) || (timeout == 0))	//超时
    {
		SDIO_ClearFlag(SDIO_FLAG_DATATIMEOUT);	//清除标志
 		errorstatus = SD_DATA_TIMEOUT;
 		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
    }
	
	//缓冲区大小SD_BlockSize字节,共SD_BlockSize / 4字
	for(cnt = 0;cnt < SD_BlockSize / 4;cnt ++)
  	{
  		SDIO_WriteData(BlockBuff[cnt]);
	}
    //清除所有标志
    SDIO_ClearFlag(SDIO_FLAG_ALL);

    //读取卡状态,等待写入完成
	do
	{
		errorstatus = IsCardProgramming(&cardstate);
	}while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));
	
	return(errorstatus);
}





/*************************************************************************************************************************
* 函数	:	SD_Error SD_WriteMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
* 功能	:	写SD卡多个块
* 参数	:	BlockAddr:块地址;
			BlockBuff:块缓冲区地址
			NumberOfBlocks:块数量
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120525
* 最后修改时间 : 20120728
* 说明	: 	写SD卡多个(大于1个)扇区
* 			20120728:修改了写入函数,现在可以成功写入数据
*************************************************************************************************************************/
SD_Error SD_WriteMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
{
	SD_Error errorstatus = SD_OK;
	u32 timeout = SDIO_WRITETIMEOUT;		//写等待超时计数器
	u16 BlockCnt = NumberOfBlocks;	//传输的块数量计数
	u8 cardstate = 0;
	u32 cardstatus = 0;
	u16 cnt = 0;

	if (BlockBuff == NULL)
	{
		errorstatus = SD_INVALID_PARAMETER;
		DEBUG("%d\r\n",errorstatus);
		return(errorstatus);
	}
 
	if (NumberOfBlocks > 1)
	{
		if (NumberOfBlocks * SD_BlockSize > SD_MAX_DATA_LENGTH)	//判断地址
		{
			errorstatus = SD_INVALID_PARAMETER;
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		SDIO_SoftwareReset(SDIO_RSTDAT);			//软件复位DAT,主要用来清空FIFO
		SDIO_SoftwareReset(SDIO_RSTCMD);	//软件复位DAT,主要用来清除状态以及命令
		SDIO_MultipleBlockMode();					//设置为多区段传输模式
		SDIO_SetTransferBlockCnt(NumberOfBlocks);	//设置传输块数量
		SDIO_SetTransferBlockSize(SD_BlockSize);	//设置单次传输的块大小为SD_BlockSize
		SDIO_WriteMode();							//设置为写数据模式
		SDIO_BlockCountEnable();					//块计数启动
		
		do
		{
			timeout --;
			//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;
			SDIO_SendCommand(SDIO_SEND_STATUS,(u32) RCA << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
			errorstatus = CmdResp1Error();
			if (errorstatus != SD_OK)
			{
				DEBUG("%d\r\n",errorstatus);
				return(errorstatus);
			}
			cardstatus = SDIO_GetResponse(SDIO_RESP1);
		}
		while (((cardstatus & 0x00000100) == 0) && (timeout > 0));
		
		if (timeout == 0)
		{
			DEBUG("%d\r\n",errorstatus);
			return(SD_ERROR);
		}
		
		timeout = SDIO_WRITETIMEOUT;
    	//发送CMD25,SDIO_WRITE_MULT_BLOCK,参数:字节地址,短返回,R1
	    SDIO_SendCommand(SDIO_WRITE_MULT_BLOCK,(BlockAddr << 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	    errorstatus = CmdResp1Error();
	    if (errorstatus != SD_OK)
	    {
	    	DEBUG("%d\r\n",errorstatus);
	    	return(errorstatus);
	    }
	    
	    do
	    {
	    	if(SDIO0->PRNSTS & BIT10)	//写缓冲区有效
	    	{
	    		SDIO_ClearFlag(SDIO_FLAG_BUFFWRITE);		//清除写缓冲区有效标志
	    		//缓冲区大小SD_BlockSize字节,共SD_BlockSize / 4字
			  	for(cnt = 0;cnt < SD_BlockSize / 4;cnt ++)
			  	{
			  		SDIO_WriteData(*BlockBuff ++);
				}
			  	BlockCnt --;	//读完了一块
			  	timeout = SDIO_READTIMEOUT;	//读完了一块,超时计数器重新开始计数
	    	}
	    	timeout --;
	    }while(BlockCnt && (timeout != 0) && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0));	//剩余块数量不为0,没超时
	    
		//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1
		SDIO_SendCommand(SDIO_STOP_TRANSMISSION,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
		errorstatus = CmdResp1Error();
		if (errorstatus != SD_OK)
		{
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		if(timeout == 0)	//超时
		{
			errorstatus = SD_DATA_TIMEOUT;
			DEBUG("%d\r\n",errorstatus);
			return(errorstatus);
		}
		
		SDIO_ClearFlag(SDIO_FLAG_ALL);	//清除所有中断标志
	}
	
	//读取卡状态,等待写入完成
	do
	{
		errorstatus = IsCardProgramming(&cardstate);
	}while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));
	
	return(errorstatus);
}





/*************************************************************************************************************************
* 函数	:	static SD_Error CmdError(void)
* 功能	:	指令执行状态(无响应)
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdError(void)
{
  SD_Error errorstatus = SD_OK;
  u32 timeout;

  timeout = SDIO_CMD0TIMEOUT;

  while ((timeout > 0) && (SDIO_GetFlagStatus(SDIO_FLAG_COMMANDEND) == 0))
  {
    timeout--;
  }

  if (timeout == 0)
  {
    errorstatus = SD_CMD_RSP_TIMEOUT;
    return(errorstatus);
  }

  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);

  return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	static SD_Error CmdResp7Error(void)
* 功能	:	指令执行状态(R7)
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp7Error(void)
{
  SD_Error errorstatus = SD_OK;
 // u32 status;
  u32 timeout = SDIO_CMD0TIMEOUT;

  do
  {
		timeout--;
  }
	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT)) && (timeout > 0));
	
  if ((timeout == 0) || (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT))
  {
    /* Card is not V2.0 complient or card does not support the set voltage range */
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
    return(errorstatus);
  }

  if (SDIO_STATUS & SDIO_FLAG_COMMANDEND)
  {
    /* Card is SD V2.0 compliant */
    errorstatus = SD_OK;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDEND);
    return(errorstatus);
  }
  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);
  
  return(errorstatus);

}


/*************************************************************************************************************************
* 函数	:	static SD_Error CmdResp1Error(void)
* 功能	:	指令执行状态(R1)
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp1Error(void)
{
  SD_Error errorstatus = SD_OK;
  u32 response_r1;
  
	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_COMMANDINDEX)));
	if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
	{
	    errorstatus = SD_CMD_RSP_TIMEOUT;
	    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
	    return(errorstatus);
	}
	else if (SDIO_STATUS & SDIO_FLAG_COMMANDCRC)
 	{
	    errorstatus = SD_CMD_CRC_FAIL;
	    SDIO_ClearFlag(SDIO_FLAG_COMMANDCRC);
	    return(errorstatus);
  	}
	else if (SDIO_STATUS & SDIO_FLAG_COMMANDINDEX)
	{
	    errorstatus = SD_ILLEGAL_CMD;
	    SDIO_ClearFlag(SDIO_FLAG_COMMANDINDEX);
	    return(errorstatus);
	}

  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);

  /* We have received response, retrieve it for analysis  */
  response_r1 = SDIO_GetResponse(SDIO_RESP1);
  if ((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
  {
    return(errorstatus);
  }

  if (response_r1 & SD_OCR_ADDR_OUT_OF_RANGE)
  {
    return(SD_ADDR_OUT_OF_RANGE);
  }

  if (response_r1 & SD_OCR_ADDR_MISALIGNED)
  {
    return(SD_ADDR_MISALIGNED);
  }

  if (response_r1 & SD_OCR_BLOCK_LEN_ERR)
  {
    return(SD_BLOCK_LEN_ERR);
  }

  if (response_r1 & SD_OCR_ERASE_SEQ_ERR)
  {
    return(SD_ERASE_SEQ_ERR);
  }

  if (response_r1 & SD_OCR_BAD_ERASE_PARAM)
  {
    return(SD_BAD_ERASE_PARAM);
  }

  if (response_r1 & SD_OCR_WRITE_PROT_VIOLATION)
  {
    return(SD_WRITE_PROT_VIOLATION);
  }

  if (response_r1 & SD_OCR_LOCK_UNLOCK_FAILED)
  {
    return(SD_LOCK_UNLOCK_FAILED);
  }

  if (response_r1 & SD_OCR_COM_CRC_FAILED)
  {
    return(SD_COM_CRC_FAILED);
  }

  if (response_r1 & SD_OCR_ILLEGAL_CMD)
  {
    return(SD_ILLEGAL_CMD);
  }

  if (response_r1 & SD_OCR_CARD_ECC_FAILED)
  {
    return(SD_CARD_ECC_FAILED);
  }

  if (response_r1 & SD_OCR_CC_ERROR)
  {
    return(SD_CC_ERROR);
  }

  if (response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR)
  {
    return(SD_GENERAL_UNKNOWN_ERROR);
  }

  if (response_r1 & SD_OCR_STREAM_READ_UNDERRUN)
  {
    return(SD_STREAM_READ_UNDERRUN);
  }

  if (response_r1 & SD_OCR_STREAM_WRITE_OVERRUN)
  {
    return(SD_STREAM_WRITE_OVERRUN);
  }

  if (response_r1 & SD_OCR_CID_CSD_OVERWRIETE)
  {
    return(SD_CID_CSD_OVERWRITE);
  }

  if (response_r1 & SD_OCR_WP_ERASE_SKIP)
  {
    return(SD_WP_ERASE_SKIP);
  }

  if (response_r1 & SD_OCR_CARD_ECC_DISABLED)
  {
    return(SD_CARD_ECC_DISABLED);
  }

  if (response_r1 & SD_OCR_ERASE_RESET)
  {
    return(SD_ERASE_RESET);
  }

  if (response_r1 & SD_OCR_AKE_SEQ_ERROR)
  {
    return(SD_AKE_SEQ_ERROR);
  }
  return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	static SD_Error CmdResp3Error(void)
* 功能	:	指令执行状态(R3,OCR)
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp3Error(void)
{
  SD_Error errorstatus = SD_OK;
//  u32 status;

	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT)));
  if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
  {
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
    return(errorstatus);
  }
  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);
  
  return(errorstatus);
}



/*************************************************************************************************************************
* 函数	:	static SD_Error CmdResp2Error(void)
* 功能	:	指令执行状态(R2,CID or CSD)
* 参数	:	无
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp2Error(void)
{
  SD_Error errorstatus = SD_OK;
//  u32 status;

	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT)));

  if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
  {
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
    return(errorstatus);
  }
  else if (SDIO_STATUS & SDIO_FLAG_COMMANDCRC)
  {
    errorstatus = SD_CMD_CRC_FAIL;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDCRC);
    return(errorstatus);
  }

  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);

  return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	static SD_Error CmdResp6Error(u16 *prca)
* 功能	:	指令执行状态(R6,RCA)
* 参数	:	prca:RCA缓冲区指针
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp6Error(u16 *prca)
{
  SD_Error errorstatus = SD_OK;
 // u32 status;
  u32 response_r1;
  
  	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_COMMANDINDEX)));
  if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
  {
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
    return(errorstatus);
  }
  else if (SDIO_STATUS & SDIO_FLAG_COMMANDCRC)
  {
    errorstatus = SD_CMD_CRC_FAIL;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDCRC);
    return(errorstatus);
  }
  else if (SDIO_STATUS & SDIO_FLAG_COMMANDINDEX)
  {
    errorstatus = SD_ILLEGAL_CMD;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDINDEX);
    return(errorstatus);
  }
  
  //清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);

  /* We have received response, retrieve it.  */
  response_r1 = SDIO_GetResponse(SDIO_RESP1);

  if (SD_ALLZERO == (response_r1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
  {
    *prca = (u16) (response_r1 >> 16);
    return(errorstatus);
  }

  if (response_r1 & SD_R6_GENERAL_UNKNOWN_ERROR)
  {
    return(SD_GENERAL_UNKNOWN_ERROR);
  }

  if (response_r1 & SD_R6_ILLEGAL_CMD)
  {
    return(SD_ILLEGAL_CMD);
  }

  if (response_r1 & SD_R6_COM_CRC_FAILED)
  {
    return(SD_COM_CRC_FAILED);
  }

  return(errorstatus);
}


/*************************************************************************************************************************
* 函数	:	static SD_Error FindSCR(u16 rca, u32 *pscr)
* 功能	:	获取SCR信息
* 参数	:	rca:卡地址,prca:RCA缓冲区指针
* 返回	:	SD_OK:成功,其它见SD Card Error code.
* 依赖	:	底层寄存器操作函数
* 作者	:	陈鹏
* 时间	:	20120516
* 最后修改时间 : 20120516
* 说明	: 	返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error FindSCR(u16 rca, u32 *pscr)
{
	SD_Error errorstatus = SD_OK;
	u32 tempscr[2] = {0, 0};
	u32 timeout = SDIO_READTIMEOUT;//读等待超时计数器

	//设置块大小为8字节
	//发送SDIO_SET_BLOCKLEN,参数8,短响应
	SDIO_SendCommand(SDIO_SET_BLOCKLEN,8,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();

	if (errorstatus != SD_OK)
	{
		DEBUG("SDIO_SET_BLOCKLEN error(%d)!\n",errorstatus);	//调试,打印错误信息
		goto _error;
	}
	
	//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应
  	SDIO_SendCommand(SDIO_APP_CMD,(u32)rca << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();
	if (errorstatus != SD_OK)
	{
		DEBUG("CMD55 error(%d)!\n",errorstatus);	//调试,打印错误信息
		goto _error;
	}
	
	SDIO_SoftwareReset(SDIO_RSTDAT);	//软件复位DAT,主要用来清空FIFO
	SDIO_ReadMode();					//设置主机控制器为读模式
	SDIO_SetTransferBlockSize(8);		//设置单次传输的块大小为8b
	SDIO_SingleBlockMode();				//设置为单块传输模式

	//发送ACMD51 SD_APP_SEND_SCR,参数0,短响应,R1
	SDIO_SendCommand(SDIO_SD_APP_SEND_SCR,0,SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	errorstatus = CmdResp1Error();
	if (errorstatus != SD_OK)
	{
		DEBUG("ACMD51 error(%d)!\n",errorstatus);	//调试,打印错误信息
		goto _error;
	}
	
	while((SDIO_GetFlagStatus(SDIO_FLAG_BUFFREAD) == 0) && timeout && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0))	//等待读缓冲区有效,或者等待超时
	{
		timeout --;
	}
	
	if (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) || (timeout == 0))	//超时
    {
		SDIO_ClearFlag(SDIO_FLAG_DATATIMEOUT);	//清除标志
 		errorstatus = SD_DATA_TIMEOUT;
		goto _error;
    }
	
	//缓冲区大小8字节,共2字
	tempscr[0] = SDIO_ReadData();
	tempscr[1] = SDIO_ReadData();


	//清除所有标志
	SDIO_ClearFlag(SDIO_FLAG_ALL);

	*(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);

_error:
	//恢复块大小为 SD_BlockSize
	SDIO_SetTransferBlockSize(SD_BlockSize);//设置传输块大小为512字节
	errorstatus = SD_SetBlockSize(SD_BlockSize);//配置SD卡块大小	
	if (errorstatus != SD_OK)
	{
		DEBUG("SD SetBlockSize error(%d)!\n",errorstatus);
		return(errorstatus);
	}
	
	return(errorstatus);
}





/*******************************************************************************
* Function Name  : IsCardProgramming
* Description    : Checks if the SD card is in programming state.
* Input          : pstatus: pointer to the variable that will contain the SD
*                  card state.
* Output         : None
* Return         : SD_Error: SD Card Error code.
*******************************************************************************/
static SD_Error IsCardProgramming(u8 *pstatus)
{
  SD_Error errorstatus = SD_OK;
  vu32 respR1 = 0, status = 0;


  //发送SDIO_SEND_STATUS,返回状态
  SDIO_SendCommand(SDIO_SEND_STATUS,(u32) RCA << 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
	
	while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_COMMANDINDEX)));
  if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
  {
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
    return(errorstatus);
  }
  else if (SDIO_STATUS & SDIO_FLAG_COMMANDCRC)
  {
    errorstatus = SD_CMD_CRC_FAIL;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDCRC);
    return(errorstatus);
  }
  else if (SDIO_STATUS & SDIO_FLAG_COMMANDINDEX)
  {
    errorstatus = SD_ILLEGAL_CMD;
    SDIO_ClearFlag(SDIO_FLAG_COMMANDINDEX);
    return(errorstatus);
  }

	//清除所有标志
  SDIO_ClearFlag(SDIO_FLAG_ALL);


  /* We have received response, retrieve it for analysis  */
  respR1 = SDIO_GetResponse(SDIO_RESP1);

  /* Find out card status */
  *pstatus = (u8) ((respR1 >> 9) & 0x0000000F);

  if ((respR1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
  {
    return(errorstatus);
  }

  if (respR1 & SD_OCR_ADDR_OUT_OF_RANGE)
  {
    return(SD_ADDR_OUT_OF_RANGE);
  }

  if (respR1 & SD_OCR_ADDR_MISALIGNED)
  {
    return(SD_ADDR_MISALIGNED);
  }

  if (respR1 & SD_OCR_BLOCK_LEN_ERR)
  {
    return(SD_BLOCK_LEN_ERR);
  }

  if (respR1 & SD_OCR_ERASE_SEQ_ERR)
  {
    return(SD_ERASE_SEQ_ERR);
  }

  if (respR1 & SD_OCR_BAD_ERASE_PARAM)
  {
    return(SD_BAD_ERASE_PARAM);
  }

  if (respR1 & SD_OCR_WRITE_PROT_VIOLATION)
  {
    return(SD_WRITE_PROT_VIOLATION);
  }

  if (respR1 & SD_OCR_LOCK_UNLOCK_FAILED)
  {
    return(SD_LOCK_UNLOCK_FAILED);
  }

  if (respR1 & SD_OCR_COM_CRC_FAILED)
  {
    return(SD_COM_CRC_FAILED);
  }

  if (respR1 & SD_OCR_ILLEGAL_CMD)
  {
    return(SD_ILLEGAL_CMD);
  }

  if (respR1 & SD_OCR_CARD_ECC_FAILED)
  {
    return(SD_CARD_ECC_FAILED);
  }

  if (respR1 & SD_OCR_CC_ERROR)
  {
    return(SD_CC_ERROR);
  }

  if (respR1 & SD_OCR_GENERAL_UNKNOWN_ERROR)
  {
    return(SD_GENERAL_UNKNOWN_ERROR);
  }

  if (respR1 & SD_OCR_STREAM_READ_UNDERRUN)
  {
    return(SD_STREAM_READ_UNDERRUN);
  }

  if (respR1 & SD_OCR_STREAM_WRITE_OVERRUN)
  {
    return(SD_STREAM_WRITE_OVERRUN);
  }

  if (respR1 & SD_OCR_CID_CSD_OVERWRIETE)
  {
    return(SD_CID_CSD_OVERWRITE);
  }

  if (respR1 & SD_OCR_WP_ERASE_SKIP)
  {
    return(SD_WP_ERASE_SKIP);
  }

  if (respR1 & SD_OCR_CARD_ECC_DISABLED)
  {
    return(SD_CARD_ECC_DISABLED);
  }

  if (respR1 & SD_OCR_ERASE_RESET)
  {
    return(SD_ERASE_RESET);
  }

  if (respR1 & SD_OCR_AKE_SEQ_ERROR)
  {
    return(SD_AKE_SEQ_ERROR);
  }

  return(errorstatus);
}



//SD卡中断服务程序,用来检测卡的插入与移除的
static void __irq Isr_SDMMC_Card(void)
{
	if(SDIO_GetFlagStatus(SDIO_FLAG_CARDREMOVAL))	//卡移除了
	{
	//	DEBUG("SDMMC Card MOVAL!\n");			//调试,打印错误信息
		SDIO_ClearFlag(SDIO_FLAG_CARDREMOVAL);		//清除卡移除中断
		SDMMC0_MOV_Flag = 1;	//卡移除了
	}
	if(SDIO_GetFlagStatus(SDIO_FLAG_CARDINSERTION))	//卡插入了
	{
	//	DEBUG("SDMMC Card IN!\n");			//调试,打印错误信息
		SDIO_ClearFlag(SDIO_FLAG_CARDINSERTION);	//清除卡插入中断
	}
	VICInterruptEnd();	//中断结束
}









</pre>sdcard_sdio.h<pre name="code" class="cpp">#ifndef _SDCARD_SDIO_H_
#define _SDCARD_SDIO_H_

#include "s3c6410_system.h"

extern u8 SDMMC0_MOV_Flag;	//卡移除信号

/* Exported types ------------------------------------------------------------*/
typedef enum
{
  /* SDIO specific error defines */
  SD_CMD_CRC_FAIL                    = (1), /* Command response received (but CRC check failed) */
  SD_DATA_CRC_FAIL                   = (2), /* Data bock sent/received (CRC check Failed) */
  SD_CMD_RSP_TIMEOUT                 = (3), /* Command response timeout */
  SD_DATA_TIMEOUT                    = (4), /* Data time out */
  SD_TX_UNDERRUN                     = (5), /* Transmit FIFO under-run */
  SD_RX_OVERRUN                      = (6), /* Receive FIFO over-run */
  SD_START_BIT_ERR                   = (7), /* Start bit not detected on all data signals in widE bus mode */
  SD_CMD_OUT_OF_RANGE                = (8), /* CMD's argument was out of range.*/
  SD_ADDR_MISALIGNED                 = (9), /* Misaligned address */
  SD_BLOCK_LEN_ERR                   = (10), /* Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
  SD_ERASE_SEQ_ERR                   = (11), /* An error in the sequence of erase command occurs.*/
  SD_BAD_ERASE_PARAM                 = (12), /* An Invalid selection for erase groups */
  SD_WRITE_PROT_VIOLATION            = (13), /* Attempt to program a write protect block */
  SD_LOCK_UNLOCK_FAILED              = (14), /* Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
  SD_COM_CRC_FAILED                  = (15), /* CRC check of the previous command failed */
  SD_ILLEGAL_CMD                     = (16), /* Command is not legal for the card state */
  SD_CARD_ECC_FAILED                 = (17), /* Card internal ECC was applied but failed to correct the data */
  SD_CC_ERROR                        = (18), /* Internal card controller error */
  SD_GENERAL_UNKNOWN_ERROR           = (19), /* General or Unknown error */
  SD_STREAM_READ_UNDERRUN            = (20), /* The card could not sustain data transfer in stream read operation. */
  SD_STREAM_WRITE_OVERRUN            = (21), /* The card could not sustain data programming in stream mode */
  SD_CID_CSD_OVERWRITE               = (22), /* CID/CSD overwrite error */
  SD_WP_ERASE_SKIP                   = (23), /* only partial address space was erased */
  SD_CARD_ECC_DISABLED               = (24), /* Command has been executed without using internal ECC */
  SD_ERASE_RESET                     = (25), /* Erase sequence was cleared before executing because an out of erase sequence command was received */
  SD_AKE_SEQ_ERROR                   = (26), /* Error in sequence of authentication. */
  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),

  /* Standard error defines */
  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,  
} SD_Error;

/* SDIO Commands  Index */
#define SDIO_GO_IDLE_STATE                       ((u8)0)
#define SDIO_SEND_OP_COND                        ((u8)1)
#define SDIO_ALL_SEND_CID                        ((u8)2)
#define SDIO_SET_REL_ADDR                        ((u8)3) /* SDIO_SEND_REL_ADDR for SD Card */
#define SDIO_SET_DSR                             ((u8)4)
#define SDIO_SDIO_SEN_OP_COND                    ((u8)5)
#define SDIO_HS_SWITCH                           ((u8)6)
#define SDIO_SEL_DESEL_CARD                      ((u8)7)
#define SDIO_HS_SEND_EXT_CSD                     ((u8)8)
#define SDIO_SEND_CSD                            ((u8)9)
#define SDIO_SEND_CID                            ((u8)10)
#define SDIO_READ_DAT_UNTIL_STOP                 ((u8)11) /* SD Card doesn't support it */
#define SDIO_STOP_TRANSMISSION                   ((u8)12)
#define SDIO_SEND_STATUS                         ((u8)13)
#define SDIO_HS_BUSTEST_READ                     ((u8)14)
#define SDIO_GO_INACTIVE_STATE                   ((u8)15)
#define SDIO_SET_BLOCKLEN                        ((u8)16)
#define SDIO_READ_SINGLE_BLOCK                   ((u8)17)
#define SDIO_READ_MULT_BLOCK                     ((u8)18)
#define SDIO_HS_BUSTEST_WRITE                    ((u8)19)
#define SDIO_WRITE_DAT_UNTIL_STOP                ((u8)20) /* SD Card doesn't support it */
#define SDIO_SET_BLOCK_COUNT                     ((u8)23) /* SD Card doesn't support it */
#define SDIO_WRITE_SINGLE_BLOCK                  ((u8)24)
#define SDIO_WRITE_MULT_BLOCK                    ((u8)25)
#define SDIO_PROG_CID                            ((u8)26) /* reserved for manufacturers */
#define SDIO_PROG_CSD                            ((u8)27)
#define SDIO_SET_WRITE_PROT                      ((u8)28)
#define SDIO_CLR_WRITE_PROT                      ((u8)29)
#define SDIO_SEND_WRITE_PROT                     ((u8)30)
#define SDIO_SD_ERASE_GRP_START                  ((u8)32) /* To set the address of the first write
                                                             block to be erased. (For SD card only) */
#define SDIO_SD_ERASE_GRP_END                    ((u8)33) /* To set the address of the last write block of the
                                                             continuous range to be erased. (For SD card only) */
#define SDIO_ERASE_GRP_START                     ((u8)35) /* To set the address of the first write block to be erased.
                                                             (For MMC card only spec 3.31) */

#define SDIO_ERASE_GRP_END                       ((u8)36) /* To set the address of the last write block of the
                                                             continuous range to be erased. (For MMC card only spec 3.31) */

#define SDIO_ERASE                               ((u8)38)
#define SDIO_FAST_IO                             ((u8)39) /* SD Card doesn't support it */
#define SDIO_GO_IRQ_STATE                        ((u8)40) /* SD Card doesn't support it */
#define SDIO_LOCK_UNLOCK                         ((u8)42)
#define SDIO_APP_CMD                             ((u8)55)
#define SDIO_GEN_CMD                             ((u8)56)
#define SDIO_NO_CMD                              ((u8)64)

/* Following commands are SD Card Specific commands.
   SDIO_APP_CMD should be sent before sending these
   commands. */
#define SDIO_APP_SD_SET_BUSWIDTH                 ((u8)6)  /* For SD Card only */
#define SDIO_SD_APP_STAUS                        ((u8)13) /* For SD Card only */
#define SDIO_SD_APP_SEND_NUM_WRITE_BLOCKS        ((u8)22) /* For SD Card only */
#define SDIO_SD_APP_OP_COND                      ((u8)41) /* For SD Card only */
#define SDIO_SD_APP_SET_CLR_CARD_DETECT          ((u8)42) /* For SD Card only */
#define SDIO_SD_APP_SEND_SCR                     ((u8)51) /* For SD Card only */
#define SDIO_SDIO_RW_DIRECT                      ((u8)52) /* For SD I/O Card only */
#define SDIO_SDIO_RW_EXTENDED                    ((u8)53) /* For SD I/O Card only */

/* Following commands are SD Card Specific security commands.
   SDIO_APP_CMD should be sent before sending these commands. */
#define SDIO_SD_APP_GET_MKB                      ((u8)43) /* For SD Card only */
#define SDIO_SD_APP_GET_MID                      ((u8)44) /* For SD Card only */
#define SDIO_SD_APP_SET_CER_RN1                  ((u8)45) /* For SD Card only */
#define SDIO_SD_APP_GET_CER_RN2                  ((u8)46) /* For SD Card only */
#define SDIO_SD_APP_SET_CER_RES2                 ((u8)47) /* For SD Card only */
#define SDIO_SD_APP_GET_CER_RES1                 ((u8)48) /* For SD Card only */
#define SDIO_SD_APP_SECURE_READ_MULTIPLE_BLOCK   ((u8)18) /* For SD Card only */
#define SDIO_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK  ((u8)25) /* For SD Card only */
#define SDIO_SD_APP_SECURE_ERASE                 ((u8)38) /* For SD Card only */
#define SDIO_SD_APP_CHANGE_SECURE_AREA           ((u8)49) /* For SD Card only */
#define SDIO_SD_APP_SECURE_WRITE_MKB             ((u8)48) /* For SD Card only */

typedef enum
{
  SD_NO_TRANSFER  = 0,
  SD_TRANSFER_IN_PROGRESS
} SDTransferState;

typedef struct
{
  u16 TransferredBytes;
  SD_Error TransferError;
  u8  padding;
} SDLastTransferInfo;

typedef struct       /* Card Specific Data */
{
  vu8  CSDStruct;            /* CSD structure */
  vu8  SysSpecVersion;       /* System specification version */
  vu8  Reserved1;            /* Reserved */
  vu8  TAAC;                 /* Data read access-time 1 */
  vu8  NSAC;                 /* Data read access-time 2 in CLK cycles */
  vu8  MaxBusClkFrec;        /* Max. bus clock frequency */
  vu16 CardComdClasses;      /* Card command classes */
  vu8  RdBlockLen;           /* Max. read data block length */
  vu8  PartBlockRead;        /* Partial blocks for read allowed */
  vu8  WrBlockMisalign;      /* Write block misalignment */
  vu8  RdBlockMisalign;      /* Read block misalignment */
  vu8  DSRImpl;              /* DSR implemented */
  vu8  Reserved2;            /* Reserved */
  vu16 DeviceSize;           /* Device Size */
  vu8  MaxRdCurrentVDDMin;   /* Max. read current @ VDD min */
  vu8  MaxRdCurrentVDDMax;   /* Max. read current @ VDD max */
  vu8  MaxWrCurrentVDDMin;   /* Max. write current @ VDD min */
  vu8  MaxWrCurrentVDDMax;   /* Max. write current @ VDD max */
  vu8  DeviceSizeMul;        /* Device size multiplier */
  vu8  EraseGrSize;          /* Erase group size */
  vu8  EraseGrMul;           /* Erase group size multiplier */
  vu8  WrProtectGrSize;      /* Write protect group size */
  vu8  WrProtectGrEnable;    /* Write protect group enable */
  vu8  ManDeflECC;           /* Manufacturer default ECC */
  vu8  WrSpeedFact;          /* Write speed factor */
  vu8  MaxWrBlockLen;        /* Max. write data block length */
  vu8  WriteBlockPaPartial;  /* Partial blocks for write allowed */
  vu8  Reserved3;            /* Reserded */
  vu8  ContentProtectAppli;  /* Content protection application */
  vu8  FileFormatGrouop;     /* File format group */
  vu8  CopyFlag;             /* Copy flag (OTP) */
  vu8  PermWrProtect;        /* Permanent write protection */
  vu8  TempWrProtect;        /* Temporary write protection */
  vu8  FileFormat;           /* File Format */
  vu8  ECC;                  /* ECC code */
  vu8  CSD_CRC;              /* CSD CRC */
  vu8  Reserved4;            /* always 1*/
} SD_CSD;

typedef struct      /*Card Identification Data*/
{
  vu8  ManufacturerID;       /* ManufacturerID */
  vu16 OEM_AppliID;          /* OEM/Application ID */
  vu32 ProdName1;            /* Product Name part1 */
  vu8  ProdName2;            /* Product Name part2*/
  vu8  ProdRev;              /* Product Revision */
  vu32 ProdSN;               /* Product Serial Number */
  vu8  Reserved1;            /* Reserved1 */
  vu16 ManufactDate;         /* Manufacturing Date */
  vu8  CID_CRC;              /* CID CRC */
  vu8  Reserved2;            /* always 1 */
} SD_CID;

typedef struct
{
  SD_CSD SD_csd;
  SD_CID SD_cid;
  u8 CardType;
  u16 RCA;
} SD_CardInfo;

/* Exported constants --------------------------------------------------------*/
#define SD_DMA_MODE                     ((u32)0x00000000)
#define SD_INTERRUPT_MODE               ((u32)0x00000001)
#define SD_POLLING_MODE                 ((u32)0x00000002)

/* Supported Memory Cards */
#define SDIO_STD_CAPACITY_SD_CARD_V1_1     ((u32)0x0)	//SD V1.1版
#define SDIO_STD_CAPACITY_SD_CARD_V2_0     ((u32)0x1)	//SD V2.0版
#define SDIO_HIGH_CAPACITY_SD_CARD         ((u32)0x2)	//大容量SD卡
#define SDIO_MULTIMEDIA_CARD               ((u32)0x3)	//MMC卡
#define SDIO_SECURE_DIGITAL_IO_CARD        ((u32)0x4)	//普通SD卡
#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD    ((u32)0x5)	//高速SD卡
#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD  ((u32)0x6)
#define SDIO_HIGH_CAPACITY_MMC_CARD        ((u32)0x7)	//大容量MMC卡







SD_Error SD_Init(void);
SD_Error SD_SetIdleSta(void);
SD_Error SD_PowerOFF(void);
SD_Error SD_PowerON(void);
SD_Error SD_InitializeCards(void);
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo);
SD_Error SD_EnableWideBusOperation(u32 WideMode);
SD_Error SD_SetDeviceMode(u32 Mode);
SD_Error SD_SelectDeselect(u32 addr);
SD_Error SD_SetBlockSize(u16 BlockSize);
SD_Error SD_ReadBlock(u32 addr, u32 *readbuff);
SD_Error SD_ReadMultiBlocks(u32 addr, u32 *readbuff, u16 NumberOfBlocks);
SD_Error SD_SelectDeselect(u32 addr);
SD_Error SD_EnableWideBusMode(u8 EN);	//使能4bit DAT线模式,如果失败将保持原来模式
SD_Error SD_WriteBlock(u32 BlockAddr, u32 *BlockBuff);
SD_Error SD_WriteMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u32 NumberOfBlocks);






#endif





评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cp1300

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值