⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sddriver.c

📁 SD卡驱动 SD_CARD_TIMEOUT 当一个SD卡的操作超出时限
💻 C
字号:
#include "SystemParameter.h"
#include "UART_API.h"
#include "SPI0_API.h"
#include "SD_API.h"
#include "MyCRC.h"
#include "TimeCount.h"

#include <LPC2103.h>

volatile unsigned char SD_CardState;

volatile unsigned char SD_CSD_Register[16];

unsigned char SD_CommandBuffer[6] = {0x40,0,0,0,0,0x95};

struct SD_Info MySD;

//                当前 SD 卡允许的最大通讯速度
volatile int         SD_Max_Rate = 1000000;



//// TestSDCardState ---- TestSDCardState ---- TestSDCardState ---- TestSDCardState ---- TestSDCardS
//
//      检查 SD 卡槽内的 SD 卡的门状态、是否已经插入和它的写保护开关状态。
//
//      返回值:
//          0   -   检查完成,状态被设置到 SD_CardState 变量中
//          -1  -   SPI0 总线被其它设备占用
//          -2  -   SD 卡槽内没有 SD 卡,或卡门被打开
//
extern int TestSDCardState(void)
{
  unsigned int  TempData;

  //  清除 SD 卡状态变量的三个待检状态
  SD_CardState &= ~(SD_CARD_EXIST | SD_CARD_WRITE_PROTECT | SD_CARD_DOOR_CLOSE);

  // 首先检查 LCD 是否在使用信号线,如果的确被 LCD 占用,则在此等待它们被释放
  while((FIOPIN & LCD_E) == 0)  {;}

  //  重新设定 IO 线为输入状态,注意:FIODIR寄存器不可读取,否则会导致其值改变
        FIODIR = FAST_IO0_DIR & (~SD_TEST_PIN);

        //        等待小小的延时,确保IO状态的转换时间
        for(TempData = 0; TempData<4; TempData++) {;}

  //  读取状态卡槽的插卡开关和写保护开关状态
    TempData = FIOPIN;

  //  将占用的两根 IO 线还原为输出,供 LCD 模块使用
    FIODIR = FAST_IO0_DIR;

  //  设定卡槽的插卡状态,如果为高,则卡槽内没有插入卡体
    SD_CardState |= (TempData & SD_SELF_PIN) ? 0 : SD_CARD_EXIST;

  //  设定插卡的写保护状态,如果为高,则写保护被设定,此时不可对进行卡写入操作
    if (SD_CardState & SD_CARD_EXIST) 
        SD_CardState |= (TempData & SD_PROTECT_PIN) ? SD_CARD_WRITE_PROTECT : 0;

  //  设定卡槽的门状态,如果为高,则卡门被打开
    SD_CardState |= (TempData & SD_DOOR_PIN) ? 0 : SD_CARD_DOOR_CLOSE;
    
  // 如卡门关闭和卡槽内插入了卡体,返回 0
        TempData = SD_CardState & (SD_CARD_DOOR_CLOSE | SD_CARD_EXIST);
  if         ( TempData == SD_CARD_DOOR_CLOSE | SD_CARD_EXIST)
                return 0;

  //  卡门打开(用户可能抽拔卡)、卡槽内无卡,则清除卡有效的相关状态,并返回-2,
  //  保留本次设置的 SD 卡状态变量的三个状态,其它状态全部清除。
  SD_CardState &= SD_CARD_EXIST | SD_CARD_WRITE_PROTECT | SD_CARD_DOOR_CLOSE;

  return -2;
}

/*
//// SD_CardBusy ---- SD_CardBusy ---- SD_CardBusy ---- SD_CardBusy ---- SD_CardBusy ---- SD_CardBus
//
//      检查 SD 卡是否处于 Busy 状态,如果卡门打开、卡槽内没有卡、SPI0 被占用、SD 卡正忙,
//  则返回非 0 值,否则 SD 卡就是处于 Ready 状态,返回0。
//
//      返回值:
//          0   - SD 卡处于 Ready 状态
//         -1   - SPI0 口被其它外设占用
//         -2   - SD 卡处于 Busy 状态
//
extern int SD_CardBusy(void)
{
    SD_CardState &= !(SD_CARD_READY);

    // 如卡门关闭和卡槽内插入了卡体,返回 0
    if ((SD_CardState & SD_CARD_DOOR_CLOSE) && (SD_CardState &  SD_CARD_EXIST))
        {
            //  如果 SPI0 被占用则返回 -1
            if (SD_CS_Enabled()) 
                return -1;
            //  如果从 Out 读回高信号,则表示 SD 卡空闲(前提是SD卡必须存在)   
            if (SPI0_GetChar() == (unsigned char)0xff)
            {
                //  设置 Ready 状态
                SD_CardState |= SD_CARD_READY;
                return 0; 
            }
        }
    //        卡门打开或卡槽内没有卡则返回 -2;
    SD_CardState &= SD_CARD_EXIST | SD_CARD_WRITE_PROTECT | SD_CARD_DOOR_CLOSE;
        return -2;
}
*/

//// GetCSD_Register ---- GetCSD_Register ---- GetCSD_Register ---- GetCSD_Register ---- GetCSD_Regi
//
//                从SD卡获得CSD寄存器的资料
//
//        返回值:
//                0  表示正常,寄存器内容已经放入SD_CSD_Register数组
//                -1 表示读取失败,这是由于SPI0被其它外设占用造成的
//                -2 表示读取失败,这是由于超时造成的
//                -3 表示SD卡返回了一个错误信息,导致该命令失败
//        
int GetCSD_Register(void)
{
        int TempData;
        
        SD_CommandBuffer[0] = 0x49;                 //        SEND_CSD Command

        SD_CS_ENABLED;

        //        发送命令,返回的是命令长度
        TempData = SPI0_SD_Data_Sent(SD_CommandBuffer, SD_COMMAND_LENGTH);
        //        如果发生错误,在此死循环,等待软件人员处理
        if (TempData<0) 
        {
                //        清除设备片选
                SD_CS_DISABLED;
                while(1){;}
        }

        //        获得SD卡的应答
        TempData = SPI0_SD_Response_R1();
        //        如果产生错误则返回
        if (TempData!=0) 
        {
                //        清除设备片选
                SD_CS_DISABLED;
                return -3;
        }

        //        开始等待计时
        TimeCountStart32();
        //        开始接收CSD寄存器的数据
        while(1)
        {
                TempData = SPI0_GetChar();
                //        获得数据块起始信号
                if (TempData == 0xfe)
                        break;
                //        如果等待时间超过250ms,则作为出错处理
                if (TimeCountTotal32() > 2500)
                {
                        //        清除设备片选
                        SD_CS_DISABLED;
                return -2;
                }
        }

        //        从数据线接收数据。
        SPI0_SD_Data_Receive(SD_CSD_Register, 16);
        //        抛弃CRC16
        TempData = SPI0_GetChar();
        TempData = SPI0_GetChar();

        //         让SD恢复工作状态
        TempData = SPI0_GetChar();

        //        清除设备片选
        SD_CS_DISABLED;
        return 0;
}


//// Get_SD_Size ---- Get_SD_Size ---- Get_SD_Size ---- Get_SD_Size ---- Get_SD_Size ---- Get_SD_Siz
//
//                获得当前SD卡的容量
//
//
//
extern __int64 Get_SD_Size(void)
{
        int C_Size = 1, C_Mul = 0;
        short Table2Pow[8] = {4, 8 ,16, 32, 64, 128, 256, 512} ;

        C_Size += (SD_CSD_Register[6] & 3) << 10;
    C_Size += SD_CSD_Register[7]<<2; 
    C_Size += SD_CSD_Register[8]>>6;
        
        C_Mul += (SD_CSD_Register[9] & 3) << 1;
        C_Mul += (SD_CSD_Register[10] & 0x80) >>7;

        return C_Size * Table2Pow[C_Mul] * 512;
}


//// SD_CardInit ---- SD_CardInit ---- SD_CardInit ---- SD_CardInit ---- SD_CardInit ---- SD_CardIni
//
//      初始化 SD 卡:它首先检查卡门和卡槽的状态,如果卡门关闭和卡槽内有合适的存储卡,
//  则它用 SPI0 发送命令将其复位,并确定使用 SPI 方式通讯。然后继续检查卡的种类。然后
//  根据上面的流程将 SD_CardState 变量内填入本次的检测状态。
//
//  返回值:
//      如果成功设置,则返回 0,卡门、卡槽和卡的工作状态在 SD_CardState 变量中被设置。
//          如果卡不能被访问,则返回负数。SD_CardState 变量中卡门、卡槽、写保护将被设
//      置成本次的检测状态。
//
extern int SD_CardInit(void)
{
  int SD_Response;

        //        将 SPI0 速度降到 1MHz
        SD_Max_Rate = 1000000;
/*

        The default command structure/protocol for SPI mode is that CRC checking is disabled. 
Since the card powers up in SD Bus mode, CMD0 must be followed by a valid CRC byte (even 
though the command is sent using the SPI structure). Once in SPI mode, CRCs are disabled 
by default.

        由于 SD 卡在加电之后,在默认的 SD 通讯模式下 CRC7 是必须要确认的,所以在下面的命令流
中数据不允许做任何更改。 一旦设置并成功进入 SPI 通讯模式后,CRC 校验自动取消,此时可以直
接发送命令(注意:最后一个字节必须为“0x01”,因为协议中要求最后那个字节的 bit0 = 1)。

*/

  SD_CardState = 0;

        MySD.Effect = 0;

        SPI0_PutChar(0xff);

        //  测试 SD 卡门、卡槽的状态,如果不合适对 SD 卡操作,则直接退出,返回-2
    if (TestSDCardState()) return -2;

    //  对 SD 卡进行初始化动作,首先设置通讯速度为 1MHz
    SetSPI0_CLK(SD_Max_Rate);

        //  对 SD 卡发送 Reset 命令。
        SD_CommandBuffer[0] = 0x40;
    SD_Response = SPI0_SD_Command_R1();    

    //  如果 SD 卡对 Reset 命令无回应,则清除 SD 卡的 Ready 状态
    if ((SD_Response < 0) || (SD_Response & 0xfc)) 
    {
        //  清除 SD 卡的 Ready 状态
        SD_CardState &= !(SD_CARD_READY);
        return -2;
    }

        //        激活卡到正常工作状态
    SD_CommandBuffer[0] = 0x41;

        SPI0_PutChar(0xff);

        //        开始等待计时
        TimeCountStart32();
        do{
                SD_Response = SPI0_SD_Command_R1();
                //        如果等待时间超过250ms,则作为出错处理
                if (TimeCountTotal32() > 2500)
                {
                //  清除 SD 卡的 Ready 状态
                SD_CardState &= !(SD_CARD_READY);
                        //        加上超时报告标记
                        SD_CardState |= SD_CARD_TIMEOUT;
                return -2;
                }
        }while((SD_Response == 1) || (SD_Response == 0xff));
        
    //  卡激活成功,获取卡的特性数据
        if (GetCSD_Register())
                {
                //  如果获取CSD寄存器内容失败,则清除 SD 卡的 Ready 状态
                SD_CardState &= !(SD_CARD_READY);
                        //        加上超时报告标记
                        SD_CardState |= SD_CARD_TIMEOUT;
                return -2;
                }

    //  所有设置成功之后,将卡设置为 Ready 状态
    SD_CardState |= SD_CARD_READY;

        //        填充SD卡的信息结构
        MySD.Effect = 1;

        //        获取当前的SD卡版本号
        MySD.SD_Ver = (SD_CSD_Register[0]>>6) ?  (SD_CSD_Register[0]>>6) : 1;

        //        计算容量大小
        MySD.Size = Get_SD_Size();

        //        获得扇区的大小,单位是字节
        MySD.SectorSize = ((SD_CSD_Register[5] & 0xf) << 1);

        //        获得可擦除的扇区块大小,单位是块
        MySD.EraseSectorSize = ((SD_CSD_Register[10] & 0x3f) << 1) + ((SD_CSD_Register[11] & 0x80) >> 7) + 1;

        //        获得文件格式
        MySD.FileFormat = (SD_CSD_Register[14] & 0xc) >> 2;

        //        将最大速度调整到10MHz,按照SD卡的DataSheet说明,它的标称值为20MHz
        SD_Max_Rate = 10000000;
  return 0; 
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -