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

📄 sddriver.c

📁 SD/MMC卡文件读写系统(FAT32)
💻 C
📖 第 1 页 / 共 2 页
字号:

// SD/MMC卡读写模块: 物理层 用户API函数

#include "sdhal.h"
#include "sdcmd.h"
#include "sddriver.h"

#if 0
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#endif
///////////////////////////////////////////////////////////////

// 向卡发送命令,并取得响应 (命令字,命令参数--长度为4字节,响应类型,响应-长度为1-5字节) 0:正确  >0:错误码
U8 SD_TxCMD(U8 cmd, U8 *param, U8 resptype, U8 *resp)
{
	S32 i,rlen;
	U8 tmp;
	SPI_CS_Enable();
    SPI_TxBYTE((cmd & 0x3F) | 0x40);	/* 发送命令头和命令字 */

    for (i = 3; i >= 0; i--)
        SPI_TxBYTE(param[i]);	/* 发送参数  */

    SPI_TxBYTE(0x95);		/* CRC校验码,只用于第1个命令 */
    
    rlen = 0;
    switch (resptype)/* 根据不同的命令,得到不同的响应长度 */
    {			
  	case R1:
   	case R1B: rlen = 1;  break;
    	 
    case R2:  rlen = 2;	 break;
    	 
   	case R3:  rlen = 5;	 break;
    	 
    default:  SPI_TxBYTE(0xFF);	
    	      SPI_CS_Disable();						 
    	      return SD_ERR_CMD_RESPTYPE;		 /* 返回命令响应类型错误*/
    	      break;
    }
    
    i = 0;				
    do 		/* 等待响应,响应的开始位为0 */
    {								 
        tmp = SPI_RxBYTE();
        i++;
    }while (((tmp & 0x80) != 0) && (i < SD_CMD_TIMEOUT));
    
    if (i >= SD_CMD_TIMEOUT)
    {												 
        SPI_CS_Disable();
        return SD_ERR_CMD_TIMEOUT;	/* 超时 */
    }
    
    for (i = rlen - 1; i >= 0; i--)
    {
        resp[i] = tmp;
        tmp = SPI_RxBYTE();/* 循环的最后发送8clock  */
    }
      
    SPI_CS_Disable();
    return SD_NO_ERR;	/* 执行成功 */
}

// 将32位的参数转为字节形式 (字节参数缓冲区,32位参数)
void SD_PackPara(U8* para, U32 value)
{
    para[3] = (U8)(value >> 24);
    para[2] = (U8)(value >> 16);
    para[1] = (U8)(value >> 8);
    para[0] = (U8)(value);
}

// 块命令 (命令字, 响应类型, 块操作参数)   0:正确  >0:错误码
U8 SD_BlockCMD(U8 cmd, U8 resptype, U32 para)
{
	U8 param[4],resp,ret;
	
	para <<= SD_BLOCKSIZE_NBITS; /* 调整地址:左移9位 */

	SD_PackPara(param, para);	/* 将参数转化为字节形式 */	

	ret = SD_TxCMD(cmd, param, resptype, &resp);
	if (ret != SD_NO_ERR)
	   	 return ret;		 /* 结束数据传输失败*/
	
	if (resp != 0)
		 return SD_ERR_CMD_RESP;	 /* 响应错误 */
		 
	return SD_NO_ERR;
}


	
// 复位SD/MMC卡      0:正确  >0:错误码
U8 SD_ResetSD(void)
{
	U8 param[4] = {0,0,0,0},resp;
	
    return (SD_TxCMD(CMD0, param, CMD0_R, &resp));	/* 复位命令*/
}

// 读SD/MMC卡的CSD寄存器  (寄存器长度(固定为16), 接收缓冲区)  0:正确  >0:错误码
U8 SD_ReadCSD(U8 csdlen, U8 *recbuf)
{
    U8 param[4] = {0,0,0,0},resp,ret;
  
    ret = SD_TxCMD(CMD9, param, CMD9_R, &resp);		/* 读CSD寄存器命令*/
    if (ret != SD_NO_ERR) 									
        return ret;									
  
    if (resp != 0)
        return SD_ERR_CMD_RESP;	/* 响应错误*/
    
	return (SD_ReadRegister(csdlen, recbuf));
}

// 读SD/MMC卡的 Card Status 寄存器 (寄存器长度(固定为2), 接收缓冲区)  0:正确  >0:错误码
U8 SD_ReadCard_Status(U8 len, U8 *buffer)
{
    U8 param[4] = {0,0,0,0};

    return (SD_TxCMD(CMD13, param, CMD13_R, buffer)); /* 读 Card Status 寄存器 */
}


// 设置一个块的长度 (块的长度值)  0:正确  >0:错误码
U8 SD_SetBlockLen(U32 length)
{
	U8 param[4],resp,ret;
  
    SD_PackPara(param, length);/* 将参数转化为字节形式 */
          												
    ret = SD_TxCMD(CMD16, param, CMD16_R, &resp);
    if (ret != SD_NO_ERR)
 		return ret;		/* 设置块的长度为length失败 */
	
	if (resp != 0)
    	return SD_ERR_CMD_RESP;	/* 响应错误 */
    
    return SD_NO_ERR; 	/* 返回执行成功 */			
}


// 读操作条件寄存器OCR (寄存器长度(固定为4), 接收缓冲区)  0:正确  >0:错误码
U8 SD_ReadOCR(U8 ocrlen, U8 *recbuf)
{
    U8 param[4] = {0,0,0,0},resp[5],tmp;

    tmp = SD_TxCMD(CMD58, param, CMD58_R, resp);		/* 读 OCR 寄存器命令 */
    if (tmp != SD_NO_ERR)				
    	return tmp;		 										
    												
    if (resp[0] != 0)
        return SD_ERR_CMD_RESP;		/* 响应错误*/
    
    for (tmp = 0; tmp < 4; tmp++)
    	recbuf[tmp] = resp[tmp + 1];	/* 复制OCR寄存器内容到接收缓冲区 */
    
    return SD_NO_ERR;
}



// 从SD卡读取数据 (长度, 接收缓冲区)  0:正确  >0:错误码
U8 SD_ReadRegister(U32 len, U8 *recbuf)
{	
	U32 i = 0;
	U8 resp;

    SPI_CS_Enable();
    do{    		/* 等待数据起始令牌*/
        resp = SPI_RxBYTE();
    	i++;
    }while((resp == 0xFF) && (i < SD_READREG_TIMEOUT));    
    
    if (i >= SD_READREG_TIMEOUT)
    {
    	SPI_CS_Disable();
    	return SD_ERR_TIMEOUT_READ;	/* 超时, 返回错误*/
  	}
  	
   	if (resp != SD_TOK_READ_STARTBLOCK)				
   	{			/* 不是收到数据起始令牌*/
		recbuf[0] = resp;							
		i = 1;	/* 还有len - 1个字节要接收 */
   	}
   	else
   		i = 0;	/* 收到数据起始令牌,还有len个字节要接收 */
   	  	
    for (; i < len; i++)
   		recbuf[i] = SPI_RxBYTE();	/* 接收数据 receive data */
   		
    i = SPI_RxBYTE();								
    i = (i << 8) + SPI_RxBYTE();  /* 读取16位CRC*/	
  
    SPI_TxBYTE(0xFF);	/* 返回之前发送8个clock*/
    SPI_CS_Disable();	
    	
	return SD_NO_ERR;
}	

//  从卡中读取数据块 (长度,接收缓冲区) 0:正确  >0:错误码
U8 SD_ReadBlockData(U32 len, U8 *recbuf)
{
    U8 tmp;
    U32 i = 0,timeout;
    
#if SD_FreeRTOS_EN    
    timeout = SD_FreeRTOS_SMALLWAIT;	/* 很少的等待时间*/
#else
	timeout = sds.timeout_read;	/* 等待接收数据开始令牌最长时间 */
#endif  
    
    SPI_CS_Enable();    
    do
    {  /* 等待接收数据开始令牌0xFE*/
        tmp = SPI_RxBYTE();
        i++;
    }while((tmp == 0xFF) && (i < timeout));
	
#if SD_FreeRTOS_EN    
    if (i >= timeout)
   	{	/* 继续等待(挂起任务)*/
   		timeout = sds.timeout_read;
   		i = 0;
	    do
    	{
        	vTaskDelay(1);		/* 挂起该任务1 tick*/
        	tmp = SPI_RxBYTE();
       	 	i++;
   		}while((tmp == 0xFF) && (i < timeout));
	}
#endif

	if (i >= timeout)
	{
		SPI_CS_Disable();
       	return SD_ERR_TIMEOUT_READ;	/* 返回读超时错误码*/
	}
	
	if (tmp != SD_TOK_READ_STARTBLOCK)	/* 块读开始令牌错误*/
	{
		SPI_TxBYTE(0xFF);
		SPI_CS_Disable();
		return SD_ERR_DATA_START_TOK;
	}
	
	for (i = 0; i < len; i++)
   		recbuf[i] = SPI_RxBYTE();	/* 接收数据*/
   		
    i = SPI_RxBYTE();								
    i = (i << 8) + SPI_RxBYTE();  /* 读取16位CRC */	

	SPI_TxBYTE(0xFF); 
	SPI_CS_Disable();

  	return SD_NO_ERR;	/* 执行成功*/
}

// 向卡写数据块 (是否为多块操作1:是0:否,  长度, 发送缓冲区)  0:正确  >0:错误码
U8 SD_WriteBlockData(U8 bmulti, U32 len, const U8 *sendbuf)
{
	U16 i;
	U8 tmp;

	SPI_CS_Enable();
		
    SPI_TxBYTE(0xFF);	/* 开始发送数据之前发送8个*/
    
    if (bmulti == 1)
        SPI_TxBYTE(SD_TOK_WRITE_STARTBLOCK_M);	/* 写多块开始令牌 */
	else
		SPI_TxBYTE(SD_TOK_WRITE_STARTBLOCK);		/* 写单块开始令牌 */

	for (i = 0; i < len; i++)
        SPI_TxBYTE(sendbuf[i]);	/* 发送数据 */

	SPI_TxBYTE((i >> 8) & 0xFF);
	SPI_TxBYTE(i & 0xFF); /* 发送CRC16校验码 */
			    
	tmp = SPI_RxBYTE();
  	if ((tmp & SD_RESP_DATA_MSK) != SD_RESP_DATA_ACCETPTED)	
  	{		
   		SPI_TxBYTE(0xFF);		/* 返回之前发送8个clock */
   		SPI_CS_Disable();
   		return SD_ERR_DATA_RESP;/* 数据响应错误  */
    }
        
    SPI_CS_Disable();
     		
    if (SD_WaitBusy(SD_WAIT_WRITE) != SD_NO_ERR)			
    	return SD_ERR_TIMEOUT_WRITE;	/* 写入超时 */
    else
    	return SD_NO_ERR; 		/* 写入正确 */
 }

// 查询SD卡是否处于忙状态	  0: 未超时  >0: 错误码	
U8 SD_WaitBusy(U8 waittype)
{
    U32 timeout, i = 0;
    U8 tmp;
    
  	if (waittype == SD_WAIT_WRITE)
  		timeout = sds.timeout_write;	/* 等待类型为写操作 */
  	else
  		timeout = sds.timeout_erase;   	/* 等待类型为擦除操作 */
    	
#if SD_FreeRTOS_EN
        timeout = SD_FreeRTOS_SMALLWAIT;	/* 很少的等待时间 */
#endif
   
	SPI_CS_Enable();
   	do
   	{ 								/* 等待忙结束 */
        tmp = SPI_RxBYTE();
        i++;
    }while ((tmp != 0xFF) && (i < timeout));	/* 忙时收到的值为0 */    

#if SD_FreeRTOS_EN
	if (i >= timeout)
	{	/* 很少等待后卡仍忙, */
  		if (waittype == SD_WAIT_WRITE)
  			timeout = sds.timeout_write;
  		else
  			timeout = sds.timeout_erase;   
			
		i = 0;
   		do
   		{ 	
   			vTaskDelay(1);		/* 操作系统挂起1 tick */
       		tmp = SPI_RxBYTE();
       		i++;
    	}while ((tmp != 0xFF) && (i < timeout)); /* 忙时收到的值为0*/    
	}
#endif	

	if(i < timeout) 
		tmp = SD_NO_ERR;		/* 返回0,表示没超时  */
	else 
		tmp = SD_ERR_TIMEOUT_WAIT;		/* 返回错误码,表示超时*/

	SPI_TxBYTE(0xFF);
	SPI_CS_Disable();								
	return tmp;		/* 返回执行结果 */
}

// SPI总线延时
void SD_SPIDelay(U8 value)

⌨️ 快捷键说明

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