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

📄 sddriver.c

📁 基于lpc2378的SD/MMC卡读写程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			SdHal_WaitBusy(sds, BUSY_TYPE_PROG);
			goto SDWR_MBLK_END;
		}
		
		ret = SdHal_WaitReadyforData(sds);              /* 等待卡可接收数据 */
        if (ret != SD_NO_ERR)
		   goto SDWR_MBLK_END;	
		
		if (i < (blocknum - 1))
		{		
 		    ret = SdHal_BeforeWriteBlock(sds);          /* 再次准备发送数据 */
	        if (ret != SD_NO_ERR)
		        goto SDWR_MBLK_END;		    
	    }
	}

    ret = SdCmd_Stop_Transmission(sds);                 /* 停止数据传输 */
    if (ret != SD_NO_ERR)
	    goto SDWR_MBLK_END;

    ret = SdHal_WaitBusy(sds, BUSY_TYPE_PROG);          /* 等待卡编程结束 */
    if (ret != SD_NO_ERR)
        goto SDWR_MBLK_END;

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


/*******************************************************************************************************************
** 函数名称: SDMMC_IdentifyCard()		
**
** 功能描述: 识别卡: SD, MMC, 或不可卡别卡
**
** 输   入: sd_struct *sds: SD/MMC卡信息结构体 
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
**
** 注    意: 执行后, 卡型保存在sds->card_type中
********************************************************************************************************************/
INT8U SDMMC_IdentifyCard(sd_struct *sds)
{
	if (SdCmd_Send_OP_Cond(sds) != SD_NO_ERR)			/* CMD1: 命令仅适合于MMC卡 */
	{
		if (SdCmd_SD_App_OP_Cond(sds) == SD_NO_ERR)     /* ACMD41: 读取OCR 寄存器 */
		{                                               
			sds->card_type = CARDTYPE_SD;               /* 卡型为 SD卡 */
		}
		else
		{		
			sds->card_type = CARDTYPE_UNKNOWN;          /* 不可识别的卡 */
			return SD_ERR_UNKNOWN_CARD;						
		}
	}
	else
		sds->card_type = CARDTYPE_MMC;	                /* 卡型为 MMC卡 */
		
	return SD_NO_ERR;		
}


/*******************************************************************************************************************
** 函数名称: SDMMC_ConfigCard()				
**
** 功能描述: 对卡的相关参数进行配置, 如卡总线宽度, 卡数据块大小
**
** 输   入: sd_struct *sds: SD/MMC卡信息结构体
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SDMMC_ConfigCard(sd_struct *sds)
{
	INT8U ret;
	
	SdHal_OpenDrainCmd(sds, 0);                         /* 禁止CMD线的开漏模式 */
		
    // 下面进入传输状态, 设置卡的相关参数    	
 	ret = SdCmd_Select_Card(sds);			            /* CMD7,进入传输状态  */
    if (ret != SD_NO_ERR)
       return ret;
 
   	if (sds->card_type == CARDTYPE_SD)	
    {                                                   /* 只有SD卡既可为宽数据总线, 又可为单数据总线 */
#if SD_WIDTHBUS_EN   
		SdHal_EnableMCIBusWidth(sds, 1);
		ret = SdCmd_Set_Bus_Width(sds, 1);    			/* ACMD6设置卡为宽数据总线方式 */
#else
		SdHal_EnableMCIBusWidth(sds, 0);
        ret = SdCmd_Set_Bus_Width(sds, 0);    			/* ACMD6设置卡为单数据总线方式 */
#endif  
    	if (ret != SD_NO_ERR)
    		return ret; 
    }	
    else
		SdHal_EnableMCIBusWidth(sds, 0);                /* MMC卡只能为单数据总线方式 */
 	
 	ret = SdCmd_Set_BlockLen(sds, SD_BLOCKSIZE);        /* CMD16, 置块数据大小为: 512字节 */
 	if (ret != SD_NO_ERR)
 	    return ret;
  	
 	SdCmd_Deselect_Card(sds, 0);		            /* CMD7, 退出传输状态 */  
 	return ret;	
}

#endif


/*******************************************************************************************************************
** 函数名称: SDMMC_GetCardInfo()				
**
** 功能描述: 获得SD/MMC卡的信息	
**
** 输   入: sd_struct *sds: 卡属性结构体
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SDMMC_GetCardInfo(sd_struct *sds)
{
	INT32U tmp;
	INT8U csdbuf[16],ret;

#if SDBUS_MODE_EN
	ret = SdCmd_Send_CSD(sds, 16, csdbuf);									    /* 读CSD寄存器    read CSD register */
#else
    ret = SpiCmd_Send_CSD(sds, 16, csdbuf);
#endif    
	if (ret != SD_NO_ERR)	
		return ret;	
		
	/* 计算块的最大长度  */														/* calculate the size of a sector */
	sds->block_len = 1 << (csdbuf[READ_BL_LEN_POS] & READ_BL_LEN_MSK);  		/* (2 ^ READ_BL_LEN) */
	
	/* 计算卡中块的个数 */														/* calculate the sector numbers of the SD Card */
	sds->block_num = ((csdbuf[C_SIZE_POS1] & C_SIZE_MSK1) << 10) +
	      			 (csdbuf[C_SIZE_POS2] << 2) +
	 	 			((csdbuf[C_SIZE_POS3] & C_SIZE_MSK3) >> 6) + 1;				/* (C_SIZE + 1)*/
		 	  															
	tmp = ((csdbuf[C_SIZE_MULT_POS1] & C_SIZE_MULT_MSK1) << 1) +   
	      ((csdbuf[C_SIZE_MULT_POS2] & C_SIZE_MULT_MSK2) >> 7) + 2;				/* (C_SIZE_MULT + 2) */
    	
    /* 获得卡中块的数量 */														/* get the block numbers in card */
	sds->block_num = sds->block_num * (1 << tmp);								/* (C_SIZE + 1) * 2 ^ (C_SIZE_MULT + 2) */
																			
	/* 计算擦除的单位(单位: 块) */	
	if (sds->card_type == CARDTYPE_MMC)
	{					    
		tmp  = ((csdbuf[ERASE_GRP_SIZE_POS] & ERASE_GRP_SIZE_MSK) >> 2) + 1;  	/* (ERASE_GRP_SIZE + 1)  */ 
		
		/* (ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULTI_MSK1 + 1) */
		tmp *= ((csdbuf[ERASE_GRP_MULTI_POS1] & ERASE_GRP_MULTI_MSK1) << 3) +
		       ((csdbuf[ERASE_GRP_MULTI_POS2] & ERASE_GRP_MULTI_MSK2) >> 5) + 1;	
	}
	else																		/*calculate the size of sector */
		tmp = ((csdbuf[SECTOR_SIZE_POS1] & SECTOR_SIZE_MSK1) << 1) +  			
	          ((csdbuf[SECTOR_SIZE_POS2] & SECTOR_SIZE_MSK2) >> 7) + 1;			/* SD: SECTOR_SIZE */
	
	sds->erase_unit = tmp;	    												/* 擦除单位(块) */ 
	
	sds->card_transpeed = tr_spexp[csdbuf[TRAN_SPEED_POS] & TRAN_SPEED_MSK1] *
	                      tr_spval[(csdbuf[TRAN_SPEED_POS] & TRAN_SPEED_MSK2) >> 3] / 10;
	
	return SD_NO_ERR;															/* 返回执行成功 return perform sucessfully */
}


/*******************************************************************************************************************
** 函数名称: SDMMC_CalTimeout()				
**
** 功能描述: 计算读/写/擦超时时间
**
** 输   入: INT8U *csdbuf : CSD寄存器内容, 长度为16字节
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
**
** 注    意: 所有的超时时间都是以一个Clock为单位
********************************************************************************************************************/
INT8U SDMMC_CalTimeout(sd_struct *sds)
{
	INT32U tmp;
	INT8U time_u,time_v,fator;
	INT8U csdbuf[16],ret;
	INT32U t_100ms = sds->host_clkval / 10;                             /* 100ms 当量, 即多少个clock */
	INT32U t_250ms = sds->host_clkval / 4;                              /* 250ms 当量, 即多少个clock */
	
#if SDBUS_MODE_EN
	ret = SdCmd_Send_CSD(sds, 16, csdbuf);								/* 读CSD寄存器 */
#else
    ret = SpiCmd_Send_CSD(sds, 16, csdbuf);
#endif
	if (ret != SD_NO_ERR)	
		return ret;	
		
	sds->timeout_read = t_100ms;								        /* 默认读超时为100ms */
	sds->timeout_write = t_250ms;							            /* 默认写超时为250ms */
	sds->timeout_erase = t_250ms;                                       /* 默认擦超时为250ms */
		
	time_u = (csdbuf[TAAC_POS] & TAAC_MSK);								/* 读超时时间单位 read timeout unit */
	time_v = (csdbuf[TAAC_POS] & NSAC_MSK) >> 3;						/* 读超时时间值   read timeout value */
	fator = (csdbuf[R2WFACTOR_POS] & R2WFACTOR_MSK) >> 2;				/* 读超时时间因数 read timeout factor */
	
	if(time_v == 0)	return SD_ERR_CARD_PARAM;							/* 卡参数有错误 card parameter is error */
	
	tmp = sds->host_clkval * time_value[time_v] / 10 / time_unit[time_u];	/* TAAC * f (单位 unit: clock) */
	tmp = tmp + csdbuf[NSAC_POS] * 100;									    /* TAAC * f + NSAC * 100 (单位 unit: clock) */
	
	/* 计算得到的超时值 the timeout value of being calculated */
	sds->timeout_read = tmp;
	sds->timeout_write = tmp * r2w_fator[fator];						/* (TAAC * f + NSAC * 100) * R2WFACTOR (单位 unit:clock)*/
	
	if (sds->card_type == CARDTYPE_SD)
	{
		sds->timeout_read  = (sds->timeout_read * 100);     			/* 实际值为计算值的100倍 */
		sds->timeout_write = (sds->timeout_write * 100);
		if (sds->timeout_read > t_100ms)						        /* 取计算值与默认值中的最小值 */
			sds->timeout_read = t_100ms;
		
		if (sds->timeout_write > t_250ms)
			sds->timeout_write = t_250ms;
	}
	else
	{
		sds->timeout_read  = (sds->timeout_read * 10);      			/* 实际值为计算值的10倍 */
		sds->timeout_write = (sds->timeout_write * 10);
	}
	
#if SD_UCOSII_EN
    if (sds->host_clkval == 0)  return SD_ERR_SD_STRUCT;
	sds->timeout_read_os  = sds->timeout_read * OS_TICKS_PER_SEC / sds->host_clkval; 
	sds->timeout_write_os = sds->timeout_write * OS_TICKS_PER_SEC / sds->host_clkval;
	sds->timeout_erase_os = sds->timeout_write_os;						/* (单位 unit: os tick) */
#endif	

    /* SPI模式及非UCOS环境下 */
#if	(!SDBUS_MODE_EN)
#if (!SD_UCOSII_EN)
    sds->timeout_read = sds->timeout_read / 8;                         /* SPI总线模式则折算为8clock为单位 */
    sds->timeout_write = sds->timeout_write / 8;
#endif
#endif

	sds->timeout_erase = sds->timeout_write;
	
	return SD_NO_ERR;	
}



/*******************************************************************************************************************
** 函数名称: SD_EraseBlock()				
**
** 功能描述: 擦除SD/MMC卡中的块
**
** 输   入: sd_struct *sds   : 卡属性结构体
**	         INT32U startaddr : 擦卡的起始地址, 地址为以块为单位的块地址
**           INT32U blocknum  : 擦除的块数            
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
**
** 注    意: startaddr 和 blocknum 建议为 sds.erase_unit 的整数倍, 因为有的卡只能以 sds.erase_unit 为单位进行擦除
********************************************************************************************************************/
#if SD_EraseBlock_EN
INT8U SD_EraseBlock(sd_struct *sds, INT32U startaddr, INT32U blocknum)
{
	INT32 tmp;
	INT8U ret;
	
	if (sds == NULL) return SD_ERR_USER_PARAM;                              /* 函数入口参数错误 */
	
	SD_RequestOSSem(sds);                                                   /* 向OS申请访问卡的信号量 */
    if (!SdHal_CheckCard(sds))							
    {
    	ret = SD_ERR_NO_CARD;                                               /* 卡没完全插入卡座中 */	
    	goto SD_ERASE_END;
	}
	
	if ((startaddr + blocknum) > sds->block_num)	
	{
		ret = SD_ERR_OVER_CARDRANGE;	
		goto SD_ERASE_END;                                                  /* 操作超出卡容量范围 */
	}
		
	if (SdHal_CheckCardWP(sds))
	{
	    ret = SD_ERR_WRITE_PROTECT;                                         /* 卡有写保护 */
		goto SD_ERASE_END;						
	}	

#if SDBUS_MODE_EN
	ret = SdCmd_Select_Card(sds);					                        /* CMD7: 进入传输状态  */
    if (ret != SD_NO_ERR)
    	goto SD_ERASE_END;
#endif

	tmp = blocknum - sds->erase_unit;	
	while(tmp >= 0)												            /* 每次擦除sds->erase_unit 块 */
	{	
		ret = SdCmd_Erase_Wr_Blk_Start(sds, startaddr);			            /* 选择起始块地址 */
		if (ret != SD_NO_ERR)
            goto SD_ERASE_END;
		
		ret = SdCmd_Erase_Wr_Blk_End(sds, startaddr + sds->erase_unit - 1);	/* 选择终止块地址 */
		if (ret != SD_NO_ERR)
	        goto SD_ERASE_END;
			
		ret = SdCmd_Erase(sds);							                    /* 擦除所选择的块 */
		if (ret != SD_NO_ERR)
            goto SD_ERASE_END;

		startaddr += sds->erase_unit;								        /* 起始地址递增 */
		blocknum  -= sds->erase_unit;
		tmp = blocknum - sds->erase_unit;
	};		
	
	if (blocknum > 0)											            /* 擦除不够sds->erase_unit的块 */
	{
		ret = SdCmd_Erase_Wr_Blk_Start(sds, startaddr);
		if (ret != SD_NO_ERR)
            goto SD_ERASE_END;
		
		ret = SdCmd_Erase_Wr_Blk_End(sds, startaddr + blocknum - 1);
		if (ret != SD_NO_ERR)
            goto SD_ERASE_END;
			
		ret = SdCmd_Erase(sds);
		if (ret != SD_NO_ERR)
            goto SD_ERASE_END;
	}

SD_ERASE_END:
#if SDBUS_MODE_EN
    SdCmd_Deselect_Card(sds, 0);                                      /* CMD7: 退出传输状态 */  
#endif
	SD_ReleaseOSSem(sds);
	return ret;											                    /* 返回擦除结果 */
}
#endif


/*******************************************************************************************************************
** 函数名称: SD_RequestOSSem()				
**
** 功能描述: 向操作系统申请访问卡的信号量
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
void SD_RequestOSSem(sd_struct *sds)
{
#if SD_UCOSII_EN
	INT8U ret;
	
	OSSemPend(sds->pSemSD, 0, &ret);				/* 等待访问卡信号量可用  */
#endif
}


/*******************************************************************************************************************
** 函数名称: SD_ReleaseOSSem()				
**
** 功能描述: 释放访问卡的信号量
**
** 输   入: sd_struct *sds  : SD/MMC卡信息结构体 
**	         
** 输   出: 无
**
** 返 回 值: 0:   正确    >0:   错误码, 见 sddriver.h 文件
********************************************************************************************************************/
void SD_ReleaseOSSem(sd_struct *sds)
{
#if SD_UCOSII_EN
	OSSemPost(sds->pSemSD);							/* 将访问卡信号量还给操作系统 */
#endif
}


/*******************************************************************************************************************
** 函数名称: SD_GetZLGSDVer()				
**
** 功能描述: 得到ZLG/SD软件包的版本号	
**
** 输   入: 无 
**	         
** 输   出: 无	
**
** 返 回 值: 版本号  Version
**
** 版本记录: V1.0   支持访问SD 卡,只能在前后台系统运行
			 
			 V2.0   支持访问SD和MMC卡,可运行于前后系统或UCOS-II
			 
			 V3.0   支持并整合了 SD/MMC 卡的SD模式和SPI模式, 软件硬件分层更加清晰
********************************************************************************************************************/
INT16U SD_GetZLGSDVer(void)
{
	return 0x0300;						/* 版本号为 3.00 */
}




/*
*****************************************************************************************
   本软件包的 SPI 总线模式, 适用于LPC21xx, LPC22xx, LPC2364/6 等带用SPI控制器的微控制器
*****************************************************************************************
*/

#if (!SDBUS_MODE_EN)

⌨️ 快捷键说明

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