Skip to content
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

Add EEPROM library #126

Draft
wants to merge 3 commits into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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 <purvayeshi550@gmail.com>
*
* 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);
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;
58 changes: 58 additions & 0 deletions libraries/EEPROM/EEPROM.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2025 Purva Yeshi <purvayeshi550@gmail.com>
*
* 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)
58 changes: 58 additions & 0 deletions samples/eeprom_operations/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. _eeprom_operations:

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

Overview
********

Read and write data from flash memory using this sample.

Prerequisites and Setup
***********************

Use any board that supports Zephyr RTOS.
This example uses **BeagleConnect Freedom**.

For setup, refer to the `documentation <https://docs.beagle.cc/boards/beagleconnect/freedom/demos-and-tutorials/using-arduino-zephyr-template.html#setup-arduino-workspace>`_.

Build and Test
**************

Follow these steps to set up and run the sample in the `arduino-workspace` directory:

1. **Set up the virtual environment:**

.. code-block:: bash

source .venv/bin/activate

2. **Build the EEPROM operations sample:**

.. code-block:: bash

west build -b beagleconnect_freedom modules/lib/Arduino-Zephyr-API/samples/eeprom_operations -p

3. **Flash the code after connecting BeagleConnect Freedom to your device:**

.. code-block:: bash

west flash

4. **Open the serial console to view the output:**

.. code-block:: bash

tio /dev/ttyACM0

Sample Output
*************

Run the code and observe the following output:

.. code-block:: text

Serial communication initialized
NVS initialized
Data written successfully
Data read: 1234
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 <purvayeshi550@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/

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

void setup() {

int data = 1234; // Example data to store
int read_data = 0;

/* 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 */
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 */
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() {

}