日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

EasyFlash | 让 Flash 成为小型 KV 数据库

發布時間:2024/8/1 数据库 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 EasyFlash | 让 Flash 成为小型 KV 数据库 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

嵌入式開源項目精選專欄

本專欄由Mculover666創建,主要內容為尋找嵌入式領域內的優質開源項目,一是幫助開發者使用開源項目實現更多的功能,二是通過這些開源項目,學習大佬的代碼及背后的實現思想,提升自己的代碼水平,和其它專欄相比,本專欄的優勢在于:

不會單純的介紹分享項目,還會包含作者親自實踐的過程分享,甚至還會有對它背后的設計思想解讀

目前本專欄包含的開源項目有:

  • cJSON | 一個輕量級C語言JSON解析器
  • paho | 支持10種語言編寫mqtt客戶端,總有一款適合你!
  • MultiButton | 一個小巧簡單易用的事件驅動型按鍵驅動模塊
  • letter-shell | 一個功能強大的嵌入式shell
  • EasyLogger | 一款輕量級且高性能的日志庫
  • SFUD | 一款串行 Flash 通用驅動庫

如果您自己編寫或者發現的開源項目不錯,歡迎留言或者私信投稿到本專欄,分享獲得雙倍的快樂!

1. EasyFlash

本期給大家帶來的開源項目是 EasyFlash,可以讓 Flash 成為小型 KV 數據庫(Key-Value),作者armink,目前收獲 975 個 star,遵循 MIT 開源許可協議。

EasyFlash是一款開源的輕量級嵌入式Flash存儲器庫,非常適合智能家居、可穿戴、工控、醫療、物聯網等需要斷電存儲功能的產品,資源占用極低,并且支持各種 MCU 片上存儲器。

目前 EasyFlash 支持以下功能:

  • ENV:快速保存產品參數,支持 寫平衡(磨損平衡) 及掉電保護功能;
  • IAP:在線升級;
  • LOG:無需文件系統,日志可直接存儲在Flash上;

項目地址:https://github.com/armink/EasyFlash

2. 移植EasyFlash

2.1. 移植思路

在移植過程中主要參考兩個資料:項目的readme文檔和demo工程。

對于這些開源項目,其實移植起來也就兩步:

  • ① 添加源碼到裸機工程中;
  • ② 實現需要的接口即可(擦、寫、讀、打印);

2.2. 準備裸機工程

本文中我使用的是小熊派IoT開發套件,主控芯片為STM32L431RCT6:

板載Flash型號為W25Q64JV,大小64Mbit,與STM32的QSPI接口相連:

移植之前需要準備一份裸機工程,我使用STM32CubeMX生成,需要初始化以下配置:

  • 配置一個串口用于打印信息
  • printf重定向
  • 配置SPI Flash通信接口(SPI或QSPI)
  • 移植SFUD開源庫(方便操作Flash)

SFUD移植過程請參考上一期文章:

  • SFUD | 一款串行 Flash 通用驅動庫

2.3. 添加EasyFlash到工程中


② 在keil中添加 SFUD 組件的源碼文件:

  • src\easyflash.c:(必選)包含EasyFlash初始化方法;
  • src\ef_utils.c:(必選)EasyFlash常用小工具;
  • port\ef_port.c:(必選)EasyFlash移植接口;
  • src\ef_env.c:Env(常規模式)相關操作接口及實現源碼;


其它兩個IAP和LOG相關的源碼暫且不用添加。

③ 將easyflash/inc頭文件路徑添加到keil中:

2.4. 實現EasyFlash移植接口

EasyFlash的移植接口都已經寫好了,在ef_port.c文件中,只需要在函數體中添加代碼即可。

① 默認環境變量集合

產品上需要的默認環境變量集中定義在這里,當 flash 第一次初始化時會將默認的環境變量寫入,采用 void * 類型,所以支持任意類型:

/* default environment variables set for user */ static const ef_env default_env_set[] = {{"wifi_ssid","FAST_88A6", 0}, //字符串大小設置為0,會自動檢測{"wifi_passwd","12345678", 0}, };

② EasyFlash初始化接口

在該接口中會傳遞默認環境變量,初始化EasyFlash移植所需的資源(比如SFUD庫的初始化):

EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size) {EfErrCode result = EF_NO_ERR;*default_env = default_env_set;*default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]);//SFUD庫初始化sfud_init();return result; }

③ 讀取Flash接口

使用SFUD開源庫提供的API實現該接口:

EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {EfErrCode result = EF_NO_ERR;//獲取SFUD Flash設備對象const sfud_flash *flash = sfud_get_device_table() + SFUD_W25Q64_DEVICE_INDEX;//使用SFUD開源庫提供的API實現Flash讀取sfud_read(flash, addr, size, (uint8_t *)buf);return result; }

④ 擦除Flash接口

使用SFUD開源庫提供的API實現該接口:

EfErrCode ef_port_erase(uint32_t addr, size_t size) {EfErrCode result = EF_NO_ERR;sfud_err sfud_result = SFUD_SUCCESS;//獲取SFUD Flash設備對象const sfud_flash *flash = sfud_get_device_table() + SFUD_W25Q64_DEVICE_INDEX;/* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0);//使用SFUD提供的API實現Flash擦除sfud_result = sfud_erase(flash, addr, size);if(sfud_result != SFUD_SUCCESS) {result = EF_ERASE_ERR;}return result; }

⑤ 寫入Flash接口

使用SFUD開源庫提供的API實現該接口:

EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {EfErrCode result = EF_NO_ERR;sfud_err sfud_result = SFUD_SUCCESS;//獲取SFUD Flash設備對象const sfud_flash *flash = sfud_get_device_table() + SFUD_W25Q64_DEVICE_INDEX;//使用SFUD開源庫提供的API實現sfud_result = sfud_write(flash, addr, size, (const uint8_t *)buf);if(sfud_result != SFUD_SUCCESS) {result = EF_WRITE_ERR;}return result; }

⑥ 對環境變量緩沖區加鎖/解鎖

裸機時可以使用關閉/打開全局中斷來上鎖/解鎖:

/*** lock the ENV ram cache*/ void ef_port_env_lock(void) {//關閉全局中斷__disable_irq(); }/*** unlock the ENV ram cache*/ void ef_port_env_unlock(void) {//打開全局中斷__enable_irq();}

⑦ EasyFlash打印數據和日志接口

在該文件最頂部開辟一塊打印數據緩沖區:

//easyflash打印數據緩沖區 static char log_buf[128];

然后實現輸出無固定格式的打印信息接口:

void ef_print(const char *format, ...) {va_list args;/* args point to the first variable parameter */va_start(args, format);/* 實現數據輸出 */vsprintf(log_buf, format, args);printf("%s", log_buf);va_end(args); }

然后使用該函數去實現調試信息日志打印接口

void ef_log_debug(const char *file, const long line, const char *format, ...) {#ifdef PRINT_DEBUGva_list args;/* args point to the first variable parameter */va_start(args, format);/* You can add your code under here. */ef_print("[Flash](%s:%ld) ", file, line);/* must use vprintf to print */vsprintf(log_buf, format, args);ef_print("%s", log_buf);printf("\r");va_end(args);#endif}

最后實現普通日志信息打印接口:

void ef_log_info(const char *format, ...) {va_list args;/* args point to the first variable parameter */va_start(args, format);/* You can add your code under here. */ef_print("[Flash]");/* must use vprintf to print */vsprintf(log_buf, format, args);ef_print("%s", log_buf);printf("\r");va_end(args); }

2.5. 配置EasyFlash

EasyFlash的核心功能配置文件在ef_cfg.h,修改說明如下。

① 環境變量功能相關

② Flash擦除粒度和寫入粒度

③ 備份區相關

④ 調試日志是否開啟

至此,EasyFlash移植、配置完成,接下來就可以愉快的使用了!

3. 使用EasyFlash

使用時包含頭文件:

#include <easyflash.h>

3.1. 初始化EasyFlash

EfErrCode easyflash_init(void);

該 API 會初始化的EasyFlash的各個組件,初始化后才可以使用別的API,第一次初始化的時候,會自動調用 ef_env_set_default 將定義的默認環境變量保存到Flash。

在main函數中初始化EasyFlash:

/* USER CODE BEGIN 2 */ //初始化EasyFlash ret = easyflash_init(); if(ret != EF_NO_ERR) {printf("EasyFlash init fail, EfErrCode = %d.r\n", ret); }/* USER CODE END 2 */

3.2. 環境變量操作API

在 V4.0 以后,環境變量在 EasyFlash 底層都是按照二進制數據格式進行存儲,即 blob 格式 ,這樣上層支持傳入任意類型。

① 獲取 blob 類型環境變量

size_t ef_get_env_blob(const char *key, void *value_buf, size_t buf_len, size_t *save_value_len);

其中參數的意義如下:

  • key:環境變量名稱
  • value_buf:存放環境變量的緩沖區
  • buf_len:該緩沖區的大小
  • save_value_len:返回該環境變量實際存儲在 flash 中的大小
  • 返回值:成功存放至緩沖區中的數據長度

② 設置 blob 類型環境變量

使用該API可以對環境變量完成如下操作:

  • 增加 :當環境變量表中不存在該名稱的環境變量時,則會執行新增操作;
  • 修改 :入參中的環境變量名稱在當前環境變量表中存在,則把該環境變量值修改為入參中的值;
  • 刪除:當入參中的value為NULL時,則會刪除入參名對應的環境變量。
EfErrCode ef_set_env_blob(const char *key, const void *value_buf, size_t buf_len);

其中參數的意義如下:

  • key:環境變量名稱
  • value_buf:環境變量值緩沖區
  • buf_len:緩沖區長度,即值的長度

3.3. 測試讀取默認環境變量

在main.c中編寫一個EasyFlash測試函數:

void test_env(void) {char wifi_ssid[20] = {0};char wifi_passwd[20] = {0};size_t len = 0;/* 讀取默認環境變量值 *///環境變量長度未知,先獲取 Flash 上存儲的實際長度 */ef_get_env_blob("wifi_ssid", NULL, 0, &len);//獲取環境變量ef_get_env_blob("wifi_ssid", wifi_ssid, len, NULL);//打印獲取的環境變量值printf("wifi_ssid env is:%s\r\n", wifi_ssid);//環境變量長度未知,先獲取 Flash 上存儲的實際長度 */ef_get_env_blob("wifi_passwd", NULL, 0, &len);//獲取環境變量ef_get_env_blob("wifi_passwd", wifi_passwd, len, NULL);//打印獲取的環境變量值printf("wifi_passwd env is:%s\r\n", wifi_passwd);/* 將環境變量值改變 */ef_set_env_blob("wifi_ssid", "SSID_TEST", 9);ef_set_env_blob("wifi_passwd", "66666666", 8);}

在main函數的初始化代碼之后調用該函數,編譯下載之后,在串口終端中可以看到讀取結果:

此時環境變量已經被修改,直接復位開發板,可以看到讀取出的新值:

3.4. Easyflash和letter-shell的結合

EasyFlash在測試階段需要不斷的設置環境變量、讀取環境變量、開發板重新上電,這個特點剛好可以應用letter-shell,直接將兩個常用函數導出為命令,在串口命令行測試。

letter-shell的移植過程請參考第2期:

  • letter-shell | 一個功能強大的嵌入式shell

移植之后將讀取環境變量的API封裝,導出到命令列表中:

/* USER CODE BEGIN 4 */ int getenv(const char *key) {size_t len = 0;char buf[20] = {0};//獲取長度ef_get_env_blob(key, NULL, 0, &len);if(len == 0){//環境變量不存在printf("evn %s is not exist\r\n", key);return -1;}else if(len < 20){//環境變量值超長printf("buf size is not enough, len is %d\r\n", len);return -1;}else{//獲取環境變量值ef_get_env_blob(key, buf, len, NULL);printf("read env %s, value is:%s\r\n", key, buf);return 0;} }SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), getenv, getenv, getenv); /* USER CODE END 4 */

編譯下載之后,在串口終端中查看串口輸出:

然后進行讀取環境變量測試:

測試成功,同理,修改環境變量的API也可以進行封裝,導出到命令列表中進行測試。

4. 設計思想解讀

對于EasyFlash的全新版本設計,作者armink在倉庫中寫了一份文檔,解鈴還須系鈴人,筆者的技術水平有限,直接放上作者的文檔鏈接,歡迎感興趣的讀者閱讀。

  • EasyFlash V4.0 ENV 功能設計與實現

5. 項目工程源碼獲取和問題交流

目前我將EasyFlash源碼、我移植到小熊派STM32L431RCT6開發板的工程源碼上傳到了QQ群里(包含好幾份HAL庫,QQ相對速度快點),可以在QQ群里下載,有問題也可以在群里交流,當然也歡迎大家分享出來自己移植的工程到QQ群里

放上QQ群二維碼:

接收更多精彩文章及資源推送,歡迎訂閱我的微信公眾號:『mculover666』。

總結

以上是生活随笔為你收集整理的EasyFlash | 让 Flash 成为小型 KV 数据库的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人精品久久久 | 亚洲区一区| 91pao | 在线观看亚洲一区二区 | 毛片毛片毛片毛片毛片毛片毛片 | 中国女人一级一次看片 | 男女扒开双腿猛进入爽爽免费 | 成人免费毛片免费 | 草草影院最新 | 黄色一级a毛片 | 日韩高清黄色 | 国产精品乱码久久久久久 | 黑花全肉高h湿play短篇 | 日本一区二区三区四区在线观看 | 天天色天天色天天色 | 老头吃奶性行交 | 国产一级做a爱免费视频 | 国产无遮挡免费观看视频网站 | 丰满人妻老熟妇伦人精品 | 天天爽天天爽夜夜爽毛片 | 亚洲网站在线免费观看 | 午夜影院啊啊啊 | 欧美xxxxbbbb| 午夜在线观看免费视频 | 天堂在线免费视频 | 国产伦精品一区二区 | 国产男女猛烈无遮挡 | 久久精品无码一区二区三区毛片 | www.久久久久.com| 亚洲国产精品二区 | 午夜免费在线观看 | 一个人在线观看www软件 | 中日韩在线观看 | 久久成人在线视频 | 日韩欧美中文一区 | 色天堂在线视频 | 国产成人精品无码免费看在线 | jizz成熟丰满老女人 | 久久六六 | 国产视频二区 | 天天干夜夜玩 | 日本欧美成人 | 国产亚洲精品久久 | 天天干夜夜看 | 岛国av噜噜噜久久久狠狠av | 一区二区三区激情视频 | 97人人模人人爽人人少妇 | 天堂8在线 | 丁香花完整视频在线观看 | 91精选 | 黄色大片免费在线观看 | 红色假期黑色婚礼2 | 校园春色自拍偷拍 | 漂亮人妻被中出中文字幕 | 精品人妻无码专区在线 | 欧美日韩亚洲精品一区二区 | 一吻定情2013日剧 | 91精品视频免费观看 | 国产一区二区三区免费视频 | 人妻中文字幕一区 | 女人私密又肥又大 | 成人欧美视频在线观看 | 亚洲精品乱码久久久久久蜜桃图片 | 日本h视频在线观看 | 久在线播放 | 精品国产乱码久久久久久蜜柚 | 亚洲久久在线观看 | 婷婷五月精品中文字幕 | 91精品国产麻豆 | 成人黄色一级片 | 夜色一区二区 | 丝袜操 | 成年人网站黄 | 欧美日韩亚洲一区二区 | 精品久久久久一区二区国产 | 国产欧美久久久 | 国产人久久人人人人爽 | 午夜污片 | jizzjizz中国精品麻豆 | 九九热在线视频免费观看 | 黄色网址在线免费看 | 亚洲天堂8 | 色中色在线视频 | 亚洲国产tv | 国产精品天美传媒入口 | 久久成人18免费观看 | 天天爱夜夜爽 | 三级4级全黄60分钟 成人自拍视频 | 最新中文av | 日韩av无码中文字幕 | 国产一级特黄视频 | 丰满人妻av一区二区三区 | 粉嫩aⅴ一区二区三区 | 国产曰肥老太婆无遮挡 | 一区二区高清在线 | 一级全黄色片 | av永久 | 欧美播放器 | 亚洲熟女乱色综合亚洲小说 |