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

📄 sd.c

📁 SD卡驱动程序,用于ARM7单片机,完全能用
💻 C
📖 第 1 页 / 共 4 页
字号:
}



/************************************************************************
函数名称: void SD_SPIDelay()						
** 功能描述: SPI总线延时							 
** 输   入: INT8U value: 延时值,不超过255		    
** 输   出: 无										
*************************************************************************/
void SD_SPIDelay(int value)
{
    int i;

    for (i = 0; i < value; i++)
        SPI_SendByte(0xFF);						 	/* 发送0xFF clock out 0xFF */
}




/**************************************************************************
** 函数名称: void SD_Power()					
** 功能描述: 对卡先下电,再上电					
** 输   入: 无									
** 输   出: 无									
****************************************************************************/
void SD_Power(void)
{
	int i;
	PINSEL0 &= ~(0x03 << 8);				/* 设置 SCK 口为GPIO口 */
	IODIR |= SPI_SCK;						/* 设置 SCK 口为输出口 */
	IOCLR = SPI_SCK;						/* 置 SCK 为低电平 */
	
	
	PINSEL0 &= ~(0x03 << 10);				/* 设置 MISO 口为GPIO口 */
	IODIR |= SPI_MISO;						/* 设置 MISO 口为输出口 */
	IOCLR = SPI_MISO;						/* 置 MISO 为低电平 */
	
	
	PINSEL0 &= ~(0x03 << 12);				/* 设置 MOSI 口为GPIO口 */
	IODIR |= SPI_MOSI;						/* 设置 MOSI 口为输出口 */
	IOCLR = SPI_MOSI;						/* 置 MISO 为低电平 */
	
	
	PINSEL0 &= ~(0x03 << 20);		 		/* 设置 CS 口为GPIO口 */
	IODIR |= SPI_CS;			 			/* 设置 CS 口为输出口 */
	IOCLR |= SPI_CS;						/* 置 CS 为低电平 */
	
	for(i = 0; i < 0x9000; i++);	
	
}




/****************************************************************************
** 函数名称: void SD_HardWareInit()				
** 功能描述: 初始化访问SD卡的硬件条件			
** 输   入: 无									
** 输   出: 无									
*****************************************************************************/
void SD_HardWareInit(void)
{
	SD_Power();
	
	
	PINSEL0 &= ~((0x03 << 8) + (0x03 << 10) + (0x03 << 12) + (0x03 << 14));
	PINSEL0 |= (0x01 << 8) + (0x01 << 10) + (0x01 << 12) + (0x01 << 14);
	
	
	SD_INSERT_GPIO();
	SD_INSERT_IN();	
	
	
	SD_WP_GPIO();								
	SD_WP_IN();	
	
	S0SPCCR = 128;    						/* 设置SPI时钟分频值为128 */
	
	S0SPCR  = (0 << 3) |				// CPHA = 0, 数据在SCK 的第一个时钟沿采样
 			 (1 << 4) |				// CPOL = 1, SCK 为低有效
 			 (1 << 5) |				// MSTR = 1, SPI 处于主模式
 			 (0 << 6) |				// LSBF = 0, SPI 数据传输MSB (位7)在先
 			 (0 << 7);				// SPIE = 0, SPI 中断被禁止
	
}


/***********************************************************
** 函数名称: void SPI_ClkToMax()				
** 功能描述: 设置SPI的clock到最大值				
** 输   入: 无									
** 输   出: 无									
************************************************************/
void SPI_ClkToMax(void)
{
	S0SPCCR = 8;								/* 设置SPI时钟分频值为8  Set the value of dividing frequency to 8 */
}



/*****************************************************************************
** 函数名称: void SPI_CS_Assert()				
** 功能描述: 片选SPI从机						 
** 输   入: 无									
** 输   出: 无									
******************************************************************************/
void SPI_CS_Assert(void)
{
	SPI_CS_CLR();			   					/* 片选SPI从机  select the SPI slave */  
}



/**********************************************************************
** 函数名称: void SPI_CS_Deassert()				
** 功能描述: 不片选SPI从机						 
** 输   入: 无									
** 输   出: 无									
**************************************************************************/
void SPI_CS_Deassert(void)
{
	SPI_CS_SET();			    				/* 不片选SPI从机  not select the SPI slave */
}



/*************************************************************************
** 函数名称: INT8U SD_SendCmd()						
** 功能描述: 向卡发送命令,并取得响应				
** 输   入: INT8U cmd	    : 命令字				
			 INT8U *param	: 命令参数,长度为4字节			    
			 INT8U resptype : 响应类型						  
			 INT8U *resp	: 响应,长度为1-5字节			  
** 输   出: 0:   正确    >0:   错误码		  		Output:	  0:  right		>0:  error code
*************************************************************************/
unsigned char SD_SendCmd(unsigned char cmd, unsigned char *param, unsigned char resptype, unsigned char *resp)
{
	int i,rlen;
	unsigned char tmp;
		
	SPI_CS_Assert();
	
	
	SPI_SendByte((cmd & 0x3F) | 0x40);				 /* 发送命令头和命令字 send command header and word */
	
	for (i = 0; i < 4; i++)
        SPI_SendByte(param[i]);						 /* 发送参数 send parameters */
	
	#if SD_CRC_EN
		tmp = SD_GetCmdByte6((cmd & 0x3F) | 0x40, param);
		SPI_SendByte(tmp);
	#else
    	SPI_SendByte(0x95);							 	 /* CRC校验码,只用于第1个命令 CRC,only used for the first command */
	#endif 
	
	rlen = 0;
    switch (resptype)								 	/* 根据不同的命令,得到不同的响应长度 */
    {												 	/* according various command,get the various response length */
  		case R1:
   	 	case R1B: rlen = 1;  break;
       		 
    	case R2:  rlen = 2;	 break;
       		 
   		case R3:  rlen = 5;	 break;
       		 
    	default:  SPI_SendByte(0xFF);	
      		      SPI_CS_Deassert();						 
        	      return SD_ERR_CMD_RESPTYPE;		 						/* 返回命令响应类型错误 return error of command response type */
    }
	i = 0;				
    do 												 	/* 等待响应,响应的开始位为0 */
    {												 	/* Wait for a response,a response is a start bit(zero) */ 
        tmp = SPI_RecByte();
        i++;
    }while (((tmp & 0x80) != 0) && (i < SD_CMD_TIMEOUT));
	
	
	if (i >= SD_CMD_TIMEOUT)
    {												 
        SPI_CS_Deassert();
        return SD_ERR_CMD_TIMEOUT;					 					/* 返回命令超时 return response timeout of command */
    }
    
    for (i = rlen - 1; i >= 0; i--)
    {
        resp[i] = tmp;
        tmp = SPI_RecByte();					 	 	/* 循环的最后发送8clock  at the last recycle,clock out 8 clock */
    }
      
    SPI_CS_Deassert();
//	Uart0_SendByte(0xc1);
	return SD_NO_ERR;	
}
/**********************************************************************
** 函数名称: INT8U SD_ResetSD()						
** 功能描述: 复位SD/MMC卡							
** 输   入: 无										
** 输   出: 0:   正确    >0:   错误码		  		
**********************************************************************/
unsigned char SD_ResetSD(void)
{
	unsigned char param[4] = {0,0,0,0},resp;
	
    return (SD_SendCmd(CMD0, param, CMD0_R, &resp));	/* 复位命令 command that reset card */
}



/**********************************************************************
** 函数名称: INT8U SD_ActiveInit()				
** 功能描述: 激活卡,并获得卡型					
** 输   入: 无								 	
** 输    出: 0:   成功    >0:  错误码		
** 函数说明: 该命令不断重复发送到SD卡,直到响应R1的Bit0(Idle)位为0,表示SD卡内部初始化处理完成。
		     当响应的Idle位为0时,SD卡就完全进入SPI模式了。当然重复发送命令CMD1是有次数限制的,
		     最大次数为宏定义SD_IDLE_WAIT_MAX.
***********************************************************************/
unsigned char SD_ActiveInit(void)
{
	unsigned char param[4] = {0,0,0,0},resp[5],ret;
	unsigned int i = 0;
	do 
    {														/* 发出CMD1, 查询卡的状态, send CMD1 to poll card status */
        ret = SD_SendCmd(CMD1, param, CMD1_R, resp);
        if (ret != SD_NO_ERR)
		{
       		return ret;
		}
        i ++;
    }while (((resp[0] & MSK_IDLE) == MSK_IDLE) && (i <= SD_IDLE_WAIT_MAX));
	
	if (i >= SD_IDLE_WAIT_MAX)
	{
       return SD_ERR_TIMEOUT_WAITIDLE;						/* 超时,返回错误 time out,return error */
	}
	
	ret = SD_SendCmd(CMD55, param, CMD55_R, resp);			/* 禁止下一个命令为应用命令  Flag that the next command is application-specific */
    if (ret != SD_NO_ERR)
	{
       	return ret;
	}
	
	
	ret = SD_SendCmd(ACMD41, param, ACMD41_R, resp);		/* 激活内部初始化命令 active card to initialize process internal */
    if (ret != SD_NO_ERR)
	{	
		return SD_ERR_UNKNOWN_CARD;
	}
		
	
	if ((resp[0] & 0xFE) == 0)
	{
      	sds.card_type = CARDTYPE_SD;						/* 是SD卡 the card is SD card */	
    }
	else
	{	
    	sds.card_type = CARDTYPE_MMC;						/* 是MMC卡 the card is MMC card */
	}	
	
		
	
	
	
	return SD_NO_ERR;
}



/***************************************************************
** 函数名称: INT8U SD_ReadOCR()						
** 功能描述: 读操作条件寄存器OCR					
** 输   入: INT8U ocrlen  : 寄存器长度(固定为4)	
			 INT8U *recbuf : 接收缓冲区				
** 输   出: 0:   正确    >0:   错误码		  		
**************************************************************/
unsigned char SD_ReadOCR(unsigned char ocrlen, unsigned char *recbuf)
{
	unsigned char param[4] = {0,0,0,0},resp[5],tmp;
	
	tmp = SD_SendCmd(CMD58, param, CMD58_R, resp);		/* 读 OCR 寄存器命令 */
    if (tmp != SD_NO_ERR)								/* read OCR register command */
	{
    	return tmp;	
	}
	
	
	if (resp[0] != 0)
	{
        return SD_ERR_CMD_RESP;			 				/* 响应错误 response is error */
    }
	
	
    for (tmp = 0; tmp < 4; tmp++)
	{
    	recbuf[tmp] = resp[tmp + 1];					/* 复制OCR寄存器内容到接收缓冲区 */
	}
	return SD_NO_ERR;
}



/*******************************************************************
** 函数名称: INT8U SD_ReadRegister()				
** 功能描述: 从SD卡读取寄存器数据					
** 输   入: INT32U len	  : 长度					
			 INT8U *recbuf: 接收缓冲区				
** 输   出: 0:   正确    >0:   错误码		  		
*********************************************************************/
unsigned char SD_ReadRegister(unsigned int len, unsigned char *recbuf)
{
	unsigned int i = 0;
	unsigned char resp;
	SPI_CS_Assert();
    do{    											/* 等待数据起始令牌 wait for data start token */
        resp = SPI_RecByte();
    	i++;
    }while((resp == 0xFF) && (i < SD_READREG_TIMEOUT));    
    
    if (i >= SD_READREG_TIMEOUT)
    {
    	SPI_CS_Deassert();
    	return SD_ERR_TIMEOUT_READ;					/* 超时, 返回错误 timeout, return error */
  	}
	
	if (resp != SD_TOK_READ_STARTBLOCK)				
   	{												/* 不是收到数据起始令牌 not receive data start token */
		recbuf[0] = resp;							
		i = 1;										/* 还有len - 1个字节要接收 still len - 1 bytes will be received */
   	}
   	else
	{
   		i = 0;
	}
	
	for (; i < len; i++)
	{
   		recbuf[i] = SPI_RecByte();					/* 接收数据 receive data */
	}
	i = SPI_RecByte();								
    i = (i << 8) + SPI_RecByte();    				/* 读取16位CRC get 16-bit CRC */
	
	#if SD_CRC_EN 
	   	if (i != SD_GetCRC16(recbuf, len))
	   	{											/* CRC校验错误 CRC check is error */
	   		SPI_SendByte(0xFF);
	   		SPI_CS_Deassert();		
	  		return SD_ERR_DATA_CRC16;				/* 返回RCR16错误  return error of CRC16 */				
	  	}    
	#endif 
	
	SPI_SendByte(0xFF);								/* 返回之前发送8个clock  clock out 8 clk before return */
    SPI_CS_Deassert();	
		
	return SD_NO_ERR; 
}
/******************************************************************************
** 函数名称: INT8U SD_ReadCSD()						
** 功能描述: 读SD/MMC卡的CSD寄存器					
** 输   入: INT8U csdlen  : 寄存器长度(固定为16)	
			 INT8U *recbuf : 接收缓冲区				
** 输   出: 0:   正确    >0:   错误码		  		
************************************************************************/
unsigned char SD_ReadCSD(unsigned char csdlen, unsigned char *recbuf)
{
	unsigned char param[4] = {0,0,0,0},resp,ret;
  
    ret = SD_SendCmd(CMD9, param, CMD9_R, &resp);		/* 读CSD寄存器命令 command that read CSD register */
    if (ret != SD_NO_ERR)
	{									
        return ret;									
  	}
    if (resp != 0)
	{
        return SD_ERR_CMD_RESP;							/* 响应错误 response is error */
    }	
	return (SD_ReadRegister(csdlen, recbuf));
	
}




/**********************************************************************
** 函数名称: void SD_PackParam()					
** 功能描述: 将32位的参数转为字节形式				
** 输   入: INT8U *parameter: 字节参数缓冲区		
			 INT32U value    : 32位参数				
** 输   出: 无										
************************************************************************/
void SD_PackParam(unsigned char *parameter, unsigned int value)
{
    parameter[0] = (unsigned char)(value >> 24);
    parameter[1] = (unsigned char)(value >> 16);
    parameter[2] = (unsigned char)(value >> 8);
    parameter[3] = (unsigned char)(value);
}



/************************************************************************
** 函数名称: INT8U SD_SetBlockLen()					
** 功能描述: 设置一个块的长度						
** 输   入: INT32U length	: 块的长度值			
** 输   出: 0:   正确    >0:   错误码		  		
**************************************************************************/
unsigned char SD_SetBlockLen(unsigned int length)
{
	unsigned char param[4],resp,ret;
	SD_PackParam(param, length);								/* 将参数转化为字节形式 change the parameter to bytes form */
	ret = SD_SendCmd(CMD16, param, CMD16_R, &resp);
    if (ret != SD_NO_ERR)
	{
 		return ret;									/* 设置块的长度为length失败 set the length of block to length fail */
	}
	if (resp != 0)
	{
    	return SD_ERR_CMD_RESP;			   			/* 响应错误 response is error */
    }
	

    return SD_NO_ERR; 								/* 返回执行成功 return perform sucessfully */			

}



/*******************************************************************************************************************
** 函数名称: INT8U SD_CalTimeout()				Name:	  INT8U SD_CalTimeout()
** 功能描述: 计算读/写/擦超时时间				Function: calculate timeout of reading,writing,erasing
** 输   入: INT8U *csdbuf : CSD寄存器内容		Input: 	  INT8U *csdbuf : CSD register content
** 输    出: 0:   成功    >0:  错误码			Output:	  0:  right			>0:  error code
*******************************************************************************************************************/
unsigned char SD_CalTimeout(unsigned char *csdbuf)
{
	unsigned int tmp;
	unsigned char time_u,time_v,fator;
	sds.timeout_read = READ_TIMEOUT_100MS;								/* 默认读超时为100ms */
	sds.timeout_write = WRITE_TIMEOUT_250MS;							/* 默认写超时为250ms */
	sds.timeout_erase = WRITE_TIMEOUT_250MS;
	
	time_u = (csdbuf[TAAC_POS] & TAAC_MSK);								/* 读超时时间单位 read timeout unit */
	time_v = (csdbuf[TAAC_POS] & NSAC_MSK) >> 3;						/* 读超时时间值   read timeout value */

⌨️ 快捷键说明

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