这是一个 SPI Flash 读写测试示例,演示如何使用 Zephyr 的 Flash API 进行擦除、写入和读取操作。
#if DT_HAS_COMPAT_STATUS_OKAY(jedec_spi_nor)
#define SPI_FLASH_COMPAT jedec_spi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_qspi_nor)
#define SPI_FLASH_COMPAT nordic_qspi_nor
// ... 其他兼容性 ...
#endif
支持的 Flash 类型:
| 兼容性字符串 | 说明 |
|---|---|
jedec_spi_nor | 标准 JEDEC SPI NOR Flash |
nordic_qspi_nor | Nordic QSPI 接口 Flash |
st_stm32_qspi_nor | STM32 QSPI Flash |
nxp_xspi_nor | NXP xSPI Flash |
const struct device *flash_dev = DEVICE_DT_GET_ONE(SPI_FLASH_COMPAT);
DEVICE_DT_GET_ONE() - 获取设备树中第一个匹配的设备int flash_erase(const struct device *dev, off_t offset, size_t size);
关键点:
0xFF示例:
rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, SPI_FLASH_SECTOR_SIZE);
int flash_write(const struct device *dev, off_t offset, const void *data, size_t len);
关键点:
1 位写为 0(不能将 0 写回 1)示例:
const uint8_t expected[] = { 0x55, 0xaa, 0x66, 0x99 };
rc = flash_write(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, expected, sizeof(expected));
int flash_read(const struct device *dev, off_t offset, void *data, size_t len);
示例:
uint8_t buf[4];
rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, sizeof(buf));
┌─────────────────────────────────────────────────┐
│ 1. 擦除扇区 (flash_erase) │
│ ↓ │
│ 2. 读取验证 (flash_read → 0xFF) │
│ ↓ │
│ 3. 写入数据 (flash_write) │
│ ↓ │
│ 4. 读取验证 (flash_read → 写入的数据) │
└─────────────────────────────────────────────────┘
#if defined SPI_FLASH_MULTI_SECTOR_TEST
void multi_sector_test(const struct device *flash_dev);
#endif
#define SPI_FLASH_TEST_REGION_OFFSET 0xff000
#define SPI_FLASH_SECTOR_SIZE 4096
const uint8_t erased[] = { 0xff, 0xff, 0xff, 0xff };
// 擦除后读取验证
rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
if (memcmp(erased, buf, len) != 0) {
printf("Flash erase failed!\n");
}
Flash 擦除特性:
1(字节值 0xFF)1 变为 0const uint8_t expected[] = { 0x55, 0xaa, 0x66, 0x99 };
// 写入后读取验证
rc = flash_write(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, expected, len);
rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
if (memcmp(expected, buf, len) == 0) {
printf("Data read matches data written. Good!!\n");
}
CONFIG_STDOUT_CONSOLE=y # 启用标准输出
CONFIG_FLASH=y # 启用 Flash 驱动
设备树配置示例:
&spi1 {
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
mx25r64: mx25r6435f@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <8000000>;
size = <67108864>; /* 64 Mbit */
jedec-id = [c2 28 17];
};
};
if (!device_is_ready(flash_dev)) {
printk("%s: device not ready.\n", flash_dev->name);
return 0;
}
rc = flash_erase(flash_dev, offset, size);
if (rc != 0) {
printf("Flash erase failed! %d\n", rc);
}
常见错误码:
| 错误码 | 含义 |
|---|---|
-EINVAL | 无效参数(地址/大小不对齐) |
-EIO | I/O 错误 |
-ENOTSUP | 不支持的操作 |
| 问题 | 答案 |
|---|---|
| SPI 时钟极性怎么改? | 设备树 spi-cpol, spi-cpha 属性 |
| Flash 扇区大小? | 通常 4KB,查看数据手册 |
| 为什么擦除后是 0xFF? | Flash 物理特性,擦除后所有位为 1 |
| 写入前必须擦除? | 是,Flash 只能 1→0,不能 0→1 |
| 如何修改测试地址? | 修改 SPI_FLASH_TEST_REGION_OFFSET |
| 特性 | UART echo_bot | SPI spi_flash |
|---|---|---|
| 驱动类型 | UART | Flash |
| 操作模式 | 中断驱动 | 同步阻塞 |
| 数据流 | 字符流 | 块设备 |
| 缓冲区 | 线性缓冲 | 直接读写 |
| 主要 API | uart_* | flash_* |
DT_HAS_COMPAT_STATUS_OKAY 宏支持多种 Flash下一步:继续分析 Button GPIO 示例!
小白 🤖 2026-03-14