Skip to content

Add EEPROM library #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libraries/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

add_subdirectory(Wire)
add_subdirectory(SPI)
add_subdirectory(EEPROM)

6 changes: 6 additions & 0 deletions libraries/EEPROM/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_include_directories(.)

if(NOT DEFINED ARDUINO_BUILD_PATH)
zephyr_sources_ifdef(CONFIG_EEPROM EEPROM.cpp)
endif()
86 changes: 86 additions & 0 deletions libraries/EEPROM/EEPROM.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Purva Yeshi <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/device.h>
#include <string.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/storage/flash_map.h>
#include <zephyr/fs/nvs.h>
#include <zephyr/logging/log.h>

#include "EEPROM.h"

static struct nvs_fs fs;

#define NVS_PARTITION storage_partition
#define NVS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(NVS_PARTITION)
#define NVS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(NVS_PARTITION)

/* Register a module for logging */
LOG_MODULE_REGISTER(eeprom, LOG_LEVEL_INF);

int arduino::ZephyrEEPROM::nvs_init(void)
{
int rc = 0;

struct flash_pages_info info;

fs.flash_device = NVS_PARTITION_DEVICE;
if (!device_is_ready(fs.flash_device)) {
LOG_ERR("Flash device %s is not ready", fs.flash_device->name);
return -ENODEV;
}

fs.offset = NVS_PARTITION_OFFSET;

rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
if (rc) {
LOG_ERR("Unable to get page info");
return rc;
}

fs.sector_size = info.size;
fs.sector_count = 3U;

rc = nvs_mount(&fs);
if (rc) {
LOG_ERR("Flash Init failed");
return rc;
}

LOG_INF("NVS initialized successfully");
return 0;
}

int arduino::ZephyrEEPROM::read_data(uint16_t id, void *data, size_t max_len)
{
/* Correctly pass data and max_len */
int rc = nvs_read(&fs, id, data, max_len);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just helping debug the issues that you're facing, have you first tried pure zephyr samples?
https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/subsys/nvs

Do these work?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I already tried the Zephyr NVS sample, but it is also failing with the same error I encountered while testing this code.
image

if (rc > 0) {
/* Data successfully read */
return rc;
} else if (rc == 0) {
LOG_ERR("Data not found for ID: %d", id);
} else {
LOG_ERR("Error reading data for ID: %d, Error: %d", id, rc);
}
/* Return the result code, which can indicate an error or success */
return rc;
}

int arduino::ZephyrEEPROM::write_data(uint16_t id, const void *data, size_t data_len)
{
/* Pass data directly */
int rc = nvs_write(&fs, id, data, data_len);
if (rc < 0) {
LOG_ERR("Error writing data for ID: %d, Error: %d", id, rc);
}
return rc;
}

arduino::ZephyrEEPROM EEPROM;
61 changes: 61 additions & 0 deletions libraries/EEPROM/EEPROM.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2025 Purva Yeshi <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <zephyr/kernel.h>
#include <zephyr/fs/nvs.h>

#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/storage/flash_map.h>
#include <string.h>
#include <stdio.h>
#include <zephyr/sys/reboot.h>

namespace arduino {

class ZephyrEEPROM {
public:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the indent correct? Doesn't public need some indentation?

Copy link
Author

@purviyeshi purviyeshi Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both styles work the same in C++, but typically, access specifiers like public are aligned with the class definition. However, the content under access specifiers should have half-indentation for better consistency, I'll make changes. I also referred to the Wire library codebase.

/* Constructor */
ZephyrEEPROM() = default;

/* Initialize the NVS storage (mounts the NVS file system) */
int nvs_init(void);


/*
* Write data to NVS
*
* Parameters:
* - id: Unique identifier for the data
* - data: Pointer to the data to write
* - data_len: Length of the data to write
*/
int write_data(uint16_t id, const void *data, size_t data_len);


/*
* Read data from NVS
*
* Parameters:
* - id: Unique identifier for the data
* - data: Pointer to buffer where the data will be read into
* - max_len: Maximum length of data to read
*/
int read_data(uint16_t id, void *data, size_t max_len);


private:
/* NVS file system structure used for managing flash memory */
struct nvs_fs fs;
};

}

extern arduino::ZephyrEEPROM EEPROM;


13 changes: 13 additions & 0 deletions samples/eeprom_operations/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

cmake_path(SET ZephyrBase $ENV{ZEPHYR_BASE})
set(DTC_OVERLAY_FILE ${ZephyrBase}/../modules/lib/Arduino-Zephyr-API/variants/${BOARD}/${BOARD}.overlay)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(eeprom_operations)

target_sources(app PRIVATE src/app.cpp)

zephyr_compile_options(-Wno-unused-variable -Wno-comment)
9 changes: 9 additions & 0 deletions samples/eeprom_operations/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _eeprom_operations:

EEPROM Operations
###############

Overview
********

A sample that reads data from flash memory, as well as writes data to flash memory.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some sort of sample output will be good to show.
Also a build command to show how to build this sample can make things much easier for any new users

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure, I'll add a sample output and include a build command.

23 changes: 23 additions & 0 deletions samples/eeprom_operations/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CONFIG_GPIO=y
CONFIG_ARDUINO_API=y
CONFIG_SPI=y
CONFIG_EEPROM=yCONFIG_FLASH_PAGE_LAYOUT

CONFIG_PWM=y
CONFIG_ADC=y
CONFIG_GPIO_GET_DIRECTION=y

CONFIG_LOG=y
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_ENTROPY_GENERATOR=y

CONFIG_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y

CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_NVS_LOG_LEVEL_DBG=y
CONFIG_REBOOT=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y

CONFIG_FLASH_PAGE_LAYOUT=y
47 changes: 47 additions & 0 deletions samples/eeprom_operations/src/app.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Purva Yeshi <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/


#include <Arduino.h>
#include "EEPROM.h"

void setup() {
/* Initialize serial communication */
Serial.begin(115200);
while (!Serial) {

; /* Wait for serial port to connect (needed for boards with native USB) */
}
Serial.println("Serial communication initialized");

/* Initialize EEPROM/NVS */
if (EEPROM.nvs_init() < 0) {
Serial.println("NVS initialization failed");
return;
}
Serial.println("NVS initialized");

/* Write data to EEPROM */
int data = 1234; // Example data to store
if (EEPROM.write_data(1, &data, sizeof(data)) < 0) {
Serial.println("Failed to write data");
} else {
Serial.println("Data written successfully");
}

/* Read data from EEPROM */
int read_data = 0;
if (EEPROM.read_data(1, &read_data, sizeof(read_data)) > 0) {
Serial.print("Data read: ");
Serial.println(read_data);
} else {
Serial.println("Failed to read data");
}
}

void loop() {

}