Non-Volatile Memory (NVMEM)
The NVMEM subsystem provides a generic interface for accessing non-volatile memory devices. It abstracts the underlying hardware and provides a unified API for reading and writing data.
Key Concepts
NVMEM Provider
An NVMEM provider is a driver that exposes NVMEM cells. For example, an EEPROM driver can be an NVMEM provider. The NVMEM provider is responsible for reading and writing data to the underlying hardware.
NVMEM Cell
An NVMEM cell is a region of non-volatile memory. It is defined in the devicetree and has properties like offset, size, and read-only status.
NVMEM Consumer
An NVMEM consumer is a driver or application that uses NVMEM cells to store or retrieve data.
Configuration
CONFIG_NVMEM: Enables the NVMEM subsystem.CONFIG_NVMEM_BBRAM: Enables NVMEM support for Battery Backed RAM.CONFIG_NVMEM_EEPROM: Enables NVMEM support for EEPROM devices.CONFIG_NVMEM_FLASH.*: Configure NVMEM support for flash devices.CONFIG_NVMEM_OTP.*: Configure NVMEM support for OTP devices.
Devicetree Bindings
The NVMEM subsystem relies on devicetree bindings to define NVMEM cells. The following is an example of how to define an NVMEM provider and cells in the devicetree:
&eeprom0 {
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
mac_address: mac_address@0 {
reg = <0x0 6>;
#nvmem-cell-cells = <0>;
read-only;
};
calibration_data: calibration_data@6 {
reg = <0x6 100>;
#nvmem-cell-cells = <0>;
};
};
};
The reg property is an array containing:
The offset in the memory in which we are creating the cell,
The size of the cell, in bytes.
#nvmem-cell-cells describes the number of property items in the phandle,
see Specifier cell names (*-cells), typically set to zero.
A consumer can then reference the NVMEM cells like this:
my_consumer: my-consumer {
compatible = "my,consumer";
nvmem-cells = <&mac_address>, <&calibration_data>;
nvmem-cell-names = "mac-address", "calibration-data";
};
Usage Example
The following is an example of how to use the NVMEM API to read data from an NVMEM cell:
#include <zephyr/nvmem.h>
static const struct nvmem_cell mac_address =
NVMEM_CELL_GET_BY_NAME(DT_NODELABEL(my_consumer), mac_address);
int main(void)
{
uint8_t mac[6];
int ret;
if (!nvmem_cell_is_ready(&mac_address)) {
printk("NVMEM cell is not ready\n");
return -ENODEV;
}
ret = nvmem_cell_read(&mac_address, mac, 0, sizeof(mac));
if (ret < 0) {
printk("Failed to read MAC address: %d\n", ret);
return ret;
}
/* ... */
}