天天看點

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

SDIO模式

SDIO簡介

SD/SDIO/MMC 主機接口可以支援 MMC 卡系統規範 4.2 版中的 3 個不同的資料。總線模式:1 位(預設)、4 位和 8 位。在 8 位模式下,該接口可以使資料傳輸速率達到 48MHz,該接口相容 SD 存儲卡規範 2.0 版。SDIO 存儲卡規範 2.0 版支援兩種資料總線模式:1 位(預設)和 4 位。

目前的晶片版本隻能一次支援一個 SD/SDIO/MMC 4.2 版的卡,但可以同

時支援多個 MMC 4.1 版或之前版本的卡。除了 SD/SDIO/MMC,這個接口完全

與 CE-ATA 數字協定版本 1.1 相容。

SD協定

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

SDIO的時鐘

SDIO_CK 時鐘是通過 PC12 引腳連接配接到 SD 卡的,是 SDIO 接口與 SD 卡用于同步的時鐘。

SDIO 選配器挂載到 AHB 總線上,通過 HCLK 二分頻輸入到擴充卡得到SDIO_CK 的時鐘,這時 SDIO_CK = HCLK/(2+CLKDIV)。其中 CLKDIV 是SDIO_CLK(寄存器)中的 CLKDIV 位。

另外,SDIO_CK 也可以由 SDIOCLK 通過設定 bypass 模式直接得到,這時SDIO_CK = SDIOCLK=HCLK。

通過下面的庫函數來配置時鐘:

SDIO_Init(&SDIO_InitStructure);

對 SD 卡的操作一般是大吞吐量的資料傳輸,是以采用 DMA 來提高效率,SDIO 采用的是 DMA2 中的通道 4。在資料傳輸的時候 SDIO 可向 DMA 送出請求。

SDIO 的指令、資料傳輸方式

SDIO 的所有指令及指令響應,都是通過 SDIO-CMD 引腳來傳輸的。

指令隻能由 host 即 STM32 的 SDIO 控制器發出。SDIO 協定把指令分成了11 種,包括基本指令,讀寫指令還有 ACMD 系列指令等。其中,在發送 ACMD指令前,要先向卡發送編号為 CMD55 的指令。

下面的指令格式圖,其中的 start bit,transmission bit ,crc7,endbit,都是由 STM32 中的 SDIO 硬體完成,我們在軟體上配置的時候隻需要設定 command index 和指令參數 argument。Command index 就是指令索引(編号),如 CMD0,CMD1…被編号成 0,1...。有的指令會包含參數,讀指令的位址參數等,這個參數被存放在 argument 段。

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

                                                                                      SD 卡指令格式 

通過下面的函數來配置、發送指令:

SDIO_SendCommand(&SDIO_CmdInitStructure);

SD 卡對 host 的各種指令的回複稱為響應,除了 CMD0 指令外,SD 卡在接收到指令都會傳回一個響應。對于不同的指令,會有不同的響應格式,共 7種,分為長響應型(136bit)和短響應型(48bit)。以下圖,響應 6(R6)為例:

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

                                                                              SD 卡指令響應格式(R6)

SDIO 通過 CMD 接收到響應後,硬體去除頭尾的資訊,把 command index儲存到 SDIO_RESPCMD 寄存器,把 argument field 内容儲存存儲到SDIO_RESPx 寄存器中。這兩個值可以分别通過下面的庫函數得到。

SDIO_GetCommandResponse(); //卡傳回接收到的指令

SDIO_GetResponse(SDIO_RESP1); //卡傳回的 argument field 内容

資料寫入,讀取。請看下面的寫資料時序圖,在軟體上,我們要處理的隻是讀忙。另外,我們的實驗中用的是 Micro SD 卡,有 4 條資料線,預設的時候 SDIO 采用 1 條資料線的傳輸方式,更改為 4 條資料線模式要通過向卡發送指令來更改。

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

卡的種類

STM32 的 SDIO 支援 SD 存儲卡,SD I/O 卡 ,MMC 卡。

其中 SDI/O 卡與 SD 存儲卡是有差別的,SDI/O 卡實際上就是利用 SDIO 接口的一些子產品,插入 SD 的插槽中,擴充裝置的功能,如:SDI/O wifi, SDI/Ocmos 相機等。而 SD 存儲卡就是我們平時常見的單純用于存儲資料的卡。

基于ARM開發闆從零開始學習STM32 09-SD卡實驗

下面以SD卡讀寫測試為例:

Main函數入口

int main(void)
{
	NVIC_Configuration();
	RS232_Init(9600);
	printf( " 開始初始化\r\n " );	
	if( SD_OK == ( Status = SD_Init() ) )     
		printf( "初始化成功 \r\n " );		
	else
		printf("初始化失敗 \r\n" );			  	
	    
 	printf( " \r\n CardType is :%d ", SDCardInfo.CardType );
	printf( " \r\n CardCapacity is :%d ", SDCardInfo.CardCapacity );
	printf( " \r\n CardBlockSize is :%d ", SDCardInfo.CardBlockSize );
	printf( " \r\n RCA is :%d ", SDCardInfo.RCA);
	printf( " \r\n ManufacturerID is :%d \r\n", SDCardInfo.SD_cid.ManufacturerID );

	SD_EraseTest();	   

	SD_SingleBlockTest();  

 	SD_MultiBlockTest();  	

  while (1)
  {}
}
           

用 NVIC_Configuration() 初始化好 SDIO 的中斷;用 RS232_Init(9600); 配置好用于傳回調試資訊的序列槽, SD_Init() 開始

進行 SDIO 的初始化;最後分别用 SD_EraseTest()、SD_SingleBlockTest()、SD_MultiBlockTest()

進行擦除,單資料塊讀寫,多資料塊讀寫測試。

SD_Init()  SD初始化 卡處于傳輸資料狀态

SD_Error SD_Init(void)
{
  SD_Error errorstatus = SD_OK;
  GPIO_Configuration();
  SDIO_DeInit();  
  errorstatus = SD_PowerON(); 
  if (errorstatus != SD_OK)
  {
    return(errorstatus);	
  }
  errorstatus = SD_InitializeCards(); 
  if (errorstatus != SD_OK)	 
  {
    return(errorstatus);
  }
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;   
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; 		
  SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;  
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;	   
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;					
  SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable; 
  SDIO_Init(&SDIO_InitStructure);
  if (errorstatus == SD_OK)
  {
      errorstatus = SD_GetCardInfo(&SDCardInfo);
  }
  if (errorstatus == SD_OK)
  {
    errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));	  
  }

  if (errorstatus == SD_OK)
  {
    errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);	
  }  

  return(errorstatus);
}
           

用 GPIO_Configuration() 進行 SDIO 的端口底層配置

分别調用了 SD_PowerON()和 SD_InitializeCards()函數,這兩個函數共同實作了上面提到的卡檢測、識别流程。

調用 SDIO_Init(&SDIO_InitStructure) 庫函數配置 SDIO 的時鐘,資料線寬度,硬體流(在讀寫資料的時候,開啟硬體流是和很必要的,可以減少出錯)。

調用 SD_GetCardInfo(&SDCardInfo) 擷取 sd 卡的 CSD 寄存器中的内容,在main 函數裡輸出到序列槽的資料就是這個時候從卡讀取得到的。

調用 SD_SelectDeselect() 標明後面即将要操作的卡。

調用 SD_EnableWideBusOperation(SDIO_BusWide_4b) 開啟 4bit 資料線模式。

如果 SD_Init() 函數能夠執行完整個流程,并且傳回值是 SD_OK 的話則說明初始

化成功,就可以開始進行擦除、讀寫的操作了。

分析SD_PowerON()的工作過程,大緻能了解SDIO的接收和發送指令的過程。下面将會上傳完整的工程到我的網盤,工程裡附帶詳細的注釋和完整的代碼,有需要的自行下載下傳。連結:https://pan.baidu.com/s/1ancN8BAqB_NkHuvwnKGWJg 提取碼:9pjm 

有興趣的可以加一下我建立的STM32技術交流群:956967059,一起交流STM32技術,有疑問大家可以一起幫忙解決。

繼續閱讀