如何使用SPI模式从SD卡中读取_单个_block(到目前为止,仍获得怪异的行为)?

| 当我从SPI总线上的PIC-18F4520向卡发出地址(0x00000000)的cmd17时,我从命令发出中获得了正确的返回R1令牌。然后,经过几次循环检查,我从发出SPI_Put_Char(0xFF)的过程中得到了一个0xFE标记。然后应该开始数据,因此我将512个字节读取到IO_Buffer数组中。扫描退货时,我得到了很多0x00字节。奇怪的是,反复地,在扇区0的位置448处,一些数据传过来-到处都是几个字节-然后最后的32个字节(我只能在LCD屏幕上一次查看32个字节)全为零,然后是引导扇区末尾预期的0x55AA标记。 奇怪的是,使用磁盘调查器显示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看起来像一个有效的分区表。如果您使用磁盘调查器从驱动器号中读取,则可能最终读取分区的扇区0,而不是从SD卡本身读取。该程序似乎无法从物理设备读取,因此您不能使用它读取分区表。     
终于找到了解决办法! 事实证明,您正在读取MBR,它位于SD卡上的地址0处。为了找到引导扇区的位置,需要读取MBR中的相应条目。条目从地址0x01be开始,每个都是16字节。条目中的兴趣点位于偏移量0x08处,长度为4个字节,称为LBA。 [Wikipedia]要获取引导扇区位置的地址,可以将LBA乘以扇区大小(512字节)。 [微芯片论坛] 例如,请参阅我的其他答案。     

要回复问题请先登录注册