Flash存储器作为嵌入式系统的非易失性存储介质,其编程原理与传统RAM有本质区别。理解这些特性是进行可靠编程的前提。
Flash存储器的两个基本操作单元:
典型时序特性(以Intel DT28F320为例):
code复制擦除时间:约1秒/块
编程时间:约10μs/字
耐久性:约100,000次擦写周期
c复制// 典型Flash操作伪代码
FLASH_Erase(0x24000000); // 必须先擦除目标块
FLASH_Write(0x24000000, 0x12345678); // 然后写入数据
Flash设备通过内部状态机响应特定命令序列:
硬件注意:并行Flash设备(如Integrator/AP的双16bit器件)需要同步写入命令到所有物理器件。
| 命令 | 第一周期 | 第二周期 | 操作说明 |
|---|---|---|---|
| Read Array | 0xFF | - | 恢复正常读取模式 |
| Program | 0x40 | 0x10 | 写入数据到指定地址 |
| Block Erase | 0x20 | 0xD0 | 擦除整个块 |
| Lock Block | 0x60 | 0x01 | 写保护指定块 |
c复制// 利用缓冲写入提升速度(Intel特有功能)
void Flash_Write_Block(uint32_t addr, uint32_t *data, int len) {
FLASH_CMD(addr, 0xE8); // 进入缓冲写入模式
for(int i=0; i<16 && i<len; i++) { // 最大16字缓冲区
*((volatile uint32_t*)addr) = data[i];
}
FLASH_CMD(addr, 0xD0); // 提交缓冲
while(!(FLASH_READ(addr) & 0x80)); // 等待完成
}
c复制#define FLASH_BASE 0x24000000
#define FLASH_SIZE (32*1024*1024) // 32MB
#define BLOCK_SIZE (64*1024) // 64KB/块
// EBI(External Bus Interface)关键配置
EBI->CS[2].CTRL = 0x0001D800; // 16bit总线, 等待状态配置
c复制// 并行写入两个16bit器件的实现
void Write_Halfwords(uint32_t addr, uint16_t data1, uint16_t data2) {
volatile uint32_t *p = (uint32_t*)(addr & ~0x3);
*p = (data2 << 16) | data1; // 单次32bit写入
}
| 特性 | Intel DT28F320 | SST39VF1601 |
|---|---|---|
| 总线宽度 | 16bit x2并行 | 16bit单器件 |
| 块大小 | 64KB | 64KB(可扇区擦除2KB) |
| 典型编程时间 | 10μs/字 | 15μs/半字 |
| 解锁要求 | 需要 | 不需要 |
c复制void SST_Sector_Erase(uint32_t sector_addr) {
// 6周期擦除命令序列
FLASH_WRITE16(0x5555, 0xAA);
FLASH_WRITE16(0x2AAA, 0x55);
FLASH_WRITE16(0x5555, 0x80);
FLASH_WRITE16(0x5555, 0xAA);
FLASH_WRITE16(0x2AAA, 0x55);
FLASH_WRITE16(sector_addr, 0x30); // 扇区擦除确认
while(FLASH_READ16(sector_addr) != 0xFFFF); // 等待完成
}
初始化阶段:
数据传输:
mermaid复制sequenceDiagram
AXD->>Target: 发送FLASH_INIT命令
Target->>AXD: 返回准备就绪
AXD->>Target: 分块传输二进制数据
Target->>Flash: 执行编程操作
Target->>AXD: 返回状态报告
验证机制:
c复制// 示例工具调用参数
flash_programmer -b 0x24000000 -f firmware.bin -v
// 参数说明:
// -b 基地址
// -f 二进制文件路径
// -v 启用验证模式
c复制typedef enum {
FLASH_OK = 0,
FLASH_ERR_ERASE,
FLASH_ERR_WRITE,
FLASH_ERR_VERIFY,
FLASH_ERR_LOCKED
} FlashStatus;
const char *flash_err_msg[] = {
[FLASH_OK] = "Operation succeeded",
[FLASH_ERR_ERASE] = "Block erase failed",
[FLASH_ERR_WRITE] = "Data programming failed",
// ...其他错误描述
};
| 方法 | 写入1MB数据耗时 | 备注 |
|---|---|---|
| 单字写入 | 12.8秒 | 基础方法,可靠性最高 |
| 缓冲写入(Intel) | 1.2秒 | 利用16字缓冲提升8倍性能 |
| 块拷贝+擦除 | 0.8秒 | 需要额外RAM缓冲 |
元数据保护:
c复制typedef struct {
uint32_t magic; // 0xDEADBEEF
uint32_t crc; // 镜像CRC校验
uint32_t length; // 有效数据长度
uint32_t version; // 固件版本
} FirmwareHeader;
双Bank切换方案:
c复制// flash_hal.h
typedef struct {
int (*init)(void);
int (*erase)(uint32_t addr, uint32_t size);
int (*write)(uint32_t addr, const void *data, uint32_t len);
// ...其他操作
} FlashOperations;
// 平台注册函数
void register_flash_ops(FlashOperations *ops);
c复制void probe_flash_cfi(uint32_t base_addr) {
// 发送CFI查询命令
FLASH_WRITE16(base_addr + 0x55, 0x98);
// 读取CFI信息
uint16_t vendor = FLASH_READ16(base_addr + 0x00);
uint16_t pri = FLASH_READ16(base_addr + 0x1A); // 主要算法标识
printf("Vendor ID: %04X, Command Set: %04X\n", vendor, pri);
}
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 写入后读取不一致 | 未正确擦除/电压不稳 | 检查擦除流程/测量供电电压 |
| 擦除操作超时 | 块锁定/器件损坏 | 执行全片解锁/更换Flash芯片 |
| 随机位错误 | 超过擦写次数/辐射干扰 | 更换芯片/增加ECC校验 |
正常编程序列:
code复制地址: 0x5555 数据: 0xAA
地址: 0x2AAA 数据: 0x55
地址: 0x5555 数据: 0xA0
地址: 目标地址 数据: 编程值
异常情况检测:
安全引导设计:
c复制void bootloader() {
if(*(uint32_t*)APP1_BASE == VALID_MAGIC) {
jump_to_app(APP1_BASE);
} else if(*(uint32_t*)APP2_BASE == VALID_MAGIC) {
jump_to_app(APP2_BASE);
} else {
enter_recovery_mode();
}
}
差分更新优化:
NOR Flash + SPI Flash组合应用:
c复制void hybrid_write(uint32_t nor_addr, uint32_t spi_addr, void *data, int len) {
if(len <= 256) { // 小数据用NOR Flash
nor_flash_write(nor_addr, data, len);
} else { // 大数据用SPI Flash
spi_flash_write(spi_addr, data, len);
}
}