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

📄 spi_mmc.c

📁 KEIL单片机有关知识,对想学此系列单偏机的朋友应该有用的哦
💻 C
字号:
/*-------------------------------------------------------------------------------------------
* Name: SPI_MMC.C
* Purpose: SD卡接口部分程序
* Version: V1.00
*------------------------------------------------------------------------------------------*/
#include "config.h"
#include "spi_mmc.h"

uint8 MMCCmd[MMC_CMD_SIZE];						//状态
uint8 MMCStatus = 0;

/**************************************SPI相关函数******************************************/

/*SPI初始化函数*/
void SPI_Init( void )
{
	uint32 portConfig;
	uint8 i,Dummy;

	//相关引脚连接定义 
	//P0.17--SCK1 P0.18--MISO1 P0.19--MOSI1 P0.20 SSEL1 CS1
	SSPCR1 = 0x00; 								//正常工作 主机模式 SSP禁能
	portConfig = PINSEL1;
	PINSEL1 = portConfig | 0x02A8;	  			//定义相关引脚为SPI模式
	IO0DIR = SPI_SEL; 							//SSEL输出
	IO0DIR = SPI_PWR;
	IO0SET = SPI_SEL;							//SSEL置高
	IO0SET = SPI_PWR;
	for(i = 0; i <100; i++);
	
	IO0CLR = SPI_PWR;
											//设置PCLK为1/2的CCLK
	VPBDIV = 0x02;								//10-->1/2
//	SSPCR0 = 0x0F07;							//0111->8位 00->SPI格式 CPOL:CPHA0->00 SCR->15
	SSPCR0 = 0x0707;							//0111->8位 00->SPI格式 CPOL:CPHA0->00 SCR->7	
	SSPCPSR = 0x02;								//SSP在主控模式下操作SSPCPSR最小为2	
	SSPCR1 = 0x02;								//正常工作 主机模式	SSP使能
	
	for ( i = 0; i < 8; i++ )
	{
		Dummy = SSPDR; 							//清空收缓冲区
	}
	return;
}
/*******************************************************************************************/

/*SPI发送函数*/
void SPI_Send( uint8 *buf, uint32 Length )
{
//	uint8 Dummy;
	
	if ( Length == 0 )
	return;
	while (!(SSPSR & 0x02));
	while ( Length != 0 )
	{												
	//	while (!(SSPSR & 0x02));			//TNF位 发送缓冲区未满
		SSPDR = *buf;							//数据寄存器
												
		while (!(SSPSR & 0x01));				//等待总线空闲
//		Dummy = SSPDR; 							//清空收缓冲区
		Length--;
		buf++;
	}
	return;
}
/*******************************************************************************************/

/*SPI接收函数*/
void SPI_Receive( uint8 *buf, uint32 Length )
{
	uint32 i;
	
	for ( i = 0; i < Length; i++ )
	{
		*buf = SPI_ReceiveByte();
		buf++;
	}
	return;
}
/*******************************************************************************************/

/*SPI字节接收函数*/
uint8 SPI_ReceiveByte( void )
{
	uint8 data;
	
	while (!(SSPSR & 0x02));
				//TNF位 发送缓冲区满																		
	SSPDR = 0xFF;								//虚写 产生时钟信号 从MISO独数据
	while (!(SSPSR & 0x04));						//等待总线空闲
	data = SSPDR;								//数据寄存器
	
return ( data );
}

/*******************************************************************************************/



/*************************************SD卡相关函数******************************************/

/*SD卡初始化*/
int mmc_init()
{
	uint32 i;
	uint8 Ini[10];
												
	MMCStatus = 0;
	IO0SET = SPI_SEL; 							//SSEL CS位->1
												//初始化SD卡 进入SPI模式 80个时钟周期												
	for(i=0; i<10; i++)							//MMCRDData做临时发送缓冲区
	{
		Ini[i] = 0xFF;					//8X10=80
	}
	SPI_Send( Ini, 10 );

	IO0CLR = SPI_SEL; 							//SSEL CS位->0
	MMCCmd[0] = 0x40;							//发送CMD0
	MMCCmd[1] = 0x00;							//卡设置为空闲状态
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0x95;
	SPI_Send( MMCCmd, MMC_CMD_SIZE );
	if( mmc_response(0x01) == 1 )
	{
		MMCStatus = IDLE_STATE_TIMEOUT;			//超时
		IO0SET = SPI_SEL;						//SSEL CS->1
		return MMCStatus;
	}
												//发送几个时钟
	IO0SET = SPI_SEL; 							//SSEL CS->1
	SPI_ReceiveByte();

	IO0CLR = SPI_SEL; 							//SSEL CS->0												
	i = MAX_TIMEOUT;							//持续发送CMD1 直到响应0x00
	do
	{											//发送CMD1
		MMCCmd[0] = 0x41;
		MMCCmd[1] = 0x00;
		MMCCmd[2] = 0x00;
		MMCCmd[3] = 0x00;
		MMCCmd[4] = 0x00;
		MMCCmd[5] = 0xFF;
		SPI_Send( MMCCmd, MMC_CMD_SIZE );
		
		i--;
	} while ( (mmc_response(0x00) != 0) && (i>0) );
	
	if ( i == 0 )								//超时
	{
		MMCStatus = OP_COND_TIMEOUT;
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}

	IO0SET = SPI_SEL; 							//发送几个时钟
	SPI_ReceiveByte();

	IO0CLR = SPI_SEL; 							//SSEL CS->0	
	MMCCmd[0] = 0x77;						   	//发送CDM16 设置块长度
	MMCCmd[1] = 0x00; 							//0x0020->512B
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd, MMC_CMD_SIZE );
	if( (mmc_response(0x00))==1 )
	{
		MMCStatus = 28;		//超时
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	IO0SET = SPI_SEL;							//发送几个时钟
	SPI_ReceiveByte();
	
	IO0CLR = SPI_SEL; 							//SSEL CS->0	
	MMCCmd[0] = 0x69;						   	//发送CDM16 设置块长度
	MMCCmd[1] = 0x00; 							//0x0020->512B
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd, MMC_CMD_SIZE );
	if( (mmc_response(0x00))==1 )
	{
		MMCStatus = 29;		//超时
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	IO0SET = SPI_SEL;							//发送几个时钟
	SPI_ReceiveByte();

	IO0CLR = SPI_SEL; 							//SSEL CS->0	
	MMCCmd[0] = 0x50;						   	//??CDM16 ?????
	MMCCmd[1] = 0x00; 							//0x5000->512B
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x02;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd, MMC_CMD_SIZE );
	if( (mmc_response(0x00))==1 )
	{
		MMCStatus = 66;		//??
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	IO0SET = SPI_SEL;							//??????
	SPI_ReceiveByte();
	
	return 0;
}
/*******************************************************************************************/

/*SD卡块写入函数*/
int mmc_write_block(uint32 block_number,uint8 buf[512])
{
	uint8 Status;
	uint16 cc;

	block_number+=39;
	block_number=block_number<<9;				//block_number*512

	IO0CLR = SPI_SEL; 							//SSEL CS->0	
												
	MMCCmd[0] = 0x58;							//发送CMD24 块写入操作
	MMCCmd[1] = (block_number & 0xFF000000) >>24;
	MMCCmd[2] = (block_number & 0x00FF0000) >>16;					//块地址高位
	MMCCmd[3] = (block_number & 0x0000FF00) >>8;
	MMCCmd[4] = 0x00;					//块地址低位
	MMCCmd[5] = 0xFF;
	SPI_Send(MMCCmd, MMC_CMD_SIZE );
	if((mmc_response(0x00))==1)
	{
		MMCStatus = WRITE_BLOCK_TIMEOUT;		//超时
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	
	MMCCmd[0] = 0xFF;
	MMCCmd[1] = 0xFF;
	MMCCmd[2] = 0xFE;
	SPI_Send( MMCCmd, 3 );						//数据起始
	SPI_Send( buf, MMC_DATA_SIZE );		//写数据
	MMCCmd[0] = 0xFF;
	MMCCmd[1] = 0xFF;	
	SPI_Send( MMCCmd,2 );
	do
	{
		Status=SPI_ReceiveByte();
	}
	while(Status==0xFF);		
	if ( (Status & 0x0F) != 0x05 )
	{
		MMCStatus = WRITE_BLOCK_FAIL;			//写入失败
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	cc=2000;
	while(cc--);
	while((SPI_ReceiveByte())!=0xFF);

	IO0SET = SPI_SEL; 							//发送几个时钟
	SPI_ReceiveByte();
	return 0;
}

/*SD卡读数据*/
int mmc_read_block(uint32 block_number,uint8 buf[512])
{
	uint8 Checksum;
	
	block_number+=39;
	block_number=block_number<<9;				//block_number*512
	IO0CLR = SPI_SEL; 							//SSEL CS->0

	MMCCmd[0] = 0x51;							//发送CMD17 读数
	MMCCmd[1] = (block_number & 0xFF000000) >>24;
	MMCCmd[2] = (block_number & 0x00FF0000) >>16;					//块地址高位
	MMCCmd[3] = (block_number & 0x0000FF00) >>8;
	MMCCmd[4] = 0x00;					//块地址低位
	MMCCmd[5] = 0xFF;
	SPI_Send(MMCCmd, MMC_CMD_SIZE );
	SPI_ReceiveByte();
	if((mmc_response(0x00))==1)
	{
		MMCStatus = 30;
		IO0SET = SPI_SEL;						//令牌丢失 SSEL CS->1
		return MMCStatus;
	}
	if((mmc_response(0xFE))==1)
	{											//令牌
		MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
		IO0SET = SPI_SEL;						//令牌丢失 SSEL CS->1
		return MMCStatus;
	}
	SPI_Receive( buf, MMC_DATA_SIZE );
	Checksum = SPI_ReceiveByte();				//和校验
	Checksum = Checksum << 0x08 | SPI_ReceiveByte();
	IO0SET = SPI_SEL; 							//SSEL CS->1
	SPI_ReceiveByte();
	return 	0;
}
/*******************************************************************************************/

/*SD卡响应函数*/
int mmc_response( uint8 response)
{
	uint32 count = 0xFFFF;
	uint8 result;
	
	while( count > 0 )
	{
		result = SPI_ReceiveByte();		   		//接收数据
		if ( result == response )
		{
			break;
		}
		count--;
	}
	if ( count == 0 )
		return 1; 								//超时无响应
	else
		return 0; 								//正常响应
}
/*******************************************************************************************/

/*SD卡读数据*/
int mmc_read_state(uint8 st[1])
{			
	IO0CLR = SPI_SEL; 							//SSEL CS->0	
	MMCCmd[0] = 0x4D;						   	
	MMCCmd[1] = 0x00; 							
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd, MMC_CMD_SIZE );

	if( (mmc_response(0x00))==1 )
	{
		MMCStatus = 23;		//超时
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}

	SPI_Receive( st, 1 );
	
	IO0SET = SPI_SEL;							//发送几个时钟
	SPI_ReceiveByte();
	
	return 0;
}
/*******************************************************************************************/

/*SD卡读数据*/
int mmc_read_csd(uint8 reg[16])
{
	uint16 Checksum;
	
	IO0CLR = SPI_SEL; 
	MMCCmd[0] = 0x49;							
	MMCCmd[1] = 0x00;
	MMCCmd[2] = 0x00;					
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;					
	MMCCmd[5] = 0xFF;
	SPI_Send(MMCCmd, MMC_CMD_SIZE );
	if((mmc_response(0x00))==1)
	{
		MMCStatus = READ_BLOCK_TIMEOUT;			//超时
		IO0SET = SPI_SEL; 						//SSEL CS->1
		return MMCStatus;
	}
	if((mmc_response(0xFE))==1)
	{											//令牌
		MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
		IO0SET = SPI_SEL;						//令牌丢失 SSEL CS->1
		return MMCStatus;
	}
	
	SPI_Receive( reg, 16 );
	Checksum = SPI_ReceiveByte();				//和校验
	Checksum = Checksum << 0x08 | SPI_ReceiveByte();
	IO0SET = SPI_SEL; 							//SSEL CS->1
	SPI_ReceiveByte();
	return 0;
}
/*******************************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -