logo资料库

STM32在SPI模式下读写SD卡.pdf

第1页 / 共25页
第2页 / 共25页
第3页 / 共25页
第4页 / 共25页
第5页 / 共25页
第6页 / 共25页
第7页 / 共25页
第8页 / 共25页
资料共25页,剩余部分请下载后查看
3.20 SD卡实验 很多单片机系统都需要大容量存储设备,以存储数据。目前常用的有 U 盘,FLASH 芯片, SD 卡等。他们各有优点,综合比较,最适合单片机系统的莫过于 SD 卡了,它不仅容量可以做 到很大(32Gb 以上),而且支持 SPI 接口,方便移动,有几种体积的尺寸可供选择(标准的 SD 卡尺寸,以及 TF 卡尺寸),能满足不同应用的要求。只需要 4 个 IO 口,就可以外扩一个最大 达 32GB 以上的外部存储器,容量选择尺度很大,更换也很方便,而且方便移动,编程也比较 简单,是单片机大容量外部存储器的首选。 ALIENTKE MiniSTM3 开发板就带有 SD 卡接口,利用 STM32 自带的 SPI 接口,最大通信 速度可达 18Mbps,每秒可传输数据 2M 字节以上,对于一般应用足够了。本节将向大家介绍, 如何在 ALIENTEK MiniSTM32 开发板上读取 SD 卡。本节分为如下几个部分: 3.20.1 SD 卡简介 3.20.2 硬件设计 3.20.3 软件设计 3.20.4 下载与测试 295
3.20.1 SD 卡简介 SD 卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快 闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助 理(PDA)和多媒体播放器等。SD 卡由日本松下、东芝及美国 SanDisk 公司于 1999 年 8 月 共同开发研制。大小犹如一张邮票的 SD 记忆卡,重量只有 2 克,但却拥有高记忆容量、快 速数据传输率、极大的移动灵活性以及很好的安全性。 SD 卡一般支持 2 种操作模式: 1,SD 卡模式; 2,SPI 模式; 主机可以选择以上任意一种模式同 SD 卡通信,SD 卡模式允许 4 线的高速数据传输。 SPI 模式允许简单的通过 SPI 接口来和 SD 卡通信,这种模式同 SD 卡模式相比就是丧失了 速度。 SD 卡的引脚排序如下图所示: 图 3.20.1.1 SD 卡引脚排序图 SD 卡引脚功能描述如下表所示: SD 卡只能使用 3.3V 的 IO 电平,所以,MCU 一定要能够支持 3.3V 的 IO 端口输出。 3.20.1.1 SD 卡引脚功能表 表 注意:在 SPI 模式下,CS/MOSI/MISO/CLK 都需要加 10~100K 左右的上拉电阻。 SD 卡要进入 SPI 模式很简单,就是在 SD 卡收到复位命令(CMD0)时,CS 为有效电 平(低电平)则 SPI 模式被启用。不过在发送 CMD0 之前,要发送>74 个时钟,这是因为 SD 卡内部有个供电电压上升时间,大概为 64 个 CLK,剩下的 10 个 CLK 用于 SD 卡同步, 之后才能开始 CMD0 的操作,在卡初始化的时候,CLK 时钟最大不能超过 400Khz!。 ALENTEK MiniSTM32 开发板使用的是 SPI 模式来读写 SD 卡,下面我们就重点介绍一 下 SD 卡在 SPI 模式下的相关操作。 首先介绍 SPI 模式下几个重要的操作命令,如下表所示: 296
命令 CMD0(0X00) CMD9(0X09) CMD10(0X0A) 参数 NONE NONE NONE CMD16(0X10) 块大小 CMD17(0X11) CMD24(0X18) CMD41(0X29) CMD55(0X37) 地址 地址 NONE NONE 回应 描述 R1 R1 R1 R1 R1 R1 R1 R1 复位 SD 卡 读取卡特定数据寄存器 读取卡标志数据寄存器 设置块大小(字节数) 读取一个块的数据 写入一个块的数据 引用命令的前命令 开始卡的初始化 CMD59(0X3B) 仅最后一位有效 R1 设置 CRC 开启(1)或关闭(0) 其中 R1 的回应格式如下表所示: 表 3.20.1.2 SPI 模式下 SD 卡部分操作指令 表 3.20.1.3 SD 卡 R1 回应格式 接着我们看看 SD 卡的初始化,SD 卡的典型初始化过程如下: 1、初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置); 2、上电延时(>74 个 CLK); 3、复位卡(CMD0); 4、激活卡,内部初始化并获取卡类型(CMD1(用于 MMC 卡)、CMD55、CMD41); 5.、查询 OCR,获取供电状况(CMD58); 6、是否使用 CRC(CMD59); 7、设置读写块数据长度(CMD16); 8、读取 CSD,获取存储卡的其他信息(CMD9); 9、发送 8CLK 后,禁止片选; 这样我们就完成了对 SD 卡的初始化,这里面我们一般设置读写块数据长度为 512 个字 节,并禁止使用 CRC。在完成了初始化之后,就可以开始读写数据了。 SD 卡读取数据,这里通过 CMD17 来实现,具体过程如下: 1、发送 CMD17; 2、接收卡响应 R1; 3、接收数据起始令牌 0XFE; 4、接收数据; 5、接收 2 个字节的 CRC,如果没有开启 CRC,这两个字节在读取后可以丢掉。 6、8CLK 之后禁止片选; 以上就是一个典型的读取 SD 卡数据过程,SD 卡的写于读数据差不多,写数据通过 CMD24 来实现,具体过程如下: 1、发送 CMD24; 2、接收卡响应 R1; 3、发送写数据起始令牌 0XFE; 297
4、发送数据; 5、发送 2 字节的伪 CRC; 6、8CLK 之后禁止片选; 以上就是一个典型的写 SD 卡过程。关于 SD 卡的介绍,我们就介绍到这里,更详细的 介绍请参考 SD 卡的参考资料。 3.20.2 硬件设计 本节实验功能简介:开机的时候先初始化 SD 卡,如果 SD 卡初始化完成,则读取扇区 0 的数据,然后通过串口打印到电脑上。如果没初始化通过,则在 LCD 上提示初始化失败。 同样用 DS0 来指示程序正在运行。 所要用到的硬件资源如下: 1)STM32F103RBT6。 2)DS0(外部 LED0)。 3)串口 1。 4)TFTLCD 液晶模块。 5)SD 卡。 前面四部分,在之前的实例已经介绍过了,这里我们介绍一下SD卡在开发板上 的连接 方式,SD卡与MCU的连接原理图如下: 图3.20.2.1 SD卡与STM32连接电路图 298
3.20.3 软件设计 打开上一节的工程,首先在 HARDWARE 文件夹下新建一个 SD 的文件夹。然后新建一 个 MMC_SD.C 和 MMC_SD.H 的文件保存在 SD 文件夹下,并将这个文件夹加入头文件包 含路径。 打开 MMC_SD.C 文件,输入如下代码: #include "sys.h" #include "mmc_sd.h" #include "spi.h" #include "usart.h" #include "delay.h" u8 SD_Type=0;//SD 卡的类型 //Mini STM32 开发板 //SD 卡 驱动 //正点原子@ALIENTEK //2010/5/13 //增加了一些延时,实测可以支持 TF 卡(1G/2G),金士顿 2G,4G 16G SD 卡 //2010/6/24 //加入了 u8 SD_GetResponse(u8 Response)函数 //修改了 u8 SD_WaitDataReady(void)函数 //增加了 USB 读卡器支持的 u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead); //和 u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);两个 函数 //等待 SD 卡回应 //Response:要得到的回应值 //返回值:0,成功得到了该回应值 // 其他,得到回应值失败 u8 SD_GetResponse(u8 Response) { u16 Count=0xFFF;//等待次数 while ((SPIx_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准 确的回应 if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败 else return MSD_RESPONSE_NO_ERROR;//正确回应 } //等待 SD 卡写入完成 //返回值:0,成功; // 其他,错误代码; u8 SD_WaitDataReady(void) { u8 r1=MSD_DATA_OTHER_ERROR; 299
return MSD_DATA_CRC_ERROR; return MSD_DATA_WRITE_ERROR; r1=MSD_DATA_OK; break; r1=MSD_DATA_OTHER_ERROR; break; retry++; switch (r1) { case MSD_DATA_OK://数据接收正确了 case MSD_DATA_CRC_ERROR: //CRC 校验错误 case MSD_DATA_WRITE_ERROR://数据写入错误 default://未知错误 } u32 retry; retry=0; do { r1=SPIx_ReadWriteByte(0xFF)&0X1F;//读到回应 if(retry==0xfffe)return 1; }while(r1==MSD_DATA_OTHER_ERROR); //数据错误时一直等待 return 0;//成功了 } //向 SD 卡发送一个命令 //输入: u8 cmd 命令 // u32 arg 命令参数 // u8 crc crc 校验值 //返回值:SD 卡返回的响应 u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc) { u8 r1; SPIx_ReadWriteByte(0xff);//高速写命令延时 SPIx_ReadWriteByte(0xff); SPIx_ReadWriteByte(0xff); u8 Retry=0; SD_CS=1; retry=0; while(SPIx_ReadWriteByte(0XFF)==0)//读到数据为 0,则数据还未写完成 { }; retry++; //delay_us(10);//SD 卡写等待需要较长的时间 if(retry>=0XFFFFFFFE)return 0XFF;//等待失败了 300
//片选端置低,选中 SD 卡 SD_CS=0; //发送 SPIx_ReadWriteByte(cmd | 0x40);//分别写入命令 SPIx_ReadWriteByte(arg >> 24); SPIx_ReadWriteByte(arg >> 16); SPIx_ReadWriteByte(arg >> 8); SPIx_ReadWriteByte(arg); SPIx_ReadWriteByte(crc); //等待响应,或超时退出 while((r1=SPIx_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry>200)break; } //关闭片选 SD_CS=1; //在总线上额外增加 8 个时钟,让 SD 卡完成剩下的工作 SPIx_ReadWriteByte(0xFF); //返回状态值 return r1; } //向 SD 卡发送一个命令(结束是不失能片选,还有后续数据传来) //输入:u8 cmd 命令 // u32 arg 命令参数 // u8 crc crc 校验值 //返回值:SD 卡返回的响应 u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc) { SPIx_ReadWriteByte(0xff);//高速写命令延时 SD_CS=0;//片选端置低,选中 SD 卡 //发送 SPIx_ReadWriteByte(cmd | 0x40); //分别写入命令 SPIx_ReadWriteByte(arg >> 24); SPIx_ReadWriteByte(arg >> 16); SPIx_ReadWriteByte(arg >> 8); SPIx_ReadWriteByte(arg); SPIx_ReadWriteByte(crc); u8 Retry=0; u8 r1; SPIx_ReadWriteByte(0xff); 301
u16 i; u8 retry; //等待响应,或超时退出 while((r1=SPIx_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry>200)break; } //返回响应值 return r1; } //把 SD 卡设置到挂起模式 //返回值:0,成功设置 // 1,设置失败 u8 SD_Idle_Sta(void) { for(i=0;i<0xf00;i++);//纯延时,等待 SD 卡上电完成 //先产生>74 个脉冲,让 SD 卡自己初始化完成 for(i=0;i<10;i++)SPIx_ReadWriteByte(0xFF); //-----------------SD 卡复位到 idle 开始----------------- //循环连续发送 CMD0,直到 SD 卡返回 0x01,进入 IDLE 状态 //超时则直接退出 retry = 0; do { //发送 CMD0,让 SD 卡进入 IDLE 状态 i = SD_SendCommand(CMD0, 0, 0x95); retry++; }while((i!=0x01)&&(retry<200)); //跳出循环后,检查原因:初始化成功?or 重试超时? if(retry==200)return 1; //失败 } //初始化 SD 卡 //如果成功返回,则会自动设置 SPI 速度为 18Mhz //返回值:0:NO_ERR // 1:TIME_OUT // 99:NO_CARD u8 SD_Init(void) { u8 r1; // 存放 SD 卡的返回值 u16 retry; // 用来进行超时计数 return 0;//成功 302
分享到:
收藏