在读取SD卡的R2长响应折腾了不少时间,原因是必须开启DMA,不开启DMA,R2响应将不会传输到SDIO的FIFO中,将SDIO接口与STM32保持一致,并兼容应用层SDIO_SDCARD驱动。

寄存器地址


//SDIO========================================================================================================
#define SDIO_BUFF_BASE                  (0xB000C000)            //寄存器基址
#define SDIO_DMA_BASE                   (0xB000C000+0x400)      //寄存器基址
#define SDIO_BASE                       (0xB000C000+0x800)      //寄存器基址typedef struct
{vu8 Buff[128];                             //SD主机嵌入式缓冲区
}SDIO_BUFF_TypeDef;typedef struct
{vu32 CTL;                                  //SD主机DMA控制和状态寄存器u32 Reserved1;vu32 SA;                                 //SD主机DMA传输起始地址寄存器vu32 BCNT;                                    //SD主机DMA传输字节计数寄存器vu32 INTEN;                                   //SD主机DMA中断使能寄存器vu32 INTSTS;                                //SD主机DMA中断状态寄存器
}SDIO_DMA_TypeDef;typedef struct
{vu32 GCTL;                                 //SD主机全局控制和状态寄存器vu32 GINTEN;                                //SD主机全局中断控制寄存器vu32 GINTSTS;                                //SD主机全局中断状态寄存器u32 Reserved1[5];vu32 CTL;                                   //SD主机控制和状态寄存器vu32 ARG;                                 //SD主机命令参数寄存器vu32 INTEN;                                    //SD主机中断允许寄存器vu32 INTSTS;                               //SD主机中断状态寄存器vu32 RESP0;                                    //SD主机接收响应令牌寄存器0vu32 RESP1;                                 //SD主机接收响应令牌寄存器1vu32 BLEN;                                  //SD主机块长度寄存器vu32 TMOUT;                                 //SD主机响应/数据输入超时寄存器vu32 ECTL;                                    //SD主机扩展控制寄存器
}SDIO_TypeDef;#define SDIO_BUFF                         ((SDIO_BUFF_TypeDef *) SDIO_BUFF_BASE)
#define SDIO_DMA                        ((SDIO_DMA_TypeDef *) SDIO_DMA_BASE)
#define SDIO                            ((SDIO_TypeDef *) SDIO_BASE)

//SDIO.c

/************************************************************************************************************** 文件名:         sdio.c* 功能:         NUC970 sdio驱动* 作者:          cp1300@139.com* 创建时间:      2020-09-04* 最后修改时间: 2020-09-04* 详细:
*************************************************************************************************************/
#include "nuc970_system.h"
#include "sdio.h"
#include "sdio_const.h"__inline u32 SDIO_GetResp1CardStatu(void);//获取R1响应的卡状态数据#define SDIO_DelayUS(x)        Delay_US(x)
#define SDIO_TIMEOUT_US     (100*1000)      //SDIO软件延时/*************************************************************************************************************************
* 函数            :   bool SDIO_Init(void)
* 功能            :   SDIO接口初始化
* 参数            :   无
* 返回            :   TRUE:初始化成功;FALSE:初始化失败;
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   默认会选择 SD host port 0
*************************************************************************************************************************/
bool SDIO_Init(void)
{//SDIO时钟选择,使用CPU时钟,CPU使用的是UPLL,300MHzu32 tempreg = SYS_REG_TYPE(REG_CLK_DIVCTL9);SYS_DeviceClockEnable(DEV_SDIO, TRUE);  //使能时钟SYS_DeviceReset(DEV_RESET_SDIO);      //复位外设tempreg &= ~(0xFFFF);                    //清除掉之前的设置tempreg |= 3 << 3;                     //时钟源选择UPLL 0x0:XIN;0x2:APLL;0x3:UPLLtempreg |= 2 << 0;                      //PLL时钟分频(2+1),输出100MHztempreg |= SDIO_CLK_400K << 8;          //SDH_N分频系数+1, 390KHzSYS_REG_TYPE(REG_CLK_DIVCTL9) = tempreg;Delay_US(100);SDIO->GCTL = 1;                            //关闭并复位SDIOnop;nop;SDIO->GCTL |= BIT1;                      //使能SDIO-不使能无法设置寄存器nop;nop;//SDIO寄存器设置     SDIO->GINTEN = 0;                        //关闭DMA中断SDIO->GINTSTS = 1;                     //清除DMA错误中断SDIO->CTL = SDIO_CTL_SW_RST;         //数据1bit模式;复位内部状态机;while(SDIO->CTL & SDIO_CTL_SW_RST);SDIO->CTL = (0x09u<<24) | (1<<16);       //设置默认配置SDIO->INTEN = 0;                        //中断全部关闭SDIO_SetDataTransBlockSize(SDIO_DataBlockSize_512B);    //默认块大小:512字节SDIO_SetDataTransTimeOut(0xFFFFFF);     //SDIO传输数据超时设置-设置为非常大,直接由应用程序来决定超时SDIO_SetBusWide(SDIO_BusWide_1b);      //SDIO设置总线宽度SDIO_SetPower(TRUE);                    //SDIO电源控制-使能SDIO_DMA->CTL = BIT1;                  //DMA复位,不启动分散加载功能while(SDIO_DMA->CTL & BIT1);SDIO_DMA->INTEN = 0;                 //关闭DMA中断SDIO_DMA->CTL |= BIT0;                 //使能DMA-2020-09-12折腾几天发现,此处必须开启DMA,否则R2响应的数据无法被接收return TRUE;
}/*************************************************************************************************************************
* 函数            :   bool SDIO_SetOut74Clock(void)
* 功能            :   SDIO输出74个时钟
* 参数            :   无
* 返回            :   TRUE:成功;FALSE:失败
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-12
* 最后修改时间    :   2020-09-12
* 说明            :
*************************************************************************************************************************/
bool SDIO_SetOut74Clock(void)
{u32 timeout = SDIO_TIMEOUT_US;//读等待超时计数器SDIO->CTL |= BIT5;                        //SDIO输出74个时钟,用于初始化SD卡,等待SD卡上电稳定while(SDIO->CTL & BIT5){timeout --;Delay_US(1);}if(timeout == 0){SDIO->CTL |= SDIO_CTL_SW_RST;       //复位SDIO控制器return FALSE;}return TRUE;
}/*************************************************************************************************************************
* 函数            :   void SDIO_SetClockSpeed(SDIO_CLOCK_SPEED ClkSpeed)
* 功能            :   SDIO设置时钟速度
* 参数            :   ClkSpeed:时钟速度,见SDIO_CLOCK_SPEED
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetClockSpeed(SDIO_CLOCK_SPEED ClkSpeed)
{u32 tempreg = SYS_REG_TYPE(REG_CLK_DIVCTL9);tempreg &= ~(0xFF << 8);                   //清除掉之前的设置tempreg |= (ClkSpeed & 0xff) << 8;         //SDH_N分频系数+1SYS_REG_TYPE(REG_CLK_DIVCTL9) = tempreg;Delay_US(10);
} /*************************************************************************************************************************
* 函数            :   u8 SDIO_GetPortSelect(void)
* 功能            :   获取当前选择的port(0-1)
* 参数            :   无
* 返回            :   通道0-1
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
u8 SDIO_GetPortSelect(void)
{if(SDIO->CTL & BIT29) return 1;else return 0;
} /*************************************************************************************************************************
* 函数            :   void SDIO_SetPortSelect(u8 port)
* 功能            :   设置SDIO当前port(0-1)
* 参数            :   通道0-1
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetPortSelect(u8 port)
{if(port) SDIO->CTL |= BIT29;else SDIO->CTL &= ~BIT29;
} /*************************************************************************************************************************
* 函数            :   void SDIO_SetBusWide(SDIO_BUS_WIDE BusWide)
* 功能            :   SDIO设置总线宽度
* 参数            :   BusWide:总线宽度,见SDIO_BUS_WIDE
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetBusWide(SDIO_BUS_WIDE BusWide)
{if(BusWide == SDIO_BusWide_1b){SDIO->CTL &= ~BIT15;      //设置为1bit模式}else{SDIO->CTL |= BIT15;            //设置为4bit模式}
} /*************************************************************************************************************************
* 函数            :   SDIO_BUS_WIDE SDIO_GetBusWide(void)
* 功能            :   获取SDIO设置的总线宽度
* 参数            :   无
* 返回            :   总线宽度,见SDIO_BUS_WIDE
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   可以获取当前端口的总线宽度
*************************************************************************************************************************/
SDIO_BUS_WIDE SDIO_GetBusWide(void)
{if(SDIO->CTL & BIT15) return SDIO_BusWide_4b;else return SDIO_BusWide_1b;
} /*************************************************************************************************************************
*函数        :    void SDIO_SendCommand(u8 CmdIndex,u32 CmdArg,SDIO_WAIT_RESP WaitResp)
*功能        :    SDIO发送一个命令
*参数        :    CmdIdx:指令索引;CmdArg:命令参数;WaitResp:响应类型
*返回        :    无
*依赖        :    底层宏定义
*作者        :    cp1300@139.com
*时间        :    2020-09-04
*最后修改时间:    2020-09-04
*说明        :    响应类型SDIO_Response_No           无应答SDIO_Response_Short        短应答SDIO_Response_Long         长应答此单片机只区分有应答还是无应答
*************************************************************************************************************************/
void SDIO_SendCommand(u8 CmdIndex, u32 CmdArg, SDIO_WAIT_RESP WaitResp)
{   u32 tmpreg;//先确保之前的命令都执行完成了,如果存在超时的,请清除掉while(SDIO->CTL & (BIT5 | BIT6 | 0X1F)){SDIO->CTL |= BIT14;                    //SW_RESETSYS_DelayMS(1);}SDIO->ARG = CmdArg;                       //参数tmpreg = SDIO->CTL; tmpreg &= ~(0X3F << 8);                  //清除命令tmpreg |= (CmdIndex&0X3F) << 8;            //设置新的命令index   if(SDIO_Response_Long == WaitResp)        //长响应R2{tmpreg |= SDIO_CTL_R2IEN_Msk;      //使能R2应答}else if(SDIO_Response_Short == WaitResp) //短响应R1{tmpreg |= SDIO_CTL_RIEN_Msk;       //使能R1应答}tmpreg |= SDIO_CTL_COEN_Msk;          //使能命令发送//清除所有标志SDIO->INTSTS = SDIO->INTSTS;         //清除中断状态SDIO->CTL = tmpreg;                     //写入,执行
}/*************************************************************************************************************************
* 函数            :   void SDIO_SetPower(bool isPowerUp)
* 功能            :   SDIO电源控制
* 参数            :   isPowerUp:TRUE:通电,为卡提供时钟;FALSE:掉电,停止时钟
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetPower(bool isPowerUp)
{if(isPowerUp){SDIO->ECTL |= 1<<(SDIO_GetPortSelect()&0x1);   //通电}else{SDIO->ECTL &= ~(1<<(SDIO_GetPortSelect()&0x1));//掉电}
}/*************************************************************************************************************************
* 函数            :   void SDIO_SetPowerSaving(bool isSaving)
* 功能            :   SDIO节能模式开关
* 参数            :   isSaving:TRUE:仅在总线激活时使能 SDIO_CK;FALSE:始终使能 SDIO_CK 时钟
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   要实现节能模式,可在总线空闲时通过将 CLK_KEEP1 置 0来禁止 SDIO_CK 时钟输出
*************************************************************************************************************************/
void SDIO_SetPowerSaving(bool isSaving)
{if(isSaving){SDIO->CTL &= ~BIT31;  //使能节能模式}else{SDIO->CTL |= BIT31;       //关闭节能模式}
}/*************************************************************************************************************************
* 函数            :   void SDIO_StartDataTrans(bool isRead)
* 功能            :   SDIO开始数据传输
* 参数            :   isRead:是否是读取
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   数据传输必须首先写入到数据计时器寄存器和数据长度寄存器,然后才写入到数据控制寄存器。对于 SDIO 多字节传输,数据长度寄存器中的值必须在 1 到 512 之间。
*************************************************************************************************************************/
void SDIO_StartDataTrans(bool isRead)
{SDIO->INTSTS = SDIO->INTSTS;                        //清除中断状态if(isRead)                                          //读取方向{SDIO->CTL |= BIT2;}else //发送方向{SDIO->CTL |= BIT3;}
}  /*************************************************************************************************************************
* 函数            :   void SDIO_SetAndStartDataTrans(u8 *pDataBuff, bool isEnableReadData, SDIO_DataBlockSize SDIOBlockSize, u32 TransDataLen)
* 功能            :   设置SDIO并开始准备数据传输
* 参数            :   pDataBuff:传输的数据缓冲区;isEnableReadData:是否为读取数据;SDIOBlockSize:SDIO传输块大小;TransDataLen:传输数据长度
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   数据传输必须首先写入到数据计时器寄存器和数据长度寄存器,然后才写入到数据控制寄存器。对于 SDIO 多字节传输,数据长度寄存器中的值必须在 1 到 512 之间。会使能DMA传输
*************************************************************************************************************************/
void SDIO_SetAndStartDataTrans(u8 *pDataBuff, bool isEnableReadData, SDIO_DataBlockSize SDIOBlockSize, u32 TransDataLen)
{//初始化DMASDIO_DMA->SA = (u32)pDataBuff;                                 //设置DMA数据传输地址//SDIO传输数据块大小设置SDIO_SetDataTransBlockSize(SDIOBlockSize);                      //设置传输块大小//SDIO传输数据长度SDIO_SetDataTransLength(TransDataLen);             SDIO->INTSTS = SDIO->INTSTS;                                 //清除中断状态    //数据读取方向if(isEnableReadData)                                            //读数据,卡到控制器{SDIO->CTL |= BIT2;}else                                                          //写数据,控制器到卡{SDIO->CTL |= BIT3;}
}  /*************************************************************************************************************************
* 函数            :   void SDIO_ClearDataTrans(void)
* 功能            :   SDIO清除数据传输
* 参数            :
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   手册上说无需清除DTEN,但是实际使用发现DTEN并不会被清除。
*************************************************************************************************************************/
void SDIO_ClearDataTrans(void)
{u32 timeout = SDIO_TIMEOUT_US;//读等待超时计数器if(SDIO->CTL & (SDIO_CTL_DOEN_Msk | SDIO_CTL_DIEN_Msk))    //之前的数据传输未完成{SDIO->CTL |= SDIO_CTL_SW_RST;                      //SW_RESETwhile(SDIO->CTL & SDIO_CTL_SW_RST){timeout --;Delay_US(1);}if(timeout == 0){DEBUG("复位SDIO命令失败\r\n");}}if((SDIO_DMA->INTSTS & 0x03) || (SDIO_DMA->CTL & BIT9))    //传输出错,或者DMA还在忙{SDIO_DMA->INTSTS = 0x03;    //清除错误timeout = SDIO_TIMEOUT_US;   //读等待超时计数器SDIO_DMA->CTL |= BIT1;        //复位DMA,会清除DMA相关配置寄存器while(SDIO_DMA->CTL & BIT1){timeout --;Delay_US(1);}if(timeout == 0){DEBUG("复位SDIO DMA失败\r\n");}}
}  /*************************************************************************************************************************
* 函数            :   void SDIO_SetDataTransTimeOut(u32 DataIimeOut)
* 功能            :   SDIO传输数据超时设置
* 参数            :   DataIimeOut:数据超时计数,以总线周期为准
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetDataTransTimeOut(u32 DataIimeOut)
{SDIO->TMOUT = DataIimeOut;         //以卡总线时钟周期表示的数据超时周期。
}  /*************************************************************************************************************************
* 函数            :   void SDIO_SetDataTransBlockSize(SDIO_DataBlockSize DataBlockSize)
* 功能            :   SDIO传输数据块大小设置
* 参数            :   DataBlockSize:块大小
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
void SDIO_SetDataTransBlockSize(SDIO_DataBlockSize DataBlockSize)
{SDIO->BLEN = DataBlockSize  & 0X7FF;
}  /*************************************************************************************************************************
* 函数            :   void SDIO_SetDataTransAddr(u32 Addr)
* 功能            :   SDIO要传输的数据地址
* 参数            :   Addr:要传输的数据地址
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-12
* 最后修改时间    :   2020-09-12
* 说明            :
*************************************************************************************************************************/
void SDIO_SetDataTransAddr(u32 Addr)
{SDIO_DMA->SA = Addr;
}/*************************************************************************************************************************
* 函数            :   void SDIO_SetDataTransLength(u32 DataLen)
* 功能            :   SDIO传输数据长度
* 参数            :   DataLen:传输数据长度(必须为块大小的整数倍)
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   对于块数据传输,数据长度寄存器中的值必须是块大小的倍数(请参见 SDIO_DCTRL)。 数据传输必须首先写入到数据计时器寄存器和数据长度寄存器,然后才写入到数据控制寄存器。对于 SDIO 多字节传输,数据长度寄存器中的值必须在 1 到 512 之间。块大小为512字节时,最大传输512*255=130560B,最小512字节。
*************************************************************************************************************************/
void SDIO_SetDataTransLength(u32 DataLen)
{u32 BlockByteSize = (SDIO->BLEN&0x7FF)+1;                                                     //当前设置的块字节大小u32 tempreg;DataLen /= BlockByteSize;                                                                  //转换为要传输的快if(DataLen == 0) {DEBUG("传输大小不足一块,无法开始传输!\r\n");return;                                                                                 //如果传输数量不足一块,则直接退出}else if(DataLen > 255){DEBUG("最多一次传输255个块,超出范围了%d!\r\n", DataLen);DataLen = 255;}tempreg = SDIO->CTL;tempreg &= ~(0xFF<<16);   //清除块设置tempreg |= DataLen << 16;SDIO->CTL = tempreg;
}  /*************************************************************************************************************************
* 函数            :   void SDIO_GetResponse(SDIO_RESP_TYPE RespIndex, u32 *pRespData)
* 功能            :   获取返回响应状态
* 参数            :   RespIndex:见SDIO_RESP_TYPE;pRespData:响应数据缓冲区
* 返回            :   无
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-12
* 说明            :   短响应需要1个字;长响应需要4个字的缓冲区短响应:u32[0]  卡状态 [31:0]长响应:u32[0] 卡状态 [127:96];[1]:卡状态 [95:64];[2]:卡状态 [63:32];[3]:卡状态 [31:1]0bNUC970 的SDH返回的长响应去掉了最低8位,并且最高字节在前面,最前面固定为0x3F(去掉)从第二字节开始,但是最低16bit都是0
*************************************************************************************************************************/
void SDIO_GetResponse(SDIO_RESP_TYPE RespIndex, u32 *pRespData)
{switch(RespIndex){case SDIO_RESP_Short: {pRespData[0] = SDIO_GetResp1CardStatu(); //获取R1响应的卡状态数据;}break;case SDIO_RESP_Long:{u8 i;//只会响应16字节,但是最前面字节是无效的固定为0x3F,也就是缺少一字节有效响应for(i = 0;i < 4;i ++){pRespData[i] = SDIO_BUFF->Buff[1+i*4+0];pRespData[i] <<= 8;pRespData[i] |= SDIO_BUFF->Buff[1+i*4+1];pRespData[i] <<= 8;pRespData[i] |= SDIO_BUFF->Buff[1+i*4+2];pRespData[i] <<= 8;pRespData[i] |= SDIO_BUFF->Buff[1+i*4+3];}pRespData[3] &= 0xFFFFFF00;}break;default:break;}
}   /*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdError(void)
* 功能            :   获取指令执行状态(无响应)
* 参数            :   无
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   无响应,只要命令发送完成了就退出
*************************************************************************************************************************/
SDIO_Error SDIO_CmdError(void)
{SDIO_Error Status = SDIO_OK;u32 timeout=SDIO_TIMEOUT_US;while (timeout){timeout--;if((SDIO->CTL & SDIO_CTL_COEN_Msk) == 0) break;           //命令发送完成了SDIO_DelayUS(1);} if(timeout==0) {SDIO->CTL |= SDIO_CTL_SW_RST;                          //复位SDIO控制器return SDIO_CMD_RSP_TIMEOUT;  }//清除所有标志SDIO->INTSTS = SDIO->INTSTS;return Status;
}    /*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdResp7Error(void)
* 功能            :   获取指令执行状态(R7)
* 参数            :   无
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   R7命令优先处理响应成功,后处理CRC错误
*************************************************************************************************************************/
SDIO_Error SDIO_CmdResp7Error(void)
{SDIO_Error Status = SDIO_OK;u32 timeout=SDIO_TIMEOUT_US;while (timeout){timeout--;if(SDIO->INTSTS &(SDIO_INT_STATUS_RITO | SDIO_INT_STATUS_CRC)) break;//CRC错误/命令响应超时if((SDIO->CTL & SDIO_CTL_RIEN_Msk) == 0) break;                      //收到响应了Delay_US(1);} if(timeout==0)                  //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("程序不应该执行到此处(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}if(SDIO->INTSTS & SDIO_INT_STATUS_RITO)                                   //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//命令响应成功if((SDIO->CTL & SDIO_CTL_RIEN_Msk) == 0){/* Card is SD V2.0 compliant */Status = SDIO_OK;SDIO->INTSTS = SDIO->INTSTS;                                       //清除所有标志return Status;}//SDIO_STA_CCRCFAIL 错误                              Status = SDIO_CMD_CRC_FAIL;//清除所有标志SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志return Status;
}   /*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdResp1Error(void)
* 功能            :   指令执行状态(R1)
* 参数            :   无
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   此命令超时设置为1分钟,必须增加超时,防止程序假死在此处如果响应不包含 CRC(CMD1 响应),则设备驱动程序必须忽略 CRC 失败状态。
*************************************************************************************************************************/
SDIO_Error SDIO_CmdResp1Error(void)
{     SDIO_Error Status = SDIO_OK;u32 timeout=SDIO_TIMEOUT_US/1;  u32 response_r1;while (timeout){timeout--;if(SDIO->INTSTS &(SDIO_INT_STATUS_RITO | SDIO_INT_STATUS_CRC)) break;//CRC错误/命令响应超时if((SDIO->CTL & SDIO_CTL_RIEN_Msk) == 0) break;                         //收到响应了Delay_US(1);} if(timeout==0)                  //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("程序不应该执行到此处(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}if(SDIO->INTSTS & SDIO_INT_STATUS_RITO)   //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//SDIO_STA_CCRCFAIL 错误if(SDIO->INTSTS & SDIO_INT_STATUS_CRC)                                  //命令校验错误{                                  Status = SDIO_CMD_CRC_FAIL;SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//清除所有标志SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志//命令执行成功,获取R1响应结果response_r1 = SDIO_GetResp1CardStatu();                                    //返回的响应if ((response_r1 & SDIO_OCR_ERRORBITS) == 0)                           //没有错误响应{return Status;}if (response_r1 & SDIO_OCR_ADDR_OUT_OF_RANGE){return (SDIO_ADDR_OUT_OF_RANGE);}if (response_r1 & SDIO_OCR_ADDR_MISALIGNED){return (SDIO_ADDR_MISALIGNED);}if (response_r1 & SDIO_OCR_BLOCK_LEN_ERR){return (SDIO_BLOCK_LEN_ERR);}if (response_r1 & SDIO_OCR_ERASE_SEQ_ERR){return (SDIO_ERASE_SEQ_ERR);}if (response_r1 & SDIO_OCR_BAD_ERASE_PARAM){return (SDIO_BAD_ERASE_PARAM);}if (response_r1 & SDIO_OCR_WRITE_PROT_VIOLATION){return (SDIO_WRITE_PROT_VIOLATION);}if (response_r1 & SDIO_OCR_LOCK_UNLOCK_FAILED){return (SDIO_LOCK_UNLOCK_FAILED);}if (response_r1 & SDIO_OCR_COM_CRC_FAILED){return (SDIO_COM_CRC_FAILED);}if (response_r1 & SDIO_OCR_ILLEGAL_CMD){return (SDIO_ILLEGAL_CMD);}if (response_r1 & SDIO_OCR_CARD_ECC_FAILED){return (SDIO_CARD_ECC_FAILED);}if (response_r1 & SDIO_OCR_CC_ERROR){return (SDIO_CC_ERROR);}if (response_r1 & SDIO_OCR_GENERAL_UNKNOWN_ERROR){return (SDIO_GENERAL_UNKNOWN_ERROR);}if (response_r1 & SDIO_OCR_STREAM_READ_UNDERRUN){return (SDIO_STREAM_READ_UNDERRUN);}if (response_r1 & SDIO_OCR_STREAM_WRITE_OVERRUN){return (SDIO_STREAM_WRITE_OVERRUN);}if (response_r1 & SDIO_OCR_CID_CSD_OVERWRIETE){return (SDIO_CID_CSD_OVERWRITE);}if (response_r1 & SDIO_OCR_WP_ERASE_SKIP){return (SDIO_WP_ERASE_SKIP);}if (response_r1 & SDIO_OCR_CARD_ECC_DISABLED){return (SDIO_CARD_ECC_DISABLED);}if (response_r1 & SDIO_OCR_ERASE_RESET){return (SDIO_ERASE_RESET);}if (response_r1 & SDIO_OCR_AKE_SEQ_ERROR){return (SDIO_AKE_SEQ_ERROR);}return Status;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdResp3Error(void)
* 功能            :   指令执行状态(R3,OCR)
* 参数            :   无
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   优先处理CRC错误
*************************************************************************************************************************/
SDIO_Error SDIO_CmdResp3Error(void)
{SDIO_Error Status = SDIO_OK;u32 timeout=SDIO_TIMEOUT_US;while (timeout){timeout--;if(SDIO->INTSTS &(SDIO_INT_STATUS_RITO | SDIO_INT_STATUS_CRC)) break;//CRC错误/命令响应超时if((SDIO->CTL & SDIO_CTL_RIEN_Msk) == 0) break;                      //收到响应了Delay_US(1);} if(timeout==0)                  //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("程序不应该执行到此处(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}if(SDIO->INTSTS & SDIO_INT_STATUS_RITO)   //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//SDIO_STA_CCRCFAIL 错误   if(SDIO->INTSTS & SDIO_INT_STATUS_CRC)                                   //命令校验错误{                                                                                   Status = SDIO_CMD_CRC_FAIL;SDIO->INTSTS = SDIO->INTSTS;                                     //清除所有标志return Status;}//清除所有标志SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志return Status;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdResp2Error(void)
* 功能            :   指令执行状态(R2,CID or CSD)
* 参数            :   无
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :   R2响应跟R3响应处理完全一致
*************************************************************************************************************************/
SDIO_Error SDIO_CmdResp2Error(void)
{SDIO_Error Status = SDIO_OK;u32 timeout=SDIO_TIMEOUT_US;while (timeout){timeout--;if(SDIO->INTSTS &(SDIO_INT_STATUS_RITO | SDIO_INT_STATUS_CRC)) break;//CRC错误/命令响应超时if((SDIO->CTL & SDIO_CTL_R2IEN_Msk) == 0) break;                     //收到r2响应了Delay_US(1);} if(timeout==0)                    //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("程序不应该执行到此处(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}if(SDIO->INTSTS & SDIO_INT_STATUS_RITO)   //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//SDIO_STA_CCRCFAIL 错误   if(SDIO->INTSTS & SDIO_INT_STATUS_CRC)                                   //命令校验错误{                                                                                   Status = SDIO_CMD_CRC_FAIL;SDIO->INTSTS = SDIO->INTSTS;                                     //清除所有标志return Status;}//清除所有标志SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志    return Status;
} /*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_CmdResp6Error(u16*prca)
* 功能            :   指令执行状态(R6,RCA)
* 参数            :   prca:RCA缓冲区指针
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
SDIO_Error SDIO_CmdResp6Error(u16*prca)
{SDIO_Error Status = SDIO_OK;                  u32 response_r1;u32 timeout=SDIO_TIMEOUT_US/1;while (timeout){timeout--;if(SDIO->INTSTS &(SDIO_INT_STATUS_RITO | SDIO_INT_STATUS_CRC)) break;//CRC错误/命令响应超时if((SDIO->CTL & SDIO_CTL_RIEN_Msk) == 0) break;                      //收到响应了Delay_US(1);} if(timeout==0)                  //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("程序不应该执行到此处(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}if(SDIO->INTSTS & SDIO_INT_STATUS_RITO)   //响应超时{                                                                                 Status = SDIO_CMD_RSP_TIMEOUT; SDIO->CTL |= SDIO_CTL_SW_RST;                                       //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                      //清除所有标志return Status;}//SDIO_STA_CCRCFAIL 错误   if(SDIO->INTSTS & SDIO_INT_STATUS_CRC)                                   //命令校验错误{                                                                                   Status = SDIO_CMD_CRC_FAIL;SDIO->INTSTS = SDIO->INTSTS;                                     //清除所有标志return Status;}//清除所有标志SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志//We have received response, retrieve it. response_r1 = SDIO_GetResp1CardStatu();if (0 == (response_r1 & (SDIO_R6_GENERAL_UNKNOWN_ERROR | SDIO_R6_ILLEGAL_CMD | SDIO_R6_COM_CRC_FAILED))){*prca = (u16) (response_r1 >> 16);return Status;}if (response_r1 & SDIO_R6_GENERAL_UNKNOWN_ERROR){return (SDIO_GENERAL_UNKNOWN_ERROR);}if (response_r1 & SDIO_R6_ILLEGAL_CMD){return (SDIO_ILLEGAL_CMD);}if (response_r1 & SDIO_R6_COM_CRC_FAILED){return(SDIO_COM_CRC_FAILED);}return Status;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SDIO_WaitTransComplete(bool isEnableReadData, u32 *pDataLen, u32 TimeOutMs)
* 功能            :   SDIO等待传输完成(等待读取或写入数据完成)
* 参数            :   isEnableReadData:是否为读取数据;pDataLen:返回实际传输的数据长度;TimeOutMs:超时时间,毫秒
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-04
* 最后修改时间    :   2020-09-04
* 说明            :
*************************************************************************************************************************/
SDIO_Error SDIO_WaitTransComplete(bool isEnableReadData, u32 *pDataLen, u32 TimeOutMs)
{SDIO_Error Status = SDIO_OK;  u32 timeout=TimeOutMs*1000/10+1;u32 cnt= ((SDIO->BLEN&0x7FF)+1) * ((SDIO->CTL>>16)&0xFF);                   //获取DMA要传输的数据长度,块大小*块数量  *pDataLen = 0;                                                             //初始化接收数量为0//等待读取完成while (timeout){timeout--;if(SDIO_DMA->INTSTS & 0x03) break;                                      //传输出错if(SDIO->INTSTS & (SDIO_INT_STATUS_CRC | SDIO_INT_STATUS_BLKD)) break; //传输完成或者CRC校验SDIO_DelayUS(1);   }if(timeout == 0) //读取超时{Status = SDIO_DATA_TIMEOUT; //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("传输超时(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                         //复位SDIO控制器SDIO_DMA->CTL |= BIT1;                                                   //复位SDIO DMASDIO->INTSTS = SDIO->INTSTS;                                         //清除所有标志SDIO_DMA->INTSTS = SDIO_DMA->INTSTS;                                 //清除DMA中断标志goto _error;}if((SDIO_DMA->INTSTS & 0x03) || (SDIO_DMA->CTL & BIT9))                       //传输出错,或者DMA还在忙{Status = SDIO_INTERNAL_ERROR;  //正常程序不应该执行到此处,如果到了此处请检查原因DEBUG("传输出错(0x%X)\r\n", SDIO->INTSTS);SDIO->CTL |= SDIO_CTL_SW_RST;                                         //复位SDIO控制器SDIO_DMA->CTL |= BIT1;                                                   //复位SDIO DMASDIO->INTSTS = SDIO->INTSTS;                                         //清除所有标志SDIO_DMA->INTSTS = SDIO_DMA->INTSTS;                                 //清除DMA中断标志goto _error;}if(SDIO->INTSTS & SDIO_INT_STATUS_CRC)                                       //数据校验错误{Status = SDIO_DATA_CRC_FAIL;  SDIO->CTL |= SDIO_CTL_SW_RST;                                           //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                          //清除所有标志goto _error;}if(SDIO->INTSTS & SDIO_INT_STATUS_BLKD)                                     //传输完成{Status = SDIO_OK;SDIO->INTSTS = SDIO->INTSTS;                                            //清除所有标志goto _error;}Status = SDIO_UNSUPPORTED_FEATURE;    SDIO->CTL |= SDIO_CTL_SW_RST;                                               //复位SDIO控制器SDIO->INTSTS = SDIO->INTSTS;                                              //清除所有标志_error: *pDataLen = cnt-SDIO_DMA->BCNT;                                             //计算实际传输的数据量return Status;
}/*************************************************************************************************************************
* 函数            :   u32 SDIO_GetResp1CardStatu(void)
* 功能            :   获取R1响应的卡状态数据
* 参数            :   无
* 返回            :   响应数据的[39:8],也就是卡状态数据
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2020-09-09
* 最后修改时间    :   2020-09-09
* 说明            :   响应数据的[39:8]
*************************************************************************************************************************/
__inline u32 SDIO_GetResp1CardStatu(void)
{u32 temp;temp = SDIO->RESP0;//响应数据的[47:16],只取出[39:16]temp <<= 8;temp |= SDIO->RESP1 & 0xFF;//响应数据的[15:8]return temp;
}

//SDIO.h

/************************************************************************************************************** 文件名:         sdio.h* 功能:         NUC970 sdio驱动* 作者:          cp1300@139.com* 创建时间:      2020-09-04* 最后修改时间: 2020-09-04* 详细:
*************************************************************************************************************/
#ifndef _SDIO_H_
#define _SDIO_H_
#include "nuc970_system.h"
#include "sdio_const.h"//SDIO时钟速度定义
typedef enum
{SDIO_CLK_100M  =  0,SDIO_CLK_50M  =  1,SDIO_CLK_33M  =  2,SDIO_CLK_25M  =  3,SDIO_CLK_20M  =  4,SDIO_CLK_16M  =  5,SDIO_CLK_14M  =  6,SDIO_CLK_12M  =  7,  SDIO_CLK_11M    =  8,SDIO_CLK_10M  =  9,  SDIO_CLK_9M     =  10,SDIO_CLK_8M      =  11,SDIO_CLK_7M      =  13,SDIO_CLK_6M      =  15,SDIO_CLK_5M      =  19,SDIO_CLK_4M      =  24,SDIO_CLK_3M      =  32,SDIO_CLK_2M      =  49,SDIO_CLK_1M      =  99,SDIO_CLK_500K    =  199,SDIO_CLK_400K   =  255,
}SDIO_CLOCK_SPEED;#define SDIO_STA_ALL              ((u32)0x000fffff)   //所有标志//中断状态掩码
#define SDIO_INT_STATUS_SD1DAT1             (1<<19)                       //该位反映了SD端口1的DAT1引脚状态
#define SDIO_INT_STATUS_SD0DAT1             (1<<18)                       //该位反映了SD端口0的DAT1引脚状态
#define SDIO_INT_STATUS_CDPS1               (1<<17)                       //SD端口1卡插入状态
#define SDIO_INT_STATUS_CDPS0               (1<<16)                       //SD端口0卡插入状态
#define SDIO_INT_STATUS_DITO                (1<<13)                       //读取数据超时
#define SDIO_INT_STATUS_RITO                (1<<12)                       //响应数据超时
#define SDIO_INT_STATUS_SDIO1               (1<<11)                       //该位指示SDIO卡1向主机发出中断
#define SDIO_INT_STATUS_SDIO0               (1<<10)                       //该位指示SDIO卡0向主机发出中断
#define SDIO_INT_STATUS_CD1                 (1<<9)                        //该位指示已插入或卸下SD卡1
#define SDIO_INT_STATUS_CD0                 (1<<8)                        //该位指示已插入或卸下SD卡0
#define SDIO_INT_STATUS_SDDAT0              (1<<7)                        //当前所选SD端口的DAT0引脚状态
#define SDIO_INT_STATUS_CRC                 (1<<1)                        //发生了CRC错误,注意R3命令没有CRC依旧会有此错误
#define SDIO_INT_STATUS_BLKD                (1<<0)                        //该位表示SD主机已完成所有数据输入或数据输出块传输//命令,或数据响应状态
#define SDIO_CTL_SW_RST                     (1<<14)                       //复位命令
#define SDIO_CTL_R2IEN_Msk                  (1<<4)                        //使能R2响应输入,收到响应后清零
#define SDIO_CTL_DOEN_Msk                   (1<<3)                        //使能数据输出,发送完后清零
#define SDIO_CTL_DIEN_Msk                   (1<<2)                        //使能数据输入,收到数据后清零
#define SDIO_CTL_RIEN_Msk                   (1<<1)                        //使能响应输入,收到响应后清零
#define SDIO_CTL_COEN_Msk                   (1<<0)                        //使能命令输出,发送完后清零bool SDIO_Init(void);                                                 //SDIO接口初始化
void SDIO_SetClockSpeed(SDIO_CLOCK_SPEED ClkSpeed);                     //SDIO设置时钟速度
void SDIO_SetBusWide(SDIO_BUS_WIDE BusWide);                            //SDIO设置总线宽度
void SDIO_SendCommand(u8 CmdIndex,u32 CmdArg,SDIO_WAIT_RESP WaitResp);  //SDIO发送一个命令
void SDIO_SetPower(bool isPowerUp);                                     //SDIO电源控制
void SDIO_SetPowerSaving(bool isSaving);                                //SDIO节能模式开关
void SDIO_StartDataTrans(bool isRead);                                  //SDIO开始数据传输
void SDIO_ClearDataTrans(void);                                         //SDIO清除数据传输
void SDIO_SetDataTransTimeOut(u32 DataIimeOut);                         //SDIO传输数据超时设置
void SDIO_SetDataTransBlockSize(SDIO_DataBlockSize DataBlockSize);      //SDIO传输数据块大小设置
void SDIO_SetDataTransLength(u32 DataLen);                              //SDIO传输数据长度
SDIO_Error SDIO_WaitTransComplete(bool isEnableReadData, u32 *pDataLen, u32 TimeOutMs);//SDIO等待传输完成(等待读取或写入数据完成)
void SDIO_SetAndStartDataTrans(u8 *pDataBuff, bool isEnableReadData, SDIO_DataBlockSize SDIOBlockSize, u32 TransDataLen);//设置SDIO并开始准备数据传输
u8 SDIO_GetPortSelect(void);                                            //获取当前选择的port(0-1)
void SDIO_SetPortSelect(u8 port);                                       //设置SDIO当前port(0-1)
bool SDIO_SetOut74Clock(void);                                          //SDIO输出74个时钟SDIO_Error SDIO_CmdError(void);                                            //获取指令执行状态(无响应)
SDIO_Error SDIO_CmdResp7Error(void);                                    //获取指令执行状态(R7)
SDIO_Error SDIO_CmdResp1Error(void);                                    //指令执行状态(R1)
SDIO_Error SDIO_CmdResp3Error(void);                                    //指令执行状态(R3,OCR)
SDIO_Error SDIO_CmdResp2Error(void);                                    //指令执行状态(R2,CID or CSD)
SDIO_Error SDIO_CmdResp6Error(u16*prca);                                //指令执行状态(R6,RCA)
void SDIO_GetResponse(SDIO_RESP_TYPE RespIndex, u32 *pRespData);        //获取返回响应状态
__inline u32 SDIO_GetMaxTransBlockCount(void) {return 0xFF;}            //获取最大传输块数量,2020-09-13新增接口#endif //_SDIO_H_

//SDIO_CONST.H

/************************************************************************************************************** 文件名      :   sdio_const.h* 功能            :   SDIO相关常量与状态定义* 作者           :   cp1300@139.com* 创建时间       :   2018-03-26* 最后修改时间  :   2018-03-26* 详细:
*************************************************************************************************************/
#ifndef _SDIO_CONST_H_
#define _SDIO_CONST_H_
#include "system.h" //SDIO块大小
typedef enum
{SDIO_DataBlockSize_1B            =    0,SDIO_DataBlockSize_2B         =  1,            SDIO_DataBlockSize_4B         =  3,            SDIO_DataBlockSize_8B         =  7,           SDIO_DataBlockSize_16B        =   15,         SDIO_DataBlockSize_32B        =    31,          SDIO_DataBlockSize_64B        =   63,    SDIO_DataBlockSize_128B       = 127,       SDIO_DataBlockSize_256B       = 255,       SDIO_DataBlockSize_512B       = 511,       SDIO_DataBlockSize_1024B      = 1023,        SDIO_DataBlockSize_2048B      =   2047,
}SDIO_DataBlockSize;//SDIO命令响应定义
typedef enum
{SDIO_Response_No           =  0,  //无应答SDIO_Response_Short        =  1,  //短应答48bitSDIO_Response_Long            =  3,  //长应答136bit
}SDIO_WAIT_RESP;//SDIO总线宽度定义
typedef enum
{   SDIO_BusWide_1b    =   0,  //1BITSDIO_BusWide_4b    =   1,    //4BIT
}SDIO_BUS_WIDE;//SDIO 各种错误枚举定义
typedef enum
{    //特殊错误定义 SDIO_CMD_CRC_FAIL                    = (1), /*!< Command response received (but CRC check failed) */SDIO_DATA_CRC_FAIL                   = (2), /*!< Data bock sent/received (CRC check Failed) */SDIO_CMD_RSP_TIMEOUT                 = (3), /*!< Command response timeout */SDIO_DATA_TIMEOUT                    = (4), /*!< Data time out */SDIO_TX_UNDERRUN                     = (5), /*!< Transmit FIFO under-run */SDIO_RX_OVERRUN                      = (6), /*!< Receive FIFO over-run */SDIO_START_BIT_ERR                   = (7), /*!< Start bit not detected on all data signals in widE bus mode */SDIO_CMD_OUT_OF_RANGE                = (8), /*!< CMD's argument was out of range.*/SDIO_ADDR_MISALIGNED                 = (9), /*!< Misaligned address */SDIO_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 */SDIO_ERASE_SEQ_ERR                   = (11), /*!< An error in the sequence of erase command occurs.*/SDIO_BAD_ERASE_PARAM                 = (12), /*!< An Invalid selection for erase groups */SDIO_WRITE_PROT_VIOLATION            = (13), /*!< Attempt to program a write protect block */SDIO_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 */SDIO_COM_CRC_FAILED                  = (15), /*!< CRC check of the previous command failed */SDIO_ILLEGAL_CMD                     = (16), /*!< Command is not legal for the card state */SDIO_CARD_ECC_FAILED                 = (17), /*!< Card internal ECC was applied but failed to correct the data */SDIO_CC_ERROR                        = (18), /*!< Internal card controller error */SDIO_GENERAL_UNKNOWN_ERROR           = (19), /*!< General or Unknown error */SDIO_STREAM_READ_UNDERRUN            = (20), /*!< The card could not sustain data transfer in stream read operation. */SDIO_STREAM_WRITE_OVERRUN            = (21), /*!< The card could not sustain data programming in stream mode */SDIO_CID_CSD_OVERWRITE               = (22), /*!< CID/CSD overwrite error */SDIO_WP_ERASE_SKIP                   = (23), /*!< only partial address space was erased */SDIO_CARD_ECC_DISABLED               = (24), /*!< Command has been executed without using internal ECC */SDIO_ERASE_RESET                     = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */SDIO_AKE_SEQ_ERROR                   = (26), /*!< Error in sequence of authentication. */SDIO_INVALID_VOLTRANGE               = (27),SDIO_ADDR_OUT_OF_RANGE               = (28),SDIO_SWITCH_ERROR                    = (29),SDIO_SDIO_DISABLED                   = (30),SDIO_SDIO_FUNCTION_BUSY              = (31),SDIO_SDIO_FUNCTION_FAILED            = (32),SDIO_SDIO_UNKNOWN_FUNCTION           = (33),//标准错误定义SDIO_INTERNAL_ERROR, SDIO_NOT_CONFIGURED,SDIO_REQUEST_PENDING, SDIO_REQUEST_NOT_APPLICABLE, SDIO_INVALID_PARAMETER,  SDIO_UNSUPPORTED_FEATURE,  SDIO_UNSUPPORTED_HW,  SDIO_ERROR,  SDIO_OK = 0
} SDIO_Error;   //SDIO响应获取定义
typedef enum
{SDIO_RESP_Short= 0,   //获取段响应中的32bit,命令索引数据 u32[0]  卡状态 [31:0]SDIO_RESP_Long = 1, //获取长响应CID或CSD(包括内部CRC7) u32[0] 卡状态 [127:96];[1]:卡状态 [95:64];[2]:卡状态 [63:32];[3]:卡状态 [31:1]0b
}SDIO_RESP_TYPE;//Masks for R6 Response
#define SDIO_R6_GENERAL_UNKNOWN_ERROR     ((u32)0x00002000)
#define SDIO_R6_ILLEGAL_CMD               ((u32)0x00004000)
#define SDIO_R6_COM_CRC_FAILED            ((u32)0x00008000)//Mask for errors Card Status R1 (OCR Register)
#define SDIO_OCR_ADDR_OUT_OF_RANGE        ((u32)0x80000000)
#define SDIO_OCR_ADDR_MISALIGNED          ((u32)0x40000000)
#define SDIO_OCR_BLOCK_LEN_ERR            ((u32)0x20000000)
#define SDIO_OCR_ERASE_SEQ_ERR            ((u32)0x10000000)
#define SDIO_OCR_BAD_ERASE_PARAM          ((u32)0x08000000)
#define SDIO_OCR_WRITE_PROT_VIOLATION     ((u32)0x04000000)
#define SDIO_OCR_LOCK_UNLOCK_FAILED       ((u32)0x01000000)
#define SDIO_OCR_COM_CRC_FAILED           ((u32)0x00800000)
#define SDIO_OCR_ILLEGAL_CMD              ((u32)0x00400000)
#define SDIO_OCR_CARD_ECC_FAILED          ((u32)0x00200000)
#define SDIO_OCR_CC_ERROR                 ((u32)0x00100000)
#define SDIO_OCR_GENERAL_UNKNOWN_ERROR    ((u32)0x00080000)
#define SDIO_OCR_STREAM_READ_UNDERRUN     ((u32)0x00040000)
#define SDIO_OCR_STREAM_WRITE_OVERRUN     ((u32)0x00020000)
#define SDIO_OCR_CID_CSD_OVERWRIETE         ((u32)0x00010000)
#define SDIO_OCR_WP_ERASE_SKIP            ((u32)0x00008000)
#define SDIO_OCR_CARD_ECC_DISABLED        ((u32)0x00004000)
#define SDIO_OCR_ERASE_RESET              ((u32)0x00002000)
#define SDIO_OCR_AKE_SEQ_ERROR            ((u32)0x00000008)
#define SDIO_OCR_ERRORBITS                ((u32)0xFDFFE008)//SDIO 指令集
#define SDIO_CMD_GO_IDLE_STATE                       ((u8)0)
#define SDIO_CMD_SEND_OP_COND                        ((u8)1)
#define SDIO_CMD_ALL_SEND_CID                        ((u8)2)
#define SDIO_CMD_SET_REL_ADDR                        ((u8)3) /*!< SDIO_SEND_REL_ADDR for SD Card */
#define SDIO_CMD_SET_DSR                             ((u8)4)
#define SDIO_CMD_SDIO_SEN_OP_COND                    ((u8)5)
#define SDIO_CMD_HS_SWITCH                           ((u8)6)
#define SDIO_CMD_SEL_DESEL_CARD                      ((u8)7)
#define SDIO_CMD_HS_SEND_EXT_CSD                     ((u8)8)
#define SDIO_CMD_SEND_CSD                            ((u8)9)
#define SDIO_CMD_SEND_CID                            ((u8)10)
#define SDIO_CMD_READ_DAT_UNTIL_STOP                 ((u8)11) /*!< SD Card doesn't support it */
#define SDIO_CMD_STOP_TRANSMISSION                   ((u8)12)
#define SDIO_CMD_SEND_STATUS                         ((u8)13)
#define SDIO_CMD_HS_BUSTEST_READ                     ((u8)14)
#define SDIO_CMD_GO_INACTIVE_STATE                   ((u8)15)
#define SDIO_CMD_SET_BLOCKLEN                        ((u8)16)
#define SDIO_CMD_READ_SINGLE_BLOCK                   ((u8)17)
#define SDIO_CMD_READ_MULT_BLOCK                     ((u8)18)
#define SDIO_CMD_HS_BUSTEST_WRITE                    ((u8)19)
#define SDIO_CMD_WRITE_DAT_UNTIL_STOP                ((u8)20)
#define SDIO_CMD_SET_BLOCK_COUNT                     ((u8)23)
#define SDIO_CMD_WRITE_SINGLE_BLOCK                  ((u8)24)
#define SDIO_CMD_WRITE_MULT_BLOCK                    ((u8)25)
#define SDIO_CMD_PROG_CID                            ((u8)26)
#define SDIO_CMD_PROG_CSD                            ((u8)27)
#define SDIO_CMD_SET_WRITE_PROT                      ((u8)28)
#define SDIO_CMD_CLR_WRITE_PROT                      ((u8)29)
#define SDIO_CMD_SEND_WRITE_PROT                     ((u8)30)
#define SDIO_CMD_SDIO_ERASE_GRP_START                  ((u8)32) /*!< To set the address of the first writeblock to be erased. (For SD card only) */
#define SDIO_CMD_SDIO_ERASE_GRP_END                    ((u8)33) /*!< To set the address of the last write block of thecontinuous range to be erased. (For SD card only) */
#define SDIO_CMD_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_CMD_ERASE_GRP_END                       ((u8)36) /*!< To set the address of the last write block of thecontinuous range to be erased. (For MMC card only spec 3.31) */#define SDIO_CMD_ERASE                               ((u8)38)
#define SDIO_CMD_FAST_IO                             ((u8)39) /*!< SD Card doesn't support it */
#define SDIO_CMD_GO_IRQ_STATE                        ((u8)40) /*!< SD Card doesn't support it */
#define SDIO_CMD_LOCK_UNLOCK                         ((u8)42)
#define SDIO_CMD_APP_CMD                             ((u8)55)
#define SDIO_CMD_GEN_CMD                             ((u8)56)
#define SDIO_CMD_NO_CMD                              ((u8)64)/** * @brief Following commands are SD Card Specific commands.*        SDIO_APP_CMD :CMD55 should be sent before sending these commands. */
#define SDIO_CMD_APP_SDIO_SET_BUSWIDTH                 ((u8)6)  /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_STAUS                        ((u8)13) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SEND_NUM_WRITE_BLOCKS        ((u8)22) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_OP_COND                      ((u8)41) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SET_CLR_CARD_DETECT          ((u8)42) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SEND_SCR                     ((u8)51) /*!< For SD Card only */
#define SDIO_CMD_SDIO_RW_DIRECT                      ((u8)52) /*!< For SD I/O Card only */
#define SDIO_CMD_SDIO_RW_EXTENDED                    ((u8)53) /*!< For SD I/O Card only *//** * @brief Following commands are SD Card Specific security commands.*        SDIO_APP_CMD should be sent before sending these commands. */
#define SDIO_CMD_SDIO_APP_GET_MKB                      ((u8)43) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_GET_MID                      ((u8)44) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SET_CER_RN1                  ((u8)45) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_GET_CER_RN2                  ((u8)46) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SET_CER_RES2                 ((u8)47) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_GET_CER_RES1                 ((u8)48) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SECURE_READ_MULTIPLE_BLOCK   ((u8)18) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SECURE_WRITE_MULTIPLE_BLOCK  ((u8)25) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SECURE_ERASE                 ((u8)38) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_CHANGE_SECURE_AREA           ((u8)49) /*!< For SD Card only */
#define SDIO_CMD_SDIO_APP_SECURE_WRITE_MKB             ((u8)48) /*!< For SD Card only */#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)//Command Class Supported
#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)#endif  //_SDIO_CONST_H_

//SDIO_SDCARD.C

/************************************************************************************************************** 文件名          :   sdio_sdcard.c* 功能               :   SDIO接口SD卡驱动* 作者             :   cp1300@139.com* 创建时间           :   2018-03-27* 最后修改时间      :   2018-03-27* 详细              :   源程序借鉴了意法STM32F103X库函数分离了底层SDIO接口,但是依赖一些数据定义,在sdio_const中,去掉了MMC卡支持,没遇到过MMC卡异常情况:如果先将卡设置为高速模式,然后再设置为4线模式,之后读取多块超时后会出现CMD12响应3,并且卡不断电情况下无法恢复通讯,所有命令均响应超时。出现了这种异常情况后,必须对卡进行重新断电才能恢复,就算单片机复位都不行。2018-03-29:删除了SCR状态读取,这个状态唯一的作用就是获取卡是否支持4线模式(很少有不支持的,就算不支持,设置失败了也会还原为单线模式),SD卡上电默认必须为单线模式2018-03-30:如果SD卡在读取或者写入数据过程中突然中断(程序复位),但是SD卡没有断电,下次可能会初始化失败,并且必须断电才能恢复。2018-03-30:读取入1-3个扇区时间均为3m,写入1个扇区为4ms,由于通信内部使用了系统延时1ms导致,此时提高系统时钟,SDIO时钟均无效,但是增加这个1ms延时可以有效防止系统卡死,提高OS运行效率2018-03-30:测试写入3个扇区时间为5ms,写入10个扇区为7ms2019-10-31:修复初始化时判断大容量卡时&写成了&=,导致判断错误2020-02-03:修改一次最大的读写限制为65535字节,FAT文件系统一次最大只会读取32KB数据2020-02-21:修改可以设置SD卡块大小,同步修改SDIO块大小,SDHC卡不支持修改块大小,去掉了读写时卡锁定检查(没啥用)2020-09-13:增加获取最大传输块数量功能,修改读写扇区是,检查并清理传输错误,修改响应数据读取接口
*************************************************************************************************************/
#include "sdio_sdcard.h"
#include "system.h"
#include "sdio_const.h"
#include "string.h"// SD卡指令表
#define CMD0    0       //复位所有的卡到idle状态
#define CMD1    1
#define CMD2    2       //通知所有卡通过CMD线返回CID值。
#define CMD3    3       //通知所有卡发布新RCA
#define ACMD6   6       //设置宽总线模式
#define CMD7    7       //选择/取消选择RCA地址卡。
#define CMD8    8       //发送SD卡接口条件,包含主机支持的电压信息,并询问卡是否支持。
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD13   13      //命令13,选定卡通过CMD线发送它状态寄存器
#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 CMD32   32      //设置擦除的起始块地址
#define CMD33   33      //设置擦除的结束块地址
#define CMD38   38      //擦除预先选定的块#define ACMD41  41      //命令41,主机要求卡发送它的支持信息(HCS)和OCR寄存器内容。
#define CMD55   55      //命令55,指定下个命令为特定应用命令,不是标准命令
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x0#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_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 SDCARD_DBUG     1
#if SDCARD_DBUG#include "system.h"#define sdcard_debug(format,...)    uart_printf(format,##__VA_ARGS__)
#else#define sdcard_debug(format,...)   /\
/#endif //SDCARD_DBUGSDIO_Error SD_SetIdleSta(SDIO_SD_HANDLE *pHandle);                                 //SD卡上电进入空闲模式,并识别卡
SDIO_Error SD_InitializeCards(SDIO_SD_HANDLE *pHandle);                             //将所有的卡进行初始化配置
static SDIO_Error SDEnableWideBus(SDIO_SD_HANDLE *pHandle, bool isEnableWideBus);   //设置SD卡宽总线模式
SDIO_Error SD_SetBlockSize(SDIO_SD_HANDLE *pHandle, u16 BlockSize);                 //设置SD卡块大小
SDIO_Error SD_EnableWideBusMode(SDIO_SD_HANDLE *pHandle, bool isEnable4BusWide);    //使能4bit DAT线模式,如果失败将保持原来模式
SDIO_Error SD_SelectDeselect(SDIO_SD_HANDLE *pHandle, u32 addr);                    //选中一个卡,并处于传输状态
SDIO_Error SD_GetCardInfo(SDIO_SD_HANDLE *pHandle, SD_CardInfo *cardinfo);          //获取卡的细节信息
SDIO_Error SD_WaitProgrammingFinish(SDIO_SD_HANDLE *pHandle, u32 TimeOutMs);        //等待编程完成
SDIO_Error SD_GetSDSCR(SDIO_SD_HANDLE *pHandle, u32 pSCR[2]);                       //获取SCR信息/*************************************************************************************************************************
* 函数            :   void SD_InterfaceInit(SDIO_SD_HANDLE *pHandle,const SDIO_SD_INTERFACE *pInterface)
* 功能            :   SD卡底层接口初始化
* 参数            :   pHandle:句柄;pInterface:通信接口
* 返回            :   无
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-27
* 最后修改时间    :   2018-03-27
* 说明            :   初始化SD卡
*************************************************************************************************************************/
void SD_InterfaceInit(SDIO_SD_HANDLE *pHandle, const SDIO_SD_INTERFACE *pInterface)
{pHandle->pInterface = pInterface;  //初始化通信接口
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_ReadStatus(SDIO_SD_HANDLE *pHandle, u32 *pSCR)
* 功能            :   读取SD卡状态寄存器
* 参数            :   pHandle:句柄;pSCR:状态寄存器的值
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-29
* 最后修改时间    :   2018-03-29
* 说明            :   必须在初始化SD卡成功后才能调用,因为需要SD卡的RCA地址
**************************************************************************************************************************/
SDIO_Error SD_ReadStatus(SDIO_SD_HANDLE *pHandle, u32 *pSCR)
{SDIO_Error errorstatus = SDIO_OK;//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;pHandle->pInterface->SDIO_SendCommand(CMD13, (u32) pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                      //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD13 error (%d)!\r\n",errorstatus);return(errorstatus);}pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, pSCR);                   //获取响应的状态return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_Init(SDIO_SD_HANDLE *pHandle)
* 功能            :   SD卡初始化
* 参数            :   pHandle:句柄
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-27
* 最后修改时间    :   2018-03-27
* 说明            :   初始化SD卡,需要提前初始化通信接口,调用:SD_InterfaceInit
*************************************************************************************************************************/
SDIO_Error SD_Init(SDIO_SD_HANDLE *pHandle)
{SDIO_Error errorstatus = SDIO_OK;if(pHandle == NULL || pHandle->pInterface == NULL){DEBUG("SDIO 接口无效!\n");           //调试,打印错误return SDIO_ERROR;}//初始化相关变量memset(&pHandle->SDCardInfo, 0, sizeof(SD_CardInfo));pHandle->SDIO_BlockSize = SDIO_DataBlockSize_512B;         //设置默认的SDIO传输块大小:512字节pHandle->pInterface->SDIO_Init();                            //SDIO硬件初始化pHandle->MaxTransBlockCount = pHandle->pInterface->SDIO_GetMaxTransBlockCount();//从SDIO驱动层获取一次最大传输块数量errorstatus = SD_SetIdleSta(pHandle);                        //SD卡上电if (errorstatus != SDIO_OK)                                 //卡上电发送错误{DEBUG("SD power up error:(%d)!\n",errorstatus);         //调试,打印错误return (errorstatus);  //返回错误}errorstatus = SD_InitializeCards(pHandle);if (errorstatus != SDIO_OK){DEBUG("SD initialize error(%d)!\r\n",errorstatus);     //调试,打印错误return (errorstatus);}//更新卡信息SD_GetCardInfo(pHandle, &pHandle->SDCardInfo);             //获取卡信息uart_printf("SD卡容量:%llu\r\n",  pHandle->SDCardInfo.CardCapacity);return (errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_Reset(SDIO_SD_HANDLE *pHandle)
* 功能            :   复位并检查卡,不支持MMC卡
* 参数            :   pHandle:接口句柄
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-29
* 最后修改时间    :   2018-03-29
* 说明            :   SD卡上电进入空闲模式(不带响应),并使用CMD55检查卡是否通讯正常
*************************************************************************************************************************/
SDIO_Error SD_Reset(SDIO_SD_HANDLE *pHandle)
{SDIO_Error errorstatus = SDIO_OK;u32 i;//循环发生发送CMD0,无响应,无返回,让SD卡进入空闲模式-无响应,无返回,多发送几次for(i = 0; i < 10; i ++){pHandle->pInterface->SDIO_SendCommand(CMD0, 0, SDIO_Response_No);          //发送命令      pHandle->pInterface->SDIO_CmdError();                                     //判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功SYS_DelayMS(1);//发送CMD55pHandle->pInterface->SDIO_SendCommand(CMD55, 0, SDIO_Response_Short);     //发送命令errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                   if(errorstatus == SDIO_OK)                                                    //卡检测成功后再发送一次CMD0,否则后面的CMD8将不会响应{pHandle->pInterface->SDIO_SendCommand(CMD0, 0, SDIO_Response_No);     //发送命令      pHandle->pInterface->SDIO_CmdError();                                 //判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功return SDIO_OK;//SD卡}else if(errorstatus == SDIO_CMD_CRC_FAIL)        //我的一个v1.1的卡在此处会返回校验错误{pHandle->pInterface->SDIO_SendCommand(CMD0, 0, SDIO_Response_No);      //发送命令      pHandle->pInterface->SDIO_CmdError();                                 //判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功return SDIO_OK;//SD卡}}DEBUG("没有检测到SD卡(错误:%d)\r\n", errorstatus);return errorstatus;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_SetIdleSta(SDIO_SD_HANDLE *pHandle)
* 功能            :   SD卡上电进入空闲模式,并识别卡
* 参数            :   pHandle:接口句柄
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   SD卡上电进入空闲模式
*************************************************************************************************************************/
SDIO_Error SD_SetIdleSta(SDIO_SD_HANDLE *pHandle)
{SDIO_Error errorstatus = SDIO_OK;u32 response = 0, count = 0;bool validvoltage = FALSE;u32 SDType = SD_STD_CAPACITY;pHandle->pInterface->SDIO_SetLowSpeedClock();       //设置为低速时钟//发送至少74个时钟,等待SD卡上电成功并同步,要求SDIO一直输出时钟SYS_DelayMS(5);errorstatus = SD_Reset(pHandle);                   //复位并检查卡if(errorstatus != SDIO_OK) return errorstatus;//发送CMD8之前一定要发送一个CMD0-此处为重复发送(保险起见),因为在SD_Reset中已经发送pHandle->pInterface->SDIO_SendCommand(CMD0, 0, SDIO_Response_No);     //发送命令      pHandle->pInterface->SDIO_CmdError();                                 //判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功//发送CMD8:SEND_IF_COND;短响应,命令参数:SD_CHECK_PATTERN;返回响应R7//识别卡版本pHandle->pInterface->SDIO_SendCommand(CMD8, SD_CHECK_PATTERN, SDIO_Response_Short);  //发送命令errorstatus = pHandle->pInterface->SDIO_CmdResp7Error();                   //获取响应R7if (errorstatus == SDIO_OK)                                                   //返回成功;说明卡为SD Card 2.0 V2.0{pHandle->CardType = SD_STD_CAPACITY_SD_CARD_V2_0;                       //SD Card 2.0SDType = SD_HIGH_CAPACITY;    sdcard_debug("SD_STD_CAPACITY_SD_CARD_V2_0!\r\n");}else   //V1.0 V1.1{pHandle->CardType = SD_STD_CAPACITY_SD_CARD_V1_1;                       //V1.0 V1.1sdcard_debug("SD Card V1.1!\r\n");                                     //调试,打印信息pHandle->pInterface->SDIO_SendCommand(CMD55, 0, SDIO_Response_Short);    //发送命令errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();   }//发送CMD55pHandle->pInterface->SDIO_SendCommand(CMD55, 0, SDIO_Response_Short);       //发送命令errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                   if(errorstatus == SDIO_OK) //SD卡{do{//发送CMD55pHandle->pInterface->SDIO_SendCommand(CMD55, 0, SDIO_Response_Short);  //发送命令errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if(errorstatus != SDIO_OK) //SD卡{DEBUG("CMD55 error(%d)!\r\n",errorstatus);                         //调试,打印错误信息return(errorstatus);}//发送ACMD41命令;命令参数:SD_APP_OP_COND(0x80100000);短响应.响应为R3,返回操作条件寄存器RCA-注意,这个命令的响应是不带CRC的,会报CRC错误,忽略即可pHandle->pInterface->SDIO_SendCommand(ACMD41, SD_VOLTAGE_WINDOW_SD | SDType, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp3Error();if (errorstatus != SDIO_OK && errorstatus != SDIO_CMD_CRC_FAIL)     //CMD CRC错误也是正常的,ACM41不响应CRC {DEBUG("ACM41 error(%d)!\r\n",errorstatus);                       //调试,打印错误信息return(errorstatus);}errorstatus = SDIO_OK;pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &response);  //获取响应,RESE1validvoltage = (bool) (((response >> 31) == 1) ? 1 : 0);count++;}while((!validvoltage) && (count < SD_MAX_VOLT_TRIAL));                  //循环初始化,直到返回成功或者超时if (count >= SD_MAX_VOLT_TRIAL)                                           //重试次数超出{errorstatus = SDIO_INVALID_VOLTRANGE;return (errorstatus);}if (response & SD_HIGH_CAPACITY)                                       //大容量卡,超过4G以上{uart_printf("SD卡是大容量卡!\r\n");pHandle->CardType = SD_HIGH_CAPACITY_SD_CARD;}}return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_InitializeCards(SDIO_SD_HANDLE *pHandle)
* 功能            :   将所有的卡进行初始化配置
* 参数            :   pHandle:句柄
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   将所有的卡进行初始化配置
*************************************************************************************************************************/
SDIO_Error SD_InitializeCards(SDIO_SD_HANDLE *pHandle)
{SDIO_Error errorstatus = SDIO_OK;u16 rca = 0x01;if(SD_SECURE_DIGITAL_IO_CARD != pHandle->CardType)   //非SECURE_DIGITAL_IO_CARD{//发送CMD2 SDIO_ALL_SEND_CID命令,命令参数:0;长回复,R2pHandle->pInterface->SDIO_SendCommand(CMD2, 0, SDIO_Response_Long);errorstatus = pHandle->pInterface->SDIO_CmdResp2Error();                //获取响应R2if (errorstatus != SDIO_OK){DEBUG("CMD2 error!(%d)\r\n",errorstatus);                            //调试,打印错误信息return (errorstatus);}//到每个卡以获取每个卡的唯一标识CIDpHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Long, pHandle->CID_Tab);  }if((SD_STD_CAPACITY_SD_CARD_V1_1 == pHandle->CardType)||(SD_STD_CAPACITY_SD_CARD_V2_0 == pHandle->CardType)||(SD_SECURE_DIGITAL_IO_COMBO_CARD == pHandle->CardType)||(SD_HIGH_CAPACITY_SD_CARD == pHandle->CardType))//判断卡类型{//发送CMD3,短响应R6pHandle->pInterface->SDIO_SendCommand(CMD3, 0, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp6Error(&rca);               //获取响应R6if (errorstatus != SDIO_OK){DEBUG("CMD3 error!(%d)\r\n",errorstatus);                                //调试,打印错误信息return (errorstatus);}       }   if (SD_MULTIMEDIA_CARD == pHandle->CardType){//发送CMD3,短响应R2pHandle->pInterface->SDIO_SendCommand(CMD3, (u32)(rca<<16), SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp2Error();                //获取响应R2if (errorstatus != SDIO_OK){DEBUG("CMD3 error!(%d)\r\n",errorstatus);                                //调试,打印错误信息return (errorstatus);}    }if (SD_SECURE_DIGITAL_IO_CARD != pHandle->CardType)           //非SECURE_DIGITAL_IO_CARD{//发送CMD9+卡RCA,取得CSD,长响应 R2;给卡发送一个新的RCA,主要是用来设置卡地址的pHandle->pInterface->SDIO_SendCommand(CMD9, (u32)(rca<<16), SDIO_Response_Long);errorstatus = pHandle->pInterface->SDIO_CmdResp2Error();                //获取响应R2if (errorstatus != SDIO_OK){DEBUG("CMD3 error!(%d)\r\n",errorstatus);                                //调试,打印错误信息return (errorstatus);}     pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Long, pHandle->CSD_Tab);         }pHandle->RCA = rca;                                                        //存储卡地址//选中卡,并激活errorstatus = SD_SelectDeselect(pHandle, (u32)pHandle->RCA << 16);if(errorstatus != SDIO_OK){DEBUG("SelectDeselect error!(%d)!\r\n",errorstatus);                  //调试,打印错误信息return(errorstatus);}//先设置为4线模式,然后再设置为高速时钟//设置宽总线模式-一定要使用低速时钟,否则会出现卡不响应,并且不可恢复,必须对卡进行重新上电errorstatus = SDIO_OK; /* All cards get intialized */errorstatus = SD_EnableWideBusMode(pHandle, TRUE);                       //配置SD卡为4线模式if(errorstatus == SDIO_OK)    {sdcard_debug("SD SDIO 4BIT OK\r\n");}else //设置失败了,还原为1线模式{errorstatus = SD_EnableWideBusMode(pHandle, FALSE);                    //还原为1线模式DEBUG("SD SDIO 4BIT ERROR (%d)\r\n",errorstatus);}//提高时钟速度-必须放到最后,否则会出现卡各种不响应,必须对卡重新上电pHandle->pInterface->SDIO_SetHighpeedClock();                          //设置高速时钟//读取SD卡SCR信息,第一次使用数据线通信errorstatus = SD_GetSDSCR(pHandle, pHandle->SCR_Tab);                 //获取SCR信息//配置SD卡的块大小,之后不要再修改了,固定块大小进行传输errorstatus = SD_SetBlockSize(pHandle, SD_BLOCK_SIZE);                    //配置SD卡块大小  if (errorstatus != SDIO_OK){DEBUG("SD SetBlockSize error(%d)!\r\n",errorstatus);return(errorstatus);}return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_SelectDeselect(SDIO_SD_HANDLE *pHandle, u32 addr)
* 功能            :   选中一个卡,并处于传输状态
* 参数            :   pHandle:句柄;addr:卡地址
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   选择一个卡并将它置于传输状态(Transfer state)CMD7用来选定和取消指定的卡,卡在待机状态下还不能进行数据通信,因为总线上可能有多个卡都是出于待机状态,必须选择一个RCA地址目标卡使其进入传输状态才可以进行数据通信。同时通过CMD7命令也可以让已经被选择的目标卡返回到待机状态。
*************************************************************************************************************************/
SDIO_Error SD_SelectDeselect(SDIO_SD_HANDLE *pHandle, u32 addr)
{SDIO_Error errorstatus = SDIO_OK;//CMD7用来选择一个卡并将它置于传输状态(Transfer state),在任何时间只能有一个卡处于传输状态pHandle->pInterface->SDIO_SendCommand(CMD7, addr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_GetCardInfo(SDIO_SD_HANDLE *pHandle, SD_CardInfo *cardinfo)
* 功能            :   获取卡的细节信息
* 参数            :   pHandle:句柄;cardinfo:卡信息结构指针,指向信息存放缓冲区地址
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   获取卡的信息,通过CSD信息得到
*************************************************************************************************************************/
SDIO_Error SD_GetCardInfo(SDIO_SD_HANDLE *pHandle, SD_CardInfo *cardinfo)
{SDIO_Error errorstatus = SDIO_OK;u8 tmp=0;      cardinfo->CardType=(u8)pHandle->CardType;                         //卡类型cardinfo->RCA=(u16)pHandle->RCA;                                //卡RCA值tmp=(u8)((pHandle->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)((pHandle->CSD_Tab[0]&0x00FF0000)>>16);                  //第1个字节cardinfo->SD_csd.TAAC=tmp;                                       //数据读时间1tmp=(u8)((pHandle->CSD_Tab[0]&0x0000FF00)>>8);                    //第2个字节cardinfo->SD_csd.NSAC=tmp;                                       //数据读时间2tmp=(u8)(pHandle->CSD_Tab[0]&0x000000FF);                       //第3个字节cardinfo->SD_csd.MaxBusClkFrec=tmp;                              //传输速度     tmp=(u8)((pHandle->CSD_Tab[1]&0xFF000000)>>24);                    //第4个字节cardinfo->SD_csd.CardComdClasses=tmp<<4;                       //卡指令类高四位tmp=(u8)((pHandle->CSD_Tab[1]&0x00FF0000)>>16);                  //第5个字节cardinfo->SD_csd.CardComdClasses|=(tmp&0xF0)>>4;               //卡指令类低四位cardinfo->SD_csd.RdBlockLen=tmp&0x0F;                          //最大读取数据长度tmp=(u8)((pHandle->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((pHandle->CardType==SD_STD_CAPACITY_SD_CARD_V1_1)||(pHandle->CardType==SD_STD_CAPACITY_SD_CARD_V2_0)||(pHandle->CardType == SD_MULTIMEDIA_CARD))//标准1.1/2.0卡/MMC卡{cardinfo->SD_csd.DeviceSize=(tmp&0x03)<<10;                   //C_SIZE(12位)tmp=(u8)(pHandle->CSD_Tab[1]&0x000000FF);                  //第7个字节 cardinfo->SD_csd.DeviceSize|=(tmp)<<2;tmp=(u8)((pHandle->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)((pHandle->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_MULTtmp=(u8)((pHandle->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(pHandle->CardType==SD_HIGH_CAPACITY_SD_CARD)          //高容量卡{tmp=(u8)(pHandle->CSD_Tab[1]&0x000000FF);        //第7个字节 cardinfo->SD_csd.DeviceSize=(tmp&0x3F)<<16;//C_SIZEtmp=(u8)((pHandle->CSD_Tab[2]&0xFF000000)>>24); //第8个字节  cardinfo->SD_csd.DeviceSize|=(tmp<<8);tmp=(u8)((pHandle->CSD_Tab[2]&0x00FF0000)>>16);   //第9个字节 cardinfo->SD_csd.DeviceSize|=(tmp);tmp=(u8)((pHandle->CSD_Tab[2]&0x0000FF00)>>8);     //第10个字节    cardinfo->CardCapacity=(u64)(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)(pHandle->CSD_Tab[2]&0x000000FF);            //第11个字节    cardinfo->SD_csd.EraseGrMul|=(tmp&0x80)>>7;cardinfo->SD_csd.WrProtectGrSize=(tmp&0x7F);tmp=(u8)((pHandle->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)((pHandle->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)((pHandle->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)(pHandle->CSD_Tab[3]&0x000000FF);           //第15个字节cardinfo->SD_csd.CSD_CRC=(tmp&0xFE)>>1;cardinfo->SD_csd.Reserved4=1;       tmp=(u8)((pHandle->CID_Tab[0]&0xFF000000)>>24);      //第0个字节cardinfo->SD_cid.ManufacturerID=tmp;         tmp=(u8)((pHandle->CID_Tab[0]&0x00FF0000)>>16);       //第1个字节cardinfo->SD_cid.OEM_AppliID=tmp<<8;     tmp=(u8)((pHandle->CID_Tab[0]&0x000000FF00)>>8);    //第2个字节cardinfo->SD_cid.OEM_AppliID|=tmp;       tmp=(u8)(pHandle->CID_Tab[0]&0x000000FF);           //第3个字节 cardinfo->SD_cid.ProdName1=tmp<<24;                 tmp=(u8)((pHandle->CID_Tab[1]&0xFF000000)>>24);     //第4个字节cardinfo->SD_cid.ProdName1|=tmp<<16;     tmp=(u8)((pHandle->CID_Tab[1]&0x00FF0000)>>16);     //第5个字节cardinfo->SD_cid.ProdName1|=tmp<<8;         tmp=(u8)((pHandle->CID_Tab[1]&0x0000FF00)>>8);       //第6个字节cardinfo->SD_cid.ProdName1|=tmp;        tmp=(u8)(pHandle->CID_Tab[1]&0x000000FF);            //第7个字节cardinfo->SD_cid.ProdName2=tmp;            tmp=(u8)((pHandle->CID_Tab[2]&0xFF000000)>>24);     //第8个字节cardinfo->SD_cid.ProdRev=tmp;         tmp=(u8)((pHandle->CID_Tab[2]&0x00FF0000)>>16);      //第9个字节cardinfo->SD_cid.ProdSN=tmp<<24;      tmp=(u8)((pHandle->CID_Tab[2]&0x0000FF00)>>8);         //第10个字节cardinfo->SD_cid.ProdSN|=tmp<<16;    tmp=(u8)(pHandle->CID_Tab[2]&0x000000FF);        //第11个字节cardinfo->SD_cid.ProdSN|=tmp<<8;         tmp=(u8)((pHandle->CID_Tab[3]&0xFF000000)>>24);    //第12个字节cardinfo->SD_cid.ProdSN|=tmp;                tmp=(u8)((pHandle->CID_Tab[3]&0x00FF0000)>>16);      //第13个字节cardinfo->SD_cid.Reserved1|=(tmp&0xF0)>>4;cardinfo->SD_cid.ManufactDate=(tmp&0x0F)<<8;    tmp=(u8)((pHandle->CID_Tab[3]&0x0000FF00)>>8);      //第14个字节cardinfo->SD_cid.ManufactDate|=tmp;           tmp=(u8)(pHandle->CID_Tab[3]&0x000000FF);         //第15个字节cardinfo->SD_cid.CID_CRC=(tmp&0xFE)>>1;cardinfo->SD_cid.Reserved2=1;  return errorstatus;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_EnableWideBusMode(SDIO_SD_HANDLE *pHandle, bool isEnable4BusWide)
* 功能            :   使能4bit DAT线模式,如果失败将保持原来模式
* 参数            :   pHandle:服务器句柄;Enable:4bit模式;Disable:1bit模式
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   设置卡和控制器为4bit总线模式,线设置开启4线模式再开启高速时钟,必须先激活选中卡
*************************************************************************************************************************/
SDIO_Error SD_EnableWideBusMode(SDIO_SD_HANDLE *pHandle, bool isEnable4BusWide)
{SDIO_Error errorstatus = SDIO_OK;//SD卡不支持设置if (pHandle->CardType == SD_MULTIMEDIA_CARD){errorstatus = SDIO_UNSUPPORTED_FEATURE;return(errorstatus);}else //SD卡{if (isEnable4BusWide)    //4BIT模式{errorstatus = SDEnableWideBus(pHandle, TRUE); //设置SD卡为4bit总线模式if (errorstatus == SDIO_OK)                       //设置SD卡成功{pHandle->pInterface->SDIO_Set4BitBusWide(); //设置SDIO控制器为4线模式}   }else{errorstatus = SDEnableWideBus(pHandle, FALSE);   //设置SD卡为1bit总线模式if (errorstatus == SDIO_OK)                       //设置SD卡成功{pHandle->pInterface->SDIO_Set1BitBusWide(); //设置SDIO控制器为1线模式}}} return (errorstatus);
}/*************************************************************************************************************************
* 函数            :   static SDIO_Error SDEnableWideBus(SDIO_SD_HANDLE *pHandle, bool isEnableWideBus)
* 功能            :   设置SD卡宽总线模式
* 参数            :   pHandle:服务器句柄;isEnableWideBus:4bit模式;Disable:1bit模式
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   设置SD卡宽总线模式-需要先读取RCA
*************************************************************************************************************************/
static SDIO_Error SDEnableWideBus(SDIO_SD_HANDLE *pHandle, bool isEnableWideBus)
{SDIO_Error errorstatus = SDIO_OK;u32 temp;pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &temp);    //获取响应if (temp & SD_CARD_LOCKED) //锁了{errorstatus = SDIO_LOCK_UNLOCK_FAILED;return(errorstatus);}if (isEnableWideBus)  //使能4bit dat{//发送CMD55,SDIO_APP_CMD,激活卡//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应pHandle->pInterface->SDIO_SendCommand(CMD55, (u32)pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("CMD55 error(%d)!\r\n",errorstatus); //调试,打印错误信息return (errorstatus);}//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x2,短响应,R1pHandle->pInterface->SDIO_SendCommand(ACMD6, 0x2, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("ACMD6 error(%d)!\r\n",errorstatus);   //调试,打印错误信息return (errorstatus);}return (errorstatus);}   else  //设置为单线模式{//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应pHandle->pInterface->SDIO_SendCommand(CMD55, (u32)pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("CMD55 error(%d)!\r\n",errorstatus);  //调试,打印错误信息return (errorstatus);}//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x0,短响应,R1pHandle->pInterface->SDIO_SendCommand(ACMD6, 0x0, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("ACMD6 error(%d)!\r\n",errorstatus);   //调试,打印错误信息return (errorstatus);}return(errorstatus);}
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_SetBlockSize(SDIO_SD_HANDLE *pHandle, u16 BlockSize)
* 功能            :   设置SD卡块大小
* 参数            :   pHandle:句柄;BlockSize:设置SD卡块大小
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   通常取512B2020-02-21:尝试设置不同大小的块,以提高速度,但是SDHC卡是不支持设置块大小的
*************************************************************************************************************************/
SDIO_Error SD_SetBlockSize(SDIO_SD_HANDLE *pHandle, u16 BlockSize)
{SDIO_Error errorstatus = SDIO_OK;u32 temp;//如果卡锁定了则返回pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &temp); //获取响应if (temp & SD_CARD_LOCKED) //锁了{errorstatus = SDIO_LOCK_UNLOCK_FAILED;return(errorstatus);}//CMD16 Set Block Size for Card pHandle->pInterface->SDIO_SendCommand(CMD16, BlockSize, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("CMD16 ERROR %d\r\n",errorstatus);//如果失败了,尝试切换到512字节//CMD16 Set Block Size for Card pHandle->pInterface->SDIO_SendCommand(CMD16, 512, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("恢复默认配置失败 ,CMD16 ERROR %d\r\n",errorstatus);}else{pHandle->SDIO_BlockSize = GetSDIO_BlockSizeForSDBlock(512);               //SDIO传输块大小DEBUG("使用默认512B块大小,设置成功\r\n");}}else //设置成功了{pHandle->SDIO_BlockSize = GetSDIO_BlockSizeForSDBlock(BlockSize);          //SDIO传输块大小}return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_ReadBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff)
* 功能            :   读SD卡一个块
* 参数            :   pHandle:句柄;BlockAddr:块地址;BlockBuff:块缓冲区地址
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   读SD卡一个块
*************************************************************************************************************************/
SDIO_Error SD_ReadBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff)
{SDIO_Error errorstatus = SDIO_OK;u32 ReadLen;                 //读取的数据长度if (pBlockBuff == NULL)          //没有分配接收缓冲区,返回{errorstatus = SDIO_INVALID_PARAMETER;return(errorstatus);}if(pHandle->CardType != SD_HIGH_CAPACITY_SD_CARD){BlockAddr <<= 9;         //小容量卡,转换为字节单位}pHandle->pInterface->SDIO_ClearDataTrans();                                     //清除数据传输//发送CMD17 READ_SINGLE_BLOCK,块读取指令,参数:块地址,短回复,R1pHandle->pInterface->SDIO_SendCommand(CMD17, BlockAddr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                       //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{DEBUG("CMD17 error (%d)!\r\n",errorstatus);return(errorstatus);}pHandle->pInterface->SDIO_SetAndStartDataTrans(pBlockBuff, TRUE, pHandle->SDIO_BlockSize, pHandle->SDCardInfo.CardBlockSize); //初始化DMA,并准备读取数据errorstatus = pHandle->pInterface->SDIO_WaitTransComplete(TRUE, &ReadLen, 150);  //SDIO等待传输完成(等待读取或写入数据完成)(超时:150ms)if(errorstatus == SDIO_OK && ReadLen != pHandle->SDCardInfo.CardBlockSize){DEBUG("读取数据错误,需要读取:%dB,实际返回:%dB\r\n", pHandle->SDCardInfo.CardBlockSize, ReadLen);}return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_ReadMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff, u16 NumberOfBlocks)
* 功能            :   读SD卡多个块
* 参数            :   pHandle:句柄;BlockAddr:块地址;pBlockBuff:块缓冲区地址;NumberOfBlocks:块数量
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   20120516
* 最后修改时间    :   2018-03-28
* 说明            :   读SD卡多个(大于1个)块
*************************************************************************************************************************/
SDIO_Error SD_ReadMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff, u16 NumberOfBlocks)
{SDIO_Error errorstatus = SDIO_OK;SDIO_Error error1;u32 ReadLen;                   //读取的数据长度if (pBlockBuff == NULL)          //没有分配接收缓冲区,返回{errorstatus = SDIO_INVALID_PARAMETER;return(errorstatus);}//限制读取的块数量if(NumberOfBlocks > pHandle->MaxTransBlockCount) {DEBUG("限制一次读取%d块,当前一次读取%d\r\n", pHandle->MaxTransBlockCount, NumberOfBlocks);NumberOfBlocks = pHandle->MaxTransBlockCount;}if(pHandle->CardType != SD_HIGH_CAPACITY_SD_CARD){BlockAddr <<= 9;           //小容量卡,转换为字节单位}pHandle->pInterface->SDIO_ClearDataTrans();                                     //清除数据传输//发送CMD18 SDIO_READ_MULT_BLOCK;多区段读命令,参数:开始地址,短返回,R1(发送后会不停的发送数据出来,需要CMD12命令取消发送)pHandle->pInterface->SDIO_SendCommand(CMD18, BlockAddr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                        //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD18 error (%d)!\r\n",errorstatus);return(errorstatus);}pHandle->pInterface->SDIO_SetAndStartDataTrans(pBlockBuff, TRUE, pHandle->SDIO_BlockSize, pHandle->SDCardInfo.CardBlockSize*NumberOfBlocks);  //初始化DMA开始读取数据errorstatus = pHandle->pInterface->SDIO_WaitTransComplete(TRUE, &ReadLen, 100*NumberOfBlocks);                                                 //SDIO等待传输完成(等待读取或写入数据完成)(超时:100ms*NumberOfBlocks)if(errorstatus == SDIO_OK && ReadLen != (pHandle->SDCardInfo.CardBlockSize*NumberOfBlocks)){DEBUG("读取数据错误,需要读取:%dB,实际返回:%dB\r\n", pHandle->SDCardInfo.CardBlockSize*NumberOfBlocks, ReadLen);}//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1pHandle->pInterface->SDIO_SendCommand(CMD12, 0, SDIO_Response_Short);error1 = pHandle->pInterface->SDIO_CmdResp1Error();if(error1 != SDIO_OK) //获取回复{DEBUG("CMD12 error (%d)!\r\n",error1);}return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_WriteBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, const u8 *pBlockBuff)
* 功能            :   写SD卡一个块
* 参数            :   BlockAddr:块地址;writebuff:写缓冲区地址
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-29
* 最后修改时间    :   2018-03-29
* 说明            :   写SD卡一个块
**************************************************************************************************************************/
SDIO_Error SD_WriteBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, const u8 *pBlockBuff)
{SDIO_Error errorstatus = SDIO_OK;u32 cardstatus = 0;u32 ReadLen = 0;u32 timeout;if (pBlockBuff == NULL){errorstatus = SDIO_INVALID_PARAMETER;return(errorstatus);}if(pHandle->CardType != SD_HIGH_CAPACITY_SD_CARD){BlockAddr <<= 9;          //小容量卡,转换为字节单位}//检查timeout = 100;   //超时100ms`do{//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;pHandle->pInterface->SDIO_SendCommand(CMD13, (u32) pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                       //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD13 error (%d)!\r\n",errorstatus);return(errorstatus);}pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &cardstatus);            //获取响应的状态if((cardstatus & 0x00000100) == 0) //没有准备好{SYS_DelayMS(1);   //延时}else //READY_FOR_DATA位有效,卡已经准备好写入了{break;}timeout --;}while (timeout);if (timeout == 0){DEBUG("等待卡写入超时,错误:%d\r\n",errorstatus);return(SDIO_ERROR);}pHandle->pInterface->SDIO_ClearDataTrans();                                      //清除数据传输//发送CMD24,SDIO_WRITE_SINGLE_BLOCK,写命令,参数:地址(大容量卡为块地址),短响应,R1pHandle->pInterface->SDIO_SendCommand(CMD24, BlockAddr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                        //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD24 error (%d)!\r\n",errorstatus);return(errorstatus);}//开始传输-写入数据pHandle->pInterface->SDIO_SetAndStartDataTrans((u8 *)pBlockBuff, FALSE, pHandle->SDIO_BlockSize, pHandle->SDCardInfo.CardBlockSize);//等待传输完成errorstatus = pHandle->pInterface->SDIO_WaitTransComplete(FALSE, &ReadLen, 150);//SDIO等待传输完成(等待读取或写入数据完成)(超时:150ms)if(errorstatus == SDIO_OK && ReadLen != pHandle->SDCardInfo.CardBlockSize){DEBUG("写入数据错误,需要写入:%dB,实际写入:%dB\r\n", pHandle->SDCardInfo.CardBlockSize, ReadLen);}//读取卡编程状态,等待写入完成errorstatus = SD_WaitProgrammingFinish(pHandle, 100);                            //等待编程完成return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_WriteMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, const u8 *pBlockBuff, u16 NumberOfBlocks)
* 功能            :   写SD卡多个块
* 参数            :   pHandle:句柄;BlockAddr:块地址;BlockBuff:块缓冲区地址NumberOfBlocks:块数量
* 返回            :   SD_OK:成功,其它见SD Card Error code.
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2018-03-30
* 最后修改时间    :   2018-03-30
* 说明            :   写SD卡多个(大于1个)块
**************************************************************************************************************************/
SDIO_Error SD_WriteMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, const u8 *pBlockBuff, u16 NumberOfBlocks)
{SDIO_Error errorstatus = SDIO_OK;u32 cardstatus = 0;u32 ReadLen = 0;u32 timeout;if (pBlockBuff == NULL){errorstatus = SDIO_INVALID_PARAMETER;return(errorstatus);}//限制读取的块数量if(NumberOfBlocks > pHandle->MaxTransBlockCount) {DEBUG("限制一次读取%d块,当前一次读取%d\r\n", pHandle->MaxTransBlockCount, NumberOfBlocks);NumberOfBlocks = pHandle->MaxTransBlockCount;}//地址检查if(pHandle->CardType != SD_HIGH_CAPACITY_SD_CARD){BlockAddr <<= 9;          //小容量卡,转换为字节单位}//检查timeout = 100;   //超时100ms`do{//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;pHandle->pInterface->SDIO_SendCommand(CMD13, (u32) pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                       //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD13 error (%d)!\r\n",errorstatus);return(errorstatus);}pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &cardstatus);            //获取响应的状态if((cardstatus & 0x00000100) == 0) //没有准备好{SYS_DelayMS(1);   //延时}else //READY_FOR_DATA位有效,卡已经准备好写入了{break;}timeout --;}while (timeout);if (timeout == 0){DEBUG("等待卡写入超时,错误:%d(状态0x%X)\r\n",errorstatus,cardstatus);return(SDIO_ERROR);}pHandle->pInterface->SDIO_ClearDataTrans();                                       //清除数据传输//发送CMD25,SDIO_WRITE_MULT_BLOCK,参数:字节地址(大容量卡为块地址),短返回,R1pHandle->pInterface->SDIO_SendCommand(CMD25, BlockAddr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                        //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD25 error (%d)!\r\n",errorstatus);return(errorstatus);}//开始传输-写入数据pHandle->pInterface->SDIO_SetAndStartDataTrans((u8 *)pBlockBuff, FALSE, pHandle->SDIO_BlockSize, pHandle->SDCardInfo.CardBlockSize*NumberOfBlocks);//等待传输完成errorstatus = pHandle->pInterface->SDIO_WaitTransComplete(FALSE, &ReadLen, 100*NumberOfBlocks);//SDIO等待传输完成(等待读取或写入数据完成)(超时:100ms*NumberOfBlocks)if(errorstatus == SDIO_OK && ReadLen != (pHandle->SDCardInfo.CardBlockSize*NumberOfBlocks)){DEBUG("写入数据错误,需要写入:%dB,实际写入:%dB\r\n", pHandle->SDCardInfo.CardBlockSize, ReadLen);}//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1pHandle->pInterface->SDIO_SendCommand(CMD12, 0, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                       //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD12 error (%d)!\r\n",errorstatus);return(errorstatus);}//读取卡编程状态,等待写入完成errorstatus = SD_WaitProgrammingFinish(pHandle, 100);                            //等待编程完成return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_EraseBlock(SDIO_SD_HANDLE *pHandle,u32 BlockAddr, u32 NumberOfBlocks)
* 功能            :   擦除指定的块
* 参数            :   pHandle:句柄;BlockAddr:擦除的块地址;NumberOfBlocks:擦除的块数量
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2018-03-30
* 最后修改时间    :   2018-03-30
* 说明            :   地址必须是块地址-擦除特别慢
*************************************************************************************************************************/
SDIO_Error SD_EraseBlock(SDIO_SD_HANDLE *pHandle,u32 BlockAddr, u32 NumberOfBlocks)
{SDIO_Error errorstatus = SDIO_OK;/*!< Check if the card coomnd class supports erase command */if (((pHandle->CSD_Tab[1] >> 20) & SD_CCCC_ERASE) == 0)   //卡不支持擦除命令{errorstatus = SDIO_REQUEST_NOT_APPLICABLE;return (errorstatus);}//发送CMD32 ERASE_GROUP_START命令,写入擦除开始地址;参数:擦除开始地址,短响应,R1pHandle->pInterface->SDIO_SendCommand(CMD32, BlockAddr, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                       //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD32 error (%d)!\r\n",errorstatus);return(errorstatus);}//发送CMD33 SD_ERASE_GRP_END命令,写入擦除结束地址;参数:擦除结束地址,短响应,R1pHandle->pInterface->SDIO_SendCommand(CMD33, BlockAddr+NumberOfBlocks, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                      //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD33 error (%d)!\r\n",errorstatus);return(errorstatus);}//发送CMD38 ERASE命令,参数0,开始擦除,响应R1bpHandle->pInterface->SDIO_SendCommand(CMD38, 0, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();                      //获取回复if (errorstatus != SDIO_OK)                                                      //命令发送错误,返回{pHandle->pInterface->SDIO_ClearDataTrans();                                   //清除数据传输DEBUG("CMD38 error (%d)!\r\n",errorstatus);return(errorstatus);}  //读取卡编程状态,等待擦除完成errorstatus = SD_WaitProgrammingFinish(pHandle, NumberOfBlocks*500);           //等待编程完成return(errorstatus);
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_WaitProgrammingFinish(SDIO_SD_HANDLE *pHandle, u32 TimeOutMs)
* 功能            :   等待编程完成
* 参数            :   pHandle:句柄;TimeOutMs:通信超时时间
* 返回            :   SDIO_Error
* 依赖            :   底层宏定义
* 作者            :   cp1300@139.com
* 时间            :   2018-03-30
* 最后修改时间    :   2018-03-30
* 说明            :   用于写入完成后等待编程完成
*************************************************************************************************************************/
SDIO_Error SD_WaitProgrammingFinish(SDIO_SD_HANDLE *pHandle, u32 TimeOutMs)
{SDIO_Error Status = SDIO_OK;u32 respR1 = 0;u8 cardstate;while(TimeOutMs){//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;pHandle->pInterface->SDIO_SendCommand(CMD13, (u32) pHandle->RCA << 16, SDIO_Response_Short);Status = pHandle->pInterface->SDIO_CmdResp1Error();                              //获取回复if (Status != SDIO_OK)                                                           //命令发送错误,返回{DEBUG("CMD13 error (%d)!\r\n",Status);return(Status);}pHandle->pInterface->SDIO_GetResponse(SDIO_RESP_Short, &respR1);              //获取响应的状态//返回状态错误查询-加入以下状态可以在编程错误时方便找出问题if (respR1 & SDIO_OCR_ADDR_OUT_OF_RANGE){Status = (SDIO_ADDR_OUT_OF_RANGE);}else if (respR1 & SDIO_OCR_ADDR_MISALIGNED){Status = (SDIO_ADDR_MISALIGNED);}else if (respR1 & SDIO_OCR_BLOCK_LEN_ERR){Status =(SDIO_BLOCK_LEN_ERR);}else if (respR1 & SDIO_OCR_ERASE_SEQ_ERR){Status = (SDIO_ERASE_SEQ_ERR);}else if (respR1 & SDIO_OCR_BAD_ERASE_PARAM){Status = (SDIO_BAD_ERASE_PARAM);}else if (respR1 & SDIO_OCR_WRITE_PROT_VIOLATION){Status = (SDIO_WRITE_PROT_VIOLATION);}else if (respR1 & SDIO_OCR_LOCK_UNLOCK_FAILED){Status = (SDIO_LOCK_UNLOCK_FAILED);}else if (respR1 & SDIO_OCR_COM_CRC_FAILED){Status = (SDIO_COM_CRC_FAILED);}else if (respR1 & SDIO_OCR_ILLEGAL_CMD){Status = (SDIO_ILLEGAL_CMD);}else if (respR1 & SDIO_OCR_CARD_ECC_FAILED){Status = (SDIO_CARD_ECC_FAILED);}else if (respR1 & SDIO_OCR_CC_ERROR){Status = (SDIO_CC_ERROR);}else if (respR1 & SDIO_OCR_GENERAL_UNKNOWN_ERROR){Status =(SDIO_GENERAL_UNKNOWN_ERROR);}else if (respR1 & SDIO_OCR_STREAM_READ_UNDERRUN){Status = (SDIO_STREAM_READ_UNDERRUN);}else if (respR1 & SDIO_OCR_STREAM_WRITE_OVERRUN){Status = (SDIO_STREAM_WRITE_OVERRUN);}else if (respR1 & SDIO_OCR_CID_CSD_OVERWRIETE){Status = (SDIO_CID_CSD_OVERWRITE);}else if (respR1 & SDIO_OCR_WP_ERASE_SKIP){Status = (SDIO_WP_ERASE_SKIP);}else if (respR1 & SDIO_OCR_CARD_ECC_DISABLED){Status = (SDIO_CARD_ECC_DISABLED);}else if (respR1 & SDIO_OCR_ERASE_RESET){Status = (SDIO_ERASE_RESET);}else if (respR1 & SDIO_OCR_AKE_SEQ_ERROR){Status = (SDIO_AKE_SEQ_ERROR);}if (Status != SDIO_OK)                                                         //命令发送错误,返回{DEBUG("CMD13 resp error (%d)!\r\n",Status);return(Status);}/* Find out card status */cardstate = (u8) ((respR1 >> 9) & 0x0000000F);if((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))      //卡在编程中,等待{Status = SDIO_ERASE_RESET;   //等待编程完成超时SYS_DelayMS(1);}else {return SDIO_OK;     //操作成功了}TimeOutMs--;}return Status;
}/*************************************************************************************************************************
* 函数            :   SDIO_Error SD_GetSDSCR(SDIO_SD_HANDLE *pHandle, u32 pSCR[2])
* 功能            :   获取SCR信息
* 参数            :   pHandle:句柄;prca:RCA缓冲区指针
* 返回            :   SDIO_Error
* 依赖            :   底层寄存器操作函数
* 作者            :   cp1300@139.com
* 时间            :   2020-09-13
* 最后修改时间    :   2020-09-13
* 说明            :
*************************************************************************************************************************/
SDIO_Error SD_GetSDSCR(SDIO_SD_HANDLE *pHandle, u32 pSCR[2])
{SDIO_Error errorstatus = SDIO_OK;u32 cnt = 0;u8 Buff[8];//设置块大小为8字节//发送SDIO_SET_BLOCKLEN,参数8,短响应pHandle->pInterface->SDIO_SendCommand(CMD16, 8, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("SDIO_SET_BLOCKLEN error(%d)!\n",errorstatus);    //调试,打印错误信息goto _error;}//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应pHandle->pInterface->SDIO_SendCommand(SDIO_CMD_APP_CMD, (u32)pHandle->RCA << 16, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){goto _error;}pHandle->pInterface->SDIO_ClearDataTrans();                                       //清除数据传输//发送ACMD51 SD_APP_SEND_SCR,参数0,短响应,R1pHandle->pInterface->SDIO_SendCommand(SDIO_CMD_SDIO_APP_SEND_SCR, 0, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){goto _error;}pHandle->pInterface->SDIO_SetAndStartDataTrans(Buff, TRUE, SDIO_DataBlockSize_8B, 8);//设置SDIO并开始准备数据传输errorstatus = pHandle->pInterface->SDIO_WaitTransComplete(TRUE, &cnt, 500);if(errorstatus == SDIO_OK){pSCR[0] = Buff[0];pSCR[0] <<= 8;pSCR[0] |= Buff[1];pSCR[0] <<= 8;pSCR[0] |= Buff[2];pSCR[0] <<= 8;pSCR[0] |= Buff[3];pSCR[1] = Buff[4];pSCR[1] <<= 8;pSCR[1] |= Buff[5];pSCR[1] <<= 8;pSCR[1] |= Buff[6];pSCR[1] <<= 8;pSCR[1] |= Buff[7];}_error://恢复块大小为 SD_BLOCK_SIZEpHandle->pInterface->SDIO_SendCommand(CMD16, SD_BLOCK_SIZE, SDIO_Response_Short);errorstatus = pHandle->pInterface->SDIO_CmdResp1Error();if (errorstatus != SDIO_OK){DEBUG("SDIO_SET_BLOCKLEN error(%d)!\n",errorstatus);    //调试,打印错误信息}return (errorstatus);
}

//sdio_sdcard.h

/************************************************************************************************************** 文件名          :   sdio_sdcard.c* 功能               :   SDIO接口SD卡驱动* 作者             :   cp1300@139.com* 创建时间           :   2018-03-27* 最后修改时间      :   2018-03-27* 详细              :   源程序借鉴了意法STM32F103X库函数分离了底层SDIO接口,但是依赖一些数据定义,在sdio_const中
*************************************************************************************************************/
#ifndef _SDIO_SDCARD_H_
#define _SDIO_SDCARD_H_
#include "sdio_const.h"
#include "system.h"//SD卡 CSD
typedef struct       /* Card Specific Data */
{u8  CSDStruct;            /* CSD structure */u8  SysSpecVersion;       /* System specification version */u8  Reserved1;            /* Reserved */u8  TAAC;                 /* Data read access-time 1 */u8  NSAC;                 /* Data read access-time 2 in CLK cycles */u8  MaxBusClkFrec;        /* Max. bus clock frequency */u16 CardComdClasses;      /* Card command classes */u8  RdBlockLen;           /* Max. read data block length */u8  PartBlockRead;        /* Partial blocks for read allowed */u8  WrBlockMisalign;      /* Write block misalignment */u8  RdBlockMisalign;      /* Read block misalignment */u8  DSRImpl;              /* DSR implemented */u8  Reserved2;            /* Reserved */u16 DeviceSize;           /* Device Size */u8  MaxRdCurrentVDDMin;   /* Max. read current @ VDD min */u8  MaxRdCurrentVDDMax;   /* Max. read current @ VDD max */u8  MaxWrCurrentVDDMin;   /* Max. write current @ VDD min */u8  MaxWrCurrentVDDMax;   /* Max. write current @ VDD max */u8  DeviceSizeMul;        /* Device size multiplier */u8  EraseGrSize;          /* Erase group size */u8  EraseGrMul;           /* Erase group size multiplier */u8  WrProtectGrSize;      /* Write protect group size */u8  WrProtectGrEnable;    /* Write protect group enable */u8  ManDeflECC;           /* Manufacturer default ECC */u8  WrSpeedFact;          /* Write speed factor */u8  MaxWrBlockLen;        /* Max. write data block length */u8  WriteBlockPaPartial;  /* Partial blocks for write allowed */u8  Reserved3;            /* Reserded */u8  ContentProtectAppli;  /* Content protection application */u8  FileFormatGrouop;     /* File format group */u8  CopyFlag;             /* Copy flag (OTP) */u8  PermWrProtect;        /* Permanent write protection */u8  TempWrProtect;        /* Temporary write protection */u8  FileFormat;           /* File Format */u8  ECC;                  /* ECC code */u8  CSD_CRC;              /* CSD CRC */u8  Reserved4;            /* always 1*/
} SD_CSD;//SD卡CID
typedef struct      /*Card Identification Data*/
{u8  ManufacturerID;       /* ManufacturerID */u16 OEM_AppliID;          /* OEM/Application ID */u32 ProdName1;            /* Product Name part1 */u8  ProdName2;            /* Product Name part2*/u8  ProdRev;              /* Product Revision */u32 ProdSN;               /* Product Serial Number */u8  Reserved1;            /* Reserved1 */u16 ManufactDate;         /* Manufacturing Date */u8  CID_CRC;              /* CID CRC */u8  Reserved2;            /* always 1 */
} SD_CID;//SD卡信息
typedef struct
{SD_CSD SD_csd;SD_CID SD_cid;u64 CardCapacity;      //SD卡容量,单位:字节,最大支持2^64字节大小的卡u32 CardBlockSize;  //SD卡块大小    u16 RCA;            //卡相对地址u8 CardType;     //卡类型
} SD_CardInfo;/* Supported Memory Cards */
typedef enum
{SD_STD_CAPACITY_SD_CARD_V1_1       =  0x0,    //SD V1.1版SD_STD_CAPACITY_SD_CARD_V2_0      =  0x1,    //SD V2.0版SD_HIGH_CAPACITY_SD_CARD          =  0x2,    //大容量SD卡-必须以块为单位读取SD_MULTIMEDIA_CARD                =  0x3,    //MMC卡SD_SECURE_DIGITAL_IO_CARD         =  0x4,    //普通SD卡SD_HIGH_SPEED_MULTIMEDIA_CARD        =  0x5,    //高速SD卡SD_SECURE_DIGITAL_IO_COMBO_CARD  =  0x6,SD_HIGH_CAPACITY_MMC_CARD           =  0x7,    //大容量MMC卡
}SD_CARD_TYPE;//SD卡扇区大小定义-注意大容量卡不支持此设置,只能使用512字节
#define SD_BLOCK_SIZE       512                     //SD卡块大小
#if(SD_BLOCK_SIZE != 512 && SD_BLOCK_SIZE != 1024 && SD_BLOCK_SIZE != 2048 && SD_BLOCK_SIZE != 4096)
#error("无效的SD卡块大小");
#endif //SD_BLOCK_SIZE//获取与SD卡块大小对应的SDIO传输块大小
__inline SDIO_DataBlockSize GetSDIO_BlockSizeForSDBlock(u32 SD_BlockSize)
{switch(SD_BlockSize){case 512: return SDIO_DataBlockSize_512B;case 1024: return SDIO_DataBlockSize_1024B;case 2048: return SDIO_DataBlockSize_2048B;default:return SDIO_DataBlockSize_512B;}
}//SD接口
typedef struct
{void (*SDIO_Init)(void);                                                   //SDIO初始化void (*SDIO_SetLowSpeedClock)(void);                                       //SDIO设置低速时钟void (*SDIO_SetHighpeedClock)(void);                                        //SDIO设置高速时钟void (*SDIO_Set1BitBusWide)(void);                                          //SDIO设置单线模式void (*SDIO_Set4BitBusWide)(void);                                          //SDIO设置4线模式void (*SDIO_SendCommand)(u8 CmdIndex,u32 CmdArg,SDIO_WAIT_RESP WaitResp);   //SDIO发送一个命令void (*SDIO_SetAndStartDataTrans)(u8 *pDataBuff, bool isEnableReadData, SDIO_DataBlockSize SDIOBlockSize, u32 TransDataLen);//设置SDIO并开始准备数据传输void (*SDIO_ClearDataTrans)(void);                                         //SDIO清除数据传输SDIO_Error (*SDIO_WaitTransComplete)(bool isEnableReadData, u32 *pDataLen, u32 TimeOutMs);//SDIO等待传输完成(等待读取或写入数据完成)void (*SDIO_GetResponse)(SDIO_RESP_TYPE RespIndex, u32 *pRespData);            //获取返回响应状态 2020-09-12 更换接口形态,更通用一些SDIO_Error (*SDIO_CmdError)(void);                                         //获取指令执行状态(无响应)SDIO_Error (*SDIO_CmdResp1Error)(void);                                      //指令执行状态(R1)SDIO_Error (*SDIO_CmdResp2Error)(void);                                     //指令执行状态(R2,CID or CSD)SDIO_Error (*SDIO_CmdResp3Error)(void);                                      //指令执行状态(R3,OCR)SDIO_Error (*SDIO_CmdResp6Error)(u16*prca);                                 //指令执行状态(R6,RCA)SDIO_Error (*SDIO_CmdResp7Error)(void);                                     //获取指令执行状态(R7)u32 (*SDIO_GetMaxTransBlockCount)(void);                                  //获取最大传输块数量,2020-09-13新增接口
}SDIO_SD_INTERFACE;//SDIO句柄
typedef struct
{const SDIO_SD_INTERFACE *pInterface;                                       //所需的SDIO接口SD_CARD_TYPE CardType;                                                   //卡类型u32 CSD_Tab[4];u32 CID_Tab[4];u32 SCR_Tab[2];u32 RCA;u32 MaxTransBlockCount;                                                       //SD卡控制器一次能传输的块最大数量SD_CardInfo SDCardInfo;                                                      //SD卡信息SDIO_DataBlockSize SDIO_BlockSize;                                           //SD卡block大小
}SDIO_SD_HANDLE;//相关接口
void SD_InterfaceInit(SDIO_SD_HANDLE *pHandle, const SDIO_SD_INTERFACE *pInterface);                        //SD卡底层接口初始化
SDIO_Error SD_Init(SDIO_SD_HANDLE *pHandle);                                                                //SD卡初始化
SDIO_Error SD_ReadStatus(SDIO_SD_HANDLE *pHandle, u32 *pSCR);                                               //读取SD卡状态寄存器
SDIO_Error SD_ReadBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff);                            //读SD卡一个块
SDIO_Error SD_ReadMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr, u8 *pBlockBuff, u16 NumberOfBlocks);  //读取SD卡多个块
SDIO_Error SD_WriteBlock(SDIO_SD_HANDLE *pHandle, u32 BlockAddr,const  u8 *pBlockBuff);                             //写SD卡一个块
SDIO_Error SD_WriteMultiBlocks(SDIO_SD_HANDLE *pHandle, u32 BlockAddr,const  u8 *pBlockBuff, u16 NumberOfBlocks);   //写SD卡多个块
SDIO_Error SD_EraseBlock(SDIO_SD_HANDLE *pHandle,u32 BlockAddr, u32 NumberOfBlocks);                        //擦除指定的块#endif //_SDIO_SDCARD_H_

//中间层接口

/************************************************************************************************************** 文件名          :   SDIO_SD_Interface.c* 功能             :   SD卡所需的SDIO接口* 作者                :   cp1300@139.com* 创建时间           :   2018-03-27* 最后修改时间      :   2018-03-27* 详细              :   定义了SDIO SD卡所需的底层SDIO接口
*************************************************************************************************************/
#include "system.h"
#include "SDIO_SD_Interface.h"
#include "sdio.h"
#include "sdio_const.h"
#include "board.h"void BI_SDIO_Init(void);                    //SDIO SD卡初始化
void BI_SDIO_SetLowSpeedClock(void);        //SDIO设置低速时钟
void BI_SDIO_SetHighpeedClock(void);        //SDIO设置高速时钟
void BI_SDIO_Set1BitBusWide(void);          //SDIO设置单线模式
void BI_SDIO_Set4BitBusWide(void);          //SDIO设置4线模式//默认的SD卡接口
const SDIO_SD_INTERFACE g_DefaultSD_Interface =
{BI_SDIO_Init,                  //SDIO初始化BI_SDIO_SetLowSpeedClock,      //SDIO设置低速时钟BI_SDIO_SetHighpeedClock,       //SDIO设置高速时钟BI_SDIO_Set1BitBusWide,         //SDIO设置单线模式BI_SDIO_Set4BitBusWide,         //SDIO设置4线模式SDIO_SendCommand,               //SDIO发送一个命令SDIO_SetAndStartDataTrans,      //SDIO设置并开始数据传输SDIO_ClearDataTrans,         //SDIO清除数据传输SDIO_WaitTransComplete,         //SDIO等待传输完成(等待读取或写入数据完成)SDIO_GetResponse,                //获取返回响应状态SDIO_CmdError,                    //获取指令执行状态(无响应)SDIO_CmdResp1Error,              //指令执行状态(R1)SDIO_CmdResp2Error,             //指令执行状态(R2,CID or CSD)SDIO_CmdResp3Error,              //指令执行状态(R3,OCR)SDIO_CmdResp6Error,             //指令执行状态(R6,RCA)SDIO_CmdResp7Error,             //获取指令执行状态(R7)SDIO_GetMaxTransBlockCount,       //获取最大传输块数量,2020-09-13新增接口
};//SDIO SD卡初始化
void BI_SDIO_Init(void)
{//SDIO 相关IO初始化SYS_GPIOx_SetAF(GPIO_PD6_SD0_nCD);SYS_GPIOx_SetAF(GPIO_PD5_SD0_DATA3);SYS_GPIOx_SetAF(GPIO_PD4_SD0_DATA2);SYS_GPIOx_SetAF(GPIO_PD3_SD0_DATA1);SYS_GPIOx_SetAF(GPIO_PD2_SD0_DATA0);SYS_GPIOx_SetAF(GPIO_PD1_SD0_SCK);SYS_GPIOx_SetAF(GPIO_PD0_SD0_CMD);SDIO_Init();                   //SDIO接口初始化SDIO_SetPortSelect(0);           //设置SDIO当前port(0-1)SDIO_SetOut74Clock();            //SDIO输出74个时钟
}//SDIO设置低速时钟
void BI_SDIO_SetLowSpeedClock(void)
{SDIO_SetClockSpeed(SDIO_CLK_400K);             //SDIO设置时钟速度
}//SDIO设置高速时钟
void BI_SDIO_SetHighpeedClock(void)
{SDIO_SetClockSpeed(SDIO_CLK_25M);              //SDIO设置时钟速度
}//SDIO设置单线模式
void BI_SDIO_Set1BitBusWide(void)
{SDIO_SetBusWide(SDIO_BusWide_1b);  //SDIO设置总线宽度
}//SDIO设置4线模式
void BI_SDIO_Set4BitBusWide(void)
{SDIO_SetBusWide(SDIO_BusWide_4b);  //SDIO设置总线宽度
}   

//测试

#include "typedef.h"
#include "nuc970_system.h"
#include "uart.h"
#include "stdlib.h"
#include "timer.h"
#include "main.h"
#include "test.h"
#include "sdio_sdcard.h"
#include "sdio_sd_interface.h"
#include "stdio.h"//sd卡测试
void sdcard_test(void)
{u8 *pDataBuff = (u8 *)malloc(4096);u32 len;SDIO_Error Status;u32 i;STOP_WATCH_HANDLE mStopWatchHandle;SD_InterfaceInit(&g_SysGlobal.mSD0_Handle, &g_DefaultSD_Interface);     //SD卡底层接口初始化while(SD_Init(&g_SysGlobal.mSD0_Handle) != SDIO_OK){SYS_DelayMS(1000);}//扇区读取g_mStopWatchClass.Restart(&mStopWatchHandle);g_mStopWatchClass.Start(&mStopWatchHandle);Status = SD_ReadBlock(&g_SysGlobal.mSD0_Handle, 0, pDataBuff);           //读SD卡一个块g_mStopWatchClass.Stop(&mStopWatchHandle);uart_printf("\r\n读取一个扇区耗时:%lluus\r\n", g_mStopWatchClass.GetElapsedUs(&mStopWatchHandle));if(SDIO_OK == Status){uart_printf("读取一个扇区成功:\r\n");//SD卡扇区读取成功for(i = 0;i < 512;i ++){uart_printf("%02X ", pDataBuff[i]);}uart_printf("\r\n");}else{uart_printf("读取一个扇区错误:%d\r\n", Status);}//写单个扇区pDataBuff[10] = 0x35;pDataBuff[20] = 0x68;g_mStopWatchClass.Restart(&mStopWatchHandle);g_mStopWatchClass.Start(&mStopWatchHandle);Status = SD_WriteBlock(&g_SysGlobal.mSD0_Handle, 0, pDataBuff);          //写SD卡一个块g_mStopWatchClass.Stop(&mStopWatchHandle);uart_printf("\r\n写一个扇区耗时:%lluus\r\n", g_mStopWatchClass.GetElapsedUs(&mStopWatchHandle));if(SDIO_OK == Status){uart_printf("写一个扇区成功:\r\n");}else{uart_printf("写一个扇区错误:%d\r\n", Status);}//多扇区读取g_mStopWatchClass.Restart(&mStopWatchHandle);g_mStopWatchClass.Start(&mStopWatchHandle);Status = SD_ReadMultiBlocks(&g_SysGlobal.mSD0_Handle, 0, pDataBuff, 2);          //读SD卡2个块g_mStopWatchClass.Stop(&mStopWatchHandle);uart_printf("\r\n读取多个扇区耗时:%lluus\r\n", g_mStopWatchClass.GetElapsedUs(&mStopWatchHandle));if(SDIO_OK == Status){uart_printf("读取多个扇区成功:\r\n");//SD卡扇区读取成功for(i = 0;i < 1024;i ++){uart_printf("%02X ", pDataBuff[i]);}uart_printf("\r\n");}else{uart_printf("读取多个扇区错误:%d\r\n", Status);}//多扇区写入pDataBuff[10] ++;pDataBuff[20] ++;pDataBuff[512+10] ++;pDataBuff[512+20] ++;g_mStopWatchClass.Restart(&mStopWatchHandle);g_mStopWatchClass.Start(&mStopWatchHandle);Status = SD_WriteMultiBlocks(&g_SysGlobal.mSD0_Handle, 0, pDataBuff, 2);          //写SD卡2个块g_mStopWatchClass.Stop(&mStopWatchHandle);uart_printf("\r\n写多个扇区耗时:%lluus\r\n", g_mStopWatchClass.GetElapsedUs(&mStopWatchHandle));if(SDIO_OK == Status){uart_printf("写多个扇区成功:\r\n");}else{uart_printf("写多个扇区错误:%d\r\n", Status);}//释放内存free(pDataBuff);while(1){SYS_DelayMS(500);}
}

测试结果

NUC970 SD卡驱动(SDIO)相关推荐

  1. STM32F1与STM32CubeIDE快速入门-SD卡驱动-SDIO+FatFs

    SD卡驱动-SDIO+FatFs 文章目录 SD卡驱动-SDIO+FatFs 1.SDIO与FatFs简单介绍 2.SDIO与FatFs配置 3.SDIO与FatFs功能测试 4.代码解析 5.STM ...

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

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

  3. sd 卡驱动在2.6内核的编写.sd/mmc/sdio kernel,sd/mmc/sdio 内核

    [转帖请注明出处:blog.csdn.net/lanmanck] sd卡驱动主要参照已有的文件即可,2410,9260都挺好.其实写驱动主要是搞清楚工作流程即可.我这里写一些心得与大家分享下,基于2. ...

  4. rt-thread SDIO驱动框架分析(SD卡驱动\SD Nand驱动)

    rt-thread SDIO驱动框架分析之SD卡驱动 文章目录 rt-thread SDIO驱动框架分析之SD卡驱动 1. 前言 2. SDIO通用驱动框架介绍 3. 文件架构分析 4. SDIO设备 ...

  5. sd 卡驱动--基于高通平台

    点击打开链接 内容来自以下博客: http://blog.csdn.net/qianjin0703/article/details/5918041 Linux设备驱动子系统第二弹 - SD卡 (有介绍 ...

  6. SD卡驱动分析(二)

    三.下面分析一下高通的android2.3的代码中SD卡驱动的流程. 在kernel中,SD卡是作为平台设备加入到内核中去的,在/kernel/arch/arm/mach-msm/devices-ms ...

  7. SD卡驱动分析(一)

    Android下的SD卡驱动与标准LINUX下的SD卡驱动好像没有太大的区别,这里就以高通的ANDROID 2.3以代表,来简要分析一下LINUX下SD卡驱动的写法.由于小弟的技术有限,分析的有错的地 ...

  8. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  9. CE下基于Zylonite硬件平台的SD卡驱动开发

    摘要:本文结合实际项目(一款以WINCE为操作系统内核的GSM/PHS双模智能手机)对嵌入式系统Windows CE5.0的底层驱动(SD卡)的架构进行了分析和研究,以MARVELL公司提供的基于IN ...

最新文章

  1. flask中的flask_uploads上传文件
  2. android动态设置错误页面,Android中替换WebView加载网页失败时的页面
  3. iOS - OC 与 C 互相操作
  4. 川大和西南交大计算机考研难易度,2020考研:百所211院校报考难易度分析
  5. C++学习之Dev-C++安装与调试
  6. DeveloperAppleHelp
  7. vue 图片切换动态绑定
  8. linux 监控软件介绍,Linux中系统整体性能监控工具详细介绍
  9. 【RecSys】推荐系统和计算广告经典算法论文及实现总结
  10. c语言 库仑计_bq27520电量计的量产设计
  11. 技术与教研并驾齐驱,海风教育如何用模式创新定义教育智能新高度?
  12. python中np是什么意思_了解python中np是做什么的
  13. safair浏览器 在回调中跳转 window.open 打不开页面 但是有判断,跳转不了
  14. Cursor攻略,吃个螃蟹
  15. 数据恢复必备宝典—BMP文件详解
  16. 白平衡测试—imatest
  17. 【微信小程序】uniapp开发小程序如何使用微信云托管或云函数进行云开发
  18. 安全集成服务资质是什么都有哪些等级?申请安全集成服务资质认证有什么好处?
  19. csdn博客栏目装修大全------如何植入“微信打赏”、“微信公众号”等
  20. 如果“宜家”是款互联网产品,那它就是款烂产品!

热门文章

  1. 淘宝最基础的优化:标题优化
  2. c语言binsearch函数头文件,C++ binary_search()函数详解
  3. android 修改已建工程的api版本,更改API级Android Studio
  4. docker java -jar_使用Docker安装Java镜像运行jar包方法
  5. python 自动输入文字_pyautogui和pyperclip实现自动输入中文
  6. 程序员一周内了解一个行业的方法
  7. 第七周OJ—百位数的分解
  8. HDU4489 动归解决
  9. bsoj 1512 金明的预算方案(树型DP)
  10. 【中科三方】高防DNS如何实现对DDoS攻击的流量清洗?