# Nand Flash Storage frameworks **Repository Path**: lhp625/nand-flash-storage-frameworks ## Basic Information - **Project Name**: Nand Flash Storage frameworks - **Description**: 一种基于MCU 内部flash和外挂 nand flash 的 记录存储框架 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-12-28 - **Last Updated**: 2024-12-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Nand flash 裸机存储框架 ## 使用方法 本框架使用cmake 编译生成。 运行 run.sh 脚本,可进行编译运行。 运行 gdb_run.sh 脚本,可进行GDB调试 ## 当前使用场景 * 设备具有足够的内部flash空间,有一个外挂的 Nand flash。 * 防止突然掉电,缓存数据丢失。 * 提高外部nand flash的利用率。 * 使用 GD5F1G NAND FLASH ,只能块擦,一块有64页,一页有2K,块擦,页写入,字节读取。 * 使用的MCU GD32F303,SRAM > 32K. flash page = 2K,可以页擦,字节读写。 ## 框架介绍 参数配置: 在store_conf.h中 配置 内部flash 的缓冲区大小,按照一页为单位。 配置 一条记录的字节大小。 配置 内部flash 的页大小,按照一页为单位。 配置 外部flash 为一个记录留存的空间,以块为单位,同时配置好,外部flash的页大小,块大小。 初始化调用: 初始化存储索引:void store_index_init(void) 初始化读取索引:void read_index_init(void) 存储数据调用: void store_new_message_to_in_flash(STR_MESSAGE_FORMAT * infor) 将数据通过该函数填入内部flash。 获得记录数量: 获得某种类型的数据总数: uint32_t get_type_record_total_num(ENU_MESSAGE_TYPE message_type) 获得所有记录的条数: uint32_t get_all_record_number(void) 读取数据调用: 非阻塞读取调度,放在循环里: void read_ctrl_schdule(void) 选择需要读取的种类 :void read_ctrl_message_add(ENU_MESSAGE_TYPE message_type) 清除保存的指定类型记录 void read_ctrl_schdule(void) ## 文件介绍: ### code/store.c/.h store是本模块的主要文件,内部含有读写功能函数。 对外提供6个API,分为读功能和写功能。详见 store.h ### store_conf.h 本文件是 用于配置存储空间的,内部分为 内部flash的每页大小,外部flash的每页大小,块大小等。 同时也设置了 预留的内外储存空间的大小和位置 * 通过配置这些参数,可以更加灵活的将该Nand flash 存储框架移植到其他地方使用。 ### in_flash / out_flash 是硬件抽象层,便于linux上进行仿真使用。 ## 框架思路 ### 存储部分: 分为内外两个存储空间。使用内部flash的几页作为数据的临时缓冲区。当数据来临时,先保存到缓冲区中。等待缓冲区存满后,然后把整个缓冲区读出,按页写入外部flash中。也就是只要往外部flsh中 一写就写一页。 外部flash使用循环存储的方式。分配N个块作为存储空间,则实际需要留 (N+1)个块,第(N+1)个块作为缓冲块,当写完第N个块后,擦除第(N+1)个块,写入数据。第(N+1)个块写完后,擦除第一个块。这样永远保持有 N 个块是保存数据的。 全局有一个存储索引,管理各种类型的数据存储的位置:在内部缓冲区存了多少条,外部flash存了几个整块,非整块的第几页。这个索引保存在内部flash中,上电读出,继续往下存。 ### 读取部分 分为两部分: 第一部分:从存储的空间中,按照旧数据->>新数据的顺序读出。一种类型的读取按照:外部数据-》内部缓冲区的顺序读取。 外部读取的数据是根据是否进行了循环存储,如果循环存储则,当前存储到的块的下一块里存放的就是最旧的数据。 如果没有进行循环,则当前的第一块就存放着最旧的数据。 内部缓冲区就是存放最新的数据。 第二部分:接受外部命令,选择读出哪种类型。送入事件队列,按照读取命令下发的先后顺序,逐一读出不同类型的记录。 每次读出的数据可以设置不同的发送速度。 当前设置,读一个内部缓冲区大小的数据,一次全发出去。 # 版本修改历史: ## 2024-3-13 修改bug: 1、在读取外部flash时,需要保证页数块数同时相等,才能认为读取结束。 将判断条件中 && --> || ,(==) ---> ( != ) 2、读取一次结束后,将该类型的读取索引清空。便于多次读取。 3、将从内部flash读出写入外部flash时建立的局部变量数组 改为全局变量。局部变量会造成内存泄漏。 ## 2024-3-16 修改bug: 1、在一次性请求多个记录种类时,超过4个会导致事件缓冲区覆盖原有未处理的事件。将事件缓冲区事件个数扩大到8个。 新增功能: 增加 清除某种类型记录的 功能 ## 2024-3-18 1、存在一个巨大的内存浪费的问题,在读取索引中,存在一个2K大小的缓冲区。但由于为每一个类型都建了一个存储索引。所以这个缓冲区占了8K大小。而实际单次真正使用的空间只有2K。 同样的问题还存在于单次读取只使用了 一个存储索引,而实际上创建了四个,也就是说每次只能使用一个,其他三个都浪费了。 目前代码已经完成实装,并初步测试运行通过,当前就县保持原状。后需复用再依据具体情况进行优化。 2、优化规范注释。 3、一号问题已解决,将读取发送缓冲区独立出来。