?? sdhal.c
字號:
lpc_mci.RecCnt = 0; /* 初始化mci_struct結構體全局變量lpc_mci */
lpc_mci.RxTxFlag = MCI_RESET_FLAG;
lpc_mci.psds = sds;
lpc_mci.CurTran = MCI_CUR_REC;
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函數名稱: SdHal_ReadBlock()
**
** 功能描述: 在發送讀單塊命令之后, 由硬件控制器實現讀取數據
**
** 輸 入: sd_struct *sds : 卡信息結構體
**
** 輸 出: INT8U *recbuf: 接收緩沖區, 大小為512字節
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_ReadBlock(sd_struct *sds, INT8U *recbuf)
{
INT32U DataCtrl = 0;
INT8U ret;
lpc_mci.pRecBuf = recbuf;
#if LPC23xx_MCI_DMA_EN
// DMA 控制器初始化
DMA_Init(1, P2M);
DMACC1Configuration |= 0x10001 | (0x04 << 1) | (0x00 << 6) | (0x06 << 11);
// 設置數據控制寄存器: 讀,塊傳輸,DMA傳輸,塊長度
DataCtrl |= ((1 << 0) | (1 << 1) | (1 << 3) | (SD_BLOCKSIZE_NBITS << 4));
#else
// 設置數據控制寄存器: 讀,塊傳輸,塊長度
DataCtrl |= ((1 << 0) | (1 << 1) | (SD_BLOCKSIZE_NBITS << 4));
#endif
#if SD_UCOSII_EN
OS_ENTER_CRITICAL();
MCIDataCtrl = DataCtrl; /* 啟動數據傳輸 */
OSSemPend(sds->pSemSdmmcRW, sds->timeout_read_os, &ret); /* 進入等待狀態 */
if (ret == OS_NO_ERR)
ret = lpc_mci.RxTxFlag; /* 返回數據接收結果 */
else if (ret == OS_TIMEOUT)
ret = SD_ERR_TIMEOUT_READ; /* 接收數據超時 */
else
ret = SD_ERR_WAIT_WRSEM; /* 等待信號量失敗 */
OS_EXIT_CRITICAL();
#else
MCIDataCtrl = DataCtrl; /* 啟動數據傳輸 */
do
{ /* 等待數據接收 */
if (lpc_mci.RxTxFlag == SD_NO_ERR)
break; /* 數據接收成功 */
}while (lpc_mci.RxTxFlag == MCI_RESET_FLAG);
ret = lpc_mci.RxTxFlag; /* 返回接收結果 */
#endif
MCIMask0 &= ~((DATA_RX_INT_MASK) | (FIFO_INT_MASK)); /* 僅禁止接收中斷 */
MCIMask1 = MCIMask0;
#if LPC23xx_MCI_DMA_EN
src_addr = (INT32U *)DMA_SRC; /* 取得 DMA 源地址 */
dest_addr = (INT32U *)DMA_DST; /* 取得 DMA 目標地址 */
if (ret == SD_NO_ERR)
memcpy(recbuf, dest_addr, 512); /* 返回接收到的數據 */
#endif
return ret;
}
/*******************************************************************************************************************
** 函數名稱: SdHal_BeforeWriteBlock()
**
** 功能描述: 在發送寫單塊命令之前, 給硬件控制器做一些事情的機會
**
** 輸 入: 無
**
** 輸 出: INT8U *recbuf: 接收緩沖區, 大小為512字節
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_BeforeWriteBlock(sd_struct *sds)
{
MCIMask0 = DATA_TX_INT_MASK | (FIFO_INT_MASK); /* 僅使能TX中斷 */
MCIMask1 = MCIMask0;
MCIClear = 0x7FF; /* 清空清零寄存器的所有標志 */
MCIDataCtrl = 0; /* 數據控制寄存器清0 */
MCIDataTimer = sds->timeout_write; /* 寫入寫數據超時值 */
MCIDataLength = SD_BLOCKSIZE; /* 數據塊的長度 */
MCIFifoCnt = 0;
lpc_mci.psds = sds; /* 初始化lpc_mci結構體變量成員 */
lpc_mci.RxTxFlag = MCI_RESET_FLAG;
lpc_mci.SendCnt = 0;
lpc_mci.CurTran = MCI_CUR_SEND;
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函數名稱: SdHal_WriteBlock()
**
** 功能描述: 在發送寫單塊命令之后, 由硬件控制器向卡發送數據
**
** 輸 入: 無
**
** 輸 出: INT8U *recbuf: 接收緩沖區, 大小為512字節
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_WriteBlock(sd_struct *sds, INT8U *sendbuf)
{
INT32U DataCtrl = 0;
INT8U ret;
#if LPC23xx_MCI_DMA_EN
src_addr = (INT32U *)DMA_SRC;
dest_addr = (INT32U *)DMA_DST;
//memcpy(sendbuf, src_addr, 512);
memcpy(src_addr, sendbuf, 512); /* 復制要寫入的數據到DMA源地址 */
DMA_Init(0, M2P); /* DMA控制器初始化 */
DMACC0Configuration |= 0x00001 | (0x00 << 1) | (0x04 << 6) | (0x05 << 11);
/* 設置數據控制寄存器: 寫, 塊傳輸, DMA, 數據長度 */
DataCtrl |= ((1 << 0) | (1 << 3) | (SD_BLOCKSIZE_NBITS << 4));
#else
lpc_mci.pSendBuf = sendbuf;
/* 設置數據控制寄存器: 讀, 塊傳輸, 數據長度 */
DataCtrl |= ((1 << 0) | (SD_BLOCKSIZE_NBITS << 4));
#endif
#if SD_UCOSII_EN
OS_ENTER_CRITICAL();
MCIDataCtrl = DataCtrl; /* 啟動數據傳輸 */
OSSemPend(sds->pSemSdmmcRW, sds->timeout_write_os, &ret); /* 進入等待狀態 */
if (ret == OS_NO_ERR)
ret = lpc_mci.RxTxFlag; /* 返回寫塊數據結果 */
else if (ret == OS_TIMEOUT)
ret = SD_ERR_TIMEOUT_WRITE; /* 返回等待超時 */
else
ret = SD_ERR_WAIT_WRSEM; /* OSSemPend()執行失敗 */
OS_EXIT_CRITICAL();
#else
MCIDataCtrl = DataCtrl; /* 啟動數據傳輸 */
do
{
if (lpc_mci.RxTxFlag == SD_NO_ERR)
break; /* 發送數據成功 */
}while (lpc_mci.RxTxFlag == MCI_RESET_FLAG);
ret = lpc_mci.RxTxFlag; /* 返回發送數據執行結果 */
#endif
MCIMask0 &= ~(DATA_TX_INT_MASK | FIFO_INT_MASK); /* 僅禁止TX中斷 */
MCIMask1 = MCIMask0;
return ret;
}
/*******************************************************************************************************************
** 函數名稱: SDMMC_WaitReadyforData()
**
** 功能描述: 等待卡可接收數據(等待卡中有空的接收緩沖區), 即等待卡狀態寄存器的 bit8 為1,
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結構體
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_WaitReadyforData(sd_struct *sds)
{
return (SdHal_WaitBusy(sds, BUSY_TYPE_RDY_DATA));
}
#define SD_UCOSII_SMALLWAIT 256 /* 運行于UCOS-II時的小等待時間(避免OSTimeDly(1)降低系統性能) */
#define CMD13_CLK_NUM 160 /* 一個CMD13大約需要160個clk */
/*******************************************************************************************************************
** 函數名稱: SdHal_WaitBusy()
**
** 功能描述: 等待卡編程或擦除結束, 即等待卡狀態由編程狀態變為傳輸狀態: prg --> tran
**
** 輸 入: sd_struct *sds : SD/MMC卡信息結構體
** INT32U BusyType : 等待忙類型, 取值為: SD_WAIT_WRITE 和 SD_WAIT_ERASE
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_WaitBusy(sd_struct *sds, INT32U busytype)
{
INT8U ret;
INT32U status, timeout = 0, cnt = 0;
INT32U stmask = CARD_STATUS_CURRENT_STATE;
INT32U stwait = CARD_STATUS_PRG; /* 等待時, 卡處于編程狀態 */
if (busytype == BUSY_TYPE_RDY_DATA)
{
timeout = sds->timeout_write / CMD13_CLK_NUM; /* 寫超時等待時間 */
stmask = CARD_STATUS_RDY_DATA;
stwait = 0; /* 等待時, 卡的接收緩沖區未就緒 */
}
else if (busytype == BUSY_TYPE_PROG)
timeout = sds->timeout_write / CMD13_CLK_NUM; /* 擦除超時等待時間 */
else if (busytype == BUSY_TYPE_ERASE)
timeout = sds->timeout_erase / CMD13_CLK_NUM;
#if SD_UCOSII_EN
timeout = SD_UCOSII_SMALLWAIT; /* 先進行快速查詢, 再每隔1 os tick查詢 */
#endif
do
{
ret = SdCmd_Send_Status(sds, &status); /* 讀取卡的狀態 */
if (ret != SD_NO_ERR)
return ret;
if (!SdHal_CheckCard(sds)) /* 檢測卡是否拔出 */
return SD_ERR_NO_CARD;
cnt++;
}while(((status & stmask) == stwait) && (cnt < timeout));
#if SD_UCOSII_EN
if (cnt >= timeout)
{ /* 很少等待后卡仍忙 */
if ((busytype == BUSY_TYPE_RDY_DATA) || (busytype == BUSY_TYPE_PROG))
timeout = sds->timeout_write_os;
else
timeout = sds->timeout_erase_os;
cnt = 0;
do
{
OSTimeDly(1); /* 操作系統掛起1 tick */
ret = SdCmd_Send_Status(sds, &status); /* 讀取卡的狀態 */
if (ret != SD_NO_ERR)
return ret;
if (!SdHal_CheckCard(sds)) /* 檢測卡是否拔出 */
return SD_ERR_NO_CARD;
cnt++;
}while(((status & stmask) == stwait) && (cnt < timeout));
}
#endif
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函數名稱: MCI_Delay()
**
** 功能描述: 延時函數
**
** 輸 入: INT16U val: 延時值, 1大約相當于5ms
**
** 輸 出: 無
**
** 返 回 值: 無
********************************************************************************************************************/
void MCI_Delay(INT16U val)
{
#if !SD_UCOSII_EN
INT16U i,j;
for (i = 0; i < val; i++)
for (j = 0; j < 0xC000; j++);
#else
OSTimeDly(val);
#endif
}
/*******************************************************************************************************************
** 函數名稱: MCI_SendCmd()
**
** 功能描述: 發送命令給卡, 但不獲取響應
**
** 輸 入: INT32U CmdIndex : 命令索引
** INT32U Argument : 命令參數
** INT32U ExpectResp : 期望得到的回復
** INT32U AllowTimeout: 是否允許超時
**
** 輸 出: 無
**
** 返 回 值: 無
********************************************************************************************************************/
void MCI_SendCmd(INT32U CmdIndex, INT32U Argument, INT32U ExpectResp, INT32U AllowTimeout)
{
INT32U CmdData = 0, i;
INT32U CmdStatus;
while ((CmdStatus = MCIStatus) & MCI_CMD_ACTIVE) /* 命令正在處理中 */
{
MCICommand = 0;
MCIClear = CmdStatus | MCI_CMD_ACTIVE; /* 清除相關狀態 */
for(i = 0; i < 0x20; i++);
}
CmdData |= (CmdIndex & 0x3F); /* 命令索引只有bit0 ~ bit5 有效 */
if (ExpectResp == EXPECT_NO_RESP) /* 無響應類型 */
{
CmdData &= ~((1 << 6) | (1 << 7)); /* 清除短響應和長響應位 */
}
else if (ExpectResp == EXPECT_SHORT_RESP) /* 希望得到短響應 */
{
CmdData |= (1 << 6);
}
else if (ExpectResp == EXPECT_LONG_RESP) /* 希望得到長響應 */
{
CmdData |= (1 << 6) | (1 << 7);
}
if (AllowTimeout) /* 是否允許超時中斷 */
CmdData |= (1 << 8);
else
CmdData &= ~(1 << 8);
CmdData |= (1 << 10); /* 使能發送命令 */
MCIArgument = Argument; /* 命令參數 */
MCICommand = CmdData; /* 啟動命令發送 */
}
/*******************************************************************************************************************
** 函數名稱: MCI_GetCmdResp()
**
** 功能描述: 從卡獲取響應, 該函數與MCI_SendCmd()成對使用
**
** 輸 入: INT32U ExpectCmdData: SD/MMC 命令碼
** INT32U ExpectResp : 希望的響應, 取值為: EXPECT_NO_RESP, EXPECT_SHORT_RESP, EXPECT_LONG_RESP
** INT8U resplen : 響應長度
**
**
** 輸 出: INT32U *CmdResp : 響應內容, 長度為resplen
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U MCI_GetCmdResp(INT32U ExpectCmdData, INT32U ExpectResp, INT8U resplen, INT32U *CmdResp)
{
INT32U LastCmdIndex;
INT32U CmdRespStatus = 0;
while (1)
{ /* 不斷循環等待卡的響應 */
CmdRespStatus = MCIStatus;
if (CmdRespStatus & (MCI_CMD_TIMEOUT))
{ /* 超時錯誤, 超時周期固定為64個MCICLK時鐘周期 */
MCIClear = CmdRespStatus | MCI_CMD_TIMEOUT;
MCICommand = 0; /* 清空命令寄存器及參數寄存器 */
MCIArgument = 0xFFFFFFFF;
return SD_ERR_CMD_TIMEOUT; /* 返回響應命令超時錯誤 */
}
if (CmdRespStatus & MCI_CMD_CRC_FAIL)
{ /* CRC校驗失敗錯誤 */
MCIClear = CmdRespStatus | MCI_CMD_CRC_FAIL;
LastCmdIndex = MCICommand & 0x003F;
if ((LastCmdIndex == SEND_OP_COND) || (LastCmdIndex == SEND_APP_OP_COND)
|| (LastCmdIndex == STOP_TRANSMISSION))
{ /* 忽略命令 SEND_OP_COND和STOP_TRANSMISSION的CRC校驗 */
MCICommand = 0;
MCIArgument = 0xFFFFFFFF;
break;
}
else
return SD_ERR_CMD_RESPCRC; /* 返回響應命令CRC校驗失敗錯誤 */
}
else if (CmdRespStatus & MCI_CMD_RESP_END)
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -