Nordic nRF52840 低功耗蓝牙BLE 5.0新手入门指南_003------FDS读写操作
1. 配置文件修改成自己合适的数值
NRF52840的FDS(Flash Data Storage)/FLASH数据存储单元,类似与一个小型的文件系统,方便用户操作,本文仅供新手学习使用,如果错误之处,请在评论区指出,非常感谢。
- sdk_config.h
//FDS数据存储模块使能开关(1=使能0=关闭)
#ifndef FDS_ENABLED
#define FDS_ENABLED 1
#endif
//配置虚拟页的多少,即用来存储FLash的虚拟页的个数
//nRF52840物理页是1024byte,虚拟页可以设置为1024和2048两种
//配置的总虚拟页中有一个页用来做数据交换使用,不用来存储真实数据
//FDS使用的总存储空间 = FDS_VIRTUAL_PAGES * FDS_VIRTUAL_PAGE_SIZE * 4bytes
#ifndef FDS_VIRTUAL_PAGES
#define FDS_VIRTUAL_PAGES 8
#endif
//虚拟页的大小设置,1024或者2048
#ifndef FDS_VIRTUAL_PAGE_SIZE
#define FDS_VIRTUAL_PAGE_SIZE 1024
#endif
//FDS后台设置,用协议栈(SoftDevice)时用后台模式(2=NRF_FSTORAGE_SD)
//不用协议栈,裸跑时用前台模式(1=NRF_FSTORAGE_NVMC)
#ifndef FDS_BACKEND
#define FDS_BACKEND 2
#endif
//FDS内部队列个数设置,不同任务对FLASH进行操作时,FDS避免程序互斥,采用队列的方式。
//如果频繁出现FDS_ERR_NO_SPACE_IN_QUEUES时增大这个值,
#ifndef FDS_OP_QUEUE_SIZE
#define FDS_OP_QUEUE_SIZE 4
#endif
//是否开启CRC校验,读写时加入CRC校验,避免数据存储和读取的不一致
#ifndef FDS_CRC_CHECK_ON_READ
#define FDS_CRC_CHECK_ON_READ 0
#endif
//在新写入的数据记录上执行CRC校验
//这项设置用来保证数据记录被写入FLASH后不被改变
#ifndef FDS_CRC_CHECK_ON_WRITE
#define FDS_CRC_CHECK_ON_WRITE 0
#endif
2. FLASH读写二操作
在读写更新删除FLASH之前都要先find是否有记录,如果找不到记录,就可以写入新的,找到成功就可以读取、更新和删除。
- 写入(write):写入新的内容到FLASH。
- 更新(update): FDS内部,先备份需要更新部分的页(可能是8bytes、12bytes…等要修改),然后删除,最后将备份的有效数据部分和需要写入的新数据写进去。
- carey_flash_fds.c
#include "carey_flash_fds.h"
#include "fds.h"
#include "app_timer.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
//这里定义了1个5秒的软件定时器,即我每隔5s读写一个词FLASH
#define FLASH_TIMER_TIMEOUT_INTERVAL APP_TIMER_TICKS(5000)
//定义定时器实体
APP_TIMER_DEF(m_flash_timer_id);
//文件ID和文件中的KEY,用来标识用,
//一个文件中可以有多个相同的KEY
#define CONFIG_FILE (0xABCD)
#define CONFIG_REC_KEY (0x1234)
/* Flag to check fds initialization. */
static bool volatile m_fds_initialized;
static bool volatile m_fds_start_write_flag = true;
uint32_t write_flash_buffer[4];
uint8_t padding_char = 0x11;
/**@brief Sleep until an event is received. */
static void power_manage(void)
{
#ifdef SOFTDEVICE_PRESENT
(void) sd_app_evt_wait();
#else
__WFE();
#endif
}
/**@brief Wait for fds to initialize. */
static void wait_for_fds_ready(void)
{
while (!m_fds_initialized)
{
power_manage();
}
}
static void fds_evt_handler(fds_evt_t const * p_evt)
{
switch (p_evt->id)
{
case FDS_EVT_INIT:
if (p_evt->result == FDS_SUCCESS)
{
m_fds_initialized = true;
NRF_LOG_INFO("FDS Initialized");
}
break;
case FDS_EVT_WRITE:
{
if (p_evt->result == FDS_SUCCESS)
{
NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->write.record_id);
NRF_LOG_INFO("File ID:\t0x%04x", p_evt->write.file_id);
NRF_LOG_INFO("Record key:\t0x%04x", p_evt->write.record_key);
}
} break;
case FDS_EVT_DEL_RECORD:
{
if (p_evt->result == FDS_SUCCESS)
{
NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->del.record_id);
NRF_LOG_INFO("File ID:\t0x%04x", p_evt->del.file_id);
NRF_LOG_INFO("Record key:\t0x%04x", p_evt->del.record_key);
}
} break;
default:
break;
}
}
void flash_fds_init(void)
{
ret_code_t ret;
/* Register first to receive an event when initialization is complete. */
ret = fds_register(fds_evt_handler);
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not initialize flash storage. fds_register() returned 0x%x.", ret);
return;//The maximum number of registered callbacks is reached.
}
NRF_LOG_INFO("Initializing fds...");
ret = fds_init();
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not initialize flash storage. fds_init() returned 0x%x.", ret);
return ;//storage full
}
/* Wait for fds to initialize. */
wait_for_fds_ready();
NRF_LOG_INFO("Reading flash usage statistics...");
fds_stat_t stat = {0};
ret = fds_stat(&stat);
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not read flash statistics. fds_stat() returned 0x%x.", ret);
return ;//Not initialized or null argument.
}
NRF_LOG_INFO("Found %d valid records.", stat.valid_records);
NRF_LOG_INFO("Found %d dirty records (ready to be garbage collected).", stat.dirty_records);
}
void flash_fds_data_store(void)
{
ret_code_t ret;
fds_record_t rec;
fds_record_desc_t desc;
fds_find_token_t tok;
memset(&rec, 0, sizeof(fds_record_t));
memset(&desc, 0, sizeof(fds_record_desc_t));
memset(&tok, 0, sizeof(fds_find_token_t));
//padding dump data
memset(write_flash_buffer, padding_char, sizeof(write_flash_buffer));
padding_char++;
rec.file_id = CONFIG_FILE;
rec.key = CONFIG_REC_KEY;
rec.data.p_data = &write_flash_buffer;
rec.data.length_words = (sizeof(write_flash_buffer) + 3) / sizeof(uint32_t);
NRF_LOG_HEXDUMP_DEBUG(rec.data.p_data, rec.data.length_words * 4);
ret = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
if (ret == FDS_SUCCESS)
{
// Update existing record.
ret = fds_record_update(&desc, &rec);
}
else if (ret == FDS_ERR_NOT_FOUND)// NRF_SUCCESS
{
ret = fds_record_write(&desc, &rec);
}
NRF_LOG_DEBUG("flash_fds_data_store: %s(0x%08X), %d) 0x%08X, %d", ret==NRF_SUCCESS?"SUCCESS":"FAILURE", ret,\
desc.record_id, tok.p_addr, tok.page);
switch (ret)
{
case FDS_SUCCESS:
NRF_LOG_INFO("FDS storage success");
return;
case FDS_ERR_BUSY:
case FDS_ERR_NO_SPACE_IN_QUEUES:
NRF_LOG_INFO("FDS Busy");
return ;
case FDS_ERR_NO_SPACE_IN_FLASH:
NRF_LOG_INFO("FDS Storage full");
return ;
default:
NRF_LOG_ERROR("Could not write data to flash. fds_record_{write|update}() returned 0x%x. ", ret);
return ;
}
}
void flash_fds_data_get(void)
{
ret_code_t ret;
fds_flash_record_t read_data = {0};
fds_record_desc_t desc = {0};
fds_find_token_t tok;
memset(&read_data, 0, sizeof(fds_flash_record_t));
memset(&desc, 0, sizeof(fds_record_desc_t));
memset(&tok, 0, sizeof(fds_find_token_t));
ret = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
if (ret != FDS_SUCCESS)
{
NRF_LOG_INFO("fds data get error: 0x%08X", ret);
return;
}
/* Open the record and read its contents. */
ret = fds_record_open(&desc, &read_data);
APP_ERROR_CHECK(ret);
NRF_LOG_HEXDUMP_DEBUG(read_data.p_data, read_data.p_header->length_words * 4);
NRF_LOG_INFO("Read file <File ID: 0x%04X, Key: 0x%04X>", read_data.p_header->file_id, read_data.p_header->record_key);
/* Close the record when done reading. */
ret = fds_record_close(&desc);
APP_ERROR_CHECK(ret);
}
void flash_fds_task(void)
{
if (m_fds_start_write_flag)
{
m_fds_start_write_flag = false;
flash_fds_data_get();
flash_fds_data_store();
}
}
/****************************************************************/
static void flash_timer_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
m_fds_start_write_flag = !m_fds_start_write_flag;
}
void flash_timers_start(void)
{
ret_code_t err_code;
err_code = app_timer_start(m_flash_timer_id, FLASH_TIMER_TIMEOUT_INTERVAL, NULL);
APP_ERROR_CHECK(err_code);
}
void flash_timer_init(void)
{
ret_code_t err_code;
// Create timers.
err_code = app_timer_create(&m_flash_timer_id, APP_TIMER_MODE_REPEATED, flash_timer_timeout_handler);
APP_ERROR_CHECK(err_code);
}
- carey_flash_fds.h
#ifndef __CAREY_FLASH_FDS_H
#define __CAREY_FLASH_FDS_H
#ifdef __cplusplus
extern "C" {
#endif
void flash_fds_task(void);
void flash_fds_init(void);
void flash_timers_start(void);
void flash_timer_init(void);
#ifdef __cplusplus
}
#endif
#endif /* __CAREY_FLASH_FDS_H */
- main.c
static void timers_init(void)
{
// Initialize timer module.
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
// Create timers.
flash_timer_init();
/* YOUR_JOB: Create any timers to be used by the application.
Below is an example of how to create a timer.
For every new timer needed, increase the value of the macro APP_TIMER_MAX_TIMERS by
one.
ret_code_t err_code;
err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
APP_ERROR_CHECK(err_code); */
}
/**@brief Function for starting timers.
*/
static void application_timers_start(void)
{
flash_timers_start();
/* YOUR_JOB: Start your timers. below is an example of how to start a timer.
ret_code_t err_code;
err_code = app_timer_start(m_app_timer_id, TIMER_INTERVAL, NULL);
APP_ERROR_CHECK(err_code); */
}
/**@brief Function for application main entry.
*/
int main(void)
{
bool erase_bonds = false;
// Initialize.
log_init();
timers_init();
//buttons_leds_init(&erase_bonds);
power_management_init();
ble_stack_init();
flash_fds_init();
gap_params_init();
gatt_init();
advertising_init();
services_init();
conn_params_init();
peer_manager_init();
// Start execution.
NRF_LOG_INFO("Template example started.");
application_timers_start();
advertising_start(erase_bonds);
// Enter main loop.
for (;;)
{
flash_fds_task();
idle_state_handle();
}
}
写博客不容易,需要大家多多支持。想了解更多,本人也可以提供有赏服务