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();
}
}
寫博客不容易,需要大家多多支持。想了解更多,本人也可以提供有賞服務