1. 物理原理:浮栅晶体管
EEPROM(和Flash)的基本存储单元是浮栅晶体管:
text
控制栅(CG) ──┐
│
┌▼┐
┌┴─┴┐
│氧化│← 浮栅(FG) - 存储电子
└┬─┬┘
│
┌▼┐ 漏极(D)
源极(S) ─────►│ │◄──────
└─┘
三种状态操作:
| 操作 | 原理 | 电子流向 |
|---|---|---|
| 擦除(Erase) | 高电压到源极 | 电子流出 浮栅 → 逻辑1 |
| 写入(Program) | 高电压到控制栅 | 电子注入 浮栅 → 逻辑0 |
| 读取(Read) | 正常电压 | 检测浮栅是否有电子 |
2. 为什么必须先擦除?
2.1 物理限制:只能从1变0,不能从0变1
c
// 物理上的位操作:
位状态 = 1 // 擦除后:浮栅无电子
位状态 = 0 // 写入后:浮栅有电子
// 关键限制:
// 0 → 1 ? 不可能!无法单独移除电子
// 只有擦除操作能批量移除电子(1 ← 0)
2.2 电路原理:
-
写入(0):给控制栅加高压,电子通过隧道效应注入浮栅
-
擦除(1):给源极加高压,电子通过隧道效应流出浮栅
-
不能部分擦除:高压是施加到整个扇区的,无法选择单个位
3. 实际操作示例
情况1:新写入数据(正确流程)
c
// 初始状态:扇区已擦除,所有位=0xFF (11111111b)
// 地址0x08E00000: 0xFF 0xFF 0xFF 0xFF ...
// 1. 先擦除(必须!)
擦除扇区(); // 所有位变为1
// 2. 写入数据
写入(0x08E00000, 0x55); // 01010101b
// 物理过程:1→0(允许),0→1(不允许但不需要)
// 结果:0x55 写入成功
情况2:不擦除直接写入(会出错)
c
// 假设当前内容:0xAA (10101010b)
// 目标写入:0x55 (01010101b)
// 错误做法:不擦除直接写
写入(0x08E00000, 0x55);
// 物理结果:
// 原来是0的位(1→0) → 保持0 ✓
// 原来是1的位(0→1) → 无法变为1! ✗
// 最终结果:0x00 (00000000b) 而不是0x55!
位级演示:
text
原始: 1 0 1 0 1 0 1 0 (0xAA)
写入: 0 1 0 1 0 1 0 1 (0x55)
结果: 0 0 0 0 0 0 0 0 (0x00) ← 错误!
4. 赛元SC32F12TK7的具体实现
4.1 最小擦除单位:扇区
SC32F12TK7的EEPROM结构:
-
扇区大小:1KB (1024字节)
-
擦除粒度 :整个扇区一起擦除
-
写入粒度:可以单字节写入
4.2 完整写入流程
c
// 需求:修改EEPROM中第10个字节(从0x08E00009)
// 步骤1:读取整个扇区到RAM缓存
uint8_t sector_buffer[1024];
memcpy(sector_buffer, (void*)0x08E00000, 1024);
// 步骤2:在RAM中修改数据
sector_buffer[9] = 新数据; // 修改第10字节
// 步骤3:擦除整个扇区
擦除扇区(0x69000000);
// 步骤4:将整个缓冲区写回
for(int i = 0; i < 1024; i++) {
写入(0x08E00000 + i, sector_buffer[i]);
}
5. 为什么设计成这样?(工程考量)
优点:
-
高密度:一个晶体管存1位,成本低
-
非易失:断电数据保存10年以上
-
可擦写:通常10万次以上(EEPROM)
缺点(必须接受的):
-
不能位寻址:只能批量擦除
-
速度慢:擦除需要几毫秒
-
寿命有限:擦写次数限制
6. 与其他存储器的对比
| 存储器类型 | 擦除需求 | 擦除单位 | 特点 |
|---|---|---|---|
| EEPROM | 必须 | 扇区(1KB) | 字节写入,寿命长 |
| Flash | 必须 | 页/块(4KB+) | 速度快,密度高 |
| FRAM | 不需要 | 无 | 无限次擦写,速度快 |
| EEPROM模拟 | 需要 | Flash块 | 用Flash模拟EEPROM |
7. 最佳实践建议
7.1 数据管理策略
c
// 方案1:日志式存储(避免频繁擦除)
struct {
uint16_t index; // 递增索引
uint8_t data[32]; // 实际数据
} log_entry;
// 每次写入新日志,索引递增
// 扇区满后才擦除
// 方案2:数据轮换
uint8_t active_sector = 0; // 当前活动扇区
// 一个扇区写满后切换到下一个
7.2 减少擦除次数的技巧
-
批量写入:收集足够数据后一次性写入
-
数据压缩:减少存储空间需求
-
使用RAM缓存:频繁修改的数据先放RAM
-
磨损均衡:轮流使用不同扇区
8.写之前的擦除要遵循的原则:
扇区擦除的原则,以3个扇区每个扇区512个字节,每次写入32个字节(子扇区32个字节)为例:
①要保证当前写的是空的子扇区。( 这一条可以删除,跟下面一条找有效地址相辅相成,如果找到了有效地址说明要写的区域就是空的)。
②要保证有空的地址区域(子扇区)便于上电恢复时"找有效地址函数"能找到要写有效地址(就是能找到空地址(空的子扇区)进行写操作,可以在每次写的时候执行判断决定是否执行擦除操作,确保下一次要写的区域是空的)。
保证了这一条其实就保证了第①条写入的区域是经过擦除的区域( 如果找到了有效地址说明要写的区域就是空的**,默认第一次写之前所有扇区是空的擦除过的(配置字设置))。**
可以每次写的时候:
如果要写的是扇区起始子扇区,擦除当前整个扇区
如果要写的是扇区最后一个子扇区,擦除下一个扇区
注:通常要配合配置字来控制,也就是第一次上电里面都是空的,有些找有效地址函数前提是没写过的时候是空的(擦除状态).
9. 常见错误及避免
c
// ❌ 错误:局部更新不擦除
*(uint8_t*)0x08E00000 = 0x11; // 第一次:OK
*(uint8_t*)0x08E00000 = 0x22; // 第二次:失败!需要先擦除
// ✅ 正确:读写-修改-写回
// 1. 读整个扇区到RAM
// 2. 在RAM中修改
// 3. 擦除扇区
// 4. 写回整个扇区
总结:
-
物理限制:浮栅晶体管只能从1→0,不能0→1
-
擦除是唯一将0变1的方法:通过高压移除电子
-
最小擦除单位是扇区:无法单独擦除某个字节
-
必须按"读取-修改-擦除-写入"流程操作
-
设计应用时要考虑EEPROM特性:减少擦写次数,延长寿命
这种"先擦后写"的特性是所有基于浮栅晶体管的非易失存储器的共同特点,理解这一点对嵌入式存储设计至关重要。
以上部分内容总结自deepseek