设备: STM32F103VE-M3,板载SD卡读写模块。
源码: 野火的SD卡扇区读写驱动,振南FAT的STM32版本。
另有1G-16G SD卡若干张。
移植过程:

  1. SD卡扇区读写驱动测试,SD卡单扇区读写,多扇区读写,多扇区擦除成功。
  2. 以此项目为基础项目,新建ZNFAT组,添加振南项目znFAT文件夹下源文件。
  3. 关联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;
}
  1. 写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("串口设置完毕\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);
}   
  1. 编译,修改错误。原因是sys.c/sys.h中void NVIC_Configuration(void)函数与原项目重名,去掉sys中那个。另外,把FWlib需要的外设驱动添加进来,并包括相应头文件,没用到的可以去掉。
  2. 编译通过,烧写到开发板。插上4G(或以上)SD卡,串口连接到电脑,复位。从串口输出的数据看出,写入的文件可以成功读出。但SD卡插到电脑却看不到文件!
  3. 用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;}
  1. 此时,已经可以向4G及以上的SDHC卡中正确读写文件,并与windows文件系统一致。
  2. 但是2G及以下的SD标准2.0卡仍然无法写入文件(驱动正常),卡在文件初始化这一步。通过查看znFAT_Init()函数,发现中止在znFAT_Device_Read_Sector((pInit_Args->BPB_Sector_No),znFAT_Buffer); 这一行。进一步输出中间值,并查看相应扇区内容,发现读取的扇区地址无效,SD卡任何位置都查找不到FAT32文件系统的特征字符串。这说明标准卡与大容量卡的文件系统有所差异。
  3. 稍后将考察文件系统,尝试进一步解决问题。

GAME PAUSE…

STM32-M3(野火)SD卡读写/移植znFAT文件访问系统相关推荐

  1. 使用vscode + gcc进行 STM32 单片机开发(三)DMA读写SD卡,移植FATFS文件系统

    背景 在本系列的前两篇文章( 使用vscode + gcc进行 STM32 单片机开发(一)编译及调试 使用vscode + gcc进行 STM32 单片机开发(二)gcc环境 移植rtthread) ...

  2. STM32CubeMX系列09——SDIO(SD卡读写、SD卡移植FATFS文件系统)

    文章目录 1. 准备工作 1.1. 简单扫盲 1.1.1. SD卡 1.1.2. TF卡 1.1.3. SDIO接口 1.2. 所用硬件及原理图 2. 创建工程 2.1. 选择主控 2.2. 系统配置 ...

  3. STM32利用FATFS文件系统给SD卡读写数据

    STM32利用FATFS文件系统给SD卡读写数据 注:FATFS文件系统官方网址(内含各种函数具体功能及参数配置): FATFS文件系统官方网址 1. 所需.c和.h文件 FATFS中的文件的作用如下 ...

  4. SDIO协议梳理附SD卡读写以及FATFS移植实例

    文章列表 嵌入式各协议标准按照OSI模型的思路进行逐个梳理,文章列表如下: 串行通信&UART协议梳理附STM32平台采用DMA以UART方式收发不定长信息 I²C总线协议梳理附STM32平台 ...

  5. 【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段

    相关文章 <[SDIO]SDIO.SD卡.FatFs文件系统相关文章索引> 1.前言 本篇文章主要是介绍SD卡的读写测试,包括:SD卡擦除测试.SD卡单一块读写测试.SD卡多个块读写测试. ...

  6. GD32F4xx SD卡读写及FATFS移植记录

      最近调试了一下GD32F450Z 的SDIO接口,读写micro SD卡并移植了FATFS调试过程记录如下,调试时使用的是16GB Kingston TF 卡. 说一下思路:分3步实现 1.从资料 ...

  7. SDIO—SD 卡读写测试

    1.SDIO 简介 SD 卡 (Secure Digital Memory Card) 在我们生活中已经非常普遍了,控制器对 SD 卡进行读写通信操作一般有两种通信接口可选,一种是 SPI 接口,另外 ...

  8. 简述sd卡2.0协议_【正点原子FPGA连载】第十二章SD卡读写TXT文本实验-领航者 ZYNQ 之嵌入式开发指南...

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  9. sdhc 读写 扇区 linux,SD卡读写扇区注意事项(转)

    在调试SD卡时,大家都喜欢使用扇区进行验证.也就是说,一般都是通过读写扇区数据进行比较,或者读取第0扇区的数据,在通过WinHex软件打开启动扇区进行比较.这种方法对于1G的SD卡或部分2G的SD卡可 ...

最新文章

  1. Docker操作命令详解
  2. Qt IFW框架简介
  3. int size java_int size()
  4. Niginx笔记-Linux上源码安装Niginx
  5. ubuntu 13.04安装注意事项和ROOT密码设置
  6. 登录后主机名变成-bash-4.2解决
  7. MVC中使用编辑器提交内容时出错的解决方法
  8. Convert.ToInt32、(int)和int.Parse 三者的区别 转
  9. exec还原oracle,详解通过Backup Exec来实施Oracle灾难恢复
  10. comsol 超声声场模拟_[转载]Comsol Multiphysics 声场仿真模块整体介绍
  11. Spring Boot干货系列(一)入门篇
  12. python通讯卡_如何使用树莓派连接EM-18RFID阅读器模块 并通过Python脚本从一些RFID卡访问信息...
  13. 写接口给京东使用的过程中学到的学习方法
  14. 树莓派4B(armv7l,arm32)buster安装PyTorch、torchvision、torchaudio、onnxruntime
  15. STM32H7外设配置速查【QSPI部分】
  16. freertos---队列管理
  17. UIWebView的用法
  18. 我的世界mod整合包java_我的世界1.10.2mod大全+整合包+合集
  19. 通讯中断 pc_《幽灵行动:断点》PC配置需求公布 4K画质需RTX2080
  20. Famous trading system

热门文章

  1. 关于verilog全加器
  2. JS使用canvas实现(下雨天)特效
  3. [微信聊天]--一个人有多成熟,就看他如何聊微信
  4. ubuntu安装opencv viz模块
  5. 全球第一开源云ERP Odoo操作手册 模块安装和界面汉化指南
  6. 使用SPSS进行曲线估算分析
  7. 雪球网爬取上市公司信息(一):爬取上市公司代号
  8. 机器学习之sklearn-KNN近邻算法分类小案例(乳腺癌预测最优模型)
  9. mysql 集群 运维_【MySQL运维】Canal集群模式与多数据库同步部署
  10. AXIS摄像头IP配置方法