操作系统:win10 64位
开发IDE:Keil MDK V5.26
SDK蓝牙协议栈:nRF5 SDK v12.3.0
使用NRF51822的FDS(Flash data storage)进行Flash的操作,用于存储一些掉电后需要保存的数据。如何使用呢?
(1)使用FDS,最好把SDK升级到较新的版本,如nRF5 SDK v12.3.0
(2)在sdk_config.h中,配置使能FDS,即把FDS_ENABLED 改为 1
// FDS_ENABLED - fds - Flash data storage module
//==========================================================
#ifndef FDS_ENABLED
#define FDS_ENABLED 1
#endif
(3)添加基于SDK的FDS相关的驱动文件。把 fds.c fstorage.c加入到工程中,并配置好头文件的路径。
相关驱动代码:
#include "fstorage.h"
#include "fds.h"
#define MAX_DVR_SN_LEN 16
#define NET_PARAM_ID 1 //这个ID不重复即可
#define DVR_SN_KEY 1 //KEY,也能不重复,一个ID可以有多个KEY,1,2,3...
uint8_t g_dvr_sn[MAX_DVR_SN_LEN];
//删除
bool del_dvr_sn(void)
{
static ret_code_t ret = 0;
fds_record_desc_t dvr_sn_desc = {0};
fds_find_token_t tok = {0};
ret = fds_record_find(NET_PARAM_ID, DVR_SN_KEY, &dvr_sn_desc, &tok);
if(ret == FDS_ERR_NOT_FOUND)
{
return false;
}
else
{
fds_record_delete(&dvr_sn_desc);
}
return true;
}
//设置保存
void set_dvr_sn(void)
{
static uint32_t sn_data[MAX_DVR_SN_LEN/4] = {0};
static uint8_t i = 0;
uint8_t * ptr_sn_data = NULL;
fds_record_desc_t dvr_sn_desc={0};
fds_record_chunk_t chunk;
fds_record_t record;
record.file_id = NET_PARAM_ID;
record.key = DVR_SN_KEY;
ptr_sn_data = (uint8_t *)sn_data;
for(i = 0; i < MAX_DVR_SN_LEN; i++)
{
ptr_sn_data[i] = g_dvr_sn[i];
}
chunk.p_data = sn_data;
chunk.length_words = sizeof(sn_data)/sizeof(uint32_t);
record.data.p_chunks = &chunk;
record.data.num_chunks = 1;
fds_record_write(&dvr_sn_desc, &record);
}
//读取
bool get_dvr_sn(void)
{
fds_find_token_t tok = {0};
fds_record_desc_t dvr_sn_desc = {0};
memset(g_dvr_sn, 0, sizeof(g_dvr_sn));
if(fds_record_find(NET_PARAM_ID, DVR_SN_KEY, &dvr_sn_desc, &tok) == FDS_SUCCESS)
{
uint8_t i = 0;
fds_flash_record_t record = {0};
fds_record_open(&dvr_sn_desc, &record);
uint8_t *p = (uint8_t*)record.p_data;
for(i = 0; i < MAX_DVR_SN_LEN; i++)
{
*(g_dvr_sn+i) = *(p+i);
}
fds_record_close(&dvr_sn_desc);
return true;
}
return false;
}
注意事项:
(1)FDS的使用时,需要设置一个ID与一个KEY,一个ID下面可以多个KEY,一个KEY可以对应一个值。一个ID下面多个不同的值,可以用多个KEY标记。
(2)FDS的写操作是异步的。也就是函数执行完,可能数据还没有及时的写入。因此,这里代入的值需要为全局变量地址或是static静态的。
(3)FDS最小的操作单位为4个字节,因此如果不足四个字节,需要补成4字节对齐。
(4)FDS理论上存一些较小的参数,长度最好不要太长。否则需要在sdk_config.h中设置FDS的大小与分区。
// FDS_VIRTUAL_PAGES - Number of virtual flash pages to use.
// One of the virtual pages is reserved by the system for garbage collection.
// Therefore, the minimum is two virtual pages: one page to store data and
// one page to be used by the system for garbage collection. The total amount
// of flash memory that is used by FDS amounts to @ref FDS_VIRTUAL_PAGES
// @ref FDS_VIRTUAL_PAGE_SIZE * 4 bytes.
#ifndef FDS_VIRTUAL_PAGES
#define FDS_VIRTUAL_PAGES 3
#endif
// FDS_VIRTUAL_PAGE_SIZE - The size of a virtual page of flash memory, expressed in number of 4-byte words.
// By default, a virtual page is the same size as a physical page.
// The size of a virtual page must be a multiple of the size of a physical page.
// <256=> 256
// <512=> 512
// <1024=> 1024
#ifndef FDS_VIRTUAL_PAGE_SIZE
#define FDS_VIRTUAL_PAGE_SIZE 256
#endif
(5)FDS操作可以通过fds_event_handler 回调函数,获取一些状态。
(6)如果数据较长,可能FDS写会失败,可以在前面调用 fds_gc() 进入垃圾回收后再写操作。