This driver for Atmel® | SMART ARM®-based microcontrollers provides an RWW emulated EEPROM memory area, for the storage and retrieval of user-application configuration data into and out of non-volatile memory.
The main array can therefore run code while EEPROM data is written.
The following peripheral is used by this module:
The following devices can use this module:
The outline of this documentation is as follows:
There are no prerequisites for this module.
SAM devices embeds a separate read while write EEPROM emulation (RWWEE) array that can be programmed while the main array is not blocked. To use RWWEE 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 RWWEE 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 RWW 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 RWW EEPROM emulated section. 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, 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 RWW 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 updated by an atomic operation, 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 RWW EEPROM page (where possible) and when writes across multiple logical RWW EEPROM pages are made in a linear fashion through the entire emulated RWW EEPROM space.
RWW EEPROM emulator is divided into a number of physical rows, each containing four identically sized 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 RWW EEPROM segment is a dedicated space that are memory mapped, as shown in the figure below.
One physical row at the end of the emulated RWW 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 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 row initially stores the contents of one or two logical RWW EEPROM memory pages (it depends on application configuration file). This quarters or halves the available storage space for the emulated RWW EEPROM but reduces the overall number of row erases that are required, by reserving two or three pages within each row for updated versions of the logical page contents. See here for a visual layout of the RWW 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.
When it is configured, each physical row stores the contents of one logical RWW EEPROM memory page. This system will allow for the same logical page to be updated up to four times into the physical memory before a row erasure procedure is needed. In the case of multiple versions of the same logical RWW EEPROM page being stored in the same physical row, the right-most (highest physical 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 RWW 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 RWW 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 RWW EEPROM page is physically stored as the page content and a header inside a single physical page, as shown in the following figure.
Within the RWW 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 RWW EEPROM page needs to be committed to physical memory, the next free 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 four 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 RWW EEPROM page results in the layout shown in the figure below.
A third write of the same logical RWW EEPROM page results in the layout shown in the figure below.
A fourth write of the same logical page requires that the RWW EEPROM emulator erase the row, as it has become full. Prior to this, the content 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 RWW 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 content of a logical EEPROM page in memory (for use by the emulation service), the available data in each RWW 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 each page, a checksum function is used to verify the integrity of the page data. When reading the page data, using rww_eeprom_emulator_read_page(). When its checksum is not correct, an error can be detected. This function can be enabled or disabled through the configuration file.
For extra information, see Extra Information. This includes:
For a list of examples related to this driver, see Examples for Emulated RWW EEPROM Service.
Data Structures | |
struct | rww_eeprom_emulator_parameters |
RWW EEPROM memory parameter structure. More... | |
Enumerations | |
enum | rwwee_logical_page_num_in_row { RWWEE_LOGICAL_PAGE_NUM_1 = 1, RWWEE_LOGICAL_PAGE_NUM_2 = 2 } |
RWW EEPROM Logical Page in Each Row. More... | |
RWW EEPROM Emulator Information | |
#define | RWW_EEPROM_EMULATOR_ID 1 |
Emulator scheme ID, identifying the scheme used to emulated EEPROM storage. More... | |
#define | RWW_EEPROM_MAJOR_VERSION 1 |
Emulator major version number, identifying the emulator major version. More... | |
#define | RWW_EEPROM_MINOR_VERSION 0 |
Emulator minor version number, identifying the emulator minor version. More... | |
#define | RWW_EEPROM_REVISION 0 |
Emulator revision version number, identifying the emulator revision. More... | |
#define | RWW_EEPROM_PAGE_SIZE (NVMCTRL_PAGE_SIZE - RWW_EEPROM_HEADER_SIZE) |
Size of the user data portion of each logical EEPROM page, in bytes. More... | |
Configuration and Initialization | |
enum status_code | rww_eeprom_emulator_init (void) |
Initializes the RWW EEPROM Emulator service. More... | |
void | rww_eeprom_emulator_erase_memory (void) |
Erases the entire emulated RWW EEPROM memory space. More... | |
enum status_code | rww_eeprom_emulator_get_parameters (struct rww_eeprom_emulator_parameters *const parameters) |
Retrieves the parameters of the RWW EEPROM Emulator memory layout. More... | |
Logical RWW EEPROM Page Reading/Writing | |
enum status_code | rww_eeprom_emulator_commit_page_buffer (void) |
Commits any cached data to physical non-volatile memory. More... | |
enum status_code | rww_eeprom_emulator_write_page (const uint8_t logical_page, const uint8_t *const data) |
Writes a page of data to an emulated RWW EEPROM memory page. More... | |
enum status_code | rww_eeprom_emulator_read_page (const uint8_t logical_page, uint8_t *const data) |
Reads a page of data from an emulated RWW EEPROM memory page. More... | |
Buffer RWW EEPROM Reading/Writing | |
enum status_code | rww_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 RWW EEPROM memory space. More... | |
enum status_code | rww_eeprom_emulator_read_buffer (const uint16_t offset, uint8_t *const data, const uint16_t length) |
Reads a buffer of data from the emulated RWW EEPROM memory space. More... | |
#define RWW_EEPROM_EMULATOR_ID 1 |
Emulator scheme ID, identifying the scheme used to emulated EEPROM storage.
Referenced by _rww_eeprom_emulator_create_master_page(), and _rww_eeprom_emulator_verify_master_page().
#define RWW_EEPROM_MAJOR_VERSION 1 |
Emulator major version number, identifying the emulator major version.
Referenced by _rww_eeprom_emulator_create_master_page(), and _rww_eeprom_emulator_verify_master_page().
#define RWW_EEPROM_MINOR_VERSION 0 |
Emulator minor version number, identifying the emulator minor version.
Referenced by _rww_eeprom_emulator_create_master_page(), and _rww_eeprom_emulator_verify_master_page().
#define RWW_EEPROM_PAGE_SIZE (NVMCTRL_PAGE_SIZE - RWW_EEPROM_HEADER_SIZE) |
Size of the user data portion of each logical EEPROM page, in bytes.
Referenced by _rww_eeprom_emulator_move_data_to_spare(), _rww_eeprom_emulator_page_checksum(), rww_eeprom_emulator_get_parameters(), rww_eeprom_emulator_read_buffer(), rww_eeprom_emulator_read_page(), rww_eeprom_emulator_write_buffer(), and rww_eeprom_emulator_write_page().
#define RWW_EEPROM_REVISION 0 |
Emulator revision version number, identifying the emulator revision.
Referenced by _rww_eeprom_emulator_create_master_page().
enum status_code rww_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 _rww_eeprom_emulator_nvm_commit_cache(), barrier, _rww_eeprom_module::cache, _rww_eeprom_module::cache_active, _rww_eeprom_page::header, _rww_eeprom_page::logical_page, _rww_eeprom_module::page_map, and STATUS_OK.
Referenced by _rww_eeprom_emulator_move_data_to_spare(), and rww_eeprom_emulator_write_page().
void rww_eeprom_emulator_erase_memory | ( | void | ) |
Erases the entire emulated RWW EEPROM memory space.
Erases and re-initializes the emulated RWW EEPROM memory space, destroying any existing data.
Master page should be created during uninitialized status
References _rww_eeprom_emulator_create_master_page(), _rww_eeprom_emulator_format_memory(), _rww_eeprom_emulator_update_page_mapping(), and _rww_eeprom_module::initialized.
enum status_code rww_eeprom_emulator_get_parameters | ( | struct rww_eeprom_emulator_parameters *const | parameters | ) |
Retrieves the parameters of the RWW EEPROM Emulator memory layout.
Retrieves the configuration parameters of the RWW EEPROM Emulator, after it has been initialized.
[out] | parameters | RWW EEPROM Emulator parameter struct to fill |
STATUS_OK | If the emulator parameters were retrieved successfully |
STATUS_ERR_NOT_INITIALIZED | If the RWW EEPROM Emulator is not initialized |
References rww_eeprom_emulator_parameters::eeprom_number_of_pages, _rww_eeprom_module::initialized, _rww_eeprom_module::logical_pages, rww_eeprom_emulator_parameters::page_size, RWW_EEPROM_PAGE_SIZE, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.
enum status_code rww_eeprom_emulator_init | ( | void | ) |
Initializes the RWW EEPROM Emulator service.
Initializes the emulated RWW EEPROM memory space. If the emulated RWW EEPROM memory has not been previously initialized, it will need to be explicitly formatted via rww_eeprom_emulator_erase_memory(). The RWW EEPROM memory space will not be automatically erased by the initialization function. Partial data may be recovered by the user application manually if the service is unable to initialize successfully.
STATUS_OK | RWW EEPROM emulation service was successfully initialized |
STATUS_ERR_BAD_FORMAT | Emulated RWW EEPROM memory is corrupt or not formatted |
STATUS_ERR_IO | RWW EEPROM data is incompatible with this version or scheme of the RWW EEPROM emulator |
STATUS_ERR_INVALID_ARG | Invalid logical page configuration |
References _rww_eeprom_emulator_update_page_mapping(), _rww_eeprom_emulator_verify_master_page(), _rww_eeprom_module::cache_active, CONF_LOGICAL_PAGE_NUM_IN_ROW, _rww_eeprom_module::initialized, _rww_eeprom_module::logical_pages, nvm_config::manual_page_write, nvm_get_config_defaults(), nvm_get_parameters(), nvm_set_config(), _rww_eeprom_module::physical_pages, RWW_EEPROM_MAX_LOGICAL_PAGES, _rww_eeprom_module::rwwee_addr, RWWEE_LOGICAL_PAGE_NUM_1, RWWEE_LOGICAL_PAGE_NUM_2, _rww_eeprom_module::spare_row, STATUS_BUSY, STATUS_ERR_BAD_FORMAT, STATUS_ERR_INVALID_ARG, and STATUS_OK.
enum status_code rww_eeprom_emulator_read_buffer | ( | const uint16_t | offset, |
uint8_t *const | data, | ||
const uint16_t | length | ||
) |
Reads a buffer of data from the emulated RWW EEPROM memory space.
Reads a buffer of data from a section of emulated RWW EEPROM memory space. The destination buffer may be of any size, and the source may lie outside of an emulated RWW EEPROM page boundary.
[in] | offset | Starting byte offset to read from, in emulated RWW 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 RWW EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated RWW EEPROM memory space was supplied |
Perform the initial page read
References _rww_eeprom_page::logical_page, rww_eeprom_emulator_read_page(), RWW_EEPROM_PAGE_SIZE, and STATUS_OK.
enum status_code rww_eeprom_emulator_read_page | ( | const uint8_t | logical_page, |
uint8_t *const | data | ||
) |
Reads a page of data from an emulated RWW EEPROM memory page.
Reads an emulated RWW EEPROM page of data from the emulated RWW EEPROM memory space.
[in] | logical_page | Logical RWW 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 RWW EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated RWW EEPROM memory space was supplied |
STATUS_ERR_BAD_FORMAT | Page data checksum is not correct, maybe data is damaged |
References _rww_eeprom_emulator_nvm_read_page(), _rww_eeprom_module::cache, _rww_eeprom_module::cache_active, _rww_eeprom_page::data, _rww_eeprom_page::header, _rww_eeprom_module::initialized, _rww_eeprom_page::logical_page, _rww_eeprom_module::logical_pages, _rww_eeprom_module::page_map, RWW_EEPROM_PAGE_SIZE, STATUS_ERR_BAD_ADDRESS, STATUS_ERR_BAD_FORMAT, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.
Referenced by rww_eeprom_emulator_read_buffer(), and rww_eeprom_emulator_write_buffer().
enum status_code rww_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 RWW EEPROM memory space.
Writes a buffer of data to a section of emulated RWW EEPROM memory space. The source buffer may be of any size, and the destination may lie outside of an emulated RWW EEPROM page boundary.
[in] | offset | Starting byte offset to write to, in emulated RWW 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 RWW EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated RWW EEPROM memory space was supplied |
Perform the initial page read if necessary
References _rww_eeprom_page::logical_page, rww_eeprom_emulator_read_page(), rww_eeprom_emulator_write_page(), RWW_EEPROM_PAGE_SIZE, and STATUS_OK.
enum status_code rww_eeprom_emulator_write_page | ( | const uint8_t | logical_page, |
const uint8_t *const | data | ||
) |
Writes a page of data to an emulated RWW EEPROM memory page.
Writes an emulated RWW EEPROM page of data to the emulated RWW EEPROM memory space.
[in] | logical_page | Logical RWW 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 RWW EEPROM emulator is not initialized |
STATUS_ERR_BAD_ADDRESS | If an address outside the valid emulated RWW EEPROM memory space was supplied |
References _rww_eeprom_emulator_is_page_free_on_row(), _rww_eeprom_emulator_move_data_to_spare(), _rww_eeprom_emulator_nvm_fill_cache(), barrier, _rww_eeprom_module::cache, _rww_eeprom_module::cache_active, _rww_eeprom_page::data, _rww_eeprom_page::header, _rww_eeprom_module::initialized, _rww_eeprom_page::logical_page, _rww_eeprom_module::logical_pages, _rww_eeprom_module::page_map, rww_eeprom_emulator_commit_page_buffer(), RWW_EEPROM_PAGE_SIZE, STATUS_ERR_BAD_ADDRESS, STATUS_ERR_NOT_INITIALIZED, and STATUS_OK.
Referenced by rww_eeprom_emulator_write_buffer().