概述
Flash在写入前必须擦除,擦除有page的限制,写入根据设备的不同可能会有对齐的限制。由于其操作的特殊性Flash无法直接接受流式数据的写入(连续的大小不定的数据),为应对该情况Zephyr对flash驱动进行了封装提供stream_flash,用于支持流式数据的写入。
stream_flash模块的特性如下:
- 提供缓存,将流式数据收集到指定量后再写入到Flash
- 支持缓存回读
- 支持断电恢复机制
stream_flash最典型的应用就是DFU升级,在Zephyr中DFU升级和coredump写入flash都使用了stream_flash。
API
API说明
flash_stream的API声明在include/storage/stream_flash.h
中,这里做注释说明
1 | /** |
在配置CONFIG_STREAM_FLASH_ERASE=y
的情况下提供擦除API
1 | /** |
在配置CONFIG_STREAM_FLASH_PROGRESS=y
的情况下提供恢复机制API
1 | /** |
使用示例
这里做简单的使用示例如下注释,当不需要做断电恢复时,移除stream_flash_progress_xxx
相关流程即可
1 |
|
实现分析
stream flash实现的核心就是将数据缓存到buffer中,当buffer满后一次性写入到flash。通过struct stream_flash_ctx
进行管理
1 | struct stream_flash_ctx { |
各字段图示如下,后面的分析可以参考该图进行理解
初始化
stream flash初始化主要完成:对setting系统的初始化用于存储下载进度,完成对struct stream_flash_ctx
的初始化赋值。
1 | int stream_flash_init(struct stream_flash_ctx *ctx, const struct device *fdev, |
写入
1 | int stream_flash_buffered_write(struct stream_flash_ctx *ctx, const uint8_t *data, |
flash写入流程,由于缓存的大小小于页,因此写入可以直接以页来操作
1 | static int flash_sync(struct stream_flash_ctx *ctx) |
上面你可能会发现,无论缓存是多大,即使小于一个page都会被执行stream_flash_erase_page
,这会不会导致前面写入在同一页得数据被擦除呢,我们来看一下其实现
1 | int stream_flash_erase_page(struct stream_flash_ctx *ctx, off_t off) |
恢复机制实现
恢复机制使用setting模块存储和改写struct stream_flash_ctx
中的bytes_written
字段完成,setting是一个可读写模块后端可以对接nvs或者文件等,这里不做展开说明,只用指定setting以key+value的map形式保存即可。
1 | int stream_flash_progress_save(struct stream_flash_ctx *ctx, |
参考
https://docs.zephyrproject.org/latest/reference/storage/stream/stream_flash.html