欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
零死角玩轉stm32-高級篇之SDIO(4bit + DMA、支持SDHC、帶協(xié)議分析)
1、SDIO(4bit + DMA、支持SDHC)

   1.1 實(shí)驗描述及工程文件清單

實(shí)驗描述:MicroSD卡(SDIO模式)測試實(shí)驗,采用4bit數據線(xiàn)模式。沒(méi)有跑文件系統,只是單純地讀block并將測試信息通過(guò)串口1在電腦的超級終端上 打印出來(lái)。

硬件連接:MicroSD卡(SDIO模式)測試實(shí)驗,采用4bit數據線(xiàn)模式。沒(méi)有跑文件系統,只是單純地讀block并將測試信息通過(guò)串口1在電腦的超級終端上 打印出來(lái)。

用到的庫文件:startup/start_stm32f10x_hd.cCMSIS/core_cm3.cCMSIS/system_stm32f10x.cFWlib/stm32f10x_gpio.cFWlib/stm32f10x_rcc.cFWlib/stm32f10x_usart.cFWlib/ stm32f10x_sdio.cFWlib/ stm32f10x_dma.cFWlib/ misc.c

用戶(hù)編寫(xiě)的文件:USER/main.cUSER/stm32f10x_it.cUSER/usart1.cUSER/ sdio_sdcard.c

野火STM32開(kāi)發(fā)板 MicroSD卡硬件原理圖:

 

   1.2 SDIO簡(jiǎn)介

野火STM32開(kāi)發(fā)板的CPU ( STM32F103VET6 )具有一個(gè)SDIO接口。SD/SDIO/MMC主機接口可以支持MMC卡系統規范4.2版中的3個(gè)不同的數據總線(xiàn)模式:1位(默認)、4位和8位。在8位模式下,該接口可以使數據傳輸速率達到48MHz,該接口兼容SD存儲卡規范2.0版。SDIO存儲卡規范2.0版支持兩種數據總線(xiàn)模式:1位(默認)和4位。

目前的芯片版本只能一次支持一個(gè)SD/SDIO/MMC 4.2版的卡,但可以同時(shí)支持多個(gè)MMC 4.1版或之前版本的卡。除了SD/SDIO/MMC,這個(gè)接口完全與CE-ATA數字協(xié)議版本1.1兼容。

   1.3 SD協(xié)議

大多數人原來(lái)沒(méi)有了解過(guò)SD協(xié)議,又看到SDIO的驅動(dòng)有2000多行,感覺(jué)無(wú)從下手。所以野火重新寫(xiě)了這個(gè)文檔進(jìn)行詳細的解釋?zhuān)瑤椭蠹腋斓乜邕^(guò)這道檻。

附資料:《Simplified_Physical_Layer_Spec.pdf》,這個(gè)資料包含了SDIO協(xié)議中SD存儲卡的部分。

下面野火結合STM32的SDIO,分析SD協(xié)議,讓大家對它先有個(gè)大概了解,更具體的說(shuō)明在代碼中展開(kāi)。

  SDIO接口圖

   

 一.從SDIO的時(shí)鐘說(shuō)起。

SDIO_CK時(shí)鐘是通過(guò)PC12引腳連接到SD卡的,是SDIO接口與SD卡用于同步的時(shí)鐘。

SDIO選配器掛載到AHB總線(xiàn)上,通過(guò)HCLK二分頻輸入到適配器得到SDIO_CK的時(shí)鐘,這時(shí)SDIO_CK = HCLK/(2+CLKDIV)。其中CLKDIV是SDIO_CLK(寄存器)中的CLKDIV位。

另外,SDIO_CK也可以由SDIOCLK通過(guò)設置bypass模式直接得到,這時(shí)SDIO_CK = SDIOCLK=HCLK。

通過(guò)下面的庫函數來(lái)配置時(shí)鐘:

SDIO_Init(&SDIO_InitStructure);

對SD卡的操作一般是大吞吐量的數據傳輸,所以采用DMA來(lái)提高效率,SDIO采用的是DMA2中的通道4。在數據傳輸的時(shí)候SDIO可向DMA發(fā)出請求。

二.講解SDIO的命令、數據傳輸方式。

SDIO的所有命令及命令響應,都是通過(guò)SDIO-CMD引腳來(lái)傳輸的。

命令只能由host即STM32的SDIO控制器發(fā)出。SDIO協(xié)議把命令分成了11種,包括基本命令,讀寫(xiě)命令還有ACMD系列命令等。其中,在發(fā)送ACMD命令前,要先向卡發(fā)送編號為CMD55的命令。

參照下面的命令格式圖,其中的start bit,transmission bit ,crc7,endbit,都是由STM32中的SDIO硬件完成,我們在軟件上配置的時(shí)候只需要設置command index和命令參數argument。Command index就是命令索引(編號),如CMD0,CMD1…被編號成0,1...。有的命令會(huì )包含參數,讀命令的地址參數等,這個(gè)參數被存放在argument段。

  SD卡命令格式

   

可以通過(guò)下面的函數來(lái)配置、發(fā)送命令:

SDIO_SendCommand(&SDIO_CmdInitStructure);   //發(fā)送命令

SD卡對host的各種命令的回復稱(chēng)為響應,除了CMD0命令外,SD卡在接收到命令都會(huì )返回一個(gè)響應。對于不同的命令,會(huì )有不同的響應格式,共7種,分為長(cháng)響應型(136bit)短響應型(48bit)。以下圖,響應6(R6)為例:

  SD卡命令響應格式(R6)

   

SDIO通過(guò)CMD接收到響應后,硬件去除頭尾的信息,把command index 保存到SDIO_RESPCMD寄存器,把argument field內容保存存儲到SDIO_RESPx寄存器中。這兩個(gè)值可以分別通過(guò)下面的庫函數得到。

SDIO_GetCommandResponse();  //卡返回接收到的命令

SDIO_GetResponse(SDIO_RESP1); //卡返回的argument field內容

數據寫(xiě)入,讀取。請看下面的寫(xiě)數據時(shí)序圖,在軟件上,我們要處理的只是讀忙。另外,我們的實(shí)驗中用的是Micro SD卡,有4條數據線(xiàn),默認的時(shí)候SDIO采用1條數據線(xiàn)的傳輸方式,更改為4條數據線(xiàn)模式要通過(guò)向卡發(fā)送命令來(lái)更改。

   SD卡的多塊寫(xiě)入時(shí)序圖

  

三.卡的種類(lèi)。

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

其中SDI/O卡SD存儲卡是有區別的,SDI/O卡實(shí)際上就是利用SDIO接口的一些模塊,插入SD的插槽中,擴展設備的功能,如:SDI/O wifi, SDI/O cmos相機等。而SD存儲卡就是我們平時(shí)常見(jiàn)的單純用于存儲數據的卡。

可使用SDIO接口類(lèi)型的卡

本實(shí)驗中使用的Micro SD卡屬于SDSC(標準容量,最大兩G)卡。介紹卡的種類(lèi)是因為SD協(xié)議中的命令也支持這三種類(lèi)型的卡,因此對STM32中的SDIO接口進(jìn)行初始化后,上電后就要對接入的卡進(jìn)行檢測、分類(lèi),這個(gè)過(guò)程是通過(guò)向卡發(fā)送一系列不同的命令,根據卡不同的響應來(lái)進(jìn)行分類(lèi)。

下面進(jìn)入代碼展開(kāi)具體講解。

1.4 代碼分析

首先要添加用的庫文件,在工程文件夾下Fwlib下我們需添加以下庫文件:

FWlib/stm32f10x_gpio.c

FWlib/stm32f10x_rcc.c

FWlib/stm32f10x_usart.c

FWlib/stm32f10x_sdio.c

FWlib/stm32f10x_dma.c

FWlib/misc.c

還要在 stm32f10x_conf.h中把相應的頭文件添加進(jìn)來(lái):

#include "stm32f10x_dma.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

#include "stm32f10x_sdio.h"

#include "stm32f10x_usart.h"

#include "misc.h"

保持良好的習慣,從main函數開(kāi)始分析:

int main(void)

{

/*進(jìn)入到main函數前,啟動(dòng)文件startup(startup_stm32f10x_xx.s)已經(jīng)調用了在

system_stm32f10x.c中的SystemInit(),配置好了系統時(shí)鐘,在外部晶振8M的條件下,

設置HCLK = 72M  */

/* Interrupt Config */

NVIC_Configuration();

/* USART1 config */

USART1_Config();

/*------------------------------ SD Init ---------------------------------- */

Status = SD_Init();

printf( "\r\n 這是一個(gè)MicroSD卡實(shí)驗(沒(méi)有跑文件系統).........\r\n " );

if(Status == SD_OK) //檢測初始化是否成功

{

printf( " \r\n SD_Init 初始化成功 \r\n " );

}

else

{

printf("\r\n SD_Init 初始化失敗 \r\n" );

printf("\r\n 返回的Status的值為: %d \r\n",Status );

}

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();  //單塊讀寫(xiě)測試

SD_MultiBlockTest();  //多塊讀寫(xiě)測試

while (1)

{}

}

main函數的流程簡(jiǎn)單明了:

1、用NVIC_Configuration()初始化好SDIO的中斷;

2、用USART1_Config()配置好用于返回調試信息的串口,SD_Init()開(kāi)始進(jìn)行SDIO的初始化;

3、最后分別用SD_EraseTest()、SD_SingleBlockTest()、SD_MultiBlockTest()進(jìn)行擦除,單數據塊讀寫(xiě),多數據塊讀寫(xiě)測試。

下面我們先進(jìn)入SDIO驅動(dòng)函數的大頭——SD_Init()進(jìn)行分析:

/*

* 函數名:SD_Init

* 描述  :初始化SD卡,使卡處于就緒狀態(tài)(準備傳輸數據)

* 輸入  :無(wú)

* 輸出  :-SD_Error SD卡錯誤代碼

*         成功時(shí)則為 SD_OK

* 調用  :外部調用

*/

SD_Error SD_Init(void)

{

/*重置SD_Error狀態(tài)*/

SD_Error errorstatus = SD_OK;

/* SDIO 外設底層引腳初始化 */

GPIO_Configuration();

/*對SDIO的所有寄存器進(jìn)行復位*/

SDIO_DeInit();

/*上電并進(jìn)行卡識別流程,確認卡的操作電壓  */

errorstatus = SD_PowerON();

/*如果上電,識別不成功,返回“響應超時(shí)”錯誤 */

if (errorstatus != SD_OK)

{

/*!< CMD Response TimeOut (wait for CMDSENT flag) */

return(errorstatus);

}

/*卡識別成功,進(jìn)行卡初始化    */

errorstatus = SD_InitializeCards();

if (errorstatus != SD_OK)   //失敗返回

{

/*!< CMD Response TimeOut (wait for CMDSENT flag) */

return(errorstatus);

}

/*!< Configure the SDIO peripheral

上電識別,卡初始化都完成后,進(jìn)入數據傳輸模式,提高讀寫(xiě)速度

速度若超過(guò)24M要進(jìn)入bypass模式

!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz

!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */

SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;

SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;         //上升沿采集數據

SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;  //時(shí)鐘頻率若超過(guò)24M,要開(kāi)啟此模式

SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;    //若開(kāi)啟此功能,在總線(xiàn)空閑時(shí)關(guān)閉sd_clk時(shí)鐘

SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;                        //1位模式

SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; //硬件流,若開(kāi)啟,在FIFO不能進(jìn)行發(fā)送和接收數據時(shí),數據傳輸暫停

SDIO_Init(&SDIO_InitStructure);

if (errorstatus == SD_OK)

{

/*----------------- Read CSD/CID MSD registers ------------------*/

errorstatus = SD_GetCardInfo(&SDCardInfo);   //用來(lái)讀取csd/cid寄存器

}

if (errorstatus == SD_OK)

{

/*----------------- Select Card --------------------------------*/

errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));   //通過(guò)cmd7  ,rca選擇要操作的卡

}

if (errorstatus == SD_OK)

{

errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);   //開(kāi)啟4bits模式

}

return(errorstatus);

}

先從整體上了解這個(gè)SD_Init()函數:

1.用 GPIO_Configuration()進(jìn)行SDIO的端口底層配置

2.分別調用了SD_PowerON()和SD_InitializeCards()函數,這兩個(gè)函數共同實(shí)現了上面提到的卡檢測、識別流程。

3.調用SDIO_Init(&SDIO_InitStructure)庫函數配置SDIO的時(shí)鐘,數據線(xiàn)寬度,硬件流(在讀寫(xiě)數據的時(shí)候,開(kāi)啟硬件流是和很必要的,可以減少出錯)

4. 調用SD_GetCardInfo(&SDCardInfo)獲取sd卡的CSD寄存器中的內容,在main函數里輸出到串口的數據就是這個(gè)時(shí)候從卡讀取得到的。

5. 調用SD_SelectDeselect()選定后面即將要操作的卡。

6.調用SD_EnableWideBusOperation(SDIO_BusWide_4b)開(kāi)啟4bit數據線(xiàn)模式

如果SD_Init()函數能夠執行完整個(gè)流程,并且返回值是SD_OK的話(huà)則說(shuō)明初始化成功,就可以開(kāi)始進(jìn)行擦除、讀寫(xiě)的操作了。

下面進(jìn)入SD_PowerON()函數,分析完這個(gè)函數大家就能了解SDIO如何接收、發(fā)送命令了。

/*

* 函數名:SD_PowerON

* 描述  :確保SD卡的工作電壓和配置控制時(shí)鐘

* 輸入  :無(wú)

* 輸出  :-SD_Error SD卡錯誤代碼

*         成功時(shí)則為 SD_OK

* 調用  :在 SD_Init() 調用

*/

SD_Error SD_PowerON(void)

{

SD_Error errorstatus = SD_OK;

uint32_t response = 0, count = 0, validvoltage = 0;

uint32_t SDType = SD_STD_CAPACITY;

/*!< Power ON Sequence -----------------------------------------------------*/

/*!< Configure the SDIO peripheral */

/*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) */

/*!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz */

/*!< SDIO_CK for initialization should not exceed 400 KHz */

/*初始化時(shí)的時(shí)鐘不能大于400KHz*/

SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */

SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;

SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;  //不使用bypass模式,直接用HCLK進(jìn)行分頻得到SDIO_CK

SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; // 空閑時(shí)不關(guān)閉時(shí)鐘電源

SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;                    //1位數據線(xiàn)

SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;//硬件流

SDIO_Init(&SDIO_InitStructure);

/*!< Set Power State to ON */

SDIO_SetPowerState(SDIO_PowerState_ON);

/*!< Enable SDIO Clock */

SDIO_ClockCmd(ENABLE);

/*下面發(fā)送一系列命令,開(kāi)始卡識別流程*/

/*!< CMD0: GO_IDLE_STATE ---------------------------------------------------*/

/*!< No CMD response required */

SDIO_CmdInitStructure.SDIO_Argument = 0x0;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;  //無(wú)響應

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;  //則CPSM在開(kāi)始發(fā)送命令之前等待數據傳輸結束。

SDIO_SendCommand(&SDIO_CmdInitStructure);         //寫(xiě)命令進(jìn)命令寄存器

errorstatus = CmdError();//檢測是否正確接收到cmd0

if (errorstatus != SD_OK) //命令發(fā)送出錯,返回

{

/*!< CMD Response TimeOut (wait for CMDSENT flag) */

return(errorstatus);

}

/*!< CMD8: SEND_IF_COND ----------------------------------------------------*/

/*!< Send CMD8 to verify SD card interface operating condition */

/*!< Argument: - [31:12]: Reserved (shall be set to '0')

- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)

- [7:0]: Check Pattern (recommended 0xAA) */

/*!< CMD Response: R7 */

SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;   //接收到命令sd會(huì )返回這個(gè)參數

SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;  //cmd8

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;     //r7

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;            //關(guān)閉等待中斷

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

/*檢查是否接收到命令*/

errorstatus = CmdResp7Error();

if (errorstatus == SD_OK)     //有響應則card遵循sd協(xié)議2.0版本

{

CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 ,先把它定義會(huì )sdsc類(lèi)型的卡*/

SDType = SD_HIGH_CAPACITY;  //這個(gè)變量用作acmd41的參數,用來(lái)詢(xún)問(wèn)是sdsc卡還是sdhc卡

}

else  //無(wú)響應,說(shuō)明是1.x的或mmc的卡

{

/*!< CMD55 */

SDIO_CmdInitStructure.SDIO_Argument = 0x00;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_APP_CMD);

}

/*!< CMD55 */     //為什么在else里和else外面都要發(fā)送CMD55?

//發(fā)送cmd55,用于檢測是sd卡還是mmc卡,或是不支持的卡

SDIO_CmdInitStructure.SDIO_Argument = 0x00;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_APP_CMD);  //是否響應,沒(méi)響應的是mmc或不支持的卡

/*!< If errorstatus is Command TimeOut, it is a MMC card */

/*!< If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)

or SD card 1.x */

if (errorstatus == SD_OK) //響應了cmd55,是sd卡,可能為1.x,可能為2.0

{

/*下面開(kāi)始循環(huán)地發(fā)送sdio支持的電壓范圍,循環(huán)一定次數*/

/*!< SD CARD */

/*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */

while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))

{

//因為下面要用到ACMD41,是ACMD命令,在發(fā)送ACMD命令前都要先向卡發(fā)送CMD55

/*!< SEND CMD55 APP_CMD with RCA as 0 */

SDIO_CmdInitStructure.SDIO_Argument = 0x00;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;   //CMD55

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_APP_CMD); //檢測響應

if (errorstatus != SD_OK)

{

return(errorstatus);//沒(méi)響應CMD55,返回

}

//acmd41,命令參數由支持的電壓范圍及HCS位組成,HCS位置一來(lái)區分卡是SDSc還是sdhc

SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;    //參數為主機可供電壓范圍及hcs位

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r3

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp3Error();    //檢測是否正確接收到數據

if (errorstatus != SD_OK)

{

return(errorstatus);  //沒(méi)正確接收到acmd41,出錯,返回

}

/*若卡需求電壓在SDIO的供電電壓范圍內,會(huì )自動(dòng)上電并標志pwr_up位*/

response = SDIO_GetResponse(SDIO_RESP1);   //讀取卡寄存器,卡狀態(tài)

validvoltage = (((response >> 31) == 1) ? 1 : 0); //讀取卡的ocr寄存器的pwr_up位,看是否已工作在正常電壓

count++;            //計算循環(huán)次數

}

if (count >= SD_MAX_VOLT_TRIAL) //循環(huán)檢測超過(guò)一定次數還沒(méi)上電

{

errorstatus = SD_INVALID_VOLTRANGE;      //SDIO不支持card的供電電壓

return(errorstatus);

}

/*檢查卡返回信息中的HCS位*/

if (response &= SD_HIGH_CAPACITY)  //判斷ocr中的ccs位 ,如果是sdsc卡則不執行下面的語(yǔ)句

{

CardType = SDIO_HIGH_CAPACITY_SD_CARD;  //把卡類(lèi)型從初始化的sdsc型改為sdhc型

}

}/*!< else MMC Card */

return(errorstatus);

}

這個(gè)函數的流程就是卡的上電、識別操作,如下圖:

卡的上電,識別流程:

截圖來(lái)自《Simplified_Physical_Layer_Spec.pdf》 page27

代碼中所有的判斷語(yǔ)句都是根據這個(gè)圖的各個(gè)識別走向展開(kāi)的,最終把卡分為1.0版的SD存儲卡,2.0版的SDSC卡和2.0版的SDHC卡。

在這個(gè)代碼流程中有兩點(diǎn)要注意一下:

1.初始化的時(shí)鐘。SDIO_CK的時(shí)鐘分為兩個(gè)階段,在初始化階段SDIO_CK的頻率要小于400KHz,初始化完成后可把SDIO_CK調整成高速模式,高速模式時(shí)超過(guò)24M要開(kāi)啟bypass模式,對于SD存儲卡即使開(kāi)啟bypass,最高頻率不能超過(guò)25MHz。

2.CMD8命令。

CMD8命令格式。

CMD8命令中的VHS是用來(lái)確認主機SDIO是否支持卡的工作電壓的。Check pattern部分可以是任何數值,若SDIO支持卡的工作電壓,卡會(huì )把接收到的check pattern數值原樣返回給主機。

CMD8命令的響應格式R7:

在驅動(dòng)程序中調用了CmdResp7Error()來(lái)檢驗卡接收命令后的響應。

3.ACMD41命令。

這個(gè)命令也是用來(lái)進(jìn)一步檢查SDIO是否支持卡的工作電壓的,協(xié)議要它在調用它之前必須先調用CMD8,另外還可以通過(guò)它命令參數中的HCS位來(lái)區分卡是SDHC卡還是SDSC卡。

確認工作電壓時(shí)循環(huán)地發(fā)送ACMD41,發(fā)送后檢查在SD卡上的OCR寄存器中的pwr_up位,若pwr_up位置為1,表明SDIO支持卡的工作電壓,卡開(kāi)始正常工作。

同時(shí)把ACMD41中的命令參數HCS位置1,卡正常工作的時(shí)候檢測OCR寄存器中的CCS位,若CCS位為1則說(shuō)明該卡為SDHC卡,為零則為SDSC卡。

因為ACMD41命令屬于A(yíng)CMD命令,在發(fā)送ACMD命令前都要先發(fā)送CMD55.

ACMD41命令格式

ACMD41命令的響應(R3),返回的是OCR寄存器的值

OCR寄存器的內容

SD卡上電確認成功后,進(jìn)入SD_InitializeCards()函數:

/*

* 函數名:SD_InitializeCards

* 描述  :初始化所有的卡或者單個(gè)卡進(jìn)入就緒狀態(tài)

* 輸入  :無(wú)

* 輸出  :-SD_Error SD卡錯誤代碼

*         成功時(shí)則為 SD_OK

* 調用  :在 SD_Init() 調用,在調用power_on()上電卡識別完畢后,調用此函數進(jìn)行卡初始化

*/

SD_Error SD_InitializeCards(void)

{

SD_Error errorstatus = SD_OK;

uint16_t rca = 0x01;

if (SDIO_GetPowerState() == SDIO_PowerState_OFF)

{

errorstatus = SD_REQUEST_NOT_APPLICABLE;

return(errorstatus);

}

if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)//判斷卡的類(lèi)型

{

/*!< Send CMD2 ALL_SEND_CID */

SDIO_CmdInitStructure.SDIO_Argument = 0x0;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp2Error();

if (SD_OK != errorstatus)

{

return(errorstatus);

}

CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);

CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);

CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);

CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);

}

/*下面開(kāi)始SD卡初始化流程*/

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))  //使用的是2.0的卡

{

/*!< Send CMD3 SET_REL_ADDR with argument 0 */

/*!< SD Card publishes its RCA. */

SDIO_CmdInitStructure.SDIO_Argument = 0x00;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;  //cmd3

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca); //把接收到的卡相對地址存起來(lái)。

if (SD_OK != errorstatus)

{

return(errorstatus);

}

}

if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)

{

RCA = rca;

/*!< Send CMD9 SEND_CSD with argument as card's RCA */

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp2Error();

if (SD_OK != errorstatus)

{

return(errorstatus);

}

CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);

CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);

CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);

CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);

}

errorstatus = SD_OK; /*!< All cards get intialized */

return(errorstatus);

}

這個(gè)函數向卡發(fā)送了CMD2和CMD3命令

1.CMD2

CMD2命令是要求卡返回它的CID寄存器的內容。

命令的響應格式(R2)。

因為命令格式是136位的,屬于長(cháng)響應。軟件接收的信息有128位。在長(cháng)響應的時(shí)候通過(guò)SDIO_GetResponse(SDIO_RESP4);中的不同參數來(lái)獲取CID中的不同數據段的數據。

2.CMD3

CMD3命令是要求卡向主機發(fā)送卡的相對地址。在接有多個(gè)卡的時(shí)候,主機要求接口上的卡重新發(fā)一個(gè)相對地址,這個(gè)地址跟卡的實(shí)際ID不一樣。比如接口上接了5個(gè)卡,這5個(gè)卡的相對地址就分別為1,2,3,4,5.以后主機SDIO對這幾個(gè)卡尋址就直接使用相對地址。這個(gè)地址的作用就是為了尋址更加簡(jiǎn)單。

接下來(lái)我們回到SD_Init()函數。分析到這里大家應該對SDIO的命令發(fā)送和響應比較清楚了。在SD_InitializeCards()之后的SD_GetCardInfo(&SDCardInfo)、 SD_SelectDeselect()和

SD_EnableWideBusOperation(SDIO_BusWide_4b)的具體實(shí)現就不再詳細分析了,實(shí)際就是發(fā)送相應的命令,對卡進(jìn)行相應的操作。

接下來(lái)分析main函數中的SD_MultiBlockTest()多塊數據讀寫(xiě)函數,讓大家了解SDIO是怎樣傳輸數據的。

/*

* 函數名:SD_MultiBlockTest

* 描述  :    多數據塊讀寫(xiě)測試

* 輸入  :無(wú)

* 輸出  :無(wú)

*/

void SD_MultiBlockTest(void)

{

/*--------------- Multiple Block Read/Write ---------------------*/

/* Fill the buffer to send */

Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);

if (Status == SD_OK)

{

/* Write multiple block of many bytes on address 0 */

Status = SD_WriteMultiBlocks(Buffer_MultiBlock_Tx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);

/* Check if the Transfer is finished */

Status = SD_WaitWriteOperation();

while(SD_GetStatus() != SD_TRANSFER_OK);

}

if (Status == SD_OK)

{

/* Read block of many bytes from address 0 */

Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);

/* Check if the Transfer is finished */

Status = SD_WaitReadOperation();

while(SD_GetStatus() != SD_TRANSFER_OK);

}

/* Check the correctness of written data */

if (Status == SD_OK)

{

TransferStatus2 = Buffercmp(Buffer_MultiBlock_Tx, Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);

}

if(TransferStatus2 == PASSED)

printf("\r\n 多塊讀寫(xiě)測試成功! " );

else

printf("\r\n 多塊讀寫(xiě)測試失??! " );

}

把這個(gè)函數拿出來(lái)分析最重要的一點(diǎn)就是讓大家注意在調用了SD_WriteMultiBlocks()這一類(lèi)讀寫(xiě)操作的函數后,一定要調用SD_WaitWriteOperation()[在讀數據時(shí)調用SD_WaitReadOperation]SD_GetStatus()來(lái)確保數據傳輸已經(jīng)結束再進(jìn)行其它操作。其中的SD_WaitWriteOperation()是用來(lái)等待DMA把緩沖的數據傳輸到SDIO的FIFO的;而SD_GetStatus()是用來(lái)等待卡與SDIO之間傳輸數據完畢的。

最后進(jìn)入SD_WriteMultiBlocks()函數分析:

/*

* 函數名:SD_WriteMultiBlocks

* 描述  :從輸入的起始地址開(kāi)始,向卡寫(xiě)入多個(gè)數據塊,

只能在DMA模式下使用這個(gè)函數

注意:調用這個(gè)函數后一定要調用

SD_WaitWriteOperation()來(lái)等待DMA傳輸結束

和   SD_GetStatus() 檢測卡與SDIO的FIFO間是否已經(jīng)完成傳輸

* 輸入  :

* @param  WriteAddr: Address from where data are to be read.

* @param  writebuff: pointer to the buffer that contain the data to be transferred.

* @param  BlockSize: the SD card Data block size. The Block size should be 512.

* @param  NumberOfBlocks: number of blocks to be written.

* 輸出  :SD錯誤類(lèi)型

*/

SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)

{

SD_Error errorstatus = SD_OK;

__IO uint32_t count = 0;

TransferError = SD_OK;

TransferEnd = 0;

StopCondition = 1;

SDIO->DCTRL = 0x0;

if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)

{

BlockSize = 512;

WriteAddr /= 512;

}

/*******************add,沒(méi)有這一段容易卡死在DMA檢測中*************************************/

/*!< Set Block Size for Card,cmd16,若是sdsc卡,可以用來(lái)設置塊大小,若是sdhc卡,塊大小為512字節,不受cmd16影響 */

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;   //r1

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);

if (SD_OK != errorstatus)

{

return(errorstatus);

}

/*********************************************************************************/

/*!< To improve performance  */

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; // cmd55

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_APP_CMD);

if (errorstatus != SD_OK)

{

return(errorstatus);

}

/*!< To improve performance *///  pre-erased,在多塊寫(xiě)入時(shí)可發(fā)送此命令進(jìn)行預擦除

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)NumberOfBlocks;  //參數為將要寫(xiě)入的塊數目

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT;  //cmd23

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_SET_BLOCK_COUNT);

if (errorstatus != SD_OK)

{

return(errorstatus);

}

/*!< Send CMD25 WRITE_MULT_BLOCK with argument data address */

SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)WriteAddr;

SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_BLOCK;

SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_WRITE_MULT_BLOCK);

if (SD_OK != errorstatus)

{

return(errorstatus);

}

SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;

SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;

SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;

SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;

SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;

SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;

SDIO_DataConfig(&SDIO_DataInitStructure);

SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);

SDIO_DMACmd(ENABLE);

SD_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * BlockSize));

return(errorstatus);

}

寫(xiě)操作在發(fā)送正式的多塊寫(xiě)入命令CMD25前調用了CMD23進(jìn)行預寫(xiě),這樣有利于提高寫(xiě)入的速度。在代碼的最后調用了SDIO_ITConfig(),SDIO的數據傳輸結束中斷就是這個(gè)時(shí)候開(kāi)啟的,數據傳輸結束時(shí),就進(jìn)入到stm32f10x_it.c文件中的中斷服務(wù)函數SDIO_IRQHandler()中處理了,中斷服務(wù)函數主要就是負責清中斷。

最后講一下官方原版的驅動(dòng)中的一個(gè)bug。

在官方原版的SDIO驅動(dòng)的SD_ReadBlock()、SD_ReadMultiBlocks()、SD_WriteBlock()和SD_WriteMultiBlocks()這幾個(gè)函數中,發(fā)送讀寫(xiě)命令前,漏掉了發(fā)送一個(gè)CMD16命令,這個(gè)命令用于設置讀寫(xiě)SD卡的塊大小。缺少這個(gè)命令很容易導致程序運行時(shí)卡死在循環(huán)檢測DMA傳輸結束的代碼中,網(wǎng)上很多人直接移植ST官方例程時(shí),用3.5版庫函數和這個(gè)4.5版的SDIO驅動(dòng)移植失敗,就是缺少了這段用CMD16設置塊大小的代碼。

到這里,終于講解完畢啦!這個(gè)講解如果能讓你從對SDIO一無(wú)所知到大概了解的話(huà),我的目標就達到啦,想要更深入了解還是要好好地配合這個(gè)例程中我在代碼中的注釋和附帶資料SD2.0協(xié)議《Simplified_Physical_Layer_Spec.pdf》好好研究一番! ^_^

注意:這個(gè)例程是沒(méi)有跑文件系統的,而是直接就去讀卡的block,這樣的話(huà)就會(huì )破壞卡的分區,在實(shí)驗完成之后,你再把卡插到電腦上時(shí),電腦會(huì )提示你要重新初始化卡,這是正常想象,并不是本實(shí)驗把你的卡弄壞了,如果卡原來(lái)有資料的請先把數據備份了再進(jìn)行測試。但跑文件系統時(shí)就不會(huì )出現這種問(wèn)題,有關(guān)文件系統的操作將在下一講的教程中講解。

1.5實(shí)驗現象

將野火STM32開(kāi)發(fā)板供電(DC5V),插上JLINK,插上串口線(xiàn)(兩頭都是母的交叉線(xiàn)),插上MicroSD卡( 我用的是1G ,經(jīng)測試,本驅動(dòng)也適用于2G以上的卡(sdhc卡)),打開(kāi)超級終端,配置超級終端為115200 8-N-1,將編譯好的程序下載到開(kāi)發(fā)板,即可看到超級終端打印出如下信息:

更多
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
STM32的SDIO控制SD卡
干貨 | STM32 SDIO折騰記
STM32的SDIO
物聯(lián)網(wǎng)技術(shù)入門(mén)
linux設備驅動(dòng)那點(diǎn)事兒之SD卡驅動(dòng)理論篇
SDIO
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久