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

写博客不容易,需要大家多多支持。想了解更多,本人也可以提供有赏服务
在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值