2. Flash驱动抽象层设计
任务目标
在Bootloader差分OTA方案中,Flash驱动层需要屏蔽不同厂商、不同型号Flash芯片的差异,向上层提供统一的读写擦除接口。本案例设计一个最小可用的Flash抽象层,支持两种典型芯片(NOR Flash与内部Flash)的模拟实现,并验证接口一致性。
接口定义
/* flash_drv.h */
#ifndef FLASH_DRV_H
#define FLASH_DRV_H
#include <stdint.h>
typedef enum {
FLASH_OK = 0,
FLASH_ERR_PARAM,
FLASH_ERR_ADDR,
FLASH_ERR_BUSY,
FLASH_ERR_UNSUPPORTED
} flash_status_t;
typedef struct {
uint32_t base_addr;
uint32_t sector_size;
uint32_t total_size;
uint32_t page_size; /* 编程最小单位 */
uint8_t is_memory_mapped; /* 1:可直接寻址, 0:需命令访问 */
} flash_info_t;
typedef struct flash_dev {
flash_info_t info;
flash_status_t (*init)(struct flash_dev *dev);
flash_status_t (*read)(struct flash_dev *dev, uint32_t offset,
uint8_t *buf, uint32_t len);
flash_status_t (*write)(struct flash_dev *dev, uint32_t offset,
const uint8_t *buf, uint32_t len);
flash_status_t (*erase)(struct flash_dev *dev, uint32_t offset,
uint32_t len);
} flash_dev_t;
/* 注册具体芯片驱动 */
flash_status_t flash_register(flash_dev_t *dev);
#endif
关键完整实现
/* flash_drv.c */
#include "flash_drv.h"
#include <string.h>
#define MAX_FLASH_DEVICES 4
static flash_dev_t *g_devices[MAX_FLASH_DEVICES];
static uint8_t g_dev_count = 0;
/* 模拟NOR Flash存储区 */
static uint8_t nor_storage[256 * 1024];
/* 模拟内部Flash存储区 */
static uint8_t int_storage[64 * 1024];
flash_status_t flash_register(flash_dev_t *dev) {
if (!dev || g_dev_count >= MAX_FLASH_DEVICES)
return FLASH_ERR_PARAM;
if (dev->init(dev) != FLASH_OK)
return FLASH_ERR_BUSY;
g_devices[g_dev_count++] = dev;
return FLASH_OK;
}
/* ---------- NOR Flash 驱动 (模拟W25Q系列) ---------- */
static flash_status_t nor_init(flash_dev_t *dev) {
dev->info.base_addr = 0x90000000;
dev->info.sector_size = 4096;
dev->info.total_size = sizeof(nor_storage);
dev->info.page_size = 256;
dev->info.is_memory_mapped = 1;
memset(nor_storage, 0xFF, sizeof(nor_storage));
return FLASH_OK;
}
static flash_status_t nor_read(flash_dev_t *dev, uint32_t offset,
uint8_t *buf, uint32_t len) {
if (!dev || !buf || offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
memcpy(buf, &nor_storage[offset], len);
return FLASH_OK;
}
static flash_status_t nor_write(flash_dev_t *dev, uint32_t offset,
const uint8_t *buf, uint32_t len) {
if (!dev || !buf || offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
/* NOR Flash只能将1写为0,模拟时直接覆盖 */
memcpy(&nor_storage[offset], buf, len);
return FLASH_OK;
}
static flash_status_t nor_erase(flash_dev_t *dev, uint32_t offset,
uint32_t len) {
if (!dev || offset % dev->info.sector_size != 0 ||
len % dev->info.sector_size != 0 ||
offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
memset(&nor_storage[offset], 0xFF, len);
return FLASH_OK;
}
/* ---------- 内部Flash驱动 (模拟STM32内部Flash) ---------- */
static flash_status_t intf_init(flash_dev_t *dev) {
dev->info.base_addr = 0x08000000;
dev->info.sector_size = 2048;
dev->info.total_size = sizeof(int_storage);
dev->info.page_size = 8; /* 内部Flash按字节编程 */
dev->info.is_memory_mapped = 1;
memset(int_storage, 0xFF, sizeof(int_storage));
return FLASH_OK;
}
static flash_status_t intf_read(flash_dev_t *dev, uint32_t offset,
uint8_t *buf, uint32_t len) {
if (!dev || !buf || offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
memcpy(buf, &int_storage[offset], len);
return FLASH_OK;
}
static flash_status_t intf_write(flash_dev_t *dev, uint32_t offset,
const uint8_t *buf, uint32_t len) {
if (!dev || !buf || offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
/* 内部Flash写入前必须已擦除(0xFF),此处模拟硬件行为 */
for (uint32_t i = 0; i < len; i++) {
if (int_storage[offset + i] != 0xFF)
return FLASH_ERR_BUSY;
}
memcpy(&int_storage[offset], buf, len);
return FLASH_OK;
}
static flash_status_t intf_erase(flash_dev_t *dev, uint32_t offset,
uint32_t len) {
if (!dev || offset % dev->info.sector_size != 0 ||
len % dev->info.sector_size != 0 ||
offset + len > dev->info.total_size)
return FLASH_ERR_PARAM;
memset(&int_storage[offset], 0xFF, len);
return FLASH_OK;
}
/* ---------- 设备实例与注册 ---------- */
static flash_dev_t nor_dev = {
.info = {0},
.init = nor_init,
.read = nor_read,
.write = nor_write,
.erase = nor_erase
};
static flash_dev_t intf_dev = {
.info = {0},
.init = intf_init,
.read = intf_read,
.write = intf_write,
.erase = intf_erase
};
void flash_drv_init(void) {
flash_register(&nor_dev);
flash_register(&intf_dev);
}
/* 供上层查询设备 */
flash_dev_t *flash_get_device(uint8_t index) {
if (index >= g_dev_count) return 0;
return g_devices[index];
}
验证代码
/* test_flash_abstraction.c */
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "flash_drv.h"
int main(void) {
flash_drv_init();
uint8_t wbuf[64], rbuf[64];
for (int dev_idx = 0; dev_idx < 2; dev_idx++) {
flash_dev_t *dev = flash_get_device(dev_idx);
assert(dev != 0);
printf("Device %d: base=0x%08X size=%u sector=%u\n",
dev_idx, dev->info.base_addr, dev->info.total_size,
dev->info.sector_size);
/* 擦除一个扇区 */
assert(dev->erase(dev, 0, dev->info.sector_size) == FLASH_OK);
/* 写入并回读验证 */
for (int i = 0; i < 64; i++) wbuf[i] = (uint8_t)(i + dev_idx);
assert(dev->write(dev, 0, wbuf, 64) == FLASH_OK);
memset(rbuf, 0, 64);
assert(dev->read(dev, 0, rbuf, 64) == FLASH_OK);
assert(memcmp(wbuf, rbuf, 64) == 0);
/* 越界访问应返回错误 */
assert(dev->read(dev, dev->info.total_size - 1, rbuf, 2) == FLASH_ERR_PARAM);
printf(" -> write/read/erase/param check PASSED\n");
}
printf("All flash abstraction tests passed.\n");
return 0;
}
编译与运行
gcc -Wall -Wextra -o test_flash flash_drv.c test_flash_abstraction.c
./test_flash
验证判定标准
- 程序输出两个设备的base地址、容量和扇区大小,且与代码中定义一致;
- 每个设备均完成“擦除→写入→回读比对→越界检查”流程,打印PASSED;
- 最终输出
All flash abstraction tests passed.,退出码为0。
设计要点
- 上层通过
flash_dev_t函数指针调用,不感知具体芯片类型;新增芯片只需实现4个接口并注册; - 内部Flash驱动模拟了“写前必须擦除”的硬件约束,返回
FLASH_ERR_BUSY;NOR Flash则允许直接覆盖; - 擦除操作强制按扇区对齐,非法参数返回
FLASH_ERR_PARAM,保证上层OTA模块的调用安全。