SPI 中 microSD 卡初始化的正确命令序列是什么?

电器工程 微信
2022-01-04 07:46:41

我正在尝试将microSD卡(2 GB,金士顿,Sandisk)与Silicon Labs C8051F931控制器连接。

我对初始化必须遵循的顺序感到非常困惑。SD Card Projects Using the PIC Microcontroller一书中,第 135 页提到:

因此,将 SD 卡切换到 SPI 模式的步骤如下:
上电。
• 向卡发送至少 74 个时钟脉冲,并将 CS 和 Data Outlines 设置为逻辑“1”。
• 将CD 线设置为低电平。
• 发送 6 字节 CMD0 命令“40 00 00 00 00 95”将卡置于 SPI 模式。
• 检查R1 响应以确保没有设置错误位。
• 重复发送命令CMD1,直到R1 响应中的“in-idle-state”位设置为“0”,
• 并且没有设置错误位。该卡现在已准备好进行读/写操作。

我试过这个,但即使是 CDM1,我也得到 01。预计为 00。

同样在这里,我看到了一个不同的命令序列,他在 CMD0 之后发送 CMD8。但是书上说我必须发送CMD1。

正确的顺序是什么?

4个回答

实际上,您可能在 SD 初始化中找到的大多数信息/代码要么过时,要么不准确,因为它早于 SDHC 和 SDXC 多年。如今,该过程更加复杂,因为它迫使您以向后兼容的方式处理旧硬件。

首先,正如其他人所提到的,选择一个较低的初始时钟速率(一般在 100 kHz - 400 kHz 范围内;如果可能,使用 400 kHz);如果设备允许,您稍后可以切换到更高的时钟。虽然新卡可以安全地承受 MHz 级时钟,但旧卡会抱怨(即无法通信或返回垃圾)。

接下来是你不应该用它CMD1来初始化 SD/SDHC/SDXC 卡,除非你的卡不能识别CMD55/ ACMD41如 SD 卡规范中所述:

在任何情况下都不建议使用 CMD1,因为主机可能难以区分 MultiMediaCard 和 SD 存储卡。

如果您向它们发出一些控制器(主要是更新和更高容量的卡),它们只会停留在空闲状态CMD1你应该先CMD8 0x1AA在reset( CMD0)后发出,然后再尝试使用CMD55 + ACMD41当且仅当失败时,使用CMD1.

tl;博士要在 SPI 模式下初始化卡,您应该:

  1. CMD0arg: 0x0, CRC: 0x95(response: 0x01) - 请注意,如果出现0xFF响应或乱码响应,您应该简单地重复此步骤;有关更多信息,请参见下文。

  2. CMD8arg: 0x000001AA, CRC: 0x87(response: 0x01,后跟 arg 的回显,在这种情况下0x000001AA) - 虽然这个命令看起来是可选的,但对于较新的卡来说它是完全强制性的。虽然0x1AA这里是一个常见的 arg 值,但实际上您也可以传递其他值;请参见“表 7-5:CMD8 在 SPI 模式下的卡操作”,第 10 页。108 规格中的详细信息。

    3a。CMD55arg: , CRC 0x0: any,实际上0x65response : 0x01;everyCMD55前缀 ACMD0x05CMD10x00xF9CMD55ACMD41

    3b。ACMD41, arg: 0x40000000, CRC: any,0x77实际上(请注意,此参数假定卡是 HCS 卡,通常是这种情况;对旧卡使用0x0arg [CRC 0xE5])。如果 response 是0x0,你就可以了;如果是0x01,转到 3a;如果是0x05,请参见上面的注释(在 3a 中);如果两者都不是,则说明有问题(另见下文)。

大多数卡片需要重复步骤 3a/3b(或CMD1旧卡片),通常至少重复一次,即使您在它们之间等待一段时间即实际顺序是CMD0/ CMD8/ CMD55/ ACMD41/ CMD55/ ACMD41(或CMD0/ CMD8/ CMD1/ CMD1) - 可以肯定的是,尝试CMD55/ ACMD41(或者CMD1如果你0x05从他们那里得到)\$n\$次(在你的理由中选择\$n\$ ;它是实际上,如果设备刚打开电源,则必须等待几百毫秒是很常见的,所以瞄准那个),如果你愿意,尝试之间会有小的延迟,如果响应则假设失败0不出现(即如果设备由于某种原因处于空闲模式)。此外,如果设备之前处于某种“奇怪”状态(例如挂断、S̲S̲ 置低 [高]、某些引脚上出现过压/欠压等),接收0xFF来自的情况很常见 - 只需给它一些时间,冲洗并重复\$n\$次。有时,乱码的响应是可以的——如果您发送了几次,但响应仍然不是也不是,请尝试继续如果它有效 - 你很高兴;如果没有 - 它可能已经坏了CMD0CMD00xFF0x01CMD8

请注意,设置了 MSB 但0xFF通常不表明您的 SPI 时钟发生了变化的响应(例如,由于 Vcc 下降,这在您进行 SD 热插拔时经常发生)。要修复它,您可以尝试完全重置设备(电源开/关、置低/置位 S̲S̲ 等);通常有效。

此外,规范说

在最后一次 SD 存储卡总线事务之后,主机需要在关闭时钟之前提供 8(八)个时钟周期让卡完成操作。

它可以在没有它的情况下工作,但由于 8 个周期 = 1 个 SPI 输出字节,它不会造成太大伤害,拥有它就很好。

请注意,您应该至少在每次之前和之后都将 S̲S̲(又名 CS)断言为低电平CMD- 这是完全强制性的CMD0(如果没有它,设备将无法打开),实际上,CMD如果您有标准,则对于所有其他 s都是必需的- 兼容的 SD 卡。似乎将卡的 S̲S̲ 永久连接到 GND如果卡是您的主机将连接到的唯一 SPI 客户端,这是一个好主意,因为它可以节省您的 uC 输出引脚和完全通过代码管理它的需要,并且因为卡应该假设它已全部选中的时间。实际上,有些卡(如果不是大多数卡)实际上期望从高到低的斜率打开,而不是简单地检测到低,因此如果您根本不切换 S̲S̲ 位,然后要么滞后就会生气时钟或吐垃圾;有些(通常是较新的)卡应该可以工作,有些(旧的)可能不行,YMMV(又一次)。尽管如此,对于任何更强大的 SPI 配置(>1 个从设备),请记住在与给定 SD 卡进行任何实际事务之前将引脚置为低电平。

此外,虽然规范说只有CMD0并且CMD8应该在 SPI 模式下具有 CRC,但某些 SD 卡(如 Transcend 卡)似乎需要适当的 CRC 来处理CMD55/ ACMD41- 如果您想安全起见,只需为它们使用预先计算的值。

此外,虽然 SPI 本身不需要上拉/下拉,但在 MISO 上进行 47k 上拉可能是个好主意;某些设备在特定情况下(例如未初始化)将其 DO 引脚保持为高阻态,并且浮动引脚始终可能是奇怪问题的根源。如果你的 uC 有 3.3 Vcc,你可以使用内部上拉;如果是 5V,除非你的 MISO 线已经有适当的 5->3.3V 逻辑转换,否则不要这样做。

进一步阅读:

如何使用 MMC/SDC

SD 规范第 1 部分简化物理层简化规范- 最重要的是第6.4.1和第7.2.1 节模式选择和初始化图 7-1:SD 存储卡状态图(SPI 模式)

SD 卡的规格可在sdcard.org上找到。简化版省略了一些细节,但您应该以第 1 部分中的图 7-2 为例,其中解释了 SDHC 和 SD 卡的初始化序列。

MicroSD 卡 <= 2 GB 可以像旧卡一样工作,因此它们最终0x00应该会为您提供结果这可能需要多次重试,因为卡可以使用来自 SPI 总线的外部时钟来驱动一些内部处理。CMD1

除了@vaxquis 出色的答案,我想引用“物理层简化规范版本 4.10,©Copyright 2001-2013 SD Group (Panasonic, SanDisk, Toshiba) and SD Card Association”中的相应图表(图 7-2 :SPI模式初始化流程):

SD 卡 SPI 初始化序列

在这里,您可以查看以何种顺序发送哪些命令以及响应告诉我们有关卡类型的信息。我认为设备支持尽可能多的卡是可取的。只要涉及到读写 512 字节块的基本操作,至少对所有 V1.x 和 V2.0 的 SD 和 HC 卡都应该是可行的。

我提供了另一种可能性。在 SPI 模式下,三星 MicroSD EVO 32GB 要求所有命令代码都具有有效的 CRC 代码。我敢打赌,他们不是唯一的。我读了一条评论,该人认为所有 32GB 以上的卡都可能是这样的。我已经调试了一个多星期的错误。在发送到卡的所有代码都具有有效的 crc 代码之前,我的代码将无法使用。我用它来计算所有的 CRC 码 https://github.com/hazelnusse/crc7/blob/master/crc7.cc 我什至尝试使用命令 59 来关闭 CRC 码,不。我希望这可以为其他人节省大量时间和精力。

我的带有 CRC 值的初始化代码..

Power On..
Clock card at least 74 (I use 80) cycles with cs high
CMD0 0, crc=0x95
CMD8 0x01aa, crc=0x87
CMD58 0, crc=0xfd
CMD55 0, crc=0x65
CMD41 0x40000000, crc=0x77
CMD9 0, crc=0xaf
CMD16, 512, crc=0x81 (If you want block length of 512)

Some random other commands..
CMD17 0, crc=0x3b (Read one block)
CMD18 0, crc=0x57 (Read multiple blocks)
CMD24 0, crc=0x6f (set write address for single block)
CMD25 0, crc=0x03 (set write address for first block)