Крошечная база данных Flash для MCU.
В ежедневном развитии микроконтроллеров всегда необходима некоторая информация. В настоящее время необходимо решение для хранения вспышки микроконтроллера. В настоящее время существует множество решений для хранения микроконтроллеров, таких как: easyflash, flashdb, osal_nv и т. Д. Их программы очень большие и не стоят хранить несколько переменных. И редко можно рассмотреть ошибки флэш -записи.
В реальных продуктах на флэш -записи встроенных продуктов может повлиять различные факторы (аккумуляторный, неожиданный отключение электроэнергии, температура и т. Д.) И не очень стабильна. Как только возникнет ошибка, это приведет к ряду проблем с продуктом.
В отличие от многих других баз данных типа KV, каждой переменной, которая должна храниться в TinyFlashDB, будет выделена отдельный сектор вспышки микроконтроллера, а длина переменной неизменна.
Следовательно, TinyFlashDB подходит только для хранения нескольких ключевых переменных (таких как: флаг прыжка IAP, время отключения питания системы и т. Д.), И не подходит для крупномасштабного хранения данных (крупномасштабное хранение данных может использовать EasyFlash и т. Д.).
Tinyflashdb был разработан, чтобы рассмотреть влияние ошибок записи, обеспечения гарантий безопасности в рамках своей способности, ресурсной занятия как можно больше (менее 1 КБ кода занимает) и универсальность (может быть переносит на 8-битные компьютеры, такие как 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 . Ошибка проверки данных флэш-заголовка не будет повторно инициализировать Flash.
index параметра: указатель индекса для работы TFDB.
Параметр rw_buffer : написать и читать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут 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 : написать и читать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут 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 сменится, другие терпят неудачу.
Двойной API TFDB инкапсулируется на основе tfdb_set и tfdb_get . tfdb dual будет вызывать tfdb_set и tfdb_get и добавить два байта SEQ в переднюю часть данных, поэтому в Dual TFDB самая длинная длина переменной хранилища составляет 253 байта.
В то же время, двойной API TFDB должен предоставить два буфера, и его необходимо 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 параметра, index хранит два 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 );Функция функции: Получить переменную с указанной длиной переменной в индексе из сектора, указанного по индексу. Ошибка проверки данных флэш-заголовка не будет повторно инициализировать Flash.
index параметра: указатель индекса для работы TFDB.
Параметр rw_buffer : написать и читать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут tfdb_port_write или tfdb_port_read для чтения и записи. Когда чип имеет особые требования для письменного кэша области данных (например, 4-байтового выравнивания, 256-байтового выравнивания и т. Д.), Указатель переменной, который соответствует требованиям, может быть передана функции для использования через этот параметр. Не менее 4 байтов в длину.
Параметр rw_buffer_bak : написать и прочитать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут 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 : написать и читать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут tfdb_port_write или tfdb_port_read для чтения и записи. Когда чип имеет особые требования для письменного кэша области данных (например, 4-байтового выравнивания, 256-байтового выравнивания и т. Д.), Указатель переменной, который соответствует требованиям, может быть передана функции для использования через этот параметр. Не менее 4 байтов в длину.
Параметр rw_buffer_bak : написать и прочитать кэш. Все операции Flash наконец скопируют отсортированные данные в буфере, а затем вызовут tfdb_port_write или tfdb_port_read для чтения и записи. Когда чип имеет особые требования для письменного кэша области данных (например, 4-байтового выравнивания, 256-байтового выравнивания и т. Д.), Указатель переменной, который соответствует требованиям, может быть передана функции для использования через этот параметр. Не менее 4 байтов в длину.
cache параметров: не может быть NULL , это должен быть кэшированный указатель, определенный tfdb_dual_cache_t . Когда данные в cache являются законными, считается, что cache был успешно инициализирован, и данные считываются непосредственно с блока флэш -блока и адреса cache .
Параметр value_from : содержание данных для сохранения.
Возвращаемое значение: TFDB_NO_ERR сменится, другие терпят неудачу.
Наблюдая за приведенным выше кодом, вы можете обнаружить, что операции TinyFlashDB требуют параметров index , определенных tfdb_index_t .
После инициализирована вспышка, информация о заголовке составляет 4 байта, поэтому поддерживается только 1, 2, 4 и 8 байтов:
Заголовок будет прочитан, когда заголовок будет инициализирован, поэтому первое требование для данных, указанных rw_buffer в функции, составляет не менее 4 байтов. Если минимальный блок записи составляет 8 байт, первое требование составляет не менее 8 байт.
| Первый байт | Второй байт | Байт 3 | Четвертый байт и другие выровненные байты |
|---|---|---|---|
| flash_size более 8-битные байты | flash_size низкие 8-битные байты | value_length | end_byte |
Когда данные хранятся, он будет выровнен в соответствии с операциями байтов, поддерживаемых FLASH, поэтому вторые данные, указанные 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 Bytes | value_length+1 байт | value_length+2 байта | Другие выровненные байты |
|---|---|---|---|
| value_from Содержание данных | value_from um vervication | end_byte | end_byte |
После каждой записи это будет рассмотрено для проверки. Если проверка не удается, она будет продолжать пытаться написать по следующему адресу. До тех пор, пока не будет достигнуто максимальное количество записей (TFDB_WRITE_MAX_RETRY) или ошибка проверки заголовка неверна.
При чтении данных он также будет рассчитан и проверен. Если он не пройдет, он будет продолжать читать до тех пор, пока не будут возвращены последние данные, которые прошли проверку, или чтение не удастся.
В передней части данных есть только 3 юридических значения для двух байтовых SEQ, 0x00ff-> 0x0ff0-> 0xff00.
Этот цикл повторяется, прочитав SEQ последней переменной в двух блоках, мы можем определить, какой сектор флэш -сектор является последним значением, хранящимся в секторе флэш -сектора.
Когда последнее значение хранится в первом секторе, следующая запись будет написана во втором секторе, и наоборот.
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 . oВарианты оптимизации компиляции 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 Процедура миграции металлов, RT-Thread можно использовать со ссылкой:
STM32F429IGT6
CH583
QQ Communication Group: 562090553