2017年11月16日 星期四

DIY - ESP8266:ESP-12F SD 記憶卡初始化(四十五)

DIY - ESP8266:ESP-12F SD 記憶卡初始化(四十五):

筆者在 2011年 DIY Microchip PIC18F4550 時,已經接觸到 SD 記憶卡,當時是初次使用,經驗和知識都缺乏,所以化了頗多時間來研究,但都是一知半解,最後結果還是可以讀寫 SD 記憶卡。其實 SD 記憶卡的初始化(Initialization)是很複雜,需要 11 步驟才可以啓動 SD 記憶卡,還要面對不同的 SD 版本。這次是使用了 ESP8266 的 SOC 處理器,雖然初始化步驟是一樣,但是也要從新寫過初始化程式,對筆者來說是一個溫故知新的機會。

ESP-12F SD 記憶卡初始化
SD 記憶卡初始化步驟: 
1. 電源啓動後要延時足夠長的時間給 SD 卡作準備過程,SD 卡處於此模式下的 Idle 狀態

2. 初始化設置 SPI CLK 到低速模式 400kHz
spi_clock(1, 8, 25); // 400kHz

3. CS 設為高電平(CS=1 / Disable CS)
SDCARD_CS_1;

4. 在片選有效的情況下首先要發送 >74 個時鐘
for(count=0; count<10;count++) spi_send(1,0xFF);

因為電源啓動後,電壓的上升過程據 SD 卡組織的計算約合 64 個 CLK 週期才能到達 SD 卡的正常工作電壓(Supply ramp up time),其後的 10 個 CLK 是為了與 SD 卡同步,之後開始 CMD0 的操作。

5. 將CS設為低電平(CS=0 / Enable CS)
SDCARD_CS_0;

6. 發送復位命令 CMD0 (GO_IDLE_STATE),回覆(Response)0x01 表示接受,進入 Idle 狀態 CRC-7 ,(Cyclic Redundancy Check)7 bits Polynomial=x7+x3+1

CRC-7 (Cyclic Redundancy Check):
char calc_CRC7(char *data, int len) { 
int i, j; 
char crc, dt; 
crc = 0; 

for (i = 0; i < len; i++) { 
     dt = *data++; 

     for (j = 0; j < 8; j++) { 
          crc <<=1; 

          if ((crc & 0x80) ^ (dt & 0x80)) 
             crc ^= 0x09; 
             dt <<= 1; 
      } 

return (crc & 0x7f);
}

7. 發送命令 CMD8 (SEND_IF_COND),判斷 SD 卡符合哪個標準  v1.0 v2.0 如果 SD 卡不能識別並返回錯誤碼 0x05 / 0xFF,說明此卡非 2.0 卡。 如果指令能被識別,則 SD 卡將返回 R1+32 位共 40 位數據,其中 R1 位 0x01 和 32 位數據為 0x000001AA。 此時可判斷卡為 2.0卡。
SendSdCardCommand(CMD08 | 0x40, 0x000001AA, 0x87, response, CMD08R);

R1 = SD 卡版本: 
SD V1.X(即SD標準卡)最大容量2GB 
R1=0x01 = 01AA SD V2.0 2.0 版本的標準卡,最多 2GB

8. 循環發送命令 CMD55 (APP_CMD)+ ACMD41(SEND_OP_COND),直到回覆(Response)0x00,SD2.0 卡初始化成功,進入 Ready 狀態

9. 發送 CMD58(READ_OCR)命令來判斷是 SDHC(High Speed Card)/ SDSC(Standard Card),到此 SD2.0 卡初始化成功(可以不用)

CCS=0=SD=Byte Addressing
CCS=1=SDHC=Block Addressing 

SD卡版本: SD V1.X(即SD標準卡)最大容量 2GB 
SD V2.0 2.0 版本的標準卡,最多 2GB SD V2.0HC 2.0 高容量卡,最多 32GB 2GB 以內的 SD 卡(標準卡)和 2GB 以上的 SD 卡(大容量卡)在地址訪問形式上不同,這一點尤其要注意,否則將會出現無法讀寫數據的問題。 如標準卡在讀寫操作時,對讀或寫命令令牌當中的地址域符初值 0x10,表示對第 16 個字節以後的地址單元進行操作(前提是此 SD 卡支持偏移讀寫操作),而對大容量卡讀或寫命令令牌當中的地址域符初值 0x10 時,則表示對第 16 塊進行讀寫操作,而且大容量卡只支持塊讀寫操作,塊大小固定為 512 字節,對其進行字節操作將會出錯。

10. 設定 Block 長度為 512 字節(512 Byte) 
CMD 16: SET_BLOCKLEN 
對於 SDHC,BLOCK LENGTH 始終固定為 512 字節,但對於其他類型(MMC,SD v1 和SD  v2 標準容量),需要告訴 SD 卡片要使用的塊長度。BLOCK LENGTH 設置為 512 字節,以允許軟件與所有類型的 SD 一起使用。
SendSdCardCommand(CMD16 | 0x40, 512, 0xff, response, CMD16R);

11. 初始化成功後,將 SPI  切換為高速模式。
spi_clock(1, SPI_CLK_PREDIV_HIGH, SPI_CLK_CNTDIV_HIGH);
spi_clock(1, 2, 5); // 10MHz

SD 記憶卡初始化步驟圖
2017年 11月 16日 天氣報告
氣溫:24.1@ 20:20
相對濕度:百分之 85%
天氣:大致多雲

沒有留言:

張貼留言