Base de datos de Flash Tiny para MCU.
En el desarrollo diario de microcontroladores, siempre se necesita información. En este momento, se necesita una solución para el almacenamiento de flash microcontrolador. Actualmente, hay muchas soluciones para el almacenamiento de microcontroladores, como: EasyFlash, FlashDB, Osal_NV, etc. Sus programas son muy grandes y no vale la pena almacenar pocas variables. Y es raro considerar los errores de escritura flash.
En los productos reales, la escritura flash de productos incrustados puede verse afectada por varios factores (apagado de batería, apagado inesperado, temperatura, etc.) y no es muy estable. Una vez que ocurre un error, conducirá a una serie de problemas de productos.
A diferencia de muchas otras bases de datos de tipo KV, cada variable que debe almacenarse en TinyFlashDB se asignará un sector de flash de microcontrolador separado, y la longitud de la variable es inmutable.
Por lo tanto, TinyFlashDB solo es adecuado para almacenar varias variables clave (como la bandera de salto de IAP, el tiempo de apagado del sistema, etc.), y no es adecuado para el almacenamiento de datos a gran escala (el almacenamiento de datos a gran escala puede usar Easyflash, etc.).
TinyFlashDB fue diseñado para considerar el impacto de los errores de escritura, buscar garantías de seguridad dentro de su capacidad, la ocupación de recursos tanto como sea posible (menos de 1 kb de código ocupa) y la universalidad como sea posible (se puede portar a las computadoras de 8 bits como 51, las series STM32L4 que no pueden escribir en orden inverso, algunos microcontroladores flashes y otras computadoras de 32 bits).
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 ;Función de estructura: en TinyFlashDB, las operaciones API requieren el índice de parámetros especificado. Esta estructura de índice almacena la dirección de flash, el tamaño de flash, la longitud de las variables almacenadas y el indicador final. Esta información se verificará al leer el sector flash.
TFDB_Err_Code tfdb_get ( const tfdb_index_t * index , uint8_t * rw_buffer , tfdb_addr_t * addr_cache , void * value_to ); Función de función: Obtenga una variable con una longitud de variable especificada en el índice del sector apuntado por index . El error de verificación de datos del encabezado Flash no reinicializará Flash.
index de parámetros: puntero de índice para la operación TFDB.
Parámetro rw_buffer : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
Parámetro addr_cache : puede ser NULL , o un puntero a la variable de caché de dirección. Cuando addr_cache no es NULL y no es 0, se considera que addr_cache se ha inicializado con éxito, ya no verifica el encabezado Flash, y los datos se leen directamente desde la dirección del addr_cache .
Parámetro value_to : la dirección para almacenar el contenido de datos.
Valor de retorno: TFDB_NO_ERR tiene éxito, otros fallan.
TFDB_Err_Code tfdb_set ( const tfdb_index_t * index , uint8_t * rw_buffer , tfdb_addr_t * addr_cache , void * value_from ); Función Función: Escriba una variable con una longitud de variable especificada en el índice en el sector señalado por index , y el error de verificación de datos del encabezado Flash se errora y Flash se reinicializa.
index de parámetros: puntero de índice para la operación TFDB.
Parámetro rw_buffer : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
Parámetro addr_cache : puede ser NULL , o un puntero a la variable de caché de dirección. Cuando addr_cache no es NULL y no es 0, se considera que addr_cache se ha inicializado con éxito, ya no verifica el encabezado Flash, y los datos se leen directamente desde la dirección del addr_cache .
Parámetro value_from : el contenido de datos se almacenará.
Valor de retorno: TFDB_NO_ERR tiene éxito, otros fallan.
La API dual TFDB se encapsula en función de tfdb_set y tfdb_get . tfdb dual llamará tfdb_set y tfdb_get y agregará dos bytes de SEQ al frente de los datos, por lo que en el Dual TFDB, la longitud de la variable de almacenamiento más larga es de 253 bytes.
Al mismo tiempo, la TFDB Dual API necesita proporcionar dos buffers, y debe aligned_value_size aumente la longitud de la variable de dos bytes y luego la recalcula.
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 ; Función de estructura: en las operaciones API duales TinyFlashDB requieren el index de parámetros especificado, index almacena dos tfdb_index_t .
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 );Función de función: Obtenga una variable con una longitud de variable especificada en el índice del sector apuntado por índice. El error de verificación de datos del encabezado Flash no reinicializará Flash.
index de parámetros: puntero de índice para la operación TFDB.
Parámetro rw_buffer : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
Parámetro rw_buffer_bak : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
cache de parámetros: no puede ser NULL , debe ser un puntero en caché definido por tfdb_dual_cache_t . Cuando los datos en cache son legales, se considera que cache se ha inicializado con éxito y los datos se leen directamente desde el bloque flash y la dirección del cache .
Parámetro value_to : la dirección para almacenar el contenido de datos.
Valor de retorno: TFDB_NO_ERR tiene éxito, otros fallan.
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 );Función Función: Escriba una variable con una longitud de variable especificada en el índice en el sector señalado por índice, y el error de verificación de datos del encabezado Flash se errora y Flash se reinicializa.
index de parámetros: puntero de índice para la operación TFDB.
Parámetro rw_buffer : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
Parámetro rw_buffer_bak : Escribir y leer caché. Todas las operaciones Flash finalmente copiarán los datos ordenados en el búfer y luego llame a tfdb_port_write o tfdb_port_read para leer y escribir. Cuando el chip tiene requisitos especiales para el caché de área de datos escrita (como la alineación de 4 bytes, la alineación de 256 bytes, etc.), el puntero variable que cumple con los requisitos puede pasar a la función para su uso a través de este parámetro. Al menos 4 bytes de longitud.
cache de parámetros: no puede ser NULL , debe ser un puntero en caché definido por tfdb_dual_cache_t . Cuando los datos en cache son legales, se considera que cache se ha inicializado con éxito y los datos se leen directamente desde el bloque flash y la dirección del cache .
Parámetro value_from : el contenido de datos se almacenará.
Valor de retorno: TFDB_NO_ERR tiene éxito, otros fallan.
Observando el código anterior, puede encontrar que las operaciones de TinyFlashDB requieren index definidos por tfdb_index_t .
Después de que se inicializa Flash, la información del encabezado es de 4 bytes, por lo que solo se admite flash con operaciones de 1, 2, 4 y 8 bytes:
El encabezado se leerá cuando se inicialice el encabezado, por lo que el primer requisito para los datos apuntados por rw_buffer en la función es al menos 4 bytes. Si la unidad de escritura mínima es de 8 bytes, el primer requisito es al menos 8 bytes.
| Primer byte | Segundo byte | Byte 3 | Cuarto byte y otros bytes alineados |
|---|---|---|---|
| Flash_size bytes más altos de 8 bits | Flash_size Bajos bajos de 8 bits | value_length | end_byte |
Cuando los datos se almacenan, se alineará de acuerdo con las operaciones de bytes compatibles con Flash, por lo que los segundos datos apuntados por rw_buffer en la función se requieren al menos aligned_value_size bytes calculados en la siguiente función:
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 bytes | value_length+1 byte | value_length+2 bytes | Otros bytes alineados |
|---|---|---|---|
| Value_from Contenido de datos | Value_ de verificación de suma | end_byte | end_byte |
Después de cada escritura, se lee para la verificación. Si la verificación falla, continuará tratando de escribir en la siguiente dirección. Hasta que se alcance el número máximo de escrituras (TFDB_Write_Max_pryry) o el error de verificación del encabezado esté incorrecto.
Al leer datos, también se calculará y verificará. Si no pasa, continuará leyendo hasta que se devuelvan los últimos datos que han pasado la verificación o la lectura falla.
Solo hay 3 valores legales para el SEQ de dos bytes en la parte delantera de los datos, 0x00ff-> 0x0ff0-> 0xff00.
Este ciclo se repite, al leer el SEQ de la última variable en los dos bloques, podemos determinar qué sector flash es el último valor almacenado en el sector flash.
Cuando el último valor se almacena en el primer sector, la próxima escritura se escribirá en el segundo sector y viceversa.
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 ;Después de eliminar la información de impresión de depuración, el recurso ocupa de la siguiente manera:
Opciones de optimización de compilación 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 . oOpciones de optimización de compilación GCC -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 Rutina de migración de metales desnudos, RT-Thread se puede usar con referencia:
STM32F429IGT6
CH583
Grupo de comunicación QQ: 562090553