https://www.amobbs.com/thread-5611031-1-1.html

本帖最后由 ericdata11 于 2015-1-18 08:47 编辑

之前我有遇過相同問題,解決方法很簡單,因為小容量(4G 以下)SD Card地址為32bit方式搜尋,大容量(4G~32G)SD Card地址為512一個扇區搜尋位置。
FATFS讀取與寫入都是已一個扇區來操作,使用小容量SD卡需要*512,使用大容量SD卡則不須*512。

SDIO底層函數中:
SD_ReadBlock()和SD_ReadMultiBlocks()函數
SD_WriteBlock()和SD_WriteMultiBlocks()函數。
這4個函數,開頭有一段code需要修改,修改如下。在剛開始進入函數後進行位置修正。

ex SD_WriteMultiBlocks()函數

BlockSize = 512;
  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)//高容量版本
  {
    // *** 大容量版本 ***
    
    //WriteAddr /= 512;
  }
else
{
// *** 小容量版本 ***
WriteAddr *= 512;
}

http://bbs.eeworld.com.cn/forum.php?mod=viewthread&tid=377465&page=1&authorid=66265

问题1:根目录下文件毁坏。

SD卡应用总结(FatFs) [复制链接]

对于SD卡的应用,想必大家都尝试多。不过,很多网友恐怕只停留在实验的基础上吧。对于SD卡在文件系统下或者不带文件系统下,对SD卡的操作都是很简单的。是的,只是简单的文件读写确实不难。但是,如果每秒钟不停的写数据,而且是不停的工作,恐怕SD卡的应用就没有这么简单了吧,有时总会出现一些莫名其妙的问题。

不知道大家是否遇到过这些问题?本人开发了几个关于SD卡的项目,例如,定时拍照、定时录音等。对于这样的项目,基本上要求每一秒都在不停的写数据,而且一般一天工作好几个小时,甚至会不停的工作。在这些项目中,本人遇到太多的问题,下面把遇到的问题及解决方法与大家分享,希望有同样经验的网友一起分享一下您的经验。

此帖出自NXP MCU论坛

现象:在FatFs下可以读写文件,可在PC上无法打开目录,提示文件毁坏。

分析:通过WinHex软件打开磁盘,发现目录完全正常,但是FAT表已经毁坏,引起的原因可能是带电插拔。

解决:既然是FAT表与目录对不上,而且FAT毁坏,就是用PC修复也只会删除这些文件,对于我们的单片机来说,也没有好的解决方法,那就格式吧。

下面的代码用于判断FAT表是否和文件目录对应的上,使用的方法是:扫描FAT表,看看应用了多少簇,在通过读取FSInfo扇区的信息,看这两者是否一致。一致时为正确,不一致一般有问题。

/*-----------------------------------------------------------------------*/
/* File system check                                                     */
/*-----------------------------------------------------------------------*/FRESULT f_fsCheck(const TCHAR *path,        /* Pointer to the logical drive number (root dir) */DWORD *nclst,                /* Pointer to the variable to return number of free clusters */FATFS **fatfs                /* Pointer to pointer to corresponding file system object to return */
)
{FRESULT res;FATFS *fs;DWORD n, clst, sect, stat;UINT i;BYTE fat, *p;/* Get drive number */res = chk_mounted(&path, fatfs, 0);fs = *fatfs;if (res == FR_OK) {/* Get number of free clusters */fat = fs->fs_type;n = 0;if (fat == FS_FAT12) {clst = 2;do {stat = get_fat(fs, clst);if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }if (stat == 1) { res = FR_INT_ERR; break; }if (stat == 0) n++;} while (++clst < fs->n_fatent);} else {clst = fs->n_fatent;sect = fs->fatbase;i = 0; p = 0;BYTE cnt = 0;do {if (!i) {res = move_window(fs, sect++);if (res != FR_OK) break;p = fs->win;i = SS(fs);}if (fat == FS_FAT16) {if (LD_WORD(p) == 0) n++;p += 2; i -= 2;} else {if ((LD_DWORD(p) & 0x0FFFFFFF) == 0){if (++cnt > 10)                   // 连续10个空簇,退出{break;}}else{n++;cnt = 0;}p += 4; i -= 4;}} while (--clst);}if (fs->last_clust > (n+10)){res = FR_INT_ERR;                   }}LEAVE_FF(fs, res);
}

FatFs中并没有这个函数,是本添加的。后面我们可以调用这个函数实现FAT检查功能。

/**************************************************************************************
* FunctionName   : FatFileSystemCheck()
* Description    : FsInfo校验
* EntryParameter : None
* ReturnValue    : 返回操作结果
**************************************************************************************/
u8 FatFileSystemCheck(void)
{FATFS *pFs;FATFS fs;FRESULT res;DWORD fre_clust;f_mount(0, &fs);res = f_fsCheck("", &fre_clust, &pFs);f_mount(0, 0);return res;
}

后面我们可以通过此函数的返回值,看是否要格式。

if (FatFileSystemCheck() != FR_OK)                              // 文件系统毁坏,格式
{App_Format();
}

问题2:根目录正常,里边的文件夹毁坏。
    
     现象:在FatFs下可以读写文件,可在PC上可以打开根目录,却无法里面的文件夹,提示文件毁坏。

分析:通过WinHex软件打开磁盘,发现目录完全正常,但是FAT表与目录数据对应不上,引起的原因可能是带电插拔。

解决:既然是FAT表与目录对不上,就是用PC修复也只会删除这些文件,对于我们的单片机来说,也没有好的解决方法,那就删除这个文件吧。

下面的代码用于判断用于判断是否可以在这个文件夹下新建文件,能新建就是正常的,否则异常,删除这个文件夹。

/**************************************************************************************
* FunctionName   : FatCreateDir()
* Description    : 创建一个新目录
* EntryParameter : folder - 文件夹的名称
* ReturnValue    : 成功返回真,否则返回假
**************************************************************************************/
u8 FatCreateDir(u8 *dir)
{FATFS fs;FRESULT res; DIR dirs;             f_mount(0, &fs);  res = f_opendir(&dirs, (const TCHAR *)dir);                                 // 打开目录if (res == FR_NO_PATH)                                                      // 没有则创建{res = f_mkdir((const TCHAR *)dir);                                         // 创建目录        if (res != FR_OK){FatDeleteFile(dir);res = (FRESULT)FatCreateDir(dir);}}f_mount(0, 0);return res;
}

问题3:文件大小为0字节,并且无法删除。
    
     现象:文件已经存在,但在PC下无法删除,删除后会自动生成。

分析:既然文件已经创建,但没有内容,说明,文件打开后,写数据失败。

解决:既然文件已经新建,但没有写内容,我们可以在写内容失败后删除此文件,否则后面就删不掉了,只能格式了。

下面的代码用于判断文件是否读写正确,文件内容为0字节,而且写失败就删除。

/**************************************************************************************
* FunctionName   : FatWriteFile()
* Description    : 写一个文件
* EntryParameter : fname - 文件名,包含路径,pBuf - 缓冲,len - 长度
* ReturnValue    : 成功返回真,否则返回假
**************************************************************************************/
u8 FatWriteFile(u8 *fname, u8 *pBuf, u16 len)
{FATFS fs;               FIL fno; UINT  bw;              FRESULT res;f_mount(0, &fs);res = f_open(&fno, (const TCHAR *)fname, FA_OPEN_ALWAYS|FA_WRITE);if (res == FR_OK){res = f_lseek(&fno, fno.fsize);                                                // 获取偏移指针if (res == FR_OK){res = f_write(&fno, pBuf, len, &bw);                                // 数据写入if ((res != FR_OK) && (fno.fsize == 0)){res = f_unlink((const TCHAR *)fname);}}}f_close(&fno);f_mount(0, 0);return res;
}

问题4:SD卡电源无法关断。
    
     现象:通过I/O端口控制SD卡电源,关断后SD卡电源端还有2.9V左右的电压。

分析:不管用mos管还是电源芯片,通过I/O端口控制都应该截断电源,但事实上SD卡电源叫还是有电,原因是这些电压是通过SPI的4个端口串进去了,特别是片选管脚。

解决:既然是通过这几个管脚窜进去的,那么在关掉电源之前让这几个管脚都没有电压输入就可以了。

问题5:临界代码。
    
     现象:在操作文件系统时有时还没有读写完成,就断电或插拔SD卡。

分析:如果没有写完数据就直接断电或插拔会导致文件或文件系统毁坏。

解决:在对文件进行写操作时进来减小临界代码的尺寸。

我们可以尽量减少操作文件的时间,如果时间不能减少,我们可以减少临界代码的尺寸,可以在代码中添加f_sync()函数。例如下面的写WAV文件中,由于需要分别写入头和文件内容,我们可以再写入一段数据后添加一个同步还是。

/**************************************************************************************
* FunctionName   : FatWriteWave()
* Description    : 写WAV文件
* EntryParameter : fname - 路径,pHd - 文件头,pDat - 数据,datLen - 数据长度
* ReturnValue    : 成功返回0,否则返回1
**************************************************************************************/
u8 FatWriteWave(u8 *fname, u8 *pHd, u8 hdLen, u8 *pDat, u16 datLen)
{FATFS fs;               FIL fno; UINT  bw;              FRESULT res;f_mount(0, &fs);res = f_open(&fno, (const TCHAR *)fname, FA_OPEN_ALWAYS|FA_WRITE);if (res == FR_OK){res = (fno.fsize > 0) ? f_lseek(&fno, fno.fsize) : f_lseek(&fno, hdLen);       if (res == FR_OK){res = f_write(&fno, pDat, datLen, &bw);                             // 数据写入if ((res != FR_OK) && (fno.fsize == 0)){res = f_unlink((const TCHAR *)fname);}else{f_sync(&fno);if (res == FR_OK){res = f_lseek(&fno, 0);if (res == FR_OK){res = f_write(&fno, pHd, hdLen, &bw);                   // 数据写入成功后再写文件头if ((res != FR_OK) && (fno.fsize == 0)){res = f_unlink((const TCHAR *)fname);}}}}}}f_close(&fno);f_mount(0, 0);return res;
}

问题6:FAT表与FSInfo信息不匹配。

现象:为了尽快操作文件,而不用通过FAT遍历就可以知道SD卡的存储状态,在FSInfo中存储了未使用簇数和空闲簇号,但某种原因导致FAT表中是实际使用情况与FSInfo中信息不匹配。

分析:FSInfo中的信息可以快速定位到SD卡中的空闲区域,如果这里的信息不正确,我们只能通过FAT表获取这些信息。如果SD卡很大,特别是应用了很大空间,从FAT表中获取这些信息非常缓慢。

解决:如果某处读写操作非常缓慢时,可能是FAT表与FSInfo中的信息不匹配,我们需要进行一次匹配以矫正FSInfo中的信息。

下面的代码可以通过扫描FAT区获取真正的空闲号和空余空间,同时矫正这些信息。


/*-----------------------------------------------------------------------*/
/* Get Number of Free Clusters and proof */
/*-----------------------------------------------------------------------*/FRESULT f_getfreeproof(
const TCHAR *path, /* Pointer to the logical drive number (root dir) */
DWORD *nclst, /* Pointer to the variable to return number of free clusters */
FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
)
{FRESULT res;FATFS *fs;DWORD n, clst, sect, stat;UINT i;BYTE fat, *p;/* Get drive number */res = chk_mounted(&path, fatfs, 0);fs = *fatfs;if (res == FR_OK) {/* Get number of free clusters */fat = fs->fs_type;n = 0;if (fat == FS_FAT12) {clst = 2;do {stat = get_fat(fs, clst);if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }if (stat == 1) { res = FR_INT_ERR; break; }if (stat == 0) n++;} while (++clst < fs->n_fatent);} else {clst = fs->n_fatent;sect = fs->fatbase;i = 0; p = 0;do {if (!i) {res = move_window(fs, sect++);if (res != FR_OK) break;p = fs->win;i = SS(fs);}if (fat == FS_FAT16) {if (LD_WORD(p) == 0) n++;p += 2; i -= 2;} else {if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;p += 4; i -= 4;}} while (--clst);}if (fs->free_clust != n){fs->free_clust = n;fs->last_clust = 0x02;if (fat == FS_FAT32) fs->fsi_flag = 1;*nclst = n;sync(fs); }}LEAVE_FF(fs, res);
}

问题7:文件毁坏。
    
     现象:在FatFs下写入文件时,有时由于头没有写对,有时由于尾没有写读,导致文件文件打开。

分析:通过WinHex软件打开磁盘,发现文件内容不正确,有点缺头,有的缺尾。

解决:既然是文件头或未不正确,我们可以对其头或尾进行判断,不正确的可以删除掉。

下面的代码是以JPGE文件为例,如果JPGE文件的头和尾不正确时,图片显示不对,对于头不对时,显示无法打开,如果是尾不正确可以打开,但部分内容无法显示,只能显示部分图像。我们可以通过判断,把不正确的图片删除,保留也没有意义。此发可以应用到其他文件上,至于该判断头还是尾,根据文件更改。

/**************************************************************************************
* FunctionName   : FatJpgFileJud()
* Description    : 文件判断
* EntryParameter : None
* ReturnValue    : 格式错误返回1,否则返回0
**************************************************************************************/
u8 FatJpgFileJud(u8 *fname)
{FATFS fs;FRESULT res;FIL file;  UINT br;u8 reVal = 1;u8 buf[2] = {0};f_mount(0, &fs);res = f_open(&file, (const TCHAR *)fname, FA_READ);                         // 打开文件if (res == FR_OK){f_lseek(&file, 0);                                                      // 打开指定位置res = f_read(&file, buf, 2, &br);                                       // 读取数据if ((res == FR_OK) && (buf[0] == 0xFF) && (buf[1] == 0xD8))             // 头判断{f_lseek(&file, file.fsize-2);                                        // 获取偏移指针res = f_read(&file, buf, 2, &br);                                   // 读取数据if ((res == FR_OK) && (buf[0] == 0xFF) && (buf[1] == 0xD9))         // 尾判断{reVal = FR_OK;}}}f_close(&file);return (reVal);
}

问题8:SD卡数据写入失败。
    
     现象:在FatFs下写入文件时,有时会一次写入不了数据,有时会连续几次写入不了数据。

分析:写入不了数据,是一些存储异常或者SD卡异常导致,例如接触不良、内存或堆栈问题等。

解决:写不了数据并不意味做SD卡有问题,我们可以让设备重启,再写入数据。

如果连续几次写不了数据就格式化SD卡,势必导致SD卡中文件内容的丢失,为了把损失将到最低,我们可以让设备重启,如果仍然无法写入数据,再格式化SD卡。

/**************************************************************************************
* FunctionName   : AppSDCardAbnormal()
* Description    : SD卡异常处理
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void AppSDCardAbnormal(void)
{ if ((AppPar.WrdErr+CMRPar.SECnt > APP_WRD_ER) && (AppPar.SdcSta == APP_SDC_NRM)){if (SDGetCardStatus() != SD_CARD_NO)                                    // 读取SD卡状态{FLSRestart();                                                       // 重启}else{AppPar.WrdErr = 0;CMRPar.SECnt  = 0;}}
}

问题9:SD卡热插拔。
    
     现象:在很都时候,我们都需要对SD卡进行热插拔操作,而我们知道,很多文件毁坏都是这样操作导致的。

分析:在读写SD卡时,突出断电由于文件并没有操作完成,会导致文件毁坏。

解决:在对SD卡进行插拔操作时,断掉SD卡的供电。

要读SD卡进行断电操作,可以有很多方法,例如,可以把SD卡锁在设备中,扒卡之前必须开锁,通过锁我们知道要对SD卡进行插拔了,所以,不能再对SD卡操作了,切断SD卡供电。在没有插入卡之前不能对SD卡供电。

当然我们还可以通过按键之类的东西实现,以保证不对SD卡带电操作即可。

SD卡应用总结(Fatfs)相关推荐

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

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

  2. STM32F1与STM32CubeIDE快速入门-SD卡驱动-SDIO+FatFs

    SD卡驱动-SDIO+FatFs 文章目录 SD卡驱动-SDIO+FatFs 1.SDIO与FatFs简单介绍 2.SDIO与FatFs配置 3.SDIO与FatFs功能测试 4.代码解析 5.STM ...

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

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

  4. 【STM32Cube_20】在SD卡上移植FATFS文件系统

    本篇详细的记录了如何使用STM32CubeMX移植FATFS文件系统到SD卡上. 1. 准备工作 硬件准备 开发板 首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi): Mi ...

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

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

  6. STM32用cube配置FATFS模式下SPI读写SD卡

    要求:掌握SD卡协议原理,用STM32F103 完成对SD卡的数据读取(FAT文件模式) 目录 一.SD卡与FATS 1.SD卡 2.FATFS文件系统 二.工程实现 1.编译运行 2.接线 3.初始 ...

  7. STM32CubeMX学习笔记(27)——FatFs文件系统使用(操作SD卡)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

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

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

  9. 贴片SD卡移植FATFS文件系统

    一.前言 手头有一块深圳雷龙提供的贴片 CS 创世 SD NAND Flash,挂载个文件系统把玩一下.首先介绍一下使用的贴片 SD 卡,以前使用的都是拔插式的 SD 卡,下面这个样子: 深圳雷龙提供 ...

最新文章

  1. 如何恢复电脑系统桌面
  2. Upsync:微博开源基于Nginx容器动态流量管理方案
  3. RabbitMQ播放模块! 构架
  4. VC++工作笔记0002---积累-VC++中的L“”是什么意思
  5. STM32工作笔记0015---STEMWIN在STM32F1开发板上的移植
  6. The Learning route of GNN
  7. FileSystemObject ADO WScript.Shell
  8. 《Go程序设计语言》- 第11章:测试
  9. DirectShow播放视频流程
  10. wincc如何实现web发布,及具体方法
  11. 诺基亚 java 软件_初学篇:诺基亚手机软件安装不求人
  12. python爬虫beta版之抓取知乎单页面回答(low 逼版)
  13. 股指期货开户的保证金和手续费是多少?怎么计算?
  14. Thinkpad T420 安装 mSATA SSD 固态硬盘
  15. linux基础知识全面总结,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  16. Matlab2018b任务栏图标消失且与m文件不关联
  17. 计算机网络应用层之HTTP协议
  18. 守株待兔欧洲游-法国(9.30-10.5)(已完工)
  19. 自如2020新产品发布:全面打造智能租住生活
  20. Location specified by ndk.dir (**/Sdk/ndk-bundle) did not contain a valid NDK ...

热门文章

  1. 511遇见易语言寻找字节集和倒找字节集
  2. 使用Python自带的IDLE默认打开.py文件
  3. 基于深度学习的网络入侵检测研究综述
  4. 转:2020-21软件测试中的重要趋势及应对措施
  5. 29个必知晓产业互联网热词
  6. 武田提供3期TOURMALINE-MM2试验的更新
  7. 初学python100例-案例32 男孩女孩小孩人数 少儿编程案例讲解
  8. java代码实现万年历
  9. 视差图(Disparity)三维重投影得到特征点的三维空间坐标的2种方法
  10. ubuntu 工作中常用的终端命令