SD卡SPI读写中文资料
SD卡读写
SD卡读写前言长期以来,以Flash Memory为存储体的SD卡因具备体积小、功耗低、可擦写以及非易失性等特点而被广泛应用于消费类电子产品中。
特别是近年来,随着价格不断下降且存储容量不断提高,它的应用范围日益增广。
当数据采集系统需要长时间地采集、记录海量数据时,选择SD卡作为存储媒质是开发者们一个很好的选择。
在电能监测以及无功补偿系统中,要连续记录大量的电压、电流、有功功率、无功功率以及时间等参数,当单片机采集到这些数据时可以利用SD 作为存储媒质。
本文主要介绍了SD卡在电能监测及无功补偿数据采集系统中的应用方案。
设计方案应用AT89C52读写SD卡有两点需要注意。
首先,需要寻找一个实现AT89C52单片机与SD卡通讯的解决方案;其次,SD卡所能接受的逻辑电平与AT89C52提供的逻辑电平不匹配,需要解决电平匹配问题。
通讯模式SD卡有两个可选的通讯协议:SD模式和SPI模式。
SD 模式是SD卡标准的读写方式,但是在选用SD模式时,往往需要选择带有SD 卡控制器接口的MCU,或者必须加入额外的SD卡控制单元以支持SD卡的读写。
然而,AT89C52单片机没有集成SD卡控制器接口,若选用SD模式通讯就无形中增加了产品的硬件成本。
在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以说是一种最佳的解决方案。
因为在SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用SPI模式对SD卡进行读写操作可大大简化硬件电路的设计。
虽然AT89C52不带SD卡硬件控制器,也没有现成的SPI 接口模块,但是可以用软件模拟出SPI总线时序。
本文用SPI 总线模式读写SD卡。
电平匹配SD卡的逻辑电平相当于3.3V TTL电平标准,而控制芯片AT89C52的逻辑电平为5V CMOS电平标准。
因此,它们之间不能直接相连,否则会有烧毁SD卡的可能。
出于对安全工作的考虑,有必要解决电平匹配问题。
spi 读写数据流程
spi 读写数据流程下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by theeditor. I hope that after you download them,they can help yousolve practical problems. The document can be customized andmodified after downloading,please adjust and use it according toactual needs, thank you!In addition, our shop provides you with various types ofpractical materials,such as educational essays, diaryappreciation,sentence excerpts,ancient poems,classic articles,topic composition,work summary,word parsing,copy excerpts,other materials and so on,want to know different data formats andwriting methods,please pay attention!SPI(Serial Peripheral Interface,串行外设接口)是一种高速、全双工、同步的通信总线,常用于微控制器与外部设备之间的数据传输。
SPI模式下对SD卡的读写控制
图 3 SD 卡的读操作
4 结束语
29
SD/MMC 卡都是把存储单元和控制器一同做到了卡上。智 能控制器的使用使得 SD/MMC 卡具有较好的兼容性和灵活性, 如今手机等一些电子产品的存储卡基本上都是 SD/MMC 卡。很 多厂家还根据产品的体积要求开发了 Mini SD/MMC 卡,这些卡 体积小,但基本的数据通信是一样的。SPI 总线接口简单易用, 兼容性好,使用 SPI 接口实现对 SD/MMC 卡的读写操作是非常简 单有效的,而且越来越多的 PC 等设备都配有读卡槽,可以直接 读取 SD/MMC 卡。因此,对一些存储数据量大的嵌入式系统,把 SD/MMC 卡作为其存储器的扩展具有很好的应用前景。
擦除错误
5
地址错误
6
参数错误
7
0
上电后,SD 卡默认进入 SD 模式,单片机将 CS 线拉低,并向 SD 卡发送 RESET 指令即 CMD0(发送命令字为 0x40、0x00、0x00、 0x00、0x00、0x95,其 中 0x95 第 一 个 命 令 不 能 少,之 后 可 以 省 去)。如 SD 卡的应答数据为 0x01,则表明 SD 卡进入了 SPI 模式, 此时 SD 卡为 idle 状态,在等待至少 74 个时钟周期后,再发送 SEND_OP_COND 指令,即 CMD1 命令;当应答信号为 0x00 时,说 明 SD 卡已经做好了和主机经行数据交换的准备,即初始化完 毕。值得注意的是,因为发送和接收是同时进行的,所以发送和
SD/MMC 卡可以工作在默认通信模式(SD 卡为 SD 通信模
图 1 单片机和 SD 卡连接的示意图
3 SD 卡的通信
作者简介:尚怡君(1983- ),女,大学本科,助教,主要研究方向: 嵌入式系统及图像处理;
SD卡的读取(SPI)
SPI模式下MCU对SD卡的控制及操作命令一、前言SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的 MCU,或者必须加入额外的SD卡控制单元以支持SD 卡的读写然而,大多数MCU都没有集成SD 卡控制器接口,若选用SD 模式通讯就无形中增加了产品的硬件成本。
在SD卡数据读写时间要求不是很严格的情况下,选用 SPI模式可以说是一种最佳的解决方案因为在 SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用 SPI模式对 SD卡进行读写操作可大大简化硬件电路的设计二、硬件电路实现以NXP的LPC2210 ARM7MCU为例,下图是周立功开发的实现板电路这里,将LPC2210MCU的SPI0用于SD卡的控制和数据读写。
对SPI0的两个数据线加了上拉电阻以便于MMC卡兼容。
卡供电采用了可控方式,通过GPIO口控制MOS管对其进行供电。
卡检测电路也使用GPIO口实现。
通过读GPIO口数据,检查卡是否写保护和完全插入。
具体内容可以参考周立功的说明书,百度文库里边有三、SD卡物理接口我们看到的SD卡一包如下所示,包含9个引脚和一个写保护开关:其引脚定义如下:注:1. S:电源;I:输入;O:推挽输出;PP:推挽I/O。
2. 扩展的DAT线(DAT1 ~ DAT3)在上电后处于输入状态。
它们在执行SET_BUS_WIDTH命令后作为DAT线操作。
当不使用DAT1 ~ DAT3 线时,主机应使自己的DAT1~DAT3线处于输入模式。
这样定义是为了与MMC卡保持兼容。
3. 上电后,这条线为带50KΩ上拉电阻的输入线(可以用于检测卡是否存在或选择 SPI 模式)。
用户可以在正常的数据传输中用 SET_CLR_CARD_DETECT(ACMD42)命令断开上拉电阻的连接。
对SD卡的读写程序
SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。
SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。
大小犹如一张邮票的SD记忆卡,重量只有2克,但却拥有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性。
贴程序:/*-------------------------------------1.本程序主要为了实现以下功能:1)通过对SPI方式对SD卡进行读与写2)简单的FAT操作3)对写入的数据进行打印2.编写日期:09.10.133.版本号:V1.04.作者:andyluo----------------------------------------*/#include<reg52.h> //添加头文件#define uchar unsigned char //宏定义数据类型#define uint unsigned int/*-------------------------------------与指示灯有关的IO--------------------------------------*/sbit power=P0^4;/*-------------------------------------与SD卡通信有关的IO---------------------------------------*/sbit SCL=P1^5;//时钟信号sbit CS=P1^6;//片选信号sbit SI=P1^7;//数据输入sbit SO=P3^3;//数据输出//错误码定义#define INIT_CMD0_ERROR 0X01#define INIT_CMD1_ERROR 0X02#define WRITE_BLOCK_ERROR 0X03#define READ_BLOCK_ERROR 0X04/*--------------------------------------与通信和定时器相关的变量---------------------------------------- */uchar cn=0;/*--------------------------------------变量定义-----------------------------------------*/uchar is_init;//用于控制SPI的速度,通过为1与0进行选择uchar xdata pbuf[512];//定义512个数据缓冲区/*--------------------------------------函数名称:delay()函数作用:用于某些程序中的延时函数特点:无返回值,带入口参数-----------------------------------------*/void delay(uint k){uint m,n;for(m=0;m<5;m++)for(n=0;n<k;n++);}/*-------------------------------SPI写一个字节----------------------------------*/void spi_write(uchar x)//SPI写一个字节,其中is_init为1 {uchar i;for(i=0;i<8;i++){SI=((x<<i)&0x80);SCL=0;if(is_init){delay(8);}SCL=1;if(is_init){delay(8);}}}/*--------------------------------SPI读一个字节----------------------------------*/uchar spi_read(){uchar temp=0,i;SO=1;for(i=0;i<8;i++){SCL=0;if(is_init){delay(8);}// if(SO)// {// temp+=(0x80>>i);// }temp=(temp<<1)+(uchar)SO;SCL=1;if(is_init)//放慢速度{delay(8);}}return(temp);}/*--------------------------------向SD卡写命令---------------------------------*/uchar write_cmd(uchar *pcmd)//pcmd为命令字{uchar temp,i,time=0;CS=1;spi_write(0XFF);CS=0;for(i=0;i<6;i++) //发送6个字节的命令字节序列{spi_write(*pcmd++);}spi_read();do{temp=spi_read();//一直读,直到读到的不是0XFF或者超时time++;}while((temp==0xff)&&(time<100));return temp;}/*------------------------------------SD卡复位,进入SPI模式,使用CMD0命令-------------------------------------*/uchar SD_Reset()//SD卡复位{uchar time,temp,i;uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节is_init=1;//set is_init flagCS=1;for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的{spi_write(0xff);//实质发了120个时钟(15*8)}CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==200){return(INIT_CMD0_ERROR );//cmd0写入失败}}while(temp!=0x01);CS=1;spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟return 0;//返回0,说明SD卡复位操作成功}/*-------------------------------------SD卡初始化,使用CMD1号命令---------------------------------------*/uchar SD_Init()//SD卡初始化,使用CMD1号命令{uchar time,temp;uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(INIT_CMD1_ERROR );}}while(temp!=0x00);is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度CS=1;spi_write(0xff);return 0;//说明初始化成功}/*-----------------------------向SD卡扇区中写数据,每一个扇区中有512个字节---------------------------------*/uchar SD_write_sector(unsigned long addr,uchar *Buffer){uchar temp,time;uint i;uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G// pcmd[4]=(addr&0x000000FF);//此行为增加项CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(temp);//命令写入失败}}while(temp!=0);for(i=0;i<100;i++)//这里要插入若干个时钟信号{spi_read();}spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中{spi_write(*Buffer++);}spi_write(0xff);spi_write(0xff);//两个字节CRC校验码temp=spi_read();//读取返回值if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收{CS=1;return(WRITE_BLOCK_ERROR );//写块数据失败}while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH// 中,需要一定时间,忙时为0x00,不忙是为0xff, )CS=1;spi_write(0xff);//补8个时钟return 0;}/*--------------------------------读SD卡的一个扇区---------------------------------*/uchar SD_read_sector(unsigned long addr,uchar *Buffer){uint i;uchar time,temp;uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令addr=addr<<9;pcmd[1]=((addr&0xff000000)>>24);pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(READ_BLOCK_ERROR);//读块失败}}while(temp!=0);while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节for(i=0;i<512;i++){Buffer[i]=spi_read();}spi_read();spi_read();CS=1;spi_write(0xff);//补8个时钟return 0;}/*---------------------------------串口初始化-----------------------------------*/void serial_init(void) //{TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1 TH0 = 0X3c; //设置定时初值,定时20ms,1s采用20*50算法TL0 = 0Xb0;ET0 = 1; //开定时器0中断标志TR0 = 1; //启动定时器0TH1 = 0xfd; //32M,9600TL1 = 0xfd;TR1 = 1; //启动定时器1SCON=0X40; //串口工作在方式1,不允许接收REN = 1; //允许串口接收ES = 1; //允许串口中断EA = 1; //开总中断}/*-------------------------函数名称:main()函数作用:主函数---------------------------*/void main(){int i=0;SD_Reset();SD_Init();serial_init();for(i=0;i<512;i++){pbuf[i]=i;//向缓冲区中写入数据}SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区for(i=0;i<512;i++){pbuf[i]=0;//清空数据缓冲区}SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据for(i=0;i<512;i++){P2=~pbuf[i];//将缓冲区中的数据输出在P2口,delay(1000);}//P2=0X00;while(1);}void timer0_int(void) interrupt 1 //中断程序,注意中断类型号{TH0=0X3c; //重新赋初值,并且必须要这样做,不然的话定时时间会不准确的TL0=0Xb0;cn++; //每当进入中断程序,count++,当有关参数设置正确后,程序会自动进入中断程序if(cn==20){cn=0;power = !power; //本机运行指示灯闪烁}}2009-10-17,09:26:21资料邮件回复引用回复编辑删除【1楼】andyluo324积分:123派别:程序还不够完善,等会改好后上完整版.2009-10-17,09:资料邮件编辑删除---------------------------------------- */uchar cn=0;/*--------------------------------------变量定义-----------------------------------------*/uchar is_init;//用于控制SPI的速度,通过为1与0进行选择uchar xdata pbuf[512];//定义512个数据缓冲区/*--------------------------------------函数名称:delay()函数作用:用于某些程序中的延时函数特点:无返回值,带入口参数-----------------------------------------*/void delay(uint k){uint m,n;for(m=0;m<5;m++)for(n=0;n<k;n++);}/*----------------------------------------函数名称:IO_init()函数作用:对相关IO进行初始化函数特点:无返回值,无入口参数------------------------------------------*/void IO_init(){SCL=1;CS=1;SO=1;power=1;}/*----------------------------------------函数名称:send_byte(uchar i)函数作用:对相关数据进行打印函数特点:无返回值,带入口参数--------------------------------------------*/void send_byte(uchar i){TI=0;SBUF=i;while(!TI);TI=0;}/*-------------------------------------------------------函数名:send_s()功能:用户函数,发送一个字符----------------------------------------------------------*/void send_s(char *s){int len=strlen(s);int i;for(i=0;i<len;i++)send_byte(s[i]);send_byte(0x0d);send_byte(0x0a);}/*-------------------------------SPI写一个字节----------------------------------*/void spi_write(uchar x)//SPI写一个字节,其中is_init为1{uchar i;for(i=0;i<8;i++){SI=((x<<i)&0x80);SCL=0;if(is_init){delay(8);}SCL=1;if(is_init){delay(8);}}}/*--------------------------------SPI读一个字节----------------------------------*/uchar spi_read(){uchar temp=0,i;SO=1;for(i=0;i<8;i++){SCL=0;if(is_init){delay(8);}// if(SO)// {// temp+=(0x80>>i);// }temp=(temp<<1)+(uchar)SO;SCL=1;if(is_init)//放慢速度{delay(8);}}return(temp);}/*--------------------------------向SD卡写命令---------------------------------*/uchar write_cmd(uchar *pcmd)//pcmd为命令字{uchar temp,i,time=0;CS=1;spi_write(0XFF);CS=0;for(i=0;i<6;i++) //发送6个字节的命令字节序列{spi_write(*pcmd++);}spi_read();do{temp=spi_read();//一直读,直到读到的不是0XFF或者超时time++;}while((temp==0xff)&&(time<100));return temp;}/*------------------------------------SD卡复位,进入SPI模式,使用CMD0命令-------------------------------------*/uchar SD_Reset()//SD卡复位{uchar time,temp,i;uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节send_s("SD_Reset start\n");is_init=1;//set is_init flagCS=1;for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的{spi_write(0xff);//实质发了120个时钟(15*8)}send_s("send 120 clk succeed\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==200){return(INIT_CMD0_ERROR );//cmd0写入失败send_s("send CMD0 ERROR\n");}}while(temp!=0x01);CS=1;spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟send_s("send CMD0 succeed\n");return 0;//返回0,说明SD卡复位操作成功}/*-------------------------------------SD卡初始化,使用CMD1号命令---------------------------------------*/uchar SD_Init()//SD卡初始化,使用CMD1号命令{uchar time,temp;uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};send_s("SD_Init start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(INIT_CMD1_ERROR );send_s("CMD1 ERROR\n");}}while(temp!=0x00);is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度send_s("send CMD1 succeed\n");CS=1;spi_write(0xff);send_s("SD_Init succeed\n");return 0;//说明初始化成功}/*-----------------------------向SD卡扇区中写数据,每一个扇区中有512个字节---------------------------------*/uchar SD_write_sector(unsigned long addr,uchar *Buffer){uchar temp,time;uint i;uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G// pcmd[4]=(addr&0x000000FF);//此行为增加项send_s("SD_write_sector start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(temp);//命令写入失败}}while(temp!=0);for(i=0;i<100;i++)//这里要插入若干个时钟信号{spi_read();}spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中{spi_write(*Buffer++);}spi_write(0xff);spi_write(0xff);//两个字节CRC校验码temp=spi_read();//读取返回值if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收{CS=1;return(WRITE_BLOCK_ERROR );//写块数据失败}while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH// 中,需要一定时间,忙时为0x00,不忙是为0xff, )send_s("SD_write_sector succeed\n");CS=1;spi_write(0xff);//补8个时钟return 0;}/*--------------------------------读SD卡的一个扇区---------------------------------*/uchar SD_read_sector(unsigned long addr,uchar *Buffer){uint i;uchar time,temp;uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令addr=addr<<9;pcmd[1]=((addr&0xff000000)>>24);pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);send_s("SD_read_sector start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(READ_BLOCK_ERROR);//读块失败}}while(temp!=0);while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节for(i=0;i<512;i++){Buffer[i]=spi_read();}spi_read();spi_read();CS=1;send_s("SD_read_sector succeed\n");spi_write(0xff);//补8个时钟return 0;}/*---------------------------------串口初始化-----------------------------------*/void serial_init(void) //{TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1 TH0 = 0X3c; //设置定时初值,定时20ms,1s采用20*50算法TL0 = 0Xb0;ET0 = 1; //开定时器0中断标志TR0 = 1; //启动定时器0TH1 = 0xfd; //11.0592M,9600TL1 = 0xfd;TR1 = 1; //启动定时器1SCON=0X40; //串口工作在方式1,不允许接收REN = 1; //允许串口接收ES = 1; //允许串口中断EA = 1; //开总中断}/*-------------------------函数名称:main()函数作用:主函数---------------------------*/void main(){int i=0;serial_init();send_s("serial_init!\n");IO_init();send_s("Port Init!\n");SD_Reset();SD_Init();for(i=0;i<512;i++){pbuf[i]=i;//向缓冲区中写入数据}SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区for(i=0;i<512;i++){pbuf[i]=0;//清空数据缓冲区}SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据for(i=0;i<512;i++){P2=~pbuf[i];//将缓冲区中的数据输出在P2口,send_byte(pbuf[i]);delay(1000);}//P2=0X00;while(1);}。
SD卡读写学习-----使用文档
SD 卡读写学习使用文档一、 概述SD 卡是基于 flash 的存储卡,其和 MMC 卡的区别在于初始化过程不同。
SD 卡的通信协议包括 SD 和 SPI 两类。
SD 卡使用卡内智能控制模块进行 FLASH 操作控制,包括协议、安全算法、数据存取、 ECC 算法、缺陷处理和分析、电源管理、时钟管理。
二、SD 卡读写操作读操作的块长度受设备 sector 大小 (512 bytes)的限制,但是可以最小为一个字节。
51单片机读写SD 卡一般使用SD 卡的SPI 模式 0、CMD 命令格式:First Byte Byte 2-5 Last Byte 参数:4Byte---32bit ,指向要写入的字节地址,所以限制了SD 卡可以最大写入4g 数据bit7 bit6 bit5~0 Databit7~1 bit0 01命令参数(高位在前)CRC 校验1示例: CMD0号命令,CMD24(0x40+24=0x58)号命令时,参数为要写入的地址。
固定 CMD0命令 参数(2-5) CRC 校验 固定01 | 00 0000 | 0000 0000 ........ 0000 | 1001 010 | 1 0x40, 0x00,0x00,0x00,0x00, 0x95 adr<<=9;//取512的整数倍,因一个扇区为512字节。
CMD[1]=(addr>>24); CMD[2]=(addr>>16); CMD[3]=(addr>>8); CMD[4]=(addr>>0); $、SPI 模式:SD 卡启动时处在SD 总线模式下,要进入SPI 模式时,要遵守如下操作。
SD 卡复位及初始化时,时钟频率一定要慢下来,最高不超过400KHZ 。
1)SD 卡复位复位SD 卡:a 、所有引脚拉高,片选CS 为1时,首先往SD 卡写入至少74个时钟信号。
(SD 卡协议规定)b 、片选CS 拉低为0,写入CMD0命令(0x40,0x00,0x00,0x00,0x00,0x95)c 、读取SD 卡MISO 返回数据直到SD 卡返回0x01。
sd卡读写
在断路器离线测试仪的设计和使用过程中,需要积累大量的正常状态和故障状态下的历史动作数据,形成样本库,作为断路器进行故障诊断的依据。
从数据库的建立和维护的角度来说,上位机比仪器本身更占有优势。
同时,由于仪器自身硬件系统资源的局限,相对复杂的故障诊断分析也需要利用上位机软件来实现。
因此,这就需要容量大、移动灵活的测试仪和上位机的中间存储介质。
SD卡(Seecure Digital Memory Cardl)是一种基于Flash的新一代存储器,具有体积小、容量大、数据传输快、移动灵活、安全性能好等优点,是许多便携式电子仪器理想的外部存储介质。
1 ATMEGAl28的SPI接口简介及基本数据传输SPI全称为“Series Peripheral Interface”,意为“串行外设接口”,是一种全双工、3线同步数据传输的串行总线接口。
图1为ATMEGA128单片机主机一从机通过SPI进行互连的示意图。
系统包括两个移位寄存器和一个主机时钟发生器。
主机通过将需要的从机的SS引脚拉低,启动一次通讯过程。
主机和从机将需要发送的数据放入相应的移位寄存器中。
主机在SCK引脚上产生时钟脉冲以交换数据。
主机的数据从主机的MOSI移出,从从机的MOSI移入;从机的数据从从机的MISO移出,从主机的MISO移入。
主机通过将从机的SS引脚拉高实现与从机的同步。
基本的通过SPI接口发送和接收单个字节的流程如图2所示。
值得注意的是,因为发送和接收是同时进行的,所以发送和接收数据使用同一个函数。
在发送数据时,并不关心函数的返回值;在接收数据时,可以发送并无实际意义的字节(如0xFF)作为函数的参数。
2 SPI模式下的ATMEGAl2B单片机与SD卡的接口电路SD卡为用户提供两种操作模式:SD模式和SPI模式。
SPI模式下SD卡的引脚定义如表1所示。
在该模式下,SD卡为主机提供了CS、SCLK、DI、DO四线接口。
ATMEGAl28单片机与SD卡的接口电路如图3所示。
单片机读写SD卡分析陈
单片机读写SD卡分析一、开篇二、硬件电路三、SPI操作1.初始化2.读3.写四、SD操作1.初始化2.读3.写五、FAT文件系统六、总结三、SPI操作1、SPI总线简介SPI(Serial Peripheral Interface--串行外设接口)总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息,20世纪80年代由Motorola 首先在其MC68HCXX系列处理器上定义的。
SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI总线系统可直接与各个厂家生产的多种标准外围器件直接接口,该接口一般使用4条线:串行时钟线(SCLK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOSI和低电平有效的从机选择线SS(有的SPI接口芯片带有中断信号线INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)。
其主要特点包括:可以同时发出和接受串行数据;可以作为主机或丛机工作;发送结束中断标志;写冲突保护;总线竞争保护。
图1是SPI总线架构示意图。
图1 SPI 总线架构基本特点:1.同步2.串行3.全双工4.非即插即用5.一主多从更多细节:1.同步时钟有主控芯片产生,每个时钟传输一位数据2.数据在传输前,首先要进行并转串,才能用一条线传输3.两条数据线,一条输入、一条输出4.主从双方有关于SPI传输的先验知识,如比特顺序、数据长度等5.数据传输有主控芯片发起,每次只与一个从芯片通讯SPI是一种同步全双工的通讯接口,每个时钟在两条数据线上各传输一比特数据。
SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。
工作模式:原理上讲,串行传输是按位传输方式,只利用一条信号线进行传输SPI由工作方式的不同,可分为两种模式:主模式和从模式 1).主模式将Master的数据传送给Slave,8位数据传送,传送完毕,申请中断2).从模式从控制器从SIMO引脚接收串行数据并把数据移入自身移位寄存器的最低位或最高位。
51平台通过SPI方式读写SD
一、总则本文件介绍了在51平台通过SPI方式读写SD/MMC卡,包括软硬件需求, SD/MMC硬件连接, SPI接口软件模拟,SD/MMC上电初始化,写单块,读单块,写多块,读多块,块擦除,上位串口通讯协议,PC上位软件操作说明等。
二、软硬件需求a) 单片机固件编译环境:Keil C51 uVision2b) PC上位软件编译环境:Visual C++ 6.0c) 硬件环境:1)W78E52B一片;2)SD/MMC卡插座一个;3)MAX232一片;4)cross串口线一条;三、SD/MMC硬件连接SD/MMC与51单片机引脚连接如下表1,供参考:51单片机引脚SD/MMC引脚P1_0SPI_CS (PIN1)P1_1SPI_SI(PIN2)P1_2SPI_SCK(PIN5)P1_3SPI_SO(PIN7)PIN4接VDDPIN3/6接GND表1 SD/MMC与51单片机引脚连接表注意:SD/MMC引脚除VDD(PIN4)/VSS(PIN3/6)外,其它引脚连接上拉电阻(47k)至3.3v 电源。
四、SPI接口软件模拟由于W78E52B没有集成硬件SPI接口,所以固件需要通过软件来模拟实现SPI接口;a) SPI接口基本原理:SPI采用HOST/SLAVE结构,HOST与SLA VE以字节为传输单位,支持4种模式;SPI接口定义有4个引脚CS,SI,SO,SCK;SD SPI接口工作于模式0,各引脚功能分别描述如下:1) CS为片选引脚,低电平为有效;2) SI为Host输出Slave输入引脚,空闲为高电平,SCK上升有效,;3) SO为Slave输出Host输入引脚,SCK下降有效;4) SCK为同步时钟;b) SPI HAL:包括4个函数,上层软件通过调用这4个函数,来实现与SD/MMC以SPI方式进行数据交换。
1) SPI_SendByte(INT8U onebyte)――以SPI方式向SD/MMC发送一个字节2) INT8U SPI_RecByte(void)――以SPI方式从SD/MMC接收一个字节3) SPI_CS_Assert(void)――将CS引脚置为低电平有效4) SPI_CS_Deassert(void)――将CS引脚置为高电平无效c) 通过SPI HAL发送的RESET命令CMD0波形图,如下图1,以供参考:图1-RESET命令CMD0波形图一、SD/MMC上电初始化当SD/MMC卡上电后,单片机需要对其进行上电初始化,上电初始化步骤顺序所列如下:1) 置CS为低,至少延时74个CLK,延时波形图,如图2,以供参考:图2-延时波形图1) 发送RESET命令CMD0,其波形图参考图1:2) 发送命令CMD1(SD卡使用命令ACMD41)激活SD/MMC卡, 固件需重复发送命令CMD1直到R1 idle state位为0。
stm32SPI模式读写SD卡
stm32SPI模式读写SD卡SPI模式读写SD卡SD卡初始化过程:1. 初始化STM32的SPI接口使用低速模式2. 延时至少74clock3. 发送CMD0,需要返回0x01,进入Idle状态4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态5. 设置读写block大小为512byte5. 把STM32的SPI设置为高速模式读一个block块的过程1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x002. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes写一个block块的过程1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x002. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes/******************************************************************* ************* Function Name : SD_MMC_SPI_Init* Description : SD_MMC_SPI_Init* Input : None* Output : None* Return : zero init success, non-zero init error************************************************************************ *******/u8 SD_MMC_SPI_Init(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_SD_MMC_SPI_CS, ENABLE);/* Configure SPI1 pins: SCK, MISO and MOSI */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);/* Configure SD_MMC_SPI_CS */GPIO_InitStructure.GPIO_Pin = SD_MMC_SPI_CS_Pin_CS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SD_MMC_SPI_CS, &GPIO_InitStructure);///////////////////////////////////////////////////////////////////////////////* initialize SPI with lowest frequency */SD_MMC_Low_Speed();/* card needs 74 cycles minimum to start up */for(u8 i = 0; i < 10; ++i) {/* wait 8 clock cycles */ SD_MMC_ReadWrite_Byte(0x00); } /* address card */ SD_MMC_SPI_SELECT();/* reset card */u8 response;for(u16 i = 0; ; ++i){response = SD_MMC_Send_Command(CMD_GO_IDLE_STATE ,0 );if( response == 0x01 ) break;if(i == 0x1ff) {SD_MMC_SPI_DESELECT(); return 1;}}/* wait for card to get ready */ for(u16 i = 0; ; ++i) {response = SD_MMC_Send_Command(CMD_SEND_OP_COND, 0);if(!(response & (1 << R1_IDLE_STATE)))break;if(i == 0x7fff) {SD_MMC_SPI_DESELECT(); return 1;}}/* set block size to 512 bytes */if(SD_MMC_Send_Command(CMD_SET_BLOCKLEN, 512)) {SD_MMC_SPI_DESELECT();return 1;}/* deaddress card */SD_MMC_SPI_DESELECT();/* switch to highest SPI frequency possible */ SD_MMC_High_Speed();return 0;//////////////////////////////////////////////////////////////////// //////////}/******************************************************************* ************* Function Name : SD_MMC_Read_Single_Block * Description :SD_MMC_Read_Single_Block * Input : sector number and buffer data point * Output : None* Return : zero success, non-zero error************************************************************************ *******/u8 SD_MMC_Read_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 Retry = 0;//读命令 send read commandResponse =SD_MMC_Send_Command(CMD_READ_SINGLE_BLOCK, sector<<9); if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();// start byte 0xfewhile(SD_MMC_ReadWrite_Byte(0xff) != 0xfe) {if(++Retry > 0xfffe){SD_MMC_SPI_DESELECT();return 1; //timeout}}for(i = 0; i < 512; ++i) {//读512个数据*buffer++ = SD_MMC_ReadWrite_Byte(0xff); }SD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff); // extra 8 CLKreturn 0;}/******************************************************************* ************* Function Name : SD_MMC_Write_Single_Block* Description : SD_MMC_Write_Single_Block * Input : sector number and buffer data point* Output : None* Return : zero success, non-zero error.************************************************************************ *******/u8 SD_MMC_Write_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 retry=0;//写命令 send write commandResponse =SD_MMC_Send_Command(CMD_WRITE_SINGLE_BLOCK, sector<<9);if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);//发开始符 start byte 0xfeSD_MMC_ReadWrite_Byte(0xfe);//送512字节数据 send 512 bytes datafor(i=0; i<512; i++){SD_MMC_ReadWrite_Byte(*buffer++);}SD_MMC_ReadWrite_Byte(0xff); //dummy crc SD_MMC_ReadWrite_Byte(0xff); //dummy crcResponse = SD_MMC_ReadWrite_Byte(0xff);//等待是否成功 judge if it successfulif( (Response&0x1f) != 0x05){SD_MMC_SPI_DESELECT();return Response;}//等待操作完 wait no busywhile(SD_MMC_ReadWrite_Byte(0xff) != 0x00) {if(retry++ > 0xfffe){SD_MMC_SPI_DESELECT();return 1;}}SD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff);// extra 8 CLKreturn 0;}if( SD_MMC_SPI_Init() ==1)printf(" _SD_MMC Initialization ERROR\r\n"); else{printf(" _SD_MMC Initialization OK\r\n"); //memset(buffer,0,512); //读取一个扇区的内容这里读的是0扇区SD_MMC_Read_Single_Block( 0 , buffer );Uart1_PutString( buffer , 512 );}。
SPI模式下对SD卡的操作
SPI模式下对SD卡的操作STM32的SPI设备简介:STM32F107VC有3个SPI设备,SPI控制器在输出数据的同时采样输入数据,使用相同时钟线。
Master设备写操作的同时,读入寄存器同时采样填充,每次也需要清空寄存器。
Master设备的读操作,实际上是通过写数据输出时钟序列,采样MISO的信号。
SD卡简介:SD卡的技术规范经过几次升级,与最初版本已有很大不同,本文基于Ver 3.01讨论从容量上分SD卡支持SPI的Mode0和Mode3SD卡支持50MHz总线,STM32的APB2总线最高72MHz,SPI分频?为36Mhz,理论上所有SD卡都可以正常操作,实际上一些低版本的卡缺乏稳定性插入信号CD:CD线是可选的信号线,没有卡时为高电位,有卡插入时CD为低电位电位稳定延迟:CS线为高的状态下输出若干时钟,延迟利于电位稳定SD卡的准备状态,初始化操作:SD卡从上电到可读写状态需要一定序列命令的操作,这个过程包括选择SPI模式和判断卡的版本以及供电操作SD规范中的流程图CMD0SD卡上电后使用CMD0进入SPI模式,CMD0的返回值是1字节的R1,R1应该为空闲0x01CMD8版本2.0以上的SD卡支持CMD8命令,包括大部分SDHC的卡和所有SDXC卡,早期的SDHC卡有可能仍属于V1.0卡命令返回值R7,第一字节为R1,Ver1.0的卡对R1的“非法命令”位2置位,Ver2.0以上卡应返回0x01ACMD41和CMD1ACMD41是为卡供电命令,供电前卡的状态为空闲(idle),R1的返回值为0x01,供电后为动作状态(ready)一些早期的卡认为ACMD41是非法命令,只能用MMC的CMD1命令供电CMD58CMD58读取卡的状态,一个重要的标志位CCS,会影响到读写操作中地址数据的设定CCS为1时为高版本卡,数据地址为页单位,512字节为一页CCS为0时,地址为以字节为单位实际地址CCS置位与否也取决于ACMD41中对HCS:30bit的置位请求CMD9取得卡容量等信息,CSO寄存器,CSO是16个字节的结构体,加上2字节的CRC,应读取18字节的内容卡的信息也有版本区别,需要分别处理CMD24 CMD17CMD24写数据CMD17读数据SD的读写都要以页单位进行,无论是否是新版本。
stm32SPI模式读写SD卡
stm32SPI模式读写SD卡SPI模式读写SD卡SD卡初始化过程:1. 初始化STM32的SPI接口使用低速模式2. 延时至少74clock3. 发送CMD0,需要返回0x01,进入Idle状态4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态5. 设置读写block大小为512byte5. 把STM32的SPI设置为高速模式读一个block块的过程1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x002. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes写一个block块的过程1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x002. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes/******************************************************************* ************* Function Name : SD_MMC_SPI_Init* Description : SD_MMC_SPI_Init* Input : None* Output : None* Return : zero init success, non-zero init error************************************************************************ *******/u8 SD_MMC_SPI_Init(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_SD_MMC_SPI_CS, ENABLE);/* Configure SPI1 pins: SCK, MISO and MOSI */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);/* Configure SD_MMC_SPI_CS */GPIO_InitStructure.GPIO_Pin = SD_MMC_SPI_CS_Pin_CS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SD_MMC_SPI_CS, &GPIO_InitStructure);///////////////////////////////////////////////////////////////////////////////* initialize SPI with lowest frequency */SD_MMC_Low_Speed();/* card needs 74 cycles minimum to start up */for(u8 i = 0; i < 10; ++i) {/* wait 8 clock cycles */ SD_MMC_ReadWrite_Byte(0x00); } /* address card */ SD_MMC_SPI_SELECT();/* reset card */u8 response;for(u16 i = 0; ; ++i){response = SD_MMC_Send_Command(CMD_GO_IDLE_STATE ,0 );if( response == 0x01 ) break;if(i == 0x1ff) {SD_MMC_SPI_DESELECT(); return 1;}}/* wait for card to get ready */ for(u16 i = 0; ; ++i) {response = SD_MMC_Send_Command(CMD_SEND_OP_COND, 0);if(!(response & (1 << R1_IDLE_STATE)))break;if(i == 0x7fff) {SD_MMC_SPI_DESELECT(); return 1;}}/* set block size to 512 bytes */if(SD_MMC_Send_Command(CMD_SET_BLOCKLEN, 512)) {SD_MMC_SPI_DESELECT();return 1;}/* deaddress card */SD_MMC_SPI_DESELECT();/* switch to highest SPI frequency possible */ SD_MMC_High_Speed();return 0;//////////////////////////////////////////////////////////////////// //////////}/******************************************************************* ************* Function Name : SD_MMC_Read_Single_Block * Description :SD_MMC_Read_Single_Block * Input : sector number and buffer data point * Output : None* Return : zero success, non-zero error************************************************************************ *******/u8 SD_MMC_Read_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 Retry = 0;//读命令 send read commandResponse =SD_MMC_Send_Command(CMD_READ_SINGLE_BLOCK, sector<<9); if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();// start byte 0xfewhile(SD_MMC_ReadWrite_Byte(0xff) != 0xfe) {if(++Retry > 0xfffe){SD_MMC_SPI_DESELECT();return 1; //timeout}}for(i = 0; i < 512; ++i) {//读512个数据*buffer++ = SD_MMC_ReadWrite_Byte(0xff); }SD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff); // extra 8 CLKreturn 0;}/******************************************************************* ************* Function Name : SD_MMC_Write_Single_Block* Description : SD_MMC_Write_Single_Block * Input : sector number and buffer data point* Output : None* Return : zero success, non-zero error.************************************************************************ *******/u8 SD_MMC_Write_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 retry=0;//写命令 send write commandResponse =SD_MMC_Send_Command(CMD_WRITE_SINGLE_BLOCK, sector<<9);if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);//发开始符 start byte 0xfeSD_MMC_ReadWrite_Byte(0xfe);//送512字节数据 send 512 bytes datafor(i=0; i<512; i++){SD_MMC_ReadWrite_Byte(*buffer++);}SD_MMC_ReadWrite_Byte(0xff); //dummy crc SD_MMC_ReadWrite_Byte(0xff); //dummy crcResponse = SD_MMC_ReadWrite_Byte(0xff);//等待是否成功 judge if it successfulif( (Response&0x1f) != 0x05){SD_MMC_SPI_DESELECT();return Response;}//等待操作完 wait no busywhile(SD_MMC_ReadWrite_Byte(0xff) != 0x00) {if(retry++ > 0xfffe){SD_MMC_SPI_DESELECT();return 1;}}SD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff);// extra 8 CLKreturn 0;}if( SD_MMC_SPI_Init() ==1)printf(" _SD_MMC Initialization ERROR\r\n"); else{printf(" _SD_MMC Initialization OK\r\n"); //memset(buffer,0,512); //读取一个扇区的内容这里读的是0扇区SD_MMC_Read_Single_Block( 0 , buffer );Uart1_PutString( buffer , 512 );}。
STM32读写SD卡要点
3.20SD卡实验很多单片机系统都需要大容量存储设备,以存储数据。
目前常用的有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 下载与测试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卡引脚功能描述如下表所示:表3.20.1.1 SD卡引脚功能表SD卡只能使用3.3V的IO电平,所以,MCU一定要能够支持3.3V的IO端口输出。
SD卡的SPI模式(中文)
SD卡的SPI模式(中文)
在SPI模式下,正好与SD模式相反,CMD1和ACMD41都没有打操作数和不会返回OCR寄存器的内容。而是,主机利用CMD58(仅用于SPI)去读 OCR寄存器。此外,主机有责任避免访问那此不在允许电压范围内的卡。 CMD58的应用不仅限于初始化期间,且可以用于任何时候。 7.2.8 错误条件 不像SD存储卡协议那样,在SPI模式下卡总会对一个命令作出响应。此响应显示了命令的接受和拒绝。如果一个命令不被支持,它被拒绝。如果CRC 校验失败,如果它含有非法的操作数,或者它在擦除序列期间不按照序列。 7.2.9 内存阵列
7.2.5 擦除和写保护 在SPI模式下擦除和写保护管理程序与SD模式下的相同。当卡正在擦除或者正在改变预定扇区清单的写保护位时,它将会进入忙状态且使DataOut线 为低电平。图46举例说明了一个有和没有忙信号的无数据的总线事务。
Figure46:无数据的操作
7.2.6 读CID/CSD寄存器 跟SD存储卡协议不同(在那里寄存器的内容是作为一个命令响应发送),在SPI模式下,CSD和CID的内容的读取是一个简单的块读事务。在16字节 的带16位CRC后缀的数据块之后,卡用一个标准的响应令牌来响应。 CSD命令的数据超时时间不能被设置入卡的TAAC,因为这个值是放在卡的CSD寄存器中。所以标准的响应超时值(NCR)被用于CSD寄存器的读响 应时间。
Figure42:读操作-数据错误
在多块读操作中,每一个被传输的块有它的16-CRC位。停止传输命令将实际地停止数据传输操作。(与SD模式相同)
Figure43:多块读操作
7.2.4 写数据 在SPI模式下,SD存储卡支持单块和多块写命令。在接收到有效的写命令(CMD24、CMD25)之后,卡将以一个响应令牌响应,然后等待主机发来 数据块。CRC后缀、块长度和起始地址都与读操作相同。(例外:控制片块读读操作的CSD参数WRITE_BL_PARTIAL)
SPI模式下SD卡的读写
SPI模式下SD卡的读写李书巳【摘要】SD卡具有移动性、体积小、容量大、易保存等许多优点,如今越来越多的被用于生产控制装置。
SD卡支持两种总线模式:SD模式与SPI模式。
SD模式时的数据传输速度与SPI模式要快,但是SD模式的协议复杂,采用单片机对SD 卡进行读写时一般都采用SPI模式。
采用不同的初始化方式可以使SD卡工作于SD模式或SPI模式。
本文以STC12C5A60S2单片机为例详细的介绍了SD卡在SPI模式下的读写操作过程。
【期刊名称】《数字技术与应用》【年(卷),期】2015(000)001【总页数】1页(P76-76)【关键词】SD卡读写;SPI模式;STC12C5A60S2单片机【作者】李书巳【作者单位】沈阳市苏家屯区职业教育中心辽宁沈阳 110102【正文语种】中文【中图分类】TP333.5随着科技的发展SD卡在人们的生活中被广泛的使用,由于SD卡具有移动性、体积小、容量大、易保存等许多优点如今越来越多的被用于生产控制装置。
一些设计开发人员会经常利用单片机对SD卡进行读写操作,下面就本人在SPI模式下SD 卡读写过程中遇到的一些问题与各位读者交流。
以STC12C5A60S2单片机为例,SPI模式下连接方法如图1,其中CS是片选端口为低电平有效,DI是SD卡写入数据端口即单片机输出数据,DO是单片机从SD卡读数据端口,CLK是同步时钟脉冲信号。
通常SD具有两种读写模式,一种是SD模式,SD卡被接通电源后就自动进入SD 模式,SD模式利用四条数据线可以实现数据并行传输,具有较高的传输速率。
但是其通讯协议比较复杂,并且多数单片机没提供专门的接口,如果用软件编写协议会使程序变得繁琐复杂,甚至影响数据传输效率。
另一种是SPI模式,我们在通电后将CS置“1”向SD卡CLK端发送至少74个时钟周期然后将CS置“0”向DI 端发送CMD0复位指令,然后向CLK发送时钟信号等待DO端回复“01H”表示复位成功,此时SD卡已进入SPI模式,并处在空闲状态。
SD卡读写操作详细说明
SD卡读写操作详细说明51单⽚机实现对SD卡的读写SD卡SPI模式下与单⽚机的连接图:22.23.//获得16位的回应24. Read_Byte_SD(); //read the first byte,ignore it.25.do26. { //读取后8位27. tmp = Read_Byte_SD();28. retry++;29. }30.while((tmp==0xff)&&(retry<100));31.return(tmp);32.}2)初始化SD卡的初始化是⾮常重要的,只有进⾏了正确的初始化,才能进⾏后⾯的各项操作。
在初始化过程中,SPI的时钟不能太快,否则会造初始化失败。
在初始化成功后,应尽量提⾼SPI的速率。
在刚开始要先发送⾄少74个时钟信号,这是必须的。
在很多读者的实验中,很多是因为疏忽了这⼀点,⽽使初始化不成功。
随后就是写⼊两个命令CMD0与CMD1,使SD卡进⼊SPI 模式初始化时序图:初始化例程:1.//--------------------------------------------------------------------------2.初始化SD卡到SPI模式3.//--------------------------------------------------------------------------4.unsigned char SD_Init()5.{6.unsigned char retry,temp;7.unsigned char i;8.unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};9. SD_Port_Init(); //初始化驱动端⼝10.11. Init_Flag=1; //将初始化标志置112.13.for (i=0;i<0x0f;i++)14. {15. Write_Byte_SD(0xff); //发送⾄少74个时钟信号16. }17.18.//向SD卡发送CMD019. retry=0;20.do21. { //为了能够成功写⼊CMD0,在这⾥写200次22. temp=Write_Command_SD(CMD);23. retry++;24.if(retry==200)25. { //超过200次26.return(INIT_CMD0_ERROR);//CMD0 Error!27. }28. }29.while(temp!=1); //回应01h,停⽌写⼊30.31.//发送CMD1到SD卡32. CMD[0] = 0x41; //CMD133. CMD[5] = 0xFF;34. retry=0;35.do36. { //为了能成功写⼊CMD1,写100次37. temp=Write_Command_SD(CMD);38. retry++;39.if(retry==100)40. { //超过100次41.return(INIT_CMD1_ERROR);//CMD1 Error!4.unsigned char Read_CSD_SD(unsigned char *Buffer)5.{6.//读取CSD寄存器的命令7.unsigned char CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};8.unsigned char temp;9. temp=SD_Read_Block(CMD,Buffer,16); //read 16 bytes10.return(temp);11.}4)读取SD卡信息综合上⾯对CID与CSD寄存器的读取,可以知道很多关于SD卡的信息,以下程序可以获取这些信息。
sd卡读写spi模式
sd卡读写 spi模式(图一)(图二)/************************************************ ********************************************************************函数名:unsigned char mmc_command(unsigned char *comm,unsigned char retuen_dat)功能:向sd卡写命令返回: 1- >;操作失败 0->;成功************************************************* ************************************************* ******************/unsigned char mmc_command(unsigned char*comm,unsigned char retuen_dat){unsigned char n,temp,count,n_count;count = 0;do{SSEL_D(0);for(n=0;n;100) return 1;}while(temp!=retuen_dat);return 0;}/************************************************ *******************************************************函数名:void mmc_init(void)功能:初始化sd卡返回:无************************************************* ************************************************* *****/void mmc_init(void){unsigned char command_dat[6];unsigned char n;for(n=0;n/************************************************ ************************************************* ******函数名:void write_mmc_dat(unsigned char*comm,unsigned char *dat,unsigned int len)功能:向sd写数据(底层)返回:无************************************************* ************************************************* *****/void write_mmc_dat(unsigned char *comm,unsigned char *dat,unsigned int len){unsigned char n,temp,n_count;//,count; unsigned int count;count = 0;for(count=0;count;>; 24);command_dat[2] = (addr >;>; 16);command_dat[3] = (addr >;>; 8);command_dat[4] = (addr >;>; 0);command_dat[5] = 0;write_mmc_dat(command_dat,buffer,512);}/************************************************ ************************************************* ******函数名:void write_mmc_dat(unsigned char*comm,unsigned char *dat,unsigned int len)功能:向sd读数据(底层)返回:无************************************************* ************************************************* *****/void read_mmc_dat(unsigned char *comm,unsigned char *dat,unsigned int len){unsigned char n,temp,count,n_count;count = 0;for(count=0;count;>; 24);command_dat[2] = (addr >;>; 16);command_dat[3] = (addr >;>; 8);command_dat[4] = (addr >;>; 0);command_dat[5] = 0;read_mmc_dat(command_dat,buffer,len);}#define SCK_IO(x) (x?(P1=0X0f):(P1=0X0f))//1->;输出 0->;输入#define MOSI_IO(x) (x?(P1=0X0f):(P1=0X0f))#define MISO_IO(x) (x?(P1=0X0f):(P1=0X0f))#define SSEL_IO(x) (x?(P1=0X0f):(P1=0X0f))#define SCK_D(x) (x?(P1|=0X01):(P1&=0XFE))#define MOSI_D(x) (x?(P1|=0X02):(P1&=0XFD))#define SSEL_D(X) (X?(P1|=0X08):(P1&=0XF7))#define MISO_I() (P1&0X04)/********************************************** 模式零 spi 写数据***********************************************/ void SPI_Send_Dat(unsigned char dat){unsigned char n;for(n=0;n上行为写下行为读code unsigned char leab[512] ={0x55,0xaa,2,3,4,5,6,7,8,9};unsigned char rmmc[16];main(){unsigned char i;Time_Count0_Init(0 ,1); //10ms时基start_time0(); //开启定时器0Time_Count1_Init(0,2); //用于产生9600串口波特率start_time1() ; //开启定时器1Uart_Config(1); //配置串口interrupt_Open(); //打开中断mmc_init();MMCWdBolckOne(0,leab);for(i=0;i。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7S P I模式本文是小弟自己翻译的(处女作哦~~~~~),难免有不妥之处,望交流指教!联系方式 QQ:286225453 Email:ioro55555@7.1介绍SPI模式SPI模式由二次传递协议组成,这个协议由Flash(基于SD卡)提供。
本模式是SD卡协议的子协议,目的是用SPI信道通讯。
SPI模式在SD卡上电后第一个复位指令(CMD0)执行后被选择,并且在接通电源时不能改变。
SPI标准定义7.2 SPI总线SD卡信道由指令和数据位(起始位和结束位)组成,SPI信道由字节定向。
每一个指令或数据块由8位的字节和CS标志构成。
类似SD卡协议, SPI通讯由指令、响应和数据组成。
全部的主机与SD卡之间的通信由主机控制。
主机执行每一跟CS标志为低的总线。
SPI模式与SD模式的响应特性有以下三方面不同∶1、被选择的卡始终对指令作出反应。
2、一个附加的(8BIT)响应产生。
3、在SD卡遇到数据检索问题时,它会作出错误反应,而不是像在SD模式中一样执行一次空操作。
除命令响应之外,每一个数据块在写操作期间会作出专门的信息响应标志反应发送给SD卡。
数据块可以大到一个扇区小到一个字节。
读/写操作由CSD(指令信号译码器)寄存器操作。
7.2.1模式选择SD卡在上电后自动SD模式。
如果CS标志在接受复位指令(CMD0)期间为低,它将进入SPI模式并且处于空闲状态。
如果SD卡识别到需要保持SD模式,它不会对指令作出任何反应并且保持在SD模式中。
如果需要SPI模式,SD卡将转到SPI模式并且进行SPI模式R1响应。
回到SD模式的必须重新上电。
在SPI 模式下,SD卡遵守部分协议系统。
支持SPI模式的SD卡指令始终有效。
7.2.2总线传送保护SPI模式每一个SD卡在总线上的数据传输由CRC(循环冗余码校验)保护。
在SPI模式, SD卡提供一种非保护模式(起动系统,建立可靠的数据联系来排除硬件或固件需要执行的CRC(循环冗余码校验)生成并且核验操作)。
在非保护模式下,指令的CRC(循环冗余码校验)仍然响应并且需要数据标志。
由于发射机和接收器忽略CRC(循环冗余码校验),它们可以任意定义。
SPI接口在非保护模式下初始化。
用来切换卡到SPI模式的复位指令(CMD0),在SD卡处于SD模式时收到并且必须有一个合法的CRC字段。
由于CMD0没有论据, 所有领域内容, 包括CRC领域, 是常数并且不要需要在运行时间被计算。
一个合法的重新设置命令是:0x40, 0x00, 0x00, 0x00, 0x00, 0x95主机可以使用CRC_ON_OFF 命令(CMD59)开启CRC(循环冗余码校验)。
7.2.3 读数据SPI 方式支持整块和多个块读操作(CMD17或CMD18) 。
当一个合法的读命令被接受时,SD卡将在长度定义在set_blocklen指令(CMD16)的数据标志后作出一个响应标志(参见图41) 。
一个合法的数据块由标准CCITT多项式(x16+x12+x5+1)产生16位CRC(循环冗余码校验)标记。
最大块长度由READ_BL_LEN给定,被定义在CSD。
如果部份块被允许(即CSD参量read_bl_len等于1), 块长度可以是在1和极限块大小之间的任意大小。
唯一读数据合法的块长度由read_bl_len给定。
起始地址可以是在卡的合法地址范围内的任一个字节地址。
每个块必须包含在一个唯一的物理卡片扇区。
在数据检索错误的情况下, SD卡片不会传送任何数据。
此时,一个数据错误响应标志将被送到主机。
如图42所示:在多个块读操作的情况下,每个被传递的块有它的16位CRC。
中止传输指令(CMD12)将停止数据传送操作(同SD卡操作方式一样) 。
图43: 多个块读操作7.2.4 写数据在SPI模式下,SD卡支持整块和多个块写指令。
在接受合法写指令(CMD24或CMD25)时, SD卡将以响应标志响应并且等待数据块从主机发送,块长度和起始地址限制是(除CSD(指令信号译码器)参量WRITE_BL_PARTIAL 控制部份块写选择之外) 与读操作一致的(见图44) 。
每个数据块有一个前缀“开始块”象征(一个字节) 。
在数据块被接受之后, SD卡将以一个数据响应标志响应。
如果数据块被接收并且没有错误, 它将被编程。
只要SD卡忙于编程, 一个连续的忙标志数据流将被送到主机(保证输出数据线路为低)。
一旦编程操作完成, 主机必须使用send_status命令(CMD13)检查编程的结果。
一些错误(例如地址溢出,违反写保护规定等。
) 只能在编程期间被查出。
唯一的合法性检查执行在数据块上并且通过数据响应标志传达给主机的是CRC(循环冗余码校验)和一般写入错误指示。
在多个块写操作时,在下个块的开始时中止通信将被看作“停止”标志代替“开始”标志。
在写入错误信号(数据响应)的情况下,主机将使用send_num_wr_blocks(ACMD22)来得到写好字块的数字。
数据标志说明在章节7.3.3里提到。
当SD卡忙时, 重置CS不会终止编程。
SD卡将复原输出数据线(三态)并且继续编程。
如果SD卡在编程完成之前被复位,输出数据线将被强制拉低并且所有命令将被撤销。
复位 (CMD0)将终止任一即将发生或正在执行的编程操作。
这可能破坏SD卡SPI模式在SPI模式下删除和写保护管理程序与SD模式相同。
当SD卡正在删除或改变预定义的扇形目录书写保护位时,它将处在忙状态并且保持输出数据线低。
如图46所示:7.2.6 读CID(通道标志)/CSD(指令信号译码器)寄存器不同于SD协议(寄存器内容作为命令响应发送), 在SPI模式下读CSD和CID是简单的读块。
SD卡将以一个标准响应标志反应(见图42)后面有16字节的CRC-16(16位循环冗余码校验)。
在数据存取时期,CSD指令无法设置SD卡的TAAC,因为它被存放在SD卡的CSD。
所以标准超出的响应时间(NCR)被用于读CSD(指令信号译码器)记录。
7.2.7复位次序SD卡需要一定的复位次序。
在上电以后复位或CMD0 (软件复位) SD卡进入空闲状态。
在这个状态唯一的合法的主机命令是CMD1(SEND_OP_COND), ACMD41 (SD_SEND_OP_COND) 和CMD58 (READ_OCR) 。
在SPI模式下,CMD1和ACMD41有一样的功能。
主机必须查询SD卡(重复地发送CMD1或ACMD41) 直到‘非空闲状态’位在卡片响应中表明(为0),那么卡片完成初始化并且准备好接收下个指令。
在SPI模式,与SD模式相反, CMD1和ACMD41没有操作数并且不归还OCR寄存器的内容。
反而,主机可以使用CMD58 (只在SPI模式有效)读OCR寄存器。
此外, 它的作用是避免主机不支持卡的电压范围。
CMD58的用法不只局限于初始化阶段, 而是可以在任何时候。
7.2.8错误状态不同于SD协议, 在SPI模式下,卡片将总对命令作出反应。
反应表明命令的采纳或拒绝。
命令可能被拒绝如果它不被支持(非法操作码), 如果CRC(循环冗余码校验)核对失败, 如果它包含了一个非法操作数, 或如果它在删除指令序列期间失序。
7.2.9 存储器阵列划分7.2.10 SD卡锁定/开SD卡用于锁定/开锁的指令在SPI模式下与SD模式是相同的。
指令反应类型是都是R1b。
在忙信号清除之后, 主机应该获得发出GET_STATUS指令的操作结果。
详见章节4.3.6 。
7.2.11操作专用命令除APP_CMD状态位(见4.10.1)在SPI模式无效外,其余的和SD模式一致。
7.2.12版权保护指令所有专门的版权保护ACMDs和安全功能与SD模式相同。
7.3 SPI模式处理寄存器7.3.1 指令标志所有的SD卡指令长度都是是6字节。
指令传输始终以左侧位开始。
所有指令由CRC(循环冗余码校验保护)(见7.2)。
指令和论证见表57。
和在SD模式一样, SPI指令被划分成几类(见表56) 。
注意,除了不支持SPI 模式的组(组1, 3 和9),必要的组在SPI模式中与SD模式一样。
详细的指令说明以下的表格提供SPI总线指令的一个详细说明。
响应定义见7.3.2。
表57列出所有SD卡指令。
在SPI模式项表明, 在SPI模式下是否支持该指令。
如果指令没有论证,这个字段的值应该调整为零。
指令的二进制编码由指令标志定义。
举例来说,‘000000’为CMD0 和‘100111’为CMD39SPI 方式1)缺省块长度是依照CSD指定的。
2)数据传输不能穿越一个物理块边界,除非在CSD中设置READ_BLK_MISALIGN。
3)数据传输不能穿越一个物理块边界,除非在CSD中WRITE_BLK_MISALIGN 持续。
4)R1b: R1 一个任选的忙信号响应。
零。
6) RD/WR _: “1”数据块到SD卡以下的表格描述全部的操作专用命令,由SD卡支持/保留。
以下的全部指令应该在app_cmd(cmd55)之前。
7.3.2 响应SD卡有几种类型的响应标志。
在SD模式下, 首先,所有都被传送到MSB(最高有效位):R1型1,空闲状态: 卡片2,清除复位:删除指令被接收了。
3,非法指令: 一个4,CRC通信错误: 上次的CRC检验失败。
5,删除程序错误: 在删除程序指令中有错误。
6,编址错误:在指令中有不准确的地址或没有匹配的块长度, 。
7,参量错误: 指令的论证(即地址, 块长度)在卡片的允许范围之外。
R1b型SPI模式这个响应标志与R1格式相同(又可选的忙信号补充)。
忙信号标志可以是任一字节数。
零值表明卡片忙。
非零值表明卡片准备好接受下一个命令。
R2型这个响应标志有二个字节并且发送响应到SEND_STATUS指令。
格式见表48 。
第一个字节与R1相同。
下面是第二字节的描述:SPI模式1,删除param:删除的一种无效选择、扇区或群。
2,违反写保护规定:命令设法写一个有写保护的字块。
3,卡片ECC(检错与纠错)失败: 卡片内部ECC被应用但没能校正数据。
4,CC(抄送)错误: 内部卡片控制器错误5,错误: 一般的或未知的错误在操作期间发生。
6,写保护删除空指令| 锁定/开锁指令失败:本状态位有含有二个操作。
当主机企图删除写保护的扇区或在卡片锁定/开锁操作期间指令错误。
7,卡被锁: 当用户使用时,设置锁定。
当开锁时,复位。
R3型这个响应标志由SD卡发送,当READ_OCR指令被接受时。
响应长度是5个字节(见图49)。
第一字节(最高有效位)的结构与R1响应类相同的。
其它四个字节包含OCR记数器。
数据响应每个写在卡上的数据块由数据响应标志承认。
这个字节的格式如下:状态位(status)的意义定义如下:‘010’ - 数据被接受。