移植方法参见我的另一篇博客:《stm32--FatFs移植(SPIFlash)》

本文仅记录在初次移植完成后,遇到的问题,和解决的过程。

调试记录:

  1. 问题1:f_open返回3,即磁盘没有准备好。

    • 原因:这是因为逻辑驱动器是按默认(0)初始化的,而在宏定义中把SPIFlash定义为了1。将SPIFlash定义为0即可。
  2. 问题2:开机是否格式化?如果不格式化,SPIFlash无法创建创建文件系统;又不可能每次开机都格式化。
    • 处理:f_getfree检测FAT卷空间,如果返回是FR_NO_FILESYSTEM,说明没有格式化过,进行格式化。
  3. 问题3:格式化失败(返回FR_DISK_ERR)【此时的BLOCK_SIZE参数是错误的】
    • 原因:diskio.c中底层写入函数入口判断错误,入口判断参数是否正常时 if(sector > SEC_MAX || sector + count > SEC_MAX) return RES_PARERR; 出错,第二个判断条件应为sector + count - 1而非sector + count。
  4. 问题4:只能格式化为FAT12格式。
    • 调试过程:仿真跟踪f_mkfs源代码:
    • 如果输入参数为FAT,函数中会减去63个扇区用于存放分区表,此时就只剩4033个扇区了;之后由这段代码,sz_vol为4033,pau为1,得出n_clst为4033<4085(MAX_FAT12),于是设为FAT12格式
    • 如果输入参数为FAT+SFD,sz_vol值为4096,之后由
    • 输入参数FAT+SFD,并在输入参数中强制pau为1,倒是不会置为FAT12格式,但是格式化返回FR_MKFS_ABORTED错误。查找错误原因,发现问题来自
  5. 问题5:不正确的格式化。【此时对FAT文件系统结构的理解是错误的】
    • sz_fat只有3,于是后面格式化只格式化了3个扇区。可是sz_fat和n_clst是互斥的:如果sz_fat很大就意味着n_clst很小,无法格式化为FAT16;如果n_clst格式化为FAT16那就意味着sz_fat是小于10的数。
    • 此时尝试创建文件,“果然”可以创建成功、但无法正确保存:每次重启后能载入文件系统,但获取不到之前创建的文件。
    • 于是开始走向错误的尝试路径:尝试减小单个扇区的定义大小、单次擦除多个扇区。
    • 尝试将单个扇区自定义为1k,block定义为4扇区,修改disk_read函数、disk_wirte函数、disk_ioctl函数,以及格式化函数f_mkfs的输入参数。
      1. 结果:不可行。实际操作中会有写入单个扇区的情况(分区:1系统保留区-x数据区-y页表区),如此,在写入第一个数据扇区的时候,会执行一次erase函数,擦除刚刚写入的系统保留区。类似的情况也会出现在其他地方。
      2. 修改为仅在初始扇区为4的倍数时,允许擦除。如此不会擦除正确写入的数据,但有可能无法成功修改某些单个小扇区。
      3. 修改为,在写入扇区时,如果判断到初始扇区不为4的倍数或结束扇区不为4的倍数,先将4k真实扇区数据读出,再擦除真实扇区,然后将读出的数据写入需写入扇区前的部分,最后将需写入的数据写入。
      4. 依旧不可行,格式化能返回ok,但重启后出现无文件系统的错误,说明文件系统写入还是有问题。
  6. 解决问题5中文件无法正确保存的问题
    • 通过USB程序,将模块连到电脑上格式化。
      1. 用8k/扇区格式化,能格式化成功。但将格式化好的模块下载fatfs程序时,fatfs读取出现问题,因为fatfs最大支持的单扇区大小为4096字节。
      2. 用我的电脑4k/扇区格式化,一直格式化失败,串口打印出log发现写入都没有问题,写入后的读取却读不到有效内容。
      3. 在程序里面加上一段打印打码,执行对0扇区的写入后,打印写入到0扇区的内容,从而判断到底是什么导致了格式化失败。结果,加上这段代码后,格式化成功。
      4. 判断为需要在写入0扇区后延时一段时间再读取才能成功。加入延时函数后,格式化没有问题了。
    • 将格式化好的模块下载fatfs程序后,读取无问题,获取剩余空间大小也没有问题。但是,在f_open创建文件、f_write进行写入操作、f_close关闭文件后,下次用f_open打开这个文件(OPEN_EXISTING选项)时,依然返回找不到文件的错误。
    • 经过各种调试,发现在disk_write函数中,每次进出打断点,这样进行的f_write和f_close操作,能成功保存文件、修改页表,下次f_open能够读到这个文件。
    • 判断是延时问题,尝试在disk_write出口处加上100ms延时,问题解决。实验发现,延时最短到15ms的时候,可以正常保存文件。最终将延时设为20ms。
  7. 解决格式化失败的问题:
    • 既然无法保存的问题出自写入后的延时,那么之前的格式化之后文件无法保存的问题是否也出自这里?
    • 之前的判断认为是fatfs将页表存在末4个扇区内,所以导致文件无法保存的原因是只格式化了前面的数个扇区,没有成功格式化。现在认为这个判断是错误的。
    • 因为经过调试发现,前几个扇区都是用于存储fatfs相关内容的。之前以为是数据区的sz_fat,目前看来应该是fat文件页表;之前认为是文件页表的sz_dir,实际上是fat目录表。
    • 也就是说,fat16文件系统的结构是这样的:(参见https://blog.csdn.net/sikuon/article/details/75222224
      1. rsv:系统保留区(0扇区的DBR,可能存在的分区表,以及其他保留扇区),位于第0--x扇区。
      2. fat:文件页表区(有时会有FAT2作为FAT的备份),位于x+1--y扇区。
      3. dir:文件目录表区,位于y+1--z扇区
      4. data:数据区,位于z+1--末扇区
    • 那么,昨天遇到的情况,格式化只格了前几个扇区,是正确的操作。如此说来,GET_BLOCK_SIZE的功能的确如我所理解的那样,是扇区数量。block_size就是一次性擦除的扇区数量。
    • 如此,格式化的参数有两种选择:
      1. 根据昨天的经验,用f_mkfs("", FM_FAT, 0, work_buffer, FF_MAX_SS);这样的参数格式化,只能格式化为FAT12(或许应该再试试,因为最初用这种参数格式化时,用的BLOCK_SIZE是4096--与此无关,只要不是SFD格式,都会-63扇区作为起始扇区)。
      2. 根据昨天的经验,用f_mkfs("", FM_FAT+FM_SFD, 4096, work_buffer, FF_MAX_SS);这样的参数,能成功格式化为FAT16,但这是软盘格式,电脑上不一定可用。
      3. 最终试验发现第一种会格式化为FAT12,第二种可行。
  8. 在最开始遇到的一个问题,后来在另一个用到Fatfs的板子上又遇到了:
    1. 现象:开机f_getfree函数返回FR_NO_FILESYSTEM,进入格式化;f_mkfs函数返回FR_OK,格式化成功;下一步f_open函数又返回FR_NO_FILESYSTEM错误。
    2. 原因:SPIFlash虚焊。焊好后恢复正常。

stm32--FatFs调试过程(SPIFlash)的更多相关文章

  1. STM32的操作过程,寄存器配置与调试过程(转载)

    很多学习stm32的,为什么学习stm32他也不知道,我们所知道的就是各个论坛讨论stm32的很多,而我们很多人之所以学习stm32是很多的淘宝卖家做了大量的图片文字宣传,于是我们经不住诱惑就买了板子 ...

  2. 关于火狐浏览器在开发调试过程中,出现javascript:void(0)的状态

    关于火狐浏览器在开发调试过程中,出现javascript:void(0)的状态 由于火狐浏览器没有安装 Adobe Flash Player 19 NPAPI这个插件 安装好了之后就可以直接运行了

  3. S3C6410裸奔之旅——RVDS2.2编译、仿真、调试过程 LED流水灯---转的

    S3C6410裸奔之旅——RVDS2.2编译.仿真.调试过程 LED流水灯 (2012-10-13 23:56:30) 转载▼ 标签: s3c6410裸奔 ok6410 rvds2.2 rvds2.2 ...

  4. MYSQL存储过程调试过程

     mysql不像oracle有plsqldevelper工具用来调试存储过程,所以有几种简单的方式追踪执行过程: 1.用一张临时表,记录调试过程: 2.直接在存储过程中,增加select xxx,在控 ...

  5. Android APP 调试过程中遇到的问题。

    调试过过程中APP安装完启动后有的时候会异常退出,报这个错误.有的时候可以直接启动.查找不到原因.网上说把commit方法替换成commitAllowingStateLoss() 也无效. Andro ...

  6. 调试过程中发现按f5无法走进jdk源码

    debug 模式 ,在fis=new FileInputStream(file); 行打断点 调试过程中发现按f5无法走进jdk源码 package com.lzl.spring.test; impo ...

  7. 0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。

    arm调试过程,如果抛一个SIGSEGV,地址在 0xe7f001f0 附近,原因居然是因为我在调试.当我使用n指令跳到下一行代码时,往往变成了continue指令一样地执行.还不确定地抛出SIGSE ...

  8. VS·调试过程中某个操作导致调试突然退出之解决方案

    阅文时长 | 0.11分钟 字数统计 | 232字符 主要内容 | 1.引言&背景 2.声明与参考资料 『VS·调试过程中某个操作导致调试突然退出之解决方案』 编写人 | SCscHero 编 ...

  9. stm32调试过程中如何判断是程序问题还是硬件问题?

    可以用软件仿真,如果软件仿真时寄存器什么的都正确,而硬件在线仿真时不对,则说明是板子硬件的问题

随机推荐

  1. linux命令之添加删除磁盘分区

    之前已经写过df和fdisk的区别了,df可以显示当前已经挂载的磁盘分区,df -T可以额外显示文件系统类型 fdisk -l可以显示出所有挂载未挂载的分区,但不显示文件类型 在我的虚拟机上有一块分配 ...

  2. 03_P52 课后作业

    1. 软件开发的早期阶段为什么进行可行性研究?应该从哪些方面研究系统的可行性? 1.进行可行性研究是为了该软件项目是否值得开发?是否具有经济效益?是否违反法律道德?是否技术可以实现?是否风险性高? 2 ...

  3. Golang Failpoint 的设计与实现

    小结: 1. https://mp.weixin.qq.com/s/veIoupLjM4l5SUVC6h_Gkw Golang Failpoint 的设计与实现 原创: 龙恒 PingCAP 今天  

  4. HashMap面试知识点

    HashMap的工作原理是近年来常见的Java面试题. 几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如 ...

  5. Android学习笔记_46_fragment的简单应用

    Fragments 诞生初衷 http://www.cnblogs.com/TerryBlog/archive/2012/02/17/2355753.html 自从Android 3.0中引入frag ...

  6. Jquery Mobile 常用参数

    data-role  属性值: data-role参数表: page        页面容器,其内部的mobile元素将会继承这个容器上所设置的属性  header     页面标题容器,这个容器内部 ...

  7. android(eclipse)新手常见问题总结(一)

    1:jdk无法更新   进入工具里面手动获取镜像资源 并且改为强制 2:报错:This version of the rendering library is more recent than you ...

  8. Vue nodejs商城-地址模块

    一.地址列表渲染 ,则不可以点击. src/views/Cart.vue <a class="btn btn--red" v-bind:class="{'btn-- ...

  9. 轻量ORM-SqlRepoEx (五) 存储过程操作

    .Net平台下兼容.NET Standard 2.0,一个实现以Lambda表达式转转换标准SQL语句,使用强类型操作数据的轻量级ORM工具,在减少魔法字串同时,通过灵活的Lambda表达式组合,实现 ...

  10. Oracle 序列的创建删除插入

    今天学习的是序列的创建蟹盖和删除插入 创建: create Sequence Seq_name increment by n     ----序列变化的程度,默认为1,可以为负数表示递减 start ...