上文已经介绍了关于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 */
}