📄 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总线硬件相关的操作函数
**
**
**------------------------------------------------------------------------------------------------------
** 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 LPC24xx_MCI_DMA_EN
INT32U *src_addr;
INT32U *dest_addr;
#endif
/* mci_struct 结构体成员 RxTxFlag 取值 */
#define MCI_RESET_FLAG 0xFF
#define MCI_CUR_REC 0x01
#define MCI_CUR_SEND 0x02
/* MCI数据传输结构体 */
typedef struct MCI_STRUCT
{
INT8U CurTran; // 当前数据传输类型, 可为MCI_CUR_REC或MCI_CUR_SEND
INT8U RxTxFlag; // 数据接收/发送标志, 用于标识接收/发送执行结果
INT8U *pRecBuf; // 接收数据缓冲区指针
INT8U *pSendBuf; // 发送数据缓冲区指针
INT32U RecCnt; // 接收数据计数器
INT32U SendCnt; // 发送数据计数器
sd_struct *psds; // 当前sd_struct结构体指针
}mci_struct;
volatile mci_struct lpc_mci; // mci_struct结构体变量
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);
/**********************************************
硬件抽象层接口函数实现文件
***********************************************/
/*******************************************************************************************************************
** 函数名称: SdHal_Initialize()
**
** 功能描述: 初始化访问卡的硬件条件
**
** 输 入: sd_struct *sds: 卡信息结构体
**
** 输 出: 无
**
** 返 回 值: 0: 正确 >0: 错误码, 见 sddriver.h 文件
**
** 主要工作: 1. 先给卡下电, 再给卡上电; 2. 设置访问卡的速度小于或等于 400KHz;
**
** 3. 使 CMD 线处于开漏状态; 4. 初始化相关硬件寄存器为适当的状态
********************************************************************************************************************/
INT8U SdHal_Initialize(sd_struct *sds)
{
// 卡下电并延时
SD_PowerOff();
MCI_Delay(1);
// 卡上电并初始化MCI相关引脚
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(); /* 配置卡写保护检测引脚 */
SD_WP_IN();
MCIPower = 0x02;
MCI_Delay(1); /* 延时 */
MCIPower |= 0x01;
MCIPower |= (1 << 6 ); /* CMD线处于开漏状态 */
// 设置访问卡时钟小于 400KHz
SdHal_SetMCIClock(sds, SD_RATE_SLOW);
// 清空 MCI 相关寄存器
MCICommand = 0;
MCIClear = 0x7FF; /* 清空MCI状态寄存器 */
MCIDataCtrl = 0;
MCIMask0 = 0; /* 屏蔽所有 MCI 中断 */
#if LPC24xx_MCI_DMA_EN
PCONP |= (1 << 29); /* 使能 GPDMA 时钟 */
#endif
return SD_NO_ERR;
}
/*******************************************************************************************************************
** 函数名称: SD_PowerOff()
**
** 功能描述: 给卡下电, 将
**
** 输 入: 无
**
** 输 出: 无
**
** 返 回 值: 无
********************************************************************************************************************/
void SD_PowerOff(void)
{
SD_POWER_GPIO();
SD_POWER_OUT();
SD_POWER_OFF(); /* 关闭 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); /* 关闭工作时钟 */
MCIPower = 0x00; /* 配置电源控制寄存器 */
MCIClock = 0;
//MCIClock &= ~(1 << 8); /* 关闭MCICLK时钟 */
}
/*******************************************************************************************************************
** 函数名称: SdHal_OpenDrainCmd()
**
** 功能描述: 设置 CMD 信号线的开漏状态
**
** 输 入: sd_struct *sds : 卡信息结构体
** INT8U bOpenDrain: > 0: CMD 信号线开漏; = 0: CMD 信号线处于非开漏
**
** 输 出: 无
**
** 返 回 值: 0: 正确 >0: 错误码, 见 sddriver.h 文件
**
** 主要工作: 1. 初始化相关硬件寄存器; 2. 先给卡下电, 再上电; 3. 设置访问卡的速度小于或等于 400KHz
**
** 4. 使 CMD 线处于开漏状态
********************************************************************************************************************/
void SdHal_OpenDrainCmd(sd_struct *sds, INT8U bOpenDrain)
{
if (bOpenDrain)
MCIPower |= (1 << 6 ); /* CMD线处于开漏状态 */
else
MCIPower &= ~(1 << 6 ); /* CMD线处于非开漏状态 */
}
/*******************************************************************************************************************
** 函数名称: SdHal_SendCmd()
**
** 功能描述: 发送一个SD/MMC命令, 并获得响应
**
** 输 入: sd_struct *sds: 卡信息结构体, 仅使用sds->card_posnum成员用于区分卡座
INT8U cmd: 命令索引(命令的[5:0]位)
** INT32U argument: 命令参数
** INT8U resptype: 响应类型, 取值可以为R0(即不需要响应), R1, R1B, R2, R3, R6
** INT8U resplen: 响应长度,
** 当响应为R0时, 取值为0(对应resp指针也可为空).
** 当响应为R1,R1B,R3,R6时, 取值4;
** 当响应为R2时, 取值为16(R2的bit[127:0]).
**
** 输 出: INT32U *resp: 响应内容, 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; /* 卡无须响应本命令 */
}
else if ((resptype == R1) || (resptype == R1B) || (resptype == R3) || (resptype == R6))
{
ExpectResp = EXPECT_SHORT_RESP; /* 短响应 */
}
else if (resptype == R2)
{
ExpectResp = EXPECT_LONG_RESP; /* 长响应 */
}
else
{
return SD_ERR_CMD_RESPTYPE; /* 错误的响应类型 */
}
MCI_SendCmd(cmd, argument, ExpectResp, 0); /* 发送命令并获取响应 */
ret = MCI_GetCmdResp(cmd, ExpectResp, resplen, resp);
if (ret != SD_NO_ERR)
return ret;
for (i = 0; i < 0x200; i++); /* 延时, 确保 MCICommand 寄存器在规定时间内不再次被写入 */
return ret;
}
/*******************************************************************************************************************
** 函数名称: SdHal_EnableMCIBusWidth()
**
** 功能描述: 使能SD/MMC主控器是否使能宽总线
**
** 输 入: sd_struct *sds: 卡信息结构体, 仅使用sds->card_posnum成员用于区分卡座
** 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);
}
/*******************************************************************************************************************
** 函数名称: SdHal_SetMCIClock()
**
** 功能描述: 设置读写SD/MMC卡时钟
**
** 输 入: sd_struct *sds : 卡信息结构体
** INT32U ClockRate: 要求的时钟速度. 取值SD_RATE_SLOW 时, 设置访问卡速度小于 400KHz
** 取值SD_RATE_NORMAL 时, 设置访问卡速度为卡的最大速度或主控器的最大速度
** 输 出: 无
**
** 返 回 值: 0: 正确 >0: 错误码, 见 sddriver.h 文件
**
** 注 意: 本函数有责任在ClockRate取不同的值时, 计算出相应的 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; /* 设置时钟小于等于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; /* 根据卡数据的最大传输速度计算分频值 */
//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 */
}
/*******************************************************************************************************************
** 函数名称: SdHal_CheckCard()
**
** 功能描述: 检测卡是否完全插入卡座中
**
** 输 入: sd_struct *sds: 卡信息结构体
**
** 输 出: 无
**
** 返 回 值: 1: 卡完全插入 0: 卡没有完全插入
********************************************************************************************************************/
INT8U SdHal_CheckCard(sd_struct *sds)
{
if (SD_INSERT_STATUS() != 0)
return 0; /* 未完全插入 */
else
return 1; /* 完全插入 */
}
/*******************************************************************************************************************
** 函数名称: SdHal_CheckCardWP()
**
** 功能描述: 检测卡写保护
**
** 输 入: sd_struct *sds: 卡信息结构体
**
** 输 出: 无
**
** 返 回 值: 1: 卡已写保护 0: 卡未写保护
********************************************************************************************************************/
INT8U SdHal_CheckCardWP(sd_struct *sds)
{
if (SD_WP_STATUS() != 0)
return 1; /* 写保护 */
else
return 0; /* 未写保护 */
}
/*******************************************************************************************************************
** 函数名称: SdHal_BeforeReadBlock()
**
** 功能描述: 在发送读单块命令之前, 给硬件控制器做一些事情的机会
**
** 输 入: sd_struct *sds : 卡信息结构体
**
** 输 出: 无
**
** 返 回 值: 0: 正确 >0: 错误码, 见 sddriver.h 文件
********************************************************************************************************************/
INT8U SdHal_BeforeReadBlock(sd_struct *sds)
{
MCIMask0 |= (DATA_RX_INT_MASK) | (FIFO_INT_MASK); /* 仅使能接收中断 */
MCIClear = 0x7FF; /* 清空清零寄存器的所有标志 */
MCIDataCtrl = 0; /* 数据控制寄存器清0 */
MCIDataTimer = sds->timeout_read; /* 读数据块超时值 */
MCIDataLength = SD_BLOCKSIZE; /* 块长度 */
MCIFifoCnt = 0; /* 清空接收FIFO计数器*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -