//**************************************************************************************
//------------------ 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);
}
|