قاعدة بيانات فلاش صغيرة لـ 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 : اكتب وقراءة ذاكرة التخزين المؤقت. ستقوم جميع عمليات الفلاش أخيرًا بنسخ البيانات المرتبة إلى المخزن المؤقت ، ثم اتصل بـ tfdb_port_write أو tfdb_port_read للقراءة والكتابة. عندما يكون لدى الشريحة متطلبات خاصة لمنطقة ذاكرة التخزين المؤقت لمنطقة البيانات المكتوبة (مثل محاذاة 4 بايت ، ومحاذاة 256 بايت ، وما إلى ذلك) ، يمكن تمرير المؤشر المتغير الذي يلبي المتطلبات إلى الوظيفة للاستخدام من خلال هذه المعلمة. على الأقل 4 بايت في الطول.
المعلمة addr_cache : يمكن أن تكون NULL ، أو مؤشر إلى متغير ذاكرة التخزين المؤقت العنوان. عندما لا يكون addr_cache NULL وليس 0 ، يُعتبر addr_cache تهيئته بنجاح ، ولم يعد التحقق من رأس الفلاش ، ويتم قراءة البيانات مباشرة من عنوان 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 تهيئته بنجاح ، ولم يعد التحقق من رأس الفلاش ، ويتم قراءة البيانات مباشرة من عنوان addr_cache .
Parameter value_from : محتوى البيانات المراد تخزينه.
قيمة الإرجاع: تنجح TFDB_NO_ERR ، والبعض الآخر يفشل.
يتم تغليف API المزدوج TFDB استنادًا إلى tfdb_set و tfdb_get . سيقوم tfdb dual باستدعاء tfdb_set و tfdb_get وإضافة بايتان من SEQ إلى مقدمة البيانات ، لذلك في TFDB Dual ، أطول طول متغير تخزين مدعوم هو 253 بايت.
في الوقت نفسه ، تحتاج واجهة برمجة تطبيقات 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 Dual ، تتطلب عمليات 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 : اكتب وقراءة ذاكرة التخزين المؤقت. ستقوم جميع عمليات الفلاش أخيرًا بنسخ البيانات المرتبة إلى المخزن المؤقت ، ثم اتصل بـ 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 .
Parameter 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 بايت _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 التحقق من مجموع | 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 مجموعة الاتصالات: 562090553