www.pudn.com > mtk_spi_sd.rar > MMC_SD.c


/*************************************************************/ 
/*                   SD/MMC操作函数库                        */ 
/*  环境WinAVR 20060421                                      */ 
/*  作者:Bozai(章其波)                                    */ 
/*  E-mail:sudazqb@163.com                                  */ 
/*  2006年11月26日                                           */ 
/*************************************************************/ 
/*          FAT diriver for  MiniMP3 Player                        */ 
/*                                                                 */ 
/* Platform   : MMC_SD                */ 
/*                                              */ 
/* Author     : ZHANGNU                                 */ 
/* E-mail     : zhangnu@ginwave.com                                 */ 
/* Date       : 2007-11-20                                         */ 
/* 
CID 128 Card identification number; card individual number for identification. Mandatory. 
RCA 16  Relative card address; local system address of a card, dynamically suggested by the card and approved by the host during initialization. Mandatory. 
DSR 16 Driver Stage Register; to configure the card's output drivers. Optional. 
CSD 128 Card Specific Data; information about the card operation conditions. Mandatory 
SCR 64 SD Configuration Register; information about the SD Memory Card’s Special Features capabilities. Mandatory 
OCR 32 Operation condition register. Mandatory. 
部分SD存储卡命令 Command Mnemonic Argument Reply Description  
0 (0x00) GO_IDLE_STATE none R1 Resets the SD card.           resets all cards to idle state 
2 ALL_SEND_CID         
3 0x03   SEND_RELATIVE_ADDR 
4 SET_DSR 
7 SELECT/DESELECT_CARD 
9 (0x09) SEND_CSD none R1 Sends card-specific data.  
10 (0x0a) SEND_CID none R1 Sends card identification.  
12  STOP_TRANSMISSION 
13 SEND_STATUS 
15 GO_INACTIVE_STATE 
16 SET_BLOCKLEN 
17 (0x11) READ_SINGLE_BLOCK address R1 Reads a block at byte address.  
18 READ_MULTIPLE_BLOCK 
24 (0x18) WRITE_BLOCK address R1 Writes a block at byte address.  
25 WRITE_MULTIPLE_BLOCK 
26 PROGRAM_CSD 
55 (0x37) APP_CMD none R1 Prefix for application command.  
59 (0x3b) CRC_ON_OFF Only Bit 0 R1 Argument sets CRC on (1) or off (0).  
41 (0x29) SEND_OP_COND none R1 Starts card initialization  
*/ 
/*******************************************************************/ 
 
 
 
#include "drv_comm.h" 
#include "stdio.h" 
#include "sccb.h" 
#include "med_api.h" 
#include "alerter_sw.h" 
#include "alerter_hw.h" 
#include "gpio_hw.h" 
#include "gpio_sw.h" 
#include "gpio_drv.h" 
#include "MMC_SD.h" 
 
typedef unsigned char  BYTE; 
 
const   BYTE        SD_CS_PIN   = GPIO_PORT_8;    //CS引脚定义  
const   BYTE        SD_DO_PIN   =  GPIO_PORT_4 ; 
const   BYTE        SD_CLK_PIN = GPIO_PORT_3; 
const   BYTE        SD_DIN_PIN = GPIO_PORT_9; 
 
 
extern void SPI_CS_Assert(void) 
{ 
 GPIO_InitIO(1, SD_CS_PIN); 
 GPIO_WriteIO(0,SD_CS_PIN); 
} 
 
extern void SPI_CS_Deassert(void) 
{ 
 GPIO_InitIO(1, SD_CS_PIN); 
 GPIO_WriteIO(1,SD_CS_PIN); 
} 
 
 
unsigned char DISK_CAPACITY[8]=                                  //磁盘容量//在SD初始化后会修改 
{ 
 0x00,0x0F,0x1C,0xF0, 
 0x00,0x00,0x02,0x00 
}; 
 
unsigned char SPI_ReadByte=0xff; 
//预置SD 命令CMD 
#define GO_IDLE_STATE         0x00   //resets all cards to idle state 
#define ALL_SEND_CID         0x02    //asks any card to send the CID numbers on the CMD line (any card that is connected to the host will respond) 
#define SEND_RELATIVE_ADDR         0x03  //ask the card to publish a new relativeaddress (RCA) 
#define SET_DSR  0x04    //programs the DSR of all cards 
#define SELECT_DESELECT_CARD 0x07  // 
#define SEND_CSD 0x09 //none R1 Sends card-specific data. 
#define SEND_CID  0x0a //none R1 Sends card identification 
#define STOP_TRANSMISSION 0x0c //forces the card to stop transmission 
#define SEND_STATUS 0x0e //addressed card sends its status register. 
#define GO_INACTIVE_STATE 0x0f //sets the card to inactive state in order to protect the card stack against communication breakdowns. 
#define SET_BLOCKLEN 0x10 //sets the block length 
#define SD_RxBufferSize 1920 
 
#define MMC_PRINTF dbg_print 
unsigned int  SSC_rx_lisr_tp_value=0; 
unsigned int  SSC_tx_lisr_tp_value=0; 
//收缓冲区 
unsigned char	SD_RX_buffer[SD_RxBufferSize] ; 
//read指针 
unsigned char	SD_RX_buffer_R	=	0; 
//write指针 
unsigned char	SD_RX_buffer_W	=	0; 
 
unsigned char SD_DI_hisr_PID; 
//低速模式  //spi low speed 
void SPI_Low(void) 
{ 
	//SSCBR = 0x0103; // SCLK running at 50kHz 
} 
 
//高速模式	//spi full speed 
void SPI_High(void) 
{ 
	//SSCBR = 0x000C; 		// SCLK running at 8*50K=500K (original) 
} 
 
void WDR(void) 
{} 
 
#define TICKS_PER_MSEC	5000 
void delay(kal_uint32 ms) 
{ 
	int i; 
	int j; 
 
	for (j = 0; j < ms; j++) 
	{ 
		for (i = 0; i < TICKS_PER_MSEC; i++) 
		{ 
			__asm 
			{ 
			 
				NOP 
			} 
		} 
	} 
 
} 
 
void con_DelayMs(unsigned int ms) 
{ 
 
#if 1 
	int i; 
	int j; 
 
	for (j = 0; j < ms; j++) 
	{ 
		for (i = 0; i < TICKS_PER_MSEC; i++) 
		{ 
			__asm 
			{ 
 
				NOP 
			} 
		} 
	} 
 
#else 
	//Delay(ms); 
	unsigned int i,j;  
 
	for(i = 0; i < ms; i++)  
	{  
		for(j=0;j<470;j++) 
		{ 
			__asm  
			{ 
				NOP 
			} 
		} 
	}  
#endif	 
	 
} 
/**************************************************************************************** 
* Function:.... SPI_INIT 
* Parameters: 
* Returns:...... 
* Description: 初始化spi 口 
* Created:.... zhangnu 
* Modified:.... 2007-11-02 
****************************************************************************************/ 
void  SPI_INIT(void) 
{ 
	//SD_RX_buffer[SD_RxBufferSize] =0; 
	memset(SD_RX_buffer, 0 , sizeof(SD_RX_buffer)); 
 
 
	GPIO_ModeSetup(SD_CLK_PIN,0); 
	GPIO_InitIO(1, SD_CLK_PIN); 
	GPIO_WriteIO(0,SD_CLK_PIN); 
 
	GPIO_ModeSetup(SD_CS_PIN,0); 
	GPIO_InitIO(1, SD_CS_PIN); 
	GPIO_WriteIO(0,SD_CS_PIN); 
 
	GPIO_ModeSetup(SD_DIN_PIN,0); 
	GPIO_InitIO(1, SD_DIN_PIN); 
	GPIO_WriteIO(0,SD_DIN_PIN); 
 
	GPIO_ModeSetup(SD_DO_PIN,0); 
	GPIO_InitIO(0, SD_DO_PIN); 
	GPIO_WriteIO(0,SD_DO_PIN);	 	 	 	 
 
	SPI_Low(); 
} 
//写一个字节到sd卡 
extern void SPIBYTE_write(unsigned char iodata) 
{ 
       unsigned char num,b; 
       num=0x80; 
 
	//写一个8位数据 
       for (b=0;b<0x08;b++)   
    {   
		WDR();//feed the dog 
		GPIO_WriteIO(0,SD_CLK_PIN);//sck=0     
		  
		if(iodata&num) 
		       GPIO_WriteIO(1,SD_DIN_PIN); //do=1 
		else 
		       GPIO_WriteIO(0,SD_DIN_PIN);//do=0 
 
		con_DelayMs(4);//4 
		WDR();//feed the dog 
		GPIO_WriteIO(1,SD_CLK_PIN);//sck=1 
		con_DelayMs(4);//4 
 
		if(num>0x01) 
			num=num>>1; 
     }   
} 
//读一个字节从sd卡 
extern unsigned char SPIBYTE_read(void) 
{ 
   unsigned char data,temp,b; 
   data=0; 
   temp=0; 
 
   for (b=0;b<0x08;b++) 
   { 
	WDR();//feed the dog   
	GPIO_WriteIO(0,SD_CLK_PIN);//sck=0     
	con_DelayMs(4);//4 
	WDR();//feed the dog 
 
	GPIO_WriteIO(1,SD_CLK_PIN);//sck=1 
       temp=GPIO_ReadIO(SD_DO_PIN); 
	WDR();//feed the dog 
	 
	if(temp) 
	{ 
	data|=0x01;   
	} 
	if(b<7) 
	{  
	data=data<<1;// 
	} 
	 
	con_DelayMs(4);//4 
	WDR();//feed the dog 
   }    
   return data; 
} 
//写读一个字节			//write one byte 
extern unsigned char SPI_WriteByte(unsigned char val) 
{ 
	unsigned char SSCRB; 
 
	SPIBYTE_write(val); 
 
	con_DelayMs(4); 
 
	SSCRB=SPIBYTE_read(); 
 
	return  (unsigned char)SSCRB; 
} 
 
#if 0 
/**************************************************************************************** 
* Function:.... SD_SSC_rx_lisr 
* Parameters: 
* Returns:.....  
* Description: SPI RX中断服务程序 
* Created:.... zhangnu 
* Modified:.... 2007-11-02 
****************************************************************************************/ 
OS_PROCESS(SD_SSC_rx_lisr) 
{ 
 
	RESETBIT(SSC0RIC, 6);    		// disable int 
  	RESETBIT(SSC0RIC, 7);   		//clear int request flags 
  //	PCL_37=GPIO_PIN | OUTPUT_PIN | DATA_PIN(0); 
	SSC_rx_lisr_tp_value++; 		//for test only 
 
	//如果循环队列已满,直接丢弃,@960应是足够大的缓存 
	if(((SD_RX_buffer_W + 1) % SD_RxBufferSize) == SD_RX_buffer_R)  
	{ 
        SD_RX_buffer[SD_RxBufferSize] =0; 
	}  
	else  
	{ 
		 
		SD_RX_buffer[SD_RX_buffer_W++]  =  (unsigned char)SSCRB;  
 
		SPI_ReadByte=SSCRB; 
 
		SD_RX_buffer_W %= SD_RxBufferSize; 
 
		//if(SD_RX_buffer_W % 20 == 0)	//收到6个才触发高级中断一次 
		//if(get_fsem(SD_DI_hisr_PID) < 1) 
		//{ 
		//	signal_fsem(SD_DI_hisr_PID); 
		//} 
	} 
		SETBIT(SSC0RIC, 6);   	 
	//	PCL_37=GPIO_PIN | OUTPUT_PIN | DATA_PIN(1); 
} 
 
/**************************************************************************************** 
* Function:.... SD_SSC_Tx_lisr 
* Parameters: 
* Returns:.....  
* Description: SPI RX中断服务程序 
* Created:.... zhangnu 
* Modified:.... 2007-11-02 
****************************************************************************************/ 
OS_PROCESS(SD_SSC_tx_lisr) 
{ 
 
	RESETBIT(SSC0TIC, 6);    		// disable int 
  	RESETBIT(SSC0TIC, 7);   		//clear int request flags 
  	//PCL_37=GPIO_PIN | OUTPUT_PIN | DATA_PIN(0); 
	SSC_tx_lisr_tp_value++; 		//for test only 
 
	 
	 
	//SETBIT(SSC0TIC, 6);   	 
	//PCL_37=GPIO_PIN | OUTPUT_PIN | DATA_PIN(1); 
} 
#endif 
//sd卡初始化		//sd card initialize 
extern void MMC_SD_Init(void) 
{ 
	SPI_INIT(); 
	SPI_CS_Deassert(); 
} 
 
extern int SD_main(void) 
{ 
	unsigned char i; 
	unsigned long  Cap; 
	unsigned char retry = 0; 
	 
	MMC_SD_Init(); 
	MMC_PRINTF("init sd card\n"); 
	while(MMC_SD_Reset())// retry 100 times 
	{ 
	       MMC_PRINTF("retry=%d\n",retry); 
		retry++; 
		if(retry>100)break; 
	} 
	if(retry<100)//if success 
	{ 
 
		//读SD卡容量 
		MMC_PRINTF("sd cap\n"); 
		Cap = (MMC_SD_ReadCapacity()/512)-1;//读到的是总容量,不是能寻址到的扇区地址,所以要减1处理 
		DISK_CAPACITY[0] = ((unsigned char *)(&Cap))[3];//转成大端格式 
		DISK_CAPACITY[1] = ((unsigned char *)(&Cap))[2]; 
		DISK_CAPACITY[2] = ((unsigned char*)(&Cap))[1]; 
		DISK_CAPACITY[3] = ((unsigned char *)(&Cap))[0]; 
	} 
       MMC_PRINTF("main capover\n"); 
	//while(1); 
	return 0; 
} 
 
//sd卡写命令		//sd send command 
extern unsigned char MMC_SD_SendCommand(unsigned char cmd, unsigned long arg) 
{ 
	unsigned char r1; 
	unsigned char retry=0; 
	 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
	SPI_WriteByte(0xff); 
	//con_DelayMs(10); 
 
	SPI_CS_Assert(); 
	 
	SPI_WriteByte(cmd | 0x40);//分别写入命令	//send command 
	//con_DelayMs(10); 
	SPI_WriteByte(arg>>24); 
	//con_DelayMs(10); 
	SPI_WriteByte(arg>>16); 
	//con_DelayMs(10); 
	SPI_WriteByte(arg>>8); 
	//con_DelayMs(10); 
	SPI_WriteByte(arg); 
	//con_DelayMs(10); 
	SPI_WriteByte(0x95); 
	//con_DelayMs(10); 
	 
	while((r1 = SPI_WriteByte(0xff)) == 0xff)//等待响应,	//wait response 
		{ 
	       //MMC_PRINTF("sd sendcommand ri=%x\n",r1); 
		if(retry++ > 100) break;//超时退出					//time out error 
		} 
	SPI_CS_Deassert(); 
       MMC_PRINTF("MMC_SD_SendCommand return r1=%d\n",r1); 
	return r1;//返回状态值					//return state 
} 
 
//sd卡复位		//reset sd card (software) 
extern unsigned char MMC_SD_Reset(void) 
{ 
	unsigned char i; 
	unsigned char retry; 
	unsigned char r1=0; 
	retry = 0; 
	SPI_Low(); 
       MMC_PRINTF("sd reset\n"); 
	do 
	{ 
		for(i=0;i<100;i++) SPI_WriteByte(0xff); 
		r1 = MMC_SD_SendCommand(0, 0);//发idle命令	//send idle command 
		retry++; 
		if(retry>10) return 1;//超时退出		//time out 
	} while(r1 != 0x01);	 
 
 
	retry = 0; 
	do 
	{ 
		r1 = MMC_SD_SendCommand(1, 0);//发active命令	//send active command 
		retry++; 
		if(retry>100) return 1;//超时退出		//time out 
	} while(r1); 
	SPI_High(); 
	r1 = MMC_SD_SendCommand(59, 0);//关crc		//disable CRC 
 
	r1 = MMC_SD_SendCommand(16, 512);//设扇区大小512	//set sector size to 512 
	return 0;//正常返回		//normal return 
} 
 
//读一个扇区		//read one sector 
extern unsigned char MMC_SD_ReadSingleBlock(unsigned long sector, unsigned char* buffer) 
{ 
	unsigned char r1; 
	unsigned int i; 
	unsigned char retry=0; 
 
	do 
	{ 
		r1 = MMC_SD_SendCommand(17, sector<<9);//读命令	//read command 
		retry++; 
		if(retry>10) return 1;//超时退出		//time out 
	} while(r1 != 0x00);	 
 
 
	SPI_CS_Assert(); 
	//等数据的开始	//wait to start recieve data 
	while(SPI_WriteByte(0xff) != 0xfe);//if(retry++ > 50){SPI_CS_Deassert();return 1;} 
 
	for(i=0; i<512; i++)//读512个数据	//read 512 bytes 
	{ 
		*buffer++ = SPI_WriteByte(0xff); 
	} 
 
	SPI_WriteByte(0xff);//伪crc 
	SPI_WriteByte(0xff); 
	 
	SPI_CS_Deassert(); 
 
	return 0; 
} 
 
 
//写一个扇区		//wirite one sector //not used in this application 
extern unsigned char MMC_SD_WriteSingleBlock(unsigned long sector, unsigned char* buffer) 
{ 
	unsigned char r1; 
	unsigned int i; 
	unsigned char retry=0; 
 
	do 
	{ 
		r1 = MMC_SD_SendCommand(24, sector<<9);//写命令	//send command 
		retry++; 
		if(retry>10) return 1;//超时退出		//time out 
	} while(r1 != 0x00);	 
 
 
 
	SPI_CS_Assert(); 
	 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
 
	SPI_WriteByte(0xfe);//发开始符			//send start byte 
	 
	for(i=0; i<512; i++)//送512字节数据		//send 512 bytes data 
	{ 
		SPI_WriteByte(*buffer++); 
	} 
	 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	 
	r1 = SPI_WriteByte(0xff); 
	 
	if( (r1&0x1f) != 0x05)//等待是否成功	//judge if it successful 
	{ 
		SPI_CS_Deassert(); 
		return r1; 
	} 
	//等待操作完		//wait no busy 
	while(!SPI_WriteByte(0xff));//if(retry++ > 50){SPI_CS_Deassert();return 1;} 
 
	SPI_CS_Deassert(); 
 
	return 0; 
} 
 
extern unsigned long MMC_SD_ReadCapacity(void) 
{ 
	unsigned char r1; 
	unsigned int i; 
	unsigned int temp; 
	unsigned char buffer[16]; 
	unsigned long Capacity; 
	//unsigned char retry=0; 
 
	r1 = MMC_SD_SendCommand(9, 0);//写命令	//send command  //READ CSD 
	if(r1 != 0x00) 
		return r1; 
 
	SPI_CS_Assert(); 
	while(SPI_WriteByte(0xff) != 0xfe); 
	 
	for(i=0;i<16;i++) 
	{ 
		buffer[i]=SPI_WriteByte(0xff); 
	}	 
 
	SPI_WriteByte(0xff); 
	SPI_WriteByte(0xff); 
	 
	SPI_WriteByte(0xff); 
	 
	SPI_CS_Deassert(); 
 
/*********************************/ 
//	C_SIZE 
	i = buffer[6]&0x03; 
	i<<=8; 
	i += buffer[7]; 
	i<<=2; 
	i += ((buffer[8]&0xc0)>>6); 
 
/**********************************/ 
//  C_SIZE_MULT 
 
	r1 = buffer[9]&0x03; 
	r1<<=2; 
	r1 += ((buffer[10]&0x80)>>7); 
 
 
/**********************************/ 
// BLOCKNR 
 
	r1+=2; 
 
	temp = 1; 
	while(r1) 
	{ 
		temp*=2; 
		r1--; 
	} 
	 
	Capacity = ((unsigned long)(i+1))*((unsigned long)temp); 
 
///////////////////////// 
// READ_BL_LEN 
 
	i = buffer[6]&0x0f; 
 
/*************************/ 
//BLOCK_LEN 
 
	temp = 1; 
	while(i) 
	{ 
		temp*=2; 
		i--; 
	} 
/************************/ 
 
 
/************** formula of the capacity ******************/ 
// 
//  memory capacity = BLOCKNR * BLOCK_LEN 
//	 
//	BLOCKNR = (C_SIZE + 1)* MULT 
// 
//           C_SIZE_MULT+2 
//	MULT = 2 
// 
//               READ_BL_LEN 
//	BLOCK_LEN = 2 
/**********************************************/ 
 
//The final result 
	 
	Capacity *= (unsigned long)temp;	  
	return Capacity;		 
}