NVM3EMDRV

Detailed Description

NVM3 Non-Volatile Memory Management driver.

Note

Using NVM3 to store data in external flash is beta tested only. Silicon Labs will NOT support any production deployments with this Beta release. Production deployments will only be supported with the GA version of this feature. This version is intended for lab and evaluation purpose only.

Introduction

The NVM3 driver provides a way for an application to safely store and retrieve variable size objects in a page based non-volatile memory. 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

A NVM3 object is a piece of data that can be stored in NVM. The object is handled as an array of bytes up to 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 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.

Repacking

As the NVM fills up, there will be 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 erasing pages takes 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 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 plus a small execution overhead. Page erasure time for the EFM32 or EFR32 parts can be found in the data sheet.

The application can use nvm3_repackNeeded() to determine if repacking is needed. The nvm3_repack() is used to do the actual repacks, and it will perform repacks only if the operation is needed.

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.

A NVM3 function that deletes or modifies a 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 user can define the user threshold by entering a value in the repackHeadroom member of the nvm3_Init_t struct used by the 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 cannot be changed by the user. The default value for the repack headroom is 0, meaning that the forced and user thresholds are equal.

Note

The repack threshold can be changed to avoid that multiple modifications of objects between user called repacks are causing automatic repacks. Care should be taken because "high" values of the repack headroom may cause increased NVM wear from increased number of repacks.

Caching

Caching is an optional feature. The NVM3 cache is an object location lookup cache, data is not stored in the cache. Using the cache will speed up accesses to the objects, and the performance will very much depend on objects beeing available in the cache. To ensure that the cache can hold all neccesary information, it must be configured to a size equivalent 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.

It is the application that must allocate and support the data for the cache, see the 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) pr. entry for EFM32 and EFR32 devices.

Note

The cache is fully initialized by nvm3_open() and automatically updated by any subsequent write, read, or delete function call.

Global Data (variables)

The NVM3 library is using some global variables to store intermediate data during open, read, write, increment and delete calls. Because the actual memory configuration is not defined at the time the NVM3 library is built, but rather at the time the user application is built, the size of the data structures must be determined by the application configuration. Also the value of the nvm3MaxFragmentCount must be set by the application at run-time before any nvm3 funcntions are called.

The 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 protect from that.

Note

If the application is using 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 Data

The nvm3 library function calls are nested several levels deep. The stack usage has been measured on some EFR32 targets with library builds for IAR and armgcc, and the maximum stack usage measured was 388 bytes.

The API

The nvm3 API is defined in the nvm3.h file, and 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 the nvm3 functions. For more information about parameters and return values see the Function Documentation section. Most functions return an Ecode_t that has the value ECODE_NVM3_OK on success or see nvm3.h for other values.

Memory Placement

The application is responsible for placing the NVM area correctly. Minimum requirements for memory placement are:

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 minimim required NVM size is dependent on both the NVM page size and the NVM3_MAX_OBJECT_SIZE value. For a device with 2 kB page size and some typical values for NVM3_MAX_OBJECT_SIZE will give the following minimum required number of pages:

Configuration Options

There are no compile-time configuration options for NVM3. All configuration parameters are contained in nvm3_Init_t.

Note

The Global Data (variables) variables must however be configured for correct size and have correct values for the nvm3 to behave correctly.

Bad NVM Page Handling

The 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 is copied to the next free page before the page is marked as BAD and the write operation resumes. If the recover operation is successful, the operation is regarded as complete and the function will return ECODE_NVM3_OK status.

Note

Erase and write errors may not be detected by NVM3 if the device is used until end of life where the failure mode can be that the NVM content is changing during a power cycle.

Error Handling

The NVM3 error handling is classic in the way that most of the functions returns an error code. The nvm3_countObjects is the only function that differs from this sceme because it returns the actual number of objects found.

The behaviour and return values from most of the functions like nvm3_readData, nvm3_writeData etc. should be pretty self explanatory, while the nvm3_open is a bit different. nvm3_open will always try to recover from the previous state and continue without any error if possible. The rationale behind this is that if a valid NVM3 instance has been established, nvm3_open will recover from brown outs 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 nvm3_open returns an error, that is an indication that there is either a design or coding error, or that many of the NVM pages have been marked as BAD leaving unsufficient space in the NVM to progress. Operation may not resume if nvm3_open returns an error.

Note

Because the nvm3_open may need to do some recovery operations, the execution time will vary from time to time.

Storing objects in 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 it is using regular memory functions to read data from FLASH.

The "driver" for internal flash is selected by setting the halHandle in the nvm3_open init struct to point to nvm3_halFlashHandle.

Storing objects in external FLASH

MNV3 has support for writing and reading objects in external FLASH by using the nvm3_hal_extflash.c "driver". The nvm3_hal_extflash.c is using the Gecko Bootloader to read, write and erase data in the FLASH. By using this scheme, NVM3 does not deal with the hardware directly. All flash communication must be taken care of by the bootloader. As long as the bootloader has been configured and build for the actual hardware, supports raw reads, writes and erases, NVM3 should be good to go.

nvm3_hal_extflash.c is using the "raw" read and write functions. It does not use the slot feature supported by the Gecko Bootloader. Be careful when configuring the bootloader memory map to avoid conflicts between NVM3 and other usage, including slot configuration.

All data objects are encrypted using CCM encryption and counter base values are encrypted using AES encryption. NVM3 encryption keys are stored in internal FLASH. Reading the external memory alone will not give access to the unencrypted data or counter values.

The "driver" for external flash is selected by setting the halHandle in the nvm3_open init struct to point to nvm3_halExtFlashHandle.

NVM3 Libraries

The NVM3 comes as pre-compiled libraries for Cortex M0, M3, M4 and M33 compiled with either armgcc or iar toolchains. In addition there are verions with and without encryption support. The versions without encryption support can only be used to store data in internal FLASH, while the ones with encryption support can be used for both internal and external FLASH. Objects in internal FLASH will never be encrypted, while objects in external FLASH must always be encrypted.

Examples

Example 1 shows initialization, usage of data objects and repacking.

#include "nvm3.h"

#include "nvm3_hal_flash.h"

// Create a NVM area across 6 Flash pages. Create a cache of 10 entries.

NVM3 static data definition helper macro for applications using linker script placement of NVM memory area. This macro exports the section 'name'_section to the linker. The section name must be placed by the user 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.
This macro also allocates static NVM3 cache.
Use this macro with NVM3_DEFINE_SECTION_INIT_DATA() to create initialization data for nvm3_open(). See Examples section for usage examples.

Open a NVM3 driver instance. A NVM3 instance 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. If the application wants to change some of the parameters, this can be done by first calling nvm3_close and then nvm3_open again.

Execute a repack operation. NVM3 will copy data or erase pages when repacking is needed. A call to nvm3_repack() may block access to the non-volatile memory for up to one page erasure time plus an small execution overhead. Exact worst-case timing characteristics can be found in the data sheet for the part.

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, care must be taken. One can either move the start address up or down in memory and adjust the size accordingly to keep the end address, or keep address and just change the size. 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 return ECODE_NVM3_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.

Set the page erase count. Normally the application should not be conserned with the erase count value. But 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 nvm3_open is called, and it 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 nvm3_open has been called, the value will be consumed and have no effect on further calls to nvm3_open.

NVM3 static data definition helper macro for applications using linker script placement of NVM memory area. This macro exports the section 'name'_section to the linker. The section name must be placed by the user 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.
This macro also allocates static NVM3 cache.
Use this macro with NVM3_DEFINE_SECTION_INIT_DATA() to create initialization data for nvm3_open(). See Examples section for usage examples.

The number of keys written to the key list. This value is less than or equal to keyListSize. If the keyListSize = 0, the function will return the total number of objects matching the key Min - Max pattern.

Open a NVM3 driver instance. A NVM3 instance 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. If the application wants to change some of the parameters, this can be done by first calling nvm3_close and then nvm3_open again.

Note

The driver handle must be initialized to zero before it is used the first time. The 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.

Execute a repack operation. NVM3 will copy data or erase pages when repacking is needed. A call to nvm3_repack() may block access to the non-volatile memory for up to one page erasure time plus an small execution overhead. Exact worst-case timing characteristics can be found in the data sheet for the part.

Note

It is not mandatory to call nvm3_repack() 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 occures by calling this function.

More information about the repack operation can be found in the Repacking section.

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, care must be taken. One can either move the start address up or down in memory and adjust the size accordingly to keep the end address, or keep address and just change the size. 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 return ECODE_NVM3_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.

Set the page erase count. Normally the application should not be conserned with the erase count value. But 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 nvm3_open is called, and it 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 nvm3_open has been called, the value will be consumed and have no effect on further calls to nvm3_open.