设备: STM32F103VE-M3,板载SD卡读写模块。
源码: 野火的SD卡扇区读写驱动,振南FAT的STM32版本。
另有1G-16G SD卡若干张。
移植过程:
- SD卡扇区读写驱动测试,SD卡单扇区读写,多扇区读写,多扇区擦除成功。
- 以此项目为基础项目,新建ZNFAT组,添加振南项目znFAT文件夹下源文件。
- 关联znFAT,源码如下。其中sdio_sdcard.h为野火SD卡驱动提供的读写模块。
sdx1.h
#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;
}
写main方法测试基本功能:文件创建,追加,打开,读取,关闭。注意相应的功能需在config.h中打开相应宏。
#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("串口设置完毕rn");
znFAT_Device_Init(); //存储设备初始化
printf("SD卡初始化完毕rn");
printf( " rn CardType is :%d ", SDCardInfo.CardType );
printf( " rn CardCapacity is :%d ", SDCardInfo.CardCapacity );
printf( " rn CardBlockSize is :%d ", SDCardInfo.CardBlockSize );
printf( " rn RCA is :%d ", SDCardInfo.RCA);
printf( " rn ManufacturerID is :%d rn", SDCardInfo.SD_cid.ManufacturerID );
znFAT_Select_Device(0,&Init_Args); //选择设备
/*
res = znFAT_Make_FS(SD1_GetTotalSec(),0);
if(res){
printf("格式化失败 , Err Code:%dn",res);
}else{
printf("格式化成功 , Err Code:%dn",res);
}*/
res=znFAT_Init(); //文件系统初始化
if(!res) //文件系统初始化成功
{
printf("Suc. to init FSrn");
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: %dn",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:%dn",res);
}else{
printf("Suc to delete file , Err Code:%dn",res);
}
*/
res=znFAT_Create_File(&fileinfo,"/ZNMCU.TXT",&dt); //创建文件
if(!res) //如果创建文件成功
{
printf("Suc. to creat file.rn");
printf("================================n");
printf("File_Name(Short 8.3):%sn",fileinfo.File_Name);
printf("File_Size:%dn",fileinfo.File_Size);
printf("File_CDate:%d-%d-%d %d:%d:%dn",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:%dn",fileinfo.File_StartClust);
printf("File_CurClust:%dn",fileinfo.File_CurClust);
printf("File_CurSec:%dn",fileinfo.File_CurSec);
printf("File_CurPos:%dn",fileinfo.File_CurPos);
printf("File_CurOffset:%dn",fileinfo.File_CurOffset);
printf("================================n");
for(i=0;i<20;i++) buf
="akkjdjnknksjk897w9887309e09e";
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 %dn:",len);
}
else
{
printf("Write Data,times:%dn",i);
printf("Current file offset is %dn",fileinfo.File_CurOffset);
}
}
znFAT_Close_File(&fileinfo); //关闭文件
}
else //如果创建文件不成功
{
printf("Fail to creat file , Err Code:%dn",res);
}
znFAT_Flush_FS(); //刷新文件系统
res = znFAT_Open_File(&fileinfo,"/ZNMCU.TXT",0,1);
if(res){
printf("Fail to open file2 , Err Code:%dn",res);
}else{
printf("Suc to open file2 , Err Code:%dn",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据1:");
while(buf2!=0){
printf("%c",buf2);
i++;
}
znFAT_Close_File(&fileinfo);
res = znFAT_Open_File(&fileinfo,"/ABCDE.TXT",0,1);
if(res){
printf("Fail to open file1 , Err Code:%dn",res);
}else{
printf("Suc to open file1 , Err Code:%dn",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据2:");
while(buf2!=0){
printf("%c",buf2);
i++;
}
znFAT_Close_File(&fileinfo);
while(1);
}
编译,修改错误。原因是sys.c/sys.h中void NVIC_Configuration(void)函数与原项目重名,去掉sys中那个。另外,把FWlib需要的外设驱动添加进来,并包括相应头文件,没用到的可以去掉。
编译通过,烧写到开发板。插上4G(或以上)SD卡,串口连接到电脑,复位。从串口输出的数据看出,写入的文件可以成功读出。但SD卡插到电脑却看不到文件!
用winhex查看SD卡扇区内容,发现znFAT调用底层驱动的入参是以扇区为地址,而野火提供的驱动却按照字节处理。所以要修改驱动源码。将sdio_sdcard.c中的
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;
}
- 此时,已经可以向4G及以上的SDHC卡中正确读写文件,并与windows文件系统一致。
- 但是2G及以下的SD标准2.0卡仍然无法写入文件(驱动正常),卡在文件初始化这一步。通过查看znFAT_Init()函数,发现中止在znFAT_Device_Read_Sector((pInit_Args->BPB_Sector_No),znFAT_Buffer); 这一行。进一步输出中间值,并查看相应扇区内容,发现读取的扇区地址无效,SD卡任何位置都查找不到FAT32文件系统的特征字符串。这说明标准卡与大容量卡的文件系统有所差异。
- 稍后将考察文件系统,尝试进一步解决问题。
GAME PAUSE…
设备: STM32F103VE-M3,板载SD卡读写模块。
源码: 野火的SD卡扇区读写驱动,振南FAT的STM32版本。
另有1G-16G SD卡若干张。
移植过程:
- SD卡扇区读写驱动测试,SD卡单扇区读写,多扇区读写,多扇区擦除成功。
- 以此项目为基础项目,新建ZNFAT组,添加振南项目znFAT文件夹下源文件。
- 关联znFAT,源码如下。其中sdio_sdcard.h为野火SD卡驱动提供的读写模块。
sdx1.h
#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;
}
写main方法测试基本功能:文件创建,追加,打开,读取,关闭。注意相应的功能需在config.h中打开相应宏。
#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("串口设置完毕rn");
znFAT_Device_Init(); //存储设备初始化
printf("SD卡初始化完毕rn");
printf( " rn CardType is :%d ", SDCardInfo.CardType );
printf( " rn CardCapacity is :%d ", SDCardInfo.CardCapacity );
printf( " rn CardBlockSize is :%d ", SDCardInfo.CardBlockSize );
printf( " rn RCA is :%d ", SDCardInfo.RCA);
printf( " rn ManufacturerID is :%d rn", SDCardInfo.SD_cid.ManufacturerID );
znFAT_Select_Device(0,&Init_Args); //选择设备
/*
res = znFAT_Make_FS(SD1_GetTotalSec(),0);
if(res){
printf("格式化失败 , Err Code:%dn",res);
}else{
printf("格式化成功 , Err Code:%dn",res);
}*/
res=znFAT_Init(); //文件系统初始化
if(!res) //文件系统初始化成功
{
printf("Suc. to init FSrn");
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: %dn",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:%dn",res);
}else{
printf("Suc to delete file , Err Code:%dn",res);
}
*/
res=znFAT_Create_File(&fileinfo,"/ZNMCU.TXT",&dt); //创建文件
if(!res) //如果创建文件成功
{
printf("Suc. to creat file.rn");
printf("================================n");
printf("File_Name(Short 8.3):%sn",fileinfo.File_Name);
printf("File_Size:%dn",fileinfo.File_Size);
printf("File_CDate:%d-%d-%d %d:%d:%dn",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:%dn",fileinfo.File_StartClust);
printf("File_CurClust:%dn",fileinfo.File_CurClust);
printf("File_CurSec:%dn",fileinfo.File_CurSec);
printf("File_CurPos:%dn",fileinfo.File_CurPos);
printf("File_CurOffset:%dn",fileinfo.File_CurOffset);
printf("================================n");
for(i=0;i<20;i++) buf
="akkjdjnknksjk897w9887309e09e";
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 %dn:",len);
}
else
{
printf("Write Data,times:%dn",i);
printf("Current file offset is %dn",fileinfo.File_CurOffset);
}
}
znFAT_Close_File(&fileinfo); //关闭文件
}
else //如果创建文件不成功
{
printf("Fail to creat file , Err Code:%dn",res);
}
znFAT_Flush_FS(); //刷新文件系统
res = znFAT_Open_File(&fileinfo,"/ZNMCU.TXT",0,1);
if(res){
printf("Fail to open file2 , Err Code:%dn",res);
}else{
printf("Suc to open file2 , Err Code:%dn",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据1:");
while(buf2!=0){
printf("%c",buf2);
i++;
}
znFAT_Close_File(&fileinfo);
res = znFAT_Open_File(&fileinfo,"/ABCDE.TXT",0,1);
if(res){
printf("Fail to open file1 , Err Code:%dn",res);
}else{
printf("Suc to open file1 , Err Code:%dn",res);
}
znFAT_ReadData(&fileinfo,5,12,buf2);
i=0;
printf("读出数据2:");
while(buf2!=0){
printf("%c",buf2);
i++;
}
znFAT_Close_File(&fileinfo);
while(1);
}
编译,修改错误。原因是sys.c/sys.h中void NVIC_Configuration(void)函数与原项目重名,去掉sys中那个。另外,把FWlib需要的外设驱动添加进来,并包括相应头文件,没用到的可以去掉。
编译通过,烧写到开发板。插上4G(或以上)SD卡,串口连接到电脑,复位。从串口输出的数据看出,写入的文件可以成功读出。但SD卡插到电脑却看不到文件!
用winhex查看SD卡扇区内容,发现znFAT调用底层驱动的入参是以扇区为地址,而野火提供的驱动却按照字节处理。所以要修改驱动源码。将sdio_sdcard.c中的
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;
}
- 此时,已经可以向4G及以上的SDHC卡中正确读写文件,并与windows文件系统一致。
- 但是2G及以下的SD标准2.0卡仍然无法写入文件(驱动正常),卡在文件初始化这一步。通过查看znFAT_Init()函数,发现中止在znFAT_Device_Read_Sector((pInit_Args->BPB_Sector_No),znFAT_Buffer); 这一行。进一步输出中间值,并查看相应扇区内容,发现读取的扇区地址无效,SD卡任何位置都查找不到FAT32文件系统的特征字符串。这说明标准卡与大容量卡的文件系统有所差异。
- 稍后将考察文件系统,尝试进一步解决问题。
GAME PAUSE…
举报