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