⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd_spi.c

📁 收集了单片机对SD卡读写源码
💻 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 + -