[SDIO] SD card 初始化及常用命令解析(附波形,uboot代碼)

目錄

初始化

1.cmd 0

2.cmd8

3.cmd55

4.acmd41

5.cmd2

6.cmd3

7.cmd9

8.cmd13

9.cmd7

10.ACMD51

11.CMD6

12.CMD16

13.CMD17

14.CMD18

15.CMD12

tuning

CMD19

DW_SDHCI的tuning流程


初始化

1.cmd 0

 

       /* Reset the Card */

       err = mmc_go_idle(mmc);

static int mmc_go_idle(struct mmc *mmc)

{

       struct mmc_cmd cmd;

       int err;

 

       usleep(1000);

       cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;

       cmd.cmdarg = 0;

       cmd.resp_type = MMC_RSP_NONE;

 

       err = mmc_send_cmd(mmc, &cmd, NULL);

       if (err)

              return err;

 

       usleep(2000);

       return 0;

}

 

 

2.cmd8

R7:

       /* Test for SD version 2 */

       err = mmc_send_if_cond(mmc);

static int mmc_send_if_cond(struct mmc *mmc)

{

       struct mmc_cmd cmd;

       int err;

 

 

       cmd.cmdidx = SD_CMD_SEND_IF_COND;

       /* We set the bit if the host supports voltages between 2.7 and 3.6 V */

       cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;

       cmd.resp_type = MMC_RSP_R7;

 

       err = mmc_send_cmd(mmc, &cmd, NULL);

 

       if (err)

              return err;

 

       if ((cmd.response[0] & 0xff) != 0xaa)

       {

              debug("UNUSABLE_ERR mmc_send_if_cond\n");

              return UNUSABLE_ERR;

       }

       else

              mmc->version = SD_VERSION_2;

      

       return 0;

}

 

3.cmd55

 

ACMD:SD card application-specific commands.

在發所有的ACMD之前,需要先發APP_CMD(CMD55)通知SD卡下一個指令爲ACMD。SD卡應答R1,然後才能發送ACMD。

              cmd.cmdidx = MMC_CMD_APP_CMD;

              cmd.resp_type = MMC_RSP_R1;

              cmd.cmdarg = 0;

 

              err = mmc_send_cmd(mmc, &cmd, NULL);

4.acmd41

 

卡片的初始化將在主機發送ACMD41命令後開始,主機每間隔1就發送一次 ACMD41 命令,直到初始化完成(OCR 寄存器的 bit31 置位

 

 

bit 31)指示卡片的上電操作是否完成

bit 30)指示卡片的容量狀態(0代表SDSC1代表SDHC或者SDXC

 

上圖OCR bit 31)爲0,即爲卡busy

 

上圖OCR bit 31)爲1,即爲卡初始化完成

 

static int sd_send_op_cond(struct mmc *mmc) //send acmd41-- get ocr data

{

       int timeout = 1000;

       int err;

       struct mmc_cmd cmd;

 

       while (1)

       {

              cmd.cmdidx = MMC_CMD_APP_CMD;

              cmd.resp_type = MMC_RSP_R1;

              cmd.cmdarg = 0;

 

              err = mmc_send_cmd(mmc, &cmd, NULL);

 

              if (err)

                     return err;

 

              cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;

              cmd.resp_type = MMC_RSP_R3;

 

              /*

               * Most cards do not answer if some reserved bits

               * in the ocr are set. However, Some controller

               * can set bit 7 (reserved for low voltages), but

               * how to manage low voltages SD card is not yet

               * specified.

               */

              cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :

                     (mmc->voltages & 0xff8000);

 

              if (mmc->version == SD_VERSION_2)

                     cmd.cmdarg |= OCR_HCS;

 

              err = mmc_send_cmd(mmc, &cmd, NULL);

 

              if (err)

                     return err;

 

              if (cmd.response[0] & OCR_BUSY)//等待OCR[31]1後跳出循環,完成初始化。

                     break;

 

              if (timeout-- <= 0)

                     return -EOPNOTSUPP;

 

              usleep(1000);

       }

 

5.cmd2

CMD2,驗證SD卡是否接入,獲取(CID)

 

       /* Put the Card in Identify Mode */

       cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :

              MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */

       cmd.resp_type = MMC_RSP_R2;

       cmd.cmdarg = 0;

 

       err = mmc_send_cmd(mmc, &cmd, NULL);

 

       if (err)

              return err;

       memcpy((void*)mmc->cid, (void*)cmd.response, 16);

 

6.cmd3

 

讀取卡相對地址RCA, 當卡收到RCA(CMD3)後,卡就會進入數據傳輸模式。

 

       /*

        * For MMC cards, set the Relative Address.

        * For SD cards, get the Relatvie Address.

        * This also puts the cards into Standby State

        */

       if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */

              cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;

              cmd.cmdarg = mmc->rca << 16;

              cmd.resp_type = MMC_RSP_R6;

 

              err = mmc_send_cmd(mmc, &cmd, NULL);

              if (err)

                     return err;

 

              if (IS_SD(mmc))

                     mmc->rca = (cmd.response[0] >> 16) & 0xffff;

       }

 

7.cmd9

 

CMD9,讀取CSD寄存器獲取卡的相關信息

RCA是之前CMD3讀取到的卡RCA

PS:R2回覆CMD9時爲CSD,回覆CMD2時爲CID

CSD(具體信息)寄存器也是 128 bits,提供了訪問卡片內容的一些信息如:傳輸速率、數據格式、錯誤類型、最大是數據訪問時間、DSR 寄存器是否啓用的。其中 bit[126:127] 記錄了 CSD 的版本號,CSD version 1.0 爲標準容量卡所用,CSD version 2.0 爲大容量或超大容量卡所用

---------------------

8.cmd13

讀取卡狀態

RCA是之前CMD3讀取到的卡RCA

 

 

 

 

 

9.cmd7

發送CMD7+RCA選中卡片, 發送CMD7+0不選中卡片,RCA是之前CMD3讀取到的卡RCA

       /* Select the card, and put it into Transfer Mode */

       if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */

       cmd.cmdidx = MMC_CMD_SELECT_CARD;

       cmd.resp_type = MMC_RSP_R1;

       cmd.cmdarg = mmc->rca << 16;

              err = mmc_send_cmd(mmc, &cmd, NULL);

       if (err)

          return err;

       }

 

10.ACMD51

發送CMD55+ACMD51讀取SCR寄存器,SD卡可以通過該值獲得位寬,如果是MMC卡則需要使用主線測試來確定卡的位寬。

PS:slave回覆ACMD51是R1+data。SCR 是放在data中的,一共8個字節。

 

 

         cmd.cmdidx = SD_CMD_APP_SEND_SCR;//51

         cmd.resp_type = MMC_RSP_R1;

         cmd.cmdarg = 0;

 

         timeout = 3;

 

  retry_scr:

         data.dest = (char *)mmc->scr;

         data.blocksize = 8;

         data.blocks = 1;

         data.flags = MMC_DATA_READ;

 

       err = mmc_send_cmd(mmc, &cmd, &data);

 

         if (err) {

                if (timeout--)

                       goto retry_scr;

 

                return err;

         }

        

       mmc->scr[0] = __be32_to_cpu(mmc->scr[0]);

       mmc->scr[1] = __be32_to_cpu(mmc->scr[1]);

//     debug("scr_0=0x%x scr_1=0x%x\n",mmc->scr[0],mmc->scr[1]);

        switch ((mmc->scr[0] >> 24) & 0xf) {//SD_SPEC

               case 0:

                      mmc->version = SD_VERSION_1_0;

                      break;

               case 1:

                      mmc->version = SD_VERSION_1_10;

                      break;

               case 2:

                      mmc->version = SD_VERSION_2;

                      if ((mmc->scr[0] >> 15) & 0x1)

                            mmc->version = SD_VERSION_3;

                      break;

               default:

                      mmc->version = SD_VERSION_1_0;

                      break;

        }

 

 

         if (mmc->scr[0] & SD_DATA_4BIT)

              mmc->card_caps |= MMC_MODE_4BIT;

11.CMD6

CMD6是SD卡速度模式切換的一個重要命令,它定義了4種不同的功能組:

  1. 訪問模式:SD總線接口速度模式的選擇;
  2. 命令系統:通過一套莫共有的命令來擴展和控制特定的功能;
  3. 驅動強度:在UHS-I模式下等選擇合適的輸出驅動強度,和主機環境相關;
  4. 電流/功率限制:UHS-I卡在UHS-I模式選擇,和主機環境相關;

 

https://upload-images.jianshu.io/upload_images/726783-0f3f6c64bd8b7f0a.png?imageMogr2/auto-orient/

 

MODE0: 查詢模式,卡返回R1 + data[511:0]

data中存放了卡對每種功能的支持情況及當前選中的功能狀態,及忙狀態。

 

MODE1: 切換模式

每次發送切換隻能選中一個功能組進行切換,其他功能組全部爲1.

static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)

{

       struct mmc_cmd cmd;

       struct mmc_data data;

 

       /* Switch the frequency */

       cmd.cmdidx = SD_CMD_SWITCH_FUNC;

       cmd.resp_type = MMC_RSP_R1;

       cmd.cmdarg = (mode << 31) | 0xffffff;

       cmd.cmdarg &= ~(0xf << (group << 2));

       cmd.cmdarg |= value << (group << 2);

 

       data.dest = (char *)resp;

       data.blocksize = 64;

       data.blocks = 1;

       data.flags = MMC_DATA_READ;

 

       return mmc_send_cmd(mmc, &cmd, &data);

 

}


12.CMD16

設置塊大小

 

13.CMD17

讀單個塊參數爲block地址

卡回覆R1 +DATA

14.CMD18

讀多塊

 

15.CMD12

停止傳輸

 

tuning

CMD19

發送tuning block

host發送CMD19,卡回覆R1+data,tuning data 的數據長度及內容是固定的,host可以根據收到的數據調整採樣的timing。

 

DW_SDHCI的tuning流程

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