原创 SD卡读写程序设计(四)

2009-11-11 21:49 5087 7 8 分类: MCU/ 嵌入式

SD卡读写程序设计(四)


一、SD卡命令层程序设计


1、上次的程序已经写出了SD操作的用户层函数,比如函数


void SD_ReadBlock( u32 BlockIndex, u8* ReadBuf ){


  u16 i;


  u8 TmpByte="0xFF";


  SD_CmdReadSingle( BlockIndex );   //发出读单块命令17


  while ( TmpByte == 0xFF )             //等待块读令牌0xFE或错误信号


  { TmpByte = SPI_GetByte( );


  }


  if ( TmpByte !=0xFE )return; //如果数据错误,直接返回


  


  for ( i="0"; i<BlockLen; i++ )


     ReadBuf = SPI_GetByte();


  TmpByte = SPI_GetByte( );


  TmpByte = SPI_GetByte( ); //不进行CRC校验


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


  SPI_PutByte( 0xFF ); //纯粹只是为了延时。


}


 


2、本次的主要任务就是实现像SD_CmdReadSingle( BlockIndex );       //发出读单块命令17


这样的命令。根据SD卡的SPI总线通信协议,首先写了下面的代码。


//ReplyType对应返回值类型


void SD_SendCmd( u8 Command, u8* Param, u8 ReplyType, u8* Reply ){


   s32 i,ReplyLen;


   u8 TmpByte;


   SPI_PutByte(    Command );   //发送命令


   for ( i="3"; i>=0; i-- )


       SPI_PutByte ( Param ); //发送参数,四个字节,高字节在前


   SPI_PutByte ( 0x95 );   //发送CRC校验码,0x95用于复位的校验,其它随意


   ReplyLen =0;


   switch ( ReplyType )              //根据返回类型,决定接受几个字节


   {  case R1: ReplyLen="1"; break;


      case R1B: ReplyLen="1"; break;


         case R2: ReplyLen="2"; break;


         case R3: ReplyLen="5"; break;


         default: SPI_PutByte ( 0xFF );


                  break;


    }


   TmpByte=0x80;


   while ( (TmpByte&0x80) != 0 )


         TmpByte = SPI_GetByte( ); //最高位为1时,不是正确的返回值


      for ( i= ReplyLen-1; i>=0; i-- )


       { Reply = TmpByte;   //先收到高字节


            TmpByte = SPI_GetByte( );


          }


}


 


3、其他的一些相关操作都通过发送命令来实现,如复位、发读单块命令等,程序如下:


void SD_Reset( void ){


   u8 ParamByte[4],Reply;


   SD_PackParam ( ParamByte, 0 );


   SD_SendCmd ( CmdReset, ParamByte, CmdReset_R, &Reply );


} //发复位命令


 


void SD_CmdReadSingle( u32 BlockIndex ){


   u8 ParamByte[4],Reply;


   SD_PackParam ( ParamByte, (u32)BlockIndex );


   SD_SendCmd ( CmdReadSingle, ParamByte, CmdReadSingle_R, &Reply );


 


}//发送读单块命令,其中CmdReadSingleCmdReadSingle_R是宏定义,分别对应命令代码和返回类型。


 


二、SPI操作程序设计


1、下面就剩下SPI的操作和配置了。


2SPI的读写操作,由库函数完成。


u8 SPI_GetByte( void ){


   while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) == RESET );


   return ( SPI_I2S_ReceiveData( SPI1 ) );


}


 


void SPI_PutByte( u8 SendByte ){


   while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) == RESET );


   SPI_I2S_SendData( SPI1, SendByte ) ;


}


 


刚开始还出了一些错,首先stm<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />32f10x_conf.h中没有定义SPI,然后,V2.02的库与李宁这个书上的还不同,查看了一下头文件才发现。


 


3、开始进行配置


 1)使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);


2)配置IO引脚:


void SPI_Config(void){       //进行SPI的初始化配置


//  u8 TmpByte;


  GPIO_InitTypeDef GPIO_InitStructure;  //进行GPIO端口设置的数据结构


  SPI_InitTypeDef SPI_InitStructure;


  //第五脚用于SCK,第六脚用于SD的输出SPI的输入,第七脚是SD的输入口


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 |GPIO_Pin_7 ;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_Init(GPIOA, &GPIO_InitStructure);


 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;    /* SD的片选引脚 */


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_Init(GPIOA, &GPIO_InitStructure);


 


  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工通信


  SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式


  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;   //8位数据


 


  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low ;       //空闲时高电平


  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //第二个时钟数据有效


  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;      //空闲时高电平


  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //进行四分频


  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; //先发送低位


  SPI_InitStructure.SPI_CRCPolynomial = 7 ;


   


  SPI_Init(SPI1, &SPI_InitStructure);      /* 根据上面结构的参数对SPI1进行初始化 */ 


  SPI_Cmd(SPI1, ENABLE);    /* 使能SPI1 */


//  SPI_I2S_SendData( SPI1, 0xaa );


//  TmpByte=SPI_I2S_ReceiveData( SPI1 );


}


简单地对SPI测试了一下,可以使用。


对整个工程编译,下载,SD读卡程序陷入死循环。明天再调试。

文章评论1条评论)

登录后参与讨论

用户1593293 2009-12-3 10:24

认识了SD卡啦!
相关推荐阅读
nthq2004 2010-05-08 20:04
USB自定义设备驱动02
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />  本来还想编写应用程序测试一下自定...
nthq2004 2010-05-07 21:35
USB自定义设备驱动01
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />  一、USB设备驱动入门1、学习目...
nthq2004 2010-05-04 21:01
智林开发板上实现自定义的USB HID设备
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />  一、自定义HID设备的相关概念1...
nthq2004 2010-05-01 21:58
U盘例程在智林开发板上的移植
 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 一、移植前的准备工作1、有哪些操...
nthq2004 2010-04-30 19:19
U盘实现流程跟踪分析02
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />   二、追踪USB大容量设备的实现...
nthq2004 2010-04-27 21:51
U盘实现流程跟踪分析01
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />   一、追踪USB大容量设备的实现...
我要评论
1
7
关闭 站长推荐上一条 /2 下一条