📄 sddriver.c
字号:
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 + -