# STM32F4内部Flash模拟EEPROM:磨损均衡与掉电保护的工程实现 ## 1. 为什么需要模拟EEPROM? STM32F4系列内置Flash容量大(如F407有1MB),但擦写寿命有限(典型10K次/扇区)。当系统需要频繁保存配置参数(如校准值、运行状态)时,直接擦写Flash会迅速耗尽寿命。外部EEPROM(如AT24C02)虽可靠,但增加BOM成本和PCB面积。因此,在成本敏感或空间受限的场景,用内部Flash模拟EEPROM成为优选。 核心挑战: - **寿命限制**:Flash擦除次数远低于EEPROM(1M次)。 - **掉电风险**:写入过程中掉电可能导致数据损坏或半写状态。 - **擦除粒度**:Flash按扇区擦除(F4通常16KB/扇区),而写入可字节/半字/字。 ## 2. 硬件基础与关键特性 STM32F4的Flash控制器支持: - **编程**:以16位(半字)为单位写入,需先置位PG位。 - **擦除**:按扇区或整片擦除,需置位SER位并等待BSY位清零。 - **选项字节**:可配置读保护等,但模拟EEPROM时通常不用。 关键寄存器:`FLASH_CR`(控制)、`FLASH_SR`(状态)、`FLASH_ACR`(延迟)。 ## 3. 磨损均衡策略 ### 3.1 扇区划分与日志结构 将Flash划分为多个逻辑扇区(如4个物理扇区,每个16KB)。采用**日志结构**:数据以记录(Record)形式顺序写入当前活动扇区,每个记录包含: - **头部**:魔数(0xA5A5)、数据长度、CRC16校验。 - **数据**:用户参数(固定长度或变长)。 - **状态**:有效/无效标记。 当活动扇区写满时,触发**扇区切换**: 1. 选择下一个空闲扇区作为新活动区。 2. 将最新有效数据从旧扇区复制到新扇区。 3. 擦除旧扇区,并标记为待用。 ### 3.2 磨损均衡算法 采用**轮询+计数器**方式: - 维护一个全局擦写计数(存储于Flash首扇区)。 - 每次切换扇区时,递增计数并选择擦写次数最少的扇区作为新活动区。 - 若所有扇区擦写次数接近,则顺序轮询。 示例代码(简化): ```c #define SECTOR_NUM 4 #define SECTOR_SIZE 0x4000 // 16KB uint32_t erase_count[SECTOR_NUM]; uint32_t select_next_sector(uint32_t current) { uint32_t min_count = erase_count[(current+1)%SECTOR_NUM]; uint32_t next = (current+1)%SECTOR_NUM; for (int i=0; i SECTOR_SIZE) { switch_sector(); } // 构造头部 RecordHeader hdr = {0xA5A5, len, crc32(data, len)}; // 写入头部和数据(注意Flash写入需半字对齐) flash_write_halfword(active_sector*SECTOR_SIZE + write_offset, hdr.magic); flash_write_halfword(active_sector*SECTOR_SIZE + write_offset+2, hdr.len); flash_write_word(active_sector*SECTOR_SIZE + write_offset+4, hdr.crc); // 写入数据(按32位对齐) for (int i=0; i