2026/4/6 16:25:08
网站建设
项目流程
只做早餐的网站,开周边网站怎么做品牌,建设局全称是什么,网站设计技能SPI Flash扇区擦除操作#xff1a;从原理到实战的完整指南你有没有遇到过这样的情况#xff1f;在给设备做固件升级时#xff0c;新代码写进去却读不出来#xff1b;或者保存配置参数后重启#xff0c;发现数据“消失”了”。如果你用的是SPI Flash#xff0c;那问题很可…SPI Flash扇区擦除操作从原理到实战的完整指南你有没有遇到过这样的情况在给设备做固件升级时新代码写进去却读不出来或者保存配置参数后重启发现数据“消失”了”。如果你用的是SPI Flash那问题很可能出在——忘了先擦再写。这不是简单的疏忽而是对Flash存储器物理特性的误解。RAM可以随时覆盖写入但Flash不行。它像一块只能用橡皮擦干净后再写字的黑板想改内容先彻底擦掉旧字迹。本文将带你深入理解SPI Flash中最关键、也最容易踩坑的操作之一扇区擦除Sector Erase。我们将从底层机制讲起一步步拆解命令流程、状态控制和工程实践中的避坑策略让你不仅能“跑通”更能“搞懂”。为什么必须先擦除才能写要真正掌握扇区擦除首先要明白一个核心事实Flash只能将比特位从1变成0不能反过来。这意味着- 初始状态下所有存储单元都是0xFF全1- 写入数据时你可以把某些位清零比如写入0x5A- 但如果下次想恢复成0xFF普通的“写操作”无能为力唯一的办法就是执行擦除Erase通过内部高压电路释放浮栅晶体管中的电荷强制所有位回到高电平状态。换句话说写入 把需要的位设为0 擦除 把全部位重置为1所以在任何写入之前目标区域必须是“干净”的——即已被擦除为全0xFF状态。否则原本的0会阻碍新数据的正确写入。这也就是为什么很多开发者第一次操作Flash时会失败他们以为可以直接“修改”某个地址的数据结果却发现怎么都写不进去或数据错乱。扇区结构与擦除粒度你知道该擦多大吗不同大小的擦除单位适用于不同的场景。常见的SPI Flash如Winbond W25Q系列通常支持以下几种擦除方式擦除类型典型大小命令代码使用场景Page Program256字节—最小写入单位Sector Erase4KB0x20✅ 推荐常用Block Erase (32KB)32KB0x52大块清理Block Erase (64KB)64KB0xD8快速批量清除Chip Erase整片0x60/0xC7出厂初始化其中4KB扇区擦除是最实用的选择。原因如下太小→ 频繁调用影响性能太大→ 容易误伤无关数据4KB正好→ 匹配大多数文件系统块大小便于管理举个例子你想更新一段固件它刚好占用了两个完整的4KB扇区。这时候你就只需要分别擦除这两个扇区然后重新编程即可不会影响其他区域的数据。⚠️ 注意擦除是以扇区为单位进行的即使你只想改几个字节也得把整个4KB都擦掉扇区擦除是怎么工作的一步步看透指令流我们以最常见的W25Q64为例来看看一次标准的4KB扇区擦除是如何完成的。第一步发送“写使能”信号Write Enable这是最关键的前置步骤每次执行写或擦除前都必须先告诉Flash“我要开始写了”。spi_flash_write_enable();对应的SPI操作是- 拉低片选CS# → LOW- 发送命令0x06- 拉高片选CS# → HIGH这个动作会设置状态寄存器中的WEL位Write Enable Latch为1。如果跳过这步后续的擦除命令将被忽略。第二步发起扇区擦除命令接下来才是真正的擦除指令SPI_CS_LOW; spi_send_byte(0x20); // Sector Erase 命令 spi_send_byte((addr 16) 0xFF); // 地址高8位 spi_send_byte((addr 8) 0xFF); // 中间8位 spi_send_byte(addr 0xFF); // 低8位 SPI_CS_HIGH;注意- 地址必须是24位格式- 实际生效的扇区由地址所在的4KB边界决定即地址对齐到4096字节例如向地址0x0001_0100发起擦除实际上会影响整个0x0001_0000 ~ 0x0001_0FFF的扇区。第三步等待擦除完成擦除不是瞬间完成的典型4KB扇区需要30~40ms才能结束。在这期间Flash处于“忙”状态不能再接收其他命令。如何判断是否完成轮询状态寄存器uint8_t spi_flash_is_busy(void) { uint8_t status; SPI_CS_LOW; spi_send_byte(0x05); // Read Status Register status spi_receive_byte(); SPI_CS_HIGH; return (status 0x01); // BUSY位 bit[0] }只要BUSY 1就说明还在擦。你可以这样等待while (spi_flash_is_busy()) { // 可在此处喂狗、处理低优先级任务 } 提示有些高端Flash支持“擦除暂停”功能Erase Suspend允许你在长时间擦除过程中临时响应读请求适合实时性要求高的系统。关键寄存器详解读懂Flash的“心跳”SPI Flash的状态寄存器就像是它的“生命体征监测仪”里面藏着几个至关重要的标志位位号名称含义SR[0]BUSY1正在擦/写0空闲SR[1]WEL1已启用写操作由0x06置位SR[2:5]BP[0:3]块保护位防止误操作SR[7]QEQuad Enable启用四线模式这些位决定了你能做什么、不能做什么。比如如果你发现某个扇区无论如何都无法擦除很可能是BP位被设置了写保护。这时你需要先清除保护// 清除块保护需先write enable spi_flash_write_enable(); SPI_CS_LOW; spi_send_byte(0x01); // Write Status Register spi_send_byte(0x00); // 设置SR0x00关闭保护 SPI_CS_HIGH;当然这样做有风险——万一不小心擦了Bootloader怎么办所以在实际项目中建议只在调试阶段开放全局解锁正式版本应固定保护关键区域。安全擦除封装别让一次失误毁掉整台设备直接裸奔调用擦除函数太危险了。我们应该把它包装成更健壮的形式。int flash_safe_erase_sector(uint32_t addr) { // 1. 检查地址合法性 if (addr FLASH_CAPACITY || addr % SECTOR_SIZE ! 0) { return -1; // 地址越界或未对齐 } // 2. 检查是否属于受保护区域如Bootloader区 if (addr BOOT_START_ADDR addr BOOT_END_ADDR) { return -2; // 禁止擦除引导区 } // 3. 启用写操作 spi_flash_write_enable(); // 4. 执行擦除 SPI_CS_LOW; spi_send_byte(0x20); spi_send_byte((addr 16) 0xFF); spi_send_byte((addr 8) 0xFF); spi_send_byte(addr 0xFF); SPI_CS_HIGH; // 5. 等待完成带超时机制 uint32_t start_time get_tick_ms(); while (spi_flash_is_busy()) { if (get_tick_ms() - start_time 50) { // 超过50ms视为失败 return -3; } feed_watchdog(); // 防止看门狗复位 } return 0; // 成功 }这个函数加入了三大防护- 地址合法性检查- 区域保护判断- 超时检测 看门狗喂狗这才是工业级代码应有的样子。实战应用场景OTA升级中的擦除逻辑假设你要实现一个FOTA空中升级功能流程大致如下1. 下载新固件 → 存入临时缓冲区如SRAM或另一块Flash分区 2. 定位旧固件所在扇区范围 3. 逐一擦除目标扇区 4. 分页写入新固件Page Program 5. 校验CRC 6. 更新启动标志下次启动加载新固件在这个过程中扇区擦除是不可逆的关键节点。一旦开始擦除旧固件就没了。如果后续断电或传输中断设备可能变砖。因此成熟的做法是采用双区备份机制A/B更新当前运行A区新固件写入B区擦除B区前无需担心破坏当前系统写完并校验成功后切换启动指针这样即使失败也能自动回滚极大提升可靠性。常见错误排查清单现象可能原因解决方案擦完读出来不是0xFF擦除未完成就读取加入状态轮询等待擦除命令无效忘记发Write Enable每次擦前加0x06特定扇区无法擦除BP位开启保护检查状态寄存器设置MCU死机擦除耗时导致看门狗超时循环中喂狗数据混乱多任务并发访问使用互斥锁保护Flash操作还有一个隐藏陷阱电源不稳定。擦除需要较高的内部电压约12V由芯片内部电荷泵生成。若供电不足2.7V可能导致擦除失败甚至扇区损坏。建议- 使用LDO稳压- 添加去耦电容0.1μF 10μF组合- 对关键应用考虑加备用电源或超级电容工程最佳实践不只是“能用”更要“可靠”避免热点磨损不要总往同一个扇区写数据。使用磨损均衡算法分散写入位置延长Flash寿命标称约10万次擦写。合理划分存储区域- 固件区静态极少更新- 参数区中频更新- 日志区高频写入可用循环日志设计启用硬件写保护引脚WP#将WP引脚连接到MCU GPIO在非更新时段拉低锁定防止程序跑飞误操作。引入日志追踪机制在独立扇区记录操作日志如“XX时间擦除YY地址”有助于故障分析。增加冗余与校验- 写后立即读回比对- 关键数据做双份存储 CRC校验考虑使用轻量文件系统如 LittleFS 或 SPIFFS它们内置了坏块管理、磨损均衡等特性省心又安全。结语把每一次擦除当作“手术”来对待SPI Flash的扇区擦除看似简单实则暗藏玄机。它不像内存操作那样宽容一旦出错轻则数据丢失重则设备瘫痪。所以请记住-每一次擦除都是不可逆的操作-必须确认地址、权限、状态三者无误-要用防御性编程思维构建Flash管理层当你能把每一个细节都掌控到位你会发现这块小小的串行闪存其实蕴藏着嵌入式系统中最深刻的工程哲学尊重硬件限制方能驾驭自由。如果你正在开发涉及固件更新、参数存储或日志记录的功能不妨停下来检查一下你的擦除逻辑——它真的足够健壮吗欢迎在评论区分享你的经验或困惑我们一起探讨如何写出更可靠的Flash驱动代码。