📄 sd_spi.#2
字号:
//SD卡命令发送程序接口
#include "inc.h"
#include "define.h"
#define MAX SD_BLOCKSIZE
extern xdata uint8 statuslen = 4;
extern xdata uint8 cidlen = 16; //len取值0~MAX
//extern xdata uint8 csdlen = 16;
extern xdata uint8 sendbuf[16] ={0,1,2,3,4,5,6,7,8,9,0};
extern xdata uint8 recbuf[1] ={0};
extern xdata uint8 resp[5] = {0};
uint8 sd_send_cmd(uint8 cmd,uint8 *param,uint8 resptype,uint8 *resp) //发送命令
{
char i,rlen;
uint8 tmp;
spi_cs_clr();
// command = 0;
spi_sendbyte(((cmd & 0x3f) | 0x40)); //发送命令头和命令字
for(i=3;i>=0;i--)
{
spi_sendbyte(param[i]); //发送 send parameters
}
if(cmd == 0)
spi_sendbyte(0x95); //CRC校验,用于第一个命令
else
spi_sendbyte(0xFF);
switch(resptype)
{
case R1: rlen = 0; break;
case R1B: rlen = 1; break;
case R2: rlen = 2; break;
case R3: rlen = 5; break;
}
i = 0;
do
{
tmp = spi_recbyte();
i++;
}
while(((tmp &0x80 )!= 0) && (i<SD_CMD_TIMEOUT));
if(rlen == 0)
resp[0] = tmp;
for(i =rlen-1;i>=0;i--)
{
resp[i] = tmp;
tmp = spi_recbyte();
}
spi_sendbyte(0xFF);
// if((cmd != 9) && (cmd != 10) && (cmd != 13))
// {
// spi_cs_set();
// }
// return ret;
return tmp;
}
void sd_pack_param(uint8 *parameter,uint32 value) //将32位数据转化为4个字节
{
parameter[3] = (uint8)(value>>24);
parameter[2] = (uint8)(value>>16);
parameter[1] = (uint8)(value>>8);
parameter[0] = (uint8)(value);
}
uint8 sd_block_cmd(uint8 cmd,uint8 restype,uint32 parameter) //块命令
{
uint8 param[4],resp,ret;
sd_pack_param(param,parameter);
ret = sd_send_cmd(cmd,param,restype,&resp);
return ret;
}
uint8 sd_set_blocklen(uint32 length) //设置块长度
{
uint8 param[4],resp,ret;
sd_pack_param(param,length);
ret = sd_send_cmd(CMD16,param,CMD16_R,&resp);
return ret;
}
uint8 sd_crc(uint8 enable)
{
uint8 param[4],resp,ret;
if( enable == 1 )
param[0] = 1; //使能CRC
else //禁止CRC
param[1] = 0;
ret = sd_send_cmd(CMD59,param,CMD59_R,&resp);
if(ret != SD_NO_ERR)
return ret;
return SD_NO_ERR;
}
uint8 sd_read_single_block(uint32 blockaddr) //读单块命令
{
sd_block_cmd(CMD17,CMD17_R,blockaddr);
sd_read(SD_BLOCKSIZE,recbuf);
spi_cs_set();
return SD_NO_ERR;
}
uint8 sd_read_multiple_block(uint32 blockaddr) //读多块命令,直到收到停止命令
{
sd_block_cmd(CMD18,CMD18_R,blockaddr);
spi_cs_set();
return SD_NO_ERR;
}
uint8 sd_stop_transmission(void) //停止发送
{
uint8 param[4] = {0,0,0,0,},resp;
return(sd_send_cmd(CMD12,param,CMD12_R,&resp));
}
uint8 sd_write_single_block(uint32 blockaddr) //写单块命令
{
sd_block_cmd(CMD24,CMD24_R,blockaddr);
sd_write(0,SD_BLOCKSIZE,sendbuf);
return SD_NO_ERR;
}
uint8 sd_write_multiple_block_cmd(uint8 blockaddr) //写多块命令
{
sd_block_cmd(CMD25,CMD25_R,blockaddr);
sd_write(1,SD_BLOCKSIZE,sendbuf);
spi_cs_set();
return SD_NO_ERR;
}
uint8 erase_startblock(uint32 startblock) //设置块擦除起始地址
{
return(sd_block_cmd(CMD32,CMD32_R,startblock));
}
uint8 erase_endblock(uint32 endblock) //设置块擦除结尾地址
{
return(sd_block_cmd(CMD33,CMD33_R,endblock));
}
uint8 erase_selectedblock(void) //擦除选中的块
{
uint8 param[4],tmp,resp;
sd_pack_param(param,0);
tmp = sd_send_cmd(CMD38,param,CMD38_R,&resp);
spi_cs_set();
return SD_NO_ERR;
}
uint8 sd_check_protect(void)
{
uint8 param[4],tmp,resp;
sd_pack_param(param,0);
tmp = sd_send_cmd(CMD30,param,CMD29_R,&resp);
spi_cs_set();
return tmp;
}
uint8 sd_clear_protect(void)
{
uint8 param[4],tmp,resp;
sd_pack_param(param,0);
tmp = sd_send_cmd(CMD29,param,CMD29_R,&resp);
spi_cs_set();
return tmp;
}
uint8 sd_set_protect(void)
{
uint8 param[4],tmp,resp;
sd_pack_param(param,0);
tmp = sd_send_cmd(CMD28,param,CMD28_R,&resp);
spi_cs_set();
return tmp;
}
/************************************数据传输*****************************************/
uint8 sd_read(uint32 len,char* recbuf) //读SD卡,len为数据长度,recbuf为数据缓冲区
{
uint8 tmp;
uint16 i = 0;
spi_cs_clr();
do
{ //等待数据起始令牌
tmp = spi_recbyte();
i++;
}while((tmp == 0xff) && (i<SD_READREG_TIMEOUT));
if(i >= SD_READREG_TIMEOUT)
{
spi_cs_set();
return SD_ERR_TIMEOUT_READ; //超时错误
}
for(i=0;i<len;i++)
{
// recbuf[i] = spi_recbyte();
tmp = spi_recbyte();
}
tmp = spi_recbyte();
tmp = spi_recbyte();
spi_sendbyte(0xFF); //返回前发送8个CLK
spi_sendbyte(0xFF);
spi_cs_set();
sd_delay(20);
return(SD_NO_ERR);
}
uint8 sd_write(uint8 bmulti,uint32 len,char* sendbuf) //写SD卡,len为长度,sendbuf为发送缓冲,
{ //bmulti为发送多块单块选择:1多块,0单块
uint32 i = 0;
uint8 tmp;
spi_cs_clr();
// spi_sendbyte(0xff); //先发送8个CLK
if( bmulti == 1 )
spi_sendbyte(SD_TOK_WRITE_STARTBLOCK_M); //写多块开始令牌
else //写单块开始令牌
spi_sendbyte(SD_TOK_WRITE_STARTBLOCK);
for(i=0;i<len;i++)
{
// spi_sendbyte(sendbuf[i]);
spi_sendbyte(0x55);
}
spi_sendbyte(0xFF); //16位CRC
spi_sendbyte(0xFF);
do
{
tmp = spi_recbyte();
}while(tmp == FF);
do
{
tmp = spi_recbyte();
}while(tmp == 0);
spi_cs_set();
sd_delay(20);
return SD_NO_ERR;
}
void sd_sendmulti_stop(void) //发送停止数据传输令牌
{
spi_sendbyte(0xff);
spi_sendbyte(SD_TOK_STOP_MULTI);
spi_recbyte();
spi_cs_set();
}
uint8 sd_en_acmd()
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(CMD55,param,CMD55_R,&resp);
spi_cs_set();
return ret;
}
uint8 sd_activates()
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(ACMD41,param,ACMD41_R,&resp);
spi_cs_set();
return ret;
}
uint8 sd_read_ocr()
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(CMD58,param,CMD58_R,&resp);
spi_cs_set();
return ret;
}
uint8 sd_readcard_status(uint8*buffer) //读card status寄存器
{
uint8 param[4] ={0,0,0,0};
uint8 ret;
ret = sd_send_cmd(CMD13,param,CMD13_R,buffer);
sd_read(statuslen,recbuf);
spi_cs_set();
return ret;
}
uint8 sd_read_csd()
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(CMD9, param, CMD9_R, &resp); /* 读CSD寄存器命令 command that read CSD register */
sd_read(cidlen,&recbuf);
spi_cs_set();
return ret;
}
uint8 sd_read_cid()
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(CMD10, param, CMD10_R, &resp); /* 读CID寄存器命令 command that read CID register */
sd_read(cidlen,&recbuf);
spi_cs_set();
return ret;
// return (sd_read(cidlen, recbuf));
}
void sd_delay(uint8 value) //延时函数
{
uint8 i,j;
for(i=0;i<value;i++)
for(j=0;j<10;j++)
{
// _NOP_();
}
}
uint8 sd_reset(void) //复位SD卡
{
uint8 param[4] = {0,0,0,0},resp,ret;
ret = sd_send_cmd(CMD0,param,CMD0_R,&resp);
spi_cs_set();
return ret;
}
uint8 sd_check(void) //发出CMD1,查询卡的状态
{
uint8 param[4] = {0,0,0,0},ret,resp;
ret = sd_send_cmd(CMD1,param,CMD1_R,&resp);
spi_cs_set();
return ret;
}
uint8 sd_init(void) //SD卡初始化进入SPI模式
{
uint8 tmp;
uint8 i = 0;
spi_cs_set();
for(i=0;i<13;i++)
{
spi_sendbyte(0xFF);
}
spi_cs_clr();
sd_reset(); //发送CMD0复位SD卡
sd_delay(2);
do
{
sd_en_acmd();
tmp = sd_activates();
sd_delay(20);
i++;
//激活初始化
}while( (tmp!= 0)&&(i<SD_CMD_TIMEOUT));
if(i>=SD_CMD_TIMEOUT)
i = 1; //超时
else
i = 0;
sd_check(); //发送CMD1查询SD卡状态
sd_delay(1);
// sd_crc(0);
// sd_delay(1);
sd_set_blocklen(SD_BLOCKSIZE); //设置BLOCK长度
sd_delay(5);
sd_clear_protect();
sd_delay(5);
sd_readcard_status(recbuf); //读card status寄存器
sd_delay(10);
sd_read_cid();
sd_delay(10);
sd_read_csd();
sd_delay(10);
return SD_NO_ERR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -