[sd card] sd card初始化流程
以SD 3.0為例。
建議先參考《[sd card] SD card初始化時的總線設置》。
一、sd card初始化流程思路說明
通過《SD_Ver3.00_Final_090416》協議中“4.2 Card Identification Mode ”和“4.3 Data Transfer Mode ”來進行說明。
1、sd card操作模式和卡狀態
通過
sd card有如上card狀態以及對應的操作模式。
inactive mode
非激活模式。當host提供的電壓不在card的電壓的可用范圍之內時,會進入這種狀態。
這種狀態下,card不會響應任何命令。card identification mode
card識別模式,host激活card和識別card的模式。
這些操作都是在card對應的CMD線上完成,并且在card identification mode模式下的所有通訊都只能在CMD線上完成。
在卡識別的過程中,card應該工作在f-OD的工作頻率下。data transefer mode
數據傳輸模式,在這種模式下,host和card可以根據data線來傳輸數據
2、card identification mode流程說明
整個card identification mode都是外部對于sd card的初始化過程。
如下圖所示:
- 操作條件
卡識別模式。參考《SD_Ver3.00_Final_090416》“4.2 Card Identification Mode ”
顧名思義,就是識別card的一個模式。一個mmc總線上可以接多張card,因此需要在這個模式下識別和激活對應的card并使之進入對應的模式。
在卡識別模式下,host會先復位所有在Card Identification Mode下的card,驗證操作電壓的范圍,辨認card并且分配給其對應的RCA地址。
這些操作都是在card對應的CMD線上完成,并且在card identification mode模式下的所有通訊都只能在CMD線上完成。
在卡識別的過程中,card應該工作在f-OD的工作頻率下。
通過上述表格可以看出Card Identification Mode下,時鐘頻率不能超過400kHz。
card identification mode下有如下幾種操作
card reset
GO_IDLE_STATE(CMD0)命令是軟件復位命令,并且是一個廣播指令,可以使所有的card進入idle狀態(除了處于inactive狀態的card)。
如果是通過上電操作進行的復位,那么所有的card都會直接進入idle狀態,也包括之前處于inactive狀態的card。
不論是CMD0或這是power-on進行的復位,所有被復位的card的CMD線都會處于input狀態,等待下一次命令的起始位。同時,所有card會簡單的初始化,將其RCA地址設置為0x0000,并且設置一個默認的驅動強度模式。operation condition validation
這個操作是用于驗證card的操作條件。
在開始host和card的通訊之前,host并不知道card支持的工作電壓,并且card也不知道當前host提供的電壓是多少。在這種情況下,host會先假設card支持某個電壓并且將card的工作電壓設置成該電壓,然后發送給card復位命令CMD0。
為了驗證host假定的電壓是否被card支持,SD 2.0協議中定義了一個新的命令CMD8。SEND_IF_COND(CMD8)命令是用來驗證sd card接口的操作條件。card會通過分析SEND_IF_COND(CMD8)命令的參數來判斷host的操作條件的正確性(也就是工作電壓是否在card支持的范圍之內),card把SEND_IF_COND(CMD8)命令的參數中的VHS域(注意,同時只能有1個bit被設置成1)當作當前host提供的工作電壓以此來判斷是否當前的供電電壓是否符合。如果card檢測到供電電壓符合操作條件的話,會在response中返回自己支持的工作電壓。如果不符合的話,不會返回response并且仍處于idle狀態。host也會根據SEND_IF_COND(CMD8)命令的response中的VHS域來獲取card支持的工作電壓。注意,CMD8并不會因此card狀態發生變化,這種功能也可以通過ACMD41來實現!!!
ocr寄存器如下,主要關注VHS域:
- card initialization
card的內部初始化是在card處理非0參數ACMD41命令的過程中完成的。
- 首先看一下ACMD41的命令格式
- 在看一下ACMD41的response的格式
注意,host必須根據自己的狀態來設置ACMD41的參數。并且不斷發送ACMD41給card直到檢測到busy為1,此時的CCS和S18A才是可靠的。隨后,card進入了ready state。
card bus signal voltage switch
通常card剛上電的情況下,其信號電壓一般都是處于3.3V的模式。當card進入ready狀態后,為了節省功耗,首先需要考慮是是否需要切換信號電壓到1.8V。
前面說過,如果host支持輸出1.8V的信號電壓的話,會將ACMD41的參數的S18R(bit24)設置為1來告訴card。當card收到這個ACMD41時,如果自己允許切換到1.8V的信號電壓模式,那么就設置response的S18A(bit24)設置為1,否則設置為0。
當host從response的S18A(bit24)解析出1的時候,可以向card發送CMD11命令,來通知card準備切換到1.8V的信號電壓模式了。隨后,host就可以將自己的輸出的信號電壓切換到1.8V了。
此時,card還是處于ready state。card identification process
card識別過程。
host會向card發送ALL_SEND_CID(CMD2)命令來要求card發送它們各自獨一無二的cid寄存器的值。一旦card收到這條命令并且向host發送了自己的CID值,就會直接進入到identification state。
隨后,host會通過SEND_RELATIVE_ADDR(CMD3)命令來要求card自己編一個RCA地址并通過response返回給host,隨后card就會進入stand-by模式。而RCA地址則會作為在transfer mode中,該card的通訊地址。注意,如果host對于card自己發布的這個地址不滿意,可以重復發送CMD2要求card修改RCA地址直到自己滿意為止。
3、data transfer mode中和初始化相關的流程
通過identification mode之后,工作電壓和信號電壓都已經設置完成。但是總線寬度和總線速度模式并沒有設置。剛power-on或者是剛執行CMD0命令的card的總線寬度為1,總線速度模式為DS模式。而這部分內容的設置則是在data transfer mode中實現的!!!
總線速度模式的設置
參考《SD_Ver3.00_Final_090416》協議中“4.2 Card Identification Mode ”和“4.3 Data Transfer Mode ”來進行說明。
總線速度模式的設置主要以依賴于CMD6。說明
switch function command(CMD6)是用來切換或者擴展card的function。當前有四個function組定義如下:
(1)Access mode:訪問模式,用于選擇SD總線接口的速度模式(也就是我們這里的目標)
(2)Command system:命令系統,可以通過共享命令集來擴展和控制一個特殊的功能
(3)Driver strength:驅動強度,在UHS-I模式下用于選擇一個合適的驅動信號強度,取決于host的環境
(4)Current limit:電流限制,在UHS-I模式下設置card的最大電流,由host的供電屬性決定
CMD6只有在transfer state下才是可用的。一旦card復位之后,所有group默認都選中function0.
card會返回R1 response(CMD線)以及512bit的狀態數據(DAT線)作為對host的CMD6的響應。從sd傳輸標準上看,CMD6相當于一個單塊讀命令、超時時間是100ms。
card對于對于CMD6的切換動作會在狀態數據傳輸完之后的8個時鐘之內完成。當CMD6導致總線行為(例如總線速度模式)發生變化后,host要求至少要等CMD6傳輸完成之后的8個時鐘之后才允許使用新的總線行為進行通訊。CMD6的模式
CMD6有兩種模式,分別是check function模式和set function模式。
(1)check function模式用來查詢card所支持的function
(2)set function模式用來切換card的functionality
狀態圖如下:
- card的group和function
sd card支持6個function group,每個group最多支持16個function。如下圖所示,
- mode 1 operation——set function
CMD6 mode 1用來切換card的functionality。
CMD6切換總線模式為HS模式的示例如下 :
綜上,可以在card處于transfer state的情況下,host向card發送CMD6命令,參數設置為“1<<31 | 0xffff00 | 總線速度模式的function”,來實現card的總線速度模式的切換。
- 總線寬度的設置
參考“ 4.3.1 Wide Bus Selection/Deselection ”
上電之后或者執行CMD0命令之后,card的總線寬度模式總是默認設置為1bit模式。
可以通過ACMD6來設置card的總線寬度模式。ACMD6要求card處于transfer state,并且處于unlock狀態。
二、在sd card初始化過程中,host要做的事情
1、命令流程
參考《SD_Ver3.00_Final_090416》協議中“3.9.4 Bus Speed Modes Selection Sequence ”
從“一、sd card初始化流程思路說明”中,可以得到host在初始化card的過程中,需要向其發送如下命令序列。
2、host流程說明
根據card的外部初始化流程,可以簡單整理出host在sd各個狀態下需要做的操作流程如下(黑體部分是我們這里重點關心的部分):
未上電狀態
- (1)準備好工作電壓、信號電壓,上電
- (2)準備好時鐘(400kHz)
idle state
- (1)嘗試獲取一個合適的工作電壓
host發送CMD0命令進行復位
host發送CMD8命令,告訴card,host可以支持SD2.0。card收到CMD8命令之后會使能自己符合SD2.0的一些新功能
host發送參數為0的ACMD41命令,提取response中的VHS,得到card支持的工作電壓范圍
host選擇一個card和host都支持的最低的工作電壓,并將host提供給card的工作電壓設置為這個值。
這個值就是合法的,后續就以這個ocr作為工作電壓重新復位開始對sd card真正的初始化過程. - (2)重新復位,完成card的內部初始化
host發送CMD0命令進行復位
host發送CMD8命令,告訴card,host可以支持SD2.0。card收到CMD8命令之后會使能自己符合SD2.0的一些新功能。同時,獲取到ocr寄存器的值。
host根據host是否支持SDHC來設置ocr的HCS、是否支持1.8V來設置ocr的S18R,將設置好的ocr作為ACMD41的參數,發送給card。
host讀取ACMD41的busy位來判斷card的內部初始化是否完成,如果沒有完成繼續發送ACMD41
一旦card的內部初始化完成,則card進入ready state。
- (1)嘗試獲取一個合適的工作電壓
ready state
- (1)設置信號電壓
host根據ACMD41的response提取對應的S18A,如果為1,說明card支持切換到信號電壓為1.8V的模式。
host發送CMD11命令,要求card切換到1.8V的信號電壓模式。
host切換提供給card的信號電壓為1.8V。 - (2)獲取card的CID值
host發送CMD2命令,要求card回復其CID寄存器的值。
一旦card返回response之后,進入identification state。
- (1)設置信號電壓
identification state
- (1)獲取card的RCA值
host發送CMD3命令,要求card回復其RCA值。
一旦card通過response返回這個RCA之后,進入stand-by state。
identification mode也就完成了。
- (1)獲取card的RCA值
stand-by state——》transfer state
- (1)獲取sd card的特殊數據寄存器
csd寄存器中存儲了sd card的一些信息。
host發送CMD9命令,要求card回去其CSD寄存器(card specific data)的值 - (2)切換到transfer state模式
后續的初始化操作需要在transfer state下進行,所以需要發送CMD7命令選中對應的card,將card切換到transfer state - (3)獲取sd card的配置寄存器和狀態寄存器
host發送ACMD51命令,要求card回復其SCR寄存器(SD configuration register)的值
host發送ACMD13命令,要求card回復其SSR寄存器(SD status regiter)的值 - (4)讀取card 的switch狀態,也就是其支持的function
host發送CMD6命令來讀取card switch status。
通過card switch status可以得到card支持的總線速度模式以及驅動強度類型。 - (5)切換總線寬度
host發送ACMD11命令,要求card將總線寬度切換到4bit模式
設置host自身的總線寬度為4bit模式 - (6)選擇合適的總線速度模式、驅動強度、以及限流并進行設置
host從host和card都支持的總線速度模式中選擇一個最優的模式。
host根據選擇的總線速度模式,來選擇對應的驅動類型以及限流值,通過CMD6命令讓card進行相應值的切換。
host發送CMD6命令、并且mode=1、group=0、function=總線速度模式碼,card收到命令之后會切換到相應的總線速度模式上。
設置host自身的總線速度模式(時序,timing)。 - (7)執行tuning操作
對于UHS-I的card來說,如果處于uhs的速度模式,host需要發送CMD19執行tuning操作以獲取一個最佳的采樣點。
- (1)獲取sd card的特殊數據寄存器
到此,host對于sd card的初始化就完成了。
三、host初始化sd card代碼分析
整個代碼設計是圍繞著“在sd card初始化過程中,host要做的事情”的思想來設計的。
因此,可以看代碼的過程中,回頭看看前面的設計思想。了解了上述的初始化流程之后再來看代碼會感覺比較容易理解。
對應代碼drivers/mmc/core/sd.c、drivers/mmc/driver/core/sd-ops.c
1、mmc_rescan_try_freq
在《[mmc subsystem] mmc core(第六章)——mmc core主模塊》中已經說明過了當host檢測到card插入的情況下,最終會調用mmc_rescan_try_freq來識別和初始化card。
和sd相關的部分如下:
2、mmc_attach_sd
去掉無關的代碼部分如下:
int mmc_attach_sd(struct mmc_host *host) {int err;u32 ocr;int retries;/** 以下部分,連同mmc_rescan_try_freq中的mmc_go_idle和mmc_send_if_cond一起構成了“嘗試獲取一個合適的工作電壓” 的任務 **/err = mmc_send_app_op_cond(host, 0, &ocr);// host發送參數為0的ACMD41命令,提取response中的VHS,得到card支持的工作電壓范圍mmc_sd_attach_bus_ops(host); // 設置bus操作集為mmc_sd_ops_unsafe或者mmc_sd_ops,mmc subsystem的內容,這里我們不關心if (host->ocr_avail_sd)host->ocr_avail = host->ocr_avail_sd;host->ocr = mmc_select_voltage(host, ocr);// host選擇一個card和host都支持的最低的工作電壓,并將host提供給card的工作電壓設置為這個值。// 后續就以host->ocr作為工作電壓對sd card進行初始化retries = 5;while (retries && !host->rescan_disable) { /** 上述已經完成了card的識別操作,并且為card選擇了一個合適的工作電壓 **/ /** 后續調用mmc_sd_init_card對sd card進行初始化,也就是代碼核心 **/err = mmc_sd_init_card(host, host->ocr, NULL);if (err) {retries--;mmc_power_off(host); // 如果初始化失敗的情況下,需要重新掉電并上電,再嘗試進行初始化usleep_range(5000, 5500);mmc_power_up(host);mmc_select_voltage(host, host->ocr);continue;}break;}mmc_release_host(host);err = mmc_add_card(host->card);mmc_claim_host(host);mmc_init_clk_scaling(host);return 0; }3、mmc_sd_init_card
mmc_sd_init_card是在已經確定了host提供給card的工作電壓值的情況下,用來對sd card進行初始化的操作。
* 結合第二節,可以知道mmc_sd_init_card主要有如下工作(黑體的部分是我們重點關心的部分):
- 重新復位,完成card的內部初始化
- 設置信號電壓,包括card和host的設置
- 獲取card的CID值
- 獲取card的RCA值
- 獲取sd card的特殊數據寄存器
- 切換到transfer state模式
- 獲取sd card的配置寄存器和狀態寄存器
- 讀取card 的switch狀態,也就是其支持的function
- 切換總線寬度,包括card和host的設置
- 選擇合適的總線速度模式、驅動強度、以及限流并進行設置,包括card和host的設置
- 執行tuning操作
- 代碼如下:
4、mmc_sd_get_cid
在上面mmc_sd_init_card中被調用。從idle state到identification state的一個過程。
* 在mmc_sd_get_cid中的重要工作如下
- 重新復位,完成card的內部初始化
- 設置信號電壓,包括card和host的設置
- 獲取card的CID值
- 代碼如下:
5、mmc_sd_init_uhs_card
在上面mmc_sd_init_card中被調用。用來初始化uhs card的總線工作模式。
主要工作如下:
- 切換總線寬度,包括card和host的設置
- 選擇合適的總線速度模式、驅動強度、以及限流并進行設置,包括card和host的設置
- 執行tuning操作
代碼如下:
以上總線設置部分的詳細內容建議參考《[sd card] SD card初始化時的總線設置》
總結
以上是生活随笔為你收集整理的[sd card] sd card初始化流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyTorch线程池泄露Leaking
- 下一篇: 我和CSDN的故事(CDSN成立20周年