MCU 용 작은 플래시 데이터베이스.
마이크로 컨트롤러의 일일 개발에서는 일부 정보가 항상 필요합니다. 현재 마이크로 컨트롤러 플래시 스토리지 용 솔루션이 필요합니다. 현재 EasyFlash, FlashDB, OSAL_NV 등과 같은 마이크로 컨트롤러 스토리지를위한 많은 솔루션이 있습니다. 해당 프로그램은 매우 크며 몇 가지 변수를 저장할 가치가 없습니다. 플래시 쓰기 오류를 고려하는 것은 드 rare니다.
실제 제품에서, 임베디드 제품의 플래시 쓰기는 다양한 요인 (배터리 구동, 예기치 않은 정전, 온도 등)의 영향을받을 수 있으며 안정적이지 않습니다. 오류가 발생하면 일련의 제품 문제가 발생합니다.
다른 많은 KV 유형 데이터베이스와 달리 TinyFlashDB에 저장 해야하는 각 변수에는 별도의 마이크로 컨트롤러 플래시 섹터가 할당되며 변수 길이는 불변입니다.
따라서 TinyFlashDB는 여러 주요 변수 (예 : IAP 점프 플래그, 시스템 전원 가입 시간 등)를 저장하는 데만 적합하며 대규모 데이터 저장에 적합하지 않습니다 (대규모 데이터 스토리지는 EasyFlash 등을 사용할 수 있음).
TinyflashDB는 쓰기 오류의 영향을 고려하고, 능력 내에서 보안 보장을 추구하고, 가능한 한 많은 자원 직업 (1KB 코드 점유) 및 가능한 한 보편성 (51, 51, STM32L4 시리즈, 일부 플래시 암호화 마이크로 콘 트롤러 및 기타 32 개가 구성된 구성원)으로 포팅 될 수 있습니다.
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 성공적으로 초기화 된 것으로 간주되며 더 이상 Flash 헤더를 확인하지 않으며 addr_cache 의 주소에서 직접 데이터를 읽습니다.
매개 변수 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 성공적으로 초기화 된 것으로 간주되며 더 이상 Flash 헤더를 확인하지 않으며 addr_cache 의 주소에서 직접 데이터를 읽습니다.
매개 변수 value_from : 저장할 데이터 컨텐츠.
반환 값 : TFDB_NO_ERR 성공하고 다른 사람들은 실패합니다.
TFDB 듀얼 API는 tfdb_set 및 tfdb_get 기반으로 캡슐화됩니다. tfdb dual tfdb_set 및 tfdb_get 호출하고 데이터의 전면에 SEQ의 2 바이트를 추가하므로 TFDB 듀얼에서 가장 긴 지원되는 스토리지 변수 길이는 253 바이트입니다.
동시에 TFDB 듀얼 API는 두 개의 버퍼를 제공해야하며, 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 듀얼에서 API 작업에는 지정된 매개 변수 index 필요하며 두 개의 tfdb_index_t 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 주소에서 직접 읽는 것으로 간주됩니다.
매개 변수 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 주소에서 직접 읽는 것으로 간주됩니다.
매개 변수 value_from : 저장할 데이터 컨텐츠.
반환 값 : TFDB_NO_ERR 성공하고 다른 사람들은 실패합니다.
위의 코드를 관찰하면 TinyFlashDB 작업에는 tfdb_index_t 에 의해 정의 된 index 매개 변수가 필요하다는 것을 알 수 있습니다.
플래시가 초기화 된 후 헤더 정보는 4 바이트이므로 1, 2, 4 및 8 바이트 작업으로 플래시 만 지원됩니다.
헤더는 헤더가 초기화되면 읽히므로 기능에서 rw_buffer 가 가리키는 데이터의 첫 번째 요구 사항은 4 바이트 이상입니다. 최소 쓰기 단위가 8 바이트 인 경우 첫 번째 요구 사항은 8 바이트 이상입니다.
| 첫 바이트 | 두 번째 바이트 | 바이트 3 | 네 번째 바이트 및 기타 정렬 된 바이트 |
|---|---|---|---|
| Flash_Size 더 높은 8 비트 바이트 | Flash_Size 낮은 8 비트 바이트 | value_length | end_byte |
데이터가 저장되면 플래시가 지원하는 바이트 작업에 따라 정렬되므로 기능에서 rw_buffer 가 가리키는 두 번째 데이터는 다음 기능에서 계산 된 적어도 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| 첫 번째 value_length 바이트 | value_length+1 바이트 | value_length+2 바이트 | 다른 정렬 된 바이트 |
|---|---|---|---|
| value_from 데이터 컨텐츠 | value_from sum verification | end_byte | end_byte |
각각 쓰기 후에는 검증을 위해 읽습니다. 확인이 실패하면 다음 주소에서 계속 쓰려고합니다. 최대 쓰기 수 (tfdb_write_max_retry)에 도달하거나 헤더 확인 오류가 잘못 될 때까지.
데이터를 읽을 때도 계산 및 확인됩니다. 통과하지 않으면 확인을 통과 한 최신 데이터가 반환되거나 읽기가 실패 할 때까지 계속 읽습니다.
데이터 전면에는 2 바이트 SEQ에 대해 3 가지 법적 값이 있습니다. 0x00ff-> 0x0ff0-> 0xff00.
이주기는 두 블록의 최신 변수의 서지를 읽음으로써 반복되면 플래시 섹터가 플래시 섹터에 저장된 최신 값인지 결정할 수 있습니다.
최신 값이 첫 번째 부문에 저장되면 다음 글은 두 번째 부문에 작성되고 그 반대도 마찬가지입니다.
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- 스레드는 다음과 같이 사용할 수 있습니다.
STM32F429IGT6
CH583
QQ 커뮤니케이션 그룹 : 562090553