<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TinyFlashDB:一種超輕量的可糾錯的通用單片機Flash存儲方案

          共 8336字,需瀏覽 17分鐘

           ·

          2022-05-28 20:38

          擊上方“芯片之家”,選擇“置頂/星標(biāo)公眾號

          干貨福利,第一時間送達!

          摘要:在單片機日常開發(fā)中,總會需要存儲一些信息,這時就需要使用單片機FLASH存儲的方案,目前單片機存儲的方案有很多如:EASYFLASHFLASHDBOSAL_NV等等方案,他們程序都非常大,在存儲不多的變量時不值得。而且現(xiàn)有方案的代碼中很少有考慮到flash寫入出錯的情況。

          在實際產(chǎn)品中,嵌入式產(chǎn)品flash寫入可能會受各種因素影響(電池供電、意外斷電、氣溫等)從而并不是很穩(wěn)定,一旦出現(xiàn)錯誤,會導(dǎo)致產(chǎn)品一系列問題。

          一、TinyFlashDB設(shè)計理念

          不同于其他很多的KV型數(shù)據(jù)庫,TinyFlashDB每一個需要存儲的變量都會分配一個單獨的單片機flash扇區(qū),變量長度不可變。

          TinyFlashDB在設(shè)計時就考慮了寫入錯誤的影響,追求力所能及的安全保障、資源占用方面盡可能的縮小(不到1kb代碼占用)、盡可能的通用性(可以移植到51等8位機,無法逆序?qū)懭氲膕tm32L4系列,某些flash加密的單片機和其他普通32位機上)。

          二、TinyFlashDB使用示例

          const tfdb_index_t test_index = {
              .end_byte = 0x00,
              .flash_addr = 0x4000,
              .flash_size = 256,
              .value_length = 2,

          };
          tfdb_addr_t addr = 0/*addr cache*/

          uint8_t test_buf[4]; /*aligned_value_size*/

          uint16_t test_value;

          void main()
          {
              TFDB_Err_Code result;
              result = tfdb_set(&test_index, test_buf, &addr, &test_value);
              if(result == TFDB_NO_ERR)
              {
                  printf("set ok, addr:%x\n", addr);
              }

              result = tfdb_get(&test_index, test_buf, &addr, &test_value);
              if(result == TFDB_NO_ERR)
              {
                  printf("get ok, addr:%x, value:%x\n", addr, test_value);
              }
          }

          三、TinyFlashDB API介紹

          typedef struct _tfdb_index_struct{
              tfdb_addr_t     flash_addr;/* the start address of the flash block */
              uint16_t        flash_size;/* the size of the flash block */
              uint8_t         value_length;/* the length of value that saved in this flash block */
              uint8_t         end_byte; /* must different to TFDB_VALUE_AFTER_ERASE */
              /* 0x00 is recommended for end_byte, because almost all flash is 0xff after erase. */
          }tfdb_index_t;

          結(jié)構(gòu)體功能:在TinyFlashDB中,API的操作都需要指定的參數(shù)index,該index結(jié)構(gòu)體中存儲了flash的地址,flash的大小,存儲的變量的長度,結(jié)束標(biāo)志位。在讀取flash扇區(qū)時會去校驗此信息。

          TFDB_Err_Code tfdb_get(const tfdb_index_t *index, uint8_t *rw_buffer, tfdb_addr_t *addr_cache, void* value_to);
          • 函數(shù)功能:從index指向的扇區(qū)中獲取一個index中指定變量長度的變量,flash頭部數(shù)據(jù)校驗出錯不會重新初始化flash。

          • 參數(shù) index:tfdb操作的index指針。

          • 參數(shù) rw_buffer:寫入和讀取的緩存,所有flash的操作最后都會將整理后的數(shù)據(jù)拷貝到該buffer中,再調(diào)用tfdb_port_write或者tfdb_port_read進行寫入。當(dāng)芯片對于寫入的數(shù)據(jù)區(qū)緩存有特殊要求(例如4字節(jié)對齊,256字節(jié)對齊等),可以通過該參數(shù)將符合要求的變量指針傳遞給函數(shù)使用。至少為4字節(jié)長度。

          • 參數(shù) addr_cache:可以是NULL,或者是地址緩存變量的指針,當(dāng)addr_cache不為NULL,并且也不為0時,則認為addr_cache已經(jīng)初始化成功,不再校驗flash頭部,直接從該addr_cache的地址讀取數(shù)據(jù)。

          • 參數(shù) value_to:要存儲數(shù)據(jù)內(nèi)容的地址。

          • 返回值:TFDB_NO_ERR成功,其他失敗。

          TFDB_Err_Code tfdb_set(const tfdb_index_t *index, uint8_t *rw_buffer, tfdb_addr_t *addr_cache, void* value_from);
          • 函數(shù)功能:在index指向的扇區(qū)中寫入一個index中指定變量長度的變量,flash頭部數(shù)據(jù)校驗出錯重新初始化flash。

          • 參數(shù) index:tfdb操作的index指針。

          • 參數(shù) rw_buffer:寫入和讀取的緩存,所有flash的操作最后都會將整理后的數(shù)據(jù)拷貝到該buffer中,再調(diào)用tfdb_port_write或者tfdb_port_read進行寫入。當(dāng)芯片對于寫入的數(shù)據(jù)區(qū)緩存有特殊要求(例如4字節(jié)對齊,256字節(jié)對齊等),可以通過該參數(shù)將符合要求的變量指針傳遞給函數(shù)使用。至少為4字節(jié)長度。

          • 參數(shù) addr_cache:可以是NULL,或者是地址緩存變量的指針,當(dāng)addr_cache不為NULL,并且也不為0時,則認為addr_cache已經(jīng)初始化成功,不再校驗flash頭部,直接從該addr_cache的地址讀取數(shù)據(jù)。

          • 參數(shù) value_from:要存儲的數(shù)據(jù)內(nèi)容。

          • 返回值:TFDB_NO_ERR成功,其他失敗。

          四、TinyFlashDB設(shè)計原理

          觀察上方代碼,可以發(fā)現(xiàn)TinyFlashDB的操作都需要tfdb_index_t定義的index參數(shù)。

          Flash初始化后頭部信息為4字節(jié),所以只支持1、2、4、8字節(jié)操作的flash:頭部初始化時會讀取頭部,所以函數(shù)中rw_buffer指向的數(shù)據(jù)第一要求至少為4字節(jié),如果最小寫入單位是8字節(jié),則為第一要求最少為8字節(jié)。

          第一字節(jié)第二字節(jié)第三字節(jié)第四字節(jié)和其他對齊字節(jié)
          flash_size高8位字節(jié)flash_size低8位字節(jié)value_lengthend_byte

          數(shù)據(jù)存儲時,會根據(jù)flash支持的字節(jié)操作進行對齊,所以函數(shù)中rw_buffer指向的數(shù)據(jù)第二要求至少為下面函數(shù)中計算得出的aligned_value_size個字節(jié):

              aligned_value_size  = index->value_length + 2;/* data + verify + end_byte */
           
          #if (TFDB_WRITE_UNIT_BYTES==2)
              /* aligned with TFDB_WRITE_UNIT_BYTES */
              aligned_value_size = ((aligned_value_size + 1) & 0xfe);
          #elif (TFDB_WRITE_UNIT_BYTES==4)
              /* aligned with TFDB_WRITE_UNIT_BYTES */
              aligned_value_size = ((aligned_value_size + 3) & 0xfc);
          #elif (TFDB_WRITE_UNIT_BYTES==8)
              /* aligned with TFDB_WRITE_UNIT_BYTES */
              aligned_value_size = ((aligned_value_size + 7) & 0xf8);
          #endif
          前value_length個字節(jié)第value_length+1字節(jié)第value_length+2字節(jié)其他對齊字節(jié)
          value_from數(shù)據(jù)內(nèi)容value_from的和校驗end_byteend_byte

          每次寫入后都會再讀取出來進行校驗,如果校驗不通過,就會繼續(xù)在下一個地址寫入。指導(dǎo)達到最大寫入次數(shù)(TFDB_WRITE_MAX_RETRY)或者頭部校驗錯誤。

          讀取數(shù)據(jù)時也會計算和校驗,不通過的話繼續(xù)讀取,直到返回校驗通過的最新數(shù)據(jù),或者讀取失敗。

          五、TinyFlashDB移植和配置

          移植使用只需要在tfdb_port.c中,編寫完成三個接口函數(shù),也要在tfdb_port.h中添加相應(yīng)的頭文件和根據(jù)不同芯片修改宏定義

          TFDB_Err_Code tfdb_port_read(tfdb_addr_t addr, uint8_t *buf, size_t size);

          TFDB_Err_Code tfdb_port_erase(tfdb_addr_t addr, size_t size);

          TFDB_Err_Code tfdb_port_write(tfdb_addr_t addr, const uint8_t *buf, size_t size);

          所有的配置項都在tfdb_port.h中

          /* use string.h or self functions */
          #define TFDB_USE_STRING_H               1

          #if TFDB_USE_STRING_H
              #include "string.h"
              #define tfdb_memcpy memcpy
              #define tfdb_memcmp memcmp
              #define TFDB_MEMCMP_SAME 0
          #else
              #define tfdb_memcpy
              #define tfdb_memcmp
              #define TFDB_MEMCMP_SAME
          #endif

          #define TFDB_DEBUG                          printf

          /* The data value in flash after erased, most are 0xff, some flash maybe different. */
          #define TFDB_VALUE_AFTER_ERASE              0xff

          /* the flash write granularity, unit: byte
           * only support 1(stm32f4)/ 2(CH559)/ 4(stm32f1)/ 8(stm32L4) */

          #define TFDB_WRITE_UNIT_BYTES               8 /* @note you must define it for a value */

          /* @note the max retry times when flash is error ,set 0 will disable retry count */
          #define TFDB_WRITE_MAX_RETRY                32

          /* must not use pointer type. Please use uint32_t, uint16_t or uint8_t. */
          typedef uint32_t    tfdb_addr_t;

          六、移植到STM32單片機

          項目地址:https://github.com/smartmx/TFDB/tree/main

          使用一下命令克隆Demo,裸機移植例程

          git clone -b raw https://github.com/smartmx/TFDB.git

          本文來源:果果小師弟

          嵌入式軟件版本怎么樣命名才比較專業(yè)?


          深度長文:STM32是如何軟硬件結(jié)合,編譯后怎么樣一步步運行起來的


          電子漫畫系列套圖更新11張,共計83張,附高清無碼下載鏈接


          又踩廠商的雷了!1000多套板子要批量返工,說多了都是淚


          覺得好看,請點這里

          瀏覽 22
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲日本在线观看 | 国产极品 国产极品 | 少妇一区二区三区97 | 色婷激情五月 | 中文字幕无码在线观看视频 |