#include "asp_sdx1.h" ///#include "myfun.h" ////#include "sd_type.h" #include "bsp_sd1_iospi.h" /*★★★★★★★★★★★★★★★★★★★★★★★★ 《振南的znFAT--嵌入式FAT32文件系统设计与实现》 一书[上下册]已经由北航出版社正式出版发行。 此书是振南历经3年多时间潜心编著,是现今市面上唯 一一套讲述FAT32文件系统、SD卡等嵌入式存储技术的 专著。书中还介绍了大量的编程技巧与振南的开发经验。 请在各大网络销售平台搜索“znFAT”,即可购买。 在全国各大书店也有售。 振南的ZN-X开发板,支持51、AVR、STM32(M0/M3/M4)等 CPU。此板可与书配套,板上各种精彩的实验实例请详见 振南网站www.znmcu.cn ★★★★★★★★★★★★★★★★★★★★★★★★*/ /*************************************************************************************** ★程序模块:【振南ZN-X开发板】上『SD卡1』驱动程序 〖STC51部分:STC15L2K60S2〗 ★功能描述:实现了SD卡的扇区读写、多扇区读写、扇区擦除、读取总物理扇区数等功能 此驱动可支持几乎所有的SD卡,包括MMC/SD/SDHC ★配套教程与参考资料: ●《振南的znFAT--嵌入式FAT32文件系统设计与实验》一书 下册 第11章《SD卡物理驱动》 ●《振南的单片机高级外设系列视频教程》之《SD卡专辑》 ****************************************************************************************/ //变量定义 //-------------------------------------------------------------- extern UINT8 Low_or_High1; //在IOSPI中定义 UINT8 SD1_Addr_Mode=0; //SD1的寻址方式,1为块寻址,0为字节寻址 UINT8 SD1_Ver=SD_VER_ERR; //SD卡1的版本 //--------------------------------------------------------------- #define SD1_SPI_SPEED_HIGH() Low_or_High1=0 #define SD1_SPI_SPEED_LOW() Low_or_High1=1 #define SD1_SPI_WByte(x) SD1_IOSPI_RWByte(x) #define SD1_SPI_RByte() SD1_IOSPI_RWByte(0XFF) /******************************************************************** - 功能描述:【振南ZN-X开发板】上『SD卡1』SPI接口初始化 - 参数说明:无 - 返回说明:0 - 注:SPI接口初始化后,首先工作在低速模式。SD卡在初始化的过程中要求 SPI速度要比较低,原则上不高于400KHZ,经验值为240KHZ。如果发现 SD卡初始化不成功,还可继续降低SPI速度,实现速度起决于电路与SD 卡品质。 ********************************************************************/ UINT8 SD1_SPI_Init(void) { SD1_IOSPI_Init(); //SPI接口初始化 return 0; } /****************************************************************** - 功能描述:向SD卡写命令 - 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针 - 返回说明:命令写入不成功,将返回0xff ******************************************************************/ UINT8 SD1_Write_Cmd(UINT8 *pcmd) { UINT8 r=0,time=0; SET_SD1_CS_PIN(1); SD1_SPI_WByte(0xFF); //发送8个时钟,提高兼容性,如果没有这里,有些SD卡可能不支持 SET_SD1_CS_PIN(0); while(0XFF!=SD1_SPI_RByte()) {/// add by cc for没有SD卡应退出 ; //等待SD卡准备好,再向其发送命令 time++; L0_uart0_uc(0x30+time); if(time>=200) { L0_uart0_uc('E'); L0_uart0_0d0a(); SET_SD1_CS_PIN(1); return(INIT_CMD0_ERROR);//CMD0写入失败 } } //将6字节的命令序列写入SD卡 SD1_SPI_WByte(pcmd[0]); SD1_SPI_WByte(pcmd[1]); SD1_SPI_WByte(pcmd[2]); SD1_SPI_WByte(pcmd[3]); SD1_SPI_WByte(pcmd[4]); SD1_SPI_WByte(pcmd[5]); if(pcmd[0]==0X1C) SD1_SPI_RByte(); //如果是停止命令,跳过多余的字节 do { r=SD1_SPI_RByte(); time++; }while((r&0X80)&&(time= TRY_TIME2) { L0_uart0_uc(0x09); L0_uart0_uc('R'); L0_uart0_uc(0x09); return(INIT_CMD0_ERROR);//CMD0写入失败 } }while(r!=0x01); L0_uart0_uc(0x09); L0_uart0_uc('6'); L0_uart0_uc(0x09); if(1==SD1_Write_Cmd(pCMD8))//写入CMD8,如果返回值为1,则SD卡版本为2.0 { L0_uart0_sendstr("SDver:2.0\r\n");/////4g卡 rbuf[0]=SD1_SPI_RByte(); rbuf[1]=SD1_SPI_RByte(); //读取4个字节的R7回应,通过它可知此SD卡是否支持2.7~3.6V的工作电压 rbuf[2]=SD1_SPI_RByte(); rbuf[3]=SD1_SPI_RByte(); if(rbuf[2]==0X01 && rbuf[3]==0XAA)//SD卡是否支持2.7~3.6V { L0_uart0_sendstr("2.7~3.6V=");/////4g卡 time=0; do { SD1_Write_Cmd(pCMD55);//写入CMD55 r=SD1_Write_Cmd(pACMD41H);//写入ACMD41,针对SD2.0 time++; if(time>=TRY_TIME) { return(INIT_SDV2_ACMD41_ERROR);//对SD2.0使用ACMD41进行初始化时产生错误 } }while(r!=0); if(0==SD1_Write_Cmd(pCMD58)) //写入CMD58,开始鉴别SD2.0 { rbuf[0]=SD1_SPI_RByte(); rbuf[1]=SD1_SPI_RByte(); //读取4个字节的OCR,其中CCS指明了是SDHC还是普通的SD rbuf[2]=SD1_SPI_RByte(); rbuf[3]=SD1_SPI_RByte(); if(rbuf[0]&0x40) { SD1_Ver=SD_VER_V2HC; //SDHC卡 SD1_Addr_Mode=1; //SDHC卡的扇区寻址方式是扇区地址 } else SD1_Ver=SD_VER_V2; //普通的SD卡,2.0的卡包含SDHC和一些普通的卡 } if(!SD1_Addr_Mode) { //addr = addr * 512 将块地址(扇区地址)转为字节地址 L0_uart0_uc(0x30+SD1_Addr_Mode); L0_uart0_sendstr("<<9 \r\n");/////4g卡 } else { L0_uart0_uc(0x30+SD1_Addr_Mode); L0_uart0_sendstr("1 mass adr \r\n");/////4g卡 } } } else //SD V1.0或MMC { L0_uart0_sendstr("SD V1.0 or MMC \r\n"); //SD卡使用ACMD41进行初始化,而MMC使用CMD1来进行初始化,依此来进一步判断是SD还是MMC SD1_Write_Cmd(pCMD55);//写入CMD55 r=SD1_Write_Cmd(pACMD41S);//写入ACMD41,针对SD1.0 if(r<=1) //检查返回值是否正确,如果正确,说明ACMD41命令被接受,即为SD卡 { SD1_Ver=SD_VER_V1; //普通的SD1.0卡,一般来说容量不会超过2G time=0; do { SD1_Write_Cmd(pCMD55);//写入CMD55 r=SD1_Write_Cmd(pACMD41S);//写入ACMD41,针对SD1.0 time++; if(time>=TRY_TIME) { return(INIT_SDV1_ACMD41_ERROR);//对SD1.0使用ACMD41进行初始化时产生错误 } }while(r!=0); } else //否则为MMC { SD1_Ver=SD_VER_MMC; //MMC卡,它不支持ACMD41命令,而是使用CMD1进行初始化 time=0; do { r=SD1_Write_Cmd(pCMD1);//写入CMD1 time++; if(time>=TRY_TIME) { return(INIT_CMD1_ERROR);//MMC卡使用CMD1命令进行初始化中产生错误 } }while(r!=0); } } if(0!=SD1_Write_Cmd(pCMD16)) //SD卡的块大小必须为512字节 { SD1_Ver=SD_VER_ERR; //如果不成功,则此卡为无法识别的卡 return INIT_ERROR; } SET_SD1_CS_PIN(1); SD1_SPI_WByte(0xFF); //按照SD卡的操作时序在这里补8个时钟 SD1_SPI_SPEED_HIGH(); //SPI切到高速 return 0;//返回0,说明复位操作成功 } /****************************************************************** - 功能描述:对SD卡若干个扇区进行擦除,擦除后扇区中的数据大部分情况 下为全0(有些卡擦除后为全0XFF,如要使用此函数,请确认) - 参数说明:addr_sta:开始扇区地址 addr_end:结束扇区地址 - 返回说明:调用成功,返回0x00,否则返回错误码 add by cc 如果addr_sta=addr_end 命令无效,一次至少擦除两个扇区 CMD32 ERASE_WR_BLK_START Mandatory CMD33 ERASE_WR_BLK_END Mandatory CMD38 ERASE Mandatory Class5 (擦除卡命令集): CMD32:设置擦除块的起始地址. CMD33:设置擦除块的终止地址. CMD38: 擦除所选择的块. ******************************************************************/ UINT8 SD1_Erase_nSector(UINT32 addr_sta,UINT32 addr_end) { UINT8 r,time; UINT8 i=0; UINT8 pCMD32[]={0x60,0x00,0x00,0x00,0x00,0xff}; //设置擦除的开始扇区地址 UINT8 pCMD33[]={0x61,0x00,0x00,0x00,0x00,0xff}; //设置擦除的结束扇区地址 UINT8 pCMD38[]={0x66,0x00,0x00,0x00,0x00,0xff}; //擦除扇区 if(!SD1_Addr_Mode) { addr_sta<<=9;addr_end<<=9; //addr = addr * 512 将块地址(扇区地址)转为字节地址 } pCMD32[1]=addr_sta>>24; //将开始地址写入到CMD32字节序列中 pCMD32[2]=addr_sta>>16; pCMD32[3]=addr_sta>>8; pCMD32[4]=addr_sta; pCMD33[1]=addr_end>>24; //将开始地址写入到CMD32字节序列中 pCMD33[2]=addr_end>>16; pCMD33[3]=addr_end>>8; pCMD33[4]=addr_end; time=0; do { r=SD1_Write_Cmd(pCMD32); time++; if(time==TRY_TIME) { return(r); //命令写入失败 } }while(r!=0); time=0; do { r=SD1_Write_Cmd(pCMD33); time++; if(time==TRY_TIME) { return(r); //命令写入失败 } }while(r!=0); time=0; do { r=SD1_Write_Cmd(pCMD38); time++; if(time==TRY_TIME) { return(r); //命令写入失败 } }while(r!=0); return 0; } /**************************************************************************** - 功能描述:将buffer指向的512个字节的数据写入到SD卡的addr扇区中 - 参数说明:addr:扇区地址 buffer:指向数据缓冲区的指针 - 返回说明:调用成功,返回0x00,否则返回错误码 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率 cc modify :tf卡的读写次数是10W次,就按1万次来算,3600s 一个小时36000十个小时 ****************************************************************************/ UINT8 L1_SD_Wsector(UINT32 addr,UINT8 *buffer) //向SD卡中的指定地址的扇区写入512个字节,使用CMD24(24号命令) { UINT8 r,time; UINT16 i=0; UINT8 pCMD24[]={0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中单个块(512字节,一个扇区)写入数据,用CMD24 if(!SD1_Addr_Mode) { addr<<=9; //addr = addr * 512 将块地址(扇区地址)转为字节地址 } pCMD24[1]=addr>>24; //将字节地址写入到CMD24字节序列中 pCMD24[2]=addr>>16; pCMD24[3]=addr>>8; pCMD24[4]=addr; time=0; do { r=SD1_Write_Cmd(pCMD24); time++; if(time==TRY_TIME) { SET_SD1_CS_PIN(1); return(r); //命令写入失败 } }while(r!=0); while(0XFF!=SD1_SPI_RByte()); //等待SD卡准备好,再向其发送命令及后续的数据 SD1_SPI_WByte(0xFE);//写入开始字节 0xfe,后面就是要写入的512个字节的数据 for(i=0;i<512;i++) //将缓冲区中要写入的512个字节写入SD1卡,减少循环次数,提高数据写入速度 { SD1_SPI_WByte(*(buffer++)); /**SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++)); SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));SD1_SPI_WByte(*(buffer++));**/ } SD1_SPI_WByte(0xFF); SD1_SPI_WByte(0xFF); //两个字节的CRC校验码,不用关心 r=SD1_SPI_RByte(); //读取返回值 if((r & 0x1F)!=0x05) //如果返回值是 XXX00101 说明数据已经被SD卡接受了 { return(WRITE_BLOCK_ERROR); //写块数据失败 } while(0xFF!=SD1_SPI_RByte());//等到SD卡不忙(数据被接受以后,SD卡要将这些数据写入到自身的FLASH中,需要一个时间) //忙时,读回来的值为0x00,不忙时,为0xff SET_SD1_CS_PIN(1); SD1_SPI_WByte(0xFF); //按照SD卡的操作时序在这里补8个时钟 return(0); //返回0,说明写扇区操作成功 } UINT8 L2_SD_Rsector(UINT16 addr,UINT8 *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令) { UINT32 addr32 = D_FILE_SECTOR; addr32 += (UINT32)addr; return L1_SD_Rsector(addr32,buffer); } UINT8 L2_SD_Wsector(UINT16 addr,UINT8 *buffer) //向SD卡中的指定地址的扇区写入512个字节,使用CMD24(24号命令) { UINT32 addr32 = D_FILE_SECTOR; addr32 += (UINT32)addr; return L1_SD_Wsector(addr32,buffer); } UINT8 L2_SD_Erase_nSector(UINT16 addr_sta,UINT16 addr_end) { UINT32 addr32= D_FILE_SECTOR,addr32end= D_FILE_SECTOR; addr32 += (UINT32)addr_sta; addr32end += (UINT32)addr_end; return SD1_Erase_nSector(addr32,addr32end); } /**************************************************************************** - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区 - 参数说明:addr:扇区地址 buffer:指向数据缓冲区的指针 - 返回说明:调用成功,返回0x00,否则返回错误码 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率 ****************************************************************************/ UINT8 L1_SD_Rsector(UINT32 addr,UINT8 *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令) { UINT16 i; UINT8 time,r; UINT8 pCMD17[]={0x51,0x00,0x00,0x00,0x00,0x01}; //CMD17的字节序列 if(!SD1_Addr_Mode) { addr<<=9; //sector = sector * 512 将块地址(扇区地址)转为字节地址 } pCMD17[1]=addr>>24; //将字节地址写入到CMD17字节序列中 pCMD17[2]=addr>>16; pCMD17[3]=addr>>8; pCMD17[4]=addr; L0_uart0_uc('Q'); time=0; do { r=SD1_Write_Cmd(pCMD17); //写入CMD17 time++; ///L0_uart0_uc(0x30+time); if(time==TRY_TIME) { L0_uart0_uc('T'); SET_SD1_CS_PIN(1); return(READ_BLOCK_ERROR); //读块失败 } }while(r!=0); L0_uart0_uc('A'); time = 0; while(SD1_SPI_RByte()!= 0xFE) { //一直读,当读到0xfe时,说明后面的是512字节的数据了 time++; ///L0_uart0_uc(0x30+time); if(time==TRY_TIME) { L0_uart0_uc('F'); SET_SD1_CS_PIN(1); return(READ_BLOCK_ERROR); //读块失败 } } //L0_uart0_uc('i'); for(i=0;i<512;i++) //将数据写入到数据缓冲区中 { *(buffer++)=SD1_SPI_RByte(); /** *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); *(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte();*(buffer++)=SD1_SPI_RByte(); **/ } SD1_SPI_RByte(); SD1_SPI_RByte();//读取两个字节的CRC校验码,不用关心它们 SET_SD1_CS_PIN(1); SD1_SPI_WByte(0xFF); //按照SD1卡的操作时序在这里补8个时钟 return 0; } #if 0 /**************************************************************************** - 功能描述:向addr扇区开始的nsec个扇区写入数据(★硬件多扇区写入) - 参数说明:nsec:扇区数 addr:开始扇区地址 buffer:指向数据缓冲区的指针 - 返回说明:调用成功,返回0x00,否则返回错误码 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率 ****************************************************************************/ UINT8 SD1_Write_nSector(UINT32 nsec,UINT32 addr,UINT8 *buffer) { UINT8 r,time; UINT32 i=0,j=0,m=0; UINT8 pCMD25[6]={0x59,0x00,0x00,0x00,0x00,0x01}; //CMD25用于完成多块连续写 UINT8 pCMD55[6]={0x77,0x00,0x00,0x00,0x00,0x01}; //CMD55,用于告知SD卡后面是ACMD,CMD55+ACMD23 UINT8 pACMD23[6]={0x57,0x00,0x00,0x00,0x00,0x01};//CMD23,多块连续预擦除 if(!SD1_Addr_Mode) addr<<=9; pCMD25[1]=addr>>24; pCMD25[2]=addr>>16; pCMD25[3]=addr>>8; pCMD25[4]=addr; pACMD23[1]=nsec>>24; pACMD23[2]=nsec>>16; pACMD23[3]=nsec>>8; pACMD23[4]=nsec; if(SD1_Ver!=SD_VER_MMC) //如果不是MMC卡,则首先写入预擦除命令,CMD55+ACMD23,这样后面的连续块写的速度会更快 { SD1_Write_Cmd(pCMD55); SD1_Write_Cmd(pACMD23); } time=0; do { r=SD1_Write_Cmd(pCMD25); time++; if(time==TRY_TIME) { return(WRITE_CMD25_ERROR); //命令写入失败 } }while(r!=0); while(0XFF!=SD1_SPI_RByte()); //等待SD卡准备好,再向其发送命令及后续的数据 for(j=0;j>24; //将字节地址写入到CMD17字节序列中 pCMD18[2]=addr>>16; pCMD18[3]=addr>>8; pCMD18[4]=addr; time=0; do { r=SD1_Write_Cmd(pCMD18); //写入CMD18 time++; if(time==TRY_TIME) { return(READ_CMD18_ERROR); //写入CMD18失败 } }while(r!=0); for(j=0;j>7)+((pCSD[9]&0x03)<<1)+2; csize=(pCSD[8]>>6)+((UINT16)pCSD[7]<<2)+((UINT16)(pCSD[6]&0x03)<<0x0A)+1; Capacity=(UINT32)csize<<(n-9);//得到扇区数 } return Capacity; } #endif