前言
最近开发nrf52833,需要往Flash中读写数据,发现开启蓝牙协议栈后,原有的操作寄存器方式会导致程序报错,网上看了一下,开启协议栈后,读写Flash需要用协议栈提供的特定函数,这里记录一下有无协议栈时不同的读写方式。
另外在我的开发中开启了蓝牙嗅探,读写即使用了协议栈提供的读写函数也操作失败,最后发现要先关闭嗅探才能正常写入,猜测不止是嗅探,估计广播时,读写Flash也要先关闭广播。
一、无协议栈时的读写
1、数据写入
//按字节,连续写FLASH
//注意Addr得是每一页的起始地址
void NRF_Flash_Write(uint32_t Addr,uint8_t* Data,uint32_t Lenth)
{
//擦除页
nrf_nvmc_page_erase(Addr);
nrf_delay_ms(100);
//写数据
nrf_nvmc_write_bytes(Addr,Data,Lenth);
}
2、数据读出
//按字节,连续读取FLASH
//每次读取一个字,然后转成字节
void NRF_Flash_Read(uint32_t Addr,uint8_t* Data,uint32_t Lenth)
{
uint32_t *pData,i,j,idx=0;
//要读的字个数
j=Lenth/4;
j=((Lenth%4)!=0)?j+1:j;
for(i=0;i<j;i++)
{
pData=(uint32_t*)Addr;
Data[idx++] = *pData;
Data[idx++] = (*pData)>>8;
Data[idx++] = (*pData)>>16;
Data[idx++] = (*pData)>>24;
Addr += 4;
}
}
二、有协议栈时的数据读写
使用fstorage方式,这里封装的函数,和无协议栈时的读写方式,读写的结果都是一样的,比如写入{0x01,0x02,0x03,0x04},读写结果都会是{0x01,0x02,0x03,0x04},因为考虑到了大小端问题
1、初始化
//头文件,对应的C文件也要添工程中
#include "nrf_fstorage.h"
#include "nrf_fstorage_sd.h"
//Flash读写回调
void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);
static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
{
if(p_evt->result != NRF_SUCCESS)
{
//printf("--> Event received: ERROR while executing an fstorage operation.");
return;
}
switch (p_evt->id)
{
case NRF_FSTORAGE_EVT_WRITE_RESULT:
{
//printf("--> Event received: wrote %d bytes at address 0x%x.",p_evt->len, p_evt->addr);
} break;
case NRF_FSTORAGE_EVT_ERASE_RESULT:
{
// printf("--> Event received: erased %d page from address 0x%x.",p_evt->len, p_evt->addr);
} break;
default:break;
}
}
//定义可操作的Flash空间
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
{
.evt_handler = fstorage_evt_handler, //回调
.start_addr = Sys_Info_Addr, //操作的起始地址
.end_addr = Sys_Info_Addr+0xFFF, //操作的结束地址
};
//协议栈下读写Flash初始化
void ble_fstorage_init()
{
ret_code_t err;
nrf_fstorage_api_t * p_fs_api;
p_fs_api = &nrf_fstorage_sd; //处理操作类型设置
err = nrf_fstorage_init(&fstorage, p_fs_api, NULL);//flash处理的开始地址和结束地址初始化
APP_ERROR_CHECK(err);
}
//协议栈下读写Flash反初始化
void ble_fstorage_deinit()
{
nrf_fstorage_uninit(&fstorage,NULL);
}
2、数据写入
注意先把蓝牙嗅探、广播关闭
//协议栈下,Flash写入,Addr需要是页地址的开头
void ble_fstorage_write(uint32_t Addr,uint8_t* Data,uint32_t Lenth)
{
uint32_t err;
//先擦除页
err=nrf_fstorage_erase(&fstorage,Addr,1,NULL);
APP_ERROR_CHECK(err);
nrf_delay_ms(10);
//写入数据,按字节
err = nrf_fstorage_write(&fstorage,Addr,Data,Lenth,NULL);
APP_ERROR_CHECK(err);
nrf_delay_ms(10);
}
3、数据读出
//协议栈下数据读出
void ble_fstorage_read(uint32_t Addr,uint8_t* Data,uint32_t Lenth)
{
uint32_t err;
err = nrf_fstorage_read(&fstorage,Addr,Data,Lenth);
APP_ERROR_CHECK(err);
}
4、实际使用
//协议栈初始化
void ble_init()
{
/* code begin*/
ble_fstorage_init();
/* code end*/
}
//调用协议栈提供的Flash读写函数前,要先停止广播或嗅探
ble_scan_stop();
//开启蓝牙协议栈后,要用协议栈提供的Flash读写函数
ble_fstorage_write(Sys_Info_Addr,(uint8_t *)&Sys_Info,sizeof(Sys_Info));
//读数据
ble_fstorage_read(Sys_Info_Addr,(uint8_t *)&Sys_Info,sizeof(Sys_Info));
//恢复嗅探
ble_scan_start();
三、总结
1、开启协议栈后,要用协议栈的专用读写函数
2、读写前,关闭嗅探,或广播