34847|85

4996

帖子

19

TA的资源

裸片初长成(初级)

楼主
 

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

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

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

最新回复

版主大大,我遇到一个问题,就是关闭文件后,出现FR_INVALID_OBJECT错误,之后就无法正常的读写,这个有什么好的解决方法。   详情 回复 发表于 2021-5-7 10:12

赞赏

1

查看全部赞赏

点赞 关注(22)
个人签名我的博客
 

回复
举报

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

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

  4. FRESULT f_fsCheck(
  5.         const TCHAR *path,        /* Pointer to the logical drive number (root dir) */
  6.         DWORD *nclst,                /* Pointer to the variable to return number of free clusters */
  7.         FATFS **fatfs                /* Pointer to pointer to corresponding file system object to return */
  8. )
  9. {
  10.         FRESULT res;
  11.         FATFS *fs;
  12.         DWORD n, clst, sect, stat;
  13.         UINT i;
  14.         BYTE fat, *p;

  15.         /* Get drive number */
  16.         res = chk_mounted(&path, fatfs, 0);
  17.         fs = *fatfs;
  18.         if (res == FR_OK) {
  19.                         /* Get number of free clusters */
  20.                   fat = fs->fs_type;
  21.                   n = 0;
  22.                   if (fat == FS_FAT12) {
  23.                           clst = 2;
  24.                           do {
  25.                                   stat = get_fat(fs, clst);
  26.                                   if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
  27.                                   if (stat == 1) { res = FR_INT_ERR; break; }
  28.                                   if (stat == 0) n++;
  29.                           } while (++clst < fs->n_fatent);
  30.                   } else {
  31.                           clst = fs->n_fatent;
  32.                           sect = fs->fatbase;
  33.                           i = 0; p = 0;
  34.                           BYTE cnt = 0;
  35.                           
  36.                           do {
  37.                                   if (!i) {
  38.                                           res = move_window(fs, sect++);
  39.                                           if (res != FR_OK) break;
  40.                                           p = fs->win;
  41.                                           i = SS(fs);
  42.                                   }
  43.                                   if (fat == FS_FAT16) {
  44.                                           if (LD_WORD(p) == 0) n++;
  45.                                           p += 2; i -= 2;
  46.                                   } else {
  47.                                           if ((LD_DWORD(p) & 0x0FFFFFFF) == 0)
  48.                                           {
  49.                                               if (++cnt > 10)                   // 连续10个空簇,退出
  50.                                               {
  51.                                                   break;
  52.                                               }
  53.                                           }
  54.                                           else
  55.                                           {
  56.                                               n++;
  57.                                               cnt = 0;
  58.                                           }
  59.                                           
  60.                                           p += 4; i -= 4;
  61.                                   }
  62.                           } while (--clst);
  63.                   }
  64.                   
  65.                   if (fs->last_clust > (n+10))
  66.                   {
  67.                       res = FR_INT_ERR;                  
  68.                   }
  69.         }
  70.         LEAVE_FF(fs, res);
  71. }
复制代码
FatFs中并没有这个函数,是本添加的。后面我们可以调用这个函数实现FAT检查功能。
  1. /**************************************************************************************
  2. * FunctionName   : FatFileSystemCheck()
  3. * Description    : FsInfo校验
  4. * EntryParameter : None
  5. * ReturnValue    : 返回操作结果
  6. **************************************************************************************/
  7. u8 FatFileSystemCheck(void)
  8. {
  9.     FATFS *pFs;
  10.     FATFS fs;
  11.     FRESULT res;
  12.     DWORD fre_clust;

  13.     f_mount(0, &fs);
  14.     res = f_fsCheck("", &fre_clust, &pFs);
  15.     f_mount(0, 0);
  16.    
  17.     return res;
  18. }
复制代码
后面我们可以通过此函数的返回值,看是否要格式。
  1. if (FatFileSystemCheck() != FR_OK)                              // 文件系统毁坏,格式
  2. {
  3.      App_Format();
  4. }
复制代码


[ 本帖最后由 zhaojun_xf 于 2013-8-6 10:42 编辑 ]
此帖出自NXP MCU论坛

点评

这个情况确实是遇到过,不知道怎么弄,播放机里可以播放,但是电脑上显示不出来,只能凑合用了。  详情 回复 发表于 2014-2-9 14:22
 
个人签名我的博客
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

     下面的代码用于判断用于判断是否可以在这个文件夹下新建文件,能新建就是正常的,否则异常,删除这个文件夹。
  1. /**************************************************************************************
  2. * FunctionName   : FatCreateDir()
  3. * Description    : 创建一个新目录
  4. * EntryParameter : folder - 文件夹的名称
  5. * ReturnValue    : 成功返回真,否则返回假
  6. **************************************************************************************/
  7. u8 FatCreateDir(u8 *dir)
  8. {
  9.     FATFS fs;
  10.     FRESULT res;
  11.     DIR dirs;            

  12.     f_mount(0, &fs);  
  13.    
  14.     res = f_opendir(&dirs, (const TCHAR *)dir);                                 // 打开目录
  15.     if (res == FR_NO_PATH)                                                      // 没有则创建
  16.     {
  17.         res = f_mkdir((const TCHAR *)dir);                                         // 创建目录        
  18.         if (res != FR_OK)
  19.         {
  20.             FatDeleteFile(dir);
  21.             res = (FRESULT)FatCreateDir(dir);
  22.         }
  23.     }
  24.    
  25.     f_mount(0, 0);
  26.     return res;
  27. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

     下面的代码用于判断文件是否读写正确,文件内容为0字节,而且写失败就删除。
  1. /**************************************************************************************
  2. * FunctionName   : FatWriteFile()
  3. * Description    : 写一个文件
  4. * EntryParameter : fname - 文件名,包含路径,pBuf - 缓冲,len - 长度
  5. * ReturnValue    : 成功返回真,否则返回假
  6. **************************************************************************************/
  7. u8 FatWriteFile(u8 *fname, u8 *pBuf, u16 len)
  8. {
  9.     FATFS fs;               
  10.     FIL fno;
  11.     UINT  bw;              
  12.     FRESULT res;
  13.    
  14.     f_mount(0, &fs);
  15.     res = f_open(&fno, (const TCHAR *)fname, FA_OPEN_ALWAYS|FA_WRITE);
  16.    
  17.     if (res == FR_OK)
  18.     {
  19.         res = f_lseek(&fno, fno.fsize);                                                // 获取偏移指针
  20.         if (res == FR_OK)
  21.         {
  22.             res = f_write(&fno, pBuf, len, &bw);                                // 数据写入
  23.             if ((res != FR_OK) && (fno.fsize == 0))
  24.             {
  25.                 res = f_unlink((const TCHAR *)fname);
  26.             }
  27.         }
  28.     }

  29.     f_close(&fno);
  30.     f_mount(0, 0);
  31.     return res;
  32. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

      解决:既然是通过这几个管脚窜进去的,那么在关掉电源之前让这几个管脚都没有电压输入就可以了。
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

2453

帖子

19

TA的资源

五彩晶圆(中级)

6
 
精品贴子
此帖出自NXP MCU论坛
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

     我们可以尽量减少操作文件的时间,如果时间不能减少,我们可以减少临界代码的尺寸,可以在代码中添加f_sync()函数。例如下面的写WAV文件中,由于需要分别写入头和文件内容,我们可以再写入一段数据后添加一个同步还是。
  1. /**************************************************************************************
  2. * FunctionName   : FatWriteWave()
  3. * Description    : 写WAV文件
  4. * EntryParameter : fname - 路径,pHd - 文件头,pDat - 数据,datLen - 数据长度
  5. * ReturnValue    : 成功返回0,否则返回1
  6. **************************************************************************************/
  7. u8 FatWriteWave(u8 *fname, u8 *pHd, u8 hdLen, u8 *pDat, u16 datLen)
  8. {
  9.     FATFS fs;               
  10.     FIL fno;
  11.     UINT  bw;              
  12.     FRESULT res;
  13.    
  14.     f_mount(0, &fs);
  15.     res = f_open(&fno, (const TCHAR *)fname, FA_OPEN_ALWAYS|FA_WRITE);
  16.     if (res == FR_OK)
  17.     {
  18.         res = (fno.fsize > 0) ? f_lseek(&fno, fno.fsize) : f_lseek(&fno, hdLen);      
  19.         if (res == FR_OK)
  20.         {
  21.             res = f_write(&fno, pDat, datLen, &bw);                             // 数据写入
  22.             if ((res != FR_OK) && (fno.fsize == 0))
  23.             {
  24.                 res = f_unlink((const TCHAR *)fname);
  25.             }
  26.             else
  27.             {
  28.                 f_sync(&fno);
  29.                 if (res == FR_OK)
  30.                 {
  31.                     res = f_lseek(&fno, 0);
  32.                     if (res == FR_OK)
  33.                     {
  34.                         res = f_write(&fno, pHd, hdLen, &bw);                   // 数据写入成功后再写文件头
  35.                         if ((res != FR_OK) && (fno.fsize == 0))
  36.                         {
  37.                             res = f_unlink((const TCHAR *)fname);
  38.                         }
  39.                     }
  40.                 }
  41.             }
  42.         }
  43.     }

  44.     f_close(&fno);
  45.     f_mount(0, 0);
  46.     return res;
  47. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

9177

帖子

6

TA的资源

管理员

8
 
这个是好东西啊,现在手上好多SD卡,有几个就是不能格式化不能删除文件的,这回找到原因和解决的办法了!
此帖出自NXP MCU论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身

点评

希望能帮你解决问题。。。。。。  详情 回复 发表于 2013-8-6 10:25
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

9
 

回复 8楼eric_wang 的帖子

希望能帮你解决问题。。。。。。
此帖出自NXP MCU论坛

点评

:titter: 我的卡删除照片自动能恢复回去,格式化都失败,这回可以解决了:lol  详情 回复 发表于 2013-8-6 10:31
 
个人签名我的博客
 
 

回复

9177

帖子

6

TA的资源

管理员

10
 

回复 9楼zhaojun_xf 的帖子

我的卡删除照片自动能恢复回去,格式化都失败,这回可以解决了
此帖出自NXP MCU论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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

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

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

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

下面的代码可以通过扫描FAT区获取真正的空闲号和空余空间,同时矫正这些信息。
  1. /*-----------------------------------------------------------------------*/
  2. /* Get Number of Free Clusters and proof */
  3. /*-----------------------------------------------------------------------*/

  4. FRESULT f_getfreeproof(
  5. const TCHAR *path, /* Pointer to the logical drive number (root dir) */
  6. DWORD *nclst, /* Pointer to the variable to return number of free clusters */
  7. FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
  8. )
  9. {
  10. FRESULT res;
  11. FATFS *fs;
  12. DWORD n, clst, sect, stat;
  13. UINT i;
  14. BYTE fat, *p;

  15. /* Get drive number */
  16. res = chk_mounted(&path, fatfs, 0);
  17. fs = *fatfs;
  18. if (res == FR_OK) {
  19. /* Get number of free clusters */
  20. fat = fs->fs_type;
  21. n = 0;
  22. if (fat == FS_FAT12) {
  23. clst = 2;
  24. do {
  25. stat = get_fat(fs, clst);
  26. if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
  27. if (stat == 1) { res = FR_INT_ERR; break; }
  28. if (stat == 0) n++;
  29. } while (++clst < fs->n_fatent);
  30. } else {
  31. clst = fs->n_fatent;
  32. sect = fs->fatbase;
  33. i = 0; p = 0;
  34. do {
  35. if (!i) {
  36. res = move_window(fs, sect++);
  37. if (res != FR_OK) break;
  38. p = fs->win;
  39. i = SS(fs);
  40. }
  41. if (fat == FS_FAT16) {
  42. if (LD_WORD(p) == 0) n++;
  43. p += 2; i -= 2;
  44. } else {
  45. if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
  46. p += 4; i -= 4;
  47. }
  48. } while (--clst);
  49. }

  50. if (fs->free_clust != n)
  51. {
  52. fs->free_clust = n;
  53. fs->last_clust = 0x02;
  54. if (fat == FS_FAT32) fs->fsi_flag = 1;
  55. *nclst = n;
  56. sync(fs);
  57. }
  58. }
  59. LEAVE_FF(fs, res);
  60. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

1729

帖子

0

TA的资源

五彩晶圆(初级)

12
 
绝对的好文章,需要大力支持一下啊!
此帖出自NXP MCU论坛

点评

谢谢支持,希望对大家有用。。。。  详情 回复 发表于 2013-8-6 11:05
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

     下面的代码是以JPGE文件为例,如果JPGE文件的头和尾不正确时,图片显示不对,对于头不对时,显示无法打开,如果是尾不正确可以打开,但部分内容无法显示,只能显示部分图像。我们可以通过判断,把不正确的图片删除,保留也没有意义。此发可以应用到其他文件上,至于该判断头还是尾,根据文件更改。
  1. /**************************************************************************************
  2. * FunctionName   : FatJpgFileJud()
  3. * Description    : 文件判断
  4. * EntryParameter : None
  5. * ReturnValue    : 格式错误返回1,否则返回0
  6. **************************************************************************************/
  7. u8 FatJpgFileJud(u8 *fname)
  8. {
  9.     FATFS fs;
  10.     FRESULT res;
  11.     FIL file;  
  12.     UINT br;
  13.     u8 reVal = 1;
  14.     u8 buf[2] = {0};

  15.     f_mount(0, &fs);
  16.     res = f_open(&file, (const TCHAR *)fname, FA_READ);                         // 打开文件
  17.    
  18.     if (res == FR_OK)
  19.     {
  20.         f_lseek(&file, 0);                                                      // 打开指定位置
  21.         res = f_read(&file, buf, 2, &br);                                       // 读取数据
  22.         if ((res == FR_OK) && (buf[0] == 0xFF) && (buf[1] == 0xD8))             // 头判断
  23.         {
  24.             f_lseek(&file, file.fsize-2);                                        // 获取偏移指针
  25.             res = f_read(&file, buf, 2, &br);                                   // 读取数据
  26.             if ((res == FR_OK) && (buf[0] == 0xFF) && (buf[1] == 0xD9))         // 尾判断
  27.             {
  28.                 reVal = FR_OK;
  29.             }
  30.         }
  31.     }
  32.    
  33.     f_close(&file);
  34.     return (reVal);      
  35. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

14
 

回复 12楼cat3902982 的帖子

谢谢支持,希望对大家有用。。。。
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

2万

帖子

74

TA的资源

管理员

15
 
赞 :)
此帖出自NXP MCU论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

     如果连续几次写不了数据就格式化SD卡,势必导致SD卡中文件内容的丢失,为了把损失将到最低,我们可以让设备重启,如果仍然无法写入数据,再格式化SD卡。
  1. /**************************************************************************************
  2. * FunctionName   : AppSDCardAbnormal()
  3. * Description    : SD卡异常处理
  4. * EntryParameter : None
  5. * ReturnValue    : None
  6. **************************************************************************************/
  7. void AppSDCardAbnormal(void)
  8. {
  9.     if ((AppPar.WrdErr+CMRPar.SECnt > APP_WRD_ER) && (AppPar.SdcSta == APP_SDC_NRM))
  10.     {
  11.         if (SDGetCardStatus() != SD_CARD_NO)                                    // 读取SD卡状态
  12.         {
  13.             FLSRestart();                                                       // 重启
  14.         }
  15.         else
  16.         {
  17.             AppPar.WrdErr = 0;
  18.             CMRPar.SECnt  = 0;
  19.         }
  20.     }
  21. }
复制代码
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

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


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

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

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

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


[ 本帖最后由 zhaojun_xf 于 2013-8-6 12:28 编辑 ]
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复

3238

帖子

5

TA的资源

五彩晶圆(中级)

18
 
不错,特来支持一下
此帖出自NXP MCU论坛
 
个人签名淘宝:https://viiot.taobao.com/Q群243090717
多年专业物联网行业经验,个人承接各类物联网外包项目
 
 

回复

64

帖子

0

TA的资源

一粒金砂(中级)

19
 
好  谢谢了
此帖出自NXP MCU论坛
 
 
 

回复

1100

帖子

3

TA的资源

五彩晶圆(初级)

20
 
:carnation: :carnation: :carnation: 给力
此帖出自NXP MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表