SD卡代码 SPI软件模拟 初始化 基于easyARM1138
SD卡的SPI模式的初始化顺序
SD卡的SPI模式的初始化顺序这些天没有出门,一直在家研究SD卡的SPI模式的初始化顺序,这里为大家总结了一下编写该程序所需要的知识:1.SD卡的官方资料SD卡的官方资料(我承认这个资料很垃圾,比起民间的技术总结它的内容可谓又臭又长,但是作为基础也要了解一下,SD协议不用看)2.清晰明了的MMC卡时序图清晰明了的MMC卡时序图(虽然这个是MMC卡的,但是在初始化的时候CMD0的时序是一样的) 电路:我用的SD卡的电路其实很简单,参考SD卡的官方资料中的电路链接就可以的。
供电问题:由于SD卡的电压是3.3V,所以你的CPU必须支持3.3V的IO端口输出。
再来说一说鸡毛蒜皮的细节:1.为了使SD卡初始化进入SPI模式,我们需要使用的命令有3个:CMD0,ACMD41,CMD55(使用ACMD类的指令前应先发CMD55,CMD55起到一个切换到ACMD类命令的作用)。
2.为什么在使用CMD0以后不使用CMD1?CMD1是MMC卡使用的指令,虽然本文并不想讨论MMC卡的问题,但是我还是要说:为了实现兼容性,上电或者发送CMD0后,应该首先发送CMD55+ACMD41确认是否有回应,如果有回应则为SD卡,如果等回应超时,则可能是MMC卡,再发CMD1确认。
3.正确的回应内容应该是:CMD0——0x01(SD卡处于in-idle-state)CMD55——0x01(SD卡处于in-idle-state)ACMD41——0x00(SD卡跳出in-idle-state,完成初始化准备接受下一条指令)这里要说的是如果最后的回应内容还是0x01的话,可以循环发送CMD55+ACMD41,直到回应的内容0x00。
4.在所有的指令中,唯独CMD0特殊,在向SD卡发送以前需要向SD卡发送74+个时钟。
那么为什么要74个CLK呢?因为在上电初期,电压的上升过程据SD卡组织的计算约合64个CLK周期才能到达SD卡的正常工作电压他们管这个叫做Supply ramp up time,其后的10个CLK是为了与SD卡同步,之后开始CMD0的操作,严格按照此项操作,一定没有问题。
easyarm1138简明教程
EasyARM1138简明教程雷正东1001213933北京大学工学院力学与控制工程z.d.leipku@一、软件安装在EasyARM1138上进行开发,必须安装以下三个软件,以确保编程和写入的实现。
1、开发环境IAR软件安装:●运行“EW ARM-KS-WEB-511.exe”,要稍等几分钟●点击“Install IAR Embedded Workbench”开始安装●输入Name、Company、License#(在附带的.txt 文件里)●输入License#和License Key●安装到默认的路径下,不要更改,即C:\Program Files\IAR Systems\Embedded Workbench 5.0 Kickstart2、LM LINK驱动程序安装:●用原装的USB 电缆连接EasyARM1138 开发板与电脑●此时,Windows 会提示“找到新硬件”,然后开始安装;请在以下指定的位置安装驱动程序:EasyARM1138 产品光盘:\安装软件\LuminaryFTDI\●注意:如果出现“没有通过Windows 徽标测试”的警告,请选择“仍然继续”●注意:安装共有3 次,Stellaris Evaluation Board A、Stellaris Evaluation Board B以及USB Composite Device(虚拟UART)都要安装。
3、《Stellaris外设驱动库》安装:●将“Stellaris 外设驱动库(快速安装)”下的文件夹“ARM”复制到IAR 安装目录下,即“C:\Program Files\IAR Systems\Embedded Workbench 5.0 Kickstart”此时会弹出“确认文件夹替换”的对话框,请选择“全部”●将文件夹“PDL-LM3S-2752”复制到C:\盘根目录下,完成。
二、EasyARM1138主板结构介绍EasyARM1138电路原理图见EasyARM1138电路原理图_SCH. pdf主板电路主要分为四个部分,所有部分共地,共5V/3.3V电位。
我的easyarm
本文写给有一定51基础的LM3S入门者搭建编译下载平台搭建平台就不多说了,就是一些软件的安装,keil for arm编译和LuminaryFTDI驱动。
在D:/安装包/ARM编译及驱动安装包里有编译和驱动软件。
里面有说明,这就不说了。
KEIL FOR ARM 新建工程经历了三四天的时间,安装keil、驱动现在终于把arm的平台搭成了。
因为有前面学习STC51的基础所以下面正式开始LM3S1138的学习。
我认为所有的单片机甚至微处理器的使用不过就是用其来控制外设,因为只有一个单片机是什么都干不了的,做成装饰品还得先把管脚磨掉免得伤人。
但是加上外设以后就不一样了,有多么神奇完全超出你的想象。
回归正题学习LM3S1138不过就是学习如何用程序让他来控制外设。
好了,说了这么多就是一个重点,学习单片机重点学习程序。
建立工程以及选择下载仿真方式的步骤:(一):打开如图在sourcegroup1中添加startup.s在Larbry中添加driverlib.lib 和(这个文件在位置driverlib/grlib/rvmdk/和driverlib/scr/rvmdk中找).lib的文件就是多个c文件的集合,作用和c文件一样,只不过c文件是可以被别人打开阅读更改的,而lib文件不能被打开编辑。
在User 中添加工程名.c(二)在中设置linker use memory layout fromtarget dialogDebug use luminary eval boardUtilities luminary eval boardKo完成开始解释为什么要这样设置先说startup.s是什么。
首先想到的是打开看看就知道了,结果里面一大坨鸟语和汇编(汇编是写给机器读的低级语言,也不能算人话),算了还是问度娘吧。
这个貌似和A51一样,那作用也是一样的了,就是起一个引导作用,创造一个c语言可以运行的环境。
参见51基础里的A51研究。
TF卡 spi 模式实现方法+源码
我们可以发现 Micro SD 卡只有8个引脚是因为比 SD 卡少了一个 Vss。当然你也可以买个卡套套 在 Micro SD 卡上,这样一来大小就和 SD 卡一样大,这时候卡套上的9个引脚就和 SD 卡一样了,你可 以完全当做 SD 卡来操作。 spi 下电路的连接非常简单,接上电源线 Vdd 和地线 Vss,再接上 spi 的 CS,SCLK,DI(MOSI) 和 DO(MISO)就可以了,其他引脚可以放空。注意 SD 卡的电源和操作电压都为2.7-3.6V,5V 的单片 机要进行电平转换或串电阻限流。还有记得 SD 卡的 CS,SCLKh 和 DI 要用10~100K 的电阻上拉。我是 套了卡套接的电路,因为 Micro SD 卡的引脚太密了,不好焊接,SD 卡相对引脚好焊。因为没有卡座, 而且也没专门的 PCB 我就直接焊到卡套上,诶牺牲了一个卡套。下面是我自己画的电路图:
读单块方法: 1.发送 CMD17,收到0x00表示成功 2.连续读直到读到开始字节0xFE 3.读512个字节 4.读两个 CRC 字节 读单块时序图:
读多块方法: 1.发送 CMD18读,收到0x00表示成功 2.连续读直到读到开始字节0xFE 3.读512字节 4.读两个 CRC 字节 5.如果还想读下一扇区,重复2-4 6.发送 CMD12来停止读多块操作
读单块和多块: SD 卡读单块和多块的命令分别为 CMD17和 CMD18,他们的参数即要读的区域的开始地址。因为考 虑到一般 SD 卡的读写要求地址对齐,所以一般我们都将地址转为块,并以扇区(块) (512Byte)为 单位进行读写, 比如读扇区0参数就为0, 读扇区1参数就为1<<9(即地址512) , 读扇区2参数就为2<<9(即 地址1024) ,依此类推。
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的读写都要以页单位进行,无论是否是新版本。
easy1138开发环境安装、设置步骤
easy1138开发环境安装、设置、自检步骤本安装参考了周立功编写的“IAR EWARM5.11使用指南”,但是没有找到IAR for ARM 5.11版本的软件,只下载到了EWARM-5302-1316.zip,也即IAR EWARM5.302,经过试用暂时没有问题。
现编写步骤如下,也可参考周立功编写的文档。
1IAR EWARM的安装1.1.11IAR EWARM安装步骤1、解压CD-EWARM-5302-1316.zip文件;2、运行解压缩出来的;3、点击Install the IAR Embedded Workbench,开始安装。
如下图所示;4.在提示输入可证号(License)时,解压缩ewarm530keygen.rar会得到注册机。
1.运行注册机;2.选择For ARM V5.30.;3.点击Get ID;5、输入许可证号(License)和密钥(License key)当出现下面的界面时将证号(License)和密钥(License key)复制过来。
安装到默认的C盘路径下,不要更改,即C:\ProgramFiles\IARSystems\EmbeddedWorkbench5.41.2安装LM LINK驱动1、将光盘内Luminary“FTDI”驱动程序复制到C盘根目录下。
安装LM LINK驱动程序复制到C盘根目录下的FTDI文件2、用USB电缆将LM LINK与PC相连,这时会弹出硬件安装向导窗口,如图0.7所示,点击“下一步”继续安装就可以了。
选择从指定位置安装,指向C盘的C:\LuminaryFTDI文件夹C:\LuminaryFTDI所示的窗口,选择“仍然继续”就可以了。
3、点击“下一步”进行安装,安装过程中将出现如图0.9 Array*注意:如果出现“没有通过Windows徽标测试”的警告,请选择“仍然继续”*注意:安装共有3次,Stellaris Evaluation Board A、Stellaris Evaluation Board B以及USB Composite Device(虚拟UART)都要安装。
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-----------------------------------------------------------------------------* ----------------------------------------------* | STM32F10x | MSD Pin |* ----------------------------------------------* | PE.3 | ChipSelect 1 |* | PA.7 / MOSI | DataIn 2 |* | | GND 3 (0 V) |* | | VDD 4 (3.3 V) |* | PA.5 / SCLK | Clock 5 |* | | GND 6 (0 V) |* | PA.6 / MISO | DataOut 7 |* -----------------------------------------------******************************************************************************* ****//* Includes ------------------------------------------------------------------*///#include "stm32f10x_lib.h"#include "stm32f10x.h"#include "hardwareinit.h"/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define sd_cs_1 GPIO_SetBits(GPIOB,GPIO_Pin_12)#define sd_cs_0 GPIO_ResetBits(GPIOB,GPIO_Pin_12)#define sd_check GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15)/* Select MSD Card: ChipSelect pin low *///#define MSD_CS_LOW() GPIO_ResetBits(GPIOE, GPIO_Pin_3)/* Deselect MSD Card: ChipSelect pin high *///#define MSD_CS_HIGH() GPIO_SetBits(GPIOE, GPIO_Pin_3)//SD传输数据结束后是否释放总线宏定义#define NO_RELEASE 0#define RELEASE 1// SD卡类型定义#define SD_TYPE_MMC 0#define SD_TYPE_V1 1#define SD_TYPE_V2 2#define SD_TYPE_V2HC 4// SD卡指令表#define CMD0 0 //卡复位#define CMD1 1#define CMD9 9 //命令9 ,读CSD数据#define CMD10 10 //命令10,读CID数据#define CMD12 12 //命令12,停止数据传输#define CMD16 16 //命令16,设置SectorSize 应返回0x00#define CMD17 17 //命令17,读sector#define CMD18 18 //命令18,读Multi sector#define ACMD23 23 //命令23,设置多sector写入前预先擦除N个block #define CMD24 24 //命令24,写sector#define CMD25 25 //命令25,写Multi sector#define ACMD41 41 //命令41,应返回0x00#define CMD55 55 //命令55,应返回0x01#define CMD58 58 //命令58,读OCR信息#define CMD59 59 //命令59,使能/禁止CRC,应返回0x00//数据写入回应字意义#define MSD_DATA_OK 0x05#define MSD_DATA_CRC_ERROR 0x0B#define MSD_DATA_WRITE_ERROR 0x0D#define MSD_DATA_OTHER_ERROR 0xFF//SD卡回应标记字#define MSD_RESPONSE_NO_ERROR 0x00#define MSD_IN_IDLE_STA TE 0x01#define MSD_ERASE_RESET 0x02#define MSD_ILLEGAL_COMMAND 0x04#define MSD_COM_CRC_ERROR 0x08#define MSD_ERASE_SEQUENCE_ERROR 0x10#define MSD_ADDRESS_ERROR 0x20#define MSD_PARAMETER_ERROR 0x40#define MSD_RESPONSE_FAILURE 0xFF#define Dummy_Byte 0xA5 //0xff/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*///u8 Dummy_Byte = 0xa5; //0xff;u8 SD_Type; //SD卡的类型u8 buf[512];/* Private function prototypes -----------------------------------------------*//* Private functions ---------------------------------------------------------*/FlagStatus sd_insert_check(void);u8 SD_WaitReady(void); //等待SD卡就绪u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);u8 SD_Init(void); //SD卡初始化u8 SD_Idle_Sta(void); //设置SD卡到挂起模式u8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据u8 SD_GetCID(u8 *cid_data); //读SD卡CIDu8 SD_GetCSD(u8 *csd_data); //读SD卡CSDu32 SD_GetCapacity(void); //取SD卡容量//USB 读卡器SD卡操作函数//u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);//u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead);u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sectoru8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //写一个sectoru8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sectoru8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count);//写多个sectoru8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes);//读取一byte//--------------------------------spi speed setting-------------------------/****************************************************************************** ** Function Name : SPI_Config* Description : Initializes the SPI1 and CS pins.* Input : None* Output : None* Return : None******************************************************************************* /void SPI_Config(u16 BaudRatePrescaler){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;/* GPIOA and GPIOC Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);/* SPI1 Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/* Configure SPI2 pins: SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PE3 pin: CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_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 = BaudRatePrescaler;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);/* SPI1 enable */SPI_Cmd(SPI2, ENABLE);}void spi_high_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//SPI_BaudRatePrescaler_256;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_4);}void spi_low_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI_BaudRatePrescaler_4;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_256);}//---------------sd_insert_check---------------------------FlagStatus sd_insert_check(void){FlagStatus card_exist_state;if(!sd_check){card_exist_state = SET;}else{card_exist_state = RESET;}return card_exist_state;}//-------------------------------------------------------------------------/****************************************************************************** ** Function Name : SPI_FLASH_SendByte* Description : Sends a byte through the SPI interface and return the byte* received from the SPI bus.* Input : byte : byte to send.* Output : None* Return : The value of the received byte.******************************************************************************* /u8 SPIx_ReadWriteByte(u8 byte){/* Loop while DR register in not emplty */while ((SPI2->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);SPI2->DR = byte;/* Wait to receive a byte */while((SPI2->SR &SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);return SPI2->DR;}//u8 SPIx_ReadWriteByte(u8 byte)//{/* Loop while DR register in not emplty *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //((SPIx->SR & SPI_I2S_FLAG) != (uint16_t)RESET)/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);/* Wait to receive a byte *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);//}/****************************************************************************** ** Function Name : SPI_FLASH_ReadByte* Description : Reads a byte from the SPI Flash.* This function must be used only if the Start_Read_Sequence* function has been previously called.* Input : None* Output : None* Return : Byte Read from the SPI Flash.******************************************************************************* /u8 SPI_ReadByte(void){return (SPIx_ReadWriteByte(Dummy_Byte));}//-----------------------------------------------------------------------------------------------------------------------------------//等待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;u32 retry;retry=0;do{r1=SPIx_ReadWriteByte(0xFF)&0X1F; //读到回应if(retry==0xfffe)return 1;retry++;switch (r1){case MSD_DATA_OK: //数据接收正确了r1=MSD_DATA_OK;break;case MSD_DATA_CRC_ERROR: //CRC校验错误return MSD_DATA_CRC_ERROR;case MSD_DATA_WRITE_ERROR: //数据写入错误return MSD_DATA_WRITE_ERROR;default: //未知错误r1=MSD_DATA_OTHER_ERROR;break;}}while(r1==MSD_DATA_OTHER_ERROR); //数据错误时一直等待retry=0;while(SPIx_ReadWriteByte(0XFF)==0) //读到数据为0,则数据还未写完成{retry++;//delay_us(10); //SD卡写等待需要较长的时间if(retry>=0XFFFFFFFE)return 0XFF; //等待失败了};return 0; //成功了}//-----------------------------------------------------------------//向SD卡发送一个命令//输入: u8 cmd 命令// u32 arg 命令参数// u8 crc crc校验值//返回值:SD卡返回的响应u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc){u8 r1;u8 Retry=0;sd_cs_1;SPIx_ReadWriteByte(0xff); //高速写命令延时SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//片选端置低,选中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){u8 Retry=0;u8 r1;SPIx_ReadWriteByte(0xff);//高速写命令延时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);//等待响应,或超时退出while((r1=SPIx_ReadWriteByte(0xFF))==0xFF){Retry++;if(Retry>200)break;}//返回响应值return r1;}//------------------------------------------------------------//把SD卡设置到挂起模式//返回值:0,成功设置// 1,设置失败u8 SD_Idle_Sta(void){u16 i;u8 retry;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; //失败return 0; //成功}//---------------------------------------------------------------//初始化SD卡//如果成功返回,则会自动设置SPI速度为18Mhz//返回值:0:NO_ERR// 1:TIME_OUT// 99:NO_CARDu8 SD_Init(void){u8 r1; // 存放SD卡的返回值u16 retry; // 用来进行超时计数u8 buff[6];/*//设置硬件上与SD卡相关联的控制引脚输出//避免NRF24L01/W25X16等的影响RCC->APB2ENR|=1<<2; //PORTA时钟使能GPIOA->CRL&=0XFFF000FF;GPIOA->CRL|=0X00033300;//PA2.3.4 推挽GPIOA->ODR|=0X7<<2; //PA2.3.4上拉SPIx_Init();SPIx_SetSpeed(SPI_SPEED_256);//设置到低速模式*/spi_low_speed();sd_cs_1;if(SD_Idle_Sta()) return 1;//超时返回1 设置到idle 模式失败//-----------------SD卡复位到idle结束-----------------//获取卡片的SD版本信息sd_cs_0;r1 = SD_SendCommand_NoDeassert(8, 0x1aa,0x87);//如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化if(r1 == 0x05){//设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC SD_Type = SD_TYPE_V1;//如果是V1.0卡,CMD8指令后没有后续数据//片选置高,结束本次命令sd_cs_1;//多发8个CLK,让SD结束后续操作SPIx_ReadWriteByte(0xFF);//-----------------SD卡、MMC卡初始化开始-----------------//发卡初始化指令CMD55+ACMD41// 如果有应答,说明是SD卡,且初始化完成// 没有回应,说明是MMC卡,额外进行相应初始化retry = 0;do{//先发CMD55,应返回0x01;否则出错r1 = SD_SendCommand(CMD55, 0, 0);if(r1 == 0XFF)return r1;//只要不是0xff,就接着发送//得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次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(1,0,0);retry++;}while((r1!=0x00)&& (retry<400));if(retry==400)return 1; //MMC卡初始化超时//写入卡类型SD_Type = SD_TYPE_MMC;}//----------MMC卡额外初始化操作结束------------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();SPIx_ReadWriteByte(0xFF);//禁止CRC校验r1 = SD_SendCommand(CMD59, 0, 0x95);if(r1 != 0x00)return r1; //命令错误,返回r1//设置Sector Sizer1 = SD_SendCommand(CMD16, 512, 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] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[1] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[2] = SPIx_ReadWriteByte(0xFF); //should be 0x01buff[3] = SPIx_ReadWriteByte(0xFF); //should be 0xAAsd_cs_1;SPIx_ReadWriteByte(0xFF);//the next 8 clocks//判断该卡是否支持2.7V-3.6V的电压范围//if(buff[2]==0x01 && buff[3]==0xAA) //不判断,让其支持的卡更多{retry = 0;//发卡初始化指令CMD55+ACMD41do{r1 = SD_SendCommand(CMD55, 0, 0);if(r1!=0x01)return r1;r1 = SD_SendCommand(ACMD41, 0x40000000, 0);if(retry>200)return r1; //超时则返回r1状态}while(r1!=0);//初始化指令发送完成,接下来获取OCR信息//-----------鉴别SD2.0卡版本开始-----------r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);if(r1!=0x00){sd_cs_1;//释放SD片选信号return r1; //如果命令没有返回正确应答,直接退出,返回应答}//读OCR指令发出后,紧接着是4字节的OCR信息buff[0] = SPIx_ReadWriteByte(0xFF);buff[1] = SPIx_ReadWriteByte(0xFF);buff[2] = SPIx_ReadWriteByte(0xFF);buff[3] = SPIx_ReadWriteByte(0xFF);//OCR接收完成,片选置高sd_cs_1;SPIx_ReadWriteByte(0xFF);//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC //如果CCS=1:SDHC CCS=0:SD2.0if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC; //检查CCSelse SD_Type = SD_TYPE_V2;//-----------鉴别SD2.0卡版本结束-----------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();}}return r1;}//---------------------------------------------------------------------//从SD卡中读回指定长度的数据,放置在给定位置//输入: u8 *data(存放读回数据的内存>len)// u16 len(数据长度)// u8 release(传输完成后是否释放总线CS置高0:不释放1:释放)//返回值:0:NO_ERR// other:错误信息u8 SD_ReceiveData(u8 *data, u16 len, u8 release){// 启动一次传输sd_cs_0;if(SD_GetResponse(0xFE)) //等待SD卡发回数据起始令牌0xFE {sd_cs_1;return 1;}while(len--)//开始接收数据{*data=SPIx_ReadWriteByte(0xFF);data++;}//下面是2个伪CRC(dummy CRC)SPIx_ReadWriteByte(0xFF);SPIx_ReadWriteByte(0xFF);if(release==RELEASE)//按需释放总线,将CS置高{sd_cs_1;//传输结束SPIx_ReadWriteByte(0xFF);}return 0;}//-----------------------------------------------------------------//获取SD卡的CID信息,包括制造商信息//输入: u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCID(u8 *cid_data){u8 r1;//发CMD10命令,读CIDr1 = SD_SendCommand(CMD10,0,0xFF);if(r1 != 0x00)return r1; //没返回正确应答,则退出,报SD_ReceiveData(cid_data,16,RELEASE);//接收16个字节的return 0;}//-------------------------------------------------------------------//获取SD卡的CSD信息,包括容量和速度信息//输入:u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCSD(u8 *csd_data){u8 r1;r1=SD_SendCommand(CMD9,0,0xFF);//发CMD9命令,读CSD if(r1)return r1; //没返回正确应答,则退出,报错SD_ReceiveData(csd_data, 16, RELEASE);//接收16个字节的数据return 0;}//------------------------------------------------------------------------ //获取SD卡的容量(字节)//返回值:0:取容量出错// 其他:SD卡的容量(字节)u32 SD_GetCapacity(void){u8 csd[16];u32 Capacity;u8 r1;u16 i;u16 temp;//取CSD信息,如果期间出错,返回0if(SD_GetCSD(csd)!=0) return 0;//如果为SDHC卡,按照下面方式计算if((csd[0]&0xC0)==0x40){Capacity=((u32)csd[8])<<8;Capacity+=(u32)csd[9]+1;Capacity = (Capacity)*1024;//得到扇区数Capacity*=512;//得到字节数}else{i = csd[6]&0x03;i<<=8;i += csd[7];i<<=2;i += ((csd[8]&0xc0)>>6);//C_SIZE_MULTr1 = csd[9]&0x03;r1<<=1;r1 += ((csd[10]&0x80)>>7);r1+=2;//BLOCKNRtemp = 1;while(r1){temp*=2;r1--;}Capacity = ((u32)(i+1))*((u32)temp);// READ_BL_LENi = csd[5]&0x0f;//BLOCK_LENtemp = 1;while(i){temp*=2;i--;}//The final resultCapacity *= (u32)temp;//字节为单位}return (u32)Capacity;}//--------------------------------------------------------------------//读SD卡的一个block//输入:u32 sector 取地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}/*u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}*///----------------------------------------------------------------------//写入SD卡的一个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_WriteSingleBlock(u32 sector, const u8 *data){u8 r1;u16 i;u16 retry;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD24, sector, 0x00);if(r1 != 0x00){return r1; //应答不正确,直接返回}//开始准备数据传输sd_cs_0;//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//放起始令牌0xFESPIx_ReadWriteByte(0xFE);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1;return r1;}//等待操作完成retry = 0;while(!SPIx_ReadWriteByte(0xff)){retry++;if(retry>0xfffe) //如果长时间写入没有完成,报错退出{sd_cs_1;return 1; //写入超时返回1}}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return 0;}//-------------------------------------------------------------------//读SD卡的多个block(实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 连续读count个block//返回值:0:成功// other:失败u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count) {u8 r1;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式//如果不是SDHC,将sector地址转成byte地址if(SD_Type!=SD_TYPE_V2HC)sector = sector<<9;//SD_WaitDataReady();//发读多块命令r1 = SD_SendCommand(CMD18, sector, 0);//读命令if(r1 != 0x00)return r1;do//开始接收数据{if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)break;buffer += 512;} while(--count);//全部传输完毕,发送停止命令SD_SendCommand(CMD12, 0, 0);//释放总线sd_cs_1;SPIx_ReadWriteByte(0xFF);if(count != 0)return count; //如果没有传完,返回剩余个数else return 0;}//------------------------------------------------------------------------//写入SD卡的N个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 写入的block数目//返回值:0:成功// other:失败u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count){u8 r1;u16 i;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type != SD_TYPE_MMC) r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除r1 = SD_SendCommand(CMD25, sector, 0x00);//发多块写入指令if(r1 != 0x00)return r1; //应答不正确,直接返回sd_cs_0;//开始准备数据传输SPIx_ReadWriteByte(0xff);//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);//--------下面是N个sector写入的循环部分do{//放起始令牌0xFC 表明是多块写入SPIx_ReadWriteByte(0xFC);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1; //如果应答为报错,则带错误代码直接退出return r1;}//等待SD卡写入完成if(SD_WaitDataReady()==1){sd_cs_1; //等待SD卡写入完成超时,直接退出报错return 1;}}while(--count);//本sector数据传输完成//发结束传输令牌0xFDr1 = SPIx_ReadWriteByte(0xFD);if(r1==0x00){count = 0xfe;}if(SD_WaitDataReady()) //等待准备好{sd_cs_1;return 1;}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return count; //返回count值,如果写完则count=0,否则count=1 }//-----------------------------------------------------------------------------//在指定扇区,从offset开始读出bytes个字节//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buf 数据存储地址(大小<=512byte)// u16 offset 在扇区里面的偏移量// u16 bytes 要读出的字节数//返回值:0:成功// other:失败u8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes){u8 r1;u16 i=0;r1=SD_SendCommand(CMD17,address<<9,0);//发送读扇区命令if(r1)return r1; //应答不正确,直接返回sd_cs_0;//选中SD卡if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE{sd_cs_1; //关闭SD卡return 1;//读取失败}for(i=0;i<offset;i++)SPIx_ReadWriteByte(0xff);//跳过offset位for(;i<offset+bytes;i++)*buf++=SPIx_ReadWriteByte(0xff);//读取有用数据for(;i<512;i++) SPIx_ReadWriteByte(0xff); //读出剩余字节SPIx_ReadWriteByte(0xff);//发送伪CRC码SPIx_ReadWriteByte(0xff);sd_cs_1;//关闭SD卡return 0;}。
51单片机SD卡SPI模式操作_1568
【51单片机SD卡SPI模式操作】摘要:sd卡有两种接口模式,一种是sd模式,另一种是spi模式。
在spi模式下,有六根接口线与主机相连,5V电平的51单片机通过电平转换可与3.3V电平的sd卡相连接。
51单片机没有专门的spi总线,可以用51单片机的IO口来模拟spi总结时序。
主机与sd卡的数据交换主要通过命令来实现,通过发送cmd0命令对sd卡进行复位,发送命令cmd1实现sd卡的spi模式初始化。
cmd17、cmd18命令是sd卡的读写扇区命令,对sd卡的操作是严格按照时序进行的。
关键词:sd卡;spi接口;时序sd卡以其大容量、低成本、携带方便、存储数据简单和安全可靠性高被大量应用于数码电子设备中,比如数码相机、数码摄像机、mp3、pda、电子学习机、电子图书等。
对sd卡的操作有复位、初始化、读写等,下面以本人掌握的材料对sd卡的操作进行分析。
一、sd卡的结构sd卡的外形与接口如图1,它有9个接点与主机相连,其接口端定义如表1所示。
sd卡有两种操作模式,一种是sd模式,另一种是spi模式,不同模式下端口的定义不同。
SD模式有一个时钟线、一个命令/反馈线、四根输入/输出信号线、两个电源地和一个电源,所有九根线都有定义,数据传输速率较快。
SPI模式只用到CS片选、数据输入、数据输出、时钟、电源地及电源六根线。
SPI模式较SD模式速度较慢,但很多单片机都有专用的SPI总线,可与sd卡直接相连,使用方便。
SD卡的内部结构如图2所示,主要有四部分组成,一是接口电路,共有九个接口电路,定义如表1所示。
二是接口控制电路,所有操作都由该控制电路具体去执行。
三是内部寄存器组OCR、CID、RCA等。
四是存储数据的存储单元。
接口电路通过控制电路与内部寄存器组成存储单元交换数据,其主要操作有写命令、读数据、写数据、读状态等。
二、sd卡的命令格式sd卡的命令格式固定为6个字节48个位,其格式如图3所示。
开始位固定为0,第二位固定为1,表示主机给sd卡的命令,然后是6位命令索引号,索引号的大小与索引号数字相同,比如cmd0的索引号为000000,索引号41为101001。
基于SPI的SD卡驱动软件设计
时默认按高位在前 . 低位在后 的传输 方式 . 当然也可 以 通过配 置相关 寄存器 以采用 低位在前的传输方式 。但 是有一 点需要 注意的是 . 在一次数据传输过程 中 , 当传
到 最 后 一 个 字 节 时 .最 后 一 个 字 节 的 传 输 必 须 按 照 低
1 驱 动 设计
一
制 和设备 管理 机制 . 以及 S I P 设备 的数据传 输接 口. 通 过 函数指针 回调 的方式来执行具体 硬件相 关的处理细
节。
种模式来实现 .模式 的选择 在上电后的第 一个复位
命令 中进行 , 由主机到 S D卡 的片选信号 ( S信 号 ) C 决
定 , 设 计 研 究 的是 S I 式 的 S 本 P模 D卡 P 接 口(ei SI Sr 1 a P r hrlnef e 是 一 种 全 双 工 的 、 于 字 节 传 输 的 ei ea It a ) p rc 基 同 步 通 信 协 议 , 片 管 脚 上 只 需 要 占用 4根 线 . 节 约 芯 既 了 芯 片 管 脚 . 为 P B 的布 局 节 省 了 空 间 . 单 易 用 . 又 C 简
在 系统 初 始 化 的 时候 .我 们 需 要 先 在 当 前 处 理 器
上注册一个 S I P 控制器 . 作为 S I P 总线 的主设备 然后 当应 用程序需 要使 用 S I P 总线进 行数据 传输 的时 候 . 就可 以将数据 存储设备作为一个 S I P 从设 备注册到 主
11 P 设 备 驱 动 框 架 . S I
由于 S I 线 工 作 于 主从 模 式 , 此 , 备 驱 动框 P总 因 设
收 稿 日期 :0 1 2 7 2 1 —1 —2 修 稿 日 期 :0 2 0 —1 21—1 9
基于EasyARM1138单片机控制的水闸控制模拟系统
基于EasyARM1138单片机控制的水闸控制模拟系统作者:孔德山来源:《硅谷》2013年第09期摘要本文阐述了如何通过自动控制系统实现对水位的自动调节,通过EasyARM1138单片机和驱动电路以及直流电机控制水闸自动泄洪,本系统中加入了反馈环节,从而使该系统能够自动的识别信号,进而将信号传入单片机中,通过软件的处理,利用直流电机控制水闸打开或关闭。
整个自动控制系统一旦设定好,无需再人工操作,既节省人力,又能及时排除险情。
关键词 L298N驱动电路;直流电机;水位探测器中图分类号:TP273 文献标识码:A 文章编号:1671—7597(2013)051-018-01夏天是一个多雨的季节,每到这个时候,水库里的水都会急剧上升,如果不能及时的对水位做出正确的处理,那么就会容易发生洪涝等灾害。
为了能够自动及时的对水库里的水位做出反应,通过水闸控制模拟系统改变水位的变化,进而不会对环境,人们的财产造成威胁。
本模拟系统利用软件通过驱动电路控制电机,当水位探测器探测水位达到某一高度时,此时水位探测器将信号传送给单片机,使驱动电路控制直流电机正向旋转,从而将水闸打开,放出多余的水;当水位下降到一定高度时,此时水位探测器将信号传给单片机,通过软件处理,使直流电动机反转,进而将水闸关闭。
1 总体设计1.1 总体结构图1.2 硬件结构1.2.1 L298N驱动电路L298N驱动电路是ST公司生产的一种高电压、大电流电机驱动芯片。
使用L298N驱动电路可以驱动两台直流电机。
分别为M1和M2。
引脚A,B可用于输入PWM脉宽调制信号对电机进行调速控制。
实现电机正反转就更容易了,输入信号端IN1接高电平输入端IN2接低电平,电机M1正转。
控制另一台电机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电机M2正转。
(反之则反转),PWM信号端A控制M1调速,PWM信号端B控制M2调速。
1.2.2 EasyARM1138单片机1.3 软件结构1.3.1 主要程序1.3.2 程序流图(如右图)2 总结本次水闸自动控制模拟系统经过试验的验证能较高的完成通过单片机的控制达到自动控制水闸自动泄洪的功能,通过水位监测仪的自动检测,但出现水位过高时会将信息传给单片机,通过单片机的处理使电机运转从而使水闸开闭,达到泄洪的目的。
SD卡引脚及spi模式基本操作过程
SD卡引脚及spi模式基本操作过程(摘自网络)对于SD卡的硬件结构,在官方的文档上有很详细的介绍,如SD卡内的存储器结构、存储单元组织方式等内容。
要实现对它的读写,最核心的是它的时序,笔者在经过了实际的测试后,使用51单片机成功实现了对SD卡的扇区读写,并对其读写速度进行了评估。
下面先来讲解SD卡的读写时序。
SD卡的引脚定义SD卡引脚功能详述:引脚编号SD模式SPI模式名称类型描述名称类型描述1 CD/DAT3 IO或PP 卡检测/数据线3#CS I 片选2 CMD PP 命令/回应DI I 数据输入3 VSS1 S 电源地VSS S 电源地4 VDD S 电源VDD S 电源5 CLK I 时钟SCLK I 时钟6 VSS2 S 电源地VSS2 S 电源地7 DAT0 IO或PP 数据线0 DO O或PP 数据输出8 DAT1 IO或PP 数据线1 RSV9 DAT2 IO或PP 数据线2 RSV注:S:电源供给I:输入O:采用推拉驱动的输出PP:采用推拉驱动的输入输出SD卡SPI模式下与单片机的连接图:SD卡支持两种总线方式:SD方式与SPI方式。
其中SD方式采用6线制,使用CLK、CMD、DAT0~DAT3进行数据通信。
而SPI方式采用4线制,使用CS、CLK、DataIn、DataOut进行数据通信。
SD方式时的数据传输速度与SPI方式要快,采用单片机对SD卡进行读写时一般都采用SPI模式。
采用不同的初始化方式可以使SD卡工作于SD方式或SPI 方式。
这里只对其SPI方式进行介绍。
SPI方式驱动SD卡的方法SD卡的SPI通信接口使其可以通过SPI通道进行数据读写。
从应用的角度来看,采用SPI接口的好处在于,很多单片机内部自带SPI控制器,不光给开发上带来方便,同时也见降低了开发成本。
然而,它也有不好的地方,如失去了SD卡的性能优势,要解决这一问题,就要用SD方式,因为它提供更大的总线数据带宽。
SD卡初始化命令介绍
SD卡有很多种类型的命令,有初始化的,特殊功能开启关闭的,寄存器查看的,读和写的,官方给出的分类更清楚一些,不过在一般使用中,我们并不需要了解的多么复杂,只要掌握了最基本的初始化命令,和读写命令,SD卡的操作就能够实现了。
每一个命令的长度都是固定的6个字节,前1个字节的值=命令号+0x40;中间4个字节为参数,不同的命令参数格式都不相同,但参数最多为4个字节;最后1个字节是CRC校验码和1位固定结束位‘1’。
这里需要说明一下0x40的意思,任何命令都有一个固定的起始格式,即先0后1,这是固定的命令起始标志,前两个字节的二进制码就是:01xx xxxx需要特殊说明的是CRC的问题,这是一种检验错误的方法,具体问题度娘说的还算明白,在SPI 模式中,CRC校验默认是关闭的,也就是说这7位必须要发,但是SD卡会在读到CRC以后自动忽略它,所以全部发1就可以。
例外的是,CMD0,CMD8这两个命令发送的时候SD卡还没有进入SPI模式,也就是说CRC校验在这个时候还是启用状态,因此这两个命令的CRC效验码必须要写正确,SD卡才会执行命令,否在在返回值R1中就会有相应的错误标志位提示开发人员CRC校验码错误。
CMD0:0x40,0x00,0x00,0x00,0x00,0x954个字节的参数都为stuff bits 填充位,那就全0即可,最后一个字节CRC是固定的CMD8:0x48,0x00,0x00,0x01,0xaa,0x870x40的固定值+8=0x48;Reserved bits也是可以填充为0的位,VHS支持电压的说明可参考datasheet,需要说明的是参数的最后1byte检查位,这个字节的内容会在R7中原原本本的返回给用户,但是这个字节的不同决定了7位CRC的不同,网上的例子一般都发0xaa,那对应的CRC码+结束位就是0x87。
A CMD41属于附加命令,发送起来要麻烦一些,必须提前通知SD卡下一条要发送的命令为ACMD,这个通知就是CMD55,它的4字节参数都为0即可,CMD55 :0x77,0x00,0x00,0x00,0x00,0xff.0x77 = 0x40 + 0x37(55的16进制表示);CRC可以忽略不要都发1即可 0xff.ACMD41:0x69,0x40,0x00,0x00,0x00,0xff.第一个字节算法同理,第一个参数从DATASHEET可以看出HCS位被置1了,目的是为了告诉SD卡我的MCU支持SDHC卡,如果SD卡不回应CMD8也就是说当前SD卡为1.0版本,那么发送ACMD41时SD卡会自动忽略这个位。
毕勇强EasyARM1138基础实验
IIC总线控制原理
汇报人:毕勇强
主要内容
• 一、EasyARM1138简介 二、IIC总线控制功能 三、实验目的 四、功能实现的程序说明
EasyARM1138的简介
● EasyARM1138是一款基于 ARM Cortex ™ -M3 先进内核 的高性能开发板。它的核心MCU是美国Luminary Micro 公 司的Stellaris®(群星)系列ARM之LM3S1138。
EasyARM1138的简介
IIC总线控制功能简介
• 本次实验使用的实验板的ARM采用的是 ARMCortexM3,该芯片有两组IIC硬件接 口。分别为34/35引脚对应的 (PA6/IICSCL)/(PA7/IICSDA)以及 70/71引脚对应的(PB2/IIC0SCL)/ (PB3/IICO0SDA)。
• ◆内嵌USB接口的下载仿真器 仅需插入一根 USB 电缆就 能5V 供电、程序下载与在线仿真、UART 串行通信“三合 一”功能。
• ◆简明的外围电路设计 调试时无需任何连线和跳线,操 作极为方便
EasyARM1138的简介
• ◆在软件上采用“C 语言+驱动库”的开发模式 提供《Stellaris外设 驱动库》快速安装方法及C 语言源代码。
功能实现的程序说明
• (一)程序流程图
功能实现的程序说明
• (二) 硬件主程序说明
功能实现程序说明
(三) 软件主程序说明
6MHz 主频,设 置I2C 主机速率 为15kbps
谢 谢!
• 本次试验CPU采用不分频方式主振荡器为OSC外接6MHZ 晶振作为系统的时钟源。
• 各使用部分的使能包括以下几点:IIC管脚使能、中断使
EasyARM1138学习过程
今天拿到了周立功的EasyARM1138开发板,又要准备大干一场了!晒晒:我准备分以下几个方面开始学习:1.了解LM3s1138内部结构,包括存储器,ADC,GPIO,等等。
其中我认为最重要的是对各个寄存器地址的掌握。
因为个人认为写驱动程序就是对各种寄存器的读写,只要把各个寄存器的地址弄清楚了(个人愚见),那么很多问题也就迎刃而解了。
2.熟悉软件开发平台IAR。
这一点我就不想多啰唆了,反正每个处理器都有一个自己的软件开发平台,所以我就烦感:又得花时间去熟悉。
那么多家大公司能不能合伙一起开发一个软件平台呢,这样给用户带来好多的方便。
3.软件硬件结合开发。
这就要好多东西了~!有的搞的,呵呵。
下面结合实例程序谈谈对这个板子的理解。
这是一个简单的LED程序:第一行是添加到系统的头文件,我们找到这个头文件:在这个头文件里面,又包含了很多的头文件,还有一些宏定义,不要怕麻烦,在看看这些子头文件里面到底是什么:我们打开第一个头文件hw_types.h,字面意思应该是硬件类型的定义。
打开看看就知道了:果然如此,第一句就说这是Stellaris外设驱动程序库3223的一部分;第二句蓝色字体就是说定义了一个Boolean类型,它的值是true 表示1,false表示0。
我们接着往下看:同样,这里也无非就是些#define,咋一看有点复杂。
不怕,我们看看蓝体字:意思是宏硬件访问,不管是直接访问还是通过bit-band区域访问。
这里我对bit-ba nd 就不了解了,没关系,现在就去了解它。
查看lm3s1138的datasheet。
这里说的很清楚。
具体是这样的:Stellaris器件内部的SRAM的地址是0x2000.0000,为了减少读-修改-写(R MW)操作的时间,ARM在Cortex-M3处理器中引入了bit-banding技术。
在bit-bandi ng使能的处理器中,存储器映射的特定区域(SRAM和外设空间)能够使用地址别名,在单个原子操作中访问各个位。
SD卡的SPI模式(中文)
7.2.3 读数据 SPI支持单块读和多块读操作(在SD存储卡协议中的CMD17 OR CMD18)。当接收一个有效的读命令后卡将在一个在SET_BLOCK_LEN(CMD16)定义 了长度的数据令牌之后,用一个响应令牌作出回复。(参考Figure41)
Figure41 单块读操作
一个有效的数据块被添加了一个16位CRC,此CRC由CCITT标准多项式X16+X12+X5+1生成。 能被READ_BL_LEN给出的最大的块的的长度大CSD中定义了。如果片块被允许,块长度可以是1~MAX块大小之间的任何长度。否则,数据读的有 效块长度只是在READ_BL_LEN中给出的值。 起始地址可以是在卡的有效地址范围内的任何字节地址。但是,每一个块,必须包含入一个单一的物理卡扇区中。 如发生一个可修复错误,卡不会传输任何数据,而是发送一个特定的数据错误令牌到主机。
7.2.7 复位序列 SD卡需要一个定义了的复位序列。上电复位或CMD0之后,卡进入了空闲模式。在这个模式中,合法的主机命令只有CMD1、ACMD41、CMD58。 在SPI模式下,CMD1和ACMD41都有同样的行为。
/bbs/view_4_3477.html(第 3/8 页)2010-9-4 下午 22:05:51
请参考英文原版。
7.2.10 卡片 锁定/解锁
请参考英文原版。
7.2版。
7.2.12 版权保护命令
请参考英文原版。
7.3 SPI模式事务包
7.3.1 命令令牌 1、命令格式 所有的SD存储卡命令都是6字节长。命令的传输总是以相应的命令代码字的左边位开始。所有的命令由CRC保护。命令的参数由以下表给出。 2、命令集 如SD模式一样,SPI命令分成几个集合。每一个集合支持一类的功能。在这两种通信模式下,SD存储卡都支持同组的可选命令集。 3、命令详细说明 下表给出了一个SPI模式总线命令集的详细说明.响应在7。3。2中定义了。表57列出了所有SD存储卡命令。SPI 模式的“YES”表示此命令在SPI模式下 被支持。由于这此限制,CSD中此命令集描述仍有效。如果一个命令不需要参数argument,此域的值应该设为零。被保留的命令在SD 模式中也是被 保留。命令的二进制代码通过记忆标志来定义。举一个例子,command index域的内容是二进制的“000000”(CMD0)和“100111”(CMD39)。 Table57:命令和argument
SPI初始化程序
//SPI初始化子程序,用于数码管显示void spi_intial(){=0x0047; // 使SPI处于复位方式, 下降沿, 八位数据 =0x0006; //主控模式,般时钟模式,使能talk,闭SPI中断SpiaRegs.SPIBRR =0x007F; //配置波特率=; // 退出复位状态EALLOW;;// 设置通用引脚为SPI引脚EDIS;}//IO初始化子程序void gpio_init(){EALLOW;; //GPIOA11设置为一般I/O口; //把GPIOA11设置为输出//将GPIOE0~GPIOE2配置为一般I/O口输出,作138译码= ;= ;//将GPIOB8~GPIOB15配置为一般I/O口,D0~D7= ;EDIS;; //GPIOA11=0;该端口为74HC595锁存信号}//键扫描子程序K1~K8int Keyscan1(void){EALLOW;//将GPIOB8~GPIOB15配置为输入,D0~D7= ;EDIS;= 0xfff8; //选通KEY低8位for (i=0; i<100; i++){} //延时//判K1~K8是否按下if (({for (i=0; i<30000; i++){} //延时消抖if (({KeyReg1= ; //读键值while (( //判K1~K8是否松开{= !;for (i=0; i<1000; i++){}}return (1);}}return (0);}//键扫描子程序K9~K16int Keyscan2(void){EALLOW;//将GPIOB8~GPIOB15配置为输入,D0~D7 = ;EDIS;= 0xfff9; //选通KEY高8位for (i=0; i<100; i++){} //延时//判K8~K16是否按下if (({for (i=0; i<30000; i++){} //延时消抖if (({KeyReg2= ; //读键值while (( //判K8~K16是否松开{= !;for (i=0; i<1000; i++){}}return (1);}}return (0);}//按键记录次数,显示在16个LED上void LedOut(Uint16 led){EALLOW;//将GPIOB8~GPIOB15配置为输出,D0~D7 = ;EDIS;= 0xfffb; //LEDB选通= ~led; //显示高8位for (i=0; i<100; i++){} //延时= 0xffff; //锁存高8位= 0xfffa; //LEDA选通= ~(led<<8); //显示低8位for (i=0; i<100; i++){}= 0xffff; //锁存低8位}//键散转子程序K1~K8void KeyFunction1(unsigned int KeyReg1) {switch(KeyReg1){case K1: {LEDReg= 0x00; //键号0}break;case K2: {LEDReg= 0x01; //键号1}break;case K3: {LEDReg= 0x02; //键号2}break;case K4: {LEDReg= 0x03; //键号3}break;case K5: {LEDReg= 0x04; //键号4}break;case K6: {LEDReg= 0x05; //键号5}break;case K7: {LEDReg= 0x06; //键号6}break;case K8: {LEDReg= 0x07; //键号7}break;default:break;}}//键散转子程序K9~K16void KeyFunction2(unsigned int KeyReg2) {switch(KeyReg2){case K9: {LEDReg= 0x08; //键号8}break;case K10: {LEDReg= 0x09; //键号9}break;case K11: {LEDReg= 0x0A; //键号A}break;case K12: {LEDReg= 0x0B; //键号B}break;case K13: {LEDReg= 0x0C; //键号C}break;case K14: {LEDReg= 0x0D; //键号D}break;case K15: {LEDReg= 0x0E; //键号E}break;case K16: {LEDReg= 0x0F; //键号F}break;default:break;}}void display (LEDReg) //显示子程序{; //给LACK信号一个低电平SpiaRegs.SPITXBUF =LEDCode[LEDReg]; //给数码管送数while( != 1){}SpiaRegs.SPIRXBUF = SpiaRegs.SPIRXBUF;; //给LACK信号一个高电平为锁存74HC595for(i=0;i<10;i++){} //延时}void main(void){Uint16 keyNum = 0x0000; //按键次数初始化InitSysCtrl(); // 系统初始化程序,该子程序存放在DSP281x_sysctrl.c中DINT; //关闭总中断spi_intial(); //SPI初始化子程序gpio_init(); // I/O初始化子程序IER = 0x0000; // 关闭外围中断IFR = 0x0000; // 清中断标志LedOut(keyNum); // LED指示灯初始化for(i=0;i<8;i++)// 8个数码管清0{SpiaRegs.SPITXBUF =LEDCode[0]; //给数码管送数while( != 1){}SpiaRegs.SPIRXBUF = SpiaRegs.SPIRXBUF;}; //给LACK信号一个高电平为锁存74HC595for(i=0;i<10;i++){}while (1){if (Keyscan1() == 1) // 调用键扫描K1~K8子程序{keyNum=keyNum+1; // 按键记数KeyFunction1(KeyReg1);display (LEDReg); //显示键值LedOut(keyNum); //显示按键次数}if (Keyscan2() == 1) // 调用键扫描K8~K16子程序{keyNum=keyNum+1;KeyFunction2(KeyReg2);display (LEDReg); //显示键值LedOut(keyNum); //显示按键次数}}}。
SPI模式下SD卡驱动的设计与实现
SPI模式下SD卡驱动的设计与实现
田茂;鲜于李可;潘永才
【期刊名称】《现代电子技术》
【年(卷),期】2009(32)14
【摘要】SD卡以其优越的性能在嵌入式设备上得到广泛的应用.介绍在
S1C33L05处理器上利用SPI总线进行SD卡的功能扩展.首先介绍具体硬件接口电路的设计,然后介绍利用SD卡的R1应答模式和处理器进行SPI总线通信的通信协议,并在此基础上实现SD卡驱动程序,最后介绍利用S1C33L05处理器的硬件中断实现热插拔的方法.实验表明,该方案在实际的应用系统中运行可靠,实用性强,在其他需要进行SD卡硬件扩展的嵌入式系统中也有很好的参考价值.
【总页数】3页(P195-196,199)
【作者】田茂;鲜于李可;潘永才
【作者单位】湖北大学,物理学与电子技术学院,湖北,武汉,430062;湖北大学,物理学与电子技术学院,湖北,武汉,430062;湖北大学,物理学与电子技术学院,湖北,武汉,430062
【正文语种】中文
【中图分类】TP368
【相关文献】
1.SPI模式下SD卡的读写 [J], 李书巳
2.基于SPI模式的Micro SD卡驱动设计与验证 [J], 张锋;潘冀宁;朱振荣
3.嵌入式linux下SPI总线设备驱动设计与实现 [J], 王艇艇;赵文博;孙国强
4.SPI模式下SD卡的读写 [J], 李书巳
5.SPI模式下对SD卡的读写控制 [J], 尚怡君;葛明涛
因版权原因,仅展示原文概要,查看原文内容请购买。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
******************************************************************************* * 本文件为SPI操作SD卡的底层驱动文件* 包括SPI模块及相关IO的初始化,SPI读写SD卡(写指令,读数据等)******************************************************************************* //* Includes ------------------------------------------------------------------*/#include "SPI_SD_driver.h"#define u8 unsigned char#define u16 unsigned short#define u32 unsigned long/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*//* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/u8 SD_Type=0;/* Private function prototypes -----------------------------------------------*//* Private functions ---------------------------------------------------------*/////////////////////////////////////////////////////////////////////////////////// 以下是SPI模块的初始化代码,配置成主机模式,访问SD卡/////////////////////////////////////////////////////////////////////////////////****************************************************************************** ** Function Name : SPI_Configuration* Description : SPI模块初始化,【包括相关IO口的初始化】* Input : None* Output : None* Return : None******************************************************************************* /void SPI_Configuration(void){SysCtlPeriEnable(SYSCTL_PERIPH_GPIOA);SysCtlPeriEnable(SYSCTL_PERIPH_GPIOC);GPIOPinTypeOut(GPIO_PORTA_BASE, 0x15);GPIOPinTypeIn(GPIO_PORTC_BASE, 0x20);}/****************************************************************************** ** Function Name : SPI_ReadWriteByte* Description : SPI读写一个字节(发送完成后返回本次通讯读取的数据)* Input : u8 TxData 待发送的数* Output : None* Return : u8 RxData 收到的数******************************************************************************* /u8 SPI_ReadByte(){u8 i,data=0;for (i=8;i>0;i--){spi_clk_0;spi_clk_1;data<<=1;if (spi_do) data|=1;}return data;}void SPI_WriteByte(u8 data){u8 i;for (i=8;i>0;i--){spi_clk_0;if (data&0x80) spi_di_1;else spi_di_0;data<<=1;spi_clk_1;}spi_di_1;}/****************************************************************************** ** Function Name : SD_WaitReady* Description : 等待SD卡Ready* Input : None* Output : None* Return : u8* 0:成功* other:失败******************************************************************************* /u8 SD_WaitReady(void){u8 r1;u16 retry;retry = 0;do{r1 = SPI_ReadByte();if(retry==0xfffe){return 1;}}while(r1!=0xFF);return 0;}/****************************************************************************** ** Function Name : SD_SendCommand* Description : 向SD卡发送一个命令* Input : u8 cmd 命令* u32 arg 命令参数* u8 crc crc校验值* Output : None* Return : u8 r1 SD卡返回的响应******************************************************************************* /u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc){unsigned char r1;unsigned char Retry = 0;//????????SPI_WriteByte(0xff);//片选端置低,选中SD卡spi_cs_0;//发送SPI_WriteByte(cmd | 0x40); //分别写入命令SPI_WriteByte(arg >> 24);SPI_WriteByte(arg >> 16);SPI_WriteByte(arg >> 8);SPI_WriteByte(arg);SPI_WriteByte(crc);//等待响应,或超时退出while((r1 = SPI_ReadByte())==0xFF){Retry++;if(Retry > 200){break;}}//关闭片选spi_cs_1;//在总线上额外增加8个时钟,让SD卡完成剩下的工作SPI_WriteByte(0xFF);//返回状态值return r1;}/****************************************************************************** ** Function Name : SD_SendCommand_NoDeassert* Description : 向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)* Input : u8 cmd 命令* u32 arg 命令参数* u8 crc crc校验值* Output : None* Return : u8 r1 SD卡返回的响应******************************************************************************* /u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc){unsigned char r1;unsigned char Retry = 0;//????????SPI_WriteByte(0xff);//片选端置低,选中SD卡spi_cs_0;//发送SPI_WriteByte(cmd | 0x40); //分别写入命令SPI_WriteByte(arg >> 24);SPI_WriteByte(arg >> 16);SPI_WriteByte(arg >> 8);SPI_WriteByte(arg);SPI_WriteByte(crc);//等待响应,或超时退出while((r1 = SPI_ReadByte())==0xFF){Retry++;if(Retry > 200){break;}}//返回响应值return r1;}/****************************************************************************** ** Function Name : SD_Init* Description : 初始化SD卡* Input : None* Output : None* Return : u8* 0:NO_ERR* 1:TIME_OUT* 99:NO_CARD******************************************************************************* /u8 SD_Init(void){u16 i; // 用来循环计数u8 r1; // 存放SD卡的返回值u16 retry; // 用来进行超时计数u8 buff[6];//如果没有检测到卡插入,直接退出,返回错误标志if(!SD_DET()){//return 99;return STA_NODISK; // FatFS错误标志:没有插入磁盘}//SD卡上电SD_PWR_ON();// 纯延时,等待SD卡上电完成for(i=0;i<0xf00;)i++;//先产生>74个脉冲,让SD卡自己初始化完成for(i=0;i<10;i++){SPI_WriteByte(0xFF);}//-----------------SD卡复位到idle开始-----------------//循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态//超时则直接退出retry = 0;do{//发送CMD0,让SD卡进入IDLE状态r1 = SD_SendCommand(CMD0, 0, 0x95);retry++;}while((r1 != 0x01) && (retry<200));//跳出循环后,检查原因:初始化成功?or 重试超时?if(retry==200){return r1; //超时返回1}//-----------------SD卡复位到idle结束-----------------//获取卡片的SD版本信息r1 = SD_SendCommand_NoDeassert(8, 0x1aa, 0x87);//如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化if(r1 == 0x05){//设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMCSD_Type = SD_TYPE_V1;//如果是V1.0卡,CMD8指令后没有后续数据//片选置高,结束本次命令spi_cs_1;//多发8个CLK,让SD结束后续操作SPI_WriteByte(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,否则重试200次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(1, 0, 0);retry++;}while((r1!=0x00)&& (retry<400));if(retry==400){return r1; //MMC卡初始化超时}//写入卡类型SD_Type = SD_TYPE_MMC;}//----------MMC卡额外初始化操作结束------------//设置SPI为高速模式//SPI_SetSpeed(1);SPI_WriteByte(0xFF);//禁止CRC校验/*r1 = SD_SendCommand(CMD59, 0, 0x01);if(r1 != 0x00){return r1; //命令错误,返回r1}//设置Sector Sizer1 = SD_SendCommand(CMD16, 512, 0xff);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_ReadByte(); //should be 0x00buff[1] = SPI_ReadByte(); //should be 0x00buff[2] = SPI_ReadByte(); //should be 0x01buff[3] = SPI_ReadByte(); //should be 0xAAspi_cs_1;//the next 8 clocksSPI_WriteByte(0xFF);//判断该卡是否支持2.7V-3.6V的电压范围if(buff[2]==0x01 && buff[3]==0xAA){//支持电压范围,可以操作retry = 0;//发卡初始化指令CMD55+ACMD41do{r1 = SD_SendCommand(CMD55, 0, 0);if(r1!=0x01){return r1;}r1 = SD_SendCommand(ACMD41, 0x40000000, 0);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_ReadByte();buff[1] = SPI_ReadByte();buff[2] = SPI_ReadByte();buff[3] = SPI_ReadByte();//OCR接收完成,片选置高spi_cs_1;SPI_WriteByte(0xFF);//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC //如果CCS=1:SDHC CCS=0:SD2.0if(buff[0]&0x40) //检查CCS{SD_Type = SD_TYPE_V2HC;}else{SD_Type = SD_TYPE_V2;}//-----------鉴别SD2.0卡版本结束-----------//设置SPI为高速模式//SPI_SetSpeed(1);}}return r1;}。