?? sdhal.c
字號:
/****************************************Copyright (c)**************************************************
** Guangzhou ZLG-MCU Development Co.,LTD.
** graduate school
** http://www.zlgmcu.com
**
**--------------File Info-------------------------------------------------------------------------------
** File name: sdhal.c
** Last modified Date: 2007-5-20
** Last Version: V2.0
** Descriptions: SD/MMC卡讀寫模塊: 硬件抽象層 ---- SD總線硬件相關(guān)的操作函數(shù)
**
**
**------------------------------------------------------------------------------------------------------
** Created by: Ming Yuan Zheng
** Created date: 2005-1-6
** Version: V1.0
** Descriptions: The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
********************************************************************************************************/
#include "sdconfig.h"
#if SDBUS_MODE_EN
#if LPC23xx_MCI_DMA_EN
INT32U *src_addr;
INT32U *dest_addr;
#endif
/* mci_struct 結(jié)構(gòu)體成員 RxTxFlag 取值 */
#define MCI_RESET_FLAG 0xFF
#define MCI_CUR_REC 0x01
#define MCI_CUR_SEND 0x02
/* MCI數(shù)據(jù)傳輸結(jié)構(gòu)體 */
typedef struct MCI_STRUCT
{
INT8U CurTran; // 當(dāng)前數(shù)據(jù)傳輸類型, 可為MCI_CUR_REC或MCI_CUR_SEND
INT8U RxTxFlag; // 數(shù)據(jù)接收/發(fā)送標(biāo)志, 用于標(biāo)識接收/發(fā)送執(zhí)行結(jié)果
INT8U *pRecBuf; // 接收數(shù)據(jù)緩沖區(qū)指針
INT8U *pSendBuf; // 發(fā)送數(shù)據(jù)緩沖區(qū)指針
INT32U RecCnt; // 接收數(shù)據(jù)計數(shù)器
INT32U SendCnt; // 發(fā)送數(shù)據(jù)計數(shù)器
sd_struct *psds; // 當(dāng)前sd_struct結(jié)構(gòu)體指針
}mci_struct;
volatile mci_struct lpc_mci; // mci_struct結(jié)構(gòu)體變量
void SD_PowerOff(void);
void MCI_Delay(INT16U val);
void MCI_SendCmd(INT32U CmdIndex, INT32U Argument, INT32U ExpectResp, INT32U AllowTimeout );
INT8U MCI_GetCmdResp(INT32U ExpectCmdData, INT32U ExpectResp, INT8U resplen, INT32U *CmdResp);
/**********************************************
硬件抽象層接口函數(shù)實(shí)現(xiàn)文件
***********************************************/
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_Initialize()
**
** 功能描述: 初始化訪問卡的硬件條件
**
** 輸 入: sd_struct *sds: 卡信息結(jié)構(gòu)體
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
**
** 主要工作: 1. 先給卡下電, 再給卡上電; 2. 設(shè)置訪問卡的速度小于或等于 400KHz;
**
** 3. 使 CMD 線處于開漏狀態(tài); 4. 初始化相關(guān)硬件寄存器為適當(dāng)?shù)臓顟B(tài)
********************************************************************************************************************/
INT8U SdHal_Initialize(sd_struct *sds)
{
// 卡下電并延時
SD_PowerOff();
MCI_Delay(1);
// 卡上電并初始化MCI相關(guān)引腳
SD_POWER_ON();
PCONP |= (1 << 28); /* 使能MCI控制器工作時鐘 */
MCI_CLK_PIN(); /* 配置MCI接口各功能引腳 */
MCI_CMD_PIN();
MCI_DAT0_PIN();
MCI_DAT1_PIN();
MCI_DAT2_PIN();
MCI_DAT3_PIN();
SD_INSERT_GPIO(); /* 配置卡插入檢測引腳 */
SD_INSERT_IN();
SD_WP_GPIO(); /* 配置卡寫保護(hù)檢測引腳 */
SD_WP_IN();
MCIPower = 0x02;
MCI_Delay(1); /* 延時 */
MCIPower |= 0x01;
MCIPower |= (1 << 6 ); /* CMD線處于開漏狀態(tài) */
// 設(shè)置訪問卡時鐘小于 400KHz
SdHal_SetMCIClock(sds, SD_RATE_SLOW);
// 清空 MCI 相關(guān)寄存器
MCICommand = 0;
MCIClear = 0x7FF; /* 清空MCI狀態(tài)寄存器 */
MCIDataCtrl = 0;
MCIMask0 = 0;
MCIMask1 = MCIMask0; /* 屏蔽所有 MCI 中斷 */
#if LPC23xx_MCI_DMA_EN
PCONP |= (1 << 29); /* 使能 GPDMA 時鐘 */
#endif
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函數(shù)名稱: SD_PowerOff()
**
** 功能描述: 給卡下電, 將
**
** 輸 入: 無
**
** 輸 出: 無
**
** 返 回 值: 無
********************************************************************************************************************/
void SD_PowerOff(void)
{
SD_POWER_GPIO();
SD_POWER_OUT();
SD_POWER_OFF(); /* 關(guān)閉 SD 卡電源 turn off power of sd card */
MCI_CLK_GPIO(); /* 配置MCI接口各功能引腳 */
MCI_CMD_GPIO();
MCI_DAT0_GPIO();
MCI_DAT1_GPIO();
MCI_DAT2_GPIO();
MCI_DAT3_GPIO();
MCI_CLK_OUT(); /* 配置MCI接口各功能引腳 */
MCI_CMD_OUT();
MCI_DAT0_OUT();
MCI_DAT1_OUT();
MCI_DAT2_OUT();
MCI_DAT3_OUT();
MCI_CLK_CLR(); /* 配置MCI接口各功能引腳 */
MCI_CMD_CLR();
MCI_DAT0_CLR();
MCI_DAT1_CLR();
MCI_DAT2_CLR();
MCI_DAT3_CLR();
PCONP &= ~(1 << 28); /* 關(guān)閉工作時鐘 */
MCIPower = 0x00; /* 配置電源控制寄存器 */
MCIClock = 0;
//MCIClock &= ~(1 << 8); /* 關(guān)閉MCICLK時鐘 */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_OpenDrainCmd()
**
** 功能描述: 設(shè)置 CMD 信號線的開漏狀態(tài)
**
** 輸 入: sd_struct *sds : 卡信息結(jié)構(gòu)體
** INT8U bOpenDrain: > 0: CMD 信號線開漏; = 0: CMD 信號線處于非開漏
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
**
** 主要工作: 1. 初始化相關(guān)硬件寄存器; 2. 先給卡下電, 再上電; 3. 設(shè)置訪問卡的速度小于或等于 400KHz
**
** 4. 使 CMD 線處于開漏狀態(tài)
********************************************************************************************************************/
void SdHal_OpenDrainCmd(sd_struct *sds, INT8U bOpenDrain)
{
if (bOpenDrain)
MCIPower |= (1 << 6 ); /* CMD線處于開漏狀態(tài) */
else
MCIPower &= ~(1 << 6 ); /* CMD線處于非開漏狀態(tài) */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_SendCmd()
**
** 功能描述: 發(fā)送一個SD/MMC命令, 并獲得響應(yīng)
**
** 輸 入: sd_struct *sds: 卡信息結(jié)構(gòu)體, 僅使用sds->card_posnum成員用于區(qū)分卡座
INT8U cmd: 命令索引(命令的[5:0]位)
** INT32U argument: 命令參數(shù)
** INT8U resptype: 響應(yīng)類型, 取值可以為R0(即不需要響應(yīng)), R1, R1B, R2, R3, R6
** INT8U resplen: 響應(yīng)長度,
** 當(dāng)響應(yīng)為R0時, 取值為0(對應(yīng)resp指針也可為空).
** 當(dāng)響應(yīng)為R1,R1B,R3,R6時, 取值4;
** 當(dāng)響應(yīng)為R2時, 取值為16(R2的bit[127:0]).
**
** 輸 出: INT32U *resp: 響應(yīng)內(nèi)容, bit127在resp[0]的bit32
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_SendCmd(sd_struct *sds, INT8U cmd, INT32U argument, INT8U resptype, INT32U *resp, INT8U resplen)
{
INT32U ExpectResp, i;
INT32U ret;
if (resptype == R0)
{
ExpectResp = EXPECT_NO_RESP; /* 卡無須響應(yīng)本命令 */
}
else if ((resptype == R1) || (resptype == R1B) || (resptype == R3) || (resptype == R6))
{
ExpectResp = EXPECT_SHORT_RESP; /* 短響應(yīng) */
}
else if (resptype == R2)
{
ExpectResp = EXPECT_LONG_RESP; /* 長響應(yīng) */
}
else
{
return SD_ERR_CMD_RESPTYPE; /* 錯誤的響應(yīng)類型 */
}
MCI_SendCmd(cmd, argument, ExpectResp, 0); /* 發(fā)送命令并獲取響應(yīng) */
ret = MCI_GetCmdResp(cmd, ExpectResp, resplen, resp);
if (ret != SD_NO_ERR)
return ret;
for (i = 0; i < 0x200; i++); /* 延時, 確保 MCICommand 寄存器在規(guī)定時間內(nèi)不再次被寫入 */
return ret;
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_EnableMCIBusWidth()
**
** 功能描述: 使能SD/MMC主控器是否使能寬總線
**
** 輸 入: sd_struct *sds: 卡信息結(jié)構(gòu)體, 僅使用sds->card_posnum成員用于區(qū)分卡座
** INT32U bWidth : > 0: 使能寬總線; 0: 禁止寬總線
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
void SdHal_EnableMCIBusWidth(sd_struct *sds, INT32U bWidth)
{
if (bWidth != 0)
MCIClock |= (1 << 11);
else
MCIClock &= ~(1 << 11);
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_SetMCIClock()
**
** 功能描述: 設(shè)置讀寫SD/MMC卡時鐘
**
** 輸 入: sd_struct *sds : 卡信息結(jié)構(gòu)體
** INT32U ClockRate: 要求的時鐘速度. 取值SD_RATE_SLOW 時, 設(shè)置訪問卡速度小于 400KHz
** 取值SD_RATE_NORMAL 時, 設(shè)置訪問卡速度為卡的最大速度或主控器的最大速度
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
**
** 注 意: 本函數(shù)有責(zé)任在ClockRate取不同的值時, 計算出相應(yīng)的 sds->clkval 值, 必須大于0.
**
********************************************************************************************************************/
void SdHal_SetMCIClock(sd_struct *sds, INT32U ClockRate)
{
INT32U i;
INT32 div = 0;
sds->host_clkval = 400000;
PCLKSEL1 &= ~(0x03 << 24);
PCLKSEL1 |= 0x01 << 24; /* MCICLK = Fcclk */
if (ClockRate == SD_RATE_SLOW)
{
div = MCLKDIV_SLOW; /* 設(shè)置時鐘小于等于400KHz */
sds->host_clkval = Fcclk / (div + 1) / 2; /* MCI 總線周期頻率 = MCLK / (2 * (div + 1)) */
}
else if (ClockRate == SD_RATE_NORMAL)
{
//div = Fcclk / sds->card_transpeed / 2 - 1; /* 根據(jù)卡數(shù)據(jù)的最大傳輸速度計算分頻值 */
//if (div < 0) div = 0;
//if (div > 254) div = 254;
div = MCLKDIV_NORMAL;
sds->host_clkval = Fcclk / (div + 1) / 2; /* MCI 總線周期頻率 = MCLK / (2 * (div + 1)) */
}
MCIClock &= ~0xFF;
MCIClock = (1 << 8) | (1 << 9) | div;
for (i = 0; i < 0x10; i++); /* 在下次寫MCIClock前, 延時 3MCLK + 2PCLK */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_CheckCard()
**
** 功能描述: 檢測卡是否完全插入卡座中
**
** 輸 入: sd_struct *sds: 卡信息結(jié)構(gòu)體
**
** 輸 出: 無
**
** 返 回 值: 1: 卡完全插入 0: 卡沒有完全插入
********************************************************************************************************************/
INT8U SdHal_CheckCard(sd_struct *sds)
{
if (SD_INSERT_STATUS() != 0)
return 0; /* 未完全插入 */
else
return 1; /* 完全插入 */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_CheckCardWP()
**
** 功能描述: 檢測卡寫保護(hù)
**
** 輸 入: sd_struct *sds: 卡信息結(jié)構(gòu)體
**
** 輸 出: 無
**
** 返 回 值: 1: 卡已寫保護(hù) 0: 卡未寫保護(hù)
********************************************************************************************************************/
INT8U SdHal_CheckCardWP(sd_struct *sds)
{
if (SD_WP_STATUS() != 0)
return 1; /* 寫保護(hù) */
else
return 0; /* 未寫保護(hù) */
}
/*******************************************************************************************************************
** 函數(shù)名稱: SdHal_BeforeReadBlock()
**
** 功能描述: 在發(fā)送讀單塊命令之前, 給硬件控制器做一些事情的機(jī)會
**
** 輸 入: sd_struct *sds : 卡信息結(jié)構(gòu)體
**
** 輸 出: 無
**
** 返 回 值: 0: 正確 >0: 錯誤碼, 見 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_BeforeReadBlock(sd_struct *sds)
{
MCIMask0 |= (DATA_RX_INT_MASK) | (FIFO_INT_MASK); /* 僅使能接收中斷 */
MCIMask1 = MCIMask0;
MCIClear = 0x7FF; /* 清空清零寄存器的所有標(biāo)志 */
MCIDataCtrl = 0; /* 數(shù)據(jù)控制寄存器清0 */
MCIDataTimer = sds->timeout_read; /* 讀數(shù)據(jù)塊超時值 */
MCIDataLength = SD_BLOCKSIZE; /* 塊長度 */
MCIFifoCnt = 0; /* 清空接收FIFO計數(shù)器*/
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -