MCUの小さなフラッシュデータベース。
マイクロコントローラーの毎日の開発では、いくつかの情報が常に必要です。現時点では、マイクロコントローラーフラッシュストレージのソリューションが必要です。現在、EasyFlash、FlashDB、OSAL_NVなど、マイクロコントローラーストレージには多くのソリューションがあります。プログラムは非常に大きく、いくつかの変数を保存する価値はありません。フラッシュ書き込みエラーを考慮することはまれです。
実際の製品では、埋め込まれた製品のフラッシュ書き込みは、さまざまな要因(バッテリー駆動、予期しない停電、温度など)の影響を受ける可能性があり、あまり安定していません。エラーが発生すると、一連の製品の問題が発生します。
他の多くのKVタイプのデータベースとは異なり、TinyFlashDBに保存する必要がある各変数には、個別のマイクロコントローラーフラッシュセクターが割り当てられ、変数の長さは不可能です。
したがって、TinyFlashDBは、いくつかの重要な変数(IAPジャンプフラグ、システムの停止時間など)の保存にのみ適しており、大規模なデータストレージには適していません(大規模なデータストレージはEasyFlashなどを使用できます)。
TinyFlashDBは、書き込みエラーの影響を検討し、その能力の中でセキュリティ保証を追求し、可能な限りリソースの職業(1KB未満のコードを占める)、および可能な限り普遍性(51、STM32L4シリーズに移植できます。
const tfdb_index_t test_index = {
. end_byte = 0x00 ,
. flash_addr = 0x4000 ,
. flash_size = 256 ,
. value_length = 2 ,
}; /* c99写法,如果编译器不支持,可自行改为c89写法 */
tfdb_addr_t addr = 0 ; /*addr cache*/
uint8_t test_buf [ TFDB_ALIGNED_RW_BUFFER_SIZE ( 2 , 1 )]; /*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:%xn" , addr );
}
addr = 0 ; /* reset addr cache, to see tfdb_get. */
result = tfdb_get ( & test_index , test_buf , & addr , & test_value );
if ( result == TFDB_NO_ERR )
{
printf ( "get ok, addr:%x, value:%xn" , addr , test_value );
}
} 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 ;構造関数:TinyFlashDBでは、API操作には指定されたパラメーターインデックスが必要です。このインデックス構造は、フラッシュのアドレス、フラッシュのサイズ、保存された変数の長さ、およびエンドフラグを保存します。この情報は、フラッシュセクターを読むときにチェックされます。
TFDB_Err_Code tfdb_get ( const tfdb_index_t * index , uint8_t * rw_buffer , tfdb_addr_t * addr_cache , void * value_to );関数関数: indexを指したセクターから指定された変数長の変数を取得します。フラッシュヘッダーのデータ検証エラーは、フラッシュを再発明しません。
パラメーターindex :TFDB操作のインデックスポインター。
パラメーターrw_buffer :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターaddr_cache : NULL 、またはアドレスキャッシュ変数へのポインターにすることができます。 addr_cacheがNULLであり、0ではない場合、 addr_cache正常に初期化されたと見なされ、フラッシュヘッダーをチェックしなくなり、データはaddr_cacheのアドレスから直接読み取られます。
Parameter value_to :データコンテンツを保存するアドレス。
返品値: 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 );関数関数: indexに指定されたセクターに指定された変数の長さが指定された変数を記述し、フラッシュヘッダーデータ検証エラーがエラーになり、フラッシュが再現されます。
パラメーターindex :TFDB操作のインデックスポインター。
パラメーターrw_buffer :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターaddr_cache : NULL 、またはアドレスキャッシュ変数へのポインターにすることができます。 addr_cacheがNULLであり、0ではない場合、 addr_cache正常に初期化されたと見なされ、フラッシュヘッダーをチェックしなくなり、データはaddr_cacheのアドレスから直接読み取られます。
Parameter value_from :保存するデータコンテンツ。
返品値: TFDB_NO_ERRが成功し、他の人は失敗します。
TFDBデュアルAPIは、 tfdb_setとtfdb_getに基づいてカプセル化されています。 tfdb dualはtfdb_setとtfdb_getを呼び出し、データの前面に2バイトのSEQを追加するため、TFDB DUALでは、最も長いサポートされているストレージ変数の長さは253バイトです。
同時に、TFDBデュアルAPIは2つのバッファーを提供する必要があり、2バイト変数の長さを増やしてから再計算するaligned_value_size使用する必要があります。
typedef struct _my_test_params_struct
{
uint32_t aa [ 2 ];
uint8_t bb [ 16 ];
} my_test_params_t ;
my_test_params_t my_test_params = {
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18
};
tfdb_dual_index_t my_test_tfdb_dual = {
. indexes [ 0 ] = {
. end_byte = 0x00 ,
. flash_addr = 0x08077000 ,
. flash_size = 256 ,
. value_length = TFDB_DUAL_VALUE_LENGTH ( sizeof ( my_test_params_t )),
},
. indexes [ 1 ] = {
. end_byte = 0x00 ,
. flash_addr = 0x08077100 ,
. flash_size = 256 ,
. value_length = TFDB_DUAL_VALUE_LENGTH ( sizeof ( my_test_params_t )),
},
};
tfdb_dual_cache_t my_test_tfdb_dual_cache = { 0 };
void my_test_tfdb_dual_func ()
{
uint32_t rw_buffer [ TFDB_DUAL_ALIGNED_RW_BUFFER_SIZE ( TFDB_DUAL_VALUE_LENGTH ( sizeof ( my_test_params_t )), 4 )];
uint32_t rw_buffer_bak [ TFDB_DUAL_ALIGNED_RW_BUFFER_SIZE ( TFDB_DUAL_VALUE_LENGTH ( sizeof ( my_test_params_t )), 4 )];
TFDB_Err_Code err ;
for ( uint8_t i = 0 ; i < 36 ; i ++ )
{
err = tfdb_dual_get ( & my_test_tfdb_dual , ( uint8_t * ) rw_buffer , ( uint8_t * ) rw_buffer_bak , & my_test_tfdb_dual_cache , & my_test_params );
if ( err == TFDB_NO_ERR )
{
printf ( "read okncache seq1:0x%04x, seq2:0x%04xnaddr1:0x%08x, addr2:0x%08xn" , my_test_tfdb_dual_cache . seq [ 0 ], my_test_tfdb_dual_cache . seq [ 1 ], my_test_tfdb_dual_cache . addr_cache [ 0 ], my_test_tfdb_dual_cache . addr_cache [ 1 ]);
}
else
{
printf ( "read err:%dn" , err );
}
my_test_params . aa [ 0 ] ++ ;
my_test_params . aa [ 1 ] ++ ;
for ( uint8_t i = 0 ; i < 16 ; i ++ )
{
my_test_params . bb [ i ] ++ ;
}
memset ( & my_test_tfdb_dual_cache , 0 , sizeof ( my_test_tfdb_dual_cache )); /* 测试无地址缓存写入 */
err = tfdb_dual_set ( & my_test_tfdb_dual , ( uint8_t * ) rw_buffer , ( uint8_t * ) rw_buffer_bak , & my_test_tfdb_dual_cache , & my_test_params );
if ( err == TFDB_NO_ERR )
{
printf ( "write okncache seq1:0x%04x, seq2:0x%04xnaddr1:0x%08x, addr2:0x%08xn" , my_test_tfdb_dual_cache . seq [ 0 ], my_test_tfdb_dual_cache . seq [ 1 ], my_test_tfdb_dual_cache . addr_cache [ 0 ], my_test_tfdb_dual_cache . addr_cache [ 1 ]);
}
else
{
printf ( "write err:%dn" , err );
}
memset ( & my_test_tfdb_dual_cache , 0 , sizeof ( my_test_tfdb_dual_cache )); /* 测试无地址缓存读取 */
}
} typedef struct _tfdb_dual_index_struct
{
tfdb_index_t indexes [ 2 ];
} tfdb_dual_index_t ;
typedef struct _tfdb_dual_cache_struct
{
tfdb_addr_t addr_cache [ 2 ];
uint16_t seq [ 2 ];
} tfdb_dual_cache_t ;構造関数:TinyFlashDB Dualでは、API操作には2つのtfdb_index_t保存index指定されたパラメーターindexが必要です。
TFDB_Err_Code tfdb_dual_get ( const tfdb_dual_index_t * index , uint8_t * rw_buffer , uint8_t * rw_buffer_bak , tfdb_dual_cache_t * cache , void * value_to );関数関数:インデックスを指したセクターから指定された変数長の変数を取得します。フラッシュヘッダーのデータ検証エラーは、フラッシュを再発明しません。
パラメーターindex :TFDB操作のインデックスポインター。
パラメーターrw_buffer :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターrw_buffer_bak :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターcache : NULLにすることはできませんtfdb_dual_cache_tで定義されたキャッシュポインターでなければなりません。 cache内のデータが合法である場合、 cacheが正常に初期化され、データがフラッシュブロックとcacheのアドレスから直接読み取られると見なされます。
Parameter value_to :データコンテンツを保存するアドレス。
返品値: TFDB_NO_ERRが成功し、他の人は失敗します。
TFDB_Err_Code tfdb_dual_set ( const tfdb_dual_index_t * index , uint8_t * rw_buffer , uint8_t * rw_buffer_bak , tfdb_dual_cache_t * cache , void * value_from );関数関数:インデックスに指定されたセクターに指定された変数の長さが指定された変数を記述し、フラッシュヘッダーデータ検証エラーがエラーになり、フラッシュが再現されます。
パラメーターindex :TFDB操作のインデックスポインター。
パラメーターrw_buffer :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターrw_buffer_bak :キャッシュを書き込み、読み取ります。すべてのフラッシュ操作は、最終的にソートされたデータをバッファにコピーし、読み取りと書き込みのためにtfdb_port_writeまたはtfdb_port_readを呼び出します。チップに書かれたデータ領域キャッシュ(4バイトアライメント、256バイトアライメントなど)の特別な要件がある場合、要件を満たす可変ポインターをこのパラメーターを介して使用するために関数に渡すことができます。少なくとも4バイトの長さ。
パラメーターcache : NULLにすることはできませんtfdb_dual_cache_tで定義されたキャッシュポインターでなければなりません。 cache内のデータが合法である場合、 cacheが正常に初期化され、データがフラッシュブロックとcacheのアドレスから直接読み取られると見なされます。
Parameter value_from :保存するデータコンテンツ。
返品値: TFDB_NO_ERRが成功し、他の人は失敗します。
上記のコードを観察すると、TinyFlashDB操作にはtfdb_index_tで定義されたindexパラメーターが必要であることがわかります。
フラッシュが初期化された後、ヘッダー情報は4バイトになるため、1、2、4、および8バイト操作のフラッシュのみがサポートされています。
ヘッダーが初期化されたときにヘッダーが読み取られるため、関数のrw_bufferによって指摘されたデータの最初の要件は、少なくとも4バイトです。最小書き込みユニットが8バイトの場合、最初の要件は少なくとも8バイトです。
| 最初のバイト | 2番目のバイト | バイト3 | 4番目のバイトおよびその他のアライメントバイト |
|---|---|---|---|
| Flash_size Higher 8ビットバイト | flash_size低い8ビットバイト | value_length | end_byte |
データが保存されると、FlashがサポートするBYTE操作に従って整列されるため、関数のrw_bufferが指し示す2番目のデータは、次の関数で計算された少なくともaligned_value_sizeバイトを必要とします。
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| first value_lengthバイト | value_length+1バイト | value_length+2バイト | その他のアライメントバイト |
|---|---|---|---|
| Value_Fromデータコンテンツ | value_from合計検証 | end_byte | end_byte |
それぞれの書き込みの後、検証のために読み上げられます。検証が失敗した場合、次のアドレスで書き込もうとします。 writesの最大数(tfdb_write_max_retry)に達するか、ヘッダー検証エラーが間違っているまで。
データを読み取るときは、計算されてチェックされます。通過しない場合、検証に合格した最新のデータが返されるか、読み取りが失敗するまで読み続けます。
データの前面にある2バイトのSEQには、0x00ff-> 0x0ff0-> 0xff00には3つの法的値のみがあります。
このサイクルは、2つのブロックの最新変数の配列を読み取ることで、フラッシュセクターに保存されている最新値であるフラッシュセクターを決定することができます。
最新の値が最初のセクターに保存される場合、次の書き込みは第2セクターで記述され、その逆も同様です。
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 ); /* 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.
* if it's over 1 byte, please be care of little endian or big endian. */
#define TFDB_VALUE_AFTER_ERASE 0xff
/* The size of TFDB_VALUE_AFTER_ERASE, only support 1 / 2 / 4.
* This value must not bigger than TFDB_WRITE_UNIT_BYTES. */
#define TFDB_VALUE_AFTER_ERASE_SIZE 1
/* 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 ;デバッグ印刷情報を削除した後、リソースは次のように占有されます。
Keil -O2コンパイル最適化オプション
Code ( inc . data ) RO Data RW Data ZI Data Debug Object Name
154 0 0 0 0 2621 tfdb_port . o
682 0 0 0 0 4595 tinyflashdb . oGCC -OSコンピレーション最適化オプション
. text . tfdb_port_read
0x00000000000039b4 0x1a ./ Drivers / TFDB / tfdb_port . o
0x00000000000039b4 tfdb_port_read
. text . tfdb_port_erase
0x00000000000039ce 0x46 ./ Drivers / TFDB / tfdb_port . o
0x00000000000039ce tfdb_port_erase
. text . tfdb_port_write
0x0000000000003a14 0x5c ./ Drivers / TFDB / tfdb_port . o
0x0000000000003a14 tfdb_port_write
. text . tfdb_check
0x0000000000003a70 0x56 ./ Drivers / TFDB / tinyflashdb . o
0x0000000000003a70 tfdb_check
. text . tfdb_init
0x0000000000003ac6 0x56 ./ Drivers / TFDB / tinyflashdb . o
0x0000000000003ac6 tfdb_init
. text . tfdb_set
0x0000000000003b1c 0x186 ./ Drivers / TFDB / tinyflashdb . o
0x0000000000003b1c tfdb_set
. text . tfdb_get
0x0000000000003ca2 0x11c ./ Drivers / TFDB / tinyflashdb . o
0x0000000000003ca2 tfdb_get 裸の金属移動ルーチン、RT-Threadを参照して使用できます。
STM32F429IGT6
CH583
QQ通信グループ:562090553