色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

SD NAND 的 SDIO在STM32上的應用詳解(下篇)

深圳市雷龍發展有限公司 ? 2022-12-08 16:14 ? 次閱讀

七.SDIO外設結構體

其實前面關于SDIO寄存器的講解已經比較詳細了,這里再借助于關于SDIO結構體再進行總結一遍。

標準庫函數對 SDIO 外設建立了三個初始化結構體,分別為 SDIO 初始化結構體SDIO_InitTypeDef、SDIO 命令初始化結構體 SDIO_CmdInitTypeDef 和 SDIO 數據初始化結
構體 SDIO_DataInitTypeDef。這些結構體成員用于設置 SDIO 工作環境參數,并由 SDIO 相應初始化配置函數或功能函數調用,這些參數將會被寫入到 SDIO 相應的寄存器,達到配置 SDIO 工作環境的目的。

至于為什么需要一個命令結構體與數據結構體,就是為了方便我們配置SDIO關于寄存器位,因為發送命令或者數據需要很多參數配置。

1.SDIO初始化結構體

SDIO 初始化結構體用于配置 SDIO 基本工作環境,比如時鐘分頻、時鐘沿、數據寬度等等。它被 SDIO_Init 函數使用。

1.png


1) SDIO_ClockEdge:主時鐘 SDIOCLK 產生 CLK 引腳時鐘有效沿選擇,可選上升沿或下降沿。

2.png


2) SDIO_ClockBypass:時鐘分頻旁路使用,可選使能或禁用,如果使能旁路,SDIOCLK (72MHZ )直接驅動 CLK 線輸出時鐘(不滿足最高25HZ的要求),如果禁用,使用 SDIO_CLKCR 寄存器的 CLKDIV 位值分頻 SDIOCLK,然后輸出到 CLK 線。一般選擇禁用時鐘分頻旁路。

3.png

3) SDIO_ClockPowerSave:節能模式選擇,可選使能或禁用,它設定 SDIO_CLKCR 寄存器的 PWRSAV 位的值。如果使能節能模式,CLK 線只有在總線激活時才有時鐘輸出;如果禁用節能模式,始終使能 CLK 線輸出時鐘。

4.png

4) SDIO_BusWide:數據線寬度選擇,可選 1 位數據總線、4 位數據總線或 8 為數據總線,系統默認使用 1 位數據總線,操作 SD 卡時在數據傳輸模式下一般選擇 4 位數據總線。它設定 SDIO_CLKCR 寄存器的 WIDBUS 位的值。

5.png

5) SDIO_HardwareFlowControl:硬件流控制選擇,可選使能或禁用,它設定SDIO_CLKCR 寄存器的 HWFC_EN 位的值。硬件流控制功能可以避免 FIFO 發送上溢和下溢錯誤。

6.png


6) SDIO_ClockDiv:時鐘分頻系數,它設定 SDIO_CLKCR 寄存器的 CLKDIV 位的值,設置 SDIOCLK 與 CLK 線輸出時鐘分頻系數:
CLK 線時鐘頻率=SDIOCLK/([CLKDIV+2])。

7.png

2.SDIO命令初始化結構體

8.png


1) SDIO_Argument:作為命令的一部分發送到卡的命令參數,它設定 SDIO 參數寄存器(SDIO_ARG)的值。

9.png


(2) SDIO_CmdIndex:命令號選擇,它設定 SDIO 命令寄存器(SDIO_CMD)的 CMDINDEX位的值。

10.png

(3) SDIO_Response:響應類型,SDIO 定義兩個響應類型:長響應和短響應。根據命令號選擇對應的響應類型。SDIO 定義了四個 32 位的 SDIO 響應寄存器(SDIO_RESPx,x=1…4),短響應只用SDIO_RESP1,長響應使用4個(SDIO_RESPx,x=1…4)。

11.png

1)命令響應寄存器

12.png


2)SDIO響應寄存器1~4

13.png

4) SDIO_Wait:等待類型選擇,有三種狀態可選,一種是無等待狀態,超時檢測功能啟動,一種是等待中斷,另外一種是等待傳輸完成。

14.png

5) SDIO_CPSM:命令路徑狀態機控制,可選使能或禁用 CPSM。它設定 SDIO_CMD 寄存器的 CPSMEN 位的值

15.png

只要我們使能的了命令狀態機,則下面發送命令和接收響應的過程中的狀態轉換就不用我們管了

16.png

當我們要發送命令,我們只需要配置這個命令初始化結構體的成員,然后調用下圖這個函數,則我們配置的參數寫入對應的寄存器位中。

17.png

3.SDIO數據初始化結構體

18.png


1) SDIO_DataTimeOut:設置數據傳輸以卡總線時鐘周期表示的超時周期,它設定 SDIO數據定時器寄存器(SDIO_DTIMER)的值。在 DPSM 進入 Wait_R 或繁忙狀態后開始遞減,直到 0 還處于以上兩種狀態則將超時狀態標志置 1(詳情前面的數據通道小節)。

19.png

2) SDIO_DataLength:設置傳輸數據長度。

20.png

3) SDIO_DataBlockSize:設置數據塊大小,有多種尺寸可選,不同命令要求的數據塊可能不同。

21.png


4) SDIO_TransferDir:數據傳輸方向,可選從主機到卡的寫操作,或從卡到主機的讀操作。

22.png

5) SDIO_TransferMode:數據傳輸模式,可選數據塊或數據流模式。對于 SD 卡操作使用數據塊類型。

23.png

6) SDIO_DPSM:數據路徑狀態機控制,可選使能或禁用 DPSM。它設定 SDIO_DCTRL寄存器的 DTEN 位的值。要實現數據傳輸都必須使能 SDIO_DPSM。

24.png


與命令一樣使能了數據路徑狀態機,就不用高那么多麻煩的狀態轉換了

八.SD卡讀寫測試實驗

我們平時使用的SD 卡都是已經包含有文件系統的,一般不會使用本實驗的操作方式讀寫 SD 卡,但是對學習SD卡的驅動原理非常重要!!!

本實驗是進行 SD卡最底層的數據讀寫操作,直接使用 SDIO 對 SD 卡進行讀寫,會損壞 SD 卡的文件系統,導致數據丟失,所以做這個實驗之前需要備份SD卡數據。

主要是學習SD卡的卡識別過程,以及數據傳輸工過程,其實就是完全依照前面的兩個流程圖來實現代碼的。

卡識別模式流程圖

25.png


數據傳輸流程圖

26.png

1.硬件設計

原理圖:

27.png


實物圖:

28.png

我這里用的是CS創世的貼片式SD卡,也稱之為SD NAND , 內部存儲單元架構為SLC,適合存代碼。直接上板時相比于拔插式SD卡在抗震和抗PIN氧化方面更有優勢,對于縮小整板體積也有一定幫助。

在這里插入圖片描述

詳情請參考:雷龍官網

30.png

2.代碼講解

先看主函數:

31.png32.png

SD_Terst函數:

33.png


我們主要講解的就是SD卡的初始化

34.png


SD_Init()函數:

/**

*函數名:SD_Init

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

*輸入:無

*輸出:-SD_ErrorSD卡錯誤代碼

*成功時則為SD_OK

*調用:外部調用

*/SD_ErrorSD_Init(void){

/*重置SD_Error狀態*/

SD_Errorerrorstatus=SD_OK;

NVIC_Configuration();

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

GPIO_Configuration();

/*對SDIO的所有寄存器進行復位*/

SDIO_DeInit();

/*上電并進行卡識別流程,確認卡的操作電壓*/

errorstatus=SD_PowerON();

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

if(errorstatus!=SD_OK)

{

/*!

return(errorstatus);

}

/*卡識別成功,進行卡初始化*/

errorstatus=SD_InitializeCards();

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

{

/*!

return(errorstatus);

}

/*配置SDIO外設

*上電識別,卡初始化都完成后,進入數據傳輸模式,提高讀寫速度

*/

/*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;

/*Bypass模式使能的話,SDIO_CK不經過SDIO_ClockDiv分頻*/

SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;

/*若開啟此功能,在總線空閑時關閉sd_clk時鐘*/

SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;

/*暫時配置成1bit模式*/

SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_1b;

/*硬件流,若開啟,在FIFO不能進行發送和接收數據時,數據傳輸暫停*/

SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;

SDIO_Init(&SDIO_InitStructure);

if(errorstatus==SD_OK)

{

/*用來讀取csd/cid寄存器*/

errorstatus=SD_GetCardInfo(&SDCardInfo);

}

if(errorstatus==SD_OK)

{

/*通過cmd7,rca選擇要操作的卡*/

errorstatus=SD_SelectDeselect((uint32_t)(SDCardInfo.RCA<

}

if(errorstatus==SD_OK)

{

/*最后為了提高讀寫,開啟4bits模式*/

errorstatus=SD_EnableWideBusOperation(SDIO_BusWide_4b);

}

return(errorstatus);}

接下來逐段代碼來分析一下:

35.png


errorstatus其實是一個SD_Error類型的枚舉變量,SD_Error 是
列舉了控制器可能出現的錯誤、比如 CRC 校驗錯誤、CRC 校驗錯誤、通信等待超時、FIFO 上溢或下溢、擦除命令錯誤等等。這些錯誤類型部分是控制器系統寄存器的標志位,部分是通過命令的響應內容得到的,如果是SD_OK則代表沒有發送錯誤,

36.png

配置SDIO中斷:

37.png


38.png


SDIO 外設底層引腳初始化

39.png


40.png

復位所有SDIO寄存器

41.png42.png

重點來了:調用SD_PowerON()進入卡識別模式

43.png

/*

*函數名:SD_PowerON

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

*輸入:無

*輸出:-SD_ErrorSD卡錯誤代碼

*成功時則為SD_OK

*調用:在SD_Init()調用

*/SD_ErrorSD_PowerON(void){

SD_Errorerrorstatus=SD_OK;

uint32_tresponse=0,count=0,validvoltage=0;

uint32_tSDType=SD_STD_CAPACITY;

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

/*上電初始化

*配置SDIO的外設

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

*初始化時的時鐘不能大于400KHz

*/

/*HCLK=72MHz,SDIOCLK=72MHz,SDIO_CK=HCLK/(178+2)=400KHz*/

SDIO_InitStructure.SDIO_ClockDiv=SDIO_INIT_CLK_DIV;

SDIO_InitStructure.SDIO_ClockEdge=SDIO_ClockEdge_Rising;

/*不使用bypass模式,直接用HCLK進行分頻得到SDIO_CK*/

SDIO_InitStructure.SDIO_ClockBypass=SDIO_ClockBypass_Disable;

/*空閑時不關閉時鐘電源*/

SDIO_InitStructure.SDIO_ClockPowerSave=SDIO_ClockPowerSave_Disable;

/*初始化的時候暫時先把數據線配置成1根*/

SDIO_InitStructure.SDIO_BusWide=SDIO_BusWide_1b;

/*失能硬件流控制*/

SDIO_InitStructure.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;

SDIO_Init(&SDIO_InitStructure);

/*開啟SDIO外設的電源*/

SDIO_SetPowerState(SDIO_PowerState_ON);

/*使能SDIO時鐘*/

SDIO_ClockCmd(ENABLE);/********************************************************************************************************/

/*下面發送一系列命令,開始卡識別流程

*CMD0:GO_IDLE_STATE(復位所以SD卡進入空閑狀態)

*沒有響應

*/

SDIO_CmdInitStructure.SDIO_Argument=0x0;

SDIO_CmdInitStructure.SDIO_CmdIndex=SD_CMD_GO_IDLE_STATE;

/*沒有響應*/

SDIO_CmdInitStructure.SDIO_Response=SDIO_Response_No;

/*關閉等待中斷*/

SDIO_CmdInitStructure.SDIO_Wait=SDIO_Wait_No;

/*CPSM在開始發送命令之前等待數據傳輸結束*/

SDIO_CmdInitStructure.SDIO_CPSM=SDIO_CPSM_Enable;

SDIO_SendCommand(&SDIO_CmdInitStructure);

/*檢測是否正確接收到cmd0*/

errorstatus=CmdError();

/*命令發送出錯,返回*/

if(errorstatus!=SD_OK)

{

/*CMDResponseTimeOut(waitforCMDSENTflag)*/

return(errorstatus);

}/********************************************************************************************************/

/*CMD8:SEND_IF_COND

*發送CMD8檢查SD卡的電壓操作條件

*

*參數:-[31:12]:保留(要被設置為'0')

*-[11:8]:支持的電壓(VHS)0x1(范圍:2.7-3.6V)

*-[7:0]:校驗模式(推薦0xAA)

*響應類型:R7

*/

/*接收到命令sd會返回這個參數*/

SDIO_CmdInitStructure.SDIO_Argument=SD_CHECK_PATTERN;

SDIO_CmdInitStructure.SDIO_CmdIndex=SDIO_SEND_IF_COND;

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=CmdResp7Error();

/*有響應則card遵循sd協議2.0版本*/

if(errorstatus==SD_OK)

{

/*SDCard2.0,先把它定義會sdsc類型的卡*/

CardType=SDIO_STD_CAPACITY_SD_CARD_V2_0;

/*這個變量用作ACMD41的參數,用來詢問是sdsc卡還是sdhc卡*/

SDType=SD_HIGH_CAPACITY;

}

else /*無響應,說明是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

*發送cmd55,用于檢測是sd卡還是mmc卡,或是不支持的卡

*CMD響應:R1

*/

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);

/*是否響應,沒響應的是mmc或不支持的卡*/

errorstatus=CmdResp1Error(SD_CMD_APP_CMD); /********************************************************************************************************/

/*若errorstatus為CommandTimeOut,說明是MMC卡

*若errorstatus為SD_OK,說明是SDcard:SD卡2.0(電壓范圍不匹配)

*或SD卡1.x

*/

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

{

/*下面開始循環地發送sdio支持的電壓范圍,循環一定次數*/

/*SDCARD

*發送ACMD41SD_APP_OP_COND,帶參數0x80100000

*/

while((!validvoltage)&&(count

{

/*在發送ACMD命令前都要先向卡發送CMD55

*發送CMD55APP_CMD,RCA為0

*/

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);

if(errorstatus!=SD_OK)

{

return(errorstatus);

}

/*ACMD41

*命令參數由支持的電壓范圍及HCS位組成,HCS位置一來區分卡是SDSC還是SDHC

*0:SDSC

*1:SDHC

*響應:R3,對應的是OCR寄存器

*/

SDIO_CmdInitStructure.SDIO_Argument=SD_VOLTAGE_WINDOW_SD|SDType;

SDIO_CmdInitStructure.SDIO_CmdIndex=SD_CMD_SD_APP_OP_COND;

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=CmdResp3Error();

if(errorstatus!=SD_OK)

{

return(errorstatus);

}

/*若卡需求電壓在SDIO的供電電壓范圍內,會自動上電并標志pwr_up位

*讀取卡寄存器,卡狀態

*/

response=SDIO_GetResponse(SDIO_RESP1);

/*讀取卡的ocr寄存器的pwr_up位,看是否已工作在正常電壓*/

validvoltage=(((response>>31)==1)?1:0);

count++; /*計算循環次數*/

}

if(count>=SD_MAX_VOLT_TRIAL) /*循環檢測超過一定次數還沒上電*/

{

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

return(errorstatus);

}

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

/*判斷ocr中的ccs位,如果是sdsc卡則不執行下面的語句*/

if(response&=SD_HIGH_CAPACITY)

{

CardType=SDIO_HIGH_CAPACITY_SD_CARD;/*把卡類型從初始化的sdsc型改為sdhc型*/

}

}/*elseMMCCard*/

return(errorstatus); }

1.配置SDIO初始化結構體**

44.png


配置 SDIO_InitStructure 結構體變量成員并調用 SDIO_Init 庫函數完成 SDIO 外設的基本配置,注意此處的 SDIO 時鐘分頻,由于處于卡識別階段,其時鐘不能超過 400KHz。

45.png

2.發送CMD0命令:要SD卡回到空閑狀態

46.png


47.png


那些檢測標志全是來源與下圖:

48.png


3.發送CMD8: 用來識別不同版本的卡和檢測卡是否能在主機提供的電壓下工作。

如果發送CMD8無響應:

1.電壓不匹配的 2.0 以上 SD 卡
2.1.0 的 SD 卡
3.不是 SD 卡

如果發送CMD8有響應:
電壓匹配的 2.0 以上 SD 卡(就是我們即將要使用的SD卡)

49.png

4.使用 ACMD41 命令判斷卡的具體類型。因為是 A 類命令,所以在發送 ACMD41之前必須先發送 CMD55,CMD55 命令的響應類型的 R1。如果 CMD55 命令都沒有響應說明是 MMC 卡或不可用卡。在正確發送 CMD55 之后就可以送ACMD41,并根據響應判斷卡類型,ACMD41 的響應號為 R3,CmdResp3Error 函數用于檢測命令正確發送并帶有超時檢測功能,但并不具備響應內容接收功能,需要在判定命令正確發送之后調用 SDIO_GetResponse 函數才能獲取響應的內容。

實際上,在有響應時,SDIO 外設會自動把響應存放在 SDIO_RESPx 寄存器中,SDIO_GetResponse 函數只是根據形參返回對應響應寄存器的值。通過判定響應內容值即可確定 SD 卡類型。

50.png


51.png

總結:執行 SD_PowerON 函數無錯誤后就已經確定了 SD 卡類型,并說明卡和主機電壓是匹配的,SD 卡處于卡識別模式下的準備狀態。退出 SD_PowerON 函數返回SD_Init 函數,執行接下來代碼。

執行 SD_PowerON 函數沒有錯誤后:SD 卡處于卡識別模式下的準備狀態

52.png53.png


SD_InitializeCards()函數:

/*

*函數名:SD_InitializeCards

*描述:初始化所有的卡或者單個卡進入就緒狀態

*輸入:無

*輸出:-SD_ErrorSD卡錯誤代碼

*成功時則為SD_OK

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

*/SD_ErrorSD_InitializeCards(void){

SD_Errorerrorstatus=SD_OK;

uint16_trca=0x01;

if(SDIO_GetPowerState()==SDIO_PowerState_OFF)

{

errorstatus=SD_REQUEST_NOT_APPLICABLE;

return(errorstatus);

}

/*判斷卡的類型*/

if(SDIO_SECURE_DIGITAL_IO_CARD!=CardType)

{

/*SendCMD2ALL_SEND_CID

*響應:R2,對應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信息存儲起來*/

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);

}/********************************************************************************************************/

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的卡*/

{

/*SendCMD3SET_REL_ADDRwithargument0

*SDCardpublishesitsRCA.

*響應:R6,對應RCA寄存器

*/

SDIO_CmdInitStructure.SDIO_Argument=0x00;

SDIO_CmdInitStructure.SDIO_CmdIndex=SD_CMD_SET_REL_ADDR;

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=CmdResp6Error(SD_CMD_SET_REL_ADDR,&rca);

if(SD_OK!=errorstatus)

{

return(errorstatus);

}

}/********************************************************************************************************/

if(SDIO_SECURE_DIGITAL_IO_CARD!=CardType)

{

RCA=rca;

/*SendCMD9SEND_CSDwithargumentascard'sRCA

*響應:R2對應寄存器CSD(Card-SpecificData)

*/

SDIO_CmdInitStructure.SDIO_Argument=(uint32_t)(rca<

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;

return(errorstatus);}

1.判斷 SDIO 電源是否啟動,如果沒有啟動電源返回錯誤。

54.png


2.發送CMD2命令 :是用于通知所有卡通過 CMD 線返回 CID 值,執行 CMD2 發送之后就可以使用 CmdResp2Error 函數獲取 CMD2 命令發送情況,發送無錯誤后即可以使用 SDIO_GetResponse 函數獲取響應內容,它是個長響應,我們把 CMD2 響應內容存放在 CID_Tab 數組內。

55.png


3.發送CMD3命令,用于指示 SD 卡自行推薦 RCA 地址,CMD3 的響應為 R6 類型,CmdResp6Error 函數用于檢查 R6 響應錯誤,它有兩個形參,一個是命令號,這里為 CMD3,另外一個是 RCA 數據指針,這里使用 rca變量的地址賦值給它,使得在 CMD3 正確響應之后 rca 變量即存放 SD 卡的 RCA。

56.png

CmdResp6Error 函數通用會對每個錯誤位進行必要的檢測,如果發現有錯誤存在則直接返回對應錯誤類型。

57.png

執行完CmdResp6Error 函數之后返回到 SD_InitializeCards 函數中,如果判斷無錯誤說明此刻 SD 卡已經處于數據傳輸模式。

58.png


4.發送 CMD9 給指定 RCA 的 SD 卡使其發送返回其 CSD 寄存器內容,這里的 RCA就是在 CmdResp6Error 函數獲取得到的 rca。最后把響應內容存放在 CSD_Tab 數組中。

59.png


在這里插入圖片描述


執行 SD_InitializeCards 函數無錯誤后 SD 卡就已經處于數據傳輸模式下的待機狀態,退出 SD_InitializeCards 后會返回前面的 SD_Init 函數,執行接下來代碼,以下是 SD_Init 函數的后續執行過程:

60.png


1) 重新配置 SDIO 外設,提高時鐘頻率,之前的卡識別模式都設定 CMD 線時鐘為小于 400KHz,進入數據傳輸模式可以把時鐘設置為小于 25MHz,以便提高數據傳輸速率。

61.png


(2) 調用 SD_GetCardInfo 函數獲取 SD 卡信息,它需要一個指向 SD_CardInfo 類型變量地址的指針形參,這里賦值為 SDCardInfo 變量的地址。SD 卡信息主要是 CID和 CSD 寄存器內容,這兩個寄存器內容在 SD_InitializeCards 函數中都完成讀取過程并將其分別存放在CID_Tab 數組和CSD_Tab 數組中,SD_GetCardInfo 函數只是簡單的把這兩個數組內容整合復制到 SDCardInfo 變量對應成員內。正確執行 SD_GetCardInfo 函數后,SDCardInfo 變量就存放了 SD 卡的很多狀態信息,這在之后應用中使用頻率是很高的。

62.png

結構體類型定義:有 SD_CSD、SD_CID、SD_CardStatus 以及 SD_CardInfo。SD_CSD 定義了 SD 卡的特定數據(CSD)寄存器位,一般提供 R2 類型的響應可以獲取得到 CSD 寄存器內容。SD_CID 結構體類似 SD_CSD 結構體,它定義 SD 卡CID 寄存器內容,也是通過 R2 響應類型獲取得到。SD_CardStatus 結構體定義了SD 卡狀態,有數據寬度、卡類型、速度等級、擦除寬度、傳輸偏移地址等等 SD卡狀態。SD_CardInfo 結構體定義了 SD 卡信息,包括了 SD_CSD 類型和 SD_CID類型成員,還有定義了卡容量、卡塊大小、卡相對地址 RCA 和卡類型成員。

63.png


主要是存儲卡的容量,卡的大小,RCA地址,卡的類型(這些是關鍵信息,由命令響應返回然后存入這個結構體中)

64.png


65.png


66.png


3) 調用 SD_SelectDeselect 函數用于選擇特定 RCA 的 SD 卡,它實際是向 SD 卡發送CMD7。執行之后,卡就從待機狀態轉變為傳輸模式,可以說數據傳輸已經是萬事俱備了

67.png


68.png


70.png


4) 擴展數據線寬度,之前的所有操作都是使用一根數據線傳輸完成的,使用 4 根數據線可以提高傳輸性能,調用可以設置數據線寬度,函數只有一個形參,用于指定數據線寬度。

71.png


至此,SD_Init 函數已經全部執行完成。如果程序可以正確執行,接下來就可以進行SD 卡讀寫以及擦除等操作。

72.png


SD_EraseTest()函數

73.png


SD_Erase()函數:

74.png


75.png


1) 檢查 SD 卡是否支持擦除功能,如果不支持則直接返回錯誤。為保證擦除指令正常進行,要求主機一個遵循下面的命令序列發送指令:CMD32->CMD33->CMD38。如果發送順序不對,SD 卡會設置 ERASE_SEQ_ERROR 位到狀態寄存器

76.png


77.png


2) SD_Erase 函數發送 CMD32 指令用于設定擦除塊開始地址,在執行無錯誤后發送CMD33 設置擦除塊的結束地址。

78.png

3) 發送擦除命令 CMD38,使得 SD 卡進行擦除操作。SD 卡擦除操作由 SD 卡內部控制完成,不同卡擦除后是 0xff 還是 0x00 由廠家決定。擦除操作需要花費一定時間,這段時間不能對 SD 卡進行其他操作。

79.png

4) 通過 IsCardProgramming 函數可以檢測 SD 卡是否處于編程狀態(即卡內部的擦寫狀態),需要確保 SD 卡擦除完成才退出 SD_Erase 函數。IsCardProgramming 函數先通過發送CMD13 命令 SD 卡發送它的狀態寄存器內容,并對響應內容進行分析得出當前 SD 卡的狀態以及可能發送的錯誤。

80.png

數據寫入操作

81.png


82.png83.png


SD_WriteBlock 函數用于向指定的目標地址寫入一個塊的數據,它有三個形參,分別為指向待寫入數據的首地址的指針變量、目標寫入地址和塊大小。塊大小一般都設置為512 字節。SD_WriteBlock 寫入函數的執行流程如下:

1) SD_WriteBlock 函數開始時將 SDIO 數據控制寄存器 (SDIO_DCTRL)清零,復位之前的傳輸設置。

在這里插入圖片描述

2) 對 SD 卡進行數據讀寫之前,都必須發送 CMD16 指定塊的大小,對于標準卡,要寫入BlockSize 長度字節的塊;對于 SDHC 卡,寫入固定為 512 字節的塊。接下來就可以發送塊寫入命令 CMD24 通知 SD 卡要進行數據寫入操作,并指定待寫入數據的目標地址。

在這里插入圖片描述84.png

3) 利用 SDIO_DataInitTypeDef 結構體類型變量配置數據傳輸的超時、塊數量、數據塊大小、數據傳輸方向等參數并使用 SDIO_DataConfig 函數完成數據傳輸環境配置。

85.png

4) 調用 SDIO_ITConfig 函數使能 SDIO 數據結束傳輸結束中斷,傳輸結束時,會跳轉到SDIO 的中斷服務函數運行。
5)SD_DMA_TxConfig 函數,配置使能 SDIO 數據向 SD 卡的數據傳輸的DMA 請求,為使 SDIO 發送 DMA 請求,需要調用
SDIO_DMACmd 函數使能。對于高容量的 SD 卡要求塊大小必須為 512 字節,SDIO 外設會自動生成 DMA 發送請求,將指定數據使用 DMA 傳輸寫入到 SD 卡內。

普通模式需要自己去處理那些溢出什么的太麻煩了,用DMA傳輸數據就好了

86.png

DMA外設配置(不清楚的參考:DMA外設詳解):

87.png


88.png

寫入操作等待函數
SD_WaitWriteOperation 函數用于檢測和等待數據寫入完成,在調用數據寫入函數之后一般都需要調用,SD_WaitWriteOperation 函數適用于單塊及多塊寫入函數。

89.png


SDIO 中斷服務函數
在進行數據傳輸操作時都會使能相關標志中斷,用于跟蹤傳輸進程和錯誤檢測。
SD_ProcessIRQSrc 函數首先判斷全局變量 StopCondition 變量是否為 1,該全局變量在SDIO 的多塊讀寫函數中被置 1(前面分析的單塊讀寫函數中 StopCondition 均為 0),因為根據 SD 卡的要求,多塊讀寫命令由 CMD12 結束,SD 卡在接收到該命令時才停止多塊的傳輸,此處正是根據 StopCondition 的情況控制是否發送 CMD12 命令,它發送命令時直接采用往寄存器寫入命令和參數的方式。

90.png


91.png


92.png

調用庫函數 SD_DMAEndOfTransferStatus 一直檢測 DMA 的傳輸完成標志,當 DMA 傳輸結束時,該函數會返回 SET 值。另外,while 循環中的判斷條件使用的TransferEnd 和 TransferError 是全局變量,它們會在 SDIO 的中斷服務函數根據傳輸情況被設置,傳輸結束后,根據 TransferError 的值來確認是否正確傳輸,若不正確則直接返回錯
誤代碼。SD_WaitWriteOperation 函數最后是清除相關標志位并返回錯誤。

數據讀取操作
同向 SD 卡寫入數據類似,從 SD 卡讀取數據可分為單塊讀取和多塊讀取。這里僅介紹單塊讀操作函數,多塊讀操作類似。

這一部分自己看代碼吧,操作差不多,已經人麻了太多了。

93.png94.png

還有多塊讀取與多塊寫入,其實是一樣的,只不過傳輸結束需要發送CMD12來結束傳輸。

總結:代碼太多了,但是核心的東西已經講完了,自己去看代碼悟一下,其實前面的理論部分懂了,代碼部分是完全按照理論來走的,只不過多了一點點細節,就這樣咯,那些邊邊角角留給你們。

3.實驗結果

在這里插入圖片描述95.png96.png

【本文轉載自CSDN,作者:rivencode】


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FlaSh
    +關注

    關注

    10

    文章

    1637

    瀏覽量

    148114
  • 閃存芯片
    +關注

    關注

    1

    文章

    120

    瀏覽量

    19627
  • 存儲芯片
    +關注

    關注

    11

    文章

    897

    瀏覽量

    43161
  • emmc
    +關注

    關注

    7

    文章

    216

    瀏覽量

    52765
收藏 人收藏

    評論

    相關推薦

    STM32F407 MCU使用SD NAND?不斷電初始化失效解決方案

    STM32F407微控制器單元(MCU)與SD NAND的結合提供了強大的存儲解決方案。然而,不斷電初始化失效問題可能會導致系統穩定性和數據完整性受損。我們將STM32F407與
    的頭像 發表于 12-11 10:51 ?357次閱讀
    <b class='flag-5'>STM32</b>F407 MCU使用<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>?不斷電初始化失效解決方案

    關于SD NAND 的概述

    SD NAND是一種小型、可表面貼裝的存儲解決方案,適用于各種嵌入式系統和便攜式設備。SD NAND技術是近年來存儲領域內的一項創新,它結
    發表于 12-06 11:22

    SD NAND 概述

    SD NAND是一種小型、可表面貼裝的存儲解決方案,適用于各種嵌入式系統和便攜式設備。SD NAND技術是近年來存儲領域內的一項創新,它結
    的頭像 發表于 12-06 11:21 ?185次閱讀

    SD NAND技術簡介

    SD NAND是一種基于NAND Flash技術的嵌入式存儲解決方案,具備SD卡協議兼容性。它結合了NAND存儲的高密度特性和
    的頭像 發表于 12-05 15:32 ?179次閱讀
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>技術簡介

    SD NAND大數據時代的應用場景

    SD NAND是一種結合了SD卡接口和NAND閃存技術的存儲解決方案。它通常指的是使用NAND閃存芯片并通過
    的頭像 發表于 10-29 15:49 ?244次閱讀
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b><b class='flag-5'>在</b>大數據時代的應用場景

    SD NAND智能眼鏡的怎么應用

    接口和NAND閃存技術的存儲解決方案,它通常被用在需要高容量、小尺寸和低功耗存儲的設備智能眼鏡的應用中,SD NAND可以扮演以下角色
    的頭像 發表于 09-14 09:55 ?362次閱讀
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b><b class='flag-5'>在</b>智能眼鏡<b class='flag-5'>上</b>的怎么應用

    MK米客方德SD NANDSTM32平臺的存儲方案

    STM32平臺SD卡的重要性不言而喻,它為嵌入式系統提供了必要的數據存儲和讀寫能力。MK米客方德SD作為市場上的一種選擇,因其耐用性、
    的頭像 發表于 08-26 10:23 ?692次閱讀
    MK米客方德<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>:<b class='flag-5'>STM32</b>平臺<b class='flag-5'>上</b>的存儲方案

    SD NAND芯片的測評與使用 基于卷積神經網絡的數字識別

    和32gbit的SD NAND FLASH芯片以及一份測試板卡。 簡介: 根據官方文檔的描述,這款芯片采用LGA-8封裝,具有標準SDIO接口,并同時兼容SPI和SD接口。因此,可以直
    的頭像 發表于 07-24 18:08 ?1426次閱讀

    淺談SD NAND

    SD NAND內部主要由NAND Flash和Flash Controller組成,大多數人把NAND FLASH 叫做閃存,是一種長壽命的非易失性的存儲器,即使
    的頭像 發表于 06-25 14:20 ?904次閱讀
    淺談<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>

    SD NAND和SPI NAND的區別

    SD NAND和SPI NAND各有優缺點,適用于不同的應用場景。SD NAND提供更高的讀寫速度和大容量存儲,適合需要高性能和大容量存儲的
    的頭像 發表于 06-04 14:26 ?2083次閱讀

    NAND Flash(貼片式TF卡)存儲新突破,基礎示例

    需求也日益增長。在這個信息爆炸的時代,一款高效、穩定、便攜的存儲設備顯得尤為重要。新品SD卡——SD NAND,應運而生,為我們的數據存儲帶來了新的革命。   
    發表于 05-21 17:13

    STM32F412使用SD卡,SDIO,FATFS系統,SD卡掛載文件系統失敗的原因?

    求助,STM32F412RET6 使用SD卡,使用SDIO接口,FATFS系統,SD卡掛載文件系統失敗。返回錯誤代碼3: 網上查到信息 \"FR_NOT_READY:物理驅動沒有工作
    發表于 04-11 07:15

    stm32 CubeMx 怎么實現SD卡/sd nand FATFS讀寫測試

    本實驗僅用于記錄和分享技術經驗若涉及侵權請聯系我刪除。   stm32 CubeMx 實現SD卡/sd nand FATFS讀寫測試。   材料:s
    發表于 01-09 17:37

    什么是SD NAND存儲芯片? SD NAND與TF卡的區別

    什么是SD NAND?它俗稱貼片式T卡,貼片式TF卡,貼片式SD卡,貼片式內存卡,貼片式閃存卡,貼片式卡...等等。雖然SD NAND 和T
    的頭像 發表于 01-06 14:35 ?1812次閱讀
    什么是<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>存儲芯片? <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>與TF卡的區別

    什么是SD NAND存儲芯片?

    前言   大家好,我們一般STM32項目開發中或者在其他嵌入式開發中,經常會用到存儲芯片存儲數據。今天我和大家來介紹一款存儲芯片,我這里采用(雷龍) CS創世 SD NAND
    發表于 01-05 17:54
    主站蜘蛛池模板: wankz tv videos国产| 国产日韩精品SUV| 自拍 偷拍 亚洲 经典| 久久九九有精品国产23百花影院| 一个人HD在线观看免费高清视频| 国产 在线 亚洲 欧美 动漫| 无套暴躁白丝秘书| 黄色a级免费网站| 中文字幕人妻无码系列第三区 | 色琪琪丁香婷婷综合久久| 97午夜理论片影院在线播放| 久久偷拍vs国产在线播放| 99日韩精品| 欧美一第一页草草影院| 国产高潮久久精品AV无码| 亚洲字幕久久| 啪啪羞羞GIF男女0OXX动态图| 国产日韩精品一区二区三区在线| 孕妇bbwbbwbbwbbw超清 | 双性大乳浪受噗呲噗呲h总| 纯肉合集(高H)| 亚洲欧美日韩中字视频三区| 黄色aa大片| WWW婷婷AV久久久影片| 亚洲精品一二三区-久久| 久久精品影院永久网址| seyeye免费高清观看| 亚洲日本激情| 人妻夜夜爽天天爽三区麻豆AV网站| wankz tv videos国产| 亚洲精品久久一区二区三区四区| 欧美hdxxxx| 国产精品大陆在线视频| 中文字幕亚洲无线码在线| 婷婷综合亚洲爱久久| 黄色三级在线观看| 趁老师睡着吃她的奶水| 小莹的性荡生活40章| 嫩草影院在线观看精品视频| 国产一区内射最近更新| 成人高清网站|