?? 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函數(shù): 初始化,讀,寫,擦卡
**
**
**------------------------------------------------------------------------------------------------------
** 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的支持,使該模塊不僅能運(yùn)行于前后臺系統(tǒng),還可運(yùn)行
** 于UCOS-II上
**------------------------------------------------------------------------------------------------------
** Modified by: Ming Yuan Zheng
** Modified date: 2007-5-19
** Version: V3.0
** Descriptions: 1. 增加了對SD/MMC卡 SD 總線模式的支持(不同模式下API函數(shù)名相同), 各API函數(shù)的入口增加了sd_struct結(jié)構(gòu)體, 用于支持多卡讀寫
**
** 2. SPI模式下和SD模式下共用 SDMMC_GetCardInfo() 和 SDMMC_CalTimeout()函數(shù)
**
** 3. sd_struct結(jié)構(gòu)體增加了成員多個成員變量, 訪問卡的時鐘及訪問卡的最大時鐘改為可動態(tài)獲取
**
** 4. SPI 模式下的命令函數(shù)使用SpiCmd_ 開頭, SD 模式下的命令使用 SdCmd_ 開頭
**
** 5. SPI 模式下與硬件相關(guān)的函數(shù)使用 SdSpiHal_ 開頭, SD 模式下與硬件相關(guān)的函數(shù)使用 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};
/* 超時時間因數(shù)表 timeout factor table */
const INT8U r2w_fator[8] = {1,2,4,8,16,32,64,128};
/* 最大傳輸速度尾數(shù)表, 原為小數(shù), 都乘 10 轉(zhuǎn)換為整數(shù) */
const INT8U tr_spval[16] = {0, 10, 12, 13, 15, 20, 25, 30, 35,
40, 45, 50, 55, 60, 70, 80};
/* 最大傳輸速度指數(shù)表, 單位 clock, 從100K ~ 100M */
const INT32U tr_spexp[4] = {100000, 1000000, 10000000, 100000000};
/*
***************************************************************************************************
用戶API函數(shù): 初始化,讀,寫,擦 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);
/*******************************************************************************************************************
** 函數(shù)名稱: SD_Initialize()
**
** 功能描述: SD/MMC 卡初始化: 復(fù)位卡,識別卡,獲取卡相關(guān)信息,使卡從識別模式進(jìn)入數(shù)據(jù)傳輸模式
**
** 輸 入: sd_struct *sds: SD/MMC卡信息結(jié)構(gòu)體
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SD_Initialize(sd_struct *sds)
{
INT8U ret, cidbuf[16];
if (sds == NULL) return SD_ERR_USER_PARAM; /* 函數(shù)入口參數(shù)錯誤 */
#if SD_UCOSII_EN
if (sds->pSemSD == NULL)
{
sds->pSemSD = OSSemCreate(1); /* 創(chuàng)建訪問卡信號量 */
if (sds->pSemSD == NULL)
return SD_ERR_CREATE_SEMSD;
}
if (sds->pSemSdmmcRW == NULL)
{
sds->pSemSdmmcRW = OSSemCreate(0); /* 創(chuàng)建讀寫擦卡等待信號量 */
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: 復(fù)位卡, 使卡進(jìn)入空閑狀態(tài) */
if (ret != SD_NO_ERR)
goto SDINIT_END;
ret = SDMMC_IdentifyCard(sds); /* CMD1或ACMD41: 識別卡, 進(jìn)入就緒狀態(tài) */
if (ret != SD_NO_ERR)
goto SDINIT_END;
ret = SdCmd_All_Send_CID(sds, 16, cidbuf); /* CMD2: 讀CID, 進(jìn)入識別狀態(tài) */
if (ret != SD_NO_ERR)
goto SDINIT_END;
ret = SdCmd_Set_Relative_Addr(sds); /* CMD3: 獲取RCA, 進(jìn)入待機(jī)狀態(tài) */
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); /* 設(shè)置訪問卡的clock為標(biāo)準(zhǔn)clock */
ret = SDMMC_CalTimeout(sds); /* 計(jì)算超時時間值 */
if (ret != SD_NO_ERR)
goto SDINIT_END;
ret = SDMMC_ConfigCard(sds); /* 設(shè)置卡相關(guān)參數(shù), 處于待機(jī)狀態(tài) */
SDINIT_END:
SD_ReleaseOSSem(sds); /* 釋放訪問卡信號量 */
return ret;
}
/*******************************************************************************************************************
** 函數(shù)名稱: SD_ReadBlock()
**
** 功能描述: 從SD/MMC卡中讀出一個數(shù)據(jù)塊
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結(jié)構(gòu)體
** INT32U blockaddr: 以塊為單位的塊地址, 例如, 卡開始的0 ~ 511字節(jié)為塊地址0, 512 ~ 1023字節(jié)的塊地址為1
**
** 輸 出: INT8U *recbuf : 接收緩沖區(qū),長度固定為 512 字節(jié)
**
** 返 回 值: 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; /* 函數(shù)入口參數(shù)錯誤 */
SD_RequestOSSem(sds); /* 向OS申請?jiān)L問卡信號量 */
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: 進(jìn)入傳輸狀態(tài) */
if (ret != SD_NO_ERR)
goto SDRD_BLK_END;
ret = SdHal_BeforeReadBlock(sds); /* 發(fā)送讀命令之前的準(zhǔn)備工作 */
if (ret != SD_NO_ERR)
goto SDRD_BLK_END;
ret = SdCmd_Read_Single_Block(sds, blockaddr); /* CMD17: 發(fā)送讀單塊命令 */
if (ret != SD_NO_ERR)
goto SDRD_BLK_END;
ret = SdHal_ReadBlock(sds, recbuf); /* 從卡接收數(shù)據(jù) */
if (ret != SD_NO_ERR)
goto SDRD_BLK_END;
SDRD_BLK_END:
SdCmd_Deselect_Card(sds, 0); /* CMD7: 退出傳輸狀態(tài) */
SD_ReleaseOSSem(sds); /* 釋放訪問卡信號量 */
return ret;
}
/*******************************************************************************************************************
** 函數(shù)名稱: SD_ReadMultiBlock()
**
** 功能描述: 從SD/MMC卡中讀出多個數(shù)據(jù)塊
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結(jié)構(gòu)體
** INT32U blockaddr: 以塊為單位的塊地址
** INT32U blocknum : 要讀取的塊的個數(shù)
**
** 輸 出: INT8U *recbuf : 接收緩沖區(qū), 長度512 * blocknum 字節(jié)
**
** 返 回 值: 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; /* 函數(shù)入口參數(shù)錯誤 */
SD_RequestOSSem(sds); /* 向OS申請?jiān)L問卡信號量 */
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: 進(jìn)入傳輸狀態(tài) */
if (ret != SD_NO_ERR)
goto SDRD_MBLK_END;
ret = SdHal_BeforeReadBlock(sds); /* 發(fā)送讀命令之前的準(zhǔn)備工作 */
if (ret != SD_NO_ERR)
goto SDRD_MBLK_END;
ret = SdCmd_Read_Multiple_Block(sds, blockaddr);/* 發(fā)送讀多塊命令 */
if (ret != SD_NO_ERR)
goto SDRD_MBLK_END;
for (i = 0; i < blocknum; i++)
{
ret = SdHal_ReadBlock(sds, recbuf); /* 接收來自卡的數(shù)據(jù) */
if (ret == SD_NO_ERR)
recbuf = recbuf + SD_BLOCKSIZE;
else
goto SDRD_MBLK_END;
if (i < (blocknum - 1))
{
ret = SdHal_BeforeReadBlock(sds); /* 接收來自卡數(shù)據(jù)之前的準(zhǔn)備工作 */
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: 退出傳輸狀態(tài) */
SD_ReleaseOSSem(sds);
return ret;
}
#endif
/*******************************************************************************************************************
** 函數(shù)名稱: SD_WriteBlock()
**
** 功能描述: 向SD/MMC卡中寫入一個塊
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結(jié)構(gòu)體
** INT32U blockaddr: 以塊為單位的塊地址, 例如, 卡開始的0 ~ 511字節(jié)為塊地址0, 512 ~ 1023字節(jié)的塊地址為1
** INT8U *sendbuf : 發(fā)送緩沖區(qū),長度固定為 512 字節(jié)
**
** 輸 出: 無
**
** 返 回 值: 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; /* 函數(shù)入口參數(shù)錯誤 */
SD_RequestOSSem(sds); /* 向OS申請?jiān)L問卡的信號量 */
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; /* 卡有寫保護(hù) */
goto SDWR_BLK_END;
}
ret = SdCmd_Select_Card(sds); /* CMD7: 進(jìn)入傳輸狀態(tài) */
if (ret != SD_NO_ERR)
goto SDWR_BLK_END;
ret = SdHal_BeforeWriteBlock(sds); /* 寫數(shù)據(jù)之前的準(zhǔn)備工作 */
if (ret != SD_NO_ERR)
goto SDWR_BLK_END;
ret = SdCmd_Write_Single_Block(sds, blockaddr); /* CMD24, 發(fā)送寫單塊命令 */
if (ret != SD_NO_ERR)
goto SDWR_BLK_END;
ret = SdHal_WriteBlock(sds, sendbuf); /* 往卡中寫入數(shù)據(jù) */
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: 退出傳輸狀態(tài) */
SD_ReleaseOSSem(sds);
return ret; /* 返回操作結(jié)果 */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SD_WriteMultiBlock()
**
** 功能描述: 向SD/MMC卡中寫入多個數(shù)據(jù)塊
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結(jié)構(gòu)體
** INT32U blockaddr: 以塊為單位的塊地址
** INT32U blocknum : 要寫入的塊的個數(shù)
** INT8U *sendbuf : 發(fā)送緩沖區(qū), 長度 512 * blocknum 字節(jié)
**
** 輸 出: 無
**
** 返 回 值: 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; /* 函數(shù)入口參數(shù)錯誤 */
SD_RequestOSSem(sds); /* 向OS申請?jiān)L問卡信號量 */
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; /* 卡有寫保護(hù) */
goto SDWR_MBLK_END;
}
ret = SdCmd_Select_Card(sds); /* CMD7: 進(jìn)入傳輸狀態(tài) */
if (ret != SD_NO_ERR)
goto SDWR_MBLK_END;
ret = SdHal_BeforeWriteBlock(sds); /* 發(fā)送數(shù)據(jù)前的準(zhǔn)備工作 */
if (ret != SD_NO_ERR)
goto SDWR_MBLK_END;
ret = SdCmd_Write_Multiple_Block(sds, blockaddr); /* CMD25, 發(fā)送寫多塊命令 */
if (ret != SD_NO_ERR)
goto SDWR_MBLK_END;
for (i = 0; i < blocknum; i++)
{
ret = SdHal_WriteBlock(sds, sendbuf); /* 寫入數(shù)據(jù) */
if (ret == SD_NO_ERR)
{
sendbuf = sendbuf + SD_BLOCKSIZE;
}
else
{ /* 寫失敗 */
SdCmd_Stop_Transmission(sds); /* 停止數(shù)據(jù)傳輸并等待忙結(jié)束 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -