Nordic nRF52840 低功耗藍牙BLE 5.0新手入門指南_003------FLASH/FDS讀寫操作

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();
    }
}

寫博客不容易,需要大家多多支持。想了解更多,本人也可以提供有賞服務
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章