讀取SD CARD遭遇到奇怪現象! |
答題得分者是:bernie_w39
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
大家好, 這個問題小弟困擾已久了.
小弟為了讀到啟動扇區的0xEB花了不少功夫, 卻始終失敗, 麻煩大家看看. 1. 讀取sector 0: 如果第一個byte是0, 則判斷第0x1be的byte是否為0x80或0x00. (此時[0x1be]為0x00) 2. 如果[0x1be]是0x80或0x00, 則讀取[0x1be]之後的第8, 9, 10, 11個byte並將其串起來(此時第8個byte為0x61, 第9個byte~第11個byte皆為0) 3. 讀取sector 0x61的內容. 於是接下來讀到的內容如下: 00000000h: B6 D1 80 E2 3F F7 E2 86 CD C0 ED 06 41 66 0F B7 00000010h: 02 00 00 00 00 F8 00 00 3F 00 FF 00 61 00 00 00 00000020h: 9F D3 03 00 CC 03 00 00 00 00 00 00 02 00 00 00 00000030h: 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040h: 00 00 29 90 AC 61 9C 4E 4F 20 4E 41 4D 45 20 20 00000050h: 20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4 00000060h: 7B 8E C1 8E D9 BD 00 7C 88 4E 02 8A 56 40 B4 08 00000070h: CD 13 73 05 B9 FF FF 8A F1 66 0F B6 C6 40 66 0F 00000080h: B6 D1 80 E2 3F F7 E2 86 CD C0 ED 06 41 66 0F B7 而我用WINHEX印出來的資料確是: 00000000h: EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 02 20 00 00000010h: 02 00 00 00 00 F8 00 00 3F 00 FF 00 61 00 00 00 00000020h: 9F D3 03 00 CC 03 00 00 00 00 00 00 02 00 00 00 00000030h: 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040h: 00 00 29 90 AC 61 9C 4E 4F 20 4E 41 4D 45 20 20 00000050h: 20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4 00000060h: 7B 8E C1 8E D9 BD 00 7C 88 4E 02 8A 56 40 B4 08 00000070h: CD 13 73 05 B9 FF FF 8A F1 66 0F B6 C6 40 66 0F 00000080h: B6 D1 80 E2 3F F7 E2 86 CD C0 ED 06 41 66 0F B7 除了前面16個byte不同之外, 其他都一樣! 更奇怪的是, 第1到第16個byte和第128到第144個byte是一模一樣的! 於是小弟試著去讀別的sector, 發現所有sector的狀況都和這個sector一樣! 第1到第16個byte消失了! 請問有大大有遭遇過一樣的問題嗎? 小弟先謝謝了~ |
㊣
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:261 回覆:2302 積分:1667 註冊:2005-01-04 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
感謝回覆, 小弟的處理器是Freescale的IMX31, 有專用的SD介面.
小弟發現不管去讀哪一個block, 都是會直接讀到第128個byte, 開頭的那16個byte怎樣就是讀不出來. int ReadOneSecFromCard(U32 AddrOnCard, P_U32 DestAddr) { U32 mmc_nob = 1; //U32是指unsign DWORD int rc = 0; U32 *pt_des = DestAddr; U32 SrcAddrOnCard = AddrOnCard; rc = sdhc_Set_BLock_Length(mmc_blk_len); //mmc_blk_len固定給512 if(rc) return rc; //Data to transfer = NOB*BLK_LEN reg32_write(&v_pSDHCRegs->NOB, 1); //對暫存器寫入1個block的命令 reg32_write(&v_pSDHCRegs->BLK_LEN, mmc_blk_len); // 對暫存器寫入512 rc = sdhc_send_read_command(SrcAddrOnCard, mmc_blk_len, 1); if(rc) return rc; sdhc_read_fifo_polling2(SD4_bit, mmc_blk_len, 1, (U32 *)(pt_des)); //這個指令會將SD CARD的block 中的值一個一個讀出來, 一次讀4個byte rc = sdhc_stop_read_operation(mmc_rca, 1); if(rc) return rc; rc = mmc_blk_len*mmc_nob; return rc; } 請各位大大幫忙查看這樣的步驟有沒有錯誤, 如需細節小弟隨時再整理出來. 謝謝!
編輯記錄
mmppeegg 重新編輯於 2008-11-03 13:49:08, 註解 無‧
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
感謝回覆, 小弟這就把這個function整理出來:
static int sdhc_read_fifo_polling2(U32 BusWidth4, U32 blk_len, U32 nob, U32 *dest_addr) { U32 buffer_size; U32 i; // how many buffers for each blk_len U32 j; // nob U32 k; // buffer size U32 m = 0; // source address pointer U32 buffer_count; U32 buffer_access_times; U32 sta; buffer_size = (BusWidth4 == 0x1)?64:16; //64 buffer_count = blk_len/buffer_size; // buffer count of each block, 8 buffer_access_times = buffer_size/4; //16 for (j = 0; j < nob; j ) { for(i = 0; i < buffer_count; i ) { sta = reg32_read(&v_pSDHCRegs->STATUS); while ( (sta & 0x80) != 0x80 ) { sta = reg32_read(&v_pSDHCRegs->STATUS); EdbgOutputDebugString("staloop : %Xh\n",sta); // wait until buffer ready for data } for (k = 0; k < buffer_access_times; k ) { dest_addr[m ]=reg32_read(&v_pSDHCRegs->BUFFER_ACCESS); EdbgOutputDebugString("dest_addr[%d] : %Xh\n",m-1, dest_addr[m-1]); //這行是小弟特地print出來的結果, 錯誤的值也是從這得到的 } } } return 0; } |
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
感謝回應, reg32_read是一個macro, 定義如下:
#define reg32_read(addr) (*(volatile unsigned long * const)(addr)) 我的debug訊息是這樣的: dest_addr[0] : E280D1B6h dest_addr[1] : 86E2F73Fh dest_addr[2] : 06EDC0CDh dest_addr[3] : B70F6641h dest_addr[4] : 00000002h dest_addr[5] : 0000F800h dest_addr[6] : 00FF003Fh dest_addr[7] : 00000061h dest_addr[8] : 0003D39Fh dest_addr[9] : 000003CCh dest_addr[10] : 00000000h dest_addr[11] : 00000002h dest_addr[12] : 00060001h dest_addr[13] : 00000000h dest_addr[14] : 00000000h dest_addr[15] : 00000000h dest_addr[16] : BA290000h dest_addr[17] : 4E04ACFFh dest_addr[18] : 414E204Fh dest_addr[19] : 2020454Dh dest_addr[20] : 41462020h dest_addr[21] : 20323354h dest_addr[22] : C9332020h dest_addr[23] : F4BCD18Eh dest_addr[24] : 8EC18E7Bh dest_addr[25] : 7C00BDD9h dest_addr[26] : 8A024E88h dest_addr[27] : 08B44056h dest_addr[28] : 057313CDh dest_addr[29] : 8AFFFFB9h dest_addr[30] : B60F66F1h dest_addr[31] : 0F6640C6h dest_addr[32] : E280D1B6h dest_addr[33] : 86E2F73Fh dest_addr[34] : 06EDC0CDh dest_addr[35] : B70F6641h dest_addr[36] : E1F766C9h 這些訊息是我將register的第一手資料拿出來, 後來當然是把它分解成unsigned char再做分析了. 很明顯的dest_addr[0]到dest_addr[3]和dest_addr[32] 到dest_addr[35] 是相同的. 如果我的演算法沒錯, 難道錯的是晶片嗎...真不敢相信...
編輯記錄
mmppeegg 重新編輯於 2008-11-05 15:17:34, 註解 無‧
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
先說聲抱歉, 這麼晚才回覆.
感謝大大不辭辛勞! 這iMX31並不是單晶片, 而是ARM11的CPU, 所以有對應的REGISTER可以去做讀取的動作. 所以對REGISTER的 寫入與存取方式也有特別的用法. 小弟這就把程式整理上來: static int sdhc_send_read_command(U32 Start_addr, U32 blk_len, U32 nob){ int err; U32 DatCon; U32 startaddr = Start_addr* blk_len; U32 arg_rca = 0x1 <<16; DatCon = 0x209;//0x9|(0x10<<8); //4bit, read, with data, R1 if (nob == 0x1) { err = sdhc_issue_cmd_wait_resp(CMD_READ_SINGLE_BLOCK, startaddr, DatCon, CHECK_TIMEOUT); if (err) DBGprint("single read error\n"); } else { err = sdhc_issue_cmd_wait_resp(CMD_READ_MULTIPLE_BLOCK, startaddr, DatCon, CHECK_TIMEOUT); if (err) DBGprint("multiple read error\n"); } return err; } 所以SrcAddrOnCard傳入之後, IMX31會將要讀取的地址寫入到register中, 而v_pSDHCRegs->BUFFER_ACCESS就是另一個register 所得到的card的回傳data. 如果在深入下去的話就得看spec了(如果大大願意的話), 耽誤到大大的時間與精神實在萬分抱歉. |
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
其實我不太能理能您說的 "iMX31並不是單晶片, 而是ARM11的CPU, 所以有對應的REGISTER可以去做讀取的動作.
所以對REGISTER的寫入與存取方式也有特別的用法." 這句話是什麼意思. 我自己沒有用過 ARM 系列的控制器, 所以無從猜起. 不管怎樣, SD 卡的運作是固定的, 指定位置與大小後, 就可以從卡上讀出 data. 如果這部份是系統包裝好的, 照說會出問題的機會不大. 有可能的幾個原因: 1. debug 訊息程式出錯, 明明是正確的資料, 但是 deubg 取自錯誤的位置, 印出錯誤的結果. 2. 資料讀取後, 在 debug 訊息出來之前, 有程式破壞了這一段資料. 3. 資料讀取時, 指定的 記憶體位置不對, 造成本身的覆蓋. 目前只有 1 的程式有看到, 看起來像是對的. 要排除 2, 最好是在讀入資料後, 就直接印出, 不要經過太多呼叫. 3 的話, 要仔細看系統的 library 包裝到什麼程度, 有沒有機會深入去追. 像是 v_pSDHCRegs 裏面的結構, 到底 是如何定義.... 諸如此類的問題. 附上一段我之前用 atmega128 寫的 sd card 讀寫程式, 它以 512 bytes 為單位, 一次讀一個 sector 出來, 用的是 SD card SPI 界面, 你可以注意它在送出了 read single block 指令之後, 要等候 SD card ready, 然後 再把資料一個一個 byte 出來, 最後是省略了 CRC 的檢查. 您不妨找找看, 在系統 library 中, 是否有類似的 動作, 亦或是這部份程式根本就是您自己寫的? 那應該不難找到問題所在. [code cpp] u_char sdCardReadBlock(u_char *buf, u_long addr) // read a single data block from SD card { u_char rc = 1, try, rsp; u_short i; for (try = 0; try < 16 && rc; try ) { sdCardSel(1); sdCardSendCmd(SD_CMD_READ_SINGLE_BLOCK, addr); if ((rsp = sdCardRecvR1()) == SD_RSPR1_IDLE_STATE) { if ((rsp = sdCardRecvR1 ()) == 0xfe) { for (i = 0; i < SD_BLOCK_LEN; i ) buf[i] = sdCardIo(0xff); // ignore CRC sdCardIo(0xff); sdCardIo(0xff); rc = 0; } else printf("SD card command 'READ_SINGLE_BLOCK' doesn't get data leading: result = x\n", rsp); } else printf("SD card command 'READ_SINGLE_BLOCK' fail: result = x\n", rsp); sdCardSel(0); } return rc; } [/code] |
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
感謝大大, 並為這麼晚回覆說聲抱歉. 大大所提供的程序小弟會仔細check, 並把實驗結果發表上來. 大大所說的第一點和第二點, 小弟已初步排除, 因為的確是讀到的第一手資料. 整個對SD的控制都是小弟自己寫的, 在這邊把發送command的程式附上, 程序應和大大所說的差不多: [code cpp]
static int sdhc_issue_cmd_wait_resp(U32 cmd_no, U32 cmd_arg, U32 cmd_dat_cont, U32 chk_res_to ) { int err; U32 resp_type; //U32 status; //status = reg32_read(&v_pSDHCRegs->STATUS); //msStall(2); reg32_write(&v_pSDHCRegs->CMD,cmd_no); msStall(2); reg32_write(&v_pSDHCRegs->ARG,cmd_arg); msStall(2); reg32_write(&v_pSDHCRegs->CMD_DAT_CONT,cmd_dat_cont); msStall(2); //if(cmd_no == 0x0010) // dbgBreakPt(); //if(cmd_no != 0x0010) sdhc_enable_clk(); //vannes: ok! switch(cmd_dat_cont & 0x07) // set FORMAT_OF_RESPONSE { case 0: resp_type = 0; // No response for current command break; case 1: resp_type = 1; // 48-bit response with CRC7 check. Format R1/R1b/R5/R6 break; case 2: resp_type = 2; //136-bit, CSD/CID read response. Format R2. break; case 3: resp_type = 3; //48-bit response without CRC check. Format R3/R4 break; } #if 1 err = sdhc_wait_end_cmd_resp(chk_res_to, resp_type); #else while(err = sdhc_wait_end_cmd_resp(chk_res_to, resp_type)); #endif return err; } static int sdhc_wait_end_cmd_resp (U32 chk_res_to, U32 resp_type) { U32 status; U32 a, b, c; a = 0; b = 0; c = 0; status = reg32_read(&v_pSDHCRegs->STATUS); //EdbgOutputDebugString("SD_DL - sdhc_wait_end_cmd_resp: cmd Status: %x\r\n", status); while((status & 0x2000) == 0x0) { //EdbgOutputDebugString("cmd Status: %x\r\n", status); status = reg32_read(&v_pSDHCRegs->STATUS); } // wait end_cmd_resp if (chk_res_to == 0x1) { if((status & 0x20)!= 0) { // check timeout and crc error status DBGprint("Error: RESPONSE CRC error\n"); reg32_write(&v_pSDHCRegs->STATUS,0x2020); // clear end_cmd_resp status bit return MMC_ERR_RESPONSE_CRC; } if((status & 0x02)!= 0) { DBGprint("Error: RESPONSE TIMEOUT error\n"); reg32_write(&v_pSDHCRegs->STATUS,0x2002); // clear end_cmd_resp status bit return MMC_ERR_RESPONSE_TIMEOUT; } } else { if((status & 0x20)!= 0) { // only check crc error status DBGprint("Error: CRC error\n"); reg32_write(&v_pSDHCRegs->STATUS,0x2020); // clear end_cmd_resp status bit return MMC_ERR_RESPONSE_CRC; } } reg32_write(&v_pSDHCRegs->STATUS,0x2000); // vannes: why? // clear end_cmd_resp status bit msStall(8); switch(resp_type) { //U8 cnt; case 1: //48-bits RES. But we only want 32 bits? a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); c = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[0] = ((a&0xff)<<24) | ((b& 0xffff)<<8) | ((c&0xff00)>>8); //EdbgOutputDebugString("CRC7 check RES!! gResp[0]: %Xh\n",gResp[0]); break; case 2: // vannes: Four 32-bit information. So total 4*32 = 128 bit? Why not 136-bit? // Bcz the first byte is not stored in FIFO!!! a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[0] = ((a<<16) | (b& 0xffff)); a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[1] = ((a<<16) | (b& 0xffff)); a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[2] = ((a<<16) | (b& 0xffff)); a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[3] = ((a<<16) | (b& 0xffff)); break; case 3: //Stall(10); a = reg32_read(&v_pSDHCRegs->RES_FIFO); b = reg32_read(&v_pSDHCRegs->RES_FIFO); c = reg32_read(&v_pSDHCRegs->RES_FIFO); gResp[0] = ((a&0xff)<<24) | ((b& 0xffff)<<8) | ((c&0xff00)>>8); break; default: memset((void *)&gResp[0], 0, sizeof(U32)*4); break; } return MMC_ERR_NONE; } [/code] 程式碼繁雜, 請大大勿怪. 所有的register都是32bit. msStall是delay函式. |
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
是的, 都是讀一樣的位置. STATUS是一個暫存器. 至於BUFFER_ACCESS則是一個CPU中的FIFO, 將DATA存進一個固定的register, 每讀取完之後就會換下一筆資料.
您提到說可能是程式的錯誤, 小弟卻是怕CPU本身的問題, 像這個FIFO到底初始化對不對, 真的不敢確定. 請看這個圖: www.wretch.cc/album/show.php |
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
1 個 FIFO 16 bytes, 這樣就有一點 make senses 了. 也許真的該去找找,
那個 FIFO 的控制方法. 有可能在發送指令之前或之後, 要對 FIFO 下一些 initial, flush 之類的動作. 不過 FIFO 有 32 組, 你的讀取是差了 8 組, 這之間應該還是有一些深奧之處. 但是, 這些問題都超出了我的經驗範圍, 我當初只是用 SPI 界面而己. 你這個 是標準 (高速) 的 SDIO 界面, 應該會快很多. 加油了. 再八卦一下, 在發送完指令之後, 收到 response 後, 試著 delay 一下子, 看看結果有沒有不同. 我的猜測 (完全胡思亂想, 沒有根據的), 那個 FIFO 結構 不是雙向的, 因為你下完指令後, 它就開始用力的去讀 block, 當你的程式去 讀 FIFO 時, 它剛好讀到第 8 組, 為了應付你的讀取動作, 它就把目前正在 工作中的 FIFO page, 直接餵給你. 因為程式邏輯一致, 秒差一致, 所以 總是在第 8 組. 看看小小的 delay 後, 會不會跳去第 18 組, 就可以知道了. |
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
|
mmppeegg
一般會員 ![]() ![]() 發表:1 回覆:11 積分:2 註冊:2008-10-22 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |