当前位置: 首页 > 工具软件 > sd > 使用案例 >

SD卡系列之---SD卡读写

邢炯
2023-12-01

上文已经介绍了关于SD的初始化流程,在完成初始化后就可以进行扇区读写了

注意事项:

SD卡只能进行整扇区读写,即512byte,每次读写必须为512byte整数倍

SD卡分2种寻址方式 1:字节寻址 2:扇区寻址

CMD读写命令说明:         0~7:cmd命令序号;

                                          8~39:扇区地址(注意寻址方式)

                                          40~47:crc校验字节

一、单块读、写流程

读单块:

1、拉低片选信号

2、发送cmd17,返回(r & 0x80)==0 表示指令被接收

3、持续读字节,直至读取到0xfe,则之后再读取512字节数据为所读目标内容

4、读取2个字节CRC(任意值均可)

5、拉高片选信号

6、补充8个时钟信号(SD卡协议说明)

写单块:

1、拉低片选信号

2、发送cmd24,返回(r & 0x80)==0 表示指令被接收

3、获取SD卡状态,等待SD好准备好

4、写入字节0xfe,该字节为数据开始标志,后续再512字节为写入字节

5、发送2个字节CRC(任意值均可)

6、读取返回值,返回值为0bxxx00101,则代表数据被正确写入

7、等待SD卡忙状态结束(SD卡将数据写入自身)

8、拉高片选信号

9、补充8个时钟信号

二、多块读、写流程

读多块:

1、拉低片选信号

2、发送cmd18,返回(r & 0x80)==0 表示指令被接收

3、持续读字节,直至读取到0xfe,则之后再读取512字节数据为所读目标内容

4、读取2个字节CRC(任意值均可)

5、如需继续读取下一扇区,跳转至步骤3,继续执行

6、发送cmd12,停止进行数据读取

7、拉高片选信号

8、补充8个时钟信号(SD卡协议说明)

写多块:

1、拉低片选信号

2、发送cmd25,返回(r & 0x80)==0 表示指令被接收

3、获取SD卡状态,等待SD好准备好

4、写入字节0xfc,该字节为数据开始标志,后续再512字节为写入字节

5、发送2个字节CRC(任意值均可)

6、读取返回值,返回值为0bxxx00101,则代表数据被正确写入

7、等待SD卡忙状态结束(SD卡将数据写入自身)

8、如需继续进行扇区写入,则跳转至步骤4继续执行

9、发送字节0XFD,完成写入

10、等待SD卡不忙

11、拉高片选信号

12、补充8个时钟信号

三、部分相关代码

(回家后补充相关代码。。。。)

写多块::

UINT8 sd_wr8_s(
        UINT8 *buff,     //pointer to the data dest address
        UINT32 sector,   //start sector number
        UINT8 count      //sector count
        )
{
    if (!(sd_inf.SD_TYPE & 4)) sector *= 512;    /* Convert to UINT8 address if needed */

    SELECT();            /* CS = L */

    if (count == 1)      /* Single block write */
    {
        if ((send_cmd(CMD24, sector) == 0)    /* WRITE_BLOCK */
                && xmit_datablock(buff, 0xFE))
            count = 0;
    }
    else                  /* Multiple block write */
    {
        if (sd_inf.SD_TYPE & 2)
        {
            send_cmd(CMD55, 0);
            send_cmd(CMD23, count);    /* ACMD23 */
        }
        if (send_cmd(CMD25, sector) == 0)      /* WRITE_MULTIPLE_BLOCK */
        {
            do{
                if (!xmit_datablock(buff, 0xFC)) break;
                buff += 512;
            }while (--count);
            if (!xmit_datablock(0, 0xFD))    /* STOP_TRAN token */
                count = 1;
        }
    }
    DESELECT();            /* CS = H */
    rcvr_spi();            /* Idle (Release DO) */
    return count ?  R_ERROR : R_OK;
}

读多块::

UINT8 sd_rd8_s(
        UINT8 *buff,
        UINT32 sector,
        UINT8 count
        )
{
    if (!(sd_inf.SD_TYPE & 4)) sector *= 512;    /* Convert to UINT8 address if needed */

        SELECT();            /* CS = L */

        if (count == 1)      /* Single block read */
        {
            if ((send_cmd(CMD17, sector) == 0)    /* READ_SINGLE_BLOCK */
                    && rcvr_datablock(buff, 512))
                count = 0;
        }
        else                  /* Multiple block read */
        {
            if (send_cmd(CMD18, sector) == 0)      /* READ_MULTIPLE_BLOCK */
            {
                do{
                    if (!rcvr_datablock(buff, 512)) break;
                    buff += 512;
                }while (--count);
                send_cmd12();                /* STOP_TRANSMISSION */
            }
        }

        DESELECT();            /* CS = H */
        rcvr_spi();            /* Idle (Release DO) */
        return count ?  R_ERROR : R_OK;
}

发送数据块

BOOL xmit_datablock (
    const UINT8 *buff,    /* 512 UINT8 data block to be transmitted */
    UINT8 token            /* Data/Stop token */
)
{
    UINT8 resp, wc;

    if (wait_ready() != 0xFF) return FALSE;

    xmit_spi(token);                    /* Xmit data token */
    if (token != 0xFD)      /* Is data token */
    {
        wc = 32;    //  512/16
        do{                              /* Xmit the 512 UINT8 data block to MMC */
//            xmit_spi(*buff++);
//            xmit_spi(*buff++);
            xmit8_spi(buff);
            buff+=16;
        }while (--wc);
        xmit_spi(0xFF);                    /* CRC (Dummy) */
        xmit_spi(0xFF);
        resp = rcvr_spi();                /* Reveive data response */
        if ((resp & 0x1F) != 0x05)        /* If not accepted, return with error */
            return FALSE;
    }
    return TRUE;
}

接受数据块:

BOOL rcvr_datablock (
    UINT8 *buff,            /* Data buffer to store received data */
    UINT16 btr            /* UINT8 count (must be even number) */
)
{
    UINT8 token;

    timer_rt(100000);
    do{                              /* Wait for data packet in timeout of 100ms */
        token = rcvr_spi();
    }while ((token == 0xFF) && (work_mode.timer));
    if(token != 0xFE) return FALSE;    /* If not valid data token, retutn with error */

    do{                              /* Receive the data block into buffer */
//        rcvr_spi_m(buff++);
//        rcvr_spi_m(buff++);
        rcvr8_spi(buff);
        buff+=16;
    }while (btr -= 16);
    rcvr_spi();                        /* Discard CRC */
    rcvr_spi();

    return TRUE;                    /* Return with success */
}

 类似资料: