sd卡spi驱动(2)--SD卡读写块

读写注意事项

SD 卡的读写要分情况,虽然每次读写都是以块为单位,但是 SD 卡的指令寻址有区分,指令寻址就是命令的参数部分,如下图的 CMD17 命令的 data address 部分

在这里插入图片描述
在这里插入图片描述

从数据手册可以看出,这个寻址方式在 SDSC(<=2GB)上是按字节寻址,在 SDHC(4GB-32GB) 和 SDXC(64GB-2TB) 上是按块寻址,具体是什么类型的卡,可以通过读取 OCR 寄存器的 CCS 位的得知

读写时的每个块的大小可以通过 CMD16 进行设置,默认是 512 字节

SD 卡的读

SD 卡读块分为单块读取和连续读取

单块读(CMD17)和多块读(CMD18)其实操作差不多,时序图如下

读相关的令牌描述如下

sd卡spi驱动(2)--SD卡读写块_第1张图片

具体操作顺序如下

  1. 发送读命令
  2. 连续读,等待 SD 卡发送 0xfe
  3. 连续读 512 字节
  4. 读取末尾2字节 CRC
  5. 需要连续读时重复 2-4 步骤,末尾发送 CMD12

具体实现代码如下

void recv_datablock(u8 *data_buf, u32 block_len)
{
    u32 cnt = 0;
    while (spi_read_byte() != 0xfe);
    while (cnt < block_len) data_buf[cnt++] = spi_read_byte();
    spi_send_clock(2*8);
}

void sd_read_blocks(u8 *data_buf, u32 sector, u32 count)
{
    u32 tmp_cnt = 0;
    sd_send_cmd_spi_enter();
    if (count == 1) {
        sd_send_cmd_spi_main(SD_CMD17, sector, 0xff);
        while (spi_read_byte() != 0x00);
        recv_datablock(data_buf, 512);
    }else if (count > 1) {
        sd_send_cmd_spi_main(SD_CMD18, sector, 0xff);
        while (spi_read_byte() != 0x00);
        while (tmp_cnt < count) {
            recv_datablock(data_buf+tmp_cnt*512, 512);
            tmp_cnt++;
        }
        sd_send_cmd_spi_main(SD_CMD12, 0, 0xff); // 停止发送
    }
    sd_send_cmd_spi_exit();
    spi_send_clock(8);
}

SD 卡的写

SD 卡的写也分为单块写(CMD24)和连续写(CMD25)

具体时序图如下

写相关的令牌描述如下

sd卡spi驱动(2)--SD卡读写块_第2张图片

具体操作顺序如下

  1. 发送写命令
  2. 发送多个时钟
  3. 发送起始标志 0xfe(单块)或0xfc(多块)
  4. 连续发送 512 字节
  5. 发送末尾2字节 CRC(0xff)
  6. 将读取的字节与0x05位与,为0x05时传输成功
  7. 需要连续发送时重复 2-6 步骤,结束多块写时发送0xfd
  8. 继续连续读取,直到不为0xff时,SD卡完成写操作

具体实现代码如下

u8 xfer_datablock(u8 *data_buf, u32 block_len, u32 flag)
{
    u8 tmp = 0;
    u8 ret = 1;
    u32 cnt = 0;
    spi_send_clock(8);
    if (flag == 0) spi_write_byte(0xFE); // single
    else spi_write_byte(0xFC);  // multi
    while (cnt < block_len)  spi_write_byte(data_buf[cnt++]);
    spi_write_byte(0xFF); // CRC
    spi_write_byte(0xFF);
    while (tmp != 0xFF) {
        tmp = spi_read_byte();
        if (tmp&0x05 == 0x05) ret = 0;
    }
    return ret;
}
u8 sd_write_blocks(u8 *data_buf, u32 sector, u32 count)
{
    u8 ret = 1;
    u32 tmp_cnt = 0;
    sd_send_cmd_spi_enter();
    if (count == 1) {
        sd_send_cmd_spi_main(SD_CMD24, sector, 0xff);
        while (spi_read_byte() != 0x00);
        xfer_datablock(data_buf, 512, 0);
    }else if (count > 1) {
        sd_send_cmd_spi_main(SD_CMD25, sector, 0xff);
        while (spi_read_byte() != 0x00);
        while (tmp_cnt < count) {
            xfer_datablock(data_buf+tmp_cnt*512, 512, 0);
            tmp_cnt++;
        }
        spi_write_byte(0xfd); // 停止发送
        while (spi_read_byte() != 0xff) // 再次检测
    }
    sd_send_cmd_spi_exit();
    spi_send_clock(8);
}

你可能感兴趣的:(sd卡spi驱动(2)--SD卡读写块)