尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32H55 Flash无写入计数器?四种方案帮你精确统计写入字节数

STM32H55 Flash无写入计数器?四种方案帮你精确统计写入字节数 很多刚上手 STM32H55 的朋友都会遇到一个让我特别有共鸣的问题“我在 Flash 里写了一批数据过了几天想确认到底写了多少字节能不能从某个内存地址或者寄存器里直接读出来” 我最初也抱着类似的期待去翻参考手册结果翻完整个 Flash 控制器章节之后发现H55 的 Flash 外设根本没有设计这种“写入字节计数器”。它不像某些外部 SPI Flash 或者 SD 卡那样在内部维护一份磨损统计或者已写容量内部 Flash 控制器只管编程、擦除、校验和保护。所以如果你想确认“从开始到现在一共写了多少字节”思路要转变一下不是去查寄存器而是根据你当前写入的数据状态去反推或者在驱动层提前埋一个计数器。这篇文章会把几种可行方案、实际代码、以及我在 H55 上调试时踩过的坑一次讲清楚。1. 先给结论H55 的 Flash 外设没有“已写入字节数”寄存器1.1 Flash 控制器到底管什么在 STM32H55 这种现代 MCU 上内部 Flash 并不是像内存条一样由 CPU 直接操作。CPU 通过 Flash 控制器对 Flash 阵列发起请求控制器内部有一套状态机负责把“用户要写一个字节/字/双字”这个请求翻译成芯片内部的时序信号。同时它还要管扇区擦除、整片擦除、写保护、读保护、选项字节以及一些错误的捕获。从这个定位就能看出来Flash 控制器更像是一个“管理员”它知道现在有没有操作正在进行BSY 忙标志、这次操作是否出错错误标志、你要擦除哪个扇区SNB 扇区编号、写保护有没有拦住你WRPERR。它不会替你统计某个地址范围内有多少个字节已经被写过。计数这件事在芯片设计者眼中不是 Flash 控制器的职责。你写多少数据、往哪儿写、写到什么程度这些信息应该在你的应用层逻辑里。所以想直接读一个寄存器然后就得到“已写入 3456 字节”在 H55 上是不存在的。类似的思路在外部串行 Flash 上也不成立——除非你用到的是带状态寄存器且厂商定义了相关统计项的专用器件STM32 内部 Flash 不提供这种能力。1.2 能从寄存器里拿到的信息只有这几种虽然拿不到直接的字节计数但 H55 的 Flash 寄存器也不是完全没用。下面这张表是我在调试时常用的能从中读到的信息类别大致如下信息来源能告诉你什么不能告诉你什么FLASH_SR 状态寄存器当前 Flash 是否忙、有没有编程/擦除错误、操作是否结束不包含已写字节数FLASH_CR 控制寄存器最近一次命令是什么、准备擦除哪个扇区、是否开启保护不会告诉你实际地址范围有多大选项字节 (OPTSR)当前 RDP 读保护级别、写保护扇区范围不包含历史写入统计Flash 内存映射哪些地址是合法内部 Flash、总容量多大哪里被写过、当前写到哪无从判断也就是说状态寄存器只能回答“操作是否成功”和“当前忙不忙”并不能回答“累计写了多少”。内存映射只能告诉你这个芯片内部 Flash 的总容量比如 1MB、2MB但它不维护“已用容量”这个概念。这和硬盘不一样——内部 Flash 没有分区表那样的元数据除非你自己创建了一套记录结构。1.3 为什么没有计数寄存器Flash 编程模型的设计逻辑站在芯片设计者的角度想一下给 Flash 控制器加一个“已写字节数寄存器”到底有没有必要内部 Flash 的本职工作是把你的程序代码和关键数据存下来。一个嵌入式产品的代码量在开发阶段容易被反复擦写但到了量产阶段一次固件下载之后基本上就不变了。真正频繁写的场景通常集中在日志、参数、OTA 备份这一类数据上。对于这类场景硬件给你的位宽足够宽容量也足够大但空间管理、磨损控制、写入统计都是软件层面的设计决策。例如一个参数存储系统完全可以做成“每次写新参数都换个地址”从而避免反复擦同一块区域。这时候“一共写了多少字节”到底是指累计写入字节、当前有效字节还是某个扇区的擦除次数硬件无法替你做语义判断因此干脆不提供这个统计功能。所以你如果在网上搜“STM32H55 Flash 写入字节数”能看到的大多数答案都会指向同一个方向程序自己记得或者通过状态反推。接下来我就按“不改变现有工程”和“改变现有工程”两种情况把方案展开说。2. 从现状反推三种不需要改代码的检查思路如果你现在手里已经有一块跑着程序的 H55 开发板不想改代码、不想重新烧录只是想知道某个数据区到底写了多少字节完全可以靠“反推”得到结果。前提是你得理解内部 Flash 擦除后的状态是 0xFF也就是每一位都是 1。只要你用编程操作写过某个地址这个地址上的内容就不再是 0xFF但要注意写入的数据本身可能包含 0xFF这个情况我后面会讲。2.1 方案一扫描 Flash 里的有效数据区在已知数据区采用“连续顺序写入”、剩余空间保持擦除态的前提下你可以从数据区末尾往回扫描找到最后一个不是 0xFF 的字节这个位置之后的区域就可以认为是未写入的空区。从区域起始地址到最后一个有效字节之间的距离近似就是已经写入的字节数。这种做法非常适合调试用。比如你的产品把校准参数存在 0x080E0000 开始的扇区写完后剩余区域从没动过那么扫描这段地址就能很快看出写入范围。实际做的时候要注意两点一是扫描要按字/半字/字节对齐访问不要在非对齐地址上读H55 的存储总线和某些外设缓冲对非对齐访问有额外限制二是如果数据里本身有 0xFF扫描结果会偏大。对二进制串行化数据来说0xFF 出现概率不低所以这个方法适合“粗略定位”而不是精确计数。2.2 方案二导出 Flash 镜像离线用脚本分析不想在目标板上写代码的话更省事的办法是直接把整个 Flash 导出来分析。用 STM32CubeProgrammer 连接 H55选择对应地址范围读取并保存为 bin 文件然后在 PC 上用一段简单 Python 脚本处理。import sys def find_last_written(filename): with open(filename, rb) as f: data f.read() last len(data) - 1 while last 0 and data[last] 0xFF: last - 1 if last 0: return 0 return last 1 if __name__ __main__: print(有效数据末尾偏移:, find_last_written(sys.argv[1]))这段脚本的逻辑和板端扫描完全一致从文件尾部往开头找直到遇到第一个非 0xFF 字节。它的好处是不会占用目标系统资源尤其适合在故障现场把 Flash 抓下来慢慢分析。缺点同样是会被数据里的 0xFF 干扰并且如果你导出的范围是从 0x08000000 开始的整个 Flash那固件代码也被算进去了。所以导出时最好精确选中要分析的数据区或者先把 Flash 分成固件区和数据区分别导。2.3 方案三从现有工程的长度字段或文件系统里找如果你的工程已经做得比较规范在数据区前面写了一个记录头里面存放 magic、数据长度和 CRC那么根本不需要扫描直接读记录头里的长度字段就行。OTA 固件尤其常见这种做法引导程序拿到镜像后先读头部里声明的大小再决定搬运多少字节。类似地如果你在 Flash 上跑了 LittleFS、FatFs 这类文件系统那么“已用字节数”通常可以从文件系统的元数据里拿到。LittleFS 的超级块中保存了块大小和块总数目录项的链上记录着文件大小FatFs 则可以通过分析 FAT 表统计已占用簇数。只不过这些字段被文件系统驱动封装起来了通常需要调用驱动提供的状态接口而不是直接读一个全局变量。2
返回列表