日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[sd card] sd card初始化流程

發布時間:2024/3/7 编程问答 78 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [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域:

__注意,重要,雖然ACMD41也可以用來獲取card支持的工作電壓,但是必須在發送ACMD41之前先發送CMD8。因為當card收到CMD8之后,就會知道host是支持SD 2.0協議的,便會使能自己的一些符合SD 2.0的新功能。同時,對于低電壓host來說,先發送CMD8也是必須的。因為如果一個雙電壓card(支持高電壓和低電壓)沒有接收到CMD8的話,只會工作在高電壓模式,此時如果該card收到了ACMD41會誤以為工作電壓不符合操作條件,就會進入inactive模式。__ SD_SEND_OP_CON(ACMD41)是讓card用來驗證工作電壓、并且拒絕不符合操作條件的host的命令。host會將自己的提供的供電范圍作為ACMD41的參數,card收到ACMD41命令之后如果檢測到供電范圍不符合自己的標準,就會進入到inactive狀態。后面會繼續說明的。 __當ACMD41的參數為0時,所有的card都會返回自己支持的工作電壓(ocr)并且不會進到inactive模式。所以,host可以先設定一個比較通用的工作點發送一個參數為0的ACMD41、從得到的response中獲取card支持的工作電壓,此時card并不會進行其他操作。然后host根據card支持的工作電壓、選擇一個合適的電壓為card進行供電。__
  • card initialization
    card的內部初始化是在card處理非0參數ACMD41命令的過程中完成的。
    • 首先看一下ACMD41的命令格式

參數位的意義如下: bit23-8:ocr,當前使用的工作電壓 bit24:S18R,當host支持1.8V的信號電壓時,設置這個bit。card如果自己也支持1.8V的信號電壓的模式的話,會在response中設置同樣位置的位。 bit28:SDXC的電源控制功能。并沒有詳細說明。 bit30:HCS,host capacity support,當設置為0時,表示host只支持SDSC類型的card,當設置為1時,說明host支持處理SDHC和SDXC類型的card。 __host向card發送SD_SEND_OP_CON(ACMD41)命令可以觸發card的內部初始化流程。而card會根據上述的位設置進行響應的處理。注意,是在card收到CMD8命令后的前提下,否則,上述有些位card會直接忽略掉。__
  • 在看一下ACMD41的response的格式

bit24:S18A,當card收到的ACMD41的S18R為1時,會在這個位設置自己是否支持切換到1.8V的信號電壓的模式下,如果支持,那么設置S18A為1.bit30:CCS,card capacity status,card的容量狀態。當card收到的ACMD41的HCS為1時(也就是host支持處理SDHC或者SDXC card),如果該card是SDHC或者SDXC,那么就將這個位設置為1,否則,設置為0.bit31:busy,當card收到參數不為0的ACMD41命令時,就開始進行內部初始化,如果返回response時初始化還沒有完成,那么這個位設置為0。否則,設置為1。

注意,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。如下圖所示,

每一個group同時只能有一個function被選中。并且function0是默認的function。 __在設置總線速度的過程中,我們需要關注的就是group1,也就是access mode。__
  • mode 1 operation——set function
    CMD6 mode 1用來切換card的functionality。
    CMD6切換總線模式為HS模式的示例如下

參數:bit31——》mode,這里應該設置為1對于不需要切換function的group直接設置為0xf,對于要修改function的group、設置其function值即可。

綜上,可以在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。
  • 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。
  • identification state

    • (1)獲取card的RCA值
      host發送CMD3命令,要求card回復其RCA值。
      一旦card通過response返回這個RCA之后,進入stand-by state。
      identification mode也就完成了。
  • 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操作以獲取一個最佳的采樣點。

到此,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相關的部分如下:

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) {host->f_init = freq; // 設置初始化頻率,取決于host的頻率表中的最低頻率,一般是400KHz/** 給card上電的準備動作 **/mmc_power_up(host);// 對應上述“未上電狀態”,主要的設置有(都是和協議中默認card上電之后的狀態是一致的,這樣才能發起通訊):// 1、host->ios.vdd,選擇host的可以提供的最低的輸出電壓,作為card的工作電壓// 2、host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN,設置總線模式為開漏模式// 3、host->ios.power_mode = MMC_POWER_UP,設置電源狀態為上電模式// 4、host->ios.bus_width = MMC_BUS_WIDTH_1,設置總線寬度為1bit模式// 5、host->ios.timing = MMC_TIMING_LEGACY,設置總線速度模式為傳統模式,對于SD來說,就是DS模式// 6、host->ios.clock = host->f_init,設置時鐘頻率,取決于host的頻率表中的最低頻率,一般是400KHz。由SD2.0協議可以知道不能超過400KHz// 7、host->ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330,設置信號電壓為3.3V模式// 8、以上設置完成后,card的上電工作已經完成,設置電源狀態為MMC_POWER_ON模式/** 以下開始做card的初始化操作 **/mmc_go_idle(host);// host發送CMD0命令進行復位mmc_send_if_cond(host, host->ocr_avail);// host發送CMD8命令,告訴card,host可以支持SD2.0。card收到CMD8命令之后會使能自己符合SD2.0的一些新功能/* Order's important: probe SDIO, then SD, then MMC */if (!mmc_attach_sdio(host)) // 先嘗試將card當作sdio設備進行識別和初始化,通過CMD5命令進行區分return 0;/** mmc_attach_sd就是對sd card進行識別和初始化的入口動作 **/if (!mmc_attach_sd(host)) // 再嘗試將card當作sd設備進行識別和初始化,通過ACMD41命令進行區分return 0;if (!mmc_attach_mmc(host)) // 最后嘗試將card當作sd設備進行識別和初始化return 0;mmc_power_off(host);return -EIO;

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操作

  • 代碼如下:
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,struct mmc_card *oldcard) {struct mmc_card *card;int err;u32 cid[4];u32 rocr = 0;BUG_ON(!host);WARN_ON(!host->claimed);/** 在mmc_sd_get_cid中完成如下工作::: **/ /** 重新復位,完成card的內部初始化 **/ /** 設置信號電壓,包括card和host的設置 **/ /** 獲取card的CID值 **/err = mmc_sd_get_cid(host, ocr, cid, &rocr); // 調用mmc_sd_get_cid進行復位、內部初始化,設置信號電壓,然后獲取CID值,最終card進入了identification state。// mmc_sd_get_cid看后續說明if (oldcard) {if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)return -ENOENT;card = oldcard;} else {card = mmc_alloc_card(host, &sd_type); card->type = MMC_TYPE_SD;memcpy(card->raw_cid, cid, sizeof(card->raw_cid));// 和mmc subsystem相關的內容,為sd card分配一個mmc_card結構體,這里我們不關心}/** 獲取card的RCA值 **/if (!mmc_host_is_spi(host)) {err = mmc_send_relative_addr(host, &card->rca); // 調用mmc_send_relative_addr發送CMD3命令,要求card回復其RCA值。// 一旦card通過response返回這個RCA之后,進入stand-by statehost->card = card;}/** 獲取sd card的特殊數據寄存器 **/if (!oldcard) {err = mmc_sd_get_csd(host, card);// csd寄存器中存儲了sd card的一些信息。// host發送CMD9命令,要求card回去其CSD寄存器(card specific data)的值// 此時card扔處于stand-by statemmc_decode_cid(card);}/** 選中sdcard,切換到transfer state模式 **/if (!mmc_host_is_spi(host)) {err = mmc_select_card(card);// 后續的初始化操作需要在transfer state下進行,所以需要發送CMD7命令選中對應的card,將card切換到transfer state}/** 獲取sd card的配置寄存器和狀態寄存器 **/ /** 讀取card 的switch狀態,也就是其支持的function **/err = mmc_sd_setup_card(host, card, oldcard != NULL);// host發送ACMD51命令,要求card回復其SCR寄存器(SD configuration register)的值// host發送ACMD13命令,要求card回復其SSR寄存器(SD status regiter)的值// host發送CMD6命令來讀取card switch status。// 通過card switch status可以得到card支持的總線速度模式以及驅動強度類型。/** 切換總線寬度,包括card和host的設置 **/ /** 選擇合適的總線速度模式、驅動強度、以及限流并進行設置,包括card和host的設置 **/ /** 執行tuning操作 **//* Initialization sequence for UHS-I cards */if (rocr & SD_ROCR_S18A) {err = mmc_sd_init_uhs_card(card); // 后續說明/* Card is an ultra-high-speed card */mmc_card_set_uhs(card);} else { // 對于非uhs card來說,直接嘗試切換到HS模式// 對于非uhs card,不需要切換其信號電壓,因為其一直工作在3.3V// 也不需要切換其信號驅動類型、執行tuning操作等等err = mmc_sd_switch_hs(card); // 發送CMD6命令嘗試將card的總線速度模式切換到HS模式if (err > 0)mmc_sd_go_highspeed(card); // 如果切換成功,將host的總線速度模式也切換到HS模式else if (err)goto free_card;mmc_set_clock(host, mmc_sd_get_max_clock(card)); // 設置時鐘為相應總線速度模式下支持的最大頻率if ((host->caps & MMC_CAP_4_BIT_DATA) &&(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); // 如果需要切換到4bit總線寬度模式,發送ACMD11通知card準備切換到4bit模式mmc_set_bus_width(host, MMC_BUS_WIDTH_4);// 設置host自身的總線寬度模式}}return 0; }

4、mmc_sd_get_cid

在上面mmc_sd_init_card中被調用。從idle state到identification state的一個過程。
* 在mmc_sd_get_cid中的重要工作如下
- 重新復位,完成card的內部初始化
- 設置信號電壓,包括card和host的設置
- 獲取card的CID值

  • 代碼如下:
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) {int err;u32 max_current;int retries = 10;try_again: /** 重新復位,完成card的內部初始化 **/mmc_go_idle(host); // host發送CMD0命令對card進行復位err = mmc_send_if_cond(host, ocr); // host發送CMD8命令,告訴card,host可以支持SD2.0。card收到CMD8命令之后會使能自己符合SD2.0的一些新功能// 同時獲取card的ocr值if (!err)ocr |= SD_OCR_CCS; // 當前代碼是支持SDHC和SDXC的處理的,所以這里設置ocr中的HCS位if (retries && mmc_host_uhs(host))ocr |= SD_OCR_S18R; // 如果host支持UHS模式,那么自然就支持1.8的信號電壓的輸出了err = mmc_send_app_op_cond(host, ocr, rocr);// host根據host是否支持SDHC來設置ocr的HCS、是否支持1.8V來設置ocr的S18R,將設置好的ocr作為ACMD41的參數,發送給card。// 當ACMD41處理完成值,card就進入到了ready state了。/** 設置信號電壓,包括card和host的設置 **/if (!mmc_host_is_spi(host) && rocr &&((*rocr & 0x41000000) == 0x41000000)) {err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);// 調用mmc_set_signal_voltage切換信號電壓到1.8V// 會先發送CMD11來通知card準備切換到信號電壓為1.8V的模式下// 然后調用host->ops->start_signal_voltage_switch來切換host輸出的信號電壓if (err == -EAGAIN) {// host讀取ACMD41的busy位來判斷card的內部初始化是否完成,如果沒有完成繼續發送ACMD41retries--;goto try_again;} else if (err) {retries = 0;goto try_again;}}/** 獲取card的CID值 **/if (mmc_host_is_spi(host))err = mmc_send_cid(host, cid);elseerr = mmc_all_send_cid(host, cid);// host發送CMD2命令,要求card回復其CID寄存器的值。// 一旦card返回response之后,進入identification state。return err; }

5、mmc_sd_init_uhs_card

在上面mmc_sd_init_card中被調用。用來初始化uhs card的總線工作模式。

  • 主要工作如下:

    • 切換總線寬度,包括card和host的設置
    • 選擇合適的總線速度模式、驅動強度、以及限流并進行設置,包括card和host的設置
    • 執行tuning操作
  • 代碼如下:

static int mmc_sd_init_uhs_card(struct mmc_card *card) {int err;u8 *status;status = kmalloc(64, GFP_KERNEL); /** 切換總線寬度,包括card和host的設置 **/// uhs都是工作在4bit的總線位寬的模式下,因此,在設置uhs的總線速度模式之前,必須先切換到4bit總線寬度模式if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);// 發送ACMD11,告訴card準備切換的4bit總線寬度模式if (err)goto out;mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);// 切換host的總線寬度為4bit模式}/** 選擇合適的總線速度模式、驅動強度、以及限流并進行設置,包括card和host的設置 **/sd_update_bus_speed_mode(card);// 根據card和host都支持的總線速度模式,選擇一個最佳的總線速度模式/* Set the driver strength for the card */err = sd_select_driver_type(card, status);// 根據要選擇的總線速度模式,切換驅動信號強度// 發送CMD6,告訴card準備切換驅動信號強度,命令格式如下:// mmc_sd_switch(card, 1, 2, drive_strength, status),屬于group2// 然后就是設置host的驅動信號強度// mmc_set_driver_type(card->host, drive_strength);/* Set current limit for the card */err = sd_set_current_limit(card, status);// 根據要選擇的總線速度模式,切換限流值// 發送CMD6,告訴card準備切換限流值,命令格式如下:// mmc_sd_switch(card, 1, 3, current_limit, status),屬于group3/* Set bus speed mode of the card */err = sd_set_bus_speed_mode(card, status);// 這里進行總線速度模式的切換,先查詢host關于該總線速度模式對應的時序模式// card——》總線速度模式,card->sd_bus_speed = host——》時序,host->ios.timing,二者是對應的// 發送CMD6,告訴card準備切換總線速度模式,命令格式如下:// mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status),屬于group0// 然后就是設置host的時序模式以及時鐘// mmc_set_timing(card->host, timing);// mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);/** 執行tuning操作 **//* SPI mode doesn't define CMD19 */if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {mmc_host_clk_hold(card->host);err = card->host->ops->execute_tuning(card->host, MMC_SEND_TUNING_BLOCK);// 對于UHS-I的card來說,如果處于uhs的速度模式,host需要發送CMD19執行tuning操作以獲取一個最佳的采樣點。mmc_host_clk_release(card->host);} out:kfree(status);return err; }

以上總線設置部分的詳細內容建議參考《[sd card] SD card初始化時的總線設置》

總結

以上是生活随笔為你收集整理的[sd card] sd card初始化流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。