bsp_SD.cpp bsp_SD.h 操作SD卡的库 /*---------------------------------------------------------------------------------------------------- # #Copyright(c)2022YuankangLiang(XerolySkinner) # #本软件按原样提供,无任何明示或暗示 #在任何情况下,作者都不承担任何损害赔偿责任 # #使用的许可声明: #1.不得歪曲本软件的来源,你不能声称你编写了原始软件. #2.免费授予以任何目的,前提是版权声明出现在所有副本中. #并且版权声明和许可声明同时出现. #3.你有使用,复制,修改,分发,和销售本软件的许可. #4.如果你在产品中使用,产品文档中的声明是赞赏的但不是必须的. #5.本通知不得从任何来源删除或更改. # #YuankangLiang(XerolySkinner) #E-mail:zabbcccbbaz@163.com #QQ:2715099320 #MobilePhone:13005636215 # #Allrightsreserved. */ #include"bsp_SD.h" //---------------------------------------------------------------------------------------------------- //程序 // voidbsp_SD::SD_CS(u8p){ HAL_GPIO_WritePin(GPIOx_CS,GPIO_Pin_CS,p==0?GPIO_PIN_SET:GPIO_PIN_RESET);} //---------------------------------------------------------------------------------------------------- u32bsp_SD::SD_sendcmd(u8cmd,u32arg,u8crc){ u8r1; u8retry; SD_CS(0); __nop(); SD_CS(1); doretry=spi_readwrite(DFF);while(retry!=0xFF); spi_readwrite(cmd|0x40); spi_readwrite(arg>>24); spi_readwrite(arg>>16); spi_readwrite(arg>>8); spi_readwrite(arg); spi_readwrite(crc); if(cmd==CMD12)spi_readwrite(DFF); dor1=spi_readwrite(0xFF);while(r1&0X80); returnr1;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_init(void){ u8r1; u8buff[6]={0}; u16retry; u8i; //MX_SPI3_Init(); SPI_setspeed(SPI_BAUDRATEPRESCALER_256); SD_CS(0); for(retry=0;retry<10;retry++)spi_readwrite(DFF); //SD卡进入IDLE状态 dor1=SD_sendcmd(CMD0,0,0x95);while(r1!=0x01); //查看SD卡的类型 SD_TYPE=0; r1=SD_sendcmd(CMD8,0x1AA,0x87); if(r1==0x01){ for(i=0;i<4;i++)buff[i]=spi_readwrite(DFF);//GettrailingreturnvalueofR7resp if(buff[2]==0X01&&buff[3]==0XAA){//卡是否支持2.7~3.6V retry=0XFFFE; do{ SD_sendcmd(CMD55,0,0X01);//发送CMD55 r1=SD_sendcmd(CMD41,0x40000000,0X01);//发送CMD41 }while(r1&&retry--); if(retry&&SD_sendcmd(CMD58,0,0X01)==0){//鉴别SD2.0卡版本开始 for(i=0;i<4;i++)buff[i]=spi_readwrite(0XFF);//得到OCR值 if(buff[0]&0x40)SD_TYPE=V2HC; elseSD_TYPE=V2;}} else{ SD_sendcmd(CMD55,0,0X01);//发送CMD55 r1=SD_sendcmd(CMD41,0,0X01);//发送CMD41 if(r1<=1){ SD_TYPE=V1; retry=0XFFFE; do{//等待退出IDLE模式 SD_sendcmd(CMD55,0,0X01);//发送CMD55 r1=SD_sendcmd(CMD41,0,0X01);//发送CMD41 }while(r1&&retry--);} else{//MMC卡不支持CMD55+CMD41识别 SD_TYPE=MMC;//MMCV3 retry=0XFFFE; dor1=SD_sendcmd(CMD1,0,0X01);while(r1&&retry--);}//等待退出IDLE模式 if(retry==0||SD_sendcmd(CMD16,512,0X01)!=0)SD_TYPE=ERR;}//错误的卡 } SD_CS(0); SPI_setspeed(SPI_BAUDRATEPRESCALER_2); if(SD_TYPE)return0; elsereturn1;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_ReceiveData(u8*data,u16len){ u8r1; SD_CS(1); do{ r1=spi_readwrite(0xFF); __nop(); }while(r1!=0xFE); while(len--){ *data=spi_readwrite(0xFF); data++;} spi_readwrite(0xFF); spi_readwrite(0xFF); return0;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_SendBlock(u8*buf,u8cmd){ u16t; u8r1; dor1=spi_readwrite(0xFF);while(r1!=0xFF); spi_readwrite(cmd); if(cmd!=0XFD){//不是结束指令 for(t=0;t<512;t++)spi_readwrite(buf[t]);//提高速度,减少函数传参时间 spi_readwrite(0xFF);//忽略crc spi_readwrite(0xFF); t=spi_readwrite(0xFF);//接收响应 if((t&0x1F)!=0x05)return2;}//响应错误 return0;}//写入成功 //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_GETCID(u8*cid_data){ u8r1; r1=SD_sendcmd(CMD10,0,0x01);//读取CID寄存器 if(r1==0x00)r1=SD_ReceiveData(cid_data,16); SD_CS(0); if(r1)return1; elsereturn0;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_GETCSD(u8*csd_data){ u8r1; r1=SD_sendcmd(CMD9,0,0x01);//发CMD9命令,读CSD寄存器 if(r1==0)r1=SD_ReceiveData(csd_data,16);//接收16个字节的数据 SD_CS(0);//取消片选 if(r1)return1; elsereturn0;} //---------------------------------------------------------------------------------------------------- u32bsp_SD::SD_GetSectorCount(void){ u8csd[16]; u32Capacity; u8n; u16csize; //取CSD信息,如果期间出错,返回0 if(SD_GETCSD(csd)!=0)return0; //如果为SDHC卡,按照下面方式计算 if((csd[0]&0xC0)==0x40){//V2.00的卡 csize=csd[9]+((u16)csd[8]<<8)+1; Capacity=(u32) csize<<10;}//得到扇区数 else{//V1.XX的卡 n=(csd[5]&15)+((csd[10]&128)>>7)+((csd[9]&3)<<1)+2; csize=(csd[8]>>6)+((u16)csd[7]<<2)+((u16)(csd[6]&3)<<10)+1; Capacity=(u32) csize<<(n-9);}//得到扇区数 returnCapacity;} //---------------------------------------------------------------------------------------------------- intbsp_SD::MSD0_GetCardInfo(PMSD_CARDINFOSD0_CardInfo){ u8r1; u8CSD_Tab[16]; u8CID_Tab[16]; /*SendCMD9,ReadCSD*/ r1=SD_sendcmd(CMD9,0,0xFF); if(r1!=0x00)returnr1; if(SD_ReceiveData(CSD_Tab,16))return1; /*SendCMD10,ReadCID*/ r1=SD_sendcmd(CMD10,0,0xFF); if(r1!=0x00)returnr1; if(SD_ReceiveData(CID_Tab,16))return2; /*Byte0*/ SD0_CardInfo->CSD.CSDStruct=(CSD_Tab[0]&0xC0)>>6; SD0_CardInfo->CSD.SysSpecVersion=(CSD_Tab[0]&0x3C)>>2; SD0_CardInfo->CSD.Reserved1=CSD_Tab[0]&0x03; /*Byte1*/ SD0_CardInfo->CSD.TAAC=CSD_Tab[1]; /*Byte2*/ SD0_CardInfo->CSD.NSAC=CSD_Tab[2]; /*Byte3*/ SD0_CardInfo->CSD.MaxBusClkFrec=CSD_Tab[3]; /*Byte4*/ SD0_CardInfo->CSD.CardComdClasses=CSD_Tab[4]<<4; /*Byte5*/ SD0_CardInfo->CSD.CardComdClasses|=(CSD_Tab[5]&0xF0)>>4; SD0_CardInfo->CSD.RdBlockLen=CSD_Tab[5]&0x0F; /*Byte6*/ SD0_CardInfo->CSD.PartBlockRead=(CSD_Tab[6]&0x80)>>7; SD0_CardInfo->CSD.WrBlockMisalign=(CSD_Tab[6]&0x40)>>6; SD0_CardInfo->CSD.RdBlockMisalign=(CSD_Tab[6]&0x20)>>5; SD0_CardInfo->CSD.DSRImpl=(CSD_Tab[6]&0x10)>>4; SD0_CardInfo->CSD.Reserved2=0;/*Reserved*/ SD0_CardInfo->CSD.DeviceSize=(CSD_Tab[6]&0x03)<<10; /*Byte7*/ SD0_CardInfo->CSD.DeviceSize|=(CSD_Tab[7])<<2; /*Byte8*/ SD0_CardInfo->CSD.DeviceSize|=(CSD_Tab[8]&0xC0)>>6; SD0_CardInfo->CSD.MaxRdCurrentVDDMin=(CSD_Tab[8]&0x38)>>3; SD0_CardInfo->CSD.MaxRdCurrentVDDMax=(CSD_Tab[8]&0x07); /*Byte9*/ SD0_CardInfo->CSD.MaxWrCurrentVDDMin=(CSD_Tab[9]&0xE0)>>5; SD0_CardInfo->CSD.MaxWrCurrentVDDMax=(CSD_Tab[9]&0x1C)>>2; SD0_CardInfo->CSD.DeviceSizeMul=(CSD_Tab[9]&0x03)<<1; /*Byte10*/ SD0_CardInfo->CSD.DeviceSizeMul|=(CSD_Tab[10]&0x80)>>7; SD0_CardInfo->CSD.EraseGrSize=(CSD_Tab[10]&0x7C)>>2; SD0_CardInfo->CSD.EraseGrMul=(CSD_Tab[10]&0x03)<<3; /*Byte11*/ SD0_CardInfo->CSD.EraseGrMul|=(CSD_Tab[11]&0xE0)>>5; SD0_CardInfo->CSD.WrProtectGrSize=(CSD_Tab[11]&0x1F); /*Byte12*/ SD0_CardInfo->CSD.WrProtectGrEnable=(CSD_Tab[12]&0x80)>>7; SD0_CardInfo->CSD.ManDeflECC=(CSD_Tab[12]&0x60)>>5; SD0_CardInfo->CSD.WrSpeedFact=(CSD_Tab[12]&0x1C)>>2; SD0_CardInfo->CSD.MaxWrBlockLen=(CSD_Tab[12]&0x03)<<2; /*Byte13*/ SD0_CardInfo->CSD.MaxWrBlockLen|=(CSD_Tab[13]&0xc0)>>6; SD0_CardInfo->CSD.WriteBlockPaPartial=(CSD_Tab[13]&0x20)>>5; SD0_CardInfo->CSD.Reserved3=0; SD0_CardInfo->CSD.ContentProtectAppli=(CSD_Tab[13]&0x01); /*Byte14*/ SD0_CardInfo->CSD.FileFormatGrouop=(CSD_Tab[14]&0x80)>>7; SD0_CardInfo->CSD.CopyFlag=(CSD_Tab[14]&0x40)>>6; SD0_CardInfo->CSD.PermWrProtect=(CSD_Tab[14]&0x20)>>5; SD0_CardInfo->CSD.TempWrProtect=(CSD_Tab[14]&0x10)>>4; SD0_CardInfo->CSD.FileFormat=(CSD_Tab[14]&0x0C)>>2; SD0_CardInfo->CSD.ECC=(CSD_Tab[14]&0x03); /*Byte15*/ SD0_CardInfo->CSD.CSD_CRC=(CSD_Tab[15]&0xFE)>>1; SD0_CardInfo->CSD.Reserved4=1; if(SD0_CardInfo->CardType==V2HC){ /*Byte7*/ SD0_CardInfo->CSD.DeviceSize=(u16)(CSD_Tab[8])*256; /*Byte8*/ SD0_CardInfo->CSD.DeviceSize+=CSD_Tab[9];} SD0_CardInfo->Capacity=SD0_CardInfo->CSD.DeviceSize*MSD_BLOCKSIZE*1024; SD0_CardInfo->BlockSize=MSD_BLOCKSIZE; /*Byte0*/ SD0_CardInfo->CID.ManufacturerID=CID_Tab[0]; /*Byte1*/ SD0_CardInfo->CID.OEM_AppliID=CID_Tab[1]<<8; /*Byte2*/ SD0_CardInfo->CID.OEM_AppliID|=CID_Tab[2]; /*Byte3*/ SD0_CardInfo->CID.ProdName1=CID_Tab[3]<<24; /*Byte4*/ SD0_CardInfo->CID.ProdName1|=CID_Tab[4]<<16; /*Byte5*/ SD0_CardInfo->CID.ProdName1|=CID_Tab[5]<<8; /*Byte6*/ SD0_CardInfo->CID.ProdName1|=CID_Tab[6]; /*Byte7*/ SD0_CardInfo->CID.ProdName2=CID_Tab[7]; /*Byte8*/ SD0_CardInfo->CID.ProdRev=CID_Tab[8]; /*Byte9*/ SD0_CardInfo->CID.ProdSN=CID_Tab[9]<<24; /*Byte10*/ SD0_CardInfo->CID.ProdSN|=CID_Tab[10]<<16; /*Byte11*/ SD0_CardInfo->CID.ProdSN|=CID_Tab[11]<<8; /*Byte12*/ SD0_CardInfo->CID.ProdSN|=CID_Tab[12]; /*Byte13*/ SD0_CardInfo->CID.Reserved1|=(CID_Tab[13]&0xF0)>>4; /*Byte14*/ SD0_CardInfo->CID.ManufactDate=(CID_Tab[13]&0x0F)<<8; /*Byte15*/ SD0_CardInfo->CID.ManufactDate|=CID_Tab[14]; /*Byte16*/ SD0_CardInfo->CID.CID_CRC=(CID_Tab[15]&0xFE)>>1; SD0_CardInfo->CID.Reserved2=1; return0;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_WriteDisk(u8*buf,u32sector,u8cnt){ u8r1; if(SD_TYPE!=V2HC)sector*=512;//转换为字节地址 if(cnt==1){ r1=SD_sendcmd(CMD24,sector,0X01);//读命令 if(r1==0)//指令发送成功 r1=SD_SendBlock(buf,0xFE);}//写512个字节 else{ if(SD_TYPE!=MMC){ SD_sendcmd(CMD55,0,0X01); SD_sendcmd(CMD23,cnt,0X01);}//发送指令 r1=SD_sendcmd(CMD25,sector,0X01);//连续读命令 if(r1==0){ do{ r1=SD_SendBlock(buf,0xFC);//接收512个字节 buf+=512;}while(--cnt&&r1==0); r1=SD_SendBlock(0,0xFD);}}//接收512个字节 SD_CS(0);//取消片选 returnr1;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::SD_ReadDisk(u8*buf,u32sector,u8cnt){ u8r1; if(SD_TYPE!=V2HC)sector<<=9;//转换为字节地址 if(cnt==1){ r1=SD_sendcmd(CMD17,sector,0X01);//读命令 if(r1==0)//指令发送成功 r1=SD_ReceiveData(buf,512);}//接收512个字节 else{ r1=SD_sendcmd(CMD18,sector,0X01);//连续读命令 do{ r1=SD_ReceiveData(buf,512);//接收512个字节 buf+=512;} while(--cnt&&r1==0); SD_sendcmd(CMD12,0,0X01);}//发送停止命令 SD_CS(0);//取消片选 returnr1;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::spi_readwrite(u8Txdata){ u8Rxdata; HAL_SPI_TransmitReceive(hspi,&Txdata,&Rxdata,1,0xFF); returnRxdata;} //---------------------------------------------------------------------------------------------------- voidbsp_SD::SPI_setspeed(u8speed){ hspi->Init.BaudRatePrescaler=speed;} //---------------------------------------------------------------------------------------------------- u8bsp_SD::offsetWrite(u64offset,u8*dat,u64datlen){ u8sectorBuff[512]={0}; u64sectorBuffptr=0; u64sectorSour=offset/512;//起始扇 u64sectorSourlen=offset%512;//起始扇内位 //填入数据 SD_ReadDisk(sectorBuff,sectorSour,1); sectorBuffptr=sectorSourlen; for(u64i=0;i<datlen;i++){ //写入数据 sectorBuff[sectorBuffptr]=dat[i]; sectorBuffptr++; //扇区回写 if(sectorBuffptr==512||i==datlen-1){ SD_WriteDisk(sectorBuff,sectorSour,1); sectorBuffptr=0; sectorSour++; if(i!=datlen-1)SD_ReadDisk(sectorBuff,sectorSour,1);}} return0; } //---------------------------------------------------------------------------------------------------- u8bsp_SD::offsetRead(u64offset,u8*dat,u64datlen){ u8sectorBuff[512]={0}; u64sectorBuffptr=0; u64sectorSour=offset/512;//起始扇 u64sectorSourlen=offset%512;//起始扇内位 //填入数据 SD_ReadDisk(sectorBuff,sectorSour,1); sectorBuffptr=sectorSourlen; for(u64i=0;i<datlen;i++){ //写入数据 dat[i]=sectorBuff[sectorBuffptr]; sectorBuffptr++; //扇区回写 if(sectorBuffptr==512||i==datlen-1){ sectorBuffptr=0; sectorSour++; if(i!=datlen-1)SD_ReadDisk(sectorBuff,sectorSour,1);}} return0;} //---------------------------------------------------------------------------------------------------- //构造函数 // bsp_SD::bsp_SD( SPI_HandleTypeDef*hspi, GPIO_TypeDef*GPIOx_CS, uint16_tGPIO_Pin_CS){ bsp_SD::hspi=hspi; bsp_SD::GPIOx_CS=GPIOx_CS; bsp_SD::GPIO_Pin_CS=GPIO_Pin_CS; bsp_SD::DFF=0xFF; bsp_SD::SD_TYPE=0x00;}