3

When I issue cmd17 with address (0x00000000) to my card from PIC-18F4520 on SPI bus, I get a correct return R1 token from the command issue. Then, after a few loops checking, I get a 0xFE marker returned from my issuing SPI_Put_Char(0xFF). Data should then start so I read 512 bytes into my IO_Buffer array. As I scan the returns, I got many 0x00 bytes. Oddly, and repeatedly, at about pos 448 in sector 0, some data comes over - a few bytes here and there - then the the final 32 bytes (I can only view 32 at a time on my LCD screen) are all zeroes followed by the 0x55AA marker expected at the end of the boot sector.

The odd thing, is that using disk investigator reveals the SD card has the proper sector zero information - MSDOS message, EB jump code, all sorts of stuff. My read command gives all that back as zeroes. I just don't get what's happening.

Other information: I boot with the cmd0, cmd8, cmd58 and OCR reads fine. Then acmd41 (looping cmd55 followed by APP_SEND_OP_COND). All seem to respond and give expected marker. Finally, I even use SEND_CID to get the card information. that returns MID=3 OID=SD and a verion SD017 followed by other information - seems all to be correct.

I have tried adding pull up and pull down resistors on DOUT from card but doesn't affect any results.

I am desperate for ideas to try to get this card to read correctly. I have (BTW) tried two other cards. They give different specific results, but qualitatively the same - initialization, OCR, and CID read all work okay. Data read gives mostly zeroes followed by some reproducible but sparse bytes, and a 0xAA55 marker!?!

My SanDisk 1GB SD card is running at 3.296 volts which seems stable during card reading.

Here's some code:

    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;
};

Thanks ahead of time!

Udo
  • 449
  • 3
  • 13
The Dick Chuck
  • 31
  • 1
  • 1
  • 4
  • I have exactly the same problem, as described here: http://electronics.stackexchange.com/questions/23053/problems-reading-data-from-a-microsd-card Can't think of any possible cause.. – Armandas Dec 01 '11 at 14:37

2 Answers2

2

Your sector 0 looks like a vaild partition table. If you read from the drive letter using disk investigator you may ended up reading the sector 0 of the partition and not from the sd-card itself. This program does not seem to be able to read from a physical device, so you can not use it to read the partition table.

Turbo J
  • 7,563
  • 1
  • 23
  • 43
1

Finally found the solution to this!

It turns out you were reading the MBR, which is located at the address 0 on the SD card. To find the location of the boot sector, one needs to read the appropriate entry in the MBR. The entries start at the address 0x01be and are 16 bytes each. The point of interest in the entry lies at the offset 0x08, is 4 bytes long and is called an LBA. [Wikipedia] To get the address of the boot sector location, one would multiply the LBA by the size of a sector (512 bytes). [Microchip forum]

For an example, see my other answer.

Community
  • 1
  • 1
Armandas
  • 2,276
  • 1
  • 22
  • 27
  • That's more or less what Turbo J says (the partition table part). :) -Note: The first thing you should check is if the sector you've just read had the 0x55,0xaa signature at the end. If it does, then it's either the partition table or the boot sector. Now you have to check all the possible fields you can for sane values. Remember to allow for both partition table and boot sector in the same sector (!) –  Mar 22 '14 at 20:22