蜗居钢琴谱:SD卡初始化

来源:百度文库 编辑:中财网 时间:2024/04/30 05:37:19

首先是SD卡的初始化问题。SD卡的初始化很简单,各个论坛上写的也很详细,个人认为基本不存在太大问题。首先是74个clk,然后CS_LOW;发送CMD0,收到的应答是0x01;接着发送CMD1,收到的应答应该是0x00;最后CS_HIGH。至此,初始化完成。需要注意的问题:初始化的时钟不宜太快,可以在SD卡初始化完成后可提高数据读写速度;在发送命令之前和收到应答位之后,主控制器应该发送8个时钟完成相应操作;CMD0的CRC是0x95,其余命令的CRC无所谓。
读取单块数据流程:CS_LOW-->8个clk-->发送CMD17-->接收响应R1-->接收读数据起始令牌0xFE-->接收数据-->接收CRC-->8个clk-->CS_HIGH;
写入单块数据流程:CS_LOW-->8个clk-->发送CMD24-->接收响应R1-->写入读数据起始令牌0xFE-->写入数据-->接收CRC-->8个clk-->CS_HIGH;

    读写操作指令:单块写命令CMD24,多块写命令CMD25;单块读命令 CMD17,多块读命令CMD18。单块读写时,数据块的长度为512字节,多块读写时SD卡收到1个停止命令CMD12后停止读写。

本程序参考自bozai的SD卡驱动程序, 增加了SD、MMC卡判断的功能,SD、MMC初始化成功后能返回卡的类型参数供主程序使用。

//--------SD_MMC.H------------------------

#ifndef __SD_MMC_H__
#define __SD_MMC_H__

// 数据宏定义

#define uint8   unsigned char
#define   int8     signed char
#define uint16 unsigned int
#define   int16    signed int
#define uint32 unsigned long
#define   int32    signed long

// C8051F015与SD_MMC 的接口定义

sbit SDCS         = P3^0;
sbit SDDET         = P3^1;
sbit SDWP         = P3^2;


void SPI_SendWreit(uchar temp);         // VS1003B DATA发送

uint8 SPI_SendByte(uint8 val);         // SPI传送一个字节

uint8 MMC_SD_SendCmd(uint8 Cmd, uint32 arg);         //发送卡命令

uint8 MMC_SD_ReadSingleBlock(uint32 sector, uint8 *buffer);         //读一个扇区

uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8 *buffer);         //写一个扇区

uint8 MMC_SD_init();         //mmc_sd卡初始化


#endif
//---------SD_MMC.C-----------------

//---------------------------------------------------------
//         SD_MMC  底层驱动函数库

//        编译环境:
Keil C V2.40
//        编写日期:2008-04-07

//        最后更新:2008-05-04

//---------------------------------------------------------
#include "main.h"
#include "sd_mmc.h"

//---------------------------------------------------
//        函数名:
SPI_SendByte
//        功  能:SPI 数据发送

//        参  数:
uchar
//        返回值:

//---------------------------------------------------

void SPI_SendWreit(uchar temp)
{
         SPI0DAT=temp;
         while(TXBSY);         // 查询发送标志位

}

//---------------------------------------------------
//        函数名:
SPI_SendByte
//        功  能:SPI传送一个字节

//        参  数:
uchar
//        返回值:
uchar
//---------------------------------------------------

uint8 SPI_SendByte(uint8 val)         // uint8= uchar
{
         SPI0DAT = val;
         while(TXBSY);
         return SPI0DAT;
}

//---------------------------------------------------
//        函数名:
MMC_SD_SendCmd
//        功  能:发送卡命令

//        参  数:
uint8,uint32
//        返回值:
uint8
//---------------------------------------------------

uint8 MMC_SD_SendCmd(uint8 Cmd, uint32 arg)
{
         uint8 r1;
         uint8 retry=0;
        
         SPI_SendWreit(0xFF);         //发命令前先发送8个时钟

        
         SPI_SendWreit(Cmd | 0x40);         //分别写入命令

         SPI_SendWreit(arg>>24);
         SPI_SendWreit(arg>>16);
         SPI_SendWreit(arg>>8);
         SPI_SendWreit(arg);
         SPI_SendWreit(0x95);                 //仅本次有效的 CRC值
        
        
         while((r1 = SPI_SendByte(0xFF)) == 0xFF)         //等待响应

                 if(retry++ > 8) break;         //超时退出


         return r1;         //返回状态值

}

//---------------------------------------------------
//        函数名:
MMC_SD_ReadSingleBlock
//        功  能:读一个扇区

//        参  数:扇区,数据缓冲区

//        返回值:

//---------------------------------------------------

uint8 MMC_SD_ReadSingleBlock(uint32 sector,uint8 *buffer)
{
         uint8 r1;
         uint16 i;

         SDCS=0;                 // 使能
Card

         r1 = MMC_SD_SendCmd(17, sector<<9);         // 发读扇区命令

        
         if(r1 != 0x00) return r1;

         while(SPI_SendByte(0xFF) != 0xFE);         //--等待数据的起始令牌号
--

         for(i=0; i<512; i++)         //读512个数据

         {
                 *buffer++ = SPI_SendByte(0xFF);
         }

         SPI_SendWreit(0xFF);         // 发送伪
CRC
         SPI_SendWreit(0xFF);
         SDCS=1;                         // 关闭
Card
         return 0;
}

//---------------------------------------------------
//        函数名:
MMC_SD_WriteSingleBlock
//        功  能:写一个扇区

//        参  数:扇区,数据缓冲区

//        返回值:

//---------------------------------------------------

uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8 *buffer)
{
         uint8 r1;
         uint16 i;

         SDCS=0;                 // 使能
Card

         r1 = MMC_SD_SendCmd(24, sector<<9);         //写命令

         if(r1 != 0x00)
                 return r1;

         SPI_SendWreit(0xFF);
         SPI_SendWreit(0xFF);
         SPI_SendWreit(0xFF);

         SPI_SendWreit(0xFE);         //发送数据起始令牌号

        
         for(i=0; i<512; i++)         //以扇区为单位写入数据

         {
                 SPI_SendWreit(*buffer++);
         }
        
         SPI_SendWreit(0xFF);         // 发送伪
CRC
         SPI_SendWreit(0xFF);
        
         r1 = SPI_SendByte(0xFF);         // 读数据应答令牌号

        
         if( (r1&0x1F) != 0x05)         //等待是否成功

         {
                 SDCS=1;
                 return r1;
         }

         while(!SPI_SendByte(0xFF));          //--等待操作完成
--

         SDCS=1;                         // 关闭
Card

         return 0;
}

//---------------------------------------------------
//        函数名:
MMC_SD_Init
//        功  能:sd卡初始化

//        参  数:无

//        返回值:uint8 type         // 卡类型返回值
: 0x10 SD, 0x20 MMC
//---------------------------------------------------

uint8 MMC_SD_init()
{
         uint8 i;
         uint8 retry;
         uint8 r1=0;
         uint8 type=0;         // 卡类型返回值:
0xA0 SD 0xB0 MMC
         SDCS = 0;                 // 使能
Card

         SPI_speed=0x13;         //低速
SPI=300k    Fsystem=12Mhz
         retry = 0;

         do
         {
                 for(i=0;i<10;i++) SPI_SendByte(0xFF);    //发送80个时钟,使卡同步

                 r1 = MMC_SD_SendCmd(0, 0);         //发Cmd0(复位)命令

                 retry++;
                 if(retry > 30) return (type=0x01); //超时退出,个别卡需要更多次循环才有反应

         } while(r1 != 0x01);                 // MMC、SD卡成功转到SPI模式


         retry = 0;

//****** SD卡在进入SPI模式后,激活命令和MMC卡一样为Cmd1,同时Cmd55+Cmd41 仍然有效
******//

/*         do
         {
                 r1 = MMC_SD_SendCmd(1, 0);         //发Cmd1(active激活)命令

                 retry++;
                 if(retry > 100) return 1;         //超时退出

         } while(r1);*/
         do
         {
                 r1 = MMC_SD_SendCmd(55, 0);         // 先发送
Cmd55
                 if(r1 == 0x01)                         // 如果有反应

                 {
                         r1 = MMC_SD_SendCmd(41,0);         // 再发送 Cmd41 进行激活

                         if(r1 == 0x00) type = 0x10;         // 激活成功就是SD卡

                 }

                 else {                                    // 如果发送 Cmd55无反应,改发送
Cmd1
                                 r1 = MMC_SD_SendCmd(1,0);
                                 if(r1 == 0x00) type = 0x20;         // 激活成功就是MMC卡

                          }

                 retry++;
                 if(retry > 255) return (type=0x01);         // 超时退出, 个别卡需要更多次循环才有反应

         } while(r1 != 0x00);                 // MMC、SD卡激活后的返回值均为
0x00*/

//         SPI_SendByte(0xFF);         // 高速SPI前先发送8个时钟

//         SPI_speed = 0x07;         // 切换到高速
SPI

         r1 = MMC_SD_SendCmd(59, 0);         //关
CRC
         r1 = MMC_SD_SendCmd(16, 512);         //设置读取一次的字节数


         SDCS = 1;                         // 关闭
Card
//         SPI_speed=0x07;         //切换到高速
SPI

         return type;         //参数返回,1为初始化错误,10为SD卡,20为MMC卡

}

//-----------------------------------------------------------
//         End of File
//------------------------------------