2011年3月23日 星期三

SD Card Driver Design (init.)

二話不說
先來張圖吧...

上圖就是完整的SD Card初始化流程
在這裡有幾個地方需要注意
首先是Power sequence
這個部分是SPI的相關設定
而SPI的詳細介紹
請參考wiki
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

在本文中
本人只探討如何設定以符合SD Card初始化的要求
因為SD卡是跑SPI控制的流程
而在初始化的過程中
SPI的CLK不能超過400KHz
所以要先將SPI的設定低於400KHz
接下來要產生"大於"74個SPICLK, 以穩定電壓

// Generate 80 SPI clock cycles, and CS and SDI must be HIGH
    SD_CS_DEASSERT;        // CS high
    for(i = 0; i < 10; i++)
        SPISEND(0xFF);

通常在這裡會產生80個
因為SPI一次只會產生8個clock cycle
所以用for loop跑個十次
就符合power sequence的規格囉
再來就進入初始化流程的第一步啦

=================================================================

// Send CMD0 to Idel state
    do
    {
        r1 = SD_Send_Cmd(GO_IDLE_STATE, 0);
        SD_CS_DEASSERT;
        retry++;
    }while((r1 != 0x01) && (retry < MAX_TIMEOUT));

// Exit loop, and check initial success or fail
    if(retry == MAX_TIMEOUT)
        return 1;        // fail

// Once the command transmitt complete, send dummy delay
    SD_Dummy_Delay();

這段程式是執行CMD 0 (命名為GO_IDLE_STATE)
當指令送出去後, 回從R1暫存器反回一個值
來check我們所送去SD卡的指令是否正確
在此用do-while語來來實現
並確保在return回來的值正確後
才進行下一個指令

附帶一提
在每個指令執行完畢後
一定要丟8個SPICLK cycle
然後再執行下個指令
否則SD卡會無法判別指令喔

=================================================================

// Send CMD8 to check SD card version
    r1 = SD_Send_Cmd(SEND_IF_COND, 0x000001AA);
// If CMD8 response return 0x05: SD_V1/MMC
    if(r1 == 0x05)
    {
        SD_Dummy_Delay();
        SD_MMC_Check();
    }    

// If CMD8 response is 0x01: SDV2/SDHC else if(r1 == 0x01) { SDHC_V2_Check(); }

CMD 8 (SEND_IF_COND)可以用來做SD卡的型別判斷
辨別SD 1.x或SD 2.x
0x1AA在這裡的用途是判斷SD 2.x的最重要依據
如果R1返回的值是0x1
表示CMD 8的argument被接受
代表此卡片為SD 2.x的
但是不是SDHC呢
則要看CMD 58 (READ_OCR)的return決定

=================================================================

// Send initial command CMD55+ACMD41 repeatedly
    do
    {
        do
        {
            r1 = SD_Send_Cmd(APP_CMD, SD_CMD_SIZE);
            SD_Dummy_Delay();
        }while((r1 !=0x01) && (test < MAX_TIMEOUT));
        if(test == MAX_TIMEOUT)
            return r1;

// Note: SDV2/SDHC must set HCS = 1 in ACMD41 argument // indicate host support SDHC or SDXC r1 = SD_Send_Cmd(SD_SEND_OP_COND, 0x40000000); SD_Dummy_Delay(); if(retry > MAX_TIMEOUT) return r1; }while(r1 != 0x00);
// Using CMD58 return response with CCS bit in OCR register r1 = SD_Send_Cmd(READ_OCR, 0); SD_Dummy_Delay();

但這裡需要 特別的注意
ACMD這一類的指令是不能單獨存在的
一定要搭配CMD 55 (APP_CMD)
因此程式段才會使用兩個do-while去做判斷
而且在此ACMD 41所要輸入的參數為 0x40000000
才能進行SD 2.x與SDHC的判斷
判斷完之後
就是利用CMD 58來讀取SD卡內的OCR暫存器
在SDHC的卡中, 是以Block Address(區塊定址)
但在SDHC之前都是用Byte Address(位元組定址)
所以可以藉此區分SD 2.x與SDHC
至於SD 1.x跟MMC該怎麼辨別呢
敬待下回分解囉......

1 則留言:

GameHeven 提到...

你好,本公司也正用單晶片SPI控制SD Card。目前還沒成功。

下第一個CMD0,卡片就沒有回應了。示波器已經量訊號好幾天,每個步驟都檢查過了。就是找不出原因。記憶卡也換過三片,都是一樣情況。

我想跟你買一片板子,請你確定記憶卡可讀可寫。然後直接把板子寄給我。我直接量你板子的訊號。

本公司在新竹。請告訴我相關費用及付款方式,謝謝!