Как прочитать _single_block с SD-карты, используя режим SPI (пока что получается странное поведение)? - PullRequest
2 голосов
/ 18 апреля 2011

Когда я запускаю cmd17 с адресом (0x00000000) для моей карты из PIC-18F4520 по шине SPI, я получаю правильный токен R1 возврата из командной строки.Затем, после проверки нескольких циклов, я получаю маркер 0xFE, возвращенный из моего выдающегося SPI_Put_Char (0xFF).Затем должны начаться данные, чтобы я прочитал 512 байт в мой массив IO_Buffer.Когда я сканирую результаты, я получил много байтов 0x00.Как ни странно, и часто, примерно в позиции 448 в секторе 0, появляются некоторые данные - несколько байтов тут и там - тогда последние 32 байта (я могу видеть только 32 на моем ЖК-экране одновременно) - все нули, за которыми следуетмаркер 0x55AA, ожидаемый в конце загрузочного сектора.

Странно то, что при использовании диска исследователь обнаруживает, что SD-карта имеет правильную информацию об нулевом секторе - сообщение MSDOS, код перехода EB, все виды вещей.Моя команда чтения возвращает все это как нули.Я просто не понимаю, что происходит.

Другая информация: я загружаюсь с cmd0, cmd8, cmd58 и OCR читает нормально.Затем acmd41 (цикл cmd55, затем APP_SEND_OP_COND).Все вроде бы отвечают и дают ожидаемый маркер.Наконец, я даже использую SEND_CID для получения информации о карте.который возвращает MID = 3 OID = SD и версию SD017, за которой следует другая информация - кажется, все правильно.

Я попытался добавить резисторы подтягивания и понижения на DOUT с карты, но не влияет на результаты.

Я отчаянно нуждаюсь в идеях, чтобы попытаться заставить эту карту правильно читать.Я (BTW) попробовал две другие карты.Они дают разные конкретные результаты, но качественно одинаковые - инициализация, OCR и CID считывают все нормально.Считывание данных дает в основном нули, за которыми следуют некоторые воспроизводимые, но разреженные байты, и маркер 0xAA55!?!

Моя SD-карта SanDisk 1 ГБ работает с напряжением 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;
};

Спасибо заранее!

Ответы [ 2 ]

2 голосов
/ 20 мая 2011

Ваш сектор 0 выглядит как таблица разделов vaild.Если вы читаете с буквы диска с помощью Disk Исследователь , вы можете прочитать сектор 0 раздела, а не с самой SD-карты.Эта программа не может читать с физического устройства, поэтому вы не можете использовать ее для чтения таблицы разделов.

1 голос
/ 01 декабря 2011

Наконец-то нашли решение этой проблемы!

Оказывается, вы читали MBR, который находится по адресу 0 на SD-карте. Чтобы найти местоположение загрузочного сектора, нужно прочитать соответствующую запись в MBR. Записи начинаются с адреса 0x01be и по 16 байт каждая. Интересующий элемент в записи находится по смещению 0x08, имеет длину 4 байта и называется LBA. [Wikipedia] Чтобы получить адрес расположения загрузочного сектора, нужно умножить LBA на размер сектора (512 байт). [Форум по микрочипам]

Например, см. мой другой ответ .

...