一、前言
因为sdk12使用fstorage代替了pstorage,网上能搜到的资料都用不了了,于是只能去nordic的官方论坛里面找。在论坛里面蹲了两天,终于实现了flash的存储。
二、实验平台
协议栈版本:nRF5_SDK_12.3.0_d7731ad
例程为ble_app_uart
三、实验流程
1、结构体与全局变量声明
#define DATA_SIZE 256
uint32_t m_datas[DATA_SIZE]={0,1,2,3,88,5,6,7};
uint8_t erase_flag=0;
uint8_t store_flag=0;
FS_REGISTER_CFG(fs_config_t fs_config) =
{
.callback = fs_evt_handler,// Function for event callbacks.
.num_pages = 1, // Number of physical flash pages required.
.priority = 0xFE // Priority for flash usage.
};
2、flash操作回调函数
static void fs_evt_handler(fs_evt_t const * const evt, fs_ret_t result)
{
if( (evt->id == FS_EVT_STORE) && (result == FS_SUCCESS) )
{
store_flag = 0;
printf("store_flag: %d \r\n", store_flag);
// NRF_LOG_RAW_INFO("store_flag: %d \r\n", store_flag);
}
else if( (evt->id == FS_EVT_ERASE) && (result == FS_SUCCESS) )
{
erase_flag = 0;
//NRF_LOG_RAW_INFO("erase_flag: %d \r\n", erase_flag);
printf("erase_flag: %d \r\n", erase_flag);
}
else if (result != NRF_SUCCESS)
{
printf("fstorage error and code: %d \r\n", result);
// NRF_LOG_RAW_INFO("fstorage error and code: %d \r\n", result);
}
}
3、flash功能初始(main函数中)
fs_ret_t ret = fs_init();
if( ret == FS_SUCCESS )
{
printf("fs init successful\r\n");
}
else
{
printf("fs init failed\r\n");
printf("err_code is:%d\r\n",ret);
m_flash_erase();
}
4、flash操作相关函数
uint32_t const * address_of_page(uint16_t page_num)
{
return fs_config.p_start_addr + (page_num * DATA_SIZE);
}
void m_flash_read(const uint32_t* address)
{
uint32_t* m_addr = (uint32_t*)address;
uint32_t buff[DATA_SIZE];
for(int i=0; i<DATA_SIZE; i++ )
{
buff[i] = *m_addr;
//NRF_LOG_INFO("Data: %d\r\n",m_tbd_obj.flash_test[i]);
m_addr++;
}
for(int i = 0; i< DATA_SIZE; i++)
{
printf("%d ",buff[i]);
}
printf("\r\n");
}
void m_flash_write(void)
{
fs_ret_t ret;
erase_flag=1;
// Erase one page (page 0).
ret = fs_erase(&fs_config, address_of_page(0), 1,NULL);
if (ret != FS_SUCCESS)
{
// NRF_LOG_INFO("fs_erase error\r\n");
printf("fs_erase error\r\n");
printf("err_code is:%d\r\n",ret);
}
else
{
printf("fs_erase FS_SUCCESS\r\n");
//NRF_LOG_INFO("fs_erase FS_SUCCESS\r\n");
}
while(erase_flag == 1) { power_manage(); }
store_flag=1;
ret = fs_store(&fs_config, fs_config.p_start_addr, m_datas, DATA_SIZE,NULL);
if (ret != FS_SUCCESS)
{
// NRF_LOG_INFO("fs_store error\r\n");
printf("fs_store error\r\n");
printf("err_code is:%d\r\n",ret);
}
else
{
//NRF_LOG_INFO("fs_store FS_SUCCESS\r\n");
printf("fs_store FS_SUCCESS\r\n");
}
while(store_flag == 1) { power_manage(); }
}
void m_flash_erase(void)
{
erase_flag=1;
// Erase one page (page 0).
fs_ret_t ret = fs_erase(&fs_config, address_of_page(0), 1, NULL);
if( ret != FS_SUCCESS )
{
// NRF_LOG_INFO("fs_erase error\r\n");
printf("fs_erase error\r\n");
printf("err_code is:%d\r\n",ret);
}
else
{
// NRF_LOG_INFO("fs_erase FS_SUCCESS\r\n");
printf("fs_erase FS_SUCCESS\r\n");
}
while(erase_flag == 1) { power_manage(); }
}
5、在ble_stack_init中添加sys_evt_dispatch
因为fstorage的实现是基于状态机,协议栈会分步进行flash操作。在我们erase/write的操作函数中有一个等待标志位清零的循环,这个标志位就是在flahs回调函数中进行清零的。
在main.c中添加
static void ble_stack_init(void)
{
.....
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);//添加系统事件派发
APP_ERROR_CHECK(err_code);
}
static void sys_evt_dispatch(uint32_t sys_evt)
{
ble_advertising_on_sys_evt(sys_evt);
//这函数在fstorage.c中实现
fs_sys_event_handler(sys_evt);
}
当有系统事件时,会执行fs_sys_event_handler(sys_evt)函数
void fs_sys_event_handler(uint32_t sys_evt)
{
fs_op_t * const p_op = &m_queue.op[m_queue.rp];
if (m_flags & FS_FLAG_PROCESSING)
{
// A flash operation was initiated by this module. Handle the result.
switch (sys_evt)
{
case NRF_EVT_FLASH_OPERATION_SUCCESS:
on_operation_success(p_op); //当flash操作成功时
break;
case NRF_EVT_FLASH_OPERATION_ERROR:
on_operation_failure(p_op); //当flash操作失败时
break;
}
}
else if ((m_flags & FS_FLAG_FLASH_REQ_PENDING))
{
// A flash operation was initiated outside this module.
// A callback which indicates that it has finished was received.
m_flags &= ~FS_FLAG_FLASH_REQ_PENDING;
// If there are any elements left in the queue, set FS_FLAG_PROCESSING.
if (m_queue.count > 0)
{
m_flags |= FS_FLAG_PROCESSING;
}
}
// Resume processing the queue, if necessary.
queue_process();
}
我们进入flash操作成功的分支,进入on_operation_success(fs_op_t * const p_op)
static void on_operation_success(fs_op_t * const p_op)
{
m_retry_count = 0;
switch (p_op->op_code)
{
case FS_OP_STORE:
{
uint16_t chunk_len;
if ((p_op->store.length_words - p_op->store.offset) < FS_MAX_WRITE_SIZE_WORDS)
{
chunk_len = p_op->store.length_words - p_op->store.offset;
}
else
{
chunk_len = FS_MAX_WRITE_SIZE_WORDS;
}
p_op->store.offset += chunk_len;
if (p_op->store.offset == p_op->store.length_words)
{
// The operation has finished.
send_event(p_op, FS_SUCCESS); //flash操作完成之后执行
queue_advance();
}
}
break;
case FS_OP_ERASE:
{
p_op->erase.page++;
p_op->erase.pages_erased++;
if (p_op->erase.pages_erased == p_op->erase.pages_to_erase)
{
send_event(p_op, FS_SUCCESS);
queue_advance();
}
}
break;
default:
// Should not happen.
break;
}
}
进入send_event(p_op, FS_SUCCESS)
static void send_event(fs_op_t const * const p_op, fs_ret_t result)
{
fs_evt_t evt;
memset(&evt, 0x00, sizeof(fs_evt_t));
switch (p_op->op_code)
{
case FS_OP_STORE:
evt.id = FS_EVT_STORE;
evt.store.p_data = p_op->store.p_dest;
evt.store.length_words = p_op->store.length_words;
break;
case FS_OP_ERASE:
evt.id = FS_EVT_ERASE;
evt.erase.first_page = p_op->erase.page - p_op->erase.pages_erased;
evt.erase.last_page = p_op->erase.page;
break;
default:
// Should not happen.
break;
}
evt.p_context = p_op->p_context;
p_op->p_config->callback(&evt, result); //这里就调用了之前注册的回调函数
}
四、实验结果
上电初始化之后,串口输出
fs init successful
调用m_flash_write()之后,串口输出
m_flash_write..fs_erase FS_SUCCESS
erase_flag: 0
fs_store FS_SUCCESS
store_flag: 0
这样代表了已经存储成功
调用m_flash_read(),输出
m_flash_read..0 1 2 3 88 5 6 7
如有错误,请留言。