1. STM32H7 Flash擦除后数据读取异常现象解析最近在调试STM32H7系列芯片时遇到了一个奇怪的问题调用HAL_FLASHEx_Erase函数擦除Flash扇区后返回值显示擦除成功但后续读取该地址时数据竟然没有变成预期的0xFFFFFFFF。这个问题困扰了我整整两天直到发现是缓存机制在作怪。具体现象是这样的开发人员按照常规流程调用擦除函数程序逻辑判断某个扇区需要擦除时会执行以下操作配置擦除参数扇区号、电压范围等调用HAL_FLASHEx_Erase执行擦除等待操作完成再次读取该地址验证是否擦除成功但诡异的是有时候读取到的数据还是擦除前的旧数据就像擦除操作根本没执行一样。更让人抓狂的是这个问题不是每次都会出现而是偶发性的给调试带来了很大困难。2. 问题根源缓存一致性机制2.1 STM32H7的缓存架构STM32H7作为Cortex-M7内核的高性能MCU配备了数据缓存(D-Cache)和指令缓存(I-Cache)。缓存的存在大大提升了CPU访问内存的效率但也带来了数据一致性的挑战。当CPU读取Flash数据时会先将数据加载到D-Cache中。后续的读取操作如果命中缓存就会直接从缓存获取数据而不会真正访问Flash。这种机制在大多数情况下都能提升性能但在Flash内容被修改时就会出问题。2.2 缓存导致的问题场景在Flash擦除场景下典型的问题流程是这样的程序第一次读取Flash地址A数据被加载到D-Cache执行擦除操作实际Flash内容已被清除程序再次读取地址ACPU直接从D-Cache获取数据结果读取到的是擦除前的旧数据而非Flash中实际的0xFFFFFFFF这个问题不仅会影响数据读取如果擦除后立即执行该区域的代码由于I-Cache的存在CPU可能会执行缓存中的旧指令导致程序行为异常。3. 解决方案与代码实现3.1 基础解决方案手动维护缓存一致性最简单的解决方法是在每次Flash操作后手动清理和无效化缓存if (HAL_FLASHEx_Erase(FlashEraseInit, SectorError) ! HAL_OK) { break; /* 发生错误了 */ } /* 关键操作维护缓存一致性 */ SCB_CleanInvalidateDCache(); // 清理并无效化数据缓存 SCB_InvalidateICache(); // 无效化指令缓存这两个函数的作用是SCB_CleanInvalidateDCache将D-Cache中已修改的数据写回内存然后使整个D-Cache失效SCB_InvalidateICache使I-Cache中的所有内容失效3.2 更彻底的解决方案操作期间禁用缓存对于可靠性要求更高的场景可以在Flash操作期间完全禁用缓存/* 禁用缓存 */ SCB_DisableICache(); SCB_DisableDCache(); /* 执行Flash操作 */ if (HAL_FLASHEx_Erase(FlashEraseInit, SectorError) ! HAL_OK) { /* 错误处理 */ } /* 重新启用缓存 */ SCB_EnableICache(); SCB# 1. 题目 #### [93. 复原 IP 地址](https://leetcode-cn.com/problems/restore-ip-addresses/) 难度中等857 **有效 IP 地址** 正好由四个整数每个整数位于 0 到 255 之间组成且不能含有前导 0整数之间用 . 分隔。 - 例如0.1.2.201 和 192.168.1.1 是 **有效** IP 地址但是 0.011.255.245、192.168.1.312 和 192.1681.1 是 **无效** IP 地址。 给定一个只包含数字的字符串 s 用以表示一个 IP 地址返回所有可能的**有效 IP 地址**这些地址可以通过在 s 中插入 . 来形成。你 **不能** 重新排序或删除 s 中的任何数字。你可以按 **任何** 顺序返回答案。 **示例 1**输入s 25525511135 输出[255.255.11.135,255.255.111.35]**示例 2**输入s 0000 输出[0.0.0.0]**示例 3**输入s 101023 输出[1.0.10.23,1.0.102.3,10.1.0.23,10.10.2.3,101.0.2.3]**提示** - 1 s.length 20 - s 仅由数字组成 # 2. 题解 # 3. code c class Solution { public: vectorstring ans; bool isValid(const string s, int start, int end) { if (start end) { return false; } if (s[start] 0 start ! end) { return false; } int num 0; for (int i start; i end; i) { if (s[i] 9 || s[i] 0) { return false; } num num * 10 (s[i] - 0); if (num 255) { return false; } } return true; } void backtracking(string s, int startIdx, int pointNum) { if (pointNum 3) { if (isValid(s, startIdx, s.size() - 1)) { ans.push_back(s); } return; } for (int i startIdx; i s.size(); i) { if (isValid(s, startIdx, i)) { s.insert(s.begin() i 1, .); pointNum; backtracking(s, i 2, pointNum); pointNum--; s.erase(s.begin() i 1); } else { break; } } return; } vectorstring restoreIpAddresses(string s) { backtracking(s, 0, 0); return ans; } };4. 心得回溯法注意终止条件。