SDIO學習


SDIO學習

內容提要


摸索SD操作許久,發現很多資料都是基於庫函數開發,為真正理解SDIO的操作流程,本文引導讀者一起去閱讀Spec文件,深入理解SDIO操作的來龍去脈。(注意:本文主要是自己的學習心得,記錄學習中感覺重要的知識點,細節還需參考Spec)

協議手冊


SDIO操作協議主要包括兩個部分

  • SDIO接口協議 SDIO Card Specification:SDIO接口操作SD/MMC等的規范
  • SD物理層協議 SD Specifications Physical Layer Spec:SD卡的操作規范

SD卡結構


如上圖所示,SD卡主要包括輸入輸出引腳、卡接口控制器、電源管理、內部寄存器、Memory接口和Memory組成。

協議理解


總線數據傳輸協議




command和response通過雙向傳輸線CMD傳輸
command表示SDIO接口傳輸給SD卡的指令,response表示SD卡傳輸個SDIO接口的信息
數據可以是1bit或4bit通過DAT傳輸(data0/data0-3)
數據線DAT是雙向的,SDIO通過它進行SD卡的讀寫操作

CMD結構


CMD命令結構


每條指令由起始位(1bit)、傳輸位(1bit)、命令索引(6bit)、CRC校驗(7bit)和結束位(1bit)組成,總長48bit。
傳輸位標識傳輸的方向,SDIO(host)傳輸的為command,transmmitter bit = 1

Responds類型


SD卡的response有多種類型,請參考Spec文檔。
response主要包含SD卡的內部寄存器內容和狀態信息,在操作過程中需密切關注。
傳輸位標識傳輸的方向,SD(host)傳輸的為response,transmmitter bit = 0

數據結構


SDIO支持1bit和4bit數據傳輸,數據發送通過移位寄存器進行串行處理

SD讀寫操作


卡狀態與操作模式


卡狀態可以通過response或CMD13得到,標識SD操作的狀態
操作模式是上電操作一般的過程

初始化


上電后,需要識別SD卡的類型,得到SD卡的狀態信息,並將SD置於stand-by模式,故需要進行初始化

初始化的步驟(SDHC卡為例)

  • 發送CMD0,將卡狀態復位到idle狀態。
  • 發送CMD8,得到response。
  • 持續發送ACMD41(CMD55+CMD41),檢測response的CCS(30bit),若CCS = 1,則為高容量卡,檢測識別是否完成response的finish(31bit)= 1執行下一步。
  • 發送CMD2得到CID信息
  • 發送CMD3得到SD卡地址信息(RCA)初始化完成,進入到stand-by模式

傳輸狀態


  • 如圖所示,通過發送不同的CMD,切換SD的狀態
  • 注意狀態的轉移情況

卡狀態確認


  • 卡狀態可以通過CMD13查看SD卡所處的狀態,確認操作正確與否

參考代碼


void SDIORead_Test(){
    int rca;
    int complete;
    int current_status;
    int error_status;
    int i;
    int n = 1000;
    int temp = 0;
    
    int rxdata0 = 0;
    int rxdata1 = 0;
    int rxdata2 = 0;
    int rxdata3 = 0;

    uart_printf("Start testing SDIO tranfer...\n");

    SDIO1_GPIOInitRemap(); //配置GPIO

//======================================================
// set up
// Test:  Init sequence, With response check  
// CMD 0  Reset Card
// CMD 8  Get voltage (Only 2.0 Card response to this)            ////
// CMD55  Indicate Next Command are Application specific
// ACMD44 Get Voltage windows
// CMD 2  CID reg
// CMD 3  Get RCA.
//======================================================

    //配置MCU的SDIO(根據不同的SDIO而定)
    SDIO1->MMC_CARDSEL = 0xdf;   //enable module, enable mmcclk
    SDIO1->MMC_CTRL    = 0x83;      //4bit,low speed,1/16 divider		
    SDIO1->MMC_INT_MASK = 0x01;  //unmask interrupt
    SDIO1->MMC_CRCCTL   = 0xC0;  

//======================================================
//reset card :CMD0
//======================================================
    CMD_Send(0,0);
		
    n = 100;
    while(n--);
//======================================================
//cmd 8 
//======================================================
    CMD_Send(8,0x1AA);
    
    n = 1000;
    while(n--);
 		
    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD8 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }

    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 =  SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);
		
while(1)
{	
//======================================================
//cmd 55 
//======================================================
    CMD_Send(55,0);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD55 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);
//======================================================
//acmd 41 
//======================================================
		CMD_Send(41,0xC0100000);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD41 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
   if(!(rxdata0>>30 & 0x1)){  //判斷CCS,CCS=1為高容量卡
   	  uart_printf("CCS = 0\n");
   }
   else{
   	  uart_printf("CCS = 1   High Capacity SD Memory Card\n");			
   }
     		
   if(!(rxdata0>>31 & 0x1)){  //判斷電壓設置,上電是否完成
   	  uart_printf("Finished = 0\n");
   }
   else{
   	  uart_printf("Finished = 1\n");			
   }
    
    n = 100;
    while(n--);	
		
    if((rxdata0>>31 & 0x1)){
	  break;             //上電完成退出循環 
    }		

}
//======================================================
//cmd 2 CID
//======================================================
    CMD_Send(2,0);

    SDIO1->MMC_IO = 0x1c;  //auto only response transfer (136bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD2 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF7<<24  |SDIO1->CMD_BUF6<<16  |SDIO1->CMD_BUF5<<8  | SDIO1->CMD_BUF4;
    rxdata2 = SDIO1->CMD_BUF11<<24 |SDIO1->CMD_BUF10<<16 |SDIO1->CMD_BUF9<<8  | SDIO1->CMD_BUF8;
    rxdata3 = SDIO1->CMD_BUF15<<24 |SDIO1->CMD_BUF14<<16 |SDIO1->CMD_BUF13<<8 | SDIO1->CMD_BUF12;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
    uart_printf("rxdata2 = %x.\n",rxdata2);
    uart_printf("rxdata3 = %x.\n",rxdata3);
    
    n = 100;
    while(n--);
//======================================================
//cmd 3 RCA  :得到RCA,后續傳輸需要
//======================================================
    CMD_Send(3,0);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD3 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    uart_printf("RCA = %x.\n",(unsigned int)rxdata0>>16);		
    
    rca = (unsigned int)rxdata0>>16;
		
    n = 100;
    while(n--);

		
//======================================================
//cmd 9 + RCA -> CSD
//======================================================
    CMD_Send(9,rca<<16);

		uart_printf("\nRCA << 16 = %x\n",(unsigned int)rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD9 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF7<<24  |SDIO1->CMD_BUF6<<16  |SDIO1->CMD_BUF5<<8  | SDIO1->CMD_BUF4;
    rxdata2 = SDIO1->CMD_BUF11<<24 |SDIO1->CMD_BUF10<<16 |SDIO1->CMD_BUF9<<8  | SDIO1->CMD_BUF8;
    rxdata3  = SDIO1->CMD_BUF15<<24 |SDIO1->CMD_BUF14<<16 |SDIO1->CMD_BUF13<<8 | SDIO1->CMD_BUF12;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
    uart_printf("rxdata2 = %x.\n",rxdata2);
    uart_printf("rxdata3 = %x.\n",rxdata3);
		
    n = 100;
    while(n--);
//======================================================
//cmd 13 status  stand-by 
//======================================================
while(1){	
    CMD_Send(13,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD13 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);			

		current_status = (rxdata0>>9) & 0xf;
		error_status   = (rxdata0>>19) & 0x1;
		uart_printf("\r\n current_status = %x.\r\n",current_status);
		uart_printf("\r\n error_status = %x.\r\n",error_status);
		
		if(current_status == 3){
			break;
		}
}		
		
//======================================================
//cmd 4 設置頻率
//======================================================
    CMD_Send(4,0x04040000);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD4 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    n = 100;
    while(n--);
		SDIO1->MMC_CTRL    = 0xc3;      //4bit,high speed,1/2 divider	
//======================================================
//cmd 7  
//======================================================
    CMD_Send(7,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD7 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
    n = 100;
    while(n--);		

	
//======================================================
//cmd 13 status   tran mode
//======================================================
while(1){	
    CMD_Send(13,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD13 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);			

		current_status = (rxdata0>>9) & 0xf;
		uart_printf("current_status = %x.\n",current_status);
		
		if(current_status == 4){
			break;
		}
}		
//======================================================
//cmd 55 
//======================================================
    CMD_Send(55,rca<<16);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
//           uart_printf("Recieve CMD55 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

//    uart_printf("rxdata0 = %x.\n",rxdata0);
//    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);		
//		
//======================================================
//acmd 6  設置bus寬度
//======================================================
    CMD_Send(6,0x2);  //4bit

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD6 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);	

//======================================================
//cmd 16  
//======================================================
    CMD_Send(16,0x200);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD16 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
	
		
    n = 100;
    while(n--);		
	
//======================================================
//cmd 17 read data 
//======================================================
//    CMD_Send(17,0x300);

    CMD_Send(17,0x0);		

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD17 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
    n = 100;
    while(n--);		

    complete = SDIO1->BUF_CTL & 0x1;
    uart_printf("\r\n\ncomplete = %d.\r\n\n",complete);
//======================================================
//read data
//======================================================
    SDIO1->BUF_CTL         = 0x020;    //disable dma, read sd card
    SDIO1->MMC_IO          = 0x3;      //!!!read data, auto transfer   
    uart_printf("Wait read data from sd card.\n");

    while(1){                                    //wait FIFO full interrupt
			 n = 100;
       while(n--);		
       if((SDIO1->BUF_CTL & 0x1)){                 //judge which interrupt generation
           uart_printf("Data transmission is completed.\n");
           break;
       }
    }
		
    complete = SDIO1->BUF_CTL & 0x1;
    uart_printf("\r\n\ncomplete = %d.\r\n\n",complete);	
//======================================================
//cmd 12
//======================================================
    CMD_Send(12,0);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD12 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    uart_printf("Read data from data_buf\n");
    SDIO1->BUF_CTL   =  0x000;    //read buf

    uart_printf("\r\n\r\n");
    for(i = 0;i<128;i++){
			 uart_printf("%x ",SDIO1->DATA_BUF0);
    } 
    uart_printf("\r\n\r\n");

    uart_printf("Read data OK\n");
		
    n = 100;
    while(n--);		
    uart_printf("Finish.\n");
}

參考資料


[1]. SD_Physical_Layer_Spec_Version 2.00.pdf
[2]. Simplified_SDIO_Card_Spec_Version 2.00.pdf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM