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

📄 sddriver.c

📁 SmartARM2400系列开发板全套资料
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************Copyright (c)**************************************************
**                               Guangzhou ZLG-MCU Development Co.,LTD.
**                                      graduate school
**                                 http://www.zlgmcu.com
**
**--------------File Info-------------------------------------------------------------------------------
** File name:			sddriver.c
** Last modified Date:	2007-5-19
** Last Version:		V2.0
** Descriptions:		SD/MMC卡读写软件包: 提供给用户API函数: 初始化,读,写,擦卡
**
**
**------------------------------------------------------------------------------------------------------
** Created by:			Ming Yuan Zheng
** Created date:		2005-1-6
** Version:				V1.0
** Descriptions:		The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:			Ming Yuan Zheng
** Modified date:		2005-3-10
** Version:				V2.0
** Descriptions:		增加了对MMC卡的支持,增加了对UCOS-II的支持,使该模块不仅能运行于前后台系统,还可运行
**						于UCOS-II上
**------------------------------------------------------------------------------------------------------
** Modified by:         Ming Yuan Zheng
** Modified date:       2007-5-19
** Version:	            V3.0
** Descriptions:        1. 增加了对SD/MMC卡 SD 总线模式的支持(不同模式下API函数名相同), 各API函数的入口增加了sd_struct结构体, 用于支持多卡读写
**
**                      2. SPI模式下和SD模式下共用 SDMMC_GetCardInfo() 和 SDMMC_CalTimeout()函数
**
**                      3. sd_struct结构体增加了成员多个成员变量, 访问卡的时钟及访问卡的最大时钟改为可动态获取
**
**                      4. SPI 模式下的命令函数使用SpiCmd_ 开头, SD 模式下的命令使用 SdCmd_ 开头
**
**                      5. SPI 模式下与硬件相关的函数使用 SdSpiHal_ 开头, SD 模式下与硬件相关的函数使用 SdHal_ 开头
********************************************************************************************************/

#include "sdconfig.h"

/* 超时时间单位表(单位:0.000000001ns) timeout unit table */
const INT32U time_unit[8] = {1000000000,100000000,10000000,
							 1000000,100000,10000,1000,100};

/* 超时时间表 timeout value table */							 
const INT8U time_value[16] = {0,10,12,13,15,20,25,30,
                              35,40,45,50,55,60,70,80};
 
/* 超时时间因数表 timeout factor table */                              
const INT8U r2w_fator[8] = {1,2,4,8,16,32,64,128};

/* 最大传输速度尾数表, 原为小数, 都乘 10 转换为整数 */
const INT8U tr_spval[16] = {0, 10, 12, 13, 15, 20, 25, 30, 35,
                          40, 45, 50, 55, 60, 70, 80};

/* 最大传输速度指数表, 单位 clock, 从100K ~ 100M */
const INT32U tr_spexp[4] = {100000, 1000000, 10000000, 100000000};
                          
	/*       
	***************************************************************************************************
		
	     用户API函数:  初始化,读,写,擦 SD/MMC卡
				
	***************************************************************************************************
	*/

void SD_RequestOSSem(sd_struct *sds);
void SD_ReleaseOSSem(sd_struct *sds);
INT8U SDMMC_GetCardInfo(sd_struct *sds);
INT8U SDMMC_CalTimeout(sd_struct *sds);


/*
*****************************************************************************
   本软件包的SD总线模式, 适用于LPC2368, LPC2378 等带用 SD 控制器的微控制器
*****************************************************************************
*/

#if SDBUS_MODE_EN

INT8U SDMMC_ConfigCard(sd_struct *sds);
INT8U SDMMC_IdentifyCard(sd_struct *sds);

/*******************************************************************************************************************
** 函数名称: SD_Initialize()				
**
** 功能描述: SD/MMC 卡初始化: 复位卡,识别卡,获取卡相关信息,使卡从识别模式进入数据传输模式 
**
** 输   入: sd_struct *sds: SD/MMC卡信息结构体 
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SD_Initialize(sd_struct *sds)
{
	INT8U ret, cidbuf[16];
	
	if (sds == NULL) return SD_ERR_USER_PARAM;          /* 函数入口参数错误 */  
		
#if SD_UCOSII_EN
	if (sds->pSemSD == NULL)
	{
    	sds->pSemSD = OSSemCreate(1);					/* 创建访问卡信号量 */ 
		if (sds->pSemSD == NULL)					
		 	return SD_ERR_CREATE_SEMSD;					
	}
	
	if (sds->pSemSdmmcRW == NULL)
	{
    	sds->pSemSdmmcRW = OSSemCreate(0);				/* 创建读写擦卡等待信号量 */ 
		if (sds->pSemSdmmcRW == NULL)					
		 	return SD_ERR_CREATE_SEMSD;					
	}					    
#endif
	SD_RequestOSSem(sds);								/* 向 OS 请求获取访问卡信号量 */
	
	if (sds->RCA != 0)  sds->RCA = 0;
	
	SdHal_Initialize(sds);							    /* HAL层初始化 */
 	
 	if (!SdHal_CheckCard(sds))							/* 检测卡是否完全插入卡座 */
 	{
 		ret = SD_ERR_NO_CARD;
 		goto SDINIT_END;
 	}
 	
	ret = SdCmd_Go_Idle_State(sds);						/* CMD0: 复位卡, 使卡进入空闲状态 */
	if (ret != SD_NO_ERR)	
		goto SDINIT_END;
	
	ret = SDMMC_IdentifyCard(sds);						/* CMD1或ACMD41: 识别卡, 进入就绪状态 */
	if (ret != SD_NO_ERR) 	
		goto SDINIT_END;	 
	  
	ret = SdCmd_All_Send_CID(sds, 16, cidbuf);          /* CMD2: 读CID, 进入识别状态 */
    if (ret != SD_NO_ERR)
	    goto SDINIT_END;
	    
	ret = SdCmd_Set_Relative_Addr(sds);					/* CMD3: 获取RCA, 进入待机状态 */
   	if (ret != SD_NO_ERR)	
   		goto SDINIT_END;
  
    ret = SDMMC_GetCardInfo(sds);						/* CMD9: 读取CSD, 获取卡的属性 */
    if (ret != SD_NO_ERR)
    	goto SDINIT_END;

    SdHal_SetMCIClock(sds, SD_RATE_NORMAL);  			/* 设置访问卡的clock为标准clock */

	ret = SDMMC_CalTimeout(sds);						/* 计算超时时间值 */
	if (ret != SD_NO_ERR)
	    goto SDINIT_END;

  	ret = SDMMC_ConfigCard(sds);						/* 设置卡相关参数, 处于待机状态 */		

SDINIT_END:	
	SD_ReleaseOSSem(sds);	                            /* 释放访问卡信号量 */
	return ret;  	
}


/*******************************************************************************************************************
** 函数名称: SD_ReadBlock()				
**
** 功能描述: 从SD/MMC卡中读出一个数据块
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**           INT32U blockaddr: 以块为单位的块地址, 例如, 卡开始的0 ~ 511字节为块地址0, 512 ~ 1023字节的块地址为1
**	         
** 输   出: INT8U *recbuf   : 接收缓冲区,长度固定为 512 字节	
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SD_ReadBlock(sd_struct *sds, INT32U blockaddr, INT8U *recbuf)
{
	INT8U ret;

    if ((sds == NULL) || (recbuf == NULL))          
        return SD_ERR_USER_PARAM;                   /* 函数入口参数错误 */ 

	SD_RequestOSSem(sds);							/* 向OS申请访问卡信号量 */
    if (!SdHal_CheckCard(sds))							
    {	
    	ret = SD_ERR_NO_CARD;   					/* 卡没完全插入座卡中 */
		goto SDRD_BLK_END;
	}
	
	if (blockaddr > sds->block_num)	
	{
		ret = SD_ERR_OVER_CARDRANGE;				/* 操作超出卡容量范围 */
	    goto SDRD_BLK_END;
	}
	
	ret = SdCmd_Select_Card(sds);					/* CMD7: 进入传输状态  */
    if (ret != SD_NO_ERR)
    	goto SDRD_BLK_END;
  			
	ret = SdHal_BeforeReadBlock(sds);               /* 发送读命令之前的准备工作 */
	if (ret != SD_NO_ERR)
		goto SDRD_BLK_END;
	
	ret = SdCmd_Read_Single_Block(sds, blockaddr);	/* CMD17: 发送读单块命令 */						
 	if (ret != SD_NO_ERR)
 		goto SDRD_BLK_END;	
	
	ret = SdHal_ReadBlock(sds, recbuf);             /* 从卡接收数据 */
	if (ret != SD_NO_ERR)
		goto SDRD_BLK_END;
  	
SDRD_BLK_END:
    SdCmd_Deselect_Card(sds, 0);				/* CMD7: 退出传输状态 */
	SD_ReleaseOSSem(sds);                           /* 释放访问卡信号量 */
    return ret;						
}


/*******************************************************************************************************************
** 函数名称: SD_ReadMultiBlock()				
**
** 功能描述: 从SD/MMC卡中读出多个数据块
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**           INT32U blockaddr: 以块为单位的块地址
**	         INT32U blocknum : 要读取的块的个数
**
** 输   出: INT8U *recbuf   : 接收缓冲区, 长度512 * blocknum 字节	
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
#if SD_ReadMultiBlock_EN
INT8U SD_ReadMultiBlock(sd_struct *sds, INT32U blockaddr, INT32U blocknum, INT8U *recbuf)
{
	INT8U ret;
	INT32U i;
	
    if ((sds == NULL) || (recbuf == NULL)) 
        return SD_ERR_USER_PARAM;                   /* 函数入口参数错误 */	
	
	SD_RequestOSSem(sds);							/* 向OS申请访问卡信号量 */
    if (!SdHal_CheckCard(sds))							
    {	
    	ret = SD_ERR_NO_CARD;   					/* 卡没完全插入卡座中 */
		goto SDRD_MBLK_END;
	}

	if (blockaddr > sds->block_num)	
	{
		ret = SD_ERR_OVER_CARDRANGE;				/* 操作超出卡容量范围 */
	    goto SDRD_MBLK_END;
	}

	ret = SdCmd_Select_Card(sds);					/* CMD7: 进入传输状态  */
    if (ret != SD_NO_ERR)
    	goto SDRD_MBLK_END;
   		
	ret = SdHal_BeforeReadBlock(sds);               /* 发送读命令之前的准备工作 */    
	if (ret != SD_NO_ERR)
		goto SDRD_MBLK_END;
			
	ret = SdCmd_Read_Multiple_Block(sds, blockaddr);/* 发送读多块命令 */						
 	if (ret != SD_NO_ERR)
 		goto SDRD_MBLK_END;
	
    for (i = 0; i < blocknum; i++)
    {		
    	ret = SdHal_ReadBlock(sds, recbuf);         /* 接收来自卡的数据 */
    	if (ret == SD_NO_ERR)
       		recbuf = recbuf + SD_BLOCKSIZE;
    	else
            goto SDRD_MBLK_END; 
        
        if (i < (blocknum - 1))
        {
            ret = SdHal_BeforeReadBlock(sds);       /* 接收来自卡数据之前的准备工作 */  
	        if (ret != SD_NO_ERR)
		        goto SDRD_MBLK_END;      
        }
    }
 
  	ret = SdCmd_Stop_Transmission(sds);             /* 停止传输 */
  	if (ret != SD_NO_ERR)
		goto SDRD_MBLK_END;  	

SDRD_MBLK_END:
    SdCmd_Deselect_Card(sds, 0);				/* CMD7: 退出传输状态 */
	SD_ReleaseOSSem(sds);
    return ret;						
}
#endif


/*******************************************************************************************************************
** 函数名称: SD_WriteBlock()				
**
** 功能描述: 向SD/MMC卡中写入一个块	
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**           INT32U blockaddr: 以块为单位的块地址, 例如, 卡开始的0 ~ 511字节为块地址0, 512 ~ 1023字节的块地址为1
**           INT8U *sendbuf  : 发送缓冲区,长度固定为 512 字节	
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SD_WriteBlock(sd_struct *sds, INT32U blockaddr, INT8U *sendbuf)
{
	INT8U ret;

    if ((sds == NULL) || (sendbuf == NULL)) 
        return SD_ERR_USER_PARAM;                    /* 函数入口参数错误 */

	SD_RequestOSSem(sds);							 /* 向OS申请访问卡的信号量 */
    if (!SdHal_CheckCard(sds))							
    {
    	ret = SD_ERR_NO_CARD;   					 /* 卡没完全插入卡座中 */
		goto SDWR_BLK_END;
	}	
	
	if (blockaddr > sds->block_num)	
	{
		ret = SD_ERR_OVER_CARDRANGE;				 /* 操作超出卡容量范围 */
		goto SDWR_BLK_END;
	}
	
	if (SdHal_CheckCardWP(sds))
	{
		ret = SD_ERR_WRITE_PROTECT;					 /* 卡有写保护 */
		goto SDWR_BLK_END;
	}
	
	ret = SdCmd_Select_Card(sds);					 /* CMD7: 进入传输状态  */
    if (ret != SD_NO_ERR)
        goto SDWR_BLK_END;
 	
	ret = SdHal_BeforeWriteBlock(sds);               /* 写数据之前的准备工作 */
	if (ret != SD_NO_ERR)
		goto SDWR_BLK_END;		
 
	ret = SdCmd_Write_Single_Block(sds, blockaddr);	 /* CMD24, 发送写单块命令 */						
 	if (ret != SD_NO_ERR)
 		goto SDWR_BLK_END;

	ret = SdHal_WriteBlock(sds, sendbuf);            /* 往卡中写入数据 */   
	if (ret != SD_NO_ERR)
		goto SDWR_BLK_END;
		
	ret = SdHal_WaitBusy(sds, BUSY_TYPE_PROG);      /* 等待卡编程完成 */
	if (ret != SD_NO_ERR)
        goto SDWR_BLK_END;
           
SDWR_BLK_END:
    SdCmd_Deselect_Card(sds, 0);              /* CMD7: 退出传输状态 */  
	SD_ReleaseOSSem(sds);
	return ret;                                     /* 返回操作结果 */	
}


/*******************************************************************************************************************
** 函数名称: SD_WriteMultiBlock()				
**
** 功能描述: 向SD/MMC卡中写入多个数据块	
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**           INT32U blockaddr: 以块为单位的块地址
**           INT32U blocknum : 要写入的块的个数
**           INT8U *sendbuf  : 发送缓冲区, 长度 512 * blocknum 字节	
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
#if SD_WriteMultiBlock_EN
INT8U SD_WriteMultiBlock(sd_struct *sds, INT32U blockaddr, INT32U blocknum, INT8U *sendbuf)
{
	INT8U ret;
	INT32U i;

    if ((sds == NULL) || (sendbuf == NULL)) 
        return SD_ERR_USER_PARAM;                       /* 函数入口参数错误 */

	SD_RequestOSSem(sds);                               /* 向OS申请访问卡信号量 */
    if (!SdHal_CheckCard(sds))							
    {
    	ret = SD_ERR_NO_CARD;                           /* 卡没完全插入卡座中 */
		goto SDWR_MBLK_END;
	}	
	
	if (blockaddr > sds->block_num)	
	{
		ret = SD_ERR_OVER_CARDRANGE;                    /* 操作超出卡容量范围 */
		goto SDWR_MBLK_END;
	}
	
	if (SdHal_CheckCardWP(sds))
	{
		ret = SD_ERR_WRITE_PROTECT;                     /* 卡有写保护 */
		goto SDWR_MBLK_END;
	}

	ret = SdCmd_Select_Card(sds);                       /* CMD7: 进入传输状态  */
    if (ret != SD_NO_ERR)
        goto SDWR_MBLK_END;
 	
	ret = SdHal_BeforeWriteBlock(sds);                  /* 发送数据前的准备工作 */
	if (ret != SD_NO_ERR)
		goto SDWR_MBLK_END;		
 
	ret = SdCmd_Write_Multiple_Block(sds, blockaddr);   /* CMD25, 发送写多块命令 */						
 	if (ret != SD_NO_ERR)
 		goto SDWR_MBLK_END;

    for (i = 0; i < blocknum; i++)
    {
		ret = SdHal_WriteBlock(sds, sendbuf);           /* 写入数据 */
 		if (ret == SD_NO_ERR)
 		{	
 			sendbuf = sendbuf + SD_BLOCKSIZE;
 		}
 		else
 		{												/* 写失败  */
			SdCmd_Stop_Transmission(sds);				/* 停止数据传输并等待忙结束 */	
			SdHal_WaitBusy(sds, BUSY_TYPE_PROG);
			goto SDWR_MBLK_END;

⌨️ 快捷键说明

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