基于SPI模式的SD卡驱动程序

u8 SD_SendCommand(u8 cmd,u32 arg, u8 crc)

 {

   u8 r1;

   unsigned int Retry = 0;

   SD_CS_DISABLE();

   SPI_ReadWriteByte(0xff);//提高兼容性,如果没有这里,有些SD卡可能不支持

   SD_CS_ENABLE();//片选端置低,选中SD卡

   /*发送命令序列*/

   SPI_ReadWriteByte(cmd | 0x40);

   SPI_ReadWriteByte((u8)(arg>>24));//参数[31..24]

   SPI_ReadWriteByte((u8)(arg>>16));//参数[23..16]

   SPI_ReadWriteByte((u8)(arg>>8)); //参数[15..8]

   SPI_ReadWriteByte((u8)arg);      //参数[7..0]

   SPI_ReadWriteByte(crc);

       //等待响应,或超时退出

       while((r1 = SPI_ReadWriteByte(0xff)==0xff))

        {

       Retry++;

       if(Retry>800)break;//根据实验测得,最好重试次数多点

         }

        //关闭片选

        SD_CS_DISABLE();

        //在总线上额外增加8个时钟,让SD卡完成剩下的工作

        SPI_ReadWriteByte(0xff);

       //返回状态值

       return r1;

  }

/************************************************************************

*SD卡初始化函数

*延时等待SD卡上电完成

*给至少74个脉冲让SD卡自己初始化完成

*持续发送发送CMD0接收0x01(可以不接受)SD回应进入Idle(空闲)状态

*

************************************************************************/

u8 SD_Init(void)

 {

  u16 i;         //用来循环计数

  u8 r1;       //存放SD卡的返回值

  u16 retry;  //用来进行超时计数

  u8 buff[6];

  SPI_ControlLine();  //SPI的配置初始化

  SPI_SetSpeed(SPI_SPEED_LOW);

  SD_CS_ENABLE();

  //纯延时,等待SD卡上电完成

  for(i=0;i<0xf00;i++);

  //先产生至少74个脉冲,让SD卡自己初始化完成

  for(i=0;i<10;i++)

  {

    SPI_ReadWriteByte(0xFF); //80clks

  }

  //-------------------SD卡复位到idle开始-------------------

  //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态

  //超时则直接退出

  retry = 0;

      do

      {

          //发送CMD0,让SD卡进入IDLE状态

      ri = 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(CMD8,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,佛则重试400次

       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(CMD1,0,0);

         retry++;

       }while(r1!=0x00)&&(retry<400);

       if(retry==400)return 1;//MMC卡初始化超时

       //写入卡类型

       SD_Type=SD_TYPE_MMC;

       }

       //----------MMC卡额外初始化操作结束---------------

       //设置SPI为高速模式

       SPI_SetSpeed(SPI_SPEED_HIGH);

       SPI_ReaadWriteByte(0xff);

       //禁止CRC校验

       r1=SD_SendCommand(CMD59,0,0x95);

       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);//shoule be 0x00

      buff[1]=SPI_ReadWriteByte(0xff);//shoule be 0x00

      buff[2]=SPI_ReadWriteByte(0xff);//shoule be 0x11

      SD_CS_DISABLE();

      SPI_ReadWriteByte(0xff);//the next 8 clocks

      //判断该卡是否支持2.7-3.6的电压范围

      //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,1);

  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还是SDHC

  //如果CCS=1:SDHC   CCS=0:   SD2.0

  if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC;//检查CCS

  else SD_Type=SD_TYPE_V2;

  //------------------鉴别SD2.0卡版本结束------------------

  //设置SPI为高速模式

  SPI_SetSpeed(1);

 }

 return r1

}

/******************************************************************

*********************SPI模式GPIO端口设置***************************

**************PA5=SCK、PA6=MISO、PA7=MOSI、PA4=CS******************

******************************************************************/

void SPI_ControlLine(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ,ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);

    /*configuration SPI1 pins:,SCK,MISO and MOSI*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 

    GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //MISO应该要初始化为上拉输入

    GPIO_Init(GPIOA, &GPIO_InitStructure);

/*configration PA4 Pin:  CS Pin*/

    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通信模式初始化***********************************

***********************设置高速或低速模式**********************************

**************************************************************************/

void SPI_SetSpeed(u8 SpeedSet)

{

   /* Initialize the SPI1 according to the SPI_InitStructure members */ 

   SPI_InitTypeDef SPI_InitStructure;

   if(SpeedSet==SPI_SPEED_HIGH)//高速

   {

      SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 

      SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 

      SPI_InitStructure.SPI_DatSize = SPI_DatSize_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_2; 

      SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; 

      SPI_InitStructure.SPI_CRCPolynomial = 7;

   

    

   SPI_Init(SPI1, &SPI_InitStructure); 

   /*SPI1 enable*/

   SPI_Cmd(SPI1,ENABLE);

   }

   else//低速

     {  

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 

        SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 

        SPI_InitStructure.SPI_DatSize = SPI_DatSize_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);

/*SPI1 enable*/

SPI_Cmd(SPI1,ENABLE); 

      }

}

/************************************************************

**************************发送命令***************************

************************************************************/

u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg,u8 crc)

{

    unsigned char r1;

    unsigned int Retry = 0;

    SD_CS_DISABLE();

    SPI_ReadWriteByte(0xff);//提高兼容性,如果没有这里,有些SD卡可能不支持

    SD_CS_ENABLE();//片选端置低,选中SD卡

    /*发送命令序列*/

    SPI_ReadWriteByte(cmd | 0x40);

    SPI_ReadWriteByte((u8)(arg>>24));//参数[31..24]

    SPI_ReadWriteByte((u8)(arg>>24));//参数[23..16]

    SPI_ReadWriteByte((u8)(arg>>24));//参数[7..0]

    SPI_ReadWriteByte(crc);

    //等待响应,或超时退出

    while((r1 = SPI_ReadWriteByte(0xff))==0xff)

    {

     Retry++;

   if(Retry>600)break;//根据实验测得,最好重试次数多点

     }

 //返回响应值

 return r1;

}

/**************************************************************

************************向SD卡写一个块*************************

**************************************************************/

u8 SD_WriteSingleBlock(u32 sector,const u8 *data)

{

u8 r1;

u16 i;

u16 retry;

//设置为高速模式

SPI_SetSpeed(SPI_SPEED_LOW);

 //如果不是SDHC,给定的是sector地址,将其转换成byte地址

 if(SD_Type!=SD_TYPE_V2HC)

 {

     sector = sector<<9;//512*sector即物理扇区的边界对齐地址

 }

 r1 = SD_SendCommand(CMD24,sector,0x00);

 if(r1 !=0x00)

 {

    return r1;//应答不正确,直接返回

 }

 //开始准备数据传输

 SD_CS_ENABLE();

 //先放3个空数据,等待SD卡准备好

 SPI_ReadWriteByte(0xff);

 SPI_ReadWriteByte(0xff);

 SPI_ReadWriteByte(0xff);

 //放起始令牌0xfe

 SPI_ReadWriteByte(0xfe);

 //发一个sector的数据

 for(i=0;i<512;i++)

 {

     SPI_ReadWriteByte(*data++);

 }

 //发2个Byte的dummy CRC

 SPI_ReadWriteByte(0xff);

 SPI_ReadWriteByte(0xff);

     //等待SD卡应答

 r1 = SPI_ReadWriteByte(0xff);

 if((r1&0x1f)!=0x05)

 {

     SD_CS_DISABLE();

 return r1;

  }

 //等待操作完成

 retry = 0;

 while(!SPI_ReadWriteByte(0xff))//卡自编程时,数据线被拉低

 {

     retry++;

 if(retry>65534)       //如果长时间写入没有完成,报错退出

 {

 SD_CS_DISABLE();

 return 1;         //写入超时返回1

  }

   }

 //写入完成,片选置1

 SD_CS_DISABLE();

 SPI_ReadWriteByte(0xff);

 return 0;

}

/********************************************************

******************从SD中读取一个块***********************

********************************************************/

u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)

{

   u8 r1;

   //设置为高速模式

   SPI_SetSpeed(SPI_SPEED_LOW);

   if(SD_Type!=SD_TYPE_V2HC)

    {

   sector = sector<<9;//512*sector即物理扇区的边界对齐地址

 }

//如果不是SDHC,将sector地址转成byte地址

//sector = sector<<9;

r1 = SD_SendCommand(CMD17,sector,1);//读命令

if(r1 !=0x00)return r1;

r1 = SD_ReceiveData(buffer,512,EELEASE) ;

if(r1 != 0)

  return r1;   //读数据出错!

else

  return 0;

}

/************************************************************

************************接收数据*****************************

************************************************************/

u8 SD_ReceiveData(u8 *data,u16 len,u8 release)

{

   u16 retry;

   u8 r1;

   //启动一次传输

   SD_CSENABLE();

   //等待SD卡发回数据起始令牌0xfe

   retry = 0;

   do

   {

  r1 = SPI_ReadWriteByte(0xff);

  retry++;

  if(retry>4000)  //4000次等待后没有应答,退出报错(根据实验测试,此处最好多试几次)

   {

     SD_CS_DISABLE();

 return 1;

 }

 }while(r1 != 0xfe);

 //开始接收数据

 while(len--)

 {

    *data = SPI_ReadWriteByte(0xff);

data++;

 }

 //下面是2个伪CRC(dummy CRC)

 SPI_ReadWriteByte(0xff);

 SPI_ReadWriteByte(0xff);

 //按需释放总线,将CS置高

 if(release == RELEASE)

 {  

    //传输结束

SD_CS_DISABLE();

SPI_ReadWriteByte(0xff);

}

  return 0;

}

void SPI_ReadWriteByte(u8 xxx)
{


void USART_Configuration(void)
{

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103是一款32位的ARM Cortex-M3系列微控制器,具有较高的性能和丰富的外设资源。要实现基于SPISD卡读卡器,可以按照以下步骤进行: 1. 硬件连接:将SD卡读卡器的MISO(Master-In-Slave-Out),MOSI(Master-Out-Slave-In),SCK(SPI时钟线)和CS(片选)分别连接到STM32F103的相应引脚。 2. 配置SPI外设:在STM32CubeIDE中,通过HAL库函数配置SPI外设,设置通信速率、数据位宽、数据传输模式等参数。 3. 初始化SD卡:通过SPI发送初始化命令给SD卡读卡器,进行SD卡的初始化,例如设置工作电压、选择SPI模式等。 4. 发送指令:通过SPISD卡发送指令进行读写操作。例如,可以发送CMD0命令来复位SD卡,CMD8命令来获取SD卡的特性等。 5. 数据传输:通过SPI进行数据传输。可以通过CMD17命令选择块号并读取SD卡上的数据块,或者使用CMD24命令选择块号并向SD卡写入数据块。 6. 错误处理:在进行SD卡读写过程中,需要根据返回的响应码进行错误处理。比如,如果接收到的响应码表明命令执行失败,可以进行相应的错误处理。 7. 关闭SD卡:在程序结束或切换到其他操作之前,使用CMD12命令关闭SD卡。 总之,通过配置SPI外设和通过SPI发送命令和数据来实现基于SPISD卡读卡器。需要注意的是,具体的代码实现和配置可能会因不同的开发环境、工具链和SD卡读卡器而有所不同。因此,以上提供的步骤仅为一般性指导,具体实施时还需参考相关文档和资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值