Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I am trying to read a block of data from a standard capacity micro SD card, but the received data does not make any sense. Here is what I'm doing:

  • Initializing the card
  • Reading data
    • Setting CS low
    • Sending CMD16 to set block length
    • Sending CMD17 with start address
    • Waiting for start byte (0xfe)
    • Receiving bytes and printing them to the serial terminal
    • Receiving CRC
    • Setting CS high
    • Sending 8 extra clocks (?)

The data I'm trying to read is the FAT16 boot sector, as shown below: Card contents And the data I'm getting out is this: enter image description here

At this point, I can't even begin to think of what is going wrong. I don't think it's a transmission error, because the data out is always the same. I can also read the boot sector signature 0x55 0xAA every time, even if I set the start address to 510 and read two bytes, they come back perfectly. The problem is that I can't read other bytes.

I also tried swapping cards and that didn't help either.

What am I missing?

EDIT: the function in question is below.

bit sd_read_block(unsigned long size, unsigned long start_addr)
{
    unsigned long i;
    unsigned char r;

    SD_CS = 0;

    r = sd_card_cmd(16, size, 0);

    sprintf(usb_uart_tx_buffer, "CMD16 R Token: %02x.\r\n", r);
    usb_uart_tx(usb_uart_tx_buffer);

    r = sd_card_cmd(17, start_addr, 0);

    sprintf(usb_uart_tx_buffer, "CMD17 R Token: %02x.\r\n", r);
    usb_uart_tx(usb_uart_tx_buffer);

    // wait for start token
    r = 0;
    while (spi_rx_byte() != 0xfe) {
        if (r++ > 25) {
            SD_CS = 1;
            return r;
        }
    }

    for (i = 0; i < size; i++) {
        if (i % 20 == 0) {
            UART1_TX(0x0d);
            UART1_TX(0x0a);
        }
        sprintf(usb_uart_tx_buffer, "%02x ", spi_rx_byte());
        usb_uart_tx(usb_uart_tx_buffer);
    }

    // CRC
    spi_rx_byte();
    spi_rx_byte();

    // extra clocks
    r = spi_rx_byte();

    SD_CS = 1;

    return 0;
}
share|improve this question
1  
I cannot really say what is going on- but there seems to be maybe byte size is incorrect - as fat16 uses different size than fat32/ntfs.. All the 00 at the start do not make sense. and then it seems some bytes are missing/ compressed? there is something wrong with the way the bytes are recived/ interpreted. –  ppumkin Dec 1 '11 at 11:22

1 Answer 1

up vote 7 down vote accepted

It turns out that I was 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 example:

In the output above, the four entries look like this:

00 02 10 00 06 2f ef af 8d 00 00 00 73 0f 3a 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As you can see, only one entry is used. The LBA in this case is 8d 00 00 00 and is in little-endian format, so in big-endian it would be 0x8d or 141 in decimal. Multiply this by 512 and you get 72192 (0x11a00). This is the address of the sector where the FAT starts.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.