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

📄 sd_driver.c

📁 STM32_电子相框.rar
💻 C
📖 第 1 页 / 共 2 页
字号:
/*这份代码经源码格式软件格式化过
     yang_hx@neusoft.com      */
/*******************************************************************************
*  本文件为SPI操作SD卡的底层驱动文件
*  包括SPI模块及相关IO的初始化,SPI读写SD卡(写指令,读数据等)
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
#include "SD_driver.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
u8 SD_Type=0 ;
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/


////////////////////////////////////////////////////////////////////////////////
// 以下是SPI模块的初始化代码,配置成主机模式,访问SD卡
////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
* Function Name  : SPI_Configuration
* Description    : SPI模块初始化,【包括相关IO口的初始化】
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SPI_Configuration(void)
{
    SPI_InitTypeDef SPI_InitStructure ;
    GPIO_InitTypeDef GPIO_InitStructure ;
    //启动SPI时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
    
    //////下面是SPI相关GPIO初始化//////
    //SPI1模块对应的SCK、MISO、MOSI为AF引脚
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 ;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP ;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //PD9 pin: CS, PD10 : SD
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //////SPI模块配置//////
    //一开始SD初始化阶段,SPI时钟频率必须<400K
    SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex ;
    SPI_InitStructure.SPI_Mode=SPI_Mode_Master ;
    SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b ;
    SPI_InitStructure.SPI_CPOL=SPI_CPOL_High ;
    SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge ;
    SPI_InitStructure.SPI_NSS=SPI_NSS_Soft ;
    SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256 ;
    SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB ;
    SPI_InitStructure.SPI_CRCPolynomial=7 ;
    SPI_Init(SPI1,&SPI_InitStructure);
    
    SPI_Cmd(SPI1,ENABLE);
    return ;
}

/*******************************************************************************
* Function Name  : SPI_SetSpeed
* Description    : SPI设置速度为高速
* Input          : u8 SpeedSet
*                  如果速度设置输入0,则低速模式,非0则高速模式
*                  SPI_SPEED_HIGH   1
*                  SPI_SPEED_LOW    0
* Output         : None
* Return         : None
*******************************************************************************/
void SPI_SetSpeed(u8 SpeedSet)
{
    SPI_InitTypeDef SPI_InitStructure ;
    
    SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex ;
    SPI_InitStructure.SPI_Mode=SPI_Mode_Master ;
    SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b ;
    SPI_InitStructure.SPI_CPOL=SPI_CPOL_High ;
    SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge ;
    SPI_InitStructure.SPI_NSS=SPI_NSS_Soft ;
    //如果速度设置输入0,则低速模式,非0则高速模式
    if(SpeedSet==SPI_SPEED_LOW)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256 ;
    }
    else 
    {
        SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_4;
    }
	//moon.mp3: 4707774 Byte size 目标文件 设为buffer[512]     
	//speed:实验测试数据,最大速度 392314 Byte/S,
	//Prescaler_128, 59592 Byte/S
	//Prescaler_64, 104617 Byte/S
	//Prescaler_32, 168134 Byte/S    162337 Byte/S
	//Prescaler_16, 261543 Byte/S    247777 Byte/S
	//Prescaler_8,  313851 Byte/S    336269 Byte/S
	//Prescaler_4,  392314 Byte/S    392314 Byte/S
	//Prescaler_2,  392314 Byte/S

    SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB ;
    SPI_InitStructure.SPI_CRCPolynomial=7 ;
    SPI_Init(SPI1,&SPI_InitStructure);
    return ;
}

/*******************************************************************************
* Function Name  : SPI_ReadWriteByte
* Description    : SPI读写一个字节(发送完成后返回本次通讯读取的数据)
* Input          : u8 TxData 待发送的数
* Output         : None
* Return         : u8 RxData 收到的数
*******************************************************************************/
u8 SPI_ReadWriteByte(u8 TxData)
{
    u8 RxData=0 ;
    
	//GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_SET); //读文件闪烁
    
	//等待发送缓冲区空
    while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
    //发一个字节
    SPI_I2S_SendData(SPI1,TxData);
    
    //等待数据接收
    while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);
    //取数据
    RxData=SPI_I2S_ReceiveData(SPI1);
    
	//GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_RESET);

    return RxData ;
}

/*******************************************************************************
* Function Name  : SD_WaitReady
* Description    : 等待SD卡Ready
* Input          : None
* Output         : None
* Return         : u8
*               0: 成功
*           other:失败
*******************************************************************************/
u8 SD_WaitReady(void)
{
    u8 r1 ;
    u16 retry ;
    retry=0 ;
    do 
    {
        r1=SPI_ReadWriteByte(0xFF);
        if(retry==0xfffe)//????如果卡异常,会死循坏!
        {
            return 1 ;
        }
    }
    while(r1!=0xFF);
    
    return 0 ;
}


/*******************************************************************************
* Function Name  : SD_SendCommand
* Description    : 向SD卡发送一个命令
* Input          : u8 cmd   命令
*                  u32 arg  命令参数
*                  u8 crc   crc校验值
* Output         : None
* Return         : u8 r1 SD卡返回的响应
*******************************************************************************/
u8 SD_SendCommand(u8 cmd,u32 arg,u8 crc)
{
    unsigned char r1 ;
    unsigned char Retry=0 ;
    
    //????????
    SPI_ReadWriteByte(0xff);
    //片选端置低,选中SD卡
    SD_CS_ENABLE();
    
    //发送
    SPI_ReadWriteByte(cmd|0x40);
    //分别写入命令
    SPI_ReadWriteByte(arg>>24);
    SPI_ReadWriteByte(arg>>16);
    SPI_ReadWriteByte(arg>>8);
    SPI_ReadWriteByte(arg);
    SPI_ReadWriteByte(crc);
    
    //等待响应,或超时退出
    while((r1=SPI_ReadWriteByte(0xFF))==0xFF)
    {
        Retry++;
        if(Retry>200)
        {
            break ;
        }
    }
    
    
    //关闭片选
    SD_CS_DISABLE();
    //在总线上额外增加8个时钟,让SD卡完成剩下的工作
    SPI_ReadWriteByte(0xFF);
    
    //返回状态值
    return r1 ;
}


/*******************************************************************************
* Function Name  : SD_SendCommand_NoDeassert
* Description    : 向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)
* Input          : u8 cmd   命令
*                  u32 arg  命令参数
*                  u8 crc   crc校验值
* Output         : None
* Return         : u8 r1 SD卡返回的响应
*******************************************************************************/
u8 SD_SendCommand_NoDeassert(u8 cmd,u32 arg,u8 crc)
{
    unsigned char r1 ;
    unsigned char Retry=0 ;
    
    //????????
    SPI_ReadWriteByte(0xff);
    //片选端置低,选中SD卡
    SD_CS_ENABLE();
    
    //发送
    SPI_ReadWriteByte(cmd|0x40);
    //分别写入命令
    SPI_ReadWriteByte(arg>>24);
    SPI_ReadWriteByte(arg>>16);
    SPI_ReadWriteByte(arg>>8);
    SPI_ReadWriteByte(arg);
    SPI_ReadWriteByte(crc);
    
    //等待响应,或超时退出
    while((r1=SPI_ReadWriteByte(0xFF))==0xFF)
    {
        Retry++;
        if(Retry>200)
        {
            break ;
        }
    }
    //返回响应值
    return r1 ;
}

/*******************************************************************************
* Function Name  : SD_Init
* Description    : 初始化SD卡
* Input          : None
* Output         : None
* Return         : u8
*                  0:NO_ERR
*                  1:TIME_OUT
*                  99:NO_CARD
*******************************************************************************/
u8 SD_Init(void)
{
    u16 i ;
    // 用来循环计数
    u8 r1 ;
    // 存放SD卡的返回值
    u16 retry ;
    // 用来进行超时计数
    u8 buff[6];
    
    //如果没有检测到卡插入,直接退出,返回错误标志
   // if(!SD_DET())
   // {
        //return 99;
   //     return STA_NODISK ;
        //  FatFS错误标志:没有插入磁盘
  //  }
    
    //SD卡上电
 //   SD_PWR_ON();
    // 纯延时,等待SD卡上电完成
    for(i=0;i<0xf00;i++);
    SPI_SetSpeed(0); 
    //先产生>74个脉冲,让SD卡自己初始化完成
    for(i=0;i<10;i++)
    {
        SPI_ReadWriteByte(0xFF);
    }
    
    //-----------------SD卡复位到idle开始-----------------
    //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
    //超时则直接退出
    retry=0 ;
    do 
    {
        //发送CMD0,让SD卡进入IDLE状态
        r1=SD_SendCommand(CMD0,0,0x95);
        retry++;
    }
    while((r1!=0x01)&&(retry<200));
    //跳出循环后,检查原因:初始化成功?or 重试超时?
    if(retry==200)
    {
        return 1 ;
        //超时返回1
    }
    //-----------------SD卡复位到idle结束-----------------
    

    //获取卡片的SD版本信息
    r1=SD_SendCommand_NoDeassert(8,0x1aa,0x87);
    
    //如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化
    if(r1==0x05)
    {
        //设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC
        SD_Type=SD_TYPE_V1 ;
        
        //如果是V1.0卡,CMD8指令后没有后续数据
        //片选置高,结束本次命令
        SD_CS_DISABLE();
        //多发8个CLK,让SD结束后续操作
        SPI_ReadWriteByte(0xFF);
        
        //-----------------SD卡、MMC卡初始化开始-----------------
        
        //发卡初始化指令CMD55+ACMD41
        // 如果有应答,说明是SD卡,且初始化完成
        // 没有回应,说明是MMC卡,额外进行相应初始化
        retry=0 ;
        do 
        {
            //先发CMD55,应返回0x01;否则出错
            r1=SD_SendCommand(CMD55,0,0);
            if(r1!=0x01)
            {
                return r1 ;
            }
            //得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次
            r1=SD_SendCommand(ACMD41,0,0);
            retry++;
        }
        while((r1!=0x00)&&(retry<400));
        // 判断是超时还是得到正确回应
        // 若有回应:是SD卡;没有回应:是MMC卡
        
        //----------MMC卡额外初始化操作开始------------
        if(retry==400)
        {
            retry=0 ;
            //发送MMC卡初始化命令(没有测试)
            do 
            {
                r1=SD_SendCommand(1,0,0);
                retry++;
            }
            while((r1!=0x00)&&(retry<400));
            if(retry==400)
            {
                return 1 ;
                //MMC卡初始化超时
            }
            //写入卡类型
            SD_Type=SD_TYPE_MMC ;
        }
        //----------MMC卡额外初始化操作结束------------
        
        //设置SPI为高速模式
        SPI_SetSpeed(1);
        
        SPI_ReadWriteByte(0xFF);
        
        //禁止CRC校验
        /*
        		r1 = SD_SendCommand(CMD59, 0, 0x01);
                if(r1 != 0x00)
                {
                    return r1;  //命令错误,返回r1
                }
                */
        //设置Sector Size
        r1=SD_SendCommand(CMD16,512,0xff);
        if(r1!=0x00)
        {
            return r1 ;
            //命令错误,返回r1
        }
        //-----------------SD卡、MMC卡初始化结束-----------------
        
    }
    //SD卡为V1.0版本的初始化结束
    
    
    //下面是V2.0卡的初始化
    //其中需要读取OCR数据,判断是SD2.0还是SD2.0HC卡
    else if(r1==0x01)
    {
        //V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令
        buff[0]=SPI_ReadWriteByte(0xFF);
        //should be 0x00
        buff[1]=SPI_ReadWriteByte(0xFF);
        //should be 0x00
        buff[2]=SPI_ReadWriteByte(0xFF);
        //should be 0x01
        buff[3]=SPI_ReadWriteByte(0xFF);
        //should be 0xAA
        
        SD_CS_DISABLE();
        //the next 8 clocks
        SPI_ReadWriteByte(0xFF);
        
        //判断该卡是否支持2.7V-3.6V的电压范围
        if(buff[2]==0x01&&buff[3]==0xAA)
        {
            //支持电压范围,可以操作
            retry=0 ;
            //发卡初始化指令CMD55+ACMD41
            do 
            {
                r1=SD_SendCommand(CMD55,0,0);
                if(r1!=0x01)
                {
                    return r1 ;
                }
                r1=SD_SendCommand(ACMD41,0x40000000,0);
                if(retry>200)
                {
                    return r1 ;
                    //超时则返回r1状态
                }
            }
            while(r1!=0);
            
            //初始化指令发送完成,接下来获取OCR信息
            
            //-----------鉴别SD2.0卡版本开始-----------
            r1=SD_SendCommand_NoDeassert(CMD58,0,0);
            if(r1!=0x00)
            {
                return r1 ;
                //如果命令没有返回正确应答,直接退出,返回应答
            }
            //读OCR指令发出后,紧接着是4字节的OCR信息
            buff[0]=SPI_ReadWriteByte(0xFF);
            buff[1]=SPI_ReadWriteByte(0xFF);
            buff[2]=SPI_ReadWriteByte(0xFF);
            buff[3]=SPI_ReadWriteByte(0xFF);
            
            //OCR接收完成,片选置高
            SD_CS_DISABLE();
            SPI_ReadWriteByte(0xFF);
            
            //检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC
            //如果CCS=1:SDHC   CCS=0:SD2.0
            //检查CCS
            if(buff[0]&0x40)
            {
                SD_Type=SD_TYPE_V2HC ;
            }
            else 
            {
                SD_Type=SD_TYPE_V2 ;
            }
            //-----------鉴别SD2.0卡版本结束-----------
            
            
            //设置SPI为高速模式

⌨️ 快捷键说明

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