基於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協議

                             

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 段。

                                      

                                                                                      SD 卡命令格式 

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

SDIO_SendCommand(&SDIO_CmdInitStructure);

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

                                      

                                                                              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 條數據線模式要通過向卡發送命令來更改。

                                

卡的種類

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

其中 SDI/O 卡與 SD 存儲卡是有區別的,SDI/O 卡實際上就是利用 SDIO 接口的一些模塊,插入 SD 的插槽中,擴展設備的功能,如:SDI/O wifi, SDI/Ocmos 相機等。而 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技術,有疑問大家可以一起幫忙解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章