Files
XerolySkinner d14d2c5c95 换血大更新
2023-03-06 12:44:58 +08:00

457 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*----------------------------------------------------------------------------------------------------
#
# Copyright (c) 2022 Yuankang Liang(XerolySkinner)
#
# 本软件按原样提供,无任何明示或暗示
# 在任何情况下,作者都不承担任何损害赔偿责任
#
# 使用的许可声明:
# 1. 不得歪曲本软件的来源,你不能声称你编写了原始软件.
# 2. 免费授予以任何目的,前提是版权声明出现在所有副本中.
# 并且版权声明和许可声明同时出现.
# 3. 你有使用,复制,修改,分发,和销售本软件的许可.
# 4. 如果你在产品中使用,产品文档中的声明是赞赏的但不是必须的.
# 5. 本通知不得从任何来源删除或更改.
#
# Yuankang Liang(XerolySkinner)
# E-mail:zabbcccbbaz@163.com
# QQ:2715099320
# Mobile Phone:13005636215
#
# All rights reserved.
*/
/**
* @file bsp_SD.cpp
* @brief 操作SD卡的库
* @mainpage 主要信息
* @author Yuankang Liang(XerolySkinner)
* @email zabbcccbbaz@163.com
* @version V1.0.0
* @date 2022-11-22 03:50
*/
#include "bsp_SD.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------
// 程序
//
/**
* @brief 片选信号
* @return 无
*/
void bsp_SD::SD_CS(u8 p){
HAL_GPIO_WritePin(GPIOx_CS, GPIO_Pin_CS, p == 0 ? GPIO_PIN_SET: GPIO_PIN_RESET);}
//----------------------------------------------------------------------------------------------------
/**
* @brief 写SD卡
* @param cmd 命令
* @param arg
* @param crc 校验码
* @return
*/
u32 bsp_SD::SD_sendcmd(u8 cmd, u32 arg, u8 crc){
u8 r1;
u8 retry;
SD_CS(0);
__nop();
SD_CS(1);
do retry = 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);
do r1 = spi_readwrite(0xFF);while(r1 & 0X80);
return r1;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 初始化SD卡
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::SD_init(void){
u8 r1;
u8 buff[6] = {0};
u16 retry;
u8 i;
// MX_SPI3_Init();
SPI_setspeed(SPI_BAUDRATEPRESCALER_256);
SD_CS(0);
for (retry = 0; retry < 10; retry++) spi_readwrite(DFF);
// SD卡进入IDLE状态
do r1 = 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); //Get trailing return value of R7 resp
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;
else SD_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; //MMC V3
retry = 0XFFFE;
do r1 = 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) return 0;
else return 1;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 读取SD卡指定长度信息
* @param *data 数据缓存区
* @param len 长度
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::SD_ReceiveData(u8 * data, u16 len){
u8 r1;
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);
return 0;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 向SD卡写入一个扇区
* @param *buf 数据缓存区
* @param cmd 操作指令
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::SD_SendBlock(u8 * buf, u8 cmd){
u16 t;
u8 r1;
do r1 = 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) return 2;} //响应错误
return 0;} //写入成功
//----------------------------------------------------------------------------------------------------
/**
* @brief 获取CID信息
* @return CID信息
*/
u8 bsp_SD::SD_GETCID(u8 * cid_data){
u8 r1;
r1 = SD_sendcmd(CMD10, 0, 0x01); //读取CID寄存器
if (r1 == 0x00) r1 = SD_ReceiveData(cid_data, 16);
SD_CS(0);
if (r1) return 1;
else return 0;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 获取CSD信息
* @return CSD信息
*/
u8 bsp_SD::SD_GETCSD(u8 * csd_data){
u8 r1;
r1 = SD_sendcmd(CMD9, 0, 0x01); //发CMD9命令读CSD寄存器
if (r1 == 0) r1 = SD_ReceiveData(csd_data, 16); //接收16个字节的数据
SD_CS(0); //取消片选
if (r1) return 1;
else return 0;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 获取SD卡的总扇区数
* @return 总扇区数
*/
u32 bsp_SD::SD_GetSectorCount(void){
u8 csd[16];
u32 Capacity;
u8 n;
u16 csize;
//取CSD信息如果期间出错返回0
if (SD_GETCSD(csd) != 0) return 0;
//如果为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);} //得到扇区数
return Capacity;}
//----------------------------------------------------------------------------------------------------
int bsp_SD::MSD0_GetCardInfo(PMSD_CARDINFO SD0_CardInfo){
u8 r1;
u8 CSD_Tab[16];
u8 CID_Tab[16];
/* Send CMD9, Read CSD */
r1 = SD_sendcmd(CMD9, 0, 0xFF);
if (r1 != 0x00) return r1;
if (SD_ReceiveData(CSD_Tab, 16)) return 1;
/* Send CMD10, Read CID */
r1 = SD_sendcmd(CMD10, 0, 0xFF);
if (r1 != 0x00) return r1;
if (SD_ReceiveData(CID_Tab, 16)) return 2;
/* Byte 0 */
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;
/* Byte 1 */
SD0_CardInfo->CSD.TAAC = CSD_Tab[1];
/* Byte 2 */
SD0_CardInfo->CSD.NSAC = CSD_Tab[2];
/* Byte 3 */
SD0_CardInfo->CSD.MaxBusClkFrec = CSD_Tab[3];
/* Byte 4 */
SD0_CardInfo->CSD.CardComdClasses = CSD_Tab[4] << 4;
/* Byte 5 */
SD0_CardInfo->CSD.CardComdClasses |= (CSD_Tab[5] &0xF0) >> 4;
SD0_CardInfo->CSD.RdBlockLen = CSD_Tab[5] &0x0F;
/* Byte 6 */
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;
/* Byte 7 */
SD0_CardInfo->CSD.DeviceSize |= (CSD_Tab[7]) << 2;
/* Byte 8 */
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);
/* Byte 9 */
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;
/* Byte 10 */
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;
/* Byte 11 */
SD0_CardInfo->CSD.EraseGrMul |= (CSD_Tab[11] &0xE0) >> 5;
SD0_CardInfo->CSD.WrProtectGrSize = (CSD_Tab[11] &0x1F);
/* Byte 12 */
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;
/* Byte 13 */
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);
/* Byte 14 */
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);
/* Byte 15 */
SD0_CardInfo->CSD.CSD_CRC = (CSD_Tab[15] &0xFE) >> 1;
SD0_CardInfo->CSD.Reserved4 = 1;
if (SD0_CardInfo->CardType == V2HC) {
/* Byte 7 */
SD0_CardInfo->CSD.DeviceSize = (u16) (CSD_Tab[8]) * 256;
/* Byte 8 */
SD0_CardInfo->CSD.DeviceSize += CSD_Tab[9];}
SD0_CardInfo->Capacity = SD0_CardInfo->CSD.DeviceSize * MSD_BLOCKSIZE * 1024;
SD0_CardInfo->BlockSize = MSD_BLOCKSIZE;
/* Byte 0 */
SD0_CardInfo->CID.ManufacturerID = CID_Tab[0];
/* Byte 1 */
SD0_CardInfo->CID.OEM_AppliID = CID_Tab[1] << 8;
/* Byte 2 */
SD0_CardInfo->CID.OEM_AppliID |= CID_Tab[2];
/* Byte 3 */
SD0_CardInfo->CID.ProdName1 = CID_Tab[3] << 24;
/* Byte 4 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[4] << 16;
/* Byte 5 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[5] << 8;
/* Byte 6 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[6];
/* Byte 7 */
SD0_CardInfo->CID.ProdName2 = CID_Tab[7];
/* Byte 8 */
SD0_CardInfo->CID.ProdRev = CID_Tab[8];
/* Byte 9 */
SD0_CardInfo->CID.ProdSN = CID_Tab[9] << 24;
/* Byte 10 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[10] << 16;
/* Byte 11 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[11] << 8;
/* Byte 12 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[12];
/* Byte 13 */
SD0_CardInfo->CID.Reserved1 |= (CID_Tab[13] &0xF0) >> 4;
/* Byte 14 */
SD0_CardInfo->CID.ManufactDate = (CID_Tab[13] &0x0F) << 8;
/* Byte 15 */
SD0_CardInfo->CID.ManufactDate |= CID_Tab[14];
/* Byte 16 */
SD0_CardInfo->CID.CID_CRC = (CID_Tab[15] &0xFE) >> 1;
SD0_CardInfo->CID.Reserved2 = 1;
return 0;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 写SD卡
* @param *buf 数据缓存区
* @param sector 起始扇区
* @param cnt 扇区数
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::SD_WriteDisk(u8 * buf, u32 sector, u8 cnt){
u8 r1;
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); //取消片选
return r1;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 读SD卡
* @param *buf 数据缓存区
* @param sector 起始扇区
* @param cnt 扇区数
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::SD_ReadDisk(u8 * buf, u32 sector, u8 cnt){
u8 r1;
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); //取消片选
return r1;}
//----------------------------------------------------------------------------------------------------
u8 bsp_SD::spi_readwrite(u8 Txdata){
u8 Rxdata;
HAL_SPI_TransmitReceive(hspi, &Txdata, &Rxdata, 1, 0xFF);
return Rxdata;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 设置SPI的速率
* @param speed 速率
* @return 无
*/
void bsp_SD::SPI_setspeed(u8 speed){
hspi->Init.BaudRatePrescaler = speed;}
//----------------------------------------------------------------------------------------------------
/**
* @brief 写入连贯的数据
* @param offset 写入位置
* @param *dat 数据缓冲区
* @param datlen 写入长度
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::offsetWrite(u64 offset,u8* dat,u64 datlen) {
u8 sectorBuff[512] = { 0 };
u64 sectorBuffptr = 0;
u64 sectorSour = offset / 512; // 起始扇
u64 sectorSourlen = offset % 512; // 起始扇内位
// 填入数据
SD_ReadDisk(sectorBuff,sectorSour,1);
sectorBuffptr = sectorSourlen;
for (u64 i = 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);}}
return 0;
}
//----------------------------------------------------------------------------------------------------
/**
* @brief 读取连贯的数据
* @param offset 读取位置
* @param *dat 数据缓冲区
* @param datlen 读取长度
* @return 返回值:0,ok;其他,失败.
*/
u8 bsp_SD::offsetRead(u64 offset,u8* dat,u64 datlen) {
u8 sectorBuff[512] = { 0 };
u64 sectorBuffptr = 0;
u64 sectorSour = offset / 512; // 起始扇
u64 sectorSourlen = offset % 512; // 起始扇内位
// 填入数据
SD_ReadDisk(sectorBuff,sectorSour,1);
sectorBuffptr = sectorSourlen;
for (u64 i = 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);}}
return 0;}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------
// 构造函数
//
bsp_SD::bsp_SD(
SPI_HandleTypeDef *hspi,
GPIO_TypeDef *GPIOx_CS,
uint16_t GPIO_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;}
//////////////////////////////////////////////////////////////////////////////////////////////////////