3

当我从 SPI 总线上的 PIC-18F4520 向我的卡发出带有地址 (0x00000000) 的 cmd17 时,我从命令发出中得到了正确的返回 R1 令牌。然后,经过几个循环检查后,我得到了一个 0xFE 标记,该标记从我发出的 SPI_Put_Char(0xFF) 中返回。然后数据应该开始,所以我将 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;
};

提前谢谢!

4

2 回答 2

2

您的扇区 0 看起来像一个有效的分区表。如果您使用磁盘调查器从驱动器号读取,您最终可能会读取分区的扇区 0,而不是从 sd 卡本身读取。这个程序似乎不能从物理设备上读取,所以你不能用它来读取分区表。

于 2011-05-20T15:24:39.827 回答
1

终于找到了解决这个问题的方法!

原来您正在读取位于 SD 卡上地址 0 的 MBR。要找到引导扇区的位置,需要读取 MBR 中的相应条目。条目从地址 0x01be 开始,每个为 16 个字节。条目中的兴趣点位于偏移量 0x08 处,长度为 4 个字节,称为 LBA。[Wikipedia]要获得引导扇区位置的地址,可以将 LBA 乘以扇区大小(512 字节)。【微芯片论坛】

例如,请参阅我的其他答案

于 2011-12-01T16:11:37.910 回答