在SPI中初始化SD卡问题

12

我看了一下 Stack Overflow 上的问题 使用SPI接口初始化microSD卡,没有找到与我的问题匹配的答案(也就是说,这些都是我已经尝试过的)。

我有一个类似的问题,我正在尝试通过微控制器的SPI接口访问SD卡(具体来说是HC908)。我尝试按照物理层简化规范 v2.00 中的流程图进行操作,对于Transcend 1 GB和2 GB以及AE&C 1 GB的卡,它似乎可以正确初始化。但是,我在我的相机上使用的旧卡的存货中发现有三张卡存在问题。

我的代码全部使用 HC908 汇编语言编写。我检查了 SPI 时钟线,在初始化期间它运行约为 350 kHz(这是 HC908 在我的低 MCU 时钟速度下提供的唯一速度倍增器,其落在 100 - 400 kHz 窗口内)。

以下是三张无法完成初始化例程的卡的结果(所有操作都是在不改变任何代码或时序参数的情况下连续进行的):

Canon 16Meg card (labeled as SD):
Set card select high
Send 80 SPI clock cycles (done by writing 0xFF 10 times)
Set card select low
Send CMD0 [0x400000000095] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (indicates idle)
Send CMD8 [0x48000001AA87] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command)
Because illegal command set local flag to indicate v1 or MMC card
Send CMD58 [0x7A00000000FD] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command)
because illegal command branch to error routine
Send CMD13 [0x4D000000000D] (show status buffer) and Loop up to 8 times waiting for high bit on response to go low
R1= 0x05 (idle and illegal command)

非法命令标志是否卡住?在进行CMD8之后,我应该执行一些操作来清除该标志吗?

SanDisk UltraII 256Meg
Set card select high
Send 80 SPI clock cycles (done by writing 0xFF 10 times)
Set card select low
Send CMD0 [0x400000000095] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle)
Send CMD8 [0x48000001AA87] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command)
Because illegal command set local flag to indicate v1 or MMC card
Send CMD58 [0x7A00000000FD] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle)
Send 0xFF 4 times to read OCR
OCR = 0xFFFFFFFF
Send CMD55 [0x770000000065] (1st part of ACMD41) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle)
Send CMD41 [0x6900000000E5] (2nd part of ACMD41) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command)
Because illegal command, assume card is MMC
Send CMD1 [0x4100000000F9] (for MMC) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command)
Repeat the CMD1 50 times (my arbitrary number to wait until idle clears)
Every R1 response is 0x05 (idle and illegal command)

为什么OCR都是F?这似乎并不正确。此外,为什么ACMD41和CMD1会回复非法命令?CMD1失败是因为卡正在等待有效的ACMD,即使出现非法命令响应也是如此吗?

SanDisk ExtremeIII 2G:
Set card select high
Send 80 SPI clock cycles (done by writing 0xFF 10 times)
Set card select low
Send CMD0 [0x400000000095] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle)
Send CMD8 [0x40000001AA87] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x7F (??? My loop shows the responses for each iteration and I got 0xFF 0xFF 0xC1 0x7F... is the card getting out of sync?)
Send CMD58 [0x7A00000000FD] and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle and back in sync)
Send 0xFF 4 times to read OCR
OCR = 0x00FF80
Send CMD55 [0x770000000065] (1st part of ACMD41) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x5F (??? loop responses are 0xFF 0xFF 0xF0 0x5F... again out of sync?)
Send CMD41 [0x6900000000E5] (2nd part of ACMD41) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x05 (idle and illegal command, but back in sync???)
Because illegal command, assume card is MMC
Send CMD1 [0x4100000000F9] (for MMC) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x7F (??? loop responses are 0xFF 0xFF 0xC1 0x7F... again out of sync?)
Repeat CMD1 and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x01 (idle)
Repeat CMD1 and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x7F (??? loop responses are 0xFF 0xFF 0xC1 0x7F... again out of sync?)
Repeat CMD1 and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x00 (out of idle)
Send CMD9 [0x4900000000AF] (get CSD) and Loop up to 8 times waiting for high bit on response to go low
R1 = 0x3F (??? loop responses are 0xFF 0xFF 0xC1 0x3F... again out of sync?)
Code craps out because Illegal command bit is high.

那张卡出了什么问题?

有时它是同步的,有时不是。(上述模式可以重复。)我已经对其进行了调试,并且没有看到在MOSI/MISO传输之间发生任何错误的时钟周期。


忘了提一下。在这些初始化三张卡失败的尝试之后,我把它们放到我的笔记本电脑的SD卡读卡器中,我仍然可以像标准的SD卡一样访问它们(读写)而没有问题。 - Sembazuru
在“SanDisk Extreme III”的命令列表中发现了一个错误:发送 CMD8 [0x40000001AA87]-应为0x48,而不是0x40。 - user1985657
3个回答

23

好的,我找到了我的问题。对于任何遇到这个问题的人来说,重要的是记住在收到响应后发送一个额外的0xFF。这为SD卡准备下一条命令提供了额外的八个时钟周期。有些卡似乎不需要这个(例如我使用的Transcend卡),但其他卡需要。

实际上,在我的“写入命令”例程的开始处,我放了一个简单的循环,它会发送0xFF,直到它得到0xFF作为响应,这样我就不必去所有读取响应的位置,确保我多发一个0xFF。因为对于SD卡来说(通常)在SPI模式下,如果没有时钟周期进入,时间就静止了。

我注意到一件事,但尚未找到答案(但目前它并没有造成任何影响):在读取CSR的16个字节后,似乎还有另外2个非0xFF的字节输出...那是CRC16吗?这很奇怪,因为CSR已经内置了CRC...


1
谢谢,你帮我省了好几个小时的时间!! - Jairo Andres Velasco Romero
1
同样的问题,这个方法非常有用,特别是发送0xFF直到返回0xFF。我之前使用的是Class 2的Transcend卡,一切正常,但当我换成Class 4的Transcend卡后,我无法初始化它,也无法读取。现在我可以了。谢谢。 - David
我曾经遇到过非常类似的问题,这个答案解决了我的问题,谢谢。我有3张SDHC卡,我的初始化适用于东芝和松下的卡,但是闪迪卡就是无法工作。发送时钟周期解决了这个问题。 - Dean2690

3
如果您启用了CRC(使用CMD59),那么是的,数据块将附加CRC16。
有关更多信息,请参见“物理层简化规范版本2.00”,章节“总线传输保护”和“数据读取”。

抱歉回复晚了...(忙于其他项目...)我猜我没有将CSR概念化为“数据块”。我只是将它视为状态寄存器。 - Sembazuru

2
这很重要:我曾经遇到过SD / MMC卡的很多麻烦,直到我发现我必须选择一个操作电压。 您可以通过发送带有设置电压位的ACMD41来实现此操作。 注意:只能选择一个位。 如果您不选择电压或选择多个电压,则在某些SD卡上会保持空闲状态并永远不会退出。
也就是说:如果您的ACMD41不断发送响应0x01,则尚未选择电压。 电压在ACMD41的32位参数位23...8中。 对于3.2V ... 3.3V,这是第20位,因此例如,您可以:
acmdSDAppOpCond[2] = (1 << (20 & 7));           /* 3.2V .. 3.3V */

这是16进制值0x10,所以您的ACMD41应该像这样... 0x69 0x40 0x10 0x00 0x00 0xCD ...或者如果是SDSC卡... 0x69 0x00 0x10 0x00 0x00 0x5F

这里是最常见值的简短(不完整)表格:

Bit23: 3.5V..3.6V
Bit22: 3.4V..3.5V
Bit21: 3.3V..3.4V
Bit20: 3.2V..3.3V
Bit19: 3.1V..3.2V
Bit18: 3.0V..3.1V
Bit17: 2.9V..3.0V
Bit16: 2.8V..2.9V
Bit15: 2.7V..2.8V

在任何时候,您不必将CS高电平切换。您可以一直保持低电平。


1
Sandisk SDCard规范如下:“在SPI模式下,与SD模式相反,ACMD41(或CMD1,对于2.1mm-SD卡)没有操作数,并且不返回OCR寄存器的内容。相反,主机可以使用CMD58(仅在SPI模式下可用)来读取OCR寄存器。此外,主机有责任避免访问不支持其电压范围的卡。”官方规范并未反对此,并明确表示标准容量卡的ACMD 41应具有0x0参数。 - thenickdude
1
在SD模式下,该参数是必需的:"[...] 主机将所需的VDD电压窗口作为[SD_SEND_OP_COND(ACMD41)]命令的操作数发送。 不能在指定范围内执行数据传输的SD卡必须从进一步的总线操作中丢弃自己并进入非活动状态2。通过在命令中省略电压范围,主机可以查询每张卡,并确定是否存在任何不兼容性,然后将超出范围的卡发送到非活动状态。" - thenickdude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接