📄 mmc_sd.c
字号:
/*******************************************************************/
/* SD diriver for MP3 Player */
/* */
/* Platform : AVRStudio4.13 b528 + WinAVR20070525 */
/* optimize -0s */
/* Author : bozai(Zhang Qibo) */
/* E-mail : sudazqb@163.com */
/* MSN : zhangqibo_1985@hotmail.com */
/* Date : 2006-06-16 */
/*******************************************************************/
/* 20080928: modify codes for ARM platform (NXP LPC2132) */
/* 20071208: modify codes for ARM platform (AT91SAM7S256) */
/* 2007-10-21: Rewrite some function, now only suply 4 functions */
/* 2007-10-18: Adjust some time & retry count for compatibility */
/* consideration */
/* 2007-06-16: After reading the spec. in detail, I found some */
/* of the code don't meet the spec., that is after */
/* the last SPI transaction, it need an extra 8 CLK */
/* to finish it's work */
/* 2007-05-04: add read capacity function */
/* 2007-04-21: */
/* Enable some code incase that when SD reset */
/* faild program can't jump the loop */
/*******************************************************************/
#include "MMC_SD.h"
#define BYTE_MODE 0
#define BLOCK_MODE 1
static uint8 address_mode=BYTE_MODE;
#define CMD_TIMOUT 8000
#define ACCESS_TIMEOUT 0x6ffff
/* spi low speed, below 400KHz */
void SPI_Low(void)
{
SSPCPSR = 128; //2-254 偶数
#if 0
AT91PS_SPI pSPI = AT91C_BASE_SPI;
unsigned int reg;
unsigned char speed = MCK/200000; /* 200KHz, below 400KHz */
reg = pSPI->SPI_CSR[0]; /* we control the CS but not SPI , so just use default SPI_CSR0 */
reg = ( reg & ~(AT91C_SPI_SCBR) ) | ( (unsigned int)speed << 8 ); /* recaulate */
pSPI->SPI_CSR[0] = reg; /* set the value */
#endif
}
/* spi high speed, not exceed 25MHz */
void SPI_High(void)
{
SSPCPSR = 4; //2-254 偶数
#if 0
AT91PS_SPI pSPI = AT91C_BASE_SPI;
unsigned int reg;
unsigned char speed = MCK/20000000; /* 20MHz */
reg = pSPI->SPI_CSR[0]; /* we control the CS but not SPI , so just use default SPI_CSR0 */
reg = ( reg & ~(AT91C_SPI_SCBR) ) | ( (unsigned int)speed << 8 ); /* recaulate */
pSPI->SPI_CSR[0] = reg; /* set the value */
#endif
}
/* read and write one byte , full duplex */
uint8 SPI_WriteByte(uint8 val)
{
SSPDR = val;
while( (SSPSR & 0x01) == 0 ); // 等待TFE置位,即发送FIFO空
return(SSPDR);
#if 0
AT91PS_SPI pSPI = AT91C_BASE_SPI;
while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); /* transfer compl. wait */
pSPI->SPI_TDR = val;
while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); /* wait for char */
return (unsigned char)( pSPI->SPI_RDR ); /* it's important to read RDR here! */
#endif
}
/* sd send command */
uint8 MMC_SD_SendCommand(uint8 cmd, uint32 arg)
{
uint8 r1;
uint16 retry=0;
//SPI_CS_Deassert;
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_CS_Assert;
SPI_WriteByte(cmd | 0x40); /* send command */
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(0x95);
while((r1 = SPI_WriteByte(0xff)) == 0xff) /* wait response */
if(retry++ > CMD_TIMOUT) break; /* time out error */
SPI_CS_Deassert;
SPI_WriteByte(0xff); // extra 8 CLK
return r1; /* return state */
}
/* sd send command */
uint8 MMC_SD_SendCommandCRC(uint8 cmd, uint32 arg, uint8 crc)
{
uint8 r1;
uint16 retry=0;
//SPI_CS_Deassert;
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_CS_Assert;
SPI_WriteByte(cmd | 0x40); /* send command */
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(crc);
while((r1 = SPI_WriteByte(0xff)) == 0xff) /* wait response */
if(retry++ > CMD_TIMOUT) break; /* time out error */
SPI_CS_Deassert;
SPI_WriteByte(0xff); // extra 8 CLK
return r1; /* return state */
}
/* sd send command */
uint8 MMC_SD_SendCommandCRC_NoDeassert(uint8 cmd, uint32 arg, uint8 crc)
{
uint8 r1;
uint16 retry=0;
//SPI_CS_Deassert;
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_CS_Assert;
SPI_WriteByte(cmd | 0x40); /* send command */
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(crc);
while((r1 = SPI_WriteByte(0xff)) == 0xff) /* wait response */
if(retry++ > CMD_TIMOUT) break; /* time out error */
return r1; /* return state */
}
/* SD card initialization, include reset and configuration */
uint8 MMC_SD_Init(void)
{
uint8 i;
uint16 retry = 0;
uint8 r1 = 0;
// uint16 j;
uint8 buffer[4];
SPI1_CS_GPIO();
SPI1_CS_OUT();
SPI_CS_Deassert;
PINSEL1 &= ~((0x01 << 2) + (0x03 << 4) + (0x03 << 6));
PINSEL1 |= (0x02 << 2) + (0x02 << 4) + (0x02 << 6);
SSPCR0 = (0x00 << 8) | // SCR=0
(0x00 << 7) | // CPHA =0时钟输出相位,仅SPI模式有效
(0x00 << 6) | // CPOL =0时钟输出极性,仅SPI模式有效
(0x00 << 4) | // FRF =00 帧格式 00=SPI,01=SSI,10=Microwire,11=保留
(0x07 << 0); // DSS 数据长度,0000-0010=保留,0011=4位,0111=8位,1111=16位
SSPCR1 = (0x00 << 3) | // SOD 从机输出禁能,1=禁止,0=允许
(0x00 << 2) | // MS 主从选择,0=主机,1=从机
(0x01 << 1) | // SSE SSP使能,1=允许SSP与其它设备通信
(0x00 << 0); // LBM 回写模式
SSPIMSC = 0x00; // 取消所有中断使能
SSPICR = 0x00; // 中断清除寄存器
/* set SPI clock speed */
SPI_Low();
_delay_ms(100);
do
{
for(i=0;i<40;i++) SPI_WriteByte(0xff);
r1 = MMC_SD_SendCommandCRC(0, 0, 0x95);/*send idle command*/
retry++;
if(retry>CMD_TIMOUT) return 1;/*time out*/
} while(r1 != 0x01);
r1 = MMC_SD_SendCommandCRC_NoDeassert(8, 0x1aa, 0x87);/*check version*/
if(r1 == 0x05) /*version 1*/ /*if it is version 2, then it will return invalid command, that is bit 2*/
{
SPI_CS_Deassert;
SPI_WriteByte(0xff); /* extra 8 CLK */
SPI_WriteByte(0xff);
printf_P(PSTR("\r\nVersion 1"));
retry = 0;
do
{
r1 = MMC_SD_SendCommandCRC(55, 0, 0);
if(r1!=0x01)
{
printf_P(PSTR("\r\n CMD55 r1=%x "),r1);
return r1;
}
retry ++;
r1 = MMC_SD_SendCommandCRC(41, 0, 0);
}while((r1!=0)&&(retry<CMD_TIMOUT));
if (retry==CMD_TIMOUT) /*then it should be MMC card: note: not tested! */
{
printf_P(PSTR("\r\nTake it as MMC card "));
retry = 0;
do
{
r1 = MMC_SD_SendCommand(1, 0);/*send active command*/
retry++;
if(retry>CMD_TIMOUT)
{
printf_P(PSTR("\r\n Time out "));
return 1;/*time out*/
}
} while(r1);
}
SPI_High(); /* Use High Speed SPI*/
_delay_ms(1000);
#if 1
r1 = MMC_SD_SendCommand(59, 0);/*disable CRC*/
if(r1 != 0)
{
printf_P(PSTR("\r\nDisabel CRC error"));
return r1;
}
r1 = MMC_SD_SendCommand(16, 512);/*set sector size to 512*/
if(r1 != 0)
{
printf_P(PSTR("\r\nSet sector size error"));
return r1;
}
#endif
address_mode = BYTE_MODE;
}
else if(r1 == 0x01)/*version 2*/ /*it only return idle*/
{
for(i=0;i<3;i++){buffer[i]=SPI_WriteByte(0xff);printf("%x ",buffer[i]);}
//if(buffer[2]!=0xaa || ((buffer[1]&0xf)!=0x01))
//{
// printf_P(PSTR("\r\n pattern error"));
// goto exit1;
//}
SPI_CS_Deassert;
SPI_WriteByte(0xff); /* extra 8 CLK */
printf_P(PSTR("\r\nVersion 2"));
retry = 0;
do
{
r1 = MMC_SD_SendCommandCRC(55, 0, 0);
if(r1!=0x01)
{
//printf_P(PSTR("\r\n CMD55 r1=%x "),r1);
return r1;
}
r1 = MMC_SD_SendCommandCRC(41, 0x40000000, 0);
}while(r1!=0);
if(MMC_SD_SendCommandCRC_NoDeassert(58, 0, 0)!=0x00)goto exit1; /*read OCR*/
for(i=0;i<4;i++)buffer[i]=SPI_WriteByte(0xff);
if(buffer[0]&(1<<6))
address_mode = BLOCK_MODE;
else
address_mode = BYTE_MODE;
SPI_CS_Deassert;
SPI_WriteByte(0xff); /* extra 8 CLK */
SPI_High(); /* Use High Speed SPI*/
}
else
{
printf_P(PSTR("\r\nnot supported card"));
}
printf_P(PSTR("\r\naddress mode = %d"),address_mode);
return 0; /*normal return*/
exit1:
printf_P(PSTR("\r\nexit 1 r1=%x "),r1);
SPI_CS_Deassert;
SPI_WriteByte(0xff); /* extra 8 CLK */
return 1;
}
//读一个扇区 //read one sector
uint8 MMC_SD_ReadSingleBlock(uint32 sector, uint8* buffer)
{
uint8 r1;
uint16 i;
uint32 retry=0;
//SPI_High(); /* Use High Speed SPI*/
r1 = MMC_SD_SendCommandCRC_NoDeassert(17, address_mode?sector:sector<<9,0);//读命令 //read command
if(r1 != 0x00)
return r1;
SPI_CS_Assert;
//等数据的开始 //wait to start recieve data
while(SPI_WriteByte(0xff) != 0xfe)if(retry++ > ACCESS_TIMEOUT){SPI_CS_Deassert;return 1;}
for(i=0; i<512; i++)//读512个数据 //read 512 bytes
{
*buffer++ = SPI_WriteByte(0xff);
}
SPI_WriteByte(0xff);//伪crc //dummy crc
SPI_WriteByte(0xff);
SPI_CS_Deassert;
SPI_WriteByte(0xff);// extra 8 CLK
return 0;
}
//写一个扇区 //wirite one sector //not used in this application
uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8* buffer)
{
uint8 r1;
uint16 i;
uint32 retry=0;
//SPI_High(); /* Use High Speed SPI*/
r1 = MMC_SD_SendCommandCRC_NoDeassert(24, address_mode?sector:sector<<9,0);//写命令 //send command
if(r1 != 0x00)
return r1;
SPI_CS_Assert;
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xfe);//发开始符 //send start byte "token"
for(i=0; i<512; i++)//送512字节数据 //send 512 bytes data
{
SPI_WriteByte(*buffer++);
}
SPI_WriteByte(0xff); //dummy crc
SPI_WriteByte(0xff);
r1 = SPI_WriteByte(0xff);
if( (r1&0x1f) != 0x05)//等待是否成功 //judge if it successful
{
SPI_CS_Deassert;
return r1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -