设备: STM32F103VE-M3,板载SD卡读写模块。
源码: 野火的SD卡扇区读写驱动,振南FAT的STM32版本。
另有1G-16G SD卡若干张。
移植过程:
#ifndef _SDX1_H_
#define _SDX1_H_
/*★★★★★★★★★★★★★★★★★★★★★★★★
《振南的znFAT--嵌入式FAT32文件系统设计与实现》
一书[上下册]已经由北航出版社正式出版发行。
此书是振南历经3年多时间潜心编著,是现今市面上唯
一一套讲述FAT32文件系统、SD卡等嵌入式存储技术的
专著。书中还介绍了大量的编程技巧与振南的开发经验。
请在各大网络销售平台搜索“znFAT”,即可购买。
在全国各大书店也有售。
振南的ZN-X开发板,支持51、AVR、STM32(M0/M3/M4)等
CPU。此板可与书配套,板上各种精彩的实验实例请详见
振南网站www.znmcu.cn
★★★★★★★★★★★★★★★★★★★★★★★★*/
/***************************************************************************************
★程序模块:【振南ZN-X开发板】上『SD卡1』驱动程序 〖STM32部分:STM32F103RBT6〗
★功能描述:实现了SD卡的扇区读写、多扇区读写、扇区擦除、读取总物理扇区数等功能
此驱动可支持几乎所有的SD卡,包括MMC/SD/SDHC
★配套教程与参考资料:
●《振南的znFAT--嵌入式FAT32文件系统设计与实验》一书 下册 第11章《SD卡物理驱动》
●《振南的单片机高级外设系列视频教程》之《SD卡专辑》
****************************************************************************************/
#include "sd_type.h"
#define SD1_CS PBout(8)
#define SET_SD1_CS_PIN(val) (SD1_CS =val)
#define TRY_TIME 10 //向SD卡写入命令之后,读取SD卡的回应次数,即读TRY_TIME次,如果在TRY_TIME次中读不到回应,产生超时错误,命令写入失败
//相关宏定义
//-------------------------------------------------------------
#define SD_VER_ERR 0X00
#define SD_VER_MMC 0X01
#define SD_VER_V1 0X02
#define SD_VER_V2 0X03
#define SD_VER_V2HC 0X04
#define INIT_ERROR 0x01 //初始化错误
#define INIT_CMD0_ERROR 0x02 //CMD0错误
#define INIT_CMD1_ERROR 0x03 //CMD1错误
#define INIT_SDV2_ACMD41_ERROR 0x04 //ACMD41错误
#define INIT_SDV1_ACMD41_ERROR 0x05 //ACMD41错误
#define WRITE_CMD24_ERROR 0x06 //写块时产生CMD24错误
#define WRITE_BLOCK_ERROR 0x07 //写块错误
#define READ_BLOCK_ERROR 0x08 //读块错误
#define WRITE_CMD25_ERROR 0x09 //在连续多块写时产生CMD25错误
#define WRITE_NBLOCK_ERROR 0x0A //连续多块写失败
#define READ_CMD18_ERROR 0x0B //在连续多块读时产生CMD18错误
#define GET_CSD_ERROR 0x0C //读CSD失败
#define BLOCK_SIZE 512
//-------------------------------------------------------------
UINT8 SD1_Init(void); //SD卡初始化
UINT8 SD1_Write_Sector(UINT32 addr,UINT8 *buffer); //将buffer数据缓冲区中的数据写入地址为addr的扇区中
UINT8 SD1_Read_Sector(UINT32 addr,UINT8 *buffer); //从地址为addr的扇区中读取数据到buffer数据缓冲区中
UINT8 SD1_Write_nSector(UINT32 nsec,UINT32 addr,UINT8 *buffer); //将buffer数据缓冲区中的数据写入起始地址为addr的nsec个连续扇区中
UINT8 SD1_Read_nSector(UINT32 nsec,UINT32 addr,UINT8 *buffer); //将buffer数据缓冲区中的数据写入起始地址为addr的nsec个连续扇区中
UINT8 SD1_Erase_nSector(UINT32 addr_sta,UINT32 addr_end);
UINT32 SD1_GetTotalSec(void); //获取SD卡的总扇区数
#endif
sdx1.c
#include "sdx1.h"
#include "sd_type.h"
#include "sdio_sdcard.h"
/*★★★★★★★★★★★★★★★★★★★★★★★★
《振南的znFAT--嵌入式FAT32文件系统设计与实现》
一书[上下册]已经由北航出版社正式出版发行。
此书是振南历经3年多时间潜心编著,是现今市面上唯
一一套讲述FAT32文件系统、SD卡等嵌入式存储技术的
专著。书中还介绍了大量的编程技巧与振南的开发经验。
请在各大网络销售平台搜索“znFAT”,即可购买。
在全国各大书店也有售。
振南的ZN-X开发板,支持51、AVR、STM32(M0/M3/M4)等
CPU。此板可与书配套,板上各种精彩的实验实例请详见
振南网站www.znmcu.cn
★★★★★★★★★★★★★★★★★★★★★★★★*/
/***************************************************************************************
★程序模块:【振南ZN-X开发板】上『SD卡1』驱动程序 〖STM32部分:STM32F103RBT6〗
★功能描述:实现了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
卡品质。
********************************************************************/
/******************************************************************
- 功能描述:SD1卡初始化,针对于不同的SD1卡,如MMC、SD1或SD1HC,初始化
方法是不同的
- 参数说明:无
- 返回说明:调用成功,返回0x00,否则返回错误码
******************************************************************/
UINT8 SD1_Init(void)
{
UINT8 Status;
Status=SD_Init(); //SD卡的初始化函数
return Status;//返回0,说明复位操作成功
}
/******************************************************************
- 功能描述:对SD1卡若干个扇区进行擦除,擦除后扇区中的数据大部分情况
下为全0(有些卡擦除后为全0XFF,如要使用此函数,请确认)
- 参数说明:addr_sta:开始扇区地址 addr_end:结束扇区地址
- 返回说明:调用成功,返回0x00,否则返回错误码
******************************************************************/
UINT8 SD1_Erase_nSector(UINT32 addr_sta,UINT32 addr_end)
{
UINT8 Status;
Status = SD_Erase(addr_sta,addr_end);
return Status;
}
/****************************************************************************
- 功能描述:将buffer指向的512个字节的数据写入到SD1卡的addr扇区中
- 参数说明:addr:扇区地址
buffer:指向数据缓冲区的指针
- 返回说明:调用成功,返回0x00,否则返回错误码
- 注:SD1卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
****************************************************************************/
UINT8 SD1_Write_Sector(UINT32 addr,UINT8 *buffer) //向SD1卡中的指定地址的扇区写入512个字节,使用CMD24(24号命令)
{
UINT8 Status;
Status = SD_WriteBlock(buffer, addr, BLOCK_SIZE);
Status = SD_WaitWriteOperation(); //等待dma传输结束
while(SD_GetStatus() != SD_TRANSFER_OK); //等待sdio到sd卡传输结束
return(Status); //返回0,说明写扇区操作成功
}
/****************************************************************************
- 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区
- 参数说明:addr:扇区地址
buffer:指向数据缓冲区的指针
- 返回说明:调用成功,返回0x00,否则返回错误码
- 注:SD1卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
****************************************************************************/
UINT8 SD1_Read_Sector(UINT32 addr,UINT8 *buffer)//从SD1卡的指定扇区中读出512个字节,使用CMD17(17号命令)
{
UINT8 Status;
Status = SD_ReadBlock(buffer, addr, BLOCK_SIZE);//读取数据
Status = SD_WaitReadOperation();
while(SD_GetStatus() != SD_TRANSFER_OK);
return Status;
}
/****************************************************************************
- 功能描述:向addr扇区开始的nsec个扇区写入数据(★硬件多扇区写入)
- 参数说明:nsec:扇区数
addr:开始扇区地址
buffer:指向数据缓冲区的指针
- 返回说明:调用成功,返回0x00,否则返回错误码
- 注:SD1卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
****************************************************************************/
UINT8 SD1_Write_nSector(UINT32 nsec,UINT32 addr,UINT8 *buffer)
{
UINT8 Status;
Status = SD_WriteMultiBlocks(buffer, addr, BLOCK_SIZE, nsec);
Status = SD_WaitWriteOperation();
while(SD_GetStatus() != SD_TRANSFER_OK);
return(Status); //返回0,说明写扇区操作成功
}
/****************************************************************************
- 功能描述:读取addr扇区开始的nsec个扇区的数据(★硬件多扇区读取)
- 参数说明:nsec:扇区数
addr:开始扇区地址
buffer:指向数据缓冲区的指针
- 返回说明:调用成功,返回0x00,否则返回错误码
- 注:SD1卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
****************************************************************************/
UINT8 SD1_Read_nSector(UINT32 nsec,UINT32 addr,UINT8 *buffer)
{
UINT8 Status;
Status = SD_ReadMultiBlocks(buffer, addr, BLOCK_SIZE, nsec);
Status = SD_WaitReadOperation();
while(SD_GetStatus() != SD_TRANSFER_OK);
return Status;
}
/****************************************************************************
- 功能描述:获取SD1卡的总扇区数(通过读取SD1卡的CSD1寄器组计算得到总扇区数)
- 参数说明:无
- 返回说明:返回SD1卡的总扇区数
- 注:无
****************************************************************************/
UINT32 SD1_GetTotalSec(void)
{
// SD_CardInfo SDCardInfo;
SD_GetCardInfo(&SDCardInfo);
return SDCardInfo.CardCapacity;
}
#include "delay.h"
#include "sys.h"
#include "usart1.h"
#include "znfat.h"
#include "sdx1.h"
#include "sdio_sdcard.h"
/*★★★★★★★★★★★★★★★★★★★★★★★★
《振南的znFAT--嵌入式FAT32文件系统设计与实现》
一书[上下册]已经由北航出版社正式出版发行。
此书是振南历经3年多时间潜心编著,是现今市面上唯
一一套讲述FAT32文件系统、SD卡等嵌入式存储技术的
专著。书中还介绍了大量的编程技巧与振南的开发经验。
请在各大网络销售平台搜索“znFAT”,即可购买。
在全国各大书店也有售。
振南的ZN-X开发板,支持51、AVR、STM32(M0/M3/M4)等
CPU。此板可与书配套,板上各种精彩的实验实例请详见
振南网站www.znmcu.cn
★★★★★★★★★★★★★★★★★★★★★★★★*/
/********************************************************************************
注:此例程用于演示振南znFAT的功能,硬件CPU为STM32F103RBT6(其它CPU平台请变通)
*********************************************************************************/
struct znFAT_Init_Args Init_Args; //初始化参数集合
struct FileInfo fileinfo; //文件信息集合
struct DateTime dt; //日期与时间
unsigned char buf[20];
unsigned char buf2[20];
int main(void)
{
unsigned int res=0,i=0;
unsigned long len=0;
delay_init();
NVIC_Configuration();
/* USART1 config */
USART1_Config();
printf("串口设置完毕\r\n");
znFAT_Device_Init(); //存储设备初始化
printf("SD卡初始化完毕\r\n");
printf( " \r\n CardType is :%d ", SDCardInfo.CardType );
printf( " \r\n CardCapacity is :%d ", SDCardInfo.CardCapacity );
printf( " \r\n CardBlockSize is :%d ", SDCardInfo.CardBlockSize );
printf( " \r\n RCA is :%d ", SDCardInfo.RCA);
printf( " \r\n ManufacturerID is :%d \r\n", SDCardInfo.SD_cid.ManufacturerID );
znFAT_Select_Device(0,&Init_Args); //选择设备
/*
res = znFAT_Make_FS(SD1_GetTotalSec(),0);
if(res){
printf("格式化失败 , Err Code:%d\n",res);
}else{
printf("格式化成功 , Err Code:%d\n",res);
}*/
res=znFAT_Init(); //文件系统初始化
if(!res) //文件系统初始化成功
{
printf("Suc. to init FS\r\n");
printf("BPB_Sector_No: %d",Init_Args.BPB_Sector_No);
printf("Total_SizeKB: %d",Init_Args.Total_SizeKB);
printf("BytesPerSector: %d",Init_Args.BytesPerSector);
printf("FATsectors: %d",Init_Args.FATsectors);
printf("SectorsPerClust: %d",Init_Args.SectorsPerClust);
printf("FirstFATSector: %d",Init_Args.FirstFATSector);
printf("FirstDirSector: %d",Init_Args.FirstDirSector);
printf("FSsec: %d",Init_Args.FSINFO_Sec);
printf("Next_Free_Cluster: %d",Init_Args.Next_Free_Cluster);
printf("FreenCluster: %d\n",Init_Args.Free_nCluster);
}
else //文件系统初始化失败
{
printf("Fail to init FS , Err Code: %d",res);
}
//==================================================================
dt.date.year=2012; dt.date.month=12; dt.date.day=21;
dt.time.hour=15; dt.time.min=14; dt.time.sec=35;
/*
res = znFAT_Delete_File("/ZNMCU.TXT");
if(res){
printf("Fail to delete file , Err Code:%d\n",res);
}else{
printf("Suc to delete file , Err Code:%d\n",res);
}
*/
res=znFAT_Create_File(&fileinfo,"/ZNMCU.TXT",&dt); //创建文件
if(!res) //如果创建文件成功
{
printf("Suc. to creat file.\r\n");
printf("================================\n");
printf("File_Name(Short 8.3):%s\n",fileinfo.File_Name);
printf("File_Size:%d\n",fileinfo.File_Size);
printf("File_CDate:%d-%d-%d %d:%d:%d\n",fileinfo.File_CDate.year,fileinfo.File_CDate.month,fileinfo.File_CDate.day,fileinfo.File_CTime.hour,fileinfo.File_CTime.min,fileinfo.File_CTime.sec);
printf("File_StartClust:%d\n",fileinfo.File_StartClust);
printf("File_CurClust:%d\n",fileinfo.File_CurClust);
printf("File_CurSec:%d\n",fileinfo.File_CurSec);
printf("File_CurPos:%d\n",fileinfo.File_CurPos);
printf("File_CurOffset:%d\n",fileinfo.File_CurOffset);
printf("================================\n");
for(i=0;i<20;i++) buf[i]="akkjdjnknksjk897w9887309e09e"[i];
for(i=0;i<10;i++)
{
len=znFAT_WriteData(&fileinfo,20,buf); //向文件写入数据
if(len==ERR_OVER_FILE_MAX_SIZE || len==ERR_OVER_DISK_SPACE)
{
printf("Have some Err %d\n:",len);
}
else
{
printf("Write Data,times:%d\n",i);
printf("Current file offset is %d\n",fileinfo.File_CurOffset);
}
}
znFAT_Close_File(&fileinfo); //关闭文件
}
else //如果创建文件不成功
{
printf("Fail to creat file , Err Code:%d\n",res);
}
znFAT_Flush_FS(); //刷新文件系统
res = znFAT_Open_File(&fileinfo,"/ZNMCU.TXT",0,1);
if(res){
printf("Fail to open file2 , Err Code:%d\n",res);
}else{
printf("Suc to open file2 , Err Code:%d\n",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据1:");
while(buf2[i]!=0){
printf("%c",buf2[i]);
i++;
}
znFAT_Close_File(&fileinfo);
res = znFAT_Open_File(&fileinfo,"/ABCDE.TXT",0,1);
if(res){
printf("Fail to open file1 , Err Code:%d\n",res);
}else{
printf("Suc to open file1 , Err Code:%d\n",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据2:");
while(buf2[i]!=0){
printf("%c",buf2[i]);
i++;
}
znFAT_Close_File(&fileinfo);
while(1);
}
if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
ReadAddr /= 512;
}
改为
if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
// ReadAddr /= 512;
}else{
ReadAddr *= 512;
}
GAME PAUSE…