1:FATFS移植
1.1:FATFS配置参数
1.3 _USE_STRFUNC
用于使能或禁用字符串函数:f_gets、f_putc、f_puts和f_printf
1.5 _USE_MKFS
使能或禁用f_mkfs函数 (格式化函数)
2.1 _CODE_PAGE
设置语言类型
2.2 _USE_LFN
使能或禁用长文件名(LFN)。当使能长文件名后,需要向工程添加包含Unicode支持函数的option/unicode.c文件。工作缓冲区增加(_MAX_LFN + 1) * 2个字节,如果使能exFAT,额外多需要608字节缓存。如果工作缓存使用栈内存,需当心栈溢出;如果工作缓冲使用堆内存,需要向工程添加内存管理函数ff_memalloc和ff_memfree。
2.3 _MAX_LFN
定义长文件名工作缓冲区大小,可以为12~255字节。当禁用长文件名时,此选项无效。
2.4 _LFN_UNICODE
使能或禁用Unicode。如果要使用Unicode(UTF16)字符串路径名,需要使能LFN和设置本选项为1。此选项还影响字符串I/O功能函数。如果禁用长文件名,此选项必须为0。
2.5 _STRF_ENCODE
通过设置_LFN_UNICODE为1使能Unicode API函数时,这个选项定义通过字符串I/O函数读写的文件字符编码。字符串I/O函数有f_gets、f_putc、f_puts和f_printf。当_LFN_UNICODE等于0时,此选项不起作用。
3.1 _VOLUMES
配置可用卷的数目,可设置为1~10。
4.5 _FS_LOCK
使能或禁用文件锁功能。控制重复打开文件和非法打开文件对象。注意:文件锁功能不具有可重入性。只读模式下,这个宏必须为0。
2.2:SDIO的SD卡移植
#include “MicroSD.c”
SD_HandleTypeDef SDCARD_Handler; //SD卡句柄
HAL_SD_CardInfoTypeDef SDCardInfo; //SD卡信息结构体
uint8_t SD_Init(void)
{
uint8_t SD_Error;
//初始化时的时钟不能大于400KHZ
SDCARD_Handler.Instance=SDIO;
SDCARD_Handler.Init.ClockEdge=SDIO_CLOCK_EDGE_RISING; //上升沿
SDCARD_Handler.Init.ClockBypass=SDIO_CLOCK_BYPASS_DISABLE; //不使用bypass模式,直接用HCLK进行分频得到SDIO_CK
SDCARD_Handler.Init.ClockPowerSave=SDIO_CLOCK_POWER_SAVE_DISABLE; //空闲时不关闭时钟电源
SDCARD_Handler.Init.BusWide=SDIO_BUS_WIDE_1B; //1位数据线
SDCARD_Handler.Init.HardwareFlowControl=SDIO_HARDWARE_FLOW_CONTROL_ENABLE;//开启硬件流控
SDCARD_Handler.Init.ClockDiv=10; //SD传输时钟频率最大25MHZ
SD_Error=HAL_SD_Init(&SDCARD_Handler);
if(SD_Error!=HAL_OK) return 1;
SD_Error=HAL_SD_ConfigWideBusOperation(&SDCARD_Handler,SDIO_BUS_WIDE_4B);//使能宽总线模式
if(SD_Error!=HAL_OK) return 2;
return 0;
}
//得到卡信息
//cardinfo:卡信息存储区
//返回值:错误状态
u8 SD_GetCardInfo(HAL_SD_CardInfoTypeDef *cardinfo)
{
u8 sta;
sta=HAL_SD_GetCardInfo(&SDCARD_Handler,cardinfo);
return sta;
}
//通过串口打印SD卡相关信息
void show_sdcard_info(void)
{
uint64_t CardCap; //SD卡容量
HAL_SD_CardCIDTypeDef SDCard_CID;
HAL_SD_GetCardCID(&SDCARD_Handler,&SDCard_CID); //获取CID
SD_GetCardInfo(&SDCardInfo); //获取SD卡信息
switch(SDCardInfo.CardType)
{
case CARD_SDSC:
{
if(SDCardInfo.CardVersion == CARD_V1_X)
printf("Card Type:SDSC V1\r\n");
else if(SDCardInfo.CardVersion == CARD_V2_X)
printf("Card Type:SDSC V2\r\n");
}
break;
case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
}
CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //计算SD卡容量
printf("Card ManufacturerID:%d\r\n",SDCard_CID.ManufacturerID); //制造商ID
printf("Card RCA:%d\r\n",SDCardInfo.RelCardAdd); //卡相对地址
printf("LogBlockNbr:%d \r\n",(u32)(SDCardInfo.LogBlockNbr)); //显示逻辑块数量
printf("LogBlockSize:%d \r\n",(u32)(SDCardInfo.LogBlockSize)); //显示逻辑块大小
printf("Card Capacity:%d MB\r\n",(u32)(CardCap>>20)); //显示容量
printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.BlockSize); //显示块大小
}
void MicrsSD_Test(void)
{
FRESULT res;
uint32_t Bw, Br;
uint8_t wtext[] = "Hello Test USB TestTime:2023/07/08 15:42:37";
uint8_t rtext[50];
char FileName[]="Micro.csv";
/* 1:挂载系统 */
res = f_mount(&SDFatFS, (TCHAR const*)SDPath, 1);
if(res != FR_OK)
printf("挂载系统失败 原因: %d", res);
else
printf("挂载系统成功");
printf("在: %s 盘上挂载\r\n", SDPath);
/* 2:创建文件 */
res = f_open(&SDFile, FileName, FA_CREATE_ALWAYS | FA_WRITE);
if(res != FR_OK)
printf("创建%s文件失败: %d\r\n", FileName,res);
else
printf("创建%s文件成功\r\n",FileName);
/* 3:写入内容 */
res = f_write(&SDFile, wtext, sizeof(wtext), (void *)&Bw);
if((Bw == 0) || (res != FR_OK))
printf("向%s写入 内容%s 失败 原因: %d\r\n",FileName,wtext,res);
else
printf("向%s写入 内容%s 成功\r\n",FileName,wtext);
f_close(&SDFile);
/* 4:打开文件 */
res = f_open(&SDFile, FileName, FA_READ);
if(res != FR_OK)
printf("打开%s文件失败 原因: %d\r\n", FileName,res);
else
printf("打开%s文件成功\r\n",FileName);
/* 5:读取文件 */
res = f_read(&SDFile, rtext, sizeof(rtext), (void *)&Br);
if((Br == 0) || (res != FR_OK))
printf("读取%s文件失败 原因: %d\r\n", FileName,res);
else
printf("读取%s文件成功\r\n",FileName);
f_close(&SDFile);
if((Br != Bw))
printf("文件读写不一致\r\n");
else
printf("文件读写一致\r\n");
printf("已将%s文件创建到磁盘%s\r\n",FileName,SDPath);
}
2.3:U盘移植
2.3:SPI的SD卡读写
0:注意SPI1的速度是SPI2的两倍 本
1:帧格式
2:设置SPI的数据大小:SPI发送接收8位帧结构
3:指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
4:定义波特率预分频的值:波特率预分频值为256
5:串行同步时钟的空闲状态为高电平
6:串行同步时钟的第二个跳变沿(上升或下降)数据被采样
7:关闭硬件CRC校验
8:NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
diskio.c
#include "diskio.h"
#include "ff_gen_drv.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern Disk_drvTypeDef disk;
#include "mmc_sd.h"
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Gets Disk Status
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
//获得磁盘状态
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/**
* @brief Initializes a Drive
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
//初始化磁盘
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
uint8_t res;
// if(pdrv<=4)//只能初始化SD卡
// {
res=SD_Init(); //SD卡初始化
// }
if(res)
return STA_NOINIT;
else
return 0; //初始化成功
}
/**
* @brief Reads Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
//读扇区
//pdrv:磁盘编号0~9
//*buff:数据接收缓冲首地址
//sector:扇区地址
//count:需要读取的扇区数
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
u8 res=0;
if (!count)
return RES_PARERR;//count不能等于0,否则返回参数错误
// if(pdrv<=4)//只能是SD卡
// {
res=SD_ReadDisk(buff,sector,count);
// }
while(res)//读出错
{
SD_Init(); //重新初始化SD卡
res=SD_ReadDisk(buff,sector,count);
}
if(res==0x00)
return RES_OK;
else
return RES_ERROR;
}
/**
* @brief Writes Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data to be written
* @param sector: Sector address (LBA)
* @param count: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
#if _USE_WRITE == 1
//写扇区
//pdrv:磁盘编号0~9
//*buff:发送数据首地址
//sector:扇区地址
//count:需要写入的扇区数
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
u8 res=0;
if (!count)
return RES_PARERR;//count不能等于0,否则返回参数错误
// if(pdrv<=4)//只能是SD卡
// {
res=SD_WriteDisk((u8*)buff,sector,count);
while(res)//写出错
{
SD_Init(); //重新初始化SD卡
res=SD_WriteDisk((u8*)buff,sector,count);
}
// }
if(res == 0x00)
return RES_OK;
else
return RES_ERROR;
}
#endif /* _USE_WRITE == 1 */
/**
* @brief I/O control operation
* @param pdrv: Physical drive number (0..)
* @param cmd: Control code
* @param *buff: Buffer to send/receive control data
* @retval DRESULT: Operation result
*/
#if _USE_IOCTL == 1
//其他表参数的获得
//pdrv:磁盘编号0~9
//ctrl:控制代码
//*buff:发送/接收缓冲区指针
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
// if(pdrv<=4)//只能是SD卡
// {
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(DWORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = 8;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = SD_GetSectorCount();
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
// }
}
return res;
}
#endif /* _USE_IOCTL == 1 */
/**
* @brief Gets Time from RTC
* @param None
* @retval Time in DWORD
*/
__weak DWORD get_fattime (void)
{
return ((2052UL-1980) << 25) /* Year = 2010 */
| (11UL << 21) /* Month = 11 */
| (2UL << 16) /* Day = 2 */
| (15U << 11) /* Hour = 15 */
| (0U << 5) /* Min = 0 */
| (0U >> 1) /* Sec = 0 */
;
}
spi.c
#define SDSPI hspi1
//SPI速度设置函数
//SPI速度=fAPB1/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BAUDRATEPRESCALER_2~SPI_BAUDRATEPRESCALER_2 256
//fAPB1时钟一般为42Mhz:
void SD_SPI_SetSpeed(uint8_t SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
__HAL_SPI_DISABLE(&SDSPI); //关闭SPI
SDSPI.Instance->CR1&=0XFFC7; //位3-5清零,用来设置波特率
SDSPI.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
__HAL_SPI_ENABLE(&SDSPI); //使能SPI
}
//SPI1 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI_SD_ReadWriteByte(uint8_t TxData)
{
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&SDSPI,&TxData,&Rxdata,1, 1000);
return Rxdata; //返回收到的数据
}
mmc_sd.c
u8 SD_Type=0;//SD卡的类型
//移植时候的接口
//data:要写入的数据
//返回值:读到的数据
u8 SD_SPI_ReadWriteByte(u8 data)
{
return SPI_SD_ReadWriteByte(data);
}
//SD卡初始化的时候,需要低速
void SD_SPI_SpeedLow(void)
{
SD_SPI_SetSpeed(SPI_BAUDRATEPRESCALER_256);//设置到低速模式
}
//SD卡正常工作的时候,可以高速了
void SD_SPI_SpeedHigh(void)
{
SD_SPI_SetSpeed(SPI_BAUDRATEPRESCALER_4);//设置到高速模式
}
//SPI硬件层初始化
void SD_SPI_Init(void)
{
MX_SPI1_Init();
LL_GPIO_SetOutputPin(SD_CS_GPIO_Port, SD_CS_Pin);
}
///
//取消选择,释放SPI总线
void SD_DisSelect(void)
{
LL_GPIO_SetOutputPin(SD_CS_GPIO_Port, SD_CS_Pin);
SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}
//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
u8 SD_Select(void)
{
LL_GPIO_ResetOutputPin(SD_CS_GPIO_Port, SD_CS_Pin);
if(SD_WaitReady()==0)return 0;//等待成功
SD_DisSelect();
return 1;//等待失败
}
//等待卡准备好
//返回值:0,准备好了;其他,错误代码
u8 SD_WaitReady(void)
{
u32 t=0;
do
{
if(SD_SPI_ReadWriteByte(0XFF)==0XFF)
return 0;//OK
t++;
}while(t<0XFFFF);//等待
RunStada |= errSDFountt; //报告SD卡挂载系统失败
return 1;
}
//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
// 其他,得到回应值失败
u8 SD_GetResponse(u8 Response)
{
u16 Count=0xFFFF;//等待次数
while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应
if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
else return MSD_RESPONSE_NO_ERROR;//正确回应
}
//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
u8 SD_RecvData(u8*buf,u16 len)
{
if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
while(len--)//开始接收数据
{
*buf=SPI_SD_ReadWriteByte(0xFF);
buf++;
}
//下面是2个伪CRC(dummy CRC)
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
return 0;//读取成功
}
//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;
u8 SD_SendBlock(u8*buf,u8 cmd)
{
u16 t;
if(SD_WaitReady())return 1;//等待准备失效
SD_SPI_ReadWriteByte(cmd);
if(cmd!=0XFD)//不是结束指令
{
for(t=0;t<512;t++)SPI_SD_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间
SD_SPI_ReadWriteByte(0xFF);//忽略crc
SD_SPI_ReadWriteByte(0xFF);
t=SD_SPI_ReadWriteByte(0xFF);//接收响应
if((t&0x1F)!=0x05)return 2;//响应错误
}
return 0;//写入成功
}
//向SD卡发送一个命令
//输入: u8 cmd 命令
// u32 arg 命令参数
// u8 crc crc校验值
//返回值:SD卡返回的响应
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{
u8 r1;
u8 Retry=0;
SD_DisSelect();//取消上次片选
if(SD_Select())return 0XFF;//片选失效
//发送
SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
SD_SPI_ReadWriteByte(arg >> 24);
SD_SPI_ReadWriteByte(arg >> 16);
SD_SPI_ReadWriteByte(arg >> 8);
SD_SPI_ReadWriteByte(arg);
SD_SPI_ReadWriteByte(crc);
if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
//等待响应,或超时退出
Retry=0X1F;
do
{
r1=SD_SPI_ReadWriteByte(0xFF);
}while((r1&0X80) && Retry--);
//返回状态值
return r1;
}
//获取SD卡的CID信息,包括制造商信息
//输入: u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
// 1:错误
u8 SD_GetCID(u8 *cid_data)
{
u8 r1;
//发CMD10命令,读CID
r1=SD_SendCmd(CMD10,0,0x01);
if(r1==0x00)
{
r1=SD_RecvData(cid_data,16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
// 1:错误
u8 SD_GetCSD(u8 *csd_data)
{
u8 r1;
r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
if(r1==0)
{
r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
//获取SD卡的总扇区数(扇区数)
//返回值:0: 取容量出错
// 其他:SD卡的容量(扇区数/512字节)
//每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
u32 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;
}
//初始化SD卡
u8 SD_Init(void)
{
u8 r1; // 存放SD卡的返回值
u16 retry; // 用来进行超时计数
u8 buf[4];
u16 i;
SD_SPI_Init(); //初始化IO
SD_SPI_SpeedLow(); //设置到低速模式
for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
retry=20;
do
{
r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
}while((r1!=0X01) && retry--);
SD_Type=0;//默认无卡
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF); //Get trailing return value of R7 resp
if(buf[2]==0X01&&buf[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++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //检查CCS
else SD_Type=SD_TYPE_V2;
}
}
}else//SD V1.x/ MMC V3
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41
if(r1<=1)
{
SD_Type=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=SD_TYPE_MMC;//MMC V3
retry=0XFFFE;
do //等待退出IDLE模式
{
r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
}
}
SD_DisSelect();//取消片选
SD_SPI_SpeedHigh();//高速
if(SD_Type)return 0;
else if(r1)return r1;
return 0xaa;//其他错误
}
//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD17,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_RecvData(buf,512);//接收512个字节
}
}else
{
r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
do
{
r1=SD_RecvData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SD_SendCmd(CMD12,0,0X01); //发送停止命令
}
SD_DisSelect();//取消片选
return r1;//
}
//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(SD_Type!=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!=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_DisSelect();//取消片选
return r1;//
}
// SD卡类型定义
#define SD_TYPE_ERR 0X00
#define SD_TYPE_MMC 0X01
#define SD_TYPE_V1 0X02
#define SD_TYPE_V2 0X04
#define SD_TYPE_V2HC 0X06
// SD卡指令表
#define CMD0 0 //卡复位
#define CMD1 1
#define CMD8 8 //命令8 ,SEND_IF_COND
#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 CMD23 23 //命令23,设置多sector写入前预先擦除N个block
#define CMD24 24 //命令24,写sector
#define CMD25 25 //命令25,写Multi sector
#define CMD41 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_STATE 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
extern u16 LastMinutes;
extern u16 LastMinutes_W;
extern u8 LastHour;
extern u8 LastDay;
//函数申明区
u8 SD_SPI_ReadWriteByte(u8 data);
void SD_SPI_SpeedLow(void);
void SD_SPI_SpeedHigh(void);
u8 SD_WaitReady(void); //等待SD卡准备
u8 SD_GetResponse(u8 Response); //获得相应
u8 SD_Init(void); //初始化
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt); //读块
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt); //写块
u32 SD_GetSectorCount(void); //读扇区数
u8 SD_GetCID(u8 *cid_data); //读SD卡CID
u8 SD_GetCSD(u8 *csd_data); //读SD卡CSD
mmc_sd.c