1079 lines
54 KiB
C
1079 lines
54 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief NVM3 API definition (Generic).
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* SPDX-License-Identifier: Zlib
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#ifndef NVM3_GENERIC_H
|
|
#define NVM3_GENERIC_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
|
|
#include "sl_status.h"
|
|
#include "ecode.h"
|
|
#include "nvm3_hal.h"
|
|
|
|
#if defined(NVM3_SECURITY)
|
|
#include "nvm3_hal_crypto.h"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup nvm3
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
#define ECODE_NVM3_OK (SL_STATUS_OK) ///< Success return value
|
|
#define ECODE_NVM3_ERR_ALIGNMENT_INVALID (SL_STATUS_NVM3_ALIGNMENT_INVALID) ///< Invalid data alignment
|
|
#define ECODE_NVM3_ERR_SIZE_TOO_SMALL (SL_STATUS_NVM3_SIZE_TOO_SMALL) ///< Not enough NVM memory specified
|
|
#define ECODE_NVM3_ERR_NO_VALID_PAGES (SL_STATUS_NVM3_NO_VALID_PAGES) ///< Initialization aborted, no valid page found
|
|
#define ECODE_NVM3_ERR_PAGE_SIZE_NOT_SUPPORTED (SL_STATUS_NVM3_PAGE_SIZE_NOT_SUPPORTED) ///< The page size is not supported
|
|
#define ECODE_NVM3_ERR_OBJECT_SIZE_NOT_SUPPORTED (SL_STATUS_NVM3_OBJECT_SIZE_NOT_SUPPORTED) ///< The object size is not supported
|
|
#define ECODE_NVM3_ERR_STORAGE_FULL (SL_STATUS_FULL) ///< No more NVM space available
|
|
#define ECODE_NVM3_ERR_NOT_OPENED (SL_STATUS_NOT_INITIALIZED) ///< The module has not been successfully opened
|
|
#define ECODE_NVM3_ERR_OPENED_WITH_OTHER_PARAMETERS (SL_STATUS_NVM3_OPENED_WITH_OTHER_PARAMETERS) ///< The module has already been opened with other parameters
|
|
#define ECODE_NVM3_ERR_PARAMETER (SL_STATUS_INVALID_PARAMETER) ///< Illegal parameter
|
|
#define ECODE_NVM3_ERR_KEY_INVALID (SL_STATUS_INVALID_KEY) ///< Invalid key value
|
|
#define ECODE_NVM3_ERR_KEY_NOT_FOUND (SL_STATUS_NOT_FOUND) ///< Key not found
|
|
#define ECODE_NVM3_ERR_OBJECT_IS_NOT_DATA (SL_STATUS_NVM3_OBJECT_IS_NOT_DATA) ///< Trying to access a data object which is currently a counter object
|
|
#define ECODE_NVM3_ERR_OBJECT_IS_NOT_A_COUNTER (SL_STATUS_NVM3_OBJECT_IS_NOT_A_COUNTER) ///< Trying to access a counter object which is currently a data object
|
|
#define ECODE_NVM3_ERR_ERASE_FAILED (SL_STATUS_FLASH_ERASE_FAILED) ///< Erase failed
|
|
#define ECODE_NVM3_ERR_WRITE_DATA_SIZE (SL_STATUS_NVM3_WRITE_DATA_SIZE) ///< The object is too large
|
|
#define ECODE_NVM3_ERR_WRITE_FAILED (SL_STATUS_FLASH_PROGRAM_FAILED) ///< Error in the write operation
|
|
#define ECODE_NVM3_ERR_READ_DATA_SIZE (SL_STATUS_NVM3_READ_DATA_SIZE) ///< Trying to read with a length different from actual object size
|
|
#define ECODE_NVM3_ERR_READ_FAILED (SL_STATUS_OBJECT_READ) ///< Error in the read operation
|
|
#define ECODE_NVM3_ERR_INIT_WITH_FULL_NVM (SL_STATUS_NVM3_INIT_WITH_FULL_NVM) ///< The module was opened with a full NVM
|
|
#define ECODE_NVM3_ERR_RESIZE_PARAMETER (SL_STATUS_NVM3_RESIZE_PARAMETER) ///< Illegal parameter
|
|
#define ECODE_NVM3_ERR_RESIZE_NOT_ENOUGH_SPACE (SL_STATUS_NVM3_RESIZE_NOT_ENOUGH_SPACE) ///< Not enough NVM to complete resize
|
|
#define ECODE_NVM3_ERR_ERASE_COUNT_ERROR (SL_STATUS_NVM3_ERASE_COUNT_ERROR) ///< Erase counts are not valid
|
|
#define ECODE_NVM3_ERR_INT_WRITE_TO_NOT_ERASED (SL_STATUS_NVM3_WRITE_TO_NOT_ERASED) ///< Write to memory that is not erased
|
|
#define ECODE_NVM3_ERR_INT_ADDR_INVALID (SL_STATUS_NVM3_INVALID_ADDR) ///< Invalid NVM address
|
|
#define ECODE_NVM3_ERR_INT_KEY_MISMATCH (SL_STATUS_NVM3_KEY_MISMATCH) ///< Key validation failure
|
|
#define ECODE_NVM3_ERR_INT_SIZE_ERROR (SL_STATUS_NVM3_SIZE_ERROR) ///< Size mismatch error
|
|
#define ECODE_NVM3_ERR_INT_EMULATOR (SL_STATUS_NVM3_EMULATOR) ///< Emulator error
|
|
#define ECODE_NVM3_ERR_INT_TEST (SL_STATUS_FAIL) ///< Internal Test error
|
|
#define ECODE_NVM3_ERR_NVM_ACCESS (SL_STATUS_NVM3_NVM_ACCESS) ///< A NVM function call was failing
|
|
#define ECODE_NVM3_ERR_ADDRESS_RANGE (SL_STATUS_NVM3_INVALID_ADDR) ///< Address and size is out of range of available NVM
|
|
|
|
/***************************************************************************//**
|
|
* @brief Definitions of NVM3 constraints.
|
|
******************************************************************************/
|
|
#define NVM3_MIN_PAGE_SIZE 4096U ///< The minimum page size supported
|
|
#define NVM3_MAX_OBJECT_SIZE_LOW_LIMIT 204U ///< The minimum value for the maximum object size
|
|
#define NVM3_MAX_OBJECT_SIZE_HIGH_LIMIT 4096U ///< The maximum value for the maximum object size
|
|
#define NVM3_MAX_OBJECT_SIZE_DEFAULT 1900U ///< The default value for the maximum object size
|
|
|
|
#if !defined(NVM3_MAX_OBJECT_SIZE)
|
|
#define NVM3_MAX_OBJECT_SIZE NVM3_MAX_OBJECT_SIZE_DEFAULT ///< The maximum object size
|
|
#endif
|
|
|
|
#if defined(NVM3_SECURITY)
|
|
#define NVM3_NONCE_SIZE (12U)
|
|
#define NVM3_GCM_TAG_SIZE (4U)
|
|
#endif
|
|
|
|
/***************************************************************************//**
|
|
* @brief NVM3 static data definition helper macro for applications using linker
|
|
* script placement of the NVM memory area. This macro exports the section 'name'_section
|
|
* to the linker. The user must place the section name in a linker script
|
|
* at an address aligned with the page size of the underlying memory system. The size of
|
|
* the NVM area must be a multiple of the page size.
|
|
* @n This macro also allocates the static NVM3 cache.
|
|
* @n Use this macro with @ref NVM3_DEFINE_SECTION_INIT_DATA() to create initialization
|
|
* data for @ref nvm3_open(). See @ref nvm3_example section for usage examples.
|
|
******************************************************************************/
|
|
#define NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize) \
|
|
static nvm3_CacheEntry_t name##_cache[cacheSize]; \
|
|
static const uint8_t name##_nvm[nvmSize] \
|
|
SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
|
|
|
|
/***************************************************************************//**
|
|
* @brief NVM3 initialization data helper macro to be used with @ref
|
|
* NVM3_DEFINE_SECTION_STATIC_DATA(). The @p name parameter in both macros must
|
|
* match.
|
|
* @n Call @ref nvm3_open() after this macro to initialize NVM3. See @ref
|
|
* nvm3_example section for code examples.
|
|
******************************************************************************/
|
|
#if defined(NVM3_SECURITY)
|
|
#define NVM3_DEFINE_SECTION_INIT_DATA(name, flashHandle, cryptoHandle) \
|
|
nvm3_Init_t name = \
|
|
{ \
|
|
(nvm3_HalPtr_t)name##_nvm, \
|
|
sizeof(name##_nvm), \
|
|
name##_cache, \
|
|
sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
|
|
NVM3_MAX_OBJECT_SIZE, \
|
|
0, \
|
|
flashHandle, \
|
|
cryptoHandle, \
|
|
NVM3_DEFAULT_SECURITY_TYPE, \
|
|
}
|
|
#else
|
|
#define NVM3_DEFINE_SECTION_INIT_DATA(name, flashHandle) \
|
|
nvm3_Init_t name = \
|
|
{ \
|
|
(nvm3_HalPtr_t)name##_nvm, \
|
|
sizeof(name##_nvm), \
|
|
name##_cache, \
|
|
sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
|
|
NVM3_MAX_OBJECT_SIZE, \
|
|
0, \
|
|
flashHandle, \
|
|
}
|
|
#endif
|
|
|
|
#define NVM3_KEY_INVALID 0xFFFFFFFFU ///< Invalid key identifier
|
|
#define NVM3_KEY_SIZE 20U ///< Unique object key identifier size in number of bits
|
|
#define NVM3_KEY_MASK ((1U << NVM3_KEY_SIZE) - 1U) ///< Unique object key identifier mask
|
|
#define NVM3_KEY_MIN 0U ///< Minimum object key value
|
|
#define NVM3_KEY_MAX NVM3_KEY_MASK ///< Maximum object key value
|
|
|
|
#define NVM3_OBJECTTYPE_DATA 0U ///< The object is data
|
|
#define NVM3_OBJECTTYPE_COUNTER 1U ///< The object is a counter
|
|
|
|
/// @brief The data type for object keys. Only the 20 least significant bits are used.
|
|
typedef uint32_t nvm3_ObjectKey_t;
|
|
|
|
/// @brief The datatype for each cache entry. The cache must be an array of these.
|
|
typedef struct nvm3_CacheEntry {
|
|
nvm3_ObjectKey_t key; ///< key
|
|
void *ptr; ///< pointer
|
|
} nvm3_CacheEntry_t;
|
|
|
|
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
|
|
|
typedef struct nvm3_Cache {
|
|
nvm3_CacheEntry_t *entryPtr; // Pointer to cache entry structure
|
|
size_t entryCount; // Total cache size
|
|
bool overflow; // Cache overflow status
|
|
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
|
|
size_t usedCount; // Number of objects in cache
|
|
#endif
|
|
} nvm3_Cache_t;
|
|
|
|
typedef struct nvm3_ObjFragDetail {
|
|
void *adr;
|
|
uint16_t len;
|
|
uint8_t typ;
|
|
} nvm3_ObjFragDetail_t;
|
|
|
|
#if defined(NVM3_SECURITY)
|
|
typedef enum {
|
|
NVM3_SECURITY_INVALID = 0,
|
|
NVM3_SECURITY_NONE = 1,
|
|
NVM3_SECURITY_AEAD = 2,
|
|
NVM3_SECURITY_ENC = 3
|
|
} nvm3_SecurityType_t;
|
|
#endif
|
|
|
|
typedef struct {
|
|
nvm3_HalPtr_t nvmAdr; // NVM address
|
|
size_t nvmSize; // NVM size
|
|
nvm3_Cache_t cache; // Cache management data
|
|
size_t maxObjectSize; // The maximum object size in bytes
|
|
size_t repackHeadroom; // The size difference between the user and forced repacks
|
|
size_t totalNvmPageCnt; // The total number of NVM pages
|
|
size_t validNvmPageCnt; // The number of valid NVM pages
|
|
size_t fifoFirstIdx; // FIFO bottom page
|
|
void *fifoFirstObj; // The first object location
|
|
void *fifoNextObj; // The next free object location
|
|
size_t unusedNvmSize; // The size of the unused NVM
|
|
bool hasBeenOpened; // Open status
|
|
size_t minUnused; // The minimum value of the unusedNvmSize
|
|
const nvm3_HalHandle_t *halHandle; // HAL handle
|
|
nvm3_HalInfo_t halInfo; // HAL information
|
|
#if defined(NVM3_SECURITY)
|
|
const nvm3_HalCryptoHandle_t *halCryptoHandle; // HAL crypto handle
|
|
nvm3_SecurityType_t secType; // Security type
|
|
#endif
|
|
} nvm3_Handle_t;
|
|
|
|
/// @endcond
|
|
|
|
/// @brief NVM3 initialization data.
|
|
typedef struct {
|
|
nvm3_HalPtr_t nvmAdr; ///< NVM memory area base address
|
|
size_t nvmSize; ///< NVM memory area size in bytes
|
|
nvm3_CacheEntry_t *cachePtr; ///< A pointer to cache
|
|
size_t cacheEntryCount; ///< The size of the cache in number of elements
|
|
size_t maxObjectSize; ///< The maximum object size in bytes
|
|
size_t repackHeadroom; ///< The size difference between the user and forced repacks
|
|
const nvm3_HalHandle_t *halHandle; ///< HAL handle
|
|
#if defined(NVM3_SECURITY)
|
|
const nvm3_HalCryptoHandle_t *halCryptoHandle; ///< HAL crypto handle
|
|
nvm3_SecurityType_t secType; ///< Security type
|
|
#endif
|
|
} nvm3_Init_t;
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Open an NVM3 driver instance, which is represented by a handle
|
|
* keeping information about the state. A successful open will initialize
|
|
* the handle and the cache with information about the objects already in the
|
|
* NVM-memory.
|
|
* Several NVM3 instances using different handles must NOT overlap NVM-memory.
|
|
* To change some of the parameters,
|
|
* first call @ref nvm3_close and then @ref nvm3_open.
|
|
* @note The driver handle must be initialized to zero before it is used the
|
|
* first time. The @ref nvm3_open can be called repeatedly with the same handle
|
|
* and initialization data. In that case, the next calls will be regarded as a
|
|
* "no operation" and the function will return the same status as the previous
|
|
* call.
|
|
*
|
|
* @param[out] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] i
|
|
* A pointer to NVM3 driver initialization data.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success and a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_open(nvm3_Handle_t *h, const nvm3_Init_t *i);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Close the NVM3 driver instance.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to the NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK is always returned.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_close(nvm3_Handle_t *h);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Write the object value identified with the key to NVM.
|
|
* If the data object exists with the same length, its old content is compared
|
|
* with the new and only if the new content is different from the old it will
|
|
* be written.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[in] value
|
|
* A pointer to the object data to write.
|
|
*
|
|
* @param[in] len
|
|
* The size of the object data in number of bytes.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_writeData(nvm3_Handle_t *h, nvm3_ObjectKey_t key, const void *value, size_t len);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Read the object data identified with a given key from NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[out] value
|
|
* A pointer to the application data buffer. The read function will copy
|
|
* data to this location. For best performance, the buffer should be word-aligned.
|
|
*
|
|
* @param[in] len
|
|
* The maximum object size in number of bytes. The @ref nvm3_getObjectInfo() function
|
|
* can be used to find the actual size.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_readData(nvm3_Handle_t *h, nvm3_ObjectKey_t key, void *value, size_t len);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Read parts of the object data identified with a given key from NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[out] value
|
|
* A pointer to the application data buffer. The read function will copy
|
|
* data to this location. For best performance, the buffer should be word-aligned.
|
|
*
|
|
* @param[in] ofs
|
|
* The offset where data shall be read from.
|
|
*
|
|
* @param[in] len
|
|
* The number of bytes to read.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_readPartialData(nvm3_Handle_t* h, nvm3_ObjectKey_t key, void* value, size_t ofs, size_t len);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Find the type and size of an object in NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[out] type
|
|
* A pointer to the location where NVM3 shall write the object type. The type can
|
|
* be either @ref NVM3_OBJECTTYPE_DATA or @ref NVM3_OBJECTTYPE_COUNTER.
|
|
*
|
|
* @param[out] len
|
|
* A pointer to the location where NVM3 writes the object size.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_getObjectInfo(nvm3_Handle_t *h, nvm3_ObjectKey_t key,
|
|
uint32_t *type, size_t *len);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Create a list of object keys for valid objects in NVM.
|
|
*
|
|
* @note
|
|
* The function @ref nvm3_countObjects() is also provided to count the
|
|
* number of valid objects.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[out] keyListPtr
|
|
* A pointer to a buffer for the key list.
|
|
*
|
|
* @param[in] keyListSize
|
|
* The number of elements in the key list buffer. If the keyListSize = 0,
|
|
* the @p keyListPtr can be NULL and the function will return the total
|
|
* number of objects.
|
|
*
|
|
* @param[in] keyMin
|
|
* The lower search key. Set to @ref NVM3_KEY_MIN to match all keys.
|
|
*
|
|
* @param[in] keyMax
|
|
* The upper search key. Set to @ref NVM3_KEY_MAX to match all keys.
|
|
*
|
|
* @return
|
|
* The number of keys written to the key list. This value is less than or equal
|
|
* to @p keyListSize. If the @p keyListSize = 0, the function will return the
|
|
* total number of objects matching the key Min - Max pattern.
|
|
******************************************************************************/
|
|
size_t nvm3_enumObjects(nvm3_Handle_t *h,
|
|
nvm3_ObjectKey_t *keyListPtr, size_t keyListSize,
|
|
nvm3_ObjectKey_t keyMin, nvm3_ObjectKey_t keyMax);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Create a list of object keys for deleted objects in NVM.
|
|
*
|
|
* @note
|
|
* The function @ref nvm3_countDeletedObjects() is also provided to count the
|
|
* number of deleted objects.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[out] keyListPtr
|
|
* A pointer to a buffer for the key list.
|
|
*
|
|
* @param[in] keyListSize
|
|
* The number of elements in the key list buffer. If the keyListSize = 0,
|
|
* the @p keyListPtr can be NULL and the function will return the total
|
|
* number of objects.
|
|
*
|
|
* @param[in] keyMin
|
|
* The lower search key. Set to @ref NVM3_KEY_MIN to match all keys.
|
|
*
|
|
* @param[in] keyMax
|
|
* The upper search key. Set to @ref NVM3_KEY_MAX to match all keys.
|
|
*
|
|
* @return
|
|
* The number of keys written to the key list. This value is less than or equal
|
|
* to @p keyListSize. If the @p keyListSize = 0, the function will return the
|
|
* total number of objects matching the key Min - Max pattern.
|
|
******************************************************************************/
|
|
size_t nvm3_enumDeletedObjects(nvm3_Handle_t *h,
|
|
nvm3_ObjectKey_t *keyListPtr, size_t keyListSize,
|
|
nvm3_ObjectKey_t keyMin, nvm3_ObjectKey_t keyMax);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Delete an object from NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_deleteObject(nvm3_Handle_t *h, nvm3_ObjectKey_t key);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Store a counter in NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[in] value
|
|
* The counter value to write.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_writeCounter(nvm3_Handle_t *h, nvm3_ObjectKey_t key, uint32_t value);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Read a counter value from NVM.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[out] value
|
|
* A pointer to the counter location. The read function will copy
|
|
* the counter value to this location.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_readCounter(nvm3_Handle_t *h, nvm3_ObjectKey_t key, uint32_t *value);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Increment a counter object value by 1 and read out optionally.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] key
|
|
* A 20-bit object identifier.
|
|
*
|
|
* @param[out] newValue
|
|
* A pointer to the counter readout location. The counter is incremented before the value
|
|
* is written to this location. Set this value to NULL to ignore readout.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_incrementCounter(nvm3_Handle_t *h, nvm3_ObjectKey_t key, uint32_t *newValue);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Delete all objects in NVM.
|
|
*
|
|
* @note
|
|
* Users don't need to call this function to get NVM3 into an
|
|
* initial valid state.
|
|
*
|
|
* @warning
|
|
* The execution time depends on the configured NVM size and may therefore be
|
|
* significant.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_eraseAll(nvm3_Handle_t *h);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Get the number of page erases of the most erased page in the NVM area since
|
|
* the first initialization.
|
|
*
|
|
* @note
|
|
* Except for pages marked as bad, pages will have an erase count equal to the
|
|
* most erased or one less because of the wear leveling algorithm.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] eraseCnt
|
|
* A pointer to the location where the NVM3 shall place the page
|
|
* erasure counter value.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_getEraseCount(nvm3_Handle_t *h, uint32_t *eraseCnt);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Set the page erase count.
|
|
* Normally, the application should not be concerned with the erase count value.
|
|
* If NVM3 is substituting a previous solution, it is possible to transfer
|
|
* the erase count to NVM3 when initializing the NVM for the first time.
|
|
* The erase count must be set before the @ref nvm3_open is called and will
|
|
* only take effect if the NVM is completely erased or contains unknown
|
|
* data to NVM3. In that case, all pages will be initialized with the supplied
|
|
* erase count. After @ref nvm3_open is called, the value will be consumed
|
|
* and will have no effect on further calls to @ref nvm3_open.
|
|
*
|
|
* @param[in] eraseCnt
|
|
* The erase count.
|
|
******************************************************************************/
|
|
void nvm3_setEraseCount(uint32_t eraseCnt);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Execute a repack operation. NVM3 will copy data or erase pages when repacking
|
|
* is needed. Calling @ref nvm3_repack() may block access to the non-volatile
|
|
* memory for up to one page erasure time plus an small execution overhead.
|
|
* The exact worst-case timing characteristics can be found in the data sheet for the
|
|
* part.
|
|
*
|
|
* @note
|
|
* Calling @ref nvm3_repack() is not mandatory because the functions that
|
|
* write data to NVM will trigger a repack if needed. Because a
|
|
* repack operation may be time consuming, the application may want to be
|
|
* in control of when repacking occurs by calling this function.
|
|
*
|
|
* More information about the repack operation can be found in the
|
|
* @ref nvm3_repack section.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_repack(nvm3_Handle_t *h);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Check the internal status of NVM3 and return true if a repack
|
|
* operation is required. The application must call @ref nvm3_repack() to
|
|
* perform the actual repack operation.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* true if repacking is needed, false if repacking is not needed.
|
|
******************************************************************************/
|
|
bool nvm3_repackNeeded(nvm3_Handle_t *h);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Resize the NVM area used by an open NVM3 instance.
|
|
* The area can be resized by changing the start or end address either up
|
|
* or down in memory. Because the input parameters to NVM3 are start address
|
|
* and size, users should be cautious. Either move the start address up or
|
|
* down in memory and adjust the size accordingly to keep the end address,
|
|
* or keep the address and change the size only.
|
|
* It is not possible to resize the area by doing changes in both ends of the
|
|
* NVM address range at the same time.
|
|
* If the resize operation returns @ref SL_STATUS_OK, the instance is still
|
|
* open and can be used to access objects in the resized NVM.
|
|
* If the resize operation fails, the instance will still be open but with
|
|
* unchanged size.
|
|
*
|
|
* @note
|
|
* It is possible to decrease the NVM area to a new size that is not capable
|
|
* of keeping the already stored objects. The result is loss of data.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @param[in] newAddr
|
|
* The start address of the NVM after resize.
|
|
*
|
|
* @param[in] newSize
|
|
* The size of the NVM after resize.
|
|
*
|
|
* @return
|
|
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
|
|
******************************************************************************/
|
|
sl_status_t nvm3_resize(nvm3_Handle_t *h, nvm3_HalPtr_t newAddr, size_t newSize);
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Count valid objects.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* The number of valid objects.
|
|
******************************************************************************/
|
|
__STATIC_INLINE size_t nvm3_countObjects(nvm3_Handle_t *h)
|
|
{
|
|
return nvm3_enumObjects(h, NULL, 0, NVM3_KEY_MIN, NVM3_KEY_MAX);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Count deleted objects.
|
|
*
|
|
* @param[in] h
|
|
* A pointer to an NVM3 driver handle.
|
|
*
|
|
* @return
|
|
* The number of deleted objects.
|
|
******************************************************************************/
|
|
__STATIC_INLINE size_t nvm3_countDeletedObjects(nvm3_Handle_t *h)
|
|
{
|
|
return nvm3_enumDeletedObjects(h, NULL, 0, NVM3_KEY_MIN, NVM3_KEY_MAX);
|
|
}
|
|
|
|
/** @} (end addtogroup nvm3) */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#include "nvm3_default.h"
|
|
|
|
/* *INDENT-OFF* */
|
|
/************ THIS SECTION IS FOR DOCUMENTATION ONLY !**********************//**
|
|
* @addtogroup nvm3 NVM3 - NVM Data Manager
|
|
* @brief NVM3 Non-Volatile Memory Data Management driver
|
|
* @{
|
|
|
|
# Introduction {#nvm3_intro}
|
|
The NVM3 driver provides a way for an application to safely store and
|
|
retrieve variable-size objects in a page-based non-volatile memory (NVM).
|
|
Objects are identified with 20-bit object identifiers denoted as keys.
|
|
|
|
The driver is designed to use pages in a sequential order to provide equal
|
|
usage and wear. The driver is resilient to power loss or reset events,
|
|
ensuring that objects retrieved from the driver are in a valid state. A
|
|
valid object will always be the last successfully stored object. NVM3 can
|
|
detect NVM defects and mark pages as unusable. NVM3 will continue to operate
|
|
on good pages after defect pages are detected.
|
|
|
|
# Objects {#nvm3_objects}
|
|
An NVM3 object is data that can be stored in NVM. The object
|
|
is handled as an array of bytes up to @ref NVM3_MAX_OBJECT_SIZE in size.
|
|
NVM3 can handle two types of objects.
|
|
-# Regular data objects. Data objects can store information of
|
|
any size up to maximum @ref NVM3_MAX_OBJECT_SIZE bytes.
|
|
-# 32-bit counter objects. Counter objects can store 32-bit counters that are
|
|
accessed with a separate set of API functions. The counter object is designed
|
|
to be compact while minimizing memory wear in applications that require
|
|
frequent persistent counter increments.
|
|
|
|
See @ref nvm3_api for more details on the API.
|
|
|
|
# Repacking {#nvm3_repack}
|
|
As the NVM fills up, it reaches a point where it can no longer store
|
|
additional objects, and a repacking operation is required to release
|
|
out-of-date objects to free up NVM. Because both writing data and erasing
|
|
pages take a long time,
|
|
the NVM3 driver does not trigger the process by itself unless free memory
|
|
reaches a critical low level. As an alternative, the application can trigger
|
|
the repacking process by calling the @ref nvm3_repack() function.
|
|
During the call, NVM3 will either move data to a new page or erase pages
|
|
that can be reused. At most, the call will block for a period equal to a page
|
|
erasure time or the time to write the largest size object (whatever is largest)
|
|
plus a small execution overhead. Page erasure and flash write timing for the
|
|
EFM32 or EFR32 parts can be found in the datasheet.
|
|
|
|
NVM3 uses two thresholds for repacking:
|
|
-# Forced threshold. This is the threshold used to force automatic repacking
|
|
when free memory reaches a critical low level.
|
|
-# User threshold. This is the threshold used by @ref nvm3_repackNeeded().
|
|
@ref nvm3_repack() will not perform repacking unless free memory is below
|
|
this threshold.
|
|
|
|
The user can define the user threshold by entering a value in the repackHeadroom
|
|
member of the @ref nvm3_Init_t structure used by the @ref nvm3_open() function.
|
|
The repackHeadroom value defines the difference between the user and forced
|
|
threshold. The forced threshold is the minimum low memory threshold defined
|
|
by the page size and maximum object size and can't be changed by the user.
|
|
The default value for the repack headroom is 0, meaning that the forced and
|
|
user thresholds are equal.
|
|
|
|
An NVM3 function that deletes or modifies data or counter object will trigger
|
|
an automatic repack operation when free memory is below the forced threshold.
|
|
The check is done before the object is modified, not after.
|
|
|
|
The application can use @ref nvm3_repackNeeded() to determine if repacking
|
|
is needed. To initiate repacks, call @ref nvm3_repack(). Note that
|
|
this function will perform repacks only if they are needed.
|
|
|
|
@note The repack threshold can be changed to prevent multiple modifications
|
|
of objects between user called repacks from causing forced repacks. Note
|
|
that "high" values of the repack headroom may cause
|
|
increased NVM wear from increased number of repacks.
|
|
|
|
See @ref nvm3_timing section for more details on repack timing.
|
|
|
|
# Caching {#nvm3_cache}
|
|
NVM3 includes an object location lookup cache to speed up object access, as
|
|
searching through the entire NVM3 contents for an object could otherwise
|
|
be slow. It is important to note that this cache only stores the location
|
|
of the object and not the object data itself. To ensure that cache can hold all necessary
|
|
information, it must be configured to a size equivalent to or larger than the
|
|
number of objects stored in NVM, including those deleted, as long as they are
|
|
not discarded by the repack function. If the cache is available,
|
|
the driver will first look in the cache to find the position of the object in NVM.
|
|
If the object position is not found in the cache, the object position will be
|
|
found by searching the NVM. The search will start at the last stored object
|
|
and search all the way to the oldest object. If the object is found, the cache
|
|
is updated accordingly.
|
|
NVM3 Optimization improves the NVM3 initialization and object lookup time.
|
|
Code size increases ~1248 bytes with NVM3 Optimization enabled. NVM3 driver provides
|
|
a means to enable or disable Optimization from Simplicity Studio UC.
|
|
|
|
The application must allocate and support data for the cache.
|
|
See the @ref nvm3_open function for more details. The size of each cache
|
|
element is one uint32_t and one pointer giving a total of 8 bytes (2 words)
|
|
per entry for EFM32 and EFR32 devices. With Optimization enabled, the size of each
|
|
cache element is two uint32_t and one pointer giving a total of 12 bytes (3 words)
|
|
per entry.
|
|
|
|
@note The cache is fully initialized by @ref nvm3_open() and automatically
|
|
updated by any subsequent write, read, or delete function call.
|
|
|
|
# Global Data (variables) {#nvm3_data}
|
|
The NVM3 service uses global variables to store intermediate data
|
|
during open, read, write, increment, and delete calls.
|
|
The application must set the value of the @ref nvm3_maxFragmentCount
|
|
at run-time before any NVM3 functions are called.
|
|
|
|
NVM3 does not support overlapped calls. If there is any chance that the
|
|
application can issue overlapped calls, the NVM3 locking mechanism must be
|
|
present and protected from that.
|
|
|
|
@note If the application uses more than one NVM3 instance, the variables
|
|
will be shared between the instances. Be sure to allocate data that have a
|
|
size that is large enough for the largest usage.
|
|
|
|
# Stack Usage {#nvm3_stack}
|
|
NVM3 function calls are nested several levels deep. The stack usage
|
|
has been measured on some EFM32, and EFR32 targets with NVM3 source
|
|
for IAR and ARM GCC. The maximum stack usage measured was 420 bytes for
|
|
IAR, and 472 bytes for ARM GCC builds. The unit test used to validate the
|
|
stack usage has a 10% margin and uses a stack limit of 462 bytes for IAR
|
|
and 520 bytes for ARM GCC. The maximum stack usage measured on SIXX device was
|
|
540 bytes for IAR, and 520 bytes for ARM GCC builds with security. The unit
|
|
test used to validate the stack usage has a 10% margin and uses a stack
|
|
limit of 600 bytes for IAR and 576 bytes for ARM GCC builds with security.
|
|
Note that the actual stack usage is a little different on the Cortex M4 and M33
|
|
with NVM3 source.
|
|
|
|
# The API {#nvm3_api}
|
|
The NVM3 API is defined in the nvm3.h file. The application code
|
|
must include the nvm3.h header file to get access to all definitions,
|
|
datatypes, and function prototypes defined by NVM3.
|
|
|
|
This section contains brief descriptions of NVM3 functions. For
|
|
more information about parameters and return values, see the Function
|
|
documentation section. Most functions return an @ref sl_status_t that has the
|
|
value @ref SL_STATUS_OK on success, or see nvm3.h for other values.
|
|
|
|
@ref nvm3_open() and @ref nvm3_close().
|
|
@n These functions open and close an NVM3 instance. @ref nvm3_open() takes a handle
|
|
of type nvm3_Handle_t and initialization data of type @ref nvm3_Init_t.
|
|
The helper macro pair @ref NVM3_DEFINE_SECTION_STATIC_DATA() and
|
|
@ref NVM3_DEFINE_SECTION_INIT_DATA() are provided to simplify initialization
|
|
data definition. For usage examples, see the @ref nvm3_example section.
|
|
|
|
@ref nvm3_getObjectInfo(), @ref nvm3_enumObjects(), @ref nvm3_deleteObject()
|
|
and nvm3_countObjects()
|
|
@n These functions work on all objects. @ref nvm3_enumObjects()
|
|
gets a list of keys to valid objects in the NVM. The search can also
|
|
be constrained by the function parameters.
|
|
@ref nvm3_countObjects() can be useful at startup to distinguish between a
|
|
first startup without any valid objects present and later reboots with valid
|
|
objects persistently stored in NVM.
|
|
|
|
@ref nvm3_writeData() and @ref nvm3_readData()
|
|
@n Write and read data objects.
|
|
|
|
@ref nvm3_writeCounter(), @ref nvm3_readCounter() and @ref nvm3_incrementCounter()
|
|
@n Write, read, and increment 32-bit counter objects.
|
|
|
|
@ref nvm3_eraseAll()
|
|
@n Erase all objects in NVM.
|
|
|
|
@ref nvm3_getEraseCount()
|
|
@n Return the erasure count for the most erased page in NVM.
|
|
|
|
@ref nvm3_repack() and @ref nvm3_repackNeeded()
|
|
@n Manage NVM3 repacking operations.
|
|
|
|
@ref nvm3_resize()
|
|
@n Resize the NVM area used by an open NVM3 instance.
|
|
|
|
# API Locking and Interrupt handling {#nvm3_locking}
|
|
Common for all NVM3 API calls is that they are not re-entrant. By default,
|
|
all functions are protected with protection functions that disable interrupts.
|
|
|
|
@note The default NVM3 protection functions can be substituted by the
|
|
application if other synchronization functions are available and disabling
|
|
interrupts for extended periods is not desired.
|
|
|
|
If the application does all the nvm3-calls from the same thread and guarantees
|
|
no overlapping calls, the lock functions don't have to do anything.
|
|
|
|
# Memory Placement {#nvm3_memory_placement}
|
|
The application is responsible for placing the NVM area correctly. The minimum
|
|
requirements for memory placement are as follows:
|
|
-# NVM area start address must be aligned with a page of the underlying
|
|
memory system.
|
|
-# NVM area size must be a multiple of the page size.
|
|
|
|
The minimum required NVM size is dependent on both the NVM page size and the
|
|
NVM3_MAX_OBJECT_SIZE value. For a device with 4 kB page size and typical
|
|
values for NVM3_MAX_OBJECT_SIZE, the following is the minimum required
|
|
number of pages:
|
|
- For NVM3_MAX_OBJECT_SIZE=208: 3 pages
|
|
- For NVM3_MAX_OBJECT_SIZE=1900: 4 pages
|
|
- For NVM3_MAX_OBJECT_SIZE=4096: 5 pages
|
|
|
|
@ref NVM3_DEFINE_SECTION_STATIC_DATA() and @ref NVM3_DEFINE_SECTION_INIT_DATA()
|
|
macros are provided to support the creation of the NVM area and initialization
|
|
data.
|
|
A linker section called 'name'_section is defined by @ref NVM3_DEFINE_SECTION_STATIC_DATA().
|
|
The NVM area is placed within the linker section. The application linker script
|
|
must place the section according to the requirements above. An error is returned
|
|
by @ref nvm3_open() on alignment or size violation.
|
|
|
|
@note When the start address and size of the data area are defined and
|
|
used by an application, make sure you use the same values at
|
|
every program startup and also reuse by new versions of the software after
|
|
an upgrade. If an application tries to open an instance with a start address
|
|
or size that does not match the previous use, it can result in permanent data loss
|
|
and failure.
|
|
|
|
# Configuration Options {#nvm3_configuration}
|
|
There are no compile-time configuration options for NVM3. All configuration
|
|
parameters are contained in @ref nvm3_Init_t.
|
|
|
|
@note The @ref nvm3_data must however be configured for correct
|
|
size and have correct values for NVM3 to behave correctly.
|
|
|
|
# Bad NVM Page Handling {#nvm3_bad_page_handling}
|
|
NVM3 has been designed to detect page erase and write errors during
|
|
normal operation and mark failing pages as BAD. If a write operation
|
|
fails, all objects that have been written to the page prior to the write
|
|
error are copied to the next free page before the page is marked as BAD and
|
|
the write operation resumes. If the recovery operation is successful, the
|
|
operation is regarded as complete, and the function will return @ref
|
|
SL_STATUS_OK status.
|
|
|
|
@note Erase and write errors may not be detected by NVM3 if the device is
|
|
used until End-of-Life (EOL), where the failure mode can be that the NVM content is
|
|
changing during a power cycle.
|
|
|
|
# Error Handling {#nvm3_error_handling}
|
|
The NVM3 error handling involves most functions
|
|
returning an error code. The @ref nvm3_countObjects is
|
|
different because it returns the actual number of objects
|
|
found.
|
|
|
|
The behavior and return values for most functions, such as @ref
|
|
nvm3_readData, @ref nvm3_writeData, and so on should be self explanatory,
|
|
while the @ref nvm3_open is slightly different. @ref nvm3_open will always try
|
|
to recover from the previous state and continue without an error, if possible.
|
|
In other words, if a valid NVM3 instance is
|
|
established, @ref nvm3_open will recover from brownouts and power cycles at
|
|
any time in any operation and bring the system to a valid state where all
|
|
pages and objects are in a known state and return success whenever possible.
|
|
From this state, normal operation can resume. If @ref nvm3_open returns an
|
|
error, it's an indication of either a design or coding error
|
|
or that many of the NVM pages have been marked as BAD, leaving insufficient
|
|
space in the NVM to progress. Operation may not resume if @ref nvm3_open
|
|
returns an error.
|
|
|
|
@note Because the @ref nvm3_open may need to do recovery operations,
|
|
the execution time will occasionally vary.
|
|
|
|
# Storing Objects in Internal Flash {#nvm3_support_internal_flash}
|
|
NVM3 has support for writing and reading objects in internal, i.e., memory-mapped
|
|
Flash memory through the nvm3_hal_flash.c "driver". nvm3_hal_flash.c
|
|
is using EMLIB functions to write and erase data while using regular
|
|
memory functions to read data from Flash.
|
|
|
|
@n The "driver" for internal Flash is selected by setting the halHandle in
|
|
the nvm3_open initialization structure to point to nvm3_halFlashHandle.
|
|
|
|
# Storing Objects in External Flash {#nvm3_support_external_flash}
|
|
NVM3 has support for writing and reading objects in external Flash by using
|
|
the nvm3_hal_flash_ext.c "driver". The nvm3_hal_flash_ext.c is using the SE
|
|
manager functions to write and erase data while using regular memory
|
|
functions to read data from external Flash.
|
|
|
|
@n The "driver" for external Flash is selected by setting the halHandle in
|
|
the nvm3_open initialization structure to point to nvm3_halFlashHandle.
|
|
|
|
# Securing Objects in External Flash {#nvm3_support_secure_storage}
|
|
All data objects are authenticated + encrypted using AES-GCM mode and
|
|
counter objects are stored in plain. Each data object which is securely stored
|
|
in external flash has a size overhead of 8 bytes. NVM3 uses device generated key
|
|
for crypto operations. Reading the external memory directly (without using NVM3)
|
|
will not give access to the unencrypted data objects.
|
|
|
|
@n HAL for crypto is added to have the flexibility to use available crypto
|
|
which can be selected by setting the halCryptoHandle in the nvm3_open
|
|
initialization structure to point to desired crypto handle.
|
|
|
|
@n NVM3 crypto key will be changed if "device erase" is triggered on a debug
|
|
locked part, which will also clean up the NVM3 from the memory. In this case,
|
|
if previously stored NVM3 data is reloaded to the same device, NVM3 data read
|
|
will fail as NVM3 crypto key has changed.
|
|
|
|
# NVM3 Source code {#nvm3_source_code}
|
|
The NVM3 source code can be compiled for Cortex M4 and M33 with either ARM GCC
|
|
or IAR toolchains. In addition, the NVM3 driver provides a means to securely
|
|
store and retrieve the objects in external Flash using authenticated encryption.
|
|
Objects in internal Flash need not be encrypted, while objects in external Flash
|
|
must always be encrypted.
|
|
|
|
# Storage Capacity {#nvm3_capacity}
|
|
Basic storage is defined as the size of on instance of all objects, including
|
|
any overhead stored with the data. For NVM3 the maximum amount of data you
|
|
can store is dependent on the number of flash pages used for storage and the
|
|
max object size used for NVM3. The following table shows the maximum allowed
|
|
basic storage for a varying number of 4 kB or 8 kB flash pages and the minimum
|
|
(204 bytes), default (254 bytes), high (1900 bytes) and maximum (4096 bytes)
|
|
max object size. Note that this is a theoretical limit, and if the basic storage
|
|
is at this limit, no space is left for wear-levelling, and page erases will be
|
|
forced for every object written. The NVM3 instance should therefore be configured
|
|
with enough flash pages to put the maximum allowed basic storage significantly
|
|
higher than the actual basic storage.
|
|
|
|
## Max Allowed Basic Storage with 4 kB page size
|
|
| Flash pages | Total size (bytes) | Max allowed basic storage (bytes) | | | |
|
|
|-------------------------------|--------------------------------------|-----------------------------------------|-------------------------------------|--------------------------------------|--------------------------------------|
|
|
| | | Max object size = 204 bytes | Max object size = 254 bytes | Max object size = 1900 bytes | Max object size = 4096 bytes |
|
|
| 3 | 12228 | 3652 | 3552 | 260 | 0 |
|
|
| 4 | 16304 | 7728 | 7628 | 4336 | 0 |
|
|
| 5 | 20380 | 11804 | 11704 | 8412 | 4020 |
|
|
| 6 | 24456 | 15880 | 15780 | 12488 | 8096 |
|
|
| 7 | 28532 | 19956 | 19856 | 16564 | 12172 |
|
|
| 8 | 32608 | 24032 | 23932 | 20640 | 16248 |
|
|
| 9 | 36684 | 28108 | 28008 | 24716 | 20324 |
|
|
| 10 | 40760 | 32184 | 32084 | 28792 | 24400 |
|
|
|
|
## Max Allowed Basic Storage with 8 kB page size
|
|
| Flash pages | Total size (bytes) | Max allowed basic storage (bytes) | | | |
|
|
|-------------------------------|--------------------------------------|-----------------------------------------|-------------------------------------|--------------------------------------|--------------------------------------|
|
|
| | | Max object size = 204 bytes | Max object size = 254 bytes | Max object size = 1900 bytes | Max object size = 4096 bytes |
|
|
| 3 | 24516 | 7748 | 7648 | 4356 | 0 |
|
|
| 4 | 32688 | 15920 | 15820 | 12528 | 8136 |
|
|
| 5 | 40860 | 24092 | 23992 | 20700 | 16308 |
|
|
| 6 | 49032 | 32264 | 32164 | 28872 | 24480 |
|
|
|
|
# Default Instance {#nvm3_default}
|
|
Several NVM3 instances can be created on a device and live independently of each other,
|
|
but to save memory, it is usually desirable to use only one NVM3 instance as each
|
|
instance adds some overhead. For this reason, a default instance exists that is used
|
|
by all Silicon Labs wireless stacks. The API to initialize the default instance and
|
|
the handles to use with the regular NVM3 API are described in @ref nvm3default.
|
|
|
|
# NVM3 in Simplicity Commander {#nvm3_commander}
|
|
Simplicity Commander is a single, all-purpose tool to be used in a production environment.
|
|
It is invoked using a simple Command Line Interface (CLI) that can also be scripted.
|
|
Simplicity Commander supports reading out the NVM3 data area from a device and parsing
|
|
the NVM3 data to extract stored values. This can be useful in a debugging scenario
|
|
where you may need to find out the stored state of an application that has been running
|
|
for some time.
|
|
|
|
For more information about using the Simplicity Commander with NVM3, see
|
|
UG162: Simplicity Commander Reference Guide.
|
|
|
|
# Execution Timing {#nvm3_timing}
|
|
There are several factors that affect the execution time for NVM3 calls that
|
|
can update the NVM, described below.
|
|
|
|
The primary factor when doing updates is that data must be written to flash.
|
|
Writing to flash is relatively slow, and timing information for the particular
|
|
device is available in the datasheet and can be used to calculate the
|
|
approximately minimum execution time. Note that NVM3 will, in addition to the
|
|
user data, write object headers, and the software will add some
|
|
overhead. The relative overhead will be larger for smaller compared to larger
|
|
objects.
|
|
|
|
When updating the flash store, repacking must be done from time to
|
|
time. See the @ref nvm3_repack section for more details about why
|
|
repacking is needed and how it works.
|
|
|
|
To minimize the time when repacks are executed, there are a few configurations
|
|
that affect how NVM3 works. The most important configurations are listed below:
|
|
-# The repackHeadroom parameter in the @ref nvm3_Init_t structure can be used
|
|
to set the number of bytes that can be written before a forced repack is
|
|
triggered. To make this work, the @ref nvm3_repack() function must be called
|
|
until the @ref nvm3_repackNeeded() returns false before the actual write.
|
|
-# Use as small objects as possible and define the NVM3_MAX_OBJECT_SIZE
|
|
accordingly. Writing and repacking large objects is time-consuming. Limiting
|
|
the maximum object size will limit the time spent in both write and repack
|
|
functions.
|
|
|
|
When triggered, the repack function will either copy data or erase a page.
|
|
To limit the time spent when copying, the repack function will return when
|
|
the NVM3_MAX_OBJECT_SIZE number of bytes have been copied. The copy operation
|
|
will resume on the next call to repack, and the application may have to call
|
|
the repack function several times to complete a full repack operation.
|
|
|
|
@note Performing the @ref nvm3_repack()/@ref nvm3_repackNeeded() loop is
|
|
highly recommended before any timing-sensitive procedure.
|
|
|
|
# Examples {#nvm3_example}
|
|
|
|
Example 1 shows initialization, usage of data objects, and repacking.
|
|
|
|
@include nvm3_example_1.c
|
|
|
|
Example 2 shows initialization and usage of counter objects. The
|
|
counter object uses a compact way of storing a 32-bit counter value while minimizing
|
|
NVM wear.
|
|
|
|
@include nvm3_example_2.c
|
|
|
|
* @} end group nvm3 ****************************************************/
|
|
|
|
#endif /* NVM3_GENERIC_H */
|