NOR FLASH
一、NOR FLASH 基础介绍
NOR FLASH 是掉电非易失性存储芯片,核心特点是支持 “片内执行(Execute On Chip)”,程序无需复制到 RAM 即可直接运行,常作为嵌入式系统的启动介质,与 NAND FLASH 形成关键差异。
1. 核心特性
- 读写特性:读取方式与 RAM 类似(按地址直接取数),但不能直接写操作,写前必须先擦除;擦除会将目标区域统一置为
0xFF
,因为 NOR FLASH 的 BIT 只能从 “1” 改为 “0”,无法从 “0” 改 “1”。 - 访问单元:分 8 位和 16 位模式,部分芯片支持双模(通过管脚选择):
- 8 位模式:1 个地址对应 1 字节(8BIT)数据,需 8 条数据线(D7-D0),地址线数量按容量匹配(如 4 字节容量需 2 条地址线 A1-A0)。
- 16 位模式:1 个地址对应 1 半字(16BIT)数据,需 16 条数据线(D15-D0),地址线数量更少(如 4 字节容量仅需 1 条地址线 A0)。
- 存储结构:按 “扇区(SECTOR)” 划分,大容量芯片还会分 “Bank”,擦除操作只能以 “扇区、Bank 或整片” 为单位,无法单个字节擦除。
- 其他限制:无本地坏区管理,坏区需软件 / 驱动处理;写入速度比 NAND FLASH 慢,需通过 CFI(通用闪存接口)获取指令清单执行操作。
二、ARM 处理器下的 NOR FLASH 烧写方式
以 ARM 处理器为核心,重点讲解 “硬件连接逻辑” 和 “8/16 位芯片的具体烧写代码”,前提是 ARM 处理器默认 1 个地址对应 1 字节数据。
1. 硬件连接:关键解决 “地址对齐” 问题
ARM 与 NOR FLASH 的连接差异,本质是 “ARM 的 1 字节地址” 与 “NOR FLASH 的 8/16 位地址” 不匹配,需通过地址线调整适配:
- 8 位 NOR FLASH 连接:地址线、数据线均 “一一对应”。例如 ARM 的 A0-An 接 FLASH 的 A0-An,ARM 的 D0-D7 接 FLASH 的 D0-D7,无需额外处理。
- 16 位 NOR FLASH 连接:地址线需 “错位连接”,数据线仍一一对应:
- 数据线:ARM 的 D0-D15 接 FLASH 的 D0-D15。
- 地址线:ARM 的 A0 悬空,A1 接 FLASH 的 A0,A2 接 FLASH 的 A1,以此类推(屏蔽 ARM 地址最低位,匹配 FLASH 的 16 位地址)。
- 补充说明:部分 ARM 处理器支持 “软件地址错位”,可通过寄存器设置替代硬件错位,具体需参考 MCU 手册;同时需在 ARM 内部配置 FLASH 位宽(8/16/32 位),确保数据读取正确。
2. 烧写核心逻辑
所有烧写操作(擦除、编程)均需按 “固定命令序列” 执行,不同位宽芯片的命令地址、数据长度不同,以下为具体实例:
(1)8 位 NOR FLASH 实例:HY29F040
HY29F040 容量 512KB,含 8 个扇区(每个 64KB),支持整片擦除、扇区擦除和字节编程,需定义字节操作指针:
U32 sysbase; // FLASH起始地址
#define SysAddr8(sysbase, offset) ((volatile U8*)(sysbase)+(offset)) // 字节地址指针
-
整片擦除(6 步命令):
*SysAddr8(sysbase, 0x5555) = 0xAA
*SysAddr8(sysbase, 0x2AAA) = 0x55
*SysAddr8(sysbase, 0x5555) = 0x80
*SysAddr8(sysbase, 0x5555) = 0xAA
*SysAddr8(sysbase, 0x2AAA) = 0x55
*SysAddr8(sysbase, 0x5555) = 0x10
-
扇区擦除(6 步命令):前 5 步与整片擦除一致,第 6 步将命令写至目标扇区地址:6.
*SysAddr8(sysbase, 目标扇区地址) = 0x30
-
字节编程(4 步命令):
*SysAddr8(sysbase, 0x5555) = 0xAA
*SysAddr8(sysbase, 0x2AAA) = 0x55
*SysAddr8(sysbase, 0x5555) = 0xA0
*SysAddr8(sysbase, 目标字节地址) = 待写数据
(2)16 位 NOR FLASH 实例:SST39VF160
SST39VF160 容量 2MB,含 512 个扇区(每个 4KB),支持整片擦除、扇区擦除和半字编程,需定义半字操作指针(地址偏移需右移 1 位,将 ARM 的字节地址转为 FLASH 的半字地址):
U32 sysbase; // FLASH起始地址
#define SysAddr16(sysbase, offset) ((volatile U16*)(sysbase)+(offset)) // 半字地址指针(1个offset对应2字节)
-
整片擦除(6 步命令):命令为 16 位数据,地址为 FLASH 的半字地址:
*SysAddr16(sysbase, 0x5555) = 0x00AA
*SysAddr16(sysbase, 0x2AAA) = 0x0055
*SysAddr16(sysbase, 0x5555) = 0x0080
*SysAddr16(sysbase, 0x5555) = 0x00AA
*SysAddr16(sysbase, 0x2AAA) = 0x0055
*SysAddr16(sysbase, 0x5555) = 0x0010
-
扇区擦除(6 步命令):前 5 步与整片擦除一致,第 6 步需将 ARM 字节地址右移 1 位,转为 FLASH 半字地址:6.
*SysAddr16(sysbase, 目标扇区字节地址 >> 1) = 0x0030
-
半字编程(4 步命令):第 4 步需将 ARM 字节地址右移 1 位,匹配 FLASH 半字地址:
*SysAddr16(sysbase, 0x5555) = 0x00AA
*SysAddr16(sysbase, 0x2AAA) = 0x0055
*SysAddr16(sysbase, 0x5555) = 0x00A0
*SysAddr16(sysbase, 目标字节地址 >> 1) = 待写半字数据
三、NOR Flash为什么要先擦后写
1. 核心原因:NOR Flash 的 “0” 和 “1” 无法直接翻转
NOR Flash 存储数据的最小单元是浮栅晶体管,数据 “0” 和 “1” 的表示依赖浮栅中是否存储电荷,且两者的翻转规则完全不同。
- 写 “1”:可以直接操作。通过施加电压,将浮栅中的电荷 “抽走”,对应数据 “1”,此过程不依赖之前的状态。
- 写 “0”:必须先擦除。要写入 “0”,需要先将浮栅 “清空”(即擦除,此时所有单元会被统一置为 “1”),再通过电压向浮栅注入电荷,才能对应数据 “0”。
- 关键矛盾:如果不擦除,存储单元可能还残留 “0” 状态(浮栅有电荷),此时直接强行注入电荷会导致电压过载,击穿晶体管的绝缘层,造成永久损坏。
2. 底层限制:擦除和写入的 “粒度” 不匹配
NOR Flash 的擦除和写入操作,在 “操作范围” 上存在根本差异,决定了必须先执行擦除。
- 擦除操作:按 “块(Block)” 执行。一次必须擦除一整个块(通常大小为 64KB 或 128KB),无法单独擦除一个字节或一个位。
- 写入操作:按 “字节(Byte)” 或 “半字” 执行。可以对单个字节进行写入,但前提是这个字节所在的块已经被擦除(所有单元为 “1”)。
- 逻辑冲突:如果不先擦除块,块内部分单元是 “0”,部分是 “1”,此时写入新数据会导致 “0” 状态单元被强行叠加写入,直接触发硬件保护或损坏。
3. 硬件保护:避免错误操作
现代 NOR Flash 芯片都内置了硬件保护机制,进一步强化了 “先擦后写” 的规则。
- 当检测到 “未擦除直接写” 的操作时,芯片会触发保护逻辑,可能直接拒绝写入并返回错误信号。
- 若保护机制失效或操作电压异常,强行写入会导致浮栅晶体管的绝缘层永久性击穿,芯片直接 “挂掉”,无法再存储数据。
参考链接:http://wiki.dzsc.com/info/5353.html#top