diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab901ee4..304223bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,6 +111,7 @@ target_sources(app
openrtx/src/core/voicePrompts.c
openrtx/src/core/voicePromptUtils.c
openrtx/src/core/voicePromptData.S
+ openrtx/src/core/nvmem_access.c
openrtx/src/rtx/rtx.cpp
openrtx/src/rtx/OpMode_FM.cpp
openrtx/src/rtx/OpMode_M17.cpp
diff --git a/meson.build b/meson.build
index 9ce86b02..a5b3b406 100644
--- a/meson.build
+++ b/meson.build
@@ -55,6 +55,7 @@ openrtx_src = ['openrtx/src/core/state.c',
'openrtx/src/core/voicePrompts.c',
'openrtx/src/core/voicePromptUtils.c',
'openrtx/src/core/voicePromptData.S',
+ 'openrtx/src/core/nvmem_access.c',
'openrtx/src/rtx/rtx.cpp',
'openrtx/src/rtx/OpMode_FM.cpp',
'openrtx/src/rtx/OpMode_M17.cpp',
diff --git a/openrtx/include/core/nvmem_access.h b/openrtx/include/core/nvmem_access.h
new file mode 100644
index 00000000..006cf5a2
--- /dev/null
+++ b/openrtx/include/core/nvmem_access.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef NVMEM_ACCESS_H
+#define NVMEM_ACCESS_H
+
+#include
+#include
+#include
+
+/**
+ * Perform a byte-aligned read operation on an NVM area.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param address: start address for the read operation.
+ * @param data: pointer to a buffer where to store the data read.
+ * @param len: number of bytes to read.
+ * @return zero on success, a negative error code otherwise.
+ */
+int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_t len);
+
+/**
+ * Perform a byte-aligned write operation on an NVM area. If the underlying
+ * device requires state syncing, a sync operation is performed at the end of
+ * the write.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param address: start address for the write operation.
+ * @param data: pointer to a buffer containing the data to write.
+ * @param len: number of bytes to write.
+ * @return zero on success, a negative error code otherwise.
+ */
+int nvmArea_write(const struct nvmArea *area, uint32_t address, const void *data,
+ size_t len);
+
+/**
+ * Perform an erase operation on an NVM area. Acceptable start address and size
+ * depend on the NVM device the area belongs to.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param address: start address for the erase operation.
+ * @param size: size of the area to be erased.
+ * @return zero on success, a negative error code otherwise.
+ */
+int nvmArea_erase(const struct nvmArea *area, uint32_t address, size_t size);
+
+/**
+ * Get the parameters of the NVM device associated to a memory area.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @return pointer to the device parameters' data structure.
+ */
+static inline const struct nvmParams *nvmArea_params(const struct nvmArea *area)
+{
+ const struct nvmDevice *dev = area->dev;
+
+ return dev->api->params(dev);
+}
+
+/**
+ * Perform a byte-aligned read operation on an NVM area partition.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param pNum: partition number.
+ * @param address: start address for the read operation.
+ * @param data: pointer to a buffer where to store the data read.
+ * @param len: number of bytes to read.
+ * @return zero on success, a negative error code otherwise.
+ */
+static inline int nvmArea_readPartition(const struct nvmArea *area,
+ const uint32_t pNum, uint32_t offset,
+ void *data, size_t len)
+{
+ const struct nvmPartition *partition = &(area->partitions[pNum]);
+ const size_t startAddr = area->startAddr + partition->offset + offset;
+
+ return nvmArea_read(area, startAddr, data, len);
+}
+
+/**
+ * Perform a byte-aligned write operation on an NVM area partition. If the
+ * underlying device requires state syncing, a sync operation is performed at
+ * the end of the write.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param pNum: partition number.
+ * @param address: start address for the write operation.
+ * @param data: pointer to a buffer containing the data to write.
+ * @param len: number of bytes to write.
+ * @return zero on success, a negative error code otherwise.
+ */
+static inline int nvmArea_writePartition(const struct nvmArea *area,
+ const uint32_t pNum, uint32_t offset,
+ const void *data, size_t len)
+{
+ const struct nvmPartition *partition = &(area->partitions[pNum]);
+ const size_t startAddr = area->startAddr + partition->offset + offset;
+
+ return nvmArea_write(area, startAddr, data, len);
+}
+
+/**
+ * Perform an erase operation on an NVM area partition. Acceptable start address
+ * and size depend on the NVM device the area belongs to.
+ *
+ * @param area: pointer to the NVM are descriptor.
+ * @param pNum: partition number.
+ * @param address: start address for the erase operation.
+ * @param size: size of the area to be erased.
+ * @return zero on success, a negative error code otherwise.
+ */
+static inline int nvmArea_erasePartition(const struct nvmArea *area,
+ const uint32_t pNum, uint32_t offset,
+ size_t size)
+{
+ const struct nvmPartition *partition = &(area->partitions[pNum]);
+ const size_t startAddr = area->startAddr + partition->offset + offset;
+
+ return nvmArea_erase(area, startAddr, size);
+}
+
+#endif
diff --git a/openrtx/src/core/nvmem_access.c b/openrtx/src/core/nvmem_access.c
new file mode 100644
index 00000000..9ede2435
--- /dev/null
+++ b/openrtx/src/core/nvmem_access.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+
+
+/**
+ * \internal
+ * Check if a read/write/erase operation is within the bounds of a given NVM
+ * area.
+ *
+ * @param area: pointer to the NVM area descriptor
+ * @param addr: start address of the read/write/erase operation
+ * @param len: size of the read/write/erase operation
+ * @return true if the operation is within the NVM area bounds
+ */
+static inline bool checkBounds(const struct nvmArea *area, uint32_t addr, size_t len)
+{
+ return (addr >= area->startAddr)
+ && ((addr + len) < (area->startAddr + area->size));
+}
+
+
+int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_t len)
+{
+ const struct nvmDevice *dev = area->dev;
+
+ if(checkBounds(area, address, len) == false)
+ return -EINVAL;
+
+ return dev->api->read(dev, address, data, len);
+}
+
+int nvmArea_write(const struct nvmArea *area, uint32_t address, void *data, size_t len)
+{
+ const struct nvmDevice *dev = area->dev;
+
+ if(checkBounds(area, address, len) == false)
+ return -EINVAL;
+
+ if(dev->api->write == NULL)
+ return -ENOTSUP;
+
+ int ret = dev->api->write(dev, address, data, len);
+ if(ret < 0)
+ return ret;
+
+ if(dev->api->sync != NULL)
+ dev->api->sync(dev);
+
+ return 0;
+}
+
+int nvmArea_erase(const struct nvmArea *area, uint32_t address, size_t size)
+{
+ const struct nvmDevice *dev = area->dev;
+
+ if(checkBounds(area, address, size) == false)
+ return -EINVAL;
+
+ if(dev->api->erase == NULL)
+ return -ENOTSUP;
+
+ return dev->api->erase(dev, address, size);
+}