# 3.写操作

作者是初学者，水平有限，本文仅作为个人学习笔记使用，不能保证内容的正确性。部分资料来源于网络，参考了SD卡协议2.0手册等资料，如果有歧义，可以与作者联系。

# 简介

写入操作有两种类型：

- 单次写操作
- 连续写操作
  其中，每次写入的数据块长度由CMD16（ SET_BLOCKLEN）命令设置。高容量SD卡的块大小固定为512字节，因此起始地址应与块边界对齐。

# 单次写操作

| 命令号 | 参数                                                         | 响应 | 名称        | 描述                                                                                       |
| ------ | ------------------------------------------------------------ | ---- | ----------- | ------------------------------------------------------------------------------------------ |
| CMD24  | \[31:0\]：数据地址，单位：字节（SDSC），单位:512字节（SDHC） | R1   | WRITE_BLOCK | 写入一个块的数据，参数为块的首地址。块的长度由CMD16设置，对于高容量卡，块大小固定为512字节 |

通过发送CMD24（WRITE_BLOCK）命令，往参数指定的地址写入一个块的数据。因为高容量卡（SDHC）的块长度固定为512字节，所以发送地址的时候，需要将起始地址对齐到512字节，也就是说，起始地址需要为512的倍数。
在写入一个块的数据之前，需要发送数据起始令牌，该令牌为1个字节，格式为0xFE，表示开始传输数据块。
接下来需要发送一个数据块，该数据块的长度由CMD16（SET_BLOCKLEN）命令设置，一般在初始化时设置完毕。高容量卡（SDHC）的块长度固定为512字节。
发送完数据块之后，需要发送一个CRC，长度为2字节，在SPI模式下，要求不高的情况下可以省略掉，固定为0xFF。
当SD卡收到以上数据的时候，会对这些数据进行计算，并且返回一个数据应答令牌，指示当前数操作是否发生错误。如果接收到的数据块没有错误，将对其进行编程。只要SD卡忙着编程，就会向主机发送连续的忙令牌流，即将DO（对应MCU的MISO）拉低，直到SD卡完成操作，才会将DO拉高，表示空闲。
![SD卡-SPI模式单次写操作.png](https://mirror.simgor.cn/typecho_img/2023/02/1507326852.png)

# 连续写操作

| 命令号 | 参数                                                         | 响应 | 名称                 | 描述                                                                                                              |
| ------ | ------------------------------------------------------------ | ---- | -------------------- | ----------------------------------------------------------------------------------------------------------------- |
| CMD25  | \[31:0\]：数据地址，单位：字节（SDSC），单位:512字节（SDHC） | R1   | WRITE_MULTIPLE_BLOCK | 连续写入多块数据，直到主机发送CMD12命令，参数为块的首地址。块的长度由CMD16设置，对于高容量卡，块大小固定为512字节 |

通过发送CMD25（WRITE_MULTIPLE_BLOCK）命令，从参数指定的地址开始，连续写入数据块。因为高容量卡（SDHC）的块长度固定为512字节，所以发送地址的时候，需要将起始地址对齐到512字节，也就是说，起始地址需要为512的倍数。
在写入一个块的数据之前，需要发送数据起始令牌，该令牌为1个字节，格式为**0xFC**，表示开始传输数据块。

> 注意：0xFC是连续写入的起始令牌，0xFE是单次读取、连续读取、单次写入的起始令牌。

接下来需要发送一个数据块，该数据块的长度由CMD16（SET_BLOCKLEN）命令设置，一般在初始化时设置完毕。高容量卡（SDHC）的块长度固定为512字节。
发送完数据块之后，需要发送一个CRC，长度为2字节，在SPI模式下，要求不高的情况下可以省略掉，固定为0xFF。
当SD卡收到以上数据的时候，会对这些数据进行计算，并且返回一个数据应答令牌，指示当前数操作是否发生错误。如果接收到的数据块没有错误，将对其进行编程。只要SD卡忙着编程，就会向主机发送连续的忙令牌流，即将DO（对应MCU的MISO）拉低，直到SD卡完成操作，才会将DO拉高，表示空闲。
这时候，可以继续重复以上的步骤，进行连续传输。当需要结束写入数据的时候，可以发送结束数据令牌，该令牌位1个字节，格式为0xFD。

> 注意：连续写入的结束条件是发送结束令牌，而不是发送CMD12命令，CMD12命令只适用于连续读操作。

![SD卡-SPI模式连续写操作.png](https://mirror.simgor.cn/typecho_img/2023/02/654117237.png)

当写入时发生数据错误，SD卡会停止写入，这时候可以发送ACMD12命令获取正确写入的块数。该命令的响应格式为4个字节的块数，以及2字节的CRC。

# 数据应答令牌格式

在发送完数据块内容和CRC之后，SD卡会返回一个数据应答令牌，指示当前数操作是否发生错误。该令牌为1个字节，低5位有效，第4位固定为0，第0位固定为1：
![Pasted image 20230203183242.png](https://mirror.simgor.cn/typecho_img/2023/02/390449443.png)

| \[1：3\]位 | 描述                 |
| ---------- | -------------------- |
| 010        | 数据已接受           |
| 101        | CRC错误，数据被拒绝  |
| 110        | 写入错误，数据被拒绝 |

# 关于写入完成之后的操作（可选）

可以继续发送CMD13（SEND_STATUS）命令。要求SD卡发送状态寄存器的内容，以获取SD卡的当前状态。

# 如果需要评论

因为是个人博客，因备案要求不能使用交互服务，如果需要评论，可以前往本文的CSDN页：
[CSDN-SD卡 SPI模式操作（3）写操作](https://blog.csdn.net/Simgo/article/details/128876798)

# 结尾

关于SD卡在SPI模式下的操作，到这里也介绍得差不多了，大家可以根据思路去编写代码，也可以去学习正点原子等厂家的代码。后续我会继续给大家介绍FatFS的使用。

