SD卡SPI模式 读写block

声明:第一次写教程,如若有错误,请指出更正。

看了很多网上的教程,还是觉得很多教程中,写多个块的时候有些问题,因此经过3天的奋斗,写出自己的教程。

本教程中,没有挂载文件系统,单纯读写Block,会破坏分区和数据。

下节再 装上文件系统Fatfs,使得应用更好。

 

硬件平台:stm8单片机

软件平台:IAR

参考文档:SD卡协议(物理层)(附件中的PDF)

作者:小强

PDF的查看链接: http://wenku.baidu.com/view/b08b868e84868762caaed5fc.html

一、概述

SD卡的通信模式有两种:SDIO和SPI模式,其中SPI模式比较简单,而SDIO模式速度快。

暂时只讲述SPI模式。本文不讲述各种错误的检查,只讲述有用的 初始化和读写操作。

硬件连接图:SD卡 <wbr>SPI模式 <wbr>读写block

 

 

SPI工作模式为:MSB在前,数据在 CLK 上升沿采集

每发送一个命令,SD将会返回8位或16位的 Response

读写必须以一个扇区为单位(Sector) 512字节或 它的倍数

二、命令结构(PDF中P101)

SD卡 <wbr>SPI模式 <wbr>读写block

 

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

{

u8 r1,retry;

 

   CLR_SD_CS();//Select SD Card

   SPI_SendByte( cmd | 0x40);//bit47 = 0, bit46 = 1

   SPI_SendByte( arg >> 24 );

   SPI_SendByte( arg >> 16 );

   SPI_SendByte( arg >> 8 );

   SPI_SendByte( arg );

   SPI_SendByte( crc | 0x01);//bit0 = 1

   

   retry = 0;

   do{

       r1 = SPI_SendByte(0xff);

       if( retry ++ > 200 ) break;

   }while(r1 == 0xff);//Get Response

   

   SET_SD_CS();//Release SD Card

   

   return r1;

}

 

三、初始化过程:

CMD0进入挂起状态

CMD1选择SD

CMD59关闭CRC校检

CMD16设定Block  Length

参考文档P109 的R1 结构:

SD卡 <wbr>SPI模式 <wbr>读写block

CMD0发送后,SD卡处于 Idle状态,因此Response0x01

而其他命令发送后,R1应该为0x00

由于 大容量SD的读写Block大小固定为512bytes

 

 

u8 SD_IDLE(void)

{

   u8 r1, retry = 0;

   

   do{

       r1 = Write_Command(CMD0, 0, 0x95);//发送就绪命令

       if(retry ++ > 200) return 1;

   }while(r1 != 0x01 );//等待返回为0x01

   

   retry = 0;

   do{

       r1 = Write_Command(CMD1, 0, 0x95);

       if(retry ++ > 200) return 1;

   }while(r1 != 0x00 ); //等待返回为 0x00

   

   r1 = Write_Command(CMD59, 0, 0x95);//关闭CRC

   r1 = Write_Command(CMD16, 512, 0xff);//设定block块大小为512

   

   return 0;

}

 

四、Read_Single_Block

时序图 详细:参考资料P96

 SD卡 <wbr>SPI模式 <wbr>读写block

 

要点:CRC16bit,即2字节

        Start  Block  0xFE

        SD卡 <wbr>SPI模式 <wbr>读写block

参考资料P112

        要点: 2~513个字节

 

u8  GetResponse(u8 Res)

{

   u8 retry = 0,r1;

   do{

     r1 = SPI_SendByte(0xFF);

     if( retry++ > 250) return 1;

   }while(r1 != Res);

   

   return 0;

}

 

 

u8 ReceiveData(u8 *buffer, u16 len)

{

   u16 i;

   u8 r1;

   CLR_SD_CS();

   

   r1 = GetResponse(0xFE);//等待起始标志 0xFE

   if( r1 ){

       SET_SD_CS();//返回非0 发生错误

       return r1;

   }

   

   for(i=0; i

       *buffer++ = SPI_SendByte(0xFF); //接收数据

   }

   

   SPI_SendByte(0xFF);//CRC 8+8位 = 16位CRC

   SPI_SendByte(0xFF);//CRC

   

   SET_SD_CS();

 

   return 0;

}

 

 

u8 ReadSingleBlock(u8 *buffer, u32 sector)

{

   u8 r1;

   if(sector<1)  return 1;// 保护0扇区

   

   r1 = Write_Command(CMD17, sector<<9, 0xFF);//由于512字节对齐,所以sector<<9

   if(r1) return r1;//发生错误

   

   r1 = ReceiveData(buffer, 512);//接收512个字节数据

   if(r1) return r1;//发生错误

   

   return 0;

}

 

五、Read_Multiple_Block

SD卡 <wbr>SPI模式 <wbr>读写block

与读取单个块,不同点:结束时,需要发送CMD12

 

 

u8 ReadMultipleBlock(u8 *buffer, u32 sector, u8 count)

{

   u8 r1;

   u16 i;

   if(sector<1)  return 1;// 保护0扇区

   

   r1 = Write_Command(CMD18, sector<<9, 0xFF);//由于512字节对齐,所以 sector<<9

   if(r1) return r1;

   

   CLR_SD_CS();

   

   while( SPI_SendByte(0xFF) != 0xFE );//Wait for Start Block Taken

   

   do{

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

           *buffer++ = SPI_SendByte(0xFF);

   

       SPI_SendByte(0xFF);//CRC

       SPI_SendByte(0xFF);//CRC

       

   }while(--count);

       

SET_SD_CS();//Release

 

   r1 = Write_Command(CMD12, 0, 0); //Stop Tran

   if(r1) return r1;

   

   return count;

}

 

 

 

 

 

六、Write_Single_Block

详细查看参考资料P97页

SD卡 <wbr>SPI模式 <wbr>读写block
要点:每个块都以 Start Block Token (0xFE) 开始  与读取数据一样

        CRCRead_Single_Block一样,即16

        Busy时,SD卡会把总线拉低

  Data_Response SD卡 <wbr>SPI模式 <wbr>读写block

资料P111

即后6位数据为0x05为数据正常

 

 

u8 WriteSingleBlock(u8 *buffer, u32 sector)

{

   u8 r1;

   u16 i;

   if(sector<1)  return 1;

   

   r1 = Write_Command(CMD24, sector<<9, 0xFF);

   if(r1) return r1;

   

   CLR_SD_CS();

   SPI_SendByte(0xFE);//Start Block Taken

   

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

       SPI_SendByte( *buffer++ );//Write Data

   

   SPI_SendByte(0xFF);//CRC 16位

   SPI_SendByte(0xFF);//CRC

   

   r1 = SPI_SendByte(0xFF) & 0x1F;//data_Response

   

   if( r1 != 0x05) return r1;//Data accepted 0x05

   

   while( !SPI_SendByte(0xFF) );//busy

   

   SET_SD_CS();//Release

   

   return 0;

}

七、Write_Multiple_Block

资料P98

 SD卡 <wbr>SPI模式 <wbr>读写block

 

SD卡 <wbr>SPI模式 <wbr>读写block

资料P112

 

 写入单个块不同的是:

Start Block Token 0XFC

停止传送数据 要发送Stop Tran Token 0xFD

 

以下是实践证明的,资料中没有

 

而且:发送Stop Tran Token后,

        还要发送 2个字节或以上,参考 读取数据中的 Start Block Token 的说明

之后还要检查 第二次 Busy (在写多个块的时序图说明)

 

 

u8 WriteMultipleBlock(u8 *buffer, u32 sector, u8 count)

{

   u8 r1;

   u16 i;

   if(sector<1)  return 1;

   

   r1 = Write_Command(CMD25, sector<<9, 0xFF);

   if(r1) return r1;

   

   CLR_SD_CS();

   

   SPI_SendByte(0xFF);

   SPI_SendByte(0xFF);

   

   do{

       SPI_SendByte(0xFC);//Start Block Taken

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

           SPI_SendByte( *buffer++ );

   

       SPI_SendByte(0xFF);//CRC

       SPI_SendByte(0xFF);//CRC

       

       r1 = SPI_SendByte(0xFF) & 0x1F;//data_Response

       

       if( r1 != 0x05) return r1;//Data accepted

       

       while( !SPI_SendByte(0xFF) );//busy

       

   }while(--count);

   

   SPI_SendByte(0xFD);//Stop Tran Taken

   

   //以下三步是重点

   //写入数据 最少为 2个字节

   SPI_SendByte(0xFF);//CRC 16位

   SPI_SendByte(0xFF);//CRC

   

   while( !SPI_SendByte(0xFF) );// 第二个 busy

           

   SET_SD_CS();//Release

       

   return count;

}

 

http://blog.sina.com.cn/s/blog_6ade392501015vv7.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值