📄 sd_spi.c
字号:
#include"SD_Card/sd_comand.h"
#include"SD_Card/Sd_Spi.h"
#include"SD_Card/Sd_config.h"
#include"SD_Card/sd_power.h"
#include"SD_Card/CRC16.h"
#define SPI_CLOCK 1500000 //SPI通信时的时钟频率.
unsigned char g_reg;
unsigned long SD_size;
unsigned char csd[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* 超时时间单位表(单位:0.000000001ns) timeout unit table */
const uint32 time_unit[8] = {1000000000,100000000,10000000,
1000000,100000,10000,1000,100};
/* 超时时间表 timeout value table */
const uint8 time_value[16] = { 0,10,12,13,15,20,25,30,
35,40,45,50,55,60,70,80};
/* 超时时间因数表 timeout factor table */
const uint8 r2w_fator[6] = {1,2,4,8,16,32};
unsigned char Spi_buff[512];
void Send_byte(unsigned char dat);
sd_struct sds;
void delay_us(unsigned char delay_time)
{
while(delay_time>0)delay_time--;
}
void SPI_delay(unsigned char Spi_delay)
{
unsigned char ch, i;
for(i=0;i<Spi_delay;i++)
{
S0SPDR=0xff;
while((S0SPSR&0x80)==0);
ch=S0SPSR;
ch=S0SPDR;
}
}
void Spi_IO_Init(void)
{
SD_IOSELPIN =0x00001500; //IO SPI0
SD_IODIR |=(SD_MOSI|SD_SCK|SD_CS);
SD_IODIR &=~SD_MISO;
SD_IOCLR =SD_SCK;
SD_IOCLR =SD_MOSI;
SD_IOCLR =SD_MISO;
}
void Spi_Init(void)
{
S0SPCR=0x0000;
SD_SSEL_SET();
S0SPCCR=0x80; //SCK=400k.note: the value>=8.
S0SPCR=0x0020; //master ,CPHA[0],CPOL[0],MSB,8bits.
}
void SetMaxClk(void)
{
S0SPCCR=0x08;
}
void Send_byte(unsigned char dat)
{
unsigned char tmp;
S0SPDR=dat;
while((S0SPSR&0x80)==0);
tmp=S0SPSR;
tmp=S0SPDR;
}
unsigned char Rec_byte()
{
unsigned char dat;
S0SPDR=0xff;
while((S0SPSR&0x80)==0);
dat=S0SPSR;
dat=S0SPDR;
return dat;
}
unsigned char Send_CMD(unsigned char *cmd,unsigned char req)
{
unsigned char i;
unsigned char ch,time_out;
time_out=0;
for(i=0;i<6;i++)
{
S0SPDR=*(cmd+i);
while((S0SPSR&0x80)==0);
ch=S0SPSR;
ch=S0SPDR;
}
do{
S0SPDR=0xff;
while((S0SPSR&0x80)==0);
ch=S0SPSR;
ch=S0SPDR;
time_out++;
}while((ch!=req)&&(time_out<TRYTIME));
return ch;
}
unsigned char Send_CMD1()
{
unsigned char temp,re_value;
temp=0;
do
{
SD_SSEL_CLR();
re_value=Send_CMD(CMD1,0x00);
temp++;
}while((re_value!=0x00)&&(temp<TRYTIME));
SD_SSEL_SET();
return re_value;
}
void SD_CalTimeout()
{
uint32 tmp;
uint8 time_u,time_v,fator;
sds.timeout_read = 100*SPI_CLOCK/100/8; /* 默认读超时为100ms */
sds.timeout_write = 250*SPI_CLOCK/1000/8; /* 默认写超时为250ms */
sds.timeout_erase = 250*SPI_CLOCK/1000/8;
time_u = (csd[1] & 0x07); /* 读超时时间单位 read timeout unit */
time_v = (csd[1] & 0x78) >> 3; /* 读超时时间值 read timeout value */
fator = (csd[12] & 0x1c) >> 2; /* 写超时时间因数 write timeout factor */
if(time_v == 0) return;
if(fator >= 6) return;
tmp = SPI_CLOCK * time_value[time_v] / 10 / time_unit[time_u]; /* TACC * f (单位 unit: clock) */
tmp = tmp + csd[2] * 100; /* TACC * f + NSAC * 100 (单位 unit: clock) */
/* 计算得到的超时值 the timeout value of being calculated */
sds.timeout_read = tmp;
sds.timeout_write = tmp * r2w_fator[fator]; /* (TACC * f + NSAC * 100) * R2WFACTOR (单位 unit:clock)*/
sds.timeout_read = sds.timeout_read * 100 / 8; /* 实际值为计算值的100倍 */
sds.timeout_write = sds.timeout_write * 100 /8;
/*
if (sds.timeout_read>(100*SPI_CLOCK/100/8))
// * 取计算值与默认值中的最小值
sds.timeout_read = (100*SPI_CLOCK/100/8);
if (sds.timeout_write>(250*SPI_CLOCK/1000/8))
sds.timeout_write = (250*SPI_CLOCK/1000/8);
*/
sds.timeout_erase = sds.timeout_write;
}
unsigned int Read_CSD()
{
// unsigned char csd[32];
unsigned int c_size;
unsigned int c_size_mult;
unsigned int mult;
unsigned int read_bl_len;
unsigned int blocknr = 0;
unsigned int block_len = 0;
unsigned int size = 0;
unsigned int timeout=0;
unsigned int taac=0,nsac=0;
unsigned char i,ch=0;
SD_SSEL_SET();
for(i=0;i<0xf;i++)
Send_byte(0xff);
while((ch!=0xfe)&&(timeout<TRYTIME))
{
SD_SSEL_CLR();
Send_CMD(CMD9,0x00);
do
{
timeout++;
ch=Rec_byte();
}while((ch!=0xfe)&&(timeout<30));
for(i=0;i<20;i++)
{
csd[i]=Rec_byte();
}
}
SD_SSEL_SET();
//计算size of sd card.
/*****************************************************************************/
c_size = csd[8] + csd[7] * 256 + (csd[6] & 0x03) * 256 * 256;
c_size >>= 6;
c_size_mult = csd[10] + (csd[9] & 0x03) * 256;
c_size_mult >>= 7;
read_bl_len = csd[5] & 0x0f;
mult = 1;
mult <<= c_size_mult + 2;
blocknr = (c_size + 1) * mult;
block_len = 1;
block_len <<= read_bl_len;
size = block_len * blocknr;
/******************************************************************************/
SD_CalTimeout();
return size;
}
unsigned char Send_Rset()
{
unsigned char temp,re_value1;
temp=0;
do{
SD_SSEL_SET();
SPI_delay(40);
SD_SSEL_CLR();
re_value1=Send_CMD(CMD0,0x01);
temp++;
}while((re_value1!=0x01)&&(temp<100));
SD_SSEL_SET();
return re_value1;
}
unsigned char SD_WaitBusy(uint8 waittype)
{
uint32 timeout, i = 0;
uint8 tmp;
if (waittype == 0x01)//写等待.
timeout = sds.timeout_write;
else //删除等待.
timeout = sds.timeout_erase;
SD_SSEL_CLR();
do
{ /* 等待忙结束 wait for being busy end */
tmp = Rec_byte();
i++; //down side,如果使用timeout ,数据根本写不进.
}while ((tmp != 0xFF) && (i <1000/* timeout*/)); /* 忙时收到的值为0xFF always receive 0xFF when card is busy */
SD_SSEL_SET(); /* 有错 */
if(i < timeout)
return 0; /* 返回0,表示没超时 return 0 indicate that operation is not time out */
else
return 1; /* 返回错误码,表示超时 return error code indicate that operation is time out */
}
uint16 SD_GetCRC16(uint8 *pSource, uint16 len)
{
uint16 i;
uint16 result = 0;
uint16 temp;
// temp=CRCTable[result
for (i = 0; i < len; i++)
{
temp=(result>>8)^(*pSource);
result =(result<<8)^temp;
pSource++;
}
// result = (result << 8)^(uint16)CRCTable[(result >> 8)^*(pSource++)];
return result;
}
void Init_SpiBuff()
{
uint16 i;
for(i=0;i<512;i++)
{
Spi_buff[i]=0x00;
}
Spi_buff[2]=0xff;
Spi_buff[3]=0x0a;
}
unsigned char SD_WriteSingleBlock(uint32 Sd_addr)
{
uint16 i;
uint8 CMD24[6]={0x58,0x0,0x0,0x0,0x0,0xFF};
uint8 ret,timeout;
Sd_addr <<= 9; /* 调整地址:左移9位 adjust address: move 9 bits left */
//SD_PackParam(param, parameter); /* 将参数转化为字节形式 change the parameter to bytes form */
CMD24[4] = (uint8)(Sd_addr >> 24);
CMD24[3] = (uint8)(Sd_addr >> 16);
CMD24[2] = (uint8)(Sd_addr >> 8);
CMD24[1] = (uint8)(Sd_addr);
Init_SpiBuff();
SD_SSEL_CLR();
timeout=0;
do{
timeout++;
ret=Send_CMD(CMD24,0x00);// * 结束数据传输失败 stop transmission operation fail
}while((ret!=0x00)&&(timeout<30));///发送有错.
// SD_SSEL_SET(); //可能不需要
Send_byte(0xff); //****************************
// SD_SSEL_CLR();
Send_byte(0xfe);
for(i=0;i<512;i++)
{
Send_byte(Spi_buff[i]);
}
i=SD_GetCRC16(Spi_buff,512);
Send_byte((i >> 8) & 0xFF); //高位在前.
Send_byte(i & 0xFF); /* 发送CRC16校验码 send CRC16 check code */
ret=Rec_byte(); //这里应该不需多次吧.
if((ret&0x0f)!=0x05)
{
Send_byte(0xFF); /* 返回之前发送8个clock clock out 8 clk before return */
SD_SSEL_SET();
return 1;//返回错误.
}
// SD_SSEL_SET();
i=SD_WaitBusy(0x01);
if(i!= 0x00)
return 2; /* 写入超时 write time out */
else
return 0; /* 写入正确 write right */
}
unsigned char SD_ReadSingleBlock(uint32 Sd_addr)
{
uint16 i;
uint8 CMD17[6]={0x51,0x00,0x0,0x0,0x0,0xff};
uint8 ret,timeout;
ret =0xff;
Sd_addr =Sd_addr<<9;
CMD17[4] = (uint8)(Sd_addr >> 24);
CMD17[3] = (uint8)(Sd_addr >> 16);
CMD17[2] = (uint8)(Sd_addr >> 8);
CMD17[1] = (uint8)(Sd_addr);
SD_SSEL_CLR();
timeout=0;
do
{
timeout++;
ret=Send_CMD(CMD17,0x00);
}while((ret!=0)&&(timeout<30));
timeout=0;
do
{
timeout++;
ret=Rec_byte();
}while((ret!=0xfe)&&(timeout<100));
for(i=0;i<512;i++) //added two CRC bytes.
{
Spi_buff[i]=Rec_byte();
}
i=Rec_byte(); //receive crc
i=Rec_byte();
SD_SSEL_SET();
Send_byte(0xff);
return 0;
}
void RepowerOn()
{
uint16 i;
Sd_PowerOff();
for(i=0;i<500;i++);
Sd_PowerOn();
for(i=0;i<500;i++);
}
void SD_Init(void)
{
uint8 j;
Init_SpiBuff();
Spi_Init();
RepowerOn();
Send_Rset();
Send_CMD1(); //mmc card use.
delay_us(2);
SetMaxClk(); //开启SPI最大速率.
SD_size= Read_CSD();
// j=SD_WriteSingleBlock(5120);
SD_ReadSingleBlock(5120);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -