2011-04-18 120 views
2

當我從SPI總線上的PIC-18F4520向我的卡發出地址爲(0x00000000)的cmd17時,我從命令問題得到正確的返回R1令牌。然後,在幾次循環檢查之後,我從發出的SPI_Put_Char(0xFF)返回一個0xFE標記。數據應該開始,所以我讀取512個字節到我的IO_Buffer數組中。當我掃描返回時,我得到了很多0x00字節。奇怪的是,在扇區0的第448位左右,有些數據會出現 - 幾個字節在這裏和那裏 - 然後是最後的32個字節(我一次只能在LCD屏幕上查看32個字節)都是零,然後是零預期在引導扇區末尾的0x55AA標記。如何使用SPI模式從SD卡read_single_block(到目前爲止還有怪異的行爲)?

奇怪的是,使用磁盤調查器顯示SD卡有適當的扇區零信息 - MSDOS消息,EB跳轉代碼,各種東西。我的閱讀命令將所有的內容都歸零。我只是不知道發生了什麼。

其他信息:我用cmd0,cmd8,cmd58啓動並且OCR讀取正常。然後acmd41(循環cmd55,然後是APP_SEND_OP_COND)。所有人似乎都回應並給出預期的標記。最後,我甚至使用SEND_CID來獲取卡信息。返回MID = 3 OID = SD和版本SD017後跟其他信息 - 似乎都是正確的。

我已經嘗試添加上拉並從卡上拉下DOUT上的電阻,但不影響任何結果。

我非常渴望嘗試讓這張卡片正確讀取。我有(順便說一句)嘗試了另外兩張牌。他們給出了不同的具體結果,但在性質上是相同的 - 初始化,OCR和CID讀取都可以。讀取的數據大多爲零,然後是一些可重現但稀疏的字節,並帶有一個0xAA55標記!

我的SanDisk 1GB SD卡運行電壓爲3.296伏,在讀卡過程中看起來很穩定。

下面是一些代碼:提前

bit MMC_Command(unsigned char cmd, unsigned short AdrH, unsigned short AdrL, unsigned char *response) 
{ 
    unsigned char response_length; 
    unsigned char MMC_Counter_Byte = 255; 
    unsigned char current_response; 

    switch (cmd) 
    { 
     case MMC_SEND_IF_COND: 
     case MMC_READ_OCR: 
      response_length = 5; 
      break; 
     case MMC_SEND_STATUS: 
      response_length = 2; 
      break; 
     default: 
      response_length = 1; 
    }; 

    DEV_xSELECT = DEV_MMC; 

    SPI_Put_Char(cmd); 
    SPI_Put_Char(AdrH >> 8); 
    SPI_Put_Char(AdrH & 0x00FFU); 
    SPI_Put_Char(AdrL >> 8); 
    SPI_Put_Char(AdrL & 0x00FFU); 
    SPI_Put_Char(0x95U); //CRC = 0x95 to get to SPI, then value not important, so always use this for convenience 

    do 
    { 
     response[0] = SPI_Put_Char(0xFF); 
    } while ((response[0] & 0x80) && --MMC_Counter_Byte); 
    if (!MMC_Counter_Byte) 
    { 
     //SPI_Put_Char(0xFF); //some say is necessary 
     DEV_xSELECT = DEV_NONE; 
     return FALSE; 
    }; 

    for (current_response = 1; current_response < response_length; current_response++) 
    { 
     response[current_response] = SPI_Put_Char(0xFF); 
    }; 

    SPI_Put_Char(0xFF); //some say is necessary 
    DEV_xSELECT = DEV_NONE; 
    return TRUE; 
}; 

    unsigned char MMC_Init_SD(void) 
{ 
    unsigned long MMC_Counter_Word; 
    unsigned char response[5]; 

    DEV_xSELECT = DEV_MMC; 

    for (MMC_Counter_Word = 0; MMC_Counter_Word < 20; MMC_Counter_Word++) 
    { 
     SPI_Put_Char(0xFFU); 
    }; 

    DEV_xSELECT = DEV_NONE; 

    for (MMC_Counter_Word = 0; MMC_Counter_Word < 10; MMC_Counter_Word++) 
    { 
     SPI_Put_Char(0xFFU); 
    }; 

    MMC_Counter_Word = 255; 
    do 
    { 
     MMC_Command(MMC_GO_IDLE_STATE, 0x0000, 0x0000, response); //cmd0 
    } while (--MMC_Counter_Word && (response[0] != 0x01)); 
    if (!MMC_Counter_Word) //if counter timed out, error 
    { 
     return FALSE; 
    }; 

    MMC_Command(MMC_SEND_IF_COND, 0x0000, 0x01AA, response); //cmd8 
    if (response[0] != 0x05) 
    { 
     return FALSE; //other card type 
    }; 

    MMC_Command(MMC_READ_OCR, 0x0000, 0x0000, response); //cmd58 

    MMC_Counter_Word = 0xFFFFU; 
    do 
    { 
     if (MMC_Command(MMC_APP_CMD, 0x0000, 0x0000, response)) //cmd55 
     { 
      MMC_Command(MMC_APP_SEND_OP_COND, 0x4001, 0x0000, response); //acmd41 
      SPI_Put_Char(0xFF); 
     } 
     else 
     { 
      return FALSE; 
     }; 
    } while (--MMC_Counter_Word && ((response[0] & 1) == 1)); 
    if (!MMC_Counter_Word) 
    { 
     return FALSE; 
    }; 

    if (MMC_Command(MMC_SEND_CID, 0x0000, 0x0000, response)) //cmd10 
    { 
     DEV_xSELECT = DEV_MMC; 

     MMC_Counter_Word = 255; 
     while (--MMC_Counter_Word && (SPI_Put_Char(0xFF) != 0xFE)); 
     if (!MMC_Counter_Word) 
     { 
      DEV_xSELECT = DEV_NONE; 
      return FALSE; 
     }; 

       //code for reading 16 byte OCR goes here 

     SPI_Put_Char(0xFFU); 
     SPI_Put_Char(0xFFU); //cycle through 16-bit CRC 
     SPI_Put_Char(0xFFU); //1GB Sandisk SD seems to require another dummy 

     DEV_xSELECT = DEV_NONE; 
     Delay_Sec(2); 
     LCD_CLS(); 
    } 
    else 
    { 
     return FALSE; 
    }; 

    return TRUE; 
}; 

    bit MMC_Fill_IO_Buffer(unsigned long sector) 
{ 
    unsigned short MMC_Fill_Index_Byte; 
    unsigned char MMC_Counter_Byte = 255; 
    unsigned char response[1]; 

    if (MMC_Command(MMC_READ_SINGLE_BLOCK, 0x0000, 0x0000, response)) //cmd10 
    { 
     DEV_xSELECT = DEV_MMC; 

     MMC_Counter_Byte = 255; 
     while (--MMC_Counter_Byte && (SPI_Put_Char(0xFF) != 0xFE)); 
     if (!MMC_Counter_Byte) 
     { 
      DEV_xSELECT = DEV_NONE; 
      return FALSE; 
     }; 
    } 
    else 
    { 
     return FALSE; 
    }; 

    for (MMC_Fill_Index_Byte = 0; MMC_Fill_Index_Byte < 512 ; MMC_Fill_Index_Byte++) 
    { 
     IO_Buffer[MMC_Fill_Index_Byte] = SPI_Put_Char(0xFF); 
    }; 
    SPI_Put_Char(0xFFU); 
    SPI_Put_Char(0xFFU); //cycle through 16-bit CRC 
    SPI_Put_Char(0xFFU); //1GB Sandisk SD seems to require another dummy 
    DEV_xSELECT = DEV_NONE; 

    //following is IO_Buffer displaying code. 
    //LCD_CLS(); 
    //for (MMC_Counter_Byte = 0; MMC_Counter_Byte < 42; MMC_Counter_Byte++) 
    //{ 
    // LCD_Draw_Byte_Hex(IO_Buffer[MMC_Counter_Byte + 448]); 
    //}; 
    //while (1); 

    return TRUE; 
}; 

謝謝!

+0

我有完全相同的問題,如下所述:http://electronics.stackexchange.com/questions/23053/problems-reading-data-from-a-microsd-card無法想到任何可能的原因。 – Armandas 2011-12-01 14:37:48

回答

1

您的扇區0看起來像一個vaild分區表。如果您使用disk investigator從驅動器盤符中讀取,則可能最終讀取分區的扇區0,而不是讀取sd卡本身。此程序似乎無法從物理設備讀取,因此您無法使用它來讀取分區表。

1

終於找到了解決方案!

事實證明,您正在讀取位於SD卡地址0處的MBR。要找到引導扇區的位置,需要讀取MBR中的相應條目。條目從地址0x01be開始,每個16字節。條目中的興趣點位於偏移量0x08處,長度爲4個字節,稱爲LBA。 [Wikipedia]要獲得引導扇區位置的地址,可以將LBA乘以一個扇區的大小(512字節)。 [Microchip forum]

有關示例,請參見my other answer

+0

這或多或少是Turbo J說的(分區表部分)。 :)注意:你應該檢查的第一件事是你剛剛讀到的扇區最後有0x55,0xaa簽名。如果是這樣,那麼它就是分區表或引導扇區。現在你必須檢查所有可能的字段你可以爲理智的價值觀。請記住在同一個扇區中允許分區表和引導扇區(!) – 2014-03-22 20:22:49