/*
* --------------"拉普兰德K60底层库"-----------------
*
* 测试硬件平台:LPLD_K60 Card
* 版权所有:北京拉普兰德电子技术有限公司
* 网络销售:http://laplenden.taobao.com
* 公司门户:http://www.lpld.cn
*
* 文件名: HAL_SDHC.c
* 用途: SDHC底层模块相关函数
* 最后修改日期: 20130214
*
* 开发者使用协议:
* 本代码面向所有使用者开放源代码,开发者可以随意修改源代码。但本段及以上注释应
* 予以保留,不得更改或删除原版权所有者姓名。二次开发者可以加注二次版权所有者,
* 但应在遵守此协议的基础上,开放源代码、不得出售代码本身。
*
* 版权说明:
* SDHC模块驱动程序摘取自飞思卡尔MQX底层驱动,部分功能由拉普兰德修改。
* HAL_SDHC.h及HAL_SDHC.c内的代码版权归飞思卡尔公司享有。
*/
#include "HAL_SDHC.h"
//SD卡信息全局变量
SDCARD_STRUCT_PTR sdcard_ptr;
//引用内核时钟
extern int core_clk_khz;
/*
* LPLD_SDHC_InitGPIO
* 初始化SDHC模块相关的GPIO引脚,并使能SDHC寄存器时钟
*
* 参数:
* init--PCR寄存器掩码
*
* 输出:
* 无
*/
static void LPLD_SDHC_InitGPIO(uint32 init)
{
PORTE_PCR0 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D1 */
PORTE_PCR1 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D0 */
PORTE_PCR2 = init & (PORT_PCR_MUX(4) | PORT_PCR_DSE_MASK); /* SDHC.CLK */
PORTE_PCR3 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.CMD */
PORTE_PCR4 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D3 */
PORTE_PCR5 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D2 */
PORTD_PCR12 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D4 */
PORTD_PCR13 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D5 */
PORTD_PCR14 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D6 */
PORTD_PCR15 = init & (PORT_PCR_MUX(4) | PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_DSE_MASK); /* SDHC.D7 */
SIM_SCGC3 |= SIM_SCGC3_ESDHC_MASK; ///sd
}
/*
* LPLD_SDHC_SetBaudrate
* 设置SDHC波特率
*
* 参数:
* clock--模块输入时钟,即core_clk_khz*1000,单位Hz
* baud--SDHC期望时钟频率,单位Hz
*
* 输出:
* 无
*/
static void LPLD_SDHC_SetBaudrate(uint32 clock, uint32 baud)
{
uint32 i,pres, div, min, minpres = 0x80, mindiv = 0x0F;
int_32 val;
//找到相近的分频因子
min = (uint32)-1;
for (pres = 2; pres <= 256; pres <<= 1)
{
for (div = 1; div <= 16; div++)
{
val = pres * div * baud - clock;
if (val >= 0)
{
if (min > val)
{
min = val;
minpres = pres;
mindiv = div;
}
}
}
}
//禁止SDHC模块时钟
SDHC_BASE_PTR->SYSCTL &= (~ SDHC_SYSCTL_SDCLKEN_MASK); //SD时钟 主机控制器停止SDCLK
//修改分频因子
div = SDHC_BASE_PTR->SYSCTL & (~ (SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DVS_MASK));
SDHC_BASE_PTR->SYSCTL = div | (SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_SDCLKFS(minpres >> 1) | SDHC_SYSCTL_DVS(mindiv - 1));
//等在时钟稳定
while (0 == (SDHC_BASE_PTR->PRSSTAT & SDHC_PRSSTAT_SDSTB_MASK))
{
for(i = 0;i < 2000;i++)
{};
};
//使能SDHC模块时钟
SDHC_BASE_PTR->SYSCTL |= SDHC_SYSCTL_SDCLKEN_MASK; //使能SDHC模块时钟
SDHC_BASE_PTR->IRQSTAT |= SDHC_IRQSTAT_DTOE_MASK;
}
/*
* LPLD_SDHC_IsRunning
* 获取SDHC模块运行状态
*
* 参数:
* 无
*
* 输出:
* TRUE--正在运行
* FALSE--停止运行
*/
static boolean LPLD_SDHC_IsRunning(void)
{
return (0 != (SDHC_BASE_PTR->PRSSTAT & (SDHC_PRSSTAT_RTA_MASK | SDHC_PRSSTAT_WTA_MASK | SDHC_PRSSTAT_DLA_MASK | SDHC_PRSSTAT_CDIHB_MASK | SDHC_PRSSTAT_CIHB_MASK)));
}
/*
* LPLD_SDHC_WaitStatus
* 等待指定状态标志位置位
*
* 参数:
* mask--状态标志位掩码
*
* 输出:
* 状态标志
*/
static uint32 LPLD_SDHC_WaitStatus(uint32 mask)
{
uint32 result;
uint32 timeout = -1;
do
{
result = SDHC_IRQSTAT & mask;
timeout--;
}
while((0 == result) && (timeout));
if(timeout)
return result;
return 0;
}
/*
* LPLD_SDHC_Init
* SDHC模块初始化函数
*
* 参数:
* coreClk--系統主频,单位Hz
* baud--SDHC期望时钟频率,单位Hz
*
* 输出:
* STA_OK--状态正常
* STA_NOINIT--驱动未初始化
* STA_NODISK--为插入卡
* STA_PROTECT--卡写保护
*/
static DRESULT LPLD_SDHC_Init(uint32 coreClk, uint32 baud)
{
sdcard_ptr->CARD = ESDHC_CARD_MMC;
//禁用GPIO的SDHC复用功能
LPLD_SDHC_InitGPIO (0);
//复位SDHC模块
SDHC_BASE_PTR->SYSCTL = SDHC_SYSCTL_RSTA_MASK | SDHC_SYSCTL_SDCLKFS(0x80); ////RSTA 全部软件复位
while (SDHC_BASE_PTR->SYSCTL & SDHC_SYSCTL_RSTA_MASK)
{ };
//初始化寄存器值
SDHC_BASE_PTR->VENDOR = 0;
SDHC_BASE_PTR->BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_BASE_PTR->PROCTL = SDHC_PROCTL_EMODE(ESDHC_PROCTL_EMODE_LITTLE) | SDHC_PROCTL_D3CD_MASK;
SDHC_BASE_PTR->WML = SDHC_WML_RDWML(16) | SDHC_WML_WRWML(16);
//设置SDHC初始化时钟,最好不要超过400kHz
LPLD_SDHC_SetBaudrate (coreClk, baud);
//等待
while (SDHC_BASE_PTR->PRSSTAT & (SDHC_PRSSTAT_CIHB_MASK | SDHC_PRSSTAT_CDIHB_MASK))
{ };
//使能GPIO的SDHC复用
LPLD_SDHC_InitGPIO (0xFFFF);
//使能各种请求
SDHC_BASE_PTR->IRQSTAT = 0xFFFF;
SDHC_BASE_PTR->IRQSTATEN = SDHC_IRQSTATEN_DEBESEN_MASK
| SDHC_IRQSTATEN_DCESEN_MASK
| SDHC_IRQSTATEN_CIESEN_MASK
| SDHC_IRQSTATEN_CEBESEN_MASK
| SDHC_IRQSTATEN_CCESEN_MASK
| SDHC_IRQSTATEN_CTOESEN_MASK
| SDHC_IRQSTATEN_BRRSEN_MASK
| SDHC_IRQSTATEN_BWRSEN_MASK
| SDHC_IRQSTATEN_CRMSEN_MASK
| SDHC_IRQSTATEN_TCSEN_MASK
| SDHC_IRQSTATEN_CCSEN_MASK
| SDHC_IRQSTATEN_DMAESEN_MASK;
//DMA Interrupt Status Enable
//等待80个初始时钟
SDHC_BASE_PTR->SYSCTL |= SDHC_SYSCTL_INITA_MASK; ////激活初始化 soup20140115
while (SDHC_BASE_PTR->SYSCTL & SDHC_SYSCTL_INITA_MASK)
{ };
return RES_OK;
}
/*
* LPLD_SDHC_SendCommand
* 向SD卡发送指定CMD命令
*
* 参数:
* command--SDHC命令信息结构体
*
* 输出:
* DRESULT--磁盘功能返回值
*/
static DRESULT LPLD_SDHC_SendCommand(ESDHC_COMMAND_STRUCT_PTR command)
{
uint32 xfertyp;
uint32 blkattr;
//检查命令
xfertyp = command->COMMAND;
if (ESDHC_XFERTYP_CMDTYP_RESUME == ((xfertyp & SDHC_XFERTYP_CMDTYP_MASK) >> SDHC_XFERTYP_CMDTYP_SHIFT)) //重新开始//CCCR写IO中止时CMD12 CMD52命令
{
//恢复类型命令必须设置DPSEL位
xfertyp |= SDHC_XFERTYP_DPSEL_MASK; ////数据被递交且使用DAT线
}
if ((0 != command->BLOCKS) && (0 != command->BLOCKSIZE))
{
xfertyp |= SDHC_XFERTYP_DPSEL_MASK;
if (command->BLOCKS != 1)
{
//多块传输
xfertyp |= SDHC_XFERTYP_MSBSEL_MASK;
}
if ((uint32)-1 == command->BLOCKS)
{
//大量传输
blkattr = SDHC_BLKATTR_BLKSIZE(command->BLOCKSIZE) | SDHC_BLKATTR_BLKCNT(0xFFFF);
}
else
{
blkattr = SDHC_BLKATTR_BLKSIZE(command->BLOCKSIZE) | SDHC_BLKATTR_BLKCNT(command->BLOCKS);
xfertyp |= SDHC_XFERTYP_BCEN_MASK;
}
}
else
{
blkattr = 0;
}
//卡移除状态清除
SDHC_BASE_PTR->IRQSTAT |= SDHC_IRQSTAT_CRM_MASK;
//等待CMD线空闲
while (SDHC_BASE_PTR->PRSSTAT & SDHC_PRSSTAT_CIHB_MASK)
{ };
//初始化命令
SDHC_BA