Microchip® Advanced Software Framework

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
SAM EEPROM Emulator (EEPROM) Service

This driver for Atmel® | SMART ARM®-based microcontrollers provides an emulated EEPROM memory space in the device's FLASH memory, for the storage and retrieval of user-application configuration data into and out of non-volatile memory.

The following peripherals are used by this module:

The following devices can use this module:

The outline of this documentation is as follows:

Prerequisites

The SAM device fuses must be configured via an external programmer or debugger, so that an EEPROM section is allocated in the main NVM flash memory contents. If a NVM section is not allocated for the EEPROM emulator, or if insufficient space for the emulator is reserved, the module will fail to initialize.

Module Overview

As the SAM devices do not contain any physical EEPROM memory, the storage of non-volatile user data is instead emulated using a special section of the device's main FLASH memory. The use of FLASH memory technology over EEPROM presents several difficulties over true EEPROM memory; data must be written as a number of physical memory pages (of several bytes each) rather than being individually byte addressable, and entire rows of FLASH must be erased before new data may be stored. To help abstract these characteristics away from the user application an emulation scheme is implemented to present a more user-friendly API for data storage and retrieval.

This module provides an EEPROM emulation layer on top of the device's internal NVM controller, to provide a standard interface for the reading and writing of non-volatile configuration data. This data is placed into the EEPROM emulated section of the device's main FLASH memory storage section, the size of which is configured using the device's fuses. Emulated EEPROM is exempt from the usual device NVM region lock bits, so that it may be read from or written to at any point in the user application.

There are many different algorithms that may be employed for EEPROM emulation using FLASH memory, to tune the write and read latencies, RAM usage, wear levelling and other characteristics. As a result, multiple different emulator schemes may be implemented, so that the most appropriate scheme for a specific application's requirements may be used.

Implementation Details

The following information is relevant for EEPROM Emulator scheme 1, version 1.0.0, as implemented by this module. Other revisions or emulation schemes may vary in their implementation details and may have different wear-leveling, latency, and other characteristics.

Emulator Characteristics

This emulator is designed for best reliability, with a good balance of available storage and write-cycle limits. It is designed to ensure that page data is automatically updated so that in the event of a failed update the previous data is not lost (when used correctly). With the exception of a system reset with data cached to the internal write-cache buffer, at most only the latest write to physical non-volatile memory will be lost in the event of a failed write.

This emulator scheme is tuned to give best write-cycle longevity when writes are confined to the same logical EEPROM page (where possible) and when writes across multiple logical EEPROM pages are made in a linear fashion through the entire emulated EEPROM space.

Physical Memory

The SAM non-volatile FLASH is divided into a number of physical rows, each containing four identically sized flash pages. Pages may be read or written to individually, however pages must be erased before being reprogrammed and the smallest granularity available for erasure is one single row.

This discrepancy results in the need for an emulator scheme that is able to handle the versioning and moving of page data to different physical rows as needed, erasing old rows ready for re-use by future page write operations.

Physically, the emulated EEPROM segment is located at the end of the physical FLASH memory space, as shown in the figure below.

Master Row

One physical FLASH row at the end of the emulated EEPROM memory space is reserved for use by the emulator to store configuration data. The master row is not user-accessible, and is reserved solely for internal use by the emulator.

Spare Row

As data needs to be preserved between row erasures, a single FLASH row is kept unused to act as destination for copied data when a write request is made to an already full row. When the write request is made, any logical pages of data in the full row that need to be preserved are written to the spare row along with the new (updated) logical page data, before the old row is erased and marked as the new spare.

Row Contents

Each physical FLASH row initially stores the contents of two logical EEPROM memory pages. This halves the available storage space for the emulated EEPROM but reduces the overall number of row erases that are required, by reserving two pages within each row for updated versions of the logical page contents. See here for a visual layout of the EEPROM Emulator physical memory.

As logical pages within a physical row are updated, the new data is filled into the remaining unused pages in the row. Once the entire row is full, a new write request will copy the logical page not being written to in the current row to the spare row with the new (updated) logical page data, before the old row is erased.

This system allows for the same logical page to be updated up to three times into physical memory before a row erasure procedure is needed. In the case of multiple versions of the same logical EEPROM page being stored in the same physical row, the right-most (highest physical FLASH memory page address) version is considered to be the most current.

Write Cache

As a typical EEPROM use case is to write to multiple sections of the same EEPROM page sequentially, the emulator is optimized with a single logical EEPROM page write cache to buffer writes before they are written to the physical backing memory store. The cache is automatically committed when a new write request to a different logical EEPROM memory page is requested, or when the user manually commits the write cache.

Without the write cache, each write request to an EEPROM memory page would require a full page write, reducing the system performance and significantly reducing the lifespan of the non-volatile memory.

Memory Layout

A single logical EEPROM page is physically stored as the page contents and a header inside a single physical FLASH page, as shown in the following figure.

page_layout.svg
Internal Layout of An Emulated EEPROM Page

Within the EEPROM memory reservation section at the top of the NVM memory space, this emulator will produce the layout as shown in the figure below when initialized for the first time.

init_layout.svg
Initial Physical Layout of The Emulated EEPROM Memory

When an EEPROM page needs to be committed to physical memory, the next free FLASH page in the same row will be chosen - this makes recovery simple, as the right-most version of a logical page in a row is considered the most current. With four pages to a physical NVM row, this allows for up to three updates to the same logical page to be made before an erase is needed. The figure below shows the result of the user writing an updated version of logical EEPROM page N-1 to the physical memory.

nm1_page_write.svg
First Write to Logical EEPROM Page N-1

A second write of the same logical EEPROM page results in the layout shown in the figure below.

nm1_page_write2.svg
Second Write to Logical EEPROM Page N-1

A third write of the same logical page requires that the EEPROM emulator erase the row, as it has become full. Prior to this, the contents of the unmodified page in the same row as the page being updated will be copied into the spare row, along with the new version of the page being updated. The old (full) row is then erased, resulting in the layout shown in the figure below.

nm1_page_write3.svg
Third Write to Logical EEPROM Page N-1

Special Considerations

NVM Controller Configuration

The EEPROM Emulator service will initialize the NVM controller as part of its own initialization routine; the NVM controller will be placed in Manual Write mode, so that explicit write commands must be sent to the controller to commit a buffered page to physical memory. The manual write command must thus be issued to the NVM controller whenever the user application wishes to write to a NVM page for its own purposes.

Logical EEPROM Page Size

As a small amount of information needs to be stored in a header before the contents of a logical EEPROM page in memory (for use by the emulation service), the available data in each EEPROM page is less than the total size of a single NVM memory page by several bytes.

Committing of the Write Cache

A single-page write cache is used internally to buffer data written to pages in order to reduce the number of physical writes required to store the user data, and to preserve the physical memory lifespan. As a result, it is important that the write cache is committed to physical memory as soon as possible after a BOD low power condition, to ensure that enough power is available to guarantee a completed write so that no data is lost.

The write cache must also be manually committed to physical memory if the user application is to perform any NVM operations using the NVM controller directly.

Extra Information

For extra information, see Extra Information. This includes:

Examples

For a list of examples related to this driver, see Examples for Emulated EEPROM Service.

API Overview

Modules

 
 Quick Start Guide(s)
 In this section you can find a list of all Quick Start guides related to the SAM EEPROM Emulator (EEPROM) Service.
 

Data Structures

struct  eeprom_emulator_parameters
 EEPROM memory parameter structure. More...
 

EEPROM Emulator Information

#define EEPROM_EMULATOR_ID   1
 Emulator scheme ID, identifying the scheme used to emulated EEPROM storage. More...
 
#define EEPROM_MAJOR_VERSION   1
 Emulator major version number, identifying the emulator major version. More...
 
#define EEPROM_MINOR_VERSION   0
 Emulator minor version number, identifying the emulator minor version. More...
 
#define EEPROM_REVISION   0
 Emulator revision version number, identifying the emulator revision. More...
 
#define EEPROM_PAGE_SIZE   (NVMCTRL_PAGE_SIZE - EEPROM_HEADER_SIZE)
 Size of the user data portion of each logical EEPROM page, in bytes. More...
 

Configuration and Initialization

enum status_code eeprom_emulator_init (void)
 Initializes the EEPROM Emulator service. More...
 
void eeprom_emulator_erase_memory (void)
 Erases the entire emulated EEPROM memory space. More...
 
enum status_code eeprom_emulator_get_parameters (struct eeprom_emulator_parameters *const parameters)
 Retrieves the parameters of the EEPROM Emulator memory layout. More...
 

Logical EEPROM Page Reading/Writing

enum status_code eeprom_emulator_commit_page_buffer (void)
 Commits any cached data to physical non-volatile memory. More...
 
enum status_code eeprom_emulator_write_page (const uint8_t logical_page, const uint8_t *const data)
 Writes a page of data to an emulated EEPROM memory page. More...
 
enum status_code eeprom_emulator_read_page (const uint8_t logical_page, uint8_t *const data)
 Reads a page of data from an emulated EEPROM memory page. More...
 

Buffer EEPROM Reading/Writing

enum status_code eeprom_emulator_write_buffer (const uint16_t offset, const uint8_t *const data, const uint16_t length)
 Writes a buffer of data to the emulated EEPROM memory space. More...
 
enum status_code eeprom_emulator_read_buffer (const uint16_t offset, uint8_t *const data, const uint16_t length)
 Reads a buffer of data from the emulated EEPROM memory space. More...
 

#define EEPROM_EMULATOR_ID   1

Emulator scheme ID, identifying the scheme used to emulated EEPROM storage.

Referenced by _eeprom_emulator_create_master_page(), and _eeprom_emulator_verify_master_page().

#define EEPROM_MAJOR_VERSION   1

Emulator major version number, identifying the emulator major version.

Referenced by _eeprom_emulator_create_master_page(), and _eeprom_emulator_verify_master_page().

#define EEPROM_MINOR_VERSION   0

Emulator minor version number, identifying the emulator minor version.

Referenced by _eeprom_emulator_create_master_page(), and _eeprom_emulator_verify_master_page().

#define EEPROM_REVISION   0

Emulator revision version number, identifying the emulator revision.

Referenced by _eeprom_emulator_create_master_page().

enum status_code eeprom_emulator_commit_page_buffer ( void  )

Commits any cached data to physical non-volatile memory.

Commits the internal SRAM caches to physical non-volatile memory, to ensure that any outstanding cached data is preserved. This function should be called prior to a system reset or shutdown to prevent data loss.

Note
This should be the first function executed in a BOD33 Early Warning callback to ensure that any outstanding cache data is fully written to prevent data loss.
This function should also be called before using the NVM controller directly in the user-application for any other purposes to prevent data loss.
Returns
Status code indicating the status of the operation.

References _eeprom_emulator_nvm_commit_cache(), barrier, _eeprom_module::cache, _eeprom_module::cache_active, _eeprom_page::header, _eeprom_page::logical_page, _eeprom_module::page_map, and STATUS_OK.

Referenced by _eeprom_emulator_move_data_to_spare(), eeprom_emulator_write_page(), main(), run_eeprom_buffer_read_write_test(), and run_eeprom_page_read_write_test().

void eeprom_emulator_erase_memory ( void  )

Erases the entire emulated EEPROM memory space.

Erases and re-initializes the emulated EEPROM memory space, destroying any existing data.

References _eeprom_emulator_create_master_page(), _eeprom_emulator_format_memory(), and _eeprom_emulator_update_page_mapping().

Referenced by run_eeprom_init_test().

enum status_code eeprom_emulator_get_parameters ( struct eeprom_emulator_parameters *const  parameters)

Retrieves the parameters of the EEPROM Emulator memory layout.

Retrieves the configuration parameters of the EEPROM Emulator, after it has been initialized.

Parameters
[out]parametersEEPROM Emulator parameter struct to fill
Returns
Status of the operation.
Return values
STATUS_OKIf the emulator parameters were retrieved successfully
STATUS_ERR_NOT_INITIALIZEDIf the EEPROM Emulator is not initialized

References eeprom_emulator_parameters::eeprom_number_of_pages, EEPROM_PAGE_SIZE, _eeprom_module::initialized, _eeprom_module::logical_pages, eeprom_emulator_parameters::page_size, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.

Referenced by run_eeprom_init_test().

enum status_code eeprom_emulator_init ( void  )

Initializes the EEPROM Emulator service.

Initializes the emulated EEPROM memory space; if the emulated EEPROM memory has not been previously initialized, it will need to be explicitly formatted via eeprom_emulator_erase_memory(). The EEPROM memory space will not be automatically erased by the initialization function, so that partial data may be recovered by the user application manually if the service is unable to initialize successfully.

Returns
Status code indicating the status of the operation.
Return values
STATUS_OKEEPROM emulation service was successfully initialized
STATUS_ERR_NO_MEMORYNo EEPROM section has been allocated in the device
STATUS_ERR_BAD_FORMATEmulated EEPROM memory is corrupt or not formatted
STATUS_ERR_IOEEPROM data is incompatible with this version or scheme of the EEPROM emulator

References _eeprom_emulator_update_page_mapping(), _eeprom_emulator_verify_master_page(), _eeprom_module::cache_active, nvm_parameters::eeprom_number_of_pages, _eeprom_module::flash, _eeprom_module::initialized, _eeprom_module::logical_pages, nvm_config::manual_page_write, nvm_get_config_defaults(), nvm_get_parameters(), nvm_set_config(), _eeprom_module::physical_pages, _eeprom_module::spare_row, STATUS_BUSY, STATUS_ERR_BAD_FORMAT, STATUS_ERR_NO_MEMORY, and STATUS_OK.

Referenced by run_eeprom_init_test().

enum status_code eeprom_emulator_read_buffer ( const uint16_t  offset,
uint8_t *const  data,
const uint16_t  length 
)

Reads a buffer of data from the emulated EEPROM memory space.

Reads a buffer of data from a section of emulated EEPROM memory space. The destination buffer may be of any size, and the source may lie outside of an emulated EEPROM page boundary.

Parameters
[in]offsetStarting byte offset to read from, in emulated EEPROM memory space
[out]dataPointer to the data buffer containing source data to read
[in]lengthLength of the data to read, in bytes
Returns
Status code indicating the status of the operation.
Return values
STATUS_OKIf the page was successfully read
STATUS_ERR_NOT_INITIALIZEDIf the EEPROM emulator is not initialized
STATUS_ERR_BAD_ADDRESSIf an address outside the valid emulated EEPROM memory space was supplied

Perform the initial page read

References buffer, eeprom_emulator_read_page(), EEPROM_PAGE_SIZE, _eeprom_page::logical_page, and STATUS_OK.

Referenced by run_eeprom_buffer_read_write_test().

enum status_code eeprom_emulator_read_page ( const uint8_t  logical_page,
uint8_t *const  data 
)

Reads a page of data from an emulated EEPROM memory page.

Reads an emulated EEPROM page of data from the emulated EEPROM memory space.

Parameters
[in]logical_pageLogical EEPROM page number to read from
[out]dataPointer to the destination data buffer to fill
Returns
Status code indicating the status of the operation.
Return values
STATUS_OKIf the page was successfully read
STATUS_ERR_NOT_INITIALIZEDIf the EEPROM emulator is not initialized
STATUS_ERR_BAD_ADDRESSIf an address outside the valid emulated EEPROM memory space was supplied

References _eeprom_emulator_nvm_read_page(), _eeprom_module::cache, _eeprom_module::cache_active, _eeprom_page::data, EEPROM_PAGE_SIZE, _eeprom_page::header, _eeprom_module::initialized, _eeprom_page::logical_page, _eeprom_module::logical_pages, _eeprom_module::page_map, STATUS_ERR_BAD_ADDRESS, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.

Referenced by eeprom_emulator_read_buffer(), eeprom_emulator_write_buffer(), main(), and run_eeprom_page_read_write_test().

enum status_code eeprom_emulator_write_buffer ( const uint16_t  offset,
const uint8_t *const  data,
const uint16_t  length 
)

Writes a buffer of data to the emulated EEPROM memory space.

Writes a buffer of data to a section of emulated EEPROM memory space. The source buffer may be of any size, and the destination may lie outside of an emulated EEPROM page boundary.

Note
Data stored in pages may be cached in volatile RAM memory; to commit any cached data to physical non-volatile memory, the eeprom_emulator_commit_page_buffer() function should be called.
Parameters
[in]offsetStarting byte offset to write to, in emulated EEPROM memory space
[in]dataPointer to the data buffer containing source data to write
[in]lengthLength of the data to write, in bytes
Returns
Status code indicating the status of the operation.
Return values
STATUS_OKIf the page was successfully read
STATUS_ERR_NOT_INITIALIZEDIf the EEPROM emulator is not initialized
STATUS_ERR_BAD_ADDRESSIf an address outside the valid emulated EEPROM memory space was supplied

Perform the initial page read if necessary

References buffer, eeprom_emulator_read_page(), eeprom_emulator_write_page(), EEPROM_PAGE_SIZE, _eeprom_page::logical_page, and STATUS_OK.

Referenced by run_eeprom_buffer_read_write_test().

enum status_code eeprom_emulator_write_page ( const uint8_t  logical_page,
const uint8_t *const  data 
)

Writes a page of data to an emulated EEPROM memory page.

Writes an emulated EEPROM page of data to the emulated EEPROM memory space.

Note
Data stored in pages may be cached in volatile RAM memory; to commit any cached data to physical non-volatile memory, the eeprom_emulator_commit_page_buffer() function should be called.
Parameters
[in]logical_pageLogical EEPROM page number to write to
[in]dataPointer to the data buffer containing source data to write
Returns
Status code indicating the status of the operation.
Return values
STATUS_OKIf the page was successfully read
STATUS_ERR_NOT_INITIALIZEDIf the EEPROM emulator is not initialized
STATUS_ERR_BAD_ADDRESSIf an address outside the valid emulated EEPROM memory space was supplied

References _eeprom_emulator_is_page_free_on_row(), _eeprom_emulator_move_data_to_spare(), _eeprom_emulator_nvm_fill_cache(), barrier, _eeprom_module::cache, _eeprom_module::cache_active, _eeprom_page::data, eeprom_emulator_commit_page_buffer(), EEPROM_PAGE_SIZE, _eeprom_page::header, _eeprom_module::initialized, _eeprom_page::logical_page, _eeprom_module::logical_pages, _eeprom_module::page_map, STATUS_ERR_BAD_ADDRESS, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.

Referenced by eeprom_emulator_write_buffer(), main(), and run_eeprom_page_read_write_test().