stm32--FatFs调试过程(SPIFlash)

时间:2022-06-30 01:25:21

移植方法参见我的另一篇博客:《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个扇区了;之后由stm32--FatFs调试过程(SPIFlash)这段代码,sz_vol为4033,pau为1,得出n_clst为4033<4085(MAX_FAT12),于是设为FAT12格式
    • 如果输入参数为FAT+SFD,sz_vol值为4096,之后由stm32--FatFs调试过程(SPIFlash)
    • 输入参数FAT+SFD,并在输入参数中强制pau为1,倒是不会置为FAT12格式,但是格式化返回FR_MKFS_ABORTED错误。查找错误原因,发现问题来自stm32--FatFs调试过程(SPIFlash)
  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&colon;void&lpar;0&rpar;的状态

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

  3. S3C6410裸奔之旅——RVDS2&period;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&&num;183&semi;调试过程中某个操作导致调试突然退出之解决方案

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

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

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

随机推荐

  1. socket阻塞与非阻塞,同步与异步

    socket阻塞与非阻塞,同步与异步 作者:huangguisu 转自:http://blog.csdn.net/hguisu/article/details/7453390 1. 概念理解 在进行网 ...

  2. javaWeb开发小工具---MailUtils及其单元测试

    本次介绍的是,在javaWeb开发中,我们不免会遇到发送邮件的需求,比如:用户注册账号,需要激活登录,以及服务器定期向会员发送礼品信息等.所以参考有关资料,写了这个MailUtils工具类. 1.Ma ...

  3. 使用Python对Excel表格进行简单的读写操作(xlrd&sol;xlwt)

    算是一个小技巧吧,只是进行一些简单的读写操作.让人不爽的是xlrd和xlwt是相对独立的,两个模块的对象不能通用,读写无法连贯操作,只能单独读.单独写,尚不知道如何解决. #①xlrd(读) #cod ...

  4. ionic获取焦点

    功能需求:点击按钮后获取input输入框的焦点 获取焦点用jq focus()不成功,因为angular也不推荐,所以网上找了一个在focus封装成指令的方法 指令写法: .directive('my ...

  5. phpMyAdmin安装设置

    phpMyAdmin是一种MySQL的管理工具,它直接从web上去管理MySQL.   假设你的web(网页存放)根目录是 /var/www/ 假设你的主机web访问是这样的 http://192.1 ...

  6. warshall、

    #include<iostream> int mian() { ][],b[][],c[][]; int i,j,k; cout<<"input the Boolea ...

  7. &ast;&ast;&ast;阿里云ECS实战配置虚拟主机 &plus; Apache 配置虚拟主机三种方式

    阿里云ECS实战配置虚拟主机 买了一台ECS阿里云服务器,性能感觉有点富余,想着可以陪着虚拟主机多一些WWW目录好放一些其他的程序.比如DEMO什么的. 今天研究了下,主要是就是做基于不同域名的虚拟主 ...

  8. ios 设置本地化显示的app名称

    内容的本地化这里不做介绍! 名称的本地化: 1.新建一个 Strings File文件,命名为InfoPlist,注意这里一定要命名为InfoPlist! 2.设置本地化信息:选择需要的语言! 3.填 ...

  9. tomcat,很多时候,可以在服务server&period;xml中可以实现一些效果

    一.--日志 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="log ...

  10. Leetcode&colon; Construct Binary Tree from Preorder and Inorder Transversal

    Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that ...