//**************************************************************************************
//------------------ MMC/SD-Card Reading and Writing implementation -------------------
//FileName : mmcgcc.c
//Function : Connect AVR to MMC/SD
//Created by : Yangxiaoping
//Created date : 05/06/2006
//Version : V1.0
//Last Modified: //2006
//Filesystem : Read or Write MMC without any filesystem
//***** 配置端口 *************
//1 CS ---> PORTB.0
//2 CMD/DI ---> PORTB.2
//3 GND ---> NC(接相应的3.3V电源地)
//4 Vcc ---> NC(接3.3V电源正)
//5 CLK ---> PORTB.1
//6 GND ---> NC(接相应的3.3V电源地)
//7 DO ---> PORTB.3
//8 NC ---- 未连接
//9 NC ---- 未连接
//****************************************************************************
#include <avr/io.h>
//#include "mmcgcc.h"
//--------------------------------------------------------------
// 硬件 SPI 端口说明 ATmega128
//--------------------------------------------------------------
#define MMC_Write PORTB //SPI port register
#define MMC_Read PINB //Data PIN
#define MMC_Direction_REG DDRB //端口方向寄存器端口
#define MMC_Chip_Select 0 //-->MMC_CS_PIN
#define SPI_Clock 1 //-->MMC_CLK_PIN
#define SPI_DO 2 //-->MMC_DI_PIN
#define SPI_DI 3 //<--MMC_DO_PIN
//------------------------------------------------------------
// Error 定义
//-------------------------------------------------------------
#define INIT_CMD0_ERROR 0x01
#define INIT_CMD1_ERROR 0x02
#define WRITE_BLOCK_ERROR 0x03
#define READ_BLOCK_ERROR 0x04
//#define MMC_Disable() MMC_Write|=(1<<MMC_Chip_Select) //SD卡无效
//#define MMC_Enable() MMC_Write&=~(1<<MMC_Chip_Select) //SD卡使能
#define MMC_Disable() asm("sbi 56-0x20,0") //SD卡无效
#define MMC_Enable() asm("cbi 56-0x20,0") //SD卡使能
//****************************************************************************
// 端口初始化
//****************************************************************************
void MMC_Port_Init(void)
{
//配置端口
MMC_Direction_REG &= ~(1<<SPI_DI); //设 PORTB.3 输入
MMC_Direction_REG |= (1<<SPI_Clock); //设 PORTB.1 输出
MMC_Direction_REG |= (1<<SPI_DO); //设 PORTB.2 输出
MMC_Direction_REG |= (1<<MMC_Chip_Select); //设 PORTB.0 输出
MMC_Write |= (1<<MMC_Chip_Select); //SD卡CS脚置高,SD卡无效.
}
//****************************************************************************
//功能描述: 从 SD 读一个字节 (硬件SPI)
//输 入: 无
//输 出: 读出的一个字节
//****************************************************************************
unsigned char Read_Byte_MMC(void)
{
unsigned char Byte;
SPDR = 0xff;
while(!(SPSR & (1<<SPIF)));
Byte = SPDR;
return (Byte);
}
//****************************************************************************
//功能描述: 向 SD 发送一个字节 (硬件SPI)
//输 入: 发送的字节
//输 出: 无
//****************************************************************************
void Write_Byte_MMC(unsigned char Byte)
{
SPDR = Byte;
while(!(SPSR & (1<<SPIF)));
}
//****************************************************************************
// 功能描述: 向卡发送命令,并取得响应,返回R1
// 输 入: unsigned char *CMD 命令
// 输 出: 返回1字节的R1
//****************************************************************************
unsigned char Write_Command_MMC(unsigned char *CMD)
{
unsigned char tmp;
unsigned char retry=0;
unsigned char i;
MMC_Disable(); //SD卡无效
Write_Byte_MMC(0xFF); //送 8 Clock
MMC_Enable(); //SD卡使能
for (i=0;i<0x06;i++) //送 6 Byte 命令去SD卡
{
Write_Byte_MMC(*CMD++);
}
//get 16 bit response
Read_Byte_MMC(); //第1个字节不要.
do
{ //Only last 8 bit is used here.Read it out.
tmp = Read_Byte_MMC(); //读出8位有效回应R1
retry++;
}
while((tmp==0xff)&&(retry<100));
return(tmp);
}
//****************************************************************************
// 功能描述: 向卡发送命令,并取得响应,返回2字节的R2
// 输 入: unsigned char *CMD 命令
// unsigned char *resp 返回缓冲区2字节
// 输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char Write_Command_MMCr2(unsigned char *CMD,unsigned char *resp)
{
unsigned char tmp;
unsigned char retry=0;
unsigned char i;
MMC_Disable(); //set MMC_Chip_Select to high (MMC/SD-Card disable)
Write_Byte_MMC(0xFF); //send 8 Clock Impulse
MMC_Enable(); //set MMC_Chip_Select to low (MMC/SD-Card active)
for (i=0;i<6;i++) //send 6 Byte Command to MMC/SD-Card
{
Write_Byte_MMC(*CMD++);
}
Read_Byte_MMC(); //read the first byte,ignore it.
do
{
tmp = Read_Byte_MMC();
retry++;
}
while((tmp==0xff)&&(retry<100));
if(retry>=100)
{
MMC_Disable();
return(tmp);
}
resp[0] = tmp; //读出2字节有效回应R2
resp[1] = Read_Byte_MMC();
return(0);
}
//****************************************************************************
//功能描述: SD卡初始化 (SPI-MODE) 硬件SPI
//输 入: 无
//输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char MMC_Init(void)
{
unsigned char temp;
unsigned int retry;
unsigned char i;
unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
unsigned char out[2];
MMC_Port_Init(); //Init SPI port
for(i=0;i<200;i++) //Wait MMC/SD ready...
{
asm("nop");
}
//Enable SPI in Master Mode with IDLE low and clock at 16E6/128
//初始化SPI 为主模式,时钟速率为128分频
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);
SPSR = (0<<SPI2X);
for (i=0;i<0x0f;i++)
{
Write_Byte_MMC(0xff); //最少发送74个clock
}
retry=0; //发送命令 CMD0 to MMC/SD Card
do
{ //延时200次发送命令 CMD0 直到R1正确
temp=Write_Command_MMC(CMD);
retry++;
if(retry==200)
{ //超时
MMC_Disable();
return(INIT_CMD0_ERROR); //CMD0 Error! (0x01)
}
}
while(temp!=1); //初始化时R1第0位为1
CMD[0] = 0x48; //Command CMD8
CMD[5] = 0xFF;
retry=0;
do
{ //延时200次发送命令 CMD8 直到R1正确
temp=Write_Command_MMC(CMD);
temp=(temp&0xF7);
retry++;
if(retry==1000) //128M时为200
{ //超时
MMC_Disable();
return(temp); //CMD1 Error! (0x02)
}
}
while((temp!=5)&&(temp!=1));
if (temp == 5) //v1.0卡
{
SD_Card = 1;
retry=0;
do
{
CMD[0] = 0x40+55; //Command CMD55
CMD[5] = 0xFF;
temp=Write_Command_MMC(CMD);
CMD[0] = 0x40+41;
CMD[1] = 0x40;
CMD[5] = 0xFF;
temp=Write_Command_MMC(CMD);
retry++;
if(retry==1000) //128M时为200
{ //超时
MMC_Disable();
return(temp); //CMD1 Error! (0x02)
}
}
while(temp!=0); //R1为0正常
}
if (temp == 1) //v2.0卡
{
SD_Card = 2;
retry=0;
do
{
CMD[0] = 0x40+55; //Command CMD55
CMD[5] = 0xFF;
temp=Write_Command_MMC(CMD);
CMD[0] = 0x40+41;
CMD[1] = 0x40;
CMD[5] = 0xFF;
temp=Write_Command_MMC(CMD);
retry++;
if(retry==1000) //128M时为200
{ //超时
MMC_Disable();
return(temp); //CMD1 Error! (0x02)
}
}
while(temp!=0); //R1为0正常
CMD[0] = 0x40+58; //Command CMD58
CMD[5] = 0xFF;
Write_Command_MMCr2(CMD,out);
if((out[1]&0x40)==0) // 如果返回CCS不等于1则为标准卡,若等于1则为高速卡
{
SD_Card = 1;
}
}
// 设置 SPI 为全速
SPCR = SPCR|(0<<SPR0)|(0<<SPR1);
SPSR = SPSR|(1<<SPI2X); //fosc/2
// SPSR &= ~(1<<SPI2X); //fosc/4
MMC_Disable(); //SD卡无效
return(0); //All commands have been taken.
}
//****************************************************************************
//功能描述: 从SD卡中读多个字节
//输 入: unsigned char *CMD 命令
// unsigned char *Buffer 接收缓冲区
// unsigned int Bytes 接收的字节数
//输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char MMC_Read_Block(unsigned char *CMD,unsigned char *Buffer,unsigned int Bytes)
{
unsigned char retry,temp;
unsigned int i;
//Send Command CMD to MMC/SD-Card
retry=0;
do
{ //Retry 100 times to send command.
temp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(READ_BLOCK_ERROR); //block write Error!
}
}
while(temp!=0);
//Read Start Byte form MMC/SD-Card (FEh/Start Byte)
while (Read_Byte_MMC() != 0xfe){}; //读数据开始令牌
for (i=0;i<Bytes;i++)
{
*Buffer++ = Read_Byte_MMC();
}
Read_Byte_MMC(); //CRC - Byte
Read_Byte_MMC(); //CRC - Byte
MMC_Disable(); //set MMC_Chip_Select to high (MMC/SD-Card invalid)
return(0);
}
//***************************************************************************
//功能描述: 从SD卡中读CID
//输 入: unsigned char *Buffer 接收缓冲区16字节
//输 出: 0: 正确 >0: 错误码
//***************************************************************************
unsigned char Read_CID_MMC(unsigned char *Buffer)
{
unsigned char CMD[] = {0x4A,0x00,0x00,0x00,0x00,0xFF};
unsigned char temp;
temp=MMC_Read_Block(CMD,Buffer,16); //read 16 bytes
return(temp);
}
//***************************************************************************
//功能描述: 从SD卡中读CSD
//输 入: unsigned char *Buffer 接收缓冲区16字节
//输 出: 0: 正确 >0: 错误码
//***************************************************************************
unsigned char Read_CSD_MMC(unsigned char *Buffer)
{
unsigned char CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};
unsigned char temp;
temp=MMC_Read_Block(CMD,Buffer,16); //read 16 bytes
return(temp);
}
//****************************************************************************
//功能描述: 从SD卡中读1个块
//输 入: unsigned long addr: 块地址
// unsigned char *Buffer : 接收缓冲区,每块512字节
//输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char MMC_read_sector(unsigned long addr,unsigned char *Buffer)
{
unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
unsigned char temp;
//Address conversation(logic block address-->byte address)
if (SD_Card==1)
{
addr = addr << 9; //addr = addr * 512
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
}
if (SD_Card==2)
{
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
CMD[4] = (addr & 0x000000FF) ;
}
temp=MMC_Read_Block(CMD,Buffer,512);
return(temp);
}
//********************************************************************************************************************
// 函数名称: unsigned char MMC_ReadMultiBlock()
// 功能描述: 从SD卡中读多个块
// 输 入: unsigned long addr: 块地址
// unsigned long blocknum : 块数量
// unsigned char *Buffer : 接收缓冲区
// 输 出: 0: 正确 >0: 错误码
//*********************************************************************************************************************
unsigned char MMC_ReadMultiBlock(unsigned long addr, unsigned long blocknum, unsigned char *Buffer)
{
unsigned char CMD[] = {0x52,0x00,0x00,0x00,0x00,0xFF};
unsigned char temp,retry;
unsigned int j;
unsigned long i;
// asm("cli");
if (SD_Card==1)
{
addr = addr << 9; //addr = addr * 512
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
}
if (SD_Card==2)
{
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
CMD[4] = (addr & 0x000000FF) ;
}
retry=0;
do
{ //Retry 100 times to send command.
temp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(temp); //send commamd Error!
}
}
while(temp!=0);
for(i=0; i<blocknum; i++)
{
while (Read_Byte_MMC() != 0xfe){};
for (j=0;j<512;j++)
{
*Buffer++ = Read_Byte_MMC();
}
Read_Byte_MMC(); //CRC - Byte
Read_Byte_MMC(); //CRC - Byte
}
CMD[0]=0x4c;
CMD[1]=0x00;
CMD[2]=0x00;
CMD[3]=0x00;
do
{ //Retry 100 times to send command.
temp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(temp); //send commamd Error!
}
}
while(temp!=0);
MMC_Disable();
// asm("sei");
return(temp);
}
//********************************************************************************************************************
// 函数名称: MMC_GetNumWRBlcoks()
// 功能描述: 得到正确写入的块数
// 输 入: *blocknum: 返回的块数
// 输 出: 0: 正确 >0: 错误码
//*******************************************************************************************************************
unsigned char MMC_GetNumWRBlcoks(unsigned long *blocknum)
{
unsigned char tmp,retry;
unsigned char CMD[] = {0x77,0x00,0x00,0x00,0x00,0xFF};
unsigned char Buffer[4];
retry=0;
do
{ //Retry 100 times to send command.
tmp=Write_Command_MMC(CMD); // CMD55 ; R1 后续命令为一个应用命令
retry++;
if(retry==100)
{
return(tmp); //send commamd Error!
}
}
while(tmp!=0);
CMD[0] = 0x56; // ACMD22 ; R1
tmp=MMC_Read_Block(CMD,Buffer,4);
if(tmp!=0)
{
return(tmp); //send commamd Error!
}
*blocknum = ((unsigned long)Buffer[0] << 24) + ((unsigned long)Buffer[1] << 16) + ((unsigned long)Buffer[2] << 8) + Buffer[3];
return(0);
}
//****************************************************************************
//功能描述: 向SD卡中写入一个块
//输 入: unsigned long addr: 块地址
// unsigned char *Buffer: 发送缓冲区每块512字节
//输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char MMC_write_sector(unsigned long addr,unsigned char *Buffer)
{
unsigned char tmp,retry;
unsigned int i;
unsigned char CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};
unsigned char R2[2];
if (SD_Card==1)
{
addr = addr << 9; //addr = addr * 512
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
}
if (SD_Card==2)
{
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
CMD[4] = (addr & 0x000000FF) ;
}
//Send Command CMD24 to MMC/SD-Card
retry=0;
do
{ //Retry 100 times to send command.
tmp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(tmp); //send commamd Error!
}
}
while(tmp!=0);
for (i=0;i<100;i++) //Before writing,send 100 clock to MMC/SD-Card
{
Read_Byte_MMC();
}
Write_Byte_MMC(0xFE); //Send Start Byte to MMC/SD-Card
for (i=0;i<512;i++) //Now send real data Bolck (512Bytes) to MMC/SD-Card
{
Write_Byte_MMC(*Buffer++); //send 512 bytes to Card
}
//CRC-Byte
Write_Byte_MMC(0xFF); //Dummy CRC
Write_Byte_MMC(0xFF); //CRC Code
tmp=Read_Byte_MMC(); // read response
if((tmp & 0x1F)!=0x05) // data block accepted ?
{
MMC_Disable();
return(WRITE_BLOCK_ERROR); //Error!
}
while (Read_Byte_MMC()!=0xff){}; //Wait till MMC/SD-Card is not busy
CMD[0]= 0x4d; //CMD13 ; R2
CMD[1]= 0x00;
CMD[2]= 0x00;
CMD[3]= 0x00;
do
{
tmp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(tmp); //send commamd Error!
}
}
while(tmp!=0);
if((R2[0] != 0) || (R2[1] != 0)) //返回R1,R2都不为0
{
MMC_Disable();
return(WRITE_BLOCK_ERROR); //Error!
}
MMC_Disable();
return(0);
}
//****************************************************************************
//功能描述: 向SD卡中写入多个块
//输 入: unsigned long addr: 块地址
// unsigned long blocknum: 块数
// unsigned char *Buffer: 发送缓冲区
//输 出: 0: 正确 >0: 错误码
//****************************************************************************
unsigned char MMC_WriteMultiBlock(unsigned long addr, unsigned long blocknum, unsigned char *Buffer)
{
unsigned char CMD[] = {0x59,0x00,0x00,0x00,0x00,0xFF};
unsigned char tmp,retry;
unsigned int j;
unsigned long i;
if (SD_Card==1)
{
addr = addr << 9; //addr = addr * 512
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
}
if (SD_Card==2)
{
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
CMD[4] = (addr & 0x000000FF) ;
}
retry=0;
do
{ //Retry 100 times to send command.
tmp=Write_Command_MMC(CMD);
retry++;
if(retry==100)
{
MMC_Disable();
return(tmp); //send commamd Error!
}
}
while(tmp!=0);
for (i=0;i<100;i++) //Before writing,send 100 clock to MMC/SD-Card
{
Read_Byte_MMC();
}
for(i=0; i<blocknum; i++)
{
Write_Byte_MMC(0xFC); //Send Start Byte to MMC/SD-Card
for (j=0;j<512;j++) //Now send real data Bolck (512Bytes)
{
Write_Byte_MMC(*Buffer++); //send 512 bytes to Card
}
Write_Byte_MMC(0xFF); //CRC
Write_Byte_MMC(0xFF); //CRC
tmp=Read_Byte_MMC(); // read response
if((tmp & 0x1F)!=0x05) // data block accepted
{
MMC_Disable();
return(WRITE_BLOCK_ERROR); //Error!
}
while (Read_Byte_MMC()!=0xff){}; //Wait till MMC/SD-Card is not busy
}
Write_Byte_MMC(0xff); //
Write_Byte_MMC(0xfd); //发送数据停止令牌
while (Read_Byte_MMC()!=0xff){}; //Wait till MMC/SD-Card is not busy
tmp = MMC_GetNumWRBlcoks(&i); //读正确写入的块数
if(tmp != 0)
{
MMC_Disable();
return(tmp); //Error!
}
if(i != blocknum)
{
MMC_Disable();
return(WRITE_BLOCK_ERROR); //正确写入块数错误
}
MMC_Disable();
return(0);
}
|