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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
A second write of the same logical EEPROM page results in the layout shown in the figure below.
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.
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.
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.
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.
For extra information, see Extra Information. This includes:
For a list of examples related to this driver, see Examples for Emulated 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_PAGE_SIZE (NVMCTRL_PAGE_SIZE - EEPROM_HEADER_SIZE) |
Size of the user data portion of each logical EEPROM page, in bytes.
Referenced by _eeprom_emulator_move_data_to_spare(), eeprom_emulator_get_parameters(), eeprom_emulator_read_buffer(), eeprom_emulator_read_page(), eeprom_emulator_write_buffer(), and eeprom_emulator_write_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.
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(), and eeprom_emulator_write_page().
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().
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.
[out] | parameters | EEPROM Emulator parameter struct to fill |
STATUS_OK | If the emulator parameters were retrieved successfully |
STATUS_ERR_NOT_INITIALIZED | If 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.
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.
STATUS_OK | EEPROM emulation service was successfully initialized |
STATUS_ERR_NO_MEMORY | No EEPROM section has been allocated in the device |
STATUS_ERR_BAD_FORMAT | Emulated EEPROM memory is corrupt or not formatted |
STATUS_ERR_IO | EEPROM 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.
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.
[in] | offset | Starting byte offset to read from, in emulated EEPROM memory space |
[out] | data | Pointer to the data buffer containing source data to read |
[in] | length | Length of the data to read, in bytes |
STATUS_OK | If the page was successfully read |
STATUS_ERR_NOT_INITIALIZED | If the EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated EEPROM memory space was supplied |
Perform the initial page read
References eeprom_emulator_read_page(), EEPROM_PAGE_SIZE, _eeprom_page::logical_page, and STATUS_OK.
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.
[in] | logical_page | Logical EEPROM page number to read from |
[out] | data | Pointer to the destination data buffer to fill |
STATUS_OK | If the page was successfully read |
STATUS_ERR_NOT_INITIALIZED | If the EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If 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(), and eeprom_emulator_write_buffer().
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.
[in] | offset | Starting byte offset to write to, in emulated EEPROM memory space |
[in] | data | Pointer to the data buffer containing source data to write |
[in] | length | Length of the data to write, in bytes |
STATUS_OK | If the page was successfully read |
STATUS_ERR_NOT_INITIALIZED | If the EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated EEPROM memory space was supplied |
Perform the initial page read if necessary
References eeprom_emulator_read_page(), eeprom_emulator_write_page(), EEPROM_PAGE_SIZE, _eeprom_page::logical_page, and STATUS_OK.
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.
[in] | logical_page | Logical EEPROM page number to write to |
[in] | data | Pointer to the data buffer containing source data to write |
STATUS_OK | If the page was successfully read |
STATUS_ERR_NOT_INITIALIZED | If the EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If 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().