在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32入門學習筆記之SD卡基礎讀寫實驗4

jf_78858299 ? 來源:滑小稽筆記 ? 作者:電子技術園地 ? 2023-02-16 15:09 ? 次閱讀

(2)創建sdio_sdcard.c文件,并輸入以下代碼。

#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
收藏 人收藏

    評論

    相關推薦

    【紫光同創國產FPGA教程】【第八章】SD讀寫實驗

    SD是現在嵌入式設備重要的存儲模塊,內部集成了nand flash控制器,方便了主機的的管理。本實驗主要是練習對sd的扇區進行
    的頭像 發表于 02-05 11:35 ?8427次閱讀
    【紫光同創國產FPGA教程】【第八章】<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    【GD32F470紫藤派開發板使用手冊】第十二講 SDIO-SD讀寫實驗

    通過本實驗主要學習以下內容: ?SDIO操作原理 ?SD讀寫實
    的頭像 發表于 05-18 09:36 ?1498次閱讀
    【GD32F470紫藤派開發板使用手冊】第十二講 SDIO-<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    arduino學習筆記18 - SD讀寫實驗

    本次實驗使用arduino驅動SD,在SD中進行文件讀寫。需要說明的是arduino的
    發表于 10-24 10:09

    接觸式IC讀寫實驗

    接觸式IC讀寫實驗 一. 實驗目的了解接觸式IC 的知識,
    發表于 09-22 17:20 ?4817次閱讀
    接觸式IC<b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    STM32開發板_SD學習

    資料包括《SD讀寫規范》和《SD接口規范》以及《SD
    發表于 06-08 17:29 ?15次下載

    ARM基礎應用實驗06_SD讀寫

    ARM嵌入式應用程序架構設計實例精講--ARM基礎應用實驗06SD讀寫
    發表于 07-08 11:08 ?0次下載

    ARM基礎應用實驗_SD讀寫

    電子專業單片機相關知識學習教材資料——ARM基礎應用實驗06SD讀寫
    發表于 09-13 17:23 ?0次下載

    STM32CubeMX生成一個SD讀寫程序

    本文檔內容介紹了一個STM32CubeMX生成一個SD讀寫程序,由于本程序是直接操作SD的物
    發表于 01-08 11:23 ?57次下載

    SD基礎讀寫實驗詳解

    SD是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
    的頭像 發表于 01-31 18:01 ?2824次閱讀
    <b class='flag-5'>SD</b><b class='flag-5'>卡</b>基礎<b class='flag-5'>讀寫實驗</b>詳解

    STM32入門學習筆記SD基礎讀寫實驗1

    SD是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
    的頭像 發表于 02-16 15:09 ?3018次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>入門</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b><b class='flag-5'>之</b><b class='flag-5'>SD</b><b class='flag-5'>卡</b>基礎<b class='flag-5'>讀寫實驗</b>1

    STM32入門學習筆記SD基礎讀寫實驗2

    SD是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
    的頭像 發表于 02-16 15:09 ?1240次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>入門</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b><b class='flag-5'>之</b><b class='flag-5'>SD</b><b class='flag-5'>卡</b>基礎<b class='flag-5'>讀寫實驗</b>2

    STM32入門學習筆記SD基礎讀寫實驗3

    SD是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。STM32F1系列自帶了標準的4位SDIO接口,最
    的頭像 發表于 02-16 15:09 ?1605次閱讀

    SD基礎讀寫實驗

    SD是嵌入式系統中最常見的存儲器,不僅容量可以做的很大,并且接口通用,支持SPI/SDIO驅動,尺寸可供選擇,能滿足不同應用的要求。
    的頭像 發表于 03-01 14:46 ?1631次閱讀
    <b class='flag-5'>SD</b><b class='flag-5'>卡</b>基礎<b class='flag-5'>讀寫實驗</b>

    淺談STM32SD

    STM32SD
    的頭像 發表于 10-19 18:28 ?2016次閱讀
    淺談<b class='flag-5'>STM32</b><b class='flag-5'>之</b><b class='flag-5'>SD</b><b class='flag-5'>卡</b>

    【GD32F303紅楓派開發板使用手冊】第二十三講 SDIO-SD讀寫實驗

    通過本實驗主要學習以下內容: ?SDIO操作原理 ?SD讀寫實
    的頭像 發表于 06-23 10:49 ?727次閱讀
    【GD32F303紅楓派開發板使用手冊】第二十三講 SDIO-<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>
    主站蜘蛛池模板: 二区视频在线 | 草久视频在线观看 | 四虎影视最新网址 | 三级三级三级网站网址 | 欧美在线视 | 噜噜噜久久久 | 我要看黄色一级毛片 | 一区二区三区四区无限乱码在线观看 | 69女poren60| 日韩免费无砖专区2020狼 | 欧美午夜片| 手机在线看片国产 | 黄色大片网| 三级欧美在线 | 高h办公室 | 免费一日本一级裸片在线观看 | 一区视频免费观看 | 国产va免费精品观看 | 天天摸日日摸 | 亚洲黄色成人 | 在线播放黄色网址 | 夜夜欢视频 | 又粗又大又爽又色又过瘾视频 | 亚洲第一色在线 | 四虎影院在线观看免费 | 欧美日韩色图 | 免费看国产一级特黄aa大片 | 狠狠干.com | 成人啪啪网站 | 草久久久久 | 日本在线视 | 国产视频一二三 | 黄页网站视频免费 视频 | 国产在线黄 | 久久草在线视频播放 | 3344a毛片在线看 | 明星三级国产免费播放 | 欧美二级| 男女爱爱视频免费看 | 亚洲精品美女 | 亚洲色图22p |