NRF51822之pstorage介绍
Introduction
Persistent data storage is a useful tool for Bluetooth low energy applications that need to store exchanged information. For example, when a bonded peer configuration needs to be cached to store the bond identification, GATT Server configuration, and/or GATT Server attribute handles, persistent data storage is used.
The Persistent Storage Manager has a generic API (Persistent Storage Interface) that is used by the SDK modules for common storage access. A generic API means that SDK modules can be reused directly on other platforms. All modules using the Persistent Storage Manager are decoupled from accessing the nRF51822 flash directly, making the SDK modules easier to reuse. For example, the Device Manager can be used on processors other than nRF51822 by implementing a storage module according to the Persistent Storage Manager API for the targeted platform.
The application interface of this module is as defined in the header and should not be altered in order to preserve the other SDK modules. The interface implementation is expected to vary based on the storage solution identified for the system. Therefore, pstorage.h defines the application interface, while pstorage_platform.h is a use case and system specific file that can contain defines and routines needed for a specific implementation of the identified interface. The source file, pstorage.c shall implement the needed APIs. SDK examples include implementation of the interface using the SoftDevice APIs for flash access on the chip.
Multiple SDK modules and the application itself may be required to store data, with each module having its own data size requirements. Therefore, this module allows registering various block size and block count, each with a separate event handler that is notified of the flash access results.

Memory layout
The pstorage_platform.h file contains the information defining where the application data is stored in flash. Generally, the rules are as follows:
- If no bootloader is present on the device, the application data is stored at the top of the flash memory. The 512 kB flash memory has a range of 0x00000000 to 0x00080000 in the memory map. The last page (addresses 0x7F000 to 0x7FFFF) is the internal pstorage swap page. If there are two pages reserved for the application data, it is two pages below the pstorage swap page in the memory map (addresses 7D000 to 7EFFF), see the pstorage_platform.h defines (PSTORAGE_NUM_OF_PAGES constant). When there is no bootloader and the value of PSTORAGE_NUM_OF_PAGES is 2, then the application data is stored at 0x7D000. The memory content can be read in the command prompt by using:
nrfjprog –memrd 0x0007D000 –n 8192
- If the device manager is used and is initialized, it will use one flash page. If the device manager is initialized before calling pstorage_register for your application data, the device manager will use the first page (starting with address 0x7D000) and the application data will be stored in the second page (starting with address 0x7E000). For details see the figure below.

- When a bootloader is present, it is located at the top of the flash memory with the application data it in the memory map, as Memory layout. For the bootloader in the SDK release, its start address is 0x7B000. To check the location yourself, you can read out the bootloader start address from UICR with:
nrfjprog –memrd 0x10001014 –n 4
If the start address of the bootloader is 0x7B000, then the swap page start address is at 0x7B000-0x1000=0x7A000 and the two pages of application data are located from 0x7A000-0x2000=0x78000 to 0x79FFF. The memory content of the two application data pages can be read with:
nrfjprog –memrd 0x00078000 –n 8192
Application Interface Overview
Any SDK or application component that is required to store its data registers with the module using the pstorage_register, will at the time of registration request the number of blocks of storage needed. The interface is designed to be asynchronous and the application is expected to register a callback to know the result of a storage access operation. Identified storage access operations include load, store, and clear. Once the application is successfully registered, the application is assigned a handle for all future operations needed for accessing these storage blocks. This handle is abstracted by pstorage_handle_t (in the platform-specific header file).
- Warning
- Before accessing any of the module APIs, the module shall be initialized using the Initialization. This initialization should be performed once.
- Note
- To implement the interface included in the example, the SoftDevice should be enabled and the scheduler (if used) should be initialized prior to initializing this module.
The application does not have to remember a handle or an identifier for each block. Instead, it needs to remember only one identifier for all the blocks. When a reference to a specific block for flash access is required, pstorage_block_identifier_get API shall be used to get a block specific handle. The base handle and block number starting from 0 are provided as input to the API.
As mentioned earlier, an asynchronous interface is defined for storage access since storing data and clearing data can take time. However, data that is to be stored is not copied by the implementation included in the SDK. Therefore, the data source provided for the store operation using the Store Data API expects resident memory. This means that the memory the data source for this API points to should not be reused or freed unless the client is notified by the asynchronous notification callback registered with the module upon completion of a store operation.
Initialization
The storage module must be initialized before using any other API of the module.
uint32_t retval; retval = pstorage_init(); if(retval == NRF_SUCCESS) { // Module initialization successful. } else { // Initialization failed, take corrective action. }
Registration
A module that requires storage must register with the storage module in order to allocate storage blocks for data. The application must register the asynchronous event notification handler, number of blocks, and block size which should be in range of PSTORAGE_MIN_BLOCK_SIZE and PSTORAGE_MAX_BLOCK_SIZE. A reference handle is given to the application once registration is successful and is remembered by the application to reference the storage blocks.
pstorage_handle_t handle; pstorage_module_param_t param; uint32_t retval; param.block_size = ; param.block_count = ; param.cb = example_cb_handler; retval = pstorage_register(¶m, &handle); if (retval == NRF_SUCCESS) { // Registration successful. } else { // Failed to register, take corrective action. }
- Note
- The application is provided here with a single handle for all blocks and a dedicated handle for each block. This saves the application from having to remember too many handles. The handle provided to the application is referred to as the base handle for the blocks allocated. The application shall use pstorage_block_identifier_get to acquire a specific block reference.
Get Block Identifier
This API provides a specific block reference to the application in allocated blocks. Allocated blocks are identified by the base block identifier provided at the time of registration. Block offset is indexed starting from zero to (number of blocks allocated - 1).
This API shall be called before a load or store operation to a specific block.
pstorage_handle_t base_handle; pstorage_handle_t block_handle; uint32_t retval; . . . // Registration successfully completed, base_handle is identifier for allocated blocks. . . . // Request to get identifier for 3rd block. retval = pstorage_block_identifier_get(&base_handle, , &block_handle); if (retval == NRF_SUCCESS) { // Get Block Identifier successful. } else { // Failed to get block id, take corrective action. }
Load Data
This API is used to read data from a storage block. It is permitted to read a part of the block using the offset field. The application should ensure that the destination has enough memory to copy data from the storage block to the destination pointer provided in the API.
- Note
- The block size and offset in load and store should be a multiple of word size (4 bytes). To get the block specific identifier Get Block Identifier API shall be used before this API.
pstorage_handle_t block_handle; uint8_t dest_data[]; uint32_t retval; // Request to read 4 bytes from block at an offset of 12 bytes. retval = pstorage_load(dest_data, &block_handle, , ); if (retval == NRF_SUCCESS) { // Load successful. Consume data. } else { // Failed to load, take corrective action. }
- Note
- The SDK implementation requires the offset and size to be a multiple of word size (4 bytes) and will not generate a success or failure event. The API return value determines the result of this operation.
Store Data
This API is used to write data to a storage block. It is permitted to write only a part of the block using the offset field. The application cannot free or reuse the memory that is the source of data until this operation is complete. The event notified using a registered callback will indicate when this operation is complete. The event result indicates whether the operation was successful or not.
- Note
- Block size and offset in load and store should be a multiple of word size (4 bytes). To get a specific block identifier, Get Block Identifier API should be used before this API.
pstorage_handle_t block_handle; uint8_t source_data[]; uint32_t retval; // Request to write 8 bytes to block at an offset of 20 bytes. retval = pstorage_store(&block_handle, source_data, , ); if (retval == NRF_SUCCESS) { // Store successfully requested. Wait for operation result. } else { // Failed to request store, take corrective action. } . . . // Event Notification Handler. static void example_cb_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len) { switch(op_code) { . . . case PSTORAGE_LOAD_OP_CODE: if (result == NRF_SUCCESS) { // Store operation successful. } else { // Store operation failed. } // Source memory can now be reused or freed. break; . . . } }
- Note
- Flash memory is unreliable when writing to a block already containing data. A clear operation is needed because the SDK implementation does not clear the blocks before writing to them. The application, not the storage module, must perform a clear operation before new data is written to the block.
Update Data
This API is used to update data in storage blocks. The application cannot free or reuse the memory that is the source of data until this operation is complete. The event notified using a registered callback will indicate when this operation is complete. The event result indicates whether the operation was successful or not.
pstorage_handle_t base_handle; uint8_t source_data[]; uint32_t retval; // Request update of one block. Block size is 16 bytes. retval = pstorage_update(&base_handle, source_data, , ); if (retval == NRF_SUCCESS) { // Update successfully requested. Wait for operation result. } else { // Failed to request update, take corrective action. } . . . // Event Notification Handler. static void example_cb_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len) { switch(op_code) { . . . case PSTORAGE_UPDATE_OP_CODE: if (result == NRF_SUCCESS) { // Update operation successful. } else { // Update operation failed. } break; . . . } }
Clear Data
This API is used to clear data in storage blocks. The event notified using a registered callback will indicate when this operation is complete. The event result indicates whether the operation was successful or not.
The size requested to be erased has to be equal or a multiple of the block size.
pstorage_handle_t base_handle; uint32_t retval; // Request clearing of all blocks in the module. 32 blocks each with 16 bytes in size. retval = pstorage_clear(&base_handle, * ); // Request clearing of one block where block size is 16 bytes. retval = pstorage_clear(&base_handle, ); if (retval == NRF_SUCCESS) { // Clear successfully requested. Wait for operation result. } else { // Failed to request clear, take corrective action. } . . . // Event Notification Handler. static void example_cb_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len) { switch(op_code) { . . . case PSTORAGE_CLEAR_OP_CODE: if (result == NRF_SUCCESS) { // Clear operation successful. } else { // Clear operation failed. } break; . . . } }
Get Status
The Persistent Storage Manager uses the pstorage_access_status_get API to communicate to an application how many storage access operations are pending. This is particularly useful when you want to enter power off mode or want to enter a radio intense operation, but before doing so, want to ensure that the storage operations are complete.
uint32_t retval; uint32_t count; // Request clearing of blocks retval = pstorage_access_status_get(&count); ) { // No pending operations, safe to power off or enter radio intense operations. } else { // Storage access pending, wait! }
Raw Mode
Certain use cases require complete control of the entire flash region and do not have typical storage requirements. The storage module then provisions for one application to be registered with it in 'raw' mode. In raw mode, the application is responsible for conceptualizing the flash region as blocks and their management. Dedicated APIs, register, store, and clear are provided to distinguish raw mode from the normal mode. Raw mode APIs have a similar signature to the normal mode.
Because this is not a typical use case, raw mode is included for only a few applications like the DFU, and by default is disabled. It is included only if PSTORAGE_RAW_MODE_ENABLE is defined in the pstorage_platform.h header.
Specifics and limitations of the SDK implementation
Additional requirements and a few limitations exist when implementing the example included. Some have already been mentioned but the following is a summarized list with more detailed information.
General:
- The SoftDevice and scheduler must be initialized first before initializing the Persistent Storage Module. Modules that use this storage module shall then be initialized after the storage module.
- Block size and offset in load, store, and update shall be a multiple of word size (4 bytes).
- Module APIs are not thread-safe or re-entrant.
- The application is expected to ensure that when a System OFF is issued, flash access is not ongoing or queued with the module.
- Power off is not handled by the module. Therefore, a power off when a flash operation is on-going or pending results in a loss of data.
- Registering for system events and passing them on to the pstorage module using the pstorage_sys_event_handler is mandatory for the module to function as expected. The code snippet below demonstrates what an application needs to do.
/**@brief Function for dispatching a system event to interested modules. @details This function is called from the System event interrupt handler after a system event has been received. @param[in] sys_evt System stack event. */ static void sys_evt_dispatch(uint32_t sys_evt) { pstorage_sys_event_handler(sys_evt); } /**@brief BLE stack initialization. @details Initializes the SoftDevice and the stack event interrupt. */ static void ble_ant_stack_init(void) { // Initialize SoftDevice SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false); // Subscribe for BLE events. uint32_t err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); APP_ERROR_CHECK(err_code); // Register with the SoftDevice handler module for System events. err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch); APP_ERROR_CHECK(err_code); }
Registration:
- Registration of a new module shall use a block size which is a multiple of word size (4 bytes).
Store:
- Writing data to blocks that already have stored data is unreliable. The application must clear the blocks before writing new data to them.
- No intermediate copy is made of the source data that will be stored in flash. The application cannot free or reuse the memory that is the data source until this operation is complete. The event notification callback notifies when this operation is complete.
Update:
- When using the update routine, the Persistent Storage Manager will use a swap area to conserve the blocks not affected. The data page is backed up in the swap area before it is erased, then the non affected blocks are copied back before the updated block is stored. It is not possible to update multiple blocks in one API call. The module detects if backing up the page is needed or not and optimizes accordingly.
- No intermediate copy is made of the source data that is to be stored in flash. The application cannot free or reuse the memory that is the data source until this operation is complete. The event notification callback notifies on the completion of this operation.
- The update operation is time intensive, so developer discretion is advised. The application should be tolerant to this.
Clear:
- When using the clear operation the Persistent Storage Manager will use a swap area to conserve the blocks not affected. The data page is backed up in the swap area, then erased, and the non affected blocks are copied back.
- The size parameter must be equal to or a multiple of the block size expressed in number of bytes.
- Clear operation is time intensive, so developer discretion is advised. The application should be tolerant to this.
Technical implementation details
The figure below illustrates the top level state transition diagram of the Persistent Storage Manager.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state when executing a use case which operates only within 1 flash page.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state when executing a use case which operates across multiple pages and only head restore is required.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state when executing use case which operates across 2 pages and both head and tail restore is required.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state when executing a use case which operates across => 3 pages and both the head and tail restore is required.

The figure below illustrates the internal state transition diagram of the DATA ERASE WITH SWAP composite state when executing a use case which operates across => 2 pages and the tail restore is required.

NRF51822之pstorage介绍的更多相关文章
- nRF51822之pstorage使用摘要
https://devzone.nordicsemi.com/question/15271/how-can-i-write-10kb-of-data-to-internal-flash/?answer ...
- NRF51822之GPIOTE介绍
Note This library is obsolete and should not be used in new designs. Instead, you should use GPIOTE ...
- nrf51822微信开发2:[转]airkiss/airsync介绍
"微信蓝牙"专题共分为8部分 1.airkiss/airsync介绍 2.eclipes的j2ee软件使用教程 3.微信公众号使用Dome(airkiss/airsync) 4.新 ...
- [专业名词·硬件] 2、DC\DC、LDO电源稳压基本常识(包含基本原理、高效率模块设计、常见问题、基于nRF51822电源管理模块分析等)·长文
综述先看这里 第一节的1.1简单介绍了DC/DC是什么: 第二节是关于DC/DC的常见的疑问答疑,非常实用: 第三节是针对nRF51822这款芯片电源管理部分的DC/DC.LDO.1.8的详细分析,对 ...
- [nRF51822] 4、 图解nRF51 SDK中的Schedule handling library 和Timer library
:nRF51822虽然是一个小型的单片机,但是能真正达到任意调用其官方驱动以及BLE协议栈的人还是奇缺的.据我所见,大都拿官方给的一个冗长的蓝牙低功耗心率计工程改的.之前我对于这个工程进行log跟踪, ...
- [nRF51822] 2、D-BUG之诗
4线SPI彩屏局部刷屏偏移解决 ——原来我早已经在成功的旁边了 最近在研究用低速.低RAM的单片机来驱动小LCD或TFT彩屏实现动画效果 首先我用一个16MHz晶振的m0内核的8位单片机nRF5182 ...
- NRF51822之GPIOTE使用
---恢复内容开始--- 在上篇介绍nrf51822的GPIOTE http://www.cnblogs.com/libra13179/p/5336580.html 我们现在开始下水游泳. /** @ ...
- 使用nRF51822/nRF51422创建一个简单的BLE应用 ---入门实例手册(中文)之五
5应用测试 需要一个USB dongle与开发板evaluation kit,并配合Master Control Panel软件,以用于测试BLE应用.前期的准备工作在<nRF51822 Eva ...
- [nRF51822] 16、nRF51822的随机数生成器,及随机数生成器的一些知识(可以帮您补补随机数发生器的知识)
1.前言 随机数生成器在通信.加密.图像传输等领域应用广泛,且一般起到关键性作用.我在最近设计的一个近场射频通信协议的碰撞避退算法的过程中,便对此有深深体会. 2.伪随机数发生器 随机数发生器一般包括 ...
随机推荐
- 安卓通过putExtra传递数据的几种方式
通过intent传递数据时,使用以下代码报错: hMap<string, object=""> map=(Map<string, object="&qu ...
- Xamarin如何生成Android项目的APK
Xamarin如何生成Android项目的APK 首先需要选择Release模式生成项目.然后从“生成”菜单中选择Export Android Package命令,就可以导出APK包.APK保存在An ...
- 贪心/字符串处理 Codeforces Round #291 (Div. 2) A. Chewbaсca and Number
题目传送门 /* WA了好几次,除了第一次不知道string不用'\0'外 都是欠考虑造成的 */ #include <cstdio> #include <cmath> #in ...
- 使用“Empty 模式”改进 Null Object
概述 Null Object 是Martin 大师提出的一种重构手段,其思想就是通过多态(派生一个Null对象)来减少逻辑(if … then …else)的判断. 而.NET中已经有Null Obj ...
- 基于Extjs的web表单设计器 第七节——取数公式设计之取数公式的使用
基于Extjs的web表单设计器 基于Extjs的web表单设计器 第一节 基于Extjs的web表单设计器 第二节——表单控件设计 基于Extjs的web表单设计器 第三节——控件拖放 基于Extj ...
- BZOJ4134 : ljw和lzr的hack比赛
设$f[x]$为$x$子树里的子游戏的sg值,$h[x]$为$x$所有儿子节点$f[x]$的异或和,则: $f[x]=mex(y到x路径上所有点的h的异或和\ xor\ y到x路径上所有点的f的异或和 ...
- 【wikioi】1033 蚯蚓的游戏问题(费用流)
http://wikioi.com/problem/1033/ 这题也是很水的费用流啊,同之前那题一样,拆点然后建边,容量为1,费用为点权.然后建个源连第一行每个点,容量为1,费用为0,然后最后一行每 ...
- asp.net 微信企业号办公系统-流程设计--流程步骤设置-事件设置
事件设置是设置当前步骤在提交前后或退回前后要执行的一些操作(该事件为服务器事件). 事件格式为:dll名称.命名空间名称.类名.方法名,这里不需要写括号和参数,处理时会自动带上当前流程实例的相关参数. ...
- Brief introduction to Scala and Breeze for statistical computing
Brief introduction to Scala and Breeze for statistical computing 时间 2013-12-31 03:17:19 Darren Wilk ...
- Ubuntu 14.04 AMD 64位 下 Android Studio 的安装
Ubuntu 14.04 AMD 64位 下 Android Studio 的安装 作者:yoyoyosiyu 邮箱:yoyoyosiyu@163.com 时间:2015年8月25日 Android ...