#include "sdio_sdcard.h"
#include "string.h"
SD_CardInfo SDCardInfo ; //SD卡信息
u8 CardType=SDIO_STD_CAPACITY_SD_CARD_V1_1 ; //SD卡類型
/***************************************************
Name :SDIO_Clock_Set
Function :SDIO發送命令函數
Paramater :
cmdindex:命令索引,低六位有效
waitrsp:期待的相應
00/10:無響應
01:短響應
11:長響應
arg:參數
Return :錯誤代碼
***************************************************/
void SDIO_Send_Cmd( u8 cmdindex, u8 waitrsp, u32 arg )
{
u32 tmpreg ;
SDIO->ARG = arg ;
tmpreg = SDIO->CMD ;
tmpreg &= 0xFFFFF800 ; //清除index和waitrsp
tmpreg |= cmdindex&0X3F ; //設置新的index
tmpreg |= waitrsp<<6 ; //設置新的wait rsp
tmpreg |= 0<<8 ; //無等待
tmpreg |= 1<<10 ; //命令通道狀態機使能
SDIO->CMD = tmpreg ;
}
/***************************************************
Name :SDIO_Send_Data_Cfg
Function :SDIO發送數據配置函數
Paramater :
datatimeout:超時時間設置
datalen:傳輸數據長度,低25位有效,必須為塊大小的整數倍
blksize:塊大小.實際大小為:2^blksize字節
dir:數據傳輸方向
0:控制器到卡
1:卡到控制器
Return :錯誤代碼
***************************************************/
void SDIO_Send_Data_Cfg( u32 datatimeout, u32 datalen, u8 blksize, u8 dir )
{
u32 tmpreg;
SDIO->DTIMER = datatimeout ;
SDIO->DLEN = datalen&0x1FFFFFF ; //低25位有效
tmpreg = SDIO->DCTRL ;
tmpreg &= 0xFFFFFF08 ; //清除之前的設置
tmpreg |= blksize<<4 ; //設置塊大小
tmpreg |= 0<<2 ; //塊數據傳輸
tmpreg |= ( dir&0x01 )<<1 ; //方向控制
tmpreg |= 1<<0 ; //數據傳輸使能,DPSM狀態機
SDIO->DCTRL = tmpreg ;
}
/***************************************************
Name :SDIO_Clock_Set
Function :SDIO時鐘初始化設置
Paramater :
clkdiv:時鐘分頻系數
Return :錯誤代碼
***************************************************/
void SDIO_Clock_Set( u8 clkdiv )
{
u32 tmpreg = SDIO->CLKCR ;
tmpreg &= 0xFFFFFF00 ;
tmpreg |= clkdiv;
SDIO->CLKCR = tmpreg ;
}
/***************************************************
Name :CmdError
Function :檢查CMD0的執行狀態
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error CmdError()
{
SD_Error errorstatus = SD_OK ;
u32 timeout=SDIO_CMD0TIMEOUT ;
while( timeout-- )
{
//命令已發送(無需響應)
if( SDIO->STA&( 1<<7 ) )
break ;
}
if( timeout==0 )
return SD_CMD_RSP_TIMEOUT ;
SDIO->ICR = 0x5FF ; //清除標記
return errorstatus ;
}
/***************************************************
Name :CmdResp7Error
Function :檢查R7響應的錯誤狀態
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error CmdResp7Error()
{
u32 status ;
u32 timeout = 0x00010000 ;
while( timeout-- )
{
status = SDIO->STA ;
if( ( status&0x45 )!=0 ) //等待接收到應答
break ;
}
//響應超時
if( ( timeout==0 )||( ( status&0x04 )==0x04 ) )
{
//當前卡不是2.0兼容卡,或者不支持設定的電壓范圍
SDIO->ICR |= 1<<2 ; //清除命令響應超時標志
return SD_CMD_RSP_TIMEOUT ;
}
//成功接收到響應
if( ( status&0x40 )==0x40 )
SDIO->ICR |= 1<<6 ; //清除響應標志
return SD_OK ;
}
/***************************************************
Name :CmdResp1Error
Function :檢查R1響應的錯誤狀態
Paramater :
cmd:當前命令
Return :錯誤代碼
***************************************************/
SD_Error CmdResp1Error( u8 cmd )
{
u32 status ;
while( 1 )
{
status = SDIO->STA ;
if( ( status&0x45 )!=0 ) //等待接收到應答
break ;
}
//響應超時
if( ( status&0x04 )==0x04 )
{
SDIO->ICR |= 1<<2 ; //清除命令響應超時標志
return SD_CMD_RSP_TIMEOUT ;
}
//CRC錯誤
if( ( status&0x01 )==0x01 )
{
SDIO->ICR |= 1<<0; //清除標志
return SD_CMD_CRC_FAIL;
}
if( SDIO->RESPCMD!=cmd )
return SD_ILLEGAL_CMD ; //命令不匹配
SDIO->ICR = 0x5FF ; //清除標記
return ( SD_Error )( SDIO->RESP1&0xFDFFE008 ) ; //返回卡響應
}
/***************************************************
Name :CmdResp3Error
Function :檢查R3響應的錯誤狀態
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error CmdResp3Error()
{
u32 status ;
while( 1 )
{
status = SDIO->STA ;
if( ( status&0x45 )!=0 ) //等待接收到應答
break ;
}
//響應超時
if( ( status&0x04 )==0x04 )
{
SDIO->ICR |= 1<<2 ; //清除命令響應超時標志
return SD_CMD_RSP_TIMEOUT ;
}
SDIO->ICR = 0x5FF ; //清除標記
return SD_OK ;
}
/***************************************************
Name :CmdResp2Error
Function :檢查R2響應的錯誤狀態
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error CmdResp2Error()
{
u32 status ;
u32 timeout = 0x00010000 ;
while( timeout-- )
{
status = SDIO->STA ;
if( ( status&0x45 )!=0 ) //接收到R2響應
break ;
}
//響應超時
if( ( timeout==0 )||( ( status&0x04 )==0x04 ) )
{
SDIO->ICR |= 1<<2 ; //清除命令響應超時標志
return SD_CMD_RSP_TIMEOUT ;
}
//CRC錯誤
if( ( status&0x01 )==0x01 )
{
SDIO->ICR |= 1<<0 ; //清除響應標志
return SD_CMD_CRC_FAIL ;
}
SDIO->ICR = 0x5FF ; //清除標記
return SD_OK ;
}
/***************************************************
Name :CmdResp6Error
Function :檢查R6響應的錯誤狀態
Paramater :
cmd:之前發送的命令
prca:卡返回的RCA地址
Return :錯誤代碼
***************************************************/
SD_Error CmdResp6Error( u8 cmd, u16 *prca )
{
SD_Error errorstatus=SD_OK ;
u32 rspr1, status;
while(1)
{
status = SDIO->STA ;
//CRC錯誤/命令響應超時/已經收到響應(CRC校驗成功)
if( status&( (1<<0)|(1<<2)|(1<<6) ) )
break ;
}
//響應超時
if( status&( 1<<2 ) )
{
SDIO->ICR |= 1<<2 ; //清除命令響應超時標志
return SD_CMD_RSP_TIMEOUT ;
}
//CRC錯誤
if( status&1<<0 )
{
SDIO->ICR |= 1<<0 ; //清除響應標志
return SD_CMD_CRC_FAIL ;
}
//判斷是否響應cmd命令
if( SDIO->RESPCMD!=cmd )
return SD_ILLEGAL_CMD ;
SDIO->ICR = 0x5FF ; //清除所有標記
rspr1 = SDIO->RESP1 ; //得到響應
if( SD_ALLZERO==( rspr1&( SD_R6_GENERAL_UNKNOWN_ERROR|SD_R6_ILLEGAL_CMD|SD_R6_COM_CRC_FAILED ) ) )
{
*prca = ( u16 )( rspr1>>16 ) ; //右移16位得到,rca
return errorstatus ;
}
if( rspr1&SD_R6_GENERAL_UNKNOWN_ERROR )
return SD_GENERAL_UNKNOWN_ERROR ;
if( rspr1&SD_R6_ILLEGAL_CMD )
return SD_ILLEGAL_CMD ;
if( rspr1&SD_R6_COM_CRC_FAILED )
return SD_COM_CRC_FAILED ;
return errorstatus ;
}
/***************************************************
Name :SDIO_IRQHandler
Function :SDIO中斷服務函數
Paramater :None
Return :錯誤代碼
***************************************************/
void SDIO_IRQHandler()
{
//接收完成中斷
if( SDIO->STA&( 1<<8 ) )
{
SDIO_Send_Cmd( SD_CMD_STOP_TRANSMISSION, 1, 0 ) ; //發送CMD12,結束傳輸
SDIO->ICR |= 1<<8 ; //清除完成中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
//數據CRC錯誤
if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清除中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
//數據超時錯誤
if( SDIO->STA&( 1<<3 ) )
{
SDIO->ICR |= 1<<3 ; //清除中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
//FIFO上溢錯誤
if( SDIO->STA&( 1<<5 ) )
{
SDIO->ICR |= 1<<5 ; //清除中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
//FIFO下溢錯誤
if( SDIO->STA&( 1<<4 ) )
{
SDIO->ICR |= 1<<4 ; //清除中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
//起始位錯誤
if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清除中斷標記
SDIO->MASK &= ~( ( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<14 )|( 1<<15 )|( 1<<4 )|( 1<<5 )|( 1<<9 ) ) ; //關閉相關中斷
}
}
/***************************************************
Name :SD_PowerON
Function :卡上電
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error SD_PowerON()
{
u8 i=0 ;
SD_Error errorstatus=SD_OK ;
u32 response=0, count=0, validvoltage=0 ;
u32 SDType=SD_STD_CAPACITY ;
//配置CLKCR寄存器
SDIO->CLKCR = 0 ; //清空CLKCR之前的設置
SDIO->CLKCR |= 0<<9 ; //非省電模式
SDIO->CLKCR |= 0<<10 ; //關閉旁路,CK根據分頻設置輸出
SDIO->CLKCR |= 0<<11 ; //1位數據寬度
SDIO->CLKCR |= 0<<13 ; //SDIOCLK上升沿產生SDIOCK
SDIO->CLKCR |= 0<<14 ; //關閉硬件流控制
SDIO_Clock_Set( SDIO_INIT_CLK_DIV ) ; //設置時鐘頻率(初始化的時候,不能超過400Khz)
SDIO->POWER = 0x03 ; //上電狀態,開啟卡時鐘
SDIO->CLKCR |= 1<<8 ; //SDIOCK使能
for( i=0; i<74; i++ )
{
SDIO_Send_Cmd( SD_CMD_GO_IDLE_STATE, 0, 0 ) ; //發送CMD0進入IDLE STAGE模式命令
errorstatus = CmdError() ;
if( errorstatus==SD_OK )
break ;
}
//返回錯誤狀態
if( errorstatus )
return errorstatus ;
SDIO_Send_Cmd( SDIO_SEND_IF_COND, 1, SD_CHECK_PATTERN ) ; //發送CMD8,短響應,檢查SD卡接口特性
errorstatus = CmdResp7Error() ; //等待R7響應
//R7響應正常
if( errorstatus==SD_OK )
{
CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0 ; //SD 2.0卡
SDType = SD_HIGH_CAPACITY ; //高容量卡
}
SDIO_Send_Cmd( SD_CMD_APP_CMD, 1, 0 ) ; //發送CMD55,短響應
errorstatus = CmdResp1Error( SD_CMD_APP_CMD ) ; //等待R1響應
//SD2.0/SD 1.1,否則為MMC卡
if( errorstatus==SD_OK )
{
//SD卡,發送ACMD41 SD_APP_OP_COND,參數為:0x80100000
while( ( !validvoltage )&&( count1, 0 ) ; //發送CMD55,短響應
errorstatus = CmdResp1Error( SD_CMD_APP_CMD ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Cmd( SD_CMD_SD_APP_OP_COND, 1, SD_VOLTAGE_WINDOW_SD|SDType ); //發送ACMD41,短響應
errorstatus = CmdResp3Error() ; //等待R3響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
response = SDIO->RESP1 ; //得到響應
validvoltage = ( ( ( response>>31 )==1 )?1:0 ) ; //判斷SD卡上電是否完成
count ++ ;
}
if( count>=SD_MAX_VOLT_TRIAL )
{
errorstatus = SD_INVALID_VOLTRANGE ;
return errorstatus ;
}
if( response&=SD_HIGH_CAPACITY )
CardType = SDIO_HIGH_CAPACITY_SD_CARD ;
}
return errorstatus ;
}
/***************************************************
Name :SD_InitializeCards
Function :初始化所有的卡
Paramater :None
Return :錯誤代碼
***************************************************/
u32 CSD_Tab[ 4 ], CID_Tab[ 4 ], RCA=0 ; //SD卡CSD,CID以及相對地址(RCA)數據
SD_Error SD_InitializeCards()
{
SD_Error errorstatus=SD_OK ;
u16 rca = 0x01 ;
//檢查電源狀態,確保為上電狀態
if( ( SDIO->POWER&0x03 )==0 )
return SD_REQUEST_NOT_APPLICABLE ;
//非SECURE_DIGITAL_IO_CARD
if( SDIO_SECURE_DIGITAL_IO_CARD!=CardType )
{
SDIO_Send_Cmd( SD_CMD_ALL_SEND_CID, 3, 0 ) ; //發送CMD2,取得CID,長響應
errorstatus = CmdResp2Error() ; //等待R2響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus;
CID_Tab[ 0 ] = SDIO->RESP1 ;
CID_Tab[ 1 ] = SDIO->RESP2 ;
CID_Tab[ 2 ] = SDIO->RESP3 ;
CID_Tab[ 3 ] = SDIO->RESP4 ;
}
//判斷卡類型
if( ( SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType )||( SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType )||( SDIO_SECURE_DIGITAL_IO_COMBO_CARD==CardType )||( SDIO_HIGH_CAPACITY_SD_CARD==CardType ) )
{
SDIO_Send_Cmd( SD_CMD_SET_REL_ADDR, 1, 0 ) ; //發送CMD3,短響應
errorstatus = CmdResp6Error( SD_CMD_SET_REL_ADDR, &rca ) ; //等待R6響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
if( SDIO_MULTIMEDIA_CARD==CardType )
{
SDIO_Send_Cmd( SD_CMD_SET_REL_ADDR, 1, ( u32 )( rca<<16 ) ) ; //發送CMD3,短響應
errorstatus = CmdResp2Error() ; //等待R2響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
//非SECURE_DIGITAL_IO_CARD
if( SDIO_SECURE_DIGITAL_IO_CARD!=CardType )
{
RCA = rca ;
SDIO_Send_Cmd( SD_CMD_SEND_CSD, 3, ( u32 )( rca<<16 ) ) ; //發送CMD9+卡RCA,取得CSD,長響應
errorstatus = CmdResp2Error() ; //等待R2響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
CSD_Tab[ 0 ] = SDIO->RESP1 ;
CSD_Tab[ 1 ] = SDIO->RESP2 ;
CSD_Tab[ 2 ] = SDIO->RESP3 ;
CSD_Tab[ 3 ] = SDIO->RESP4 ;
}
return SD_OK ; //卡初始化成功
}
/***************************************************
Name :SD_GetCardInfo
Function :得到卡信息
Paramater :
cardinfo:卡信息存儲區
Return :錯誤代碼
***************************************************/
SD_Error SD_GetCardInfo( SD_CardInfo *cardinfo )
{
SD_Error errorstatus = SD_OK ;
u8 tmp = 0 ;
cardinfo->CardType = ( u8 )CardType ; //卡類型
cardinfo->RCA = ( u16 )RCA ; //卡RCA值
tmp = ( u8 )( ( CSD_Tab[ 0 ]&0xFF000000 )>>24 ) ;
cardinfo->SD_csd.CSDStruct = ( tmp&0xC0 )>>6 ; //CSD結構
cardinfo->SD_csd.SysSpecVersion = ( tmp&0x3C )>>2 ; //2.0協議還沒定義這部分(為保留),應該是后續協議定義的
cardinfo->SD_csd.Reserved1 = tmp&0x03 ; //2個保留位
tmp = ( u8 )( ( CSD_Tab[ 0 ]&0x00FF0000 )>>16 ) ; //第1個字節
cardinfo->SD_csd.TAAC = tmp ; //數據讀時間1
tmp = ( u8 )( ( CSD_Tab[ 0 ]&0x0000FF00 )>>8 ) ; //第2個字節
cardinfo->SD_csd.NSAC = tmp ; //數據讀時間2
tmp = ( u8 )( CSD_Tab[ 0 ]&0x000000FF ) ; //第3個字節
cardinfo->SD_csd.MaxBusClkFrec = tmp ; //傳輸速度
tmp = ( u8 )( ( CSD_Tab[ 1 ]&0xFF000000 )>>24 ) ; //第4個字節
cardinfo->SD_csd.CardComdClasses = tmp<<4 ; //卡指令類高四位
tmp = ( u8 )( ( CSD_Tab[ 1 ]&0x00FF0000 )>>16 ) ; //第5個字節
cardinfo->SD_csd.CardComdClasses |= ( tmp&0xF0 )>>4 ; //卡指令類低四位
cardinfo->SD_csd.RdBlockLen = tmp&0x0F ; //最大讀取數據長度
tmp = ( u8 )( ( CSD_Tab[ 1 ]&0x0000FF00 )>>8 ) ; //第6個字節
cardinfo->SD_csd.PartBlockRead = ( tmp&0x80 )>>7 ; //允許分塊讀
cardinfo->SD_csd.WrBlockMisalign = ( tmp&0x40 )>>6 ; //寫塊錯位
cardinfo->SD_csd.RdBlockMisalign = ( tmp&0x20 )>>5 ; //讀塊錯位
cardinfo->SD_csd.DSRImpl = ( tmp&0x10 )>>4 ;
cardinfo->SD_csd.Reserved2 = 0 ; //保留
//標準1.1/2.0卡/MMC卡
if( ( CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1 )||( CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0 )||( SDIO_MULTIMEDIA_CARD==CardType ) )
{
cardinfo->SD_csd.DeviceSize = ( tmp&0x03 )<<10 ; //C_SIZE(12位)
tmp = ( u8 )( CSD_Tab[ 1 ]&0x000000FF ) ; //第7個字節
cardinfo->SD_csd.DeviceSize |= tmp<<2 ;
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0xFF000000 )>>24 ); //第8個字節
cardinfo->SD_csd.DeviceSize |= ( tmp&0xC0 )>>6 ;
cardinfo->SD_csd.MaxRdCurrentVDDMin = ( tmp&0x38 )>>3 ;
cardinfo->SD_csd.MaxRdCurrentVDDMax = ( tmp&0x07 ) ;
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0x00FF0000 )>>16 ) ; //第9個字節
cardinfo->SD_csd.MaxWrCurrentVDDMin = ( tmp&0xE0 )>>5 ;
cardinfo->SD_csd.MaxWrCurrentVDDMax = ( tmp&0x1C )>>2 ;
cardinfo->SD_csd.DeviceSizeMul = ( tmp&0x03 )<<1 ; //C_SIZE_MULT
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0x0000FF00 )>>8 ) ; //第10個字節
cardinfo->SD_csd.DeviceSizeMul |= ( tmp&0x80 )>>7 ;
cardinfo->CardCapacity = ( cardinfo->SD_csd.DeviceSize+1 ) ; //計算卡容量
cardinfo->CardCapacity *= ( 1<<( cardinfo->SD_csd.DeviceSizeMul+2 ) ) ;
cardinfo->CardBlockSize = 1<<( cardinfo->SD_csd.RdBlockLen ) ; //塊大小
cardinfo->CardCapacity *= cardinfo->CardBlockSize ;
}
//高容量卡
else if( CardType==SDIO_HIGH_CAPACITY_SD_CARD )
{
tmp = ( u8 )( CSD_Tab[ 1 ]&0x000000FF ); //第7個字節
cardinfo->SD_csd.DeviceSize = ( tmp&0x3F )<<16 ; //C_SIZE
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0xFF000000 )>>24 ) ; //第8個字節
cardinfo->SD_csd.DeviceSize |= ( tmp<<8 ) ;
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0x00FF0000 )>>16 ) ; //第9個字節
cardinfo->SD_csd.DeviceSize |= tmp ;
tmp = ( u8 )( ( CSD_Tab[ 2 ]&0x0000FF00 )>>8 ) ; //第10個字節
cardinfo->CardCapacity = ( long long )( cardinfo->SD_csd.DeviceSize+1 )*512*1024 ; //計算卡容量
cardinfo->CardBlockSize = 512 ; //塊大小固定為512字節
}
cardinfo->SD_csd.EraseGrSize = ( tmp&0x40 )>>6 ;
cardinfo->SD_csd.EraseGrMul = ( tmp&0x3F )<<1 ;
tmp = ( u8 )( CSD_Tab[ 2 ]&0x000000FF ) ; //第11個字節
cardinfo->SD_csd.EraseGrMul |= ( tmp&0x80 )>>7 ;
cardinfo->SD_csd.WrProtectGrSize=( tmp&0x7F ) ;
tmp = ( u8 )( ( CSD_Tab[ 3 ]&0xFF000000 )>>24 ) ; //第12個字節
cardinfo->SD_csd.WrProtectGrEnable = ( tmp&0x80 )>>7 ;
cardinfo->SD_csd.ManDeflECC = ( tmp&0x60 )>>5 ;
cardinfo->SD_csd.WrSpeedFact = ( tmp&0x1C )>>2 ;
cardinfo->SD_csd.MaxWrBlockLen=( tmp&0x03 )<<2 ;
tmp = ( u8 )( ( CSD_Tab[ 3 ]&0x00FF0000 )>>16 ) ; //第13個字節
cardinfo->SD_csd.MaxWrBlockLen |= ( tmp&0xC0 )>>6 ;
cardinfo->SD_csd.WriteBlockPaPartial = ( tmp&0x20 )>>5 ;
cardinfo->SD_csd.Reserved3 = 0 ;
cardinfo->SD_csd.ContentProtectAppli=(tmp&0x01);
tmp = ( u8 )( ( CSD_Tab[ 3 ]&0x0000FF00 )>>8 ) ; //第14個字節
cardinfo->SD_csd.FileFormatGrouop = ( tmp&0x80 )>>7 ;
cardinfo->SD_csd.CopyFlag = ( tmp&0x40 )>>6 ;
cardinfo->SD_csd.PermWrProtect = ( tmp&0x20 )>>5 ;
cardinfo->SD_csd.TempWrProtect = ( tmp&0x10 )>>4 ;
cardinfo->SD_csd.FileFormat = ( tmp&0x0C )>>2 ;
cardinfo->SD_csd.ECC = ( tmp&0x03 ) ;
tmp = ( u8 )( CSD_Tab[ 3 ]&0x000000FF ) ; //第15個字節
cardinfo->SD_csd.CSD_CRC = ( tmp&0xFE )>>1 ;
cardinfo->SD_csd.Reserved4 = 1 ;
tmp = ( u8 )( ( CID_Tab[ 0 ]&0xFF000000 )>>24 ) ; //第0個字節
cardinfo->SD_cid.ManufacturerID = tmp ;
tmp = ( u8 )( ( CID_Tab[ 0 ]&0x00FF0000 )>>16 ) ; //第1個字節
cardinfo->SD_cid.OEM_AppliID=tmp<<8;
tmp = ( u8 )( ( CID_Tab[ 0 ]&0x000000FF00 )>>8 ) ; //第2個字節
cardinfo->SD_cid.OEM_AppliID |= tmp ;
tmp = ( u8 )( CID_Tab[ 0 ]&0x000000FF ) ; //第3個字節
cardinfo->SD_cid.ProdName1 = tmp<<24 ;
tmp = ( u8 )( ( CID_Tab[ 1 ]&0xFF000000 )>>24 ) ; //第4個字節
cardinfo->SD_cid.ProdName1 |= tmp<<16 ;
tmp = ( u8 )( ( CID_Tab[ 1 ]&0x00FF0000 )>>16 ) ; //第5個字節
cardinfo->SD_cid.ProdName1 |= tmp<<8 ;
tmp = ( u8 )( ( CID_Tab[ 1 ]&0x0000FF00 )>>8 ) ; //第6個字節
cardinfo->SD_cid.ProdName1 |= tmp ;
tmp = ( u8 )( CID_Tab[ 1 ]&0x000000FF ) ; //第7個字節
cardinfo->SD_cid.ProdName2 = tmp ;
tmp = ( u8 )( ( CID_Tab[ 2 ]&0xFF000000 )>>24 ) ; //第8個字節
cardinfo->SD_cid.ProdRev = tmp ;
tmp = ( u8 )( ( CID_Tab[ 2 ]&0x00FF0000 )>>16 ) ; //第9個字節
cardinfo->SD_cid.ProdSN = tmp<<24 ;
tmp = ( u8 )( ( CID_Tab[ 2 ]&0x0000FF00 )>>8 ) ; //第10個字節
cardinfo->SD_cid.ProdSN |= tmp<<16 ;
tmp = ( u8 )( CID_Tab[ 2 ]&0x000000FF ); //第11個字節
cardinfo->SD_cid.ProdSN |= tmp<<8 ;
tmp = ( u8 )( ( CID_Tab[ 3 ]&0xFF000000 )>>24 ) ; //第12個字節
cardinfo->SD_cid.ProdSN |= tmp ;
tmp = ( u8 )( ( CID_Tab[ 3 ]&0x00FF0000 )>>16 ) ; //第13個字節
cardinfo->SD_cid.Reserved1 |= ( tmp&0xF0 )>>4 ;
cardinfo->SD_cid.ManufactDate = ( tmp&0x0F )<<8 ;
tmp = ( u8 )( ( CID_Tab[ 3 ]&0x0000FF00 )>>8 ) ; //第14個字節
cardinfo->SD_cid.ManufactDate |= tmp ;
tmp = ( u8 )( CID_Tab[ 3 ]&0x000000FF ) ; //第15個字節
cardinfo->SD_cid.CID_CRC = ( tmp&0xFE )>>1 ;
cardinfo->SD_cid.Reserved2 = 1 ;
return errorstatus ;
}
/***************************************************
Name :FindSCR
Function :查找SD卡的SCR寄存器值
Paramater :
rca:卡相對地址
pscr:數據緩存區(存儲SCR內容)
Return :錯誤代碼
***************************************************/
SD_Error FindSCR( u16 rca, u32 *pscr )
{
u32 index = 0 ;
SD_Error errorstatus = SD_OK ;
u32 tempscr[ 2 ] = { 0, 0 } ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCKLEN, 1, 8 ) ; //發送CMD16,短響應,設置Block Size為8字節
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCKLEN ) ;
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Cmd( SD_CMD_APP_CMD, 1, ( u32 )rca<<16 ) ; //發送CMD55,短響應
errorstatus = CmdResp1Error( SD_CMD_APP_CMD ) ;
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, 8, 3, 1 ) ; //8個字節長度,block為8字節,SD卡到SDIO
SDIO_Send_Cmd( SD_CMD_SD_APP_SEND_SCR, 1, 0 ) ; //發送ACMD51,短響應,參數為0
errorstatus = CmdResp1Error( SD_CMD_SD_APP_SEND_SCR ) ;
if( errorstatus!=SD_OK )
return errorstatus ;
while( !( SDIO->STA&( SDIO_FLAG_RXOVERR|SDIO_FLAG_DCRCFAIL|SDIO_FLAG_DTIMEOUT|SDIO_FLAG_DBCKEND|SDIO_FLAG_STBITERR ) ) )
{
//接收FIFO數據可用
if( SDIO->STA&( 1<<21 ) )
{
*( tempscr+index ) = SDIO->FIFO ; //讀取FIFO內容
index ++ ;
if( index>=2 )
break ;
}
}
//接收數據超時
if( SDIO->STA&( 1<<3 ) )
{
SDIO->ICR |= 1<<3 ; //清除標記
return SD_DATA_TIMEOUT ;
}
//已發送/接收的數據塊CRC校驗錯誤
else if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清除標記
return SD_DATA_CRC_FAIL ;
}
//接收FIFO溢出
else if( SDIO->STA&( 1<<5 ) )
{
SDIO->ICR |= 1<<5 ; //清除標記
return SD_RX_OVERRUN ;
}
//起始位檢測錯誤
else if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清除標記
return SD_START_BIT_ERR ;
}
SDIO->ICR = 0X5FF ; //清除標記
//把數據順序按8位為單位倒過來.
*( pscr+1 ) = ( ( tempscr[ 0 ]&SD_0TO7BITS )<<24 )|( ( tempscr[ 0 ]&SD_8TO15BITS )<<8 )|( ( tempscr[ 0 ]&SD_16TO23BITS )>>8 )|( ( tempscr[ 0 ]&SD_24TO31BITS )>>24 ) ;
*( pscr ) = ( ( tempscr[ 1 ]&SD_0TO7BITS )<<24 )|( ( tempscr[ 1 ]&SD_8TO15BITS )<<8 )|( ( tempscr[ 1 ]&SD_16TO23BITS )>>8 )|( ( tempscr[ 1 ]&SD_24TO31BITS )>>24 ) ;
return errorstatus ;
}
/***************************************************
Name :SDEnWideBus
Function :SDIO使能寬總線模式
Paramater :
enx:使能開關
0:不使能
1:使能
Return :錯誤代碼
***************************************************/
SD_Error SDEnWideBus( u8 enx )
{
SD_Error errorstatus = SD_OK ;
u32 scr[ 2 ] = { 0, 0 } ;
u8 arg = 0x00 ;
if( enx )
arg = 0x02 ;
else
arg = 0x00 ;
//SD卡處于LOCKED狀態
if( SDIO->RESP1&SD_CARD_LOCKED )
return SD_LOCK_UNLOCK_FAILED ;
errorstatus = FindSCR( RCA, scr ); //得到SCR寄存器數據
if( errorstatus!=SD_OK )
return errorstatus ;
//支持寬總線
if( ( scr[ 1 ]&SD_WIDE_BUS_SUPPORT )!=SD_ALLZERO )
{
SDIO_Send_Cmd( SD_CMD_APP_CMD, 1, ( u32 )RCA<<16 ); //發送CMD55+RCA,短響應
errorstatus = CmdResp1Error( SD_CMD_APP_CMD ) ;
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Cmd( SD_CMD_APP_SD_SET_BUSWIDTH, 1, arg ) ; //發送ACMD6,短響應,參數:10,4位;00,1位
errorstatus = CmdResp1Error( SD_CMD_APP_SD_SET_BUSWIDTH ) ;
return errorstatus ;
}
else
return SD_REQUEST_NOT_APPLICABLE ; //不支持寬總線設置
}
/***************************************************
Name :SD_EnableWideBusOperation
Function :設置SDIO總線寬度
Paramater :
wmode:位寬模式
0->1位數據寬度
1->4位數據寬度
2->8位數據寬度
Return :錯誤代碼
***************************************************/
SD_Error SD_EnableWideBusOperation( u32 wmode )
{
SD_Error errorstatus = SD_OK ;
if( SDIO_MULTIMEDIA_CARD==CardType )
return SD_UNSUPPORTED_FEATURE ; //MMC卡不支持
else if( ( SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType )||( SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType )||( SDIO_HIGH_CAPACITY_SD_CARD==CardType ) )
{
if( wmode>=2 )
return SD_UNSUPPORTED_FEATURE ; //不支持8位模式
else
{
errorstatus = SDEnWideBus( wmode ) ;
if( SD_OK==errorstatus )
{
SDIO->CLKCR &= ~( 3<<11 ) ; //清除之前的位寬設置
SDIO->CLKCR |= ( u16 )wmode<<11 ; //1位/4位總線寬度
SDIO->CLKCR |= 0<<14 ; //不開啟硬件流控制
}
}
}
return errorstatus ;
}
/***************************************************
Name :SD_Init
Function :初始化SD卡
Paramater :None
Return :錯誤代碼
***************************************************/
SD_Error SD_Init()
{
u8 clkdiv=0 ;
SD_Error errorstatus=SD_OK ;
//SDIO IO口初始化
RCC->APB2ENR |= 1<<4 ; //使能PC時鐘
RCC->APB2ENR |= 1<<5 ; //使能PD時鐘
RCC->AHBENR |= 1<<10 ; //使能SDIO時鐘
RCC->AHBENR |= 1<<1 ; //使能DMA2時鐘
GPIOC->CRH &= 0xFFF00000 ;
GPIOC->CRH |= 0x000BBBBB ; //PC.8~12 復用輸出
GPIOD->CRL &= 0xFFFFF0FF ;
GPIOD->CRL |= 0x00000B00 ; //PD2復用輸出
//SDIO外設寄存器設置為默認值
SDIO->POWER = 0x00000000 ;
SDIO->CLKCR = 0x00000000 ;
SDIO->ARG = 0x00000000 ;
SDIO->CMD = 0x00000000 ;
SDIO->DTIMER = 0x00000000 ;
SDIO->DLEN = 0x00000000 ;
SDIO->DCTRL = 0x00000000 ;
SDIO->ICR = 0x00C007FF ;
SDIO->MASK = 0x00000000 ;
NVIC_Init( 0, 0, SDIO_IRQn, 2 ) ; //SDIO中斷配置
errorstatus = SD_PowerON() ; //SD卡上電
if( errorstatus==SD_OK )
errorstatus=SD_InitializeCards() ; //初始化SD卡
if( errorstatus==SD_OK )
errorstatus=SD_GetCardInfo( &SDCardInfo ) ; //獲取卡信息
if( errorstatus==SD_OK )
{
SDIO_Send_Cmd( SD_CMD_SEL_DESEL_CARD, 1, SDCardInfo.RCA<<16 ) ; //發送CMD7,選擇卡,短響應
errorstatus = CmdResp1Error( SD_CMD_SEL_DESEL_CARD ) ;
}
if( errorstatus==SD_OK )
errorstatus=SD_EnableWideBusOperation( 1 ) ; //4位寬度,如果是MMC卡,則不能用4位模式
if( ( errorstatus==SD_OK )||( SDIO_MULTIMEDIA_CARD==CardType ) )
{
if( ( SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1 )||( SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0 ) )
clkdiv = SDIO_TRANSFER_CLK_DIV+6 ; //V1.1/V2.0卡,設置最高72/12=6Mhz
else
clkdiv = SDIO_TRANSFER_CLK_DIV ; //SDHC等其他卡,設置最高72/6=12Mhz
SDIO_Clock_Set( clkdiv ); //設置時鐘頻率
}
return errorstatus ;
}
/***************************************************
Name :convert_from_bytes_to_power_of_two
Function :得到NumberOfBytes以2為底的指數
Paramater :
NumberOfBytes:字節數
Return :以2為底的指數值
***************************************************/
u8 convert_from_bytes_to_power_of_two( u16 NumberOfBytes )
{
u8 count=0 ;
while( NumberOfBytes!=1 )
{
NumberOfBytes >>= 1 ;
count ++ ;
}
return count ;
}
/***************************************************
Name :SD_ReadBlock
Function :讀取一個塊
Paramater :
buf:讀數據緩存區(必須4字節對齊)
addr:讀取地址
blksize:塊大小
Return :錯誤代碼
***************************************************/
SD_Error SD_ReadBlock( u8 *buf, long long addr, u16 blksize )
{
SD_Error errorstatus = SD_OK ;
u8 power ;
u32 count=0, *tempbuff=( u32* )buf ; //轉換為u32指針
u32 timeout = SDIO_DATATIMEOUT ;
if( NULL==buf )
return SD_INVALID_PARAMETER ;
SDIO->DCTRL = 0x0 ; //數據控制寄存器清零(關DMA)
//大容量卡
if( CardType==SDIO_HIGH_CAPACITY_SD_CARD )
{
blksize = 512 ;
addr >>= 9 ;
}
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, 0, 0, 0 ) ; //清除DPSM狀態機配置
//卡鎖了
if( SDIO->RESP1&SD_CARD_LOCKED )
return SD_LOCK_UNLOCK_FAILED ;
if( ( blksize>0 )&&( blksize<=2048 )&&( ( blksize&( blksize-1 ) )==0 ) )
{
power = convert_from_bytes_to_power_of_two( blksize ) ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCKLEN, 1, blksize ) ; //發送CMD16+設置數據長度為blksize,短響應
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCKLEN ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
else
return SD_INVALID_PARAMETER ;
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, blksize, power, 1 ) ; //blksize,卡到控制器
SDIO_Send_Cmd( SD_CMD_READ_SINGLE_BLOCK, 1, addr ) ; //發送CMD17+從addr地址出讀取數據,短響應
errorstatus = CmdResp1Error( SD_CMD_READ_SINGLE_BLOCK ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
__asm volatile( "cpsid i" ) ; //關閉總中斷(POLLING模式,嚴禁中斷打斷SDIO讀寫操作!!!)
//無上溢/CRC/超時/完成(標志)/起始位錯誤
while( !( SDIO->STA&( ( 1<<5 )|( 1<<1 )|( 1<<3 )|( 1<<10 )|( 1<<9 ) ) ) )
{
//接收區半滿,表示至少存了8個字
if( SDIO->STA&( 1<<15 ) )
{
for( count=0; count<8; count++ ) //循環讀取數據
*( tempbuff+count ) = SDIO->FIFO ;
tempbuff += 8 ;
timeout = 0x7FFFFF ; //讀數據溢出時間
}
//處理超時
else
{
if( timeout==0 )
return SD_DATA_TIMEOUT ;
timeout -- ;
}
}
//數據超時錯誤
if( SDIO->STA&( 1<<3 ) )
{
SDIO->ICR |= 1<<3 ; //清錯誤標志
return SD_DATA_TIMEOUT ;
}
//數據塊CRC錯誤
else if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清錯誤標志
return SD_DATA_CRC_FAIL ;
}
//接收FIFO上溢錯誤
else if( SDIO->STA&( 1<<5 ) )
{
SDIO->ICR |= 1<<5 ; //清錯誤標志
return SD_RX_OVERRUN ;
}
//接收起始位錯誤
else if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清錯誤標志
return SD_START_BIT_ERR ;
}
//FIFO里面,還存在可用數據
while( SDIO->STA&( 1<<21 ) )
{
*tempbuff = SDIO->FIFO ; //循環讀取數據
tempbuff ++ ;
}
__asm volatile( "cpsie i" ) ; //開啟總中斷
SDIO->ICR = 0x5FF ; //清除所有標記
return errorstatus ;
}
/***************************************************
Name :SD_ReadMultiBlocks
Function :讀取多個塊
Paramater :
buf:讀數據緩存區(必須4字節對齊)
addr:讀取地址
blksize:塊大小
nblks:要讀取的塊數
Return :錯誤代碼
***************************************************/
__align(4) u32 *tempbuff ;
SD_Error SD_ReadMultiBlocks( u8 *buf, long long addr, u16 blksize, u32 nblks )
{
SD_Error errorstatus = SD_OK ;
u8 power ;
u32 count = 0 ;
u32 timeout = SDIO_DATATIMEOUT ;
tempbuff = ( u32* )buf ; //轉換為u32指針
SDIO->DCTRL = 0x0 ; //數據控制寄存器清零(關DMA)
//大容量卡
if( CardType==SDIO_HIGH_CAPACITY_SD_CARD )
{
blksize = 512 ;
addr >>= 9 ;
}
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, 0, 0, 0 ) ; //清除DPSM狀態機配置
//卡鎖了
if( SDIO->RESP1&SD_CARD_LOCKED )
return SD_LOCK_UNLOCK_FAILED ;
if( ( blksize>0 )&&( blksize<=2048 )&&( ( blksize&( blksize-1 ) )==0 ) )
{
power = convert_from_bytes_to_power_of_two( blksize ) ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCKLEN, 1, blksize ) ; //發送CMD16+設置數據長度為blksize,短響應
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCKLEN ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
else
return SD_INVALID_PARAMETER ;
//多塊讀
if( nblks>1 )
{
//判斷是否超過最大接收長度
if( nblks*blksize>SD_MAX_DATA_LENGTH )
return SD_INVALID_PARAMETER ;
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, nblks*blksize, power, 1 ) ; //nblks*blksize,512塊大小,卡到控制器
SDIO_Send_Cmd( SD_CMD_READ_MULT_BLOCK, 1, addr ) ; //發送CMD18+從addr地址出讀取數據,短響應
errorstatus = CmdResp1Error( SD_CMD_READ_MULT_BLOCK ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
__asm volatile( "cpsid i" ) ; //關閉總中斷(POLLING模式,嚴禁中斷打斷SDIO讀寫操作!!!)
//無上溢/CRC/超時/完成(標志)/起始位錯誤
while( !( SDIO->STA&( ( 1<<5 )|( 1<<1 )|( 1<<3 )|( 1<<8 )|( 1<<9 ) ) ) )
{
//接收區半滿,表示至少存了8個字
if( SDIO->STA&( 1<<15 ) )
{
//循環讀取數據
for( count=0; count<8; count++ )
*( tempbuff+count ) = SDIO->FIFO ;
tempbuff += 8 ;
timeout = 0X7FFFFF ; //讀數據溢出時間
}
//處理超時
else
{
if( timeout==0 )
return SD_DATA_TIMEOUT ;
timeout -- ;
}
}
//數據超時錯誤
if( SDIO->STA&( 1<<3 ) )
{
SDIO->ICR |= 1<<3 ; //清錯誤標志
return SD_DATA_TIMEOUT;
}
//數據塊CRC錯誤
else if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清錯誤標志
return SD_DATA_CRC_FAIL ;
}
//接收fifo上溢錯誤
else if( SDIO->STA&( 1<<5 ) )
{
SDIO->ICR |= 1<<5 ; //清錯誤標志
return SD_RX_OVERRUN;
}
//接收起始位錯誤
else if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清錯誤標志
return SD_START_BIT_ERR ;
}
//FIFO里面,還存在可用數據
while( SDIO->STA&( 1<<21 ) )
{
*tempbuff = SDIO->FIFO ; //循環讀取數據
tempbuff ++ ;
}
//接收結束
if( SDIO->STA&( 1<<8 ) )
{
if( ( SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType )||( SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType )||( SDIO_HIGH_CAPACITY_SD_CARD==CardType ) )
{
SDIO_Send_Cmd( SD_CMD_STOP_TRANSMISSION, 1, 0 ) ; //發送CMD12+結束傳輸
errorstatus = CmdResp1Error( SD_CMD_STOP_TRANSMISSION ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
}
}
__asm volatile( "cpsie i" ) ; //開啟總中斷
SDIO->ICR = 0x5FF ; //清除所有標記
}
return errorstatus ;
}
/***************************************************
Name :IsCardProgramming
Function :檢查卡是否正在執行寫操作
Paramater :
pstatus:當前狀態
Return :錯誤代碼
***************************************************/
SD_Error IsCardProgramming( u8 *pstatus )
{
volatile u32 respR1=0, status=0 ;
SDIO_Send_Cmd( SD_CMD_SEND_STATUS, 1, ( u32 )RCA<<16 ) ; //發送CMD13
status = SDIO->STA ;
while( !( status&( ( 1<<0 )|( 1<<6 )|( 1<<2 ) ) ) )
status = SDIO->STA ; //等待操作完成
//CRC檢測失敗
if( status&( 1<<0 ) )
{
SDIO->ICR |= 1<<0 ; //清除錯誤標記
return SD_CMD_CRC_FAIL ;
}
//命令超時
if( status&( 1<<2 ) )
{
SDIO->ICR |= 1<<2 ; //清除錯誤標記
return SD_CMD_RSP_TIMEOUT ;
}
if( SDIO->RESPCMD!=SD_CMD_SEND_STATUS )
return SD_ILLEGAL_CMD ;
SDIO->ICR = 0X5FF ; //清除所有標記
respR1 = SDIO->RESP1 ;
*pstatus = ( u8 )( ( respR1>>9 )&0x0000000F ) ;
return SD_OK ;
}
/***************************************************
Name :SD_WriteBlock
Function :寫1個塊
Paramater :
buf:數據緩存區
addr:寫地址
blksize:塊大小
Return :錯誤代碼
***************************************************/
SD_Error SD_WriteBlock( u8 *buf, long long addr, u16 blksize )
{
SD_Error errorstatus = SD_OK ;
u8 power=0, cardstate=0 ;
u32 timeout=0, bytestransferred=0 ;
u32 cardstatus=0, count=0, restwords=0 ;
u32 tlen = blksize ; //總長度(字節)
u32*tempbuff = ( u32* )buf ;
//參數錯誤
if( buf==NULL )
return SD_INVALID_PARAMETER ;
SDIO->DCTRL = 0x0 ; //數據控制寄存器清零(關DMA)
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, 0, 0, 0 ) ; //清除DPSM狀態機配置
//卡鎖了
if( SDIO->RESP1&SD_CARD_LOCKED )
return SD_LOCK_UNLOCK_FAILED ;
//大容量卡
if( CardType==SDIO_HIGH_CAPACITY_SD_CARD )
{
blksize = 512 ;
addr >>= 9 ;
}
if( ( blksize>0 )&&( blksize<=2048 )&&( ( blksize&( blksize-1 ) )==0 ) )
{
power = convert_from_bytes_to_power_of_two( blksize ) ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCKLEN, 1, blksize ) ; //發送CMD16+設置數據長度為blksize,短響應
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCKLEN ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
else
return SD_INVALID_PARAMETER ;
SDIO_Send_Cmd( SD_CMD_SEND_STATUS, 1, ( u32 )RCA<<16 ) ; //發送CMD13,查詢卡的狀態,短響應
errorstatus = CmdResp1Error( SD_CMD_SEND_STATUS ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
cardstatus = SDIO->RESP1 ;
timeout = SD_DATATIMEOUT ;
//檢查READY_FOR_DATA位是否置位
while( ( ( cardstatus&0x00000100 )==0 )&&( timeout>0 ) )
{
timeout -- ;
SDIO_Send_Cmd( SD_CMD_SEND_STATUS, 1, ( u32 )RCA<<16 ) ; //發送CMD13,查詢卡的狀態,短響應
errorstatus = CmdResp1Error( SD_CMD_SEND_STATUS ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
cardstatus = SDIO->RESP1 ;
}
if( timeout==0 )
return SD_ERROR ;
SDIO_Send_Cmd( SD_CMD_WRITE_SINGLE_BLOCK, 1, addr ) ; //發送CMD24,寫單塊指令,短響應
errorstatus = CmdResp1Error( SD_CMD_WRITE_SINGLE_BLOCK ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, blksize, power, 0 ) ; //blksize, 控制器到卡
timeout = SDIO_DATATIMEOUT ;
__asm volatile( "cpsid i" ) ; //關閉總中斷(POLLING模式,嚴禁中斷打斷SDIO讀寫操作!!!)
//數據塊發送成功/下溢/CRC/超時/起始位錯誤
while( !( SDIO->STA&( ( 1<<10 )|( 1<<4 )|( 1<<1 )|( 1<<3 )|( 1<<9 ) ) ) )
{
//發送區半空,表示至少存了8個字
if( SDIO->STA&( 1<<14 ) )
{
//不夠32字節了
if( ( tlen-bytestransferred )4==0 )?( ( tlen-bytestransferred )/4 ):( ( tlen-bytestransferred )/4+1 ) ;
for( count=0; count4 )
SDIO->FIFO = *tempbuff ;
}
else
{
for( count=0; count<8; count++ )
SDIO->FIFO = *( tempbuff+count ) ;
tempbuff += 8 ;
bytestransferred += 32 ;
}
timeout = 0x3FFFFFFF ; //寫數據溢出時間
}
else
{
if( timeout==0 )
return SD_DATA_TIMEOUT ;
timeout -- ;
}
}
//數據超時錯誤
if( SDIO->STA&( 1<<3 ) )
{
SDIO->ICR |= 1<<3 ; //清錯誤標志
return SD_DATA_TIMEOUT ;
}
//數據塊CRC錯誤
else if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清錯誤標志
return SD_DATA_CRC_FAIL ;
}
//接收fifo下溢錯誤
else if( SDIO->STA&( 1<<4 ) )
{
SDIO->ICR |= 1<<4 ; //清錯誤標志
return SD_TX_UNDERRUN ;
}
//接收起始位錯誤
else if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清錯誤標志
return SD_START_BIT_ERR ;
}
__asm volatile( "cpsie i" ) ; //開啟總中斷
SDIO->ICR = 0x5FF ; //清除所有標記
SDIO->ICR = 0x5FF ; //清除所有標記
errorstatus = IsCardProgramming( &cardstate ) ;
while( ( errorstatus==SD_OK )&&( ( cardstate==SD_CARD_PROGRAMMING )||( cardstate==SD_CARD_RECEIVING ) ) )
errorstatus = IsCardProgramming( &cardstate ) ;
return errorstatus ;
}
/***************************************************
Name :SD_WriteMultiBlocks
Function :寫多個塊
Paramater :
buf:數據緩存區
addr:寫地址
blksize:塊大小
nblks:要寫入的塊數
Return :錯誤代碼
***************************************************/
SD_Error SD_WriteMultiBlocks( u8 *buf, long long addr, u16 blksize, u32 nblks )
{
SD_Error errorstatus = SD_OK ;
u8 power = 0, cardstate = 0 ;
u32 timeout=0, bytestransferred=0 ;
u32 count = 0, restwords = 0 ;
u32 tlen= nblks*blksize ; //總長度(字節)
u32 *tempbuff = ( u32* )buf ;
//參數錯誤
if( buf==NULL )
return SD_INVALID_PARAMETER ;
SDIO->DCTRL = 0x0 ; //數據控制寄存器清零(關DMA)
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, 0, 0, 0 ); //清除DPSM狀態機配置
//卡鎖了
if( SDIO->RESP1&SD_CARD_LOCKED )
return SD_LOCK_UNLOCK_FAILED ;
//大容量卡
if( CardType==SDIO_HIGH_CAPACITY_SD_CARD )
{
blksize = 512 ;
addr >>= 9 ;
}
if( ( blksize>0 )&&( blksize<=2048 )&&( ( blksize&( blksize-1 ) )==0 ) )
{
power = convert_from_bytes_to_power_of_two( blksize ) ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCKLEN, 1, blksize ) ; //發送CMD16+設置數據長度為blksize,短響應
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCKLEN ) ; //等待R1響應
//響應錯誤
if( errorstatus!=SD_OK )
return errorstatus ;
}
else
return SD_INVALID_PARAMETER ;
if( nblks>1 )
{
if( nblks*blksize>SD_MAX_DATA_LENGTH )
return SD_INVALID_PARAMETER ;
if( ( SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType )||( SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType )||( SDIO_HIGH_CAPACITY_SD_CARD==CardType ) )
{
//提高性能
SDIO_Send_Cmd( SD_CMD_APP_CMD, 1, ( u32 )RCA<<16 ); //發送ACMD55,短響應
errorstatus = CmdResp1Error( SD_CMD_APP_CMD ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Cmd( SD_CMD_SET_BLOCK_COUNT, 1, nblks ) ; //發送CMD23,設置塊數量,短響應
errorstatus = CmdResp1Error( SD_CMD_SET_BLOCK_COUNT ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
}
SDIO_Send_Cmd( SD_CMD_WRITE_MULT_BLOCK, 1, addr ) ; //發送CMD25,多塊寫指令,短響應
errorstatus = CmdResp1Error( SD_CMD_WRITE_MULT_BLOCK ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
SDIO_Send_Data_Cfg( SD_DATATIMEOUT, nblks*blksize, power, 0 ) ; //blksize控制器到卡
timeout = SDIO_DATATIMEOUT ;
__asm volatile( "cpsid i" ) ; //關閉總中斷(POLLING模式,嚴禁中斷打斷SDIO讀寫操作!!!)
//下溢/CRC/數據結束/超時/起始位錯誤
while( !( SDIO->STA&( ( 1<<4 )|( 1<<1) |( 1<<8 )|( 1<<3 )|( 1<<9 ) ) ) )
{
//發送區半空,表示至少存了8字(32字節)
if( SDIO->STA&( 1<<14 ) )
{
//不夠32字節了
if( ( tlen-bytestransferred )4==0 )?( ( tlen-bytestransferred )/4 ):( ( tlen-bytestransferred )/4+1 );
for( count=0; count4 )
SDIO->FIFO = *tempbuff ;
}
//發送區半空,可以發送至少8字(32字節)數據
else
{
for( count=0; countFIFO = *( tempbuff+count ) ;
tempbuff += SD_HALFFIFO ;
bytestransferred += SD_HALFFIFOBYTES ;
}
timeout = 0x3FFFFFFF ; //寫數據溢出時間
}
else
{
if( timeout==0 )
return SD_DATA_TIMEOUT ;
timeout -- ;
}
}
//數據超時錯誤
if(SDIO->STA&(1<<3))
{
SDIO->ICR |= 1<<3 ; //清錯誤標志
return SD_DATA_TIMEOUT ;
}
//數據塊CRC錯誤
else if( SDIO->STA&( 1<<1 ) )
{
SDIO->ICR |= 1<<1 ; //清錯誤標志
return SD_DATA_CRC_FAIL ;
}
//接收fifo下溢錯誤
else if( SDIO->STA&( 1<<4 ) )
{
SDIO->ICR |= 1<<4 ; //清錯誤標志
return SD_TX_UNDERRUN ;
}
//接收起始位錯誤
else if( SDIO->STA&( 1<<9 ) )
{
SDIO->ICR |= 1<<9 ; //清錯誤標志
return SD_START_BIT_ERR ;
}
//發送結束
if( SDIO->STA&( 1<<8 ) )
{
if( ( SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType )||( SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType )||( SDIO_HIGH_CAPACITY_SD_CARD==CardType ) )
{
SDIO_Send_Cmd( SD_CMD_STOP_TRANSMISSION, 1, 0 ) ; //發送CMD12+結束傳輸
errorstatus = CmdResp1Error( SD_CMD_STOP_TRANSMISSION ) ; //等待R1響應
if( errorstatus!=SD_OK )
return errorstatus ;
}
}
__asm volatile( "cpsie i" ) ; //開啟總中斷
SDIO->ICR=0x5FF ; //清除所有標記
}
SDIO->ICR = 0x5FF ; //清除所有標記
errorstatus = IsCardProgramming( &cardstate ) ;
while( ( errorstatus==SD_OK )&&( ( cardstate==SD_CARD_PROGRAMMING )||( cardstate==SD_CARD_RECEIVING ) ) )
errorstatus = IsCardProgramming( &cardstate ) ;
return errorstatus ;
}
/***************************************************
Name :SD_ReadDisk
Function :讀SD卡
Paramater :
buf:數據緩存區
sector:扇區地址
cnt:扇區個數
Return :錯誤代碼
***************************************************/
__align(4) u8 SDIO_DATA_BUFFER[ 512 ] ;
u8 SD_ReadDisk( u8*buf, u32 sector, u8 cnt )
{
u8 sta = SD_OK ;
long long lsector = sector ;
u8 n ;
if( CardType!=SDIO_STD_CAPACITY_SD_CARD_V1_1 )
lsector <<= 9 ;
if( ( ( u32 )buf%4 )!=0 )
{
for( n=0; n512*n, 512 ) ; //單個sector的讀操作
memcpy( buf , SDIO_DATA_BUFFER , 512 ) ;
buf += 512 ;
}
}
else
{
if( cnt==1 )
sta = SD_ReadBlock( buf, lsector, 512 ) ; //單個sector的讀操作
else
sta = SD_ReadMultiBlocks( buf, lsector, 512, cnt ) ; //多個sector
}
return sta ;
}
/***************************************************
Name :SD_WriteDisk
Function :寫SD卡
Paramater :
buf:數據緩存區
sector:扇區地址
cnt:扇區個數
Return :錯誤代碼
***************************************************/
u8 SD_WriteDisk( u8*buf, u32 sector, u8 cnt )
{
u8 sta = SD_OK ;
u8 n ;
long long lsector = sector ;
if( CardType!=SDIO_STD_CAPACITY_SD_CARD_V1_1 )
lsector <<= 9 ;
if( ( ( u32 )buf%4 )!=0 )
{
for( n=0; n512 ) ;
sta = SD_WriteBlock( SDIO_DATA_BUFFER, lsector+512*n, 512 ) ; //單個sector的寫操作
buf += 512 ;
}
}
else
{
if( cnt==1 )
sta = SD_WriteBlock( buf, lsector, 512 ) ; //單個sector的寫操作
else
sta = SD_WriteMultiBlocks( buf, lsector, 512, cnt ) ; //多個sector
}
return sta ;
}
(3)創建1.c文件,并輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "sdio_sdcard.h"
int main()
{
u8 Str[ 30 ] ;
u16 temp ;
STM32_Clock_Init( 9 ) ; //系統時鐘設置
SysTick_Init( 72 ) ; //延時初始化
USART1_Init( 72, 115200 ) ; //串口初始化為115200
LCD_Init() ; //初始化LCD
while( SD_Init() ) ; //初始化SD卡
temp = SDCardInfo.CardCapacity>>20 ; //單位換算
sprintf( ( char * )Str, "SD Size: %4d MB", temp ) ;
LCD_ShowString( 30, 170, Str ) ; //顯示SD卡容量
while(1)
{
}
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
單片機
+關注
關注
6043文章
44623瀏覽量
638720 -
存儲器
+關注
關注
38文章
7529瀏覽量
164369 -
SD卡
+關注
關注
2文章
566瀏覽量
64127 -
SDIO
+關注
關注
2文章
73瀏覽量
19404
發布評論請先 登錄
相關推薦
SD卡基礎讀寫實驗詳解
SD卡是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
STM32入門學習筆記之SD卡基礎讀寫實驗1
SD卡是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
STM32入門學習筆記之SD卡基礎讀寫實驗2
SD卡是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
STM32入門學習筆記之SD卡基礎讀寫實驗3
SD卡是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
評論