Cypress Em_EEPROM Middleware Library 2.0
Cypress Em_EEPROM Middleware Library

The Emulated EEPROM (Em_EEPROM) middleware emulates an EEPROM storage in PSoC's internal flash memory. The Em_EEPROM middleware operates on the top of the flash driver included in the PSoC 6 Peripheral Driver Library (psoc6pdl).

Use the Em_EEPROM to store non-volatile data on a target device when increasing flash memory endurance and restoring corrupted data from a redundant copy is required.

Features:

  • EEPROM-Like Non-Volatile Storage
  • Easy to use Read and Write
  • Optional Wear Leveling
  • Optional Redundant Data Storage

General Description

Include cy_em_eeprom.h to get access to all functions and other declarations in this library. See the Quick Start Guide to start using the Em_EEPROM.

Refer to the Supported Software and Tools section for compatibility information.

Refer to the Changelog section for differences between Em_EEPROM versions. The Changelog section also describes the impact of the changes to your code.

Em_EEPROM operates on the top of the flash driver. The flash driver has some prerequisites for proper operation. Refer to the "Flash (Flash System Routine)" section of the PSoC 6 Peripheral Driver Library (psoc6pdl) API Reference Manual. Also, refer to the Limitations and Restrictions section for the different Em_EEPROM middleware restrictions and limitations.

The Em_EEPROM middleware can operate in various modes:

  • with or without wear leveling - depending on whether you want to increase the endurance of the flash memory.
  • with or without a redundant copy - depending on how critical for you is the ability to recover information.
  • to save flash and work via Em_EEPROM APIs similar to the flash driver APIs. But, in this case, recovering your data and monitoring the flash endurance is impossible.

There are several use cases depending on where you store your Em_EEPROM data:

  • in the application flash
  • in the auxiliary flash
  • in the application flash at a fixed address.

The Configuration Considerations section provides the guidance for all these operation modes and use cases. You may also want to migrate from PSoC Creator to ModusToolbox or other environment to simply use the Em_EEPROM middleware APIs. Refer to the Migration from PSoC Creator section.

The Quick Start Guide section highlights the use case, when the Em_EEPROM data is located in the application flash, and the Em_EEPROM is configured to increase the flash endurance (the wearLevelingFactor parameter is turned on).

Quick Start Guide

Cypress Em_EEPROM middleware can be used in various Development Environments such as ModusToolbox, MBED, etc. Refer to the Supported Software and Tools section.

The below steps describe the simplest way of enabling the Em_EEPROM middleware with placing EEPROM memory into the application flash.

  1. Open/Create an application where to add the Em_EEPROM function.
  2. Add the Em_EEPROM middleware to your project. This quick start guide assumes that the environment is configured to use the PSoC 6 Peripheral Driver Library (psoc6pdl) for development and the PSoC 6 Peripheral Driver Library (psoc6pdl) is included in the project. If you are using the ModusToolbox development environment select the application in the Project Explorer window and navigate to the Project/ModusToolbox Middleware Selector menu. A window appears, check the Emulated EEPROM middleware and click the OK button.
  3. Include Em_EEPROM in the main.c file:
    #include "cy_em_eeprom.h"
  4. Define the Em_EEPROM configuration as follow:
    /* The maximum size of data to store in EEPROM is one flash row (512 Bytes) */
    #define DATA_SIZE (CY_EM_EEPROM_FLASH_SIZEOF_ROW)
    /* The Simple Mode is turned off */
    #define SIMPLE_MODE (0u)
    /* Increases the flash endurance twice */
    #define WEAR_LEVELING (2u)
    /* The Redundant Copy is turned off */
    #define REDUNDANT_COPY (0u)
    /* The Blocking Write is turned on */
    #define BLOCKING_WRITE (1u)
    Refer to the cy_stc_eeprom_config_t structure for details of other configuration options.
  5. Declare the Em_EEPROM storage variable (further Em_EEPROM Storage) in the application flash:
    const uint8_t emEepromStorage[CY_EM_EEPROM_GET_PHYSICAL_SIZE(DATA_SIZE, SIMPLE_MODE, WEAR_LEVELING, REDUNDANT_COPY)] = {0u};
    The allocated memory must be initialized by zeros, and aligned to the whole row size CY_EM_EEPROM_FLASH_SIZEOF_ROW, otherwise the Em_EEPROM middleware behavior will be unexpected.
    Refer to the Configuration Considerations section for other options of Em_EEPROM flash allocation.
  6. Allocate memory for the Em_EEPROM context structure:
  7. Allocate memory for the Em_EEPROM configuration structure and initialize it:
    cy_stc_eeprom_config_t eepromConfig =
    {
    .eepromSize = DATA_SIZE,
    .simpleMode = SIMPLE_MODE,
    .wearLevelingFactor = WEAR_LEVELING,
    .redundantCopy = REDUNDANT_COPY,
    .blockingWrite = 1u,
    .userFlashStartAddr = (uint32_t)&(emEepromStorage[0u]),
    };
  8. Initialize the Em_EEPROM middleware once at the start:
    if (CY_EM_EEPROM_SUCCESS != Cy_Em_EEPROM_Init(&eepromConfig, &eepromContext))
    {
    //Error check action
    }
  9. Now, the Em_EEPROM middleware is ready to use. Call the Write or Read functions to write or read one byte:
    uint8_t readData = 0xAAu;
    if (CY_EM_EEPROM_SUCCESS != Cy_Em_EEPROM_Write(0u, &readData, 1u, &eepromContext))
    {
    //Error check action
    }
    if (CY_EM_EEPROM_SUCCESS != Cy_Em_EEPROM_Read(0u, &readData, 1u, &eepromContext))
    {
    //Error check action
    }

Configuration Considerations

This section consists of different guides and instruction of how to enable, configure, and use the Emulated EEPROM Middleware in a design. As you can see from the Quick Start Guide section, the settings of the Em_EEPROM middleware are controlled with the cy_stc_eeprom_config_t structure. Please see its description to learn about the parameters and values.

Now we will describe the most common use cases along with the configuration structure examples and code snippets. The list of sections under Configuration Considerations:

Also refer to the Limitations and Restrictions for the existing restrictions.

Operating Modes

The settings of the Em_EEPROM middleware are controlled by the cy_stc_eeprom_config_t structure. See its description to learn about the parameters and values.

Wear Leveling

Depending on whether you want to increase the flash memory endurance or not, enable or disable the wear leveling. The higher the value is, the more flash is used, but a higher number of erase/write cycles can be done on Em_EEPROM. Multiply this number by the datasheet write endurance spec to determine the max of write cycles.
The amount of wear leveling from 1 to 10. 1 means no wear leveling is used.

To configure the wear leveling just set the WEAR_LEVELING macro value from (1u) to (10u) in step #4 in the Quick Start Guide section:

/* Increases the flash endurance twice */
#define WEAR_LEVELING (2u)

Redundant Copy

Depending on how critical for you is recovering information, configure the redundant copy feature. If enabled (1 - enabled, 0 - disabled), a checksum (stored in a row) is calculated on each row of data, while a redundant copy of Em_EEPROM is stored in another location. When data is read, first the checksum is checked. If that checksum is bad, and the redundant copy's checksum is good, the copy is restored.

To configure the redundant copy just set the REDUNDANT_COPY macro value to (1u) or (0u) in step #4 in the Quick Start Guide section:

/* The Redundant Copy is turned off */
#define REDUNDANT_COPY (0u)

Simple Mode

Simple mode, when enabled (1 - enabled, 0 - disabled), means no additional service information is stored by the Em_EEPROM middleware like checksums, headers, a number of writes, etc. Data is stored directly by the specified address. The size of Em_EEPROM storage is equal to the number of byte specified in the eepromSize parameter rounded up to a full row size CY_EM_EEPROM_FLASH_SIZEOF_ROW. The wear leveling and redundant copy features are disabled, i.e. wearLevelingFactor and redundantCopy parameters are ignored.

To configure Simple mode just set the SIMPLE_MODE macro value to (1u) or (0u) in step #4 in the Quick Start Guide section:

/* The Simple Mode is turned off */
#define SIMPLE_MODE (0u)

Em_EEPROM Location

The user is responsible for allocating space in flash for Em_EEPROM (further the Em_EEPROM storage).

The Em_EEPROM storage can be placed:

  • in the application flash
  • in the auxiliary flash.

Additionally, the storage can be placed at a fixed address in the application flash.

The storage location must be aligned to CY_EM_EEPROM_FLASH_SIZEOF_ROW.

The storage size depends on other configuration parameters and is calculated using the following equation:

  1. Simple mode is turned on. It means the direct mapping of the user data in the Em_EEPROM storage:

    storageSize = eepromSize

    where:
    eepromSize the number of bytes to store in the Em_EEPROM storage rounded up to a full row size CY_EM_EEPROM_FLASH_SIZEOF_ROW. The row size is specific for a device family. Refer to the specific PSoC device datasheet.

  2. Simple mode is turned off. It means the Em_EEPROM middleware stores service information about number of writes, checksums, etc.

    storageSize = eepromSize * 2 * wearLevelingFactor * (1 + redundantCopy)

    where:
    eepromSize the number of bytes to store in the Em_EEPROM storage rounded up to the half of a row size (CY_EM_EEPROM_FLASH_SIZEOF_ROW / 2u). The row size is specific for a device family. Refer to the specific PSoC device datasheet.

Use the CY_EM_EEPROM_GET_PHYSICAL_SIZE() macro to get the needed storage size depending on the configuration.

Em_EEPROM Location in the application flash

The below example shows placing the Em_EEPROM storage in the application flash for GCC, ARMCC, and IAR compilers:

const uint8_t emEepromStorage[STORAGE_SIZE] = {0u};

where STORAGE_SIZE is the size of the Em_EEPROM storage. Refer to the Em_EEPROM Location section for size calculation equations. For convenience, use the CY_EM_EEPROM_GET_PHYSICAL_SIZE macro to get the needed Em_EEPROM storage size depending on the configuration.

Em_EEPROM Location in the auxiliary flash

Writes to rows affect the endurance of other rows in the same sector. We recommend using the auxiliary flash for frequently-updated data. The below example shows placing the Em_EEPROM storage in the auxiliary flash (section .cy_em_eeprom) for GCC, ARMCC, and IAR compilers.

CY_SECTION(".cy_em_eeprom")
const uint8_t emEepromStorage[STORAGE_SIZE] = {0u};

where STORAGE_SIZE is the size of the storage. Refer to the Em_EEPROM Location section for size calculation equations. For convenience, use the CY_EM_EEPROM_GET_PHYSICAL_SIZE macro to get the needed Em_EEPROM storage size depending on the configuration.

Em_EEPROM Location in the application flash at a fixed address

To allocate the Em_EEPROM storage at a fixed address in the application flash, modify the linker control file (linker script). This requires fundamental knowledge of the linker control file, because there is a risk of receiving a linker error while building the project if you make some improper modifications.

This approach demonstrates adding the storage reservation in the application flash after the application. You must calculate the application end address and select the address of the Em_EEPROM storage so that the memory spaces of the storage and the application do not overlap. You might also add some offset between the application end address and the Em_EEPROM storage start address to ensure there is extra space in case the project code grows.

Em_EEPROM Storage at a Fixed Address for GCC Compiler

  1. Build the project to generate linker scripts.
  2. Open the linker script "cy8c6xx7_cm4_dual.ld" for the CM4 core and search the following declaration:
    etext = . ;
    Paste the following code right after the declaration:
    EM_EEPROM_START_ADDRESS = <EEPROM Storage Address>;
    .my_emulated_eeprom EM_EEPROM_START_ADDRESS :
    {
    KEEP(*(.my_emulated_eeprom))
    } > flash
    where:
    • EEPROM Storage Address is an absolute address in flash where the Em_EEPROM operates. You must define the address value. Ensure the address is aligned to the size of the device's flash row and does not overlap with the memory space used by the application.
    • my_emulated_eeprom is the name of the section where the Em_EEPROM storage will be placed. The name can be changed to any name you choose.
  3. Save the changes and close the file.
  4. Declare the Em_EEPROM storage in the newly created section. To do this, declare an array in flash, aligned to the size of the flash row of the device you are using. An example of such array declaration is the following:
    CY_SECTION(".my_emulated_eeprom")
    const uint8 emEepromStorage[STORAGE_SIZE];
  5. After the Em_EEPROM storage is defined, pass the address to the middleware:
    eepromConfig.userFlashStartAddr = (uint32_t)&(emEepromStorage[0u]);
  6. Build the project to verify the correctness of the linker control file modifications.

Limitations and Restrictions

  • The Em_EEPROM storage location must be initialized with zeros and aligned to the flash row size referred to in the specific PSoC device datasheet otherwise the Em_EEPROM behavior may be unexpected. For convenience, CY_EM_EEPROM_FLASH_SIZEOF_ROW is provided.
  • The Em_EEPROM storage size depends on the configuration. Refer to the Em_EEPROM Location section for size calculation equations. For convenience, the CY_EM_EEPROM_GET_PHYSICAL_SIZE macro is provided.
  • Do not modify the Em_EEPROM context structure cy_stc_eeprom_context_t since it may cause unexpected behavior of the Cy_Em_EEPROM functions that rely on this context structure.
  • The Internal memory address map, flash organization, size of rows, etc. is specific for each device family. Refer to the specific device datasheet for the details.
  • The Read-While-Write (RWW) feature available in PSoC 6 MCU allows you to write to flash while executing the code from flash. There are restrictions on using this feature for EEPROM emulation. There are also multiple constraints for blocking and nonblocking flash operations, relating to interrupts, Power mode, IPC usage, etc. Refer to the "Flash (Flash System Routine)" section of the PSoC 6 Peripheral Driver Library (psoc6pdl) API Reference Manual.
  • Manage auxiliary flash space for both cores of PSoC 6. For PSoC 6, by default, the complier always assigns both cores with full range of auxiliary flash (0x14000000-0x14008000) for EM_EEPROM. Both cores operate on the same flash object. A building error would occur if there is an out-sync operation on the memory range from any single core. If more than one driver and/or middleware occupying the auxiliary flash is simultaneously under used, for example, Bluetooth Low Energy (BLE) and Em_EEPROM, a building error will occur while generating the elf file. The error occurs because there is an auxiliary flash region allocated for BLE to store the Bonding list, and this region will only be allocated to the core where the BLE host lies. This out-sync between the two cores causes the building failure. For details of how to manage the auxiliary flash for both cores properly refer to the Manage Flash Space for Both Cores of PSoC 6 – KBA224173
  • Writing of multiple rows by single the Cy_Em_EEPROM_Write() function may lead to the following behavior: The first row is written, then the device is reset due to power down or other reasons, then the device is powered up again. This leads to data integrity loss: i.e. the first row contains new data while the rest of the rows contain old data and Em_EEPROM will not be able to detect the issue since the row checksum is valid.

Migration from PSoC Creator

This section helps migrate your project from PSoC Creator with the Em_EEPROM component to ModusToolbox or other software environment using the Em_EEPROM middleware.

The migration consists of three steps:

Migration of Em_EEPROM Location

The PSoC Creator Em_EEPROM component has parameter "Use Emulated EEPROM". It defines where the Em_EEPROM storage is located.

  • "Use Emulated EEPROM" = No
    The Em_EEPROM storage is defined by the application program. Then move the Em_EEPROM storage declaration from the PSoC Creator project into the ModusToolbox project. Refer to Em_EEPROM Location to check for other possible options.
  • "Use Emulated EEPROM" = Yes
    The Em_EEPROM component provides Em_EEPROM storage located in the auxiliary flash. The Em_EEPROM middleware requires the storage to be provided by the application program. Therefore, place the below code into your application program.
    CY_SECTION(".cy_em_eeprom")
    const uint8_t emEepromStorage[STORAGE_SIZE] = {0u};
    where STORAGE_SIZE is the size of the storage that can be seen in the Em_EEPROM component customizer as "Actual EEPROM size (bytes)".
    For convenience, use the CY_EM_EEPROM_GET_PHYSICAL_SIZE macro to get the needed Em_EEPROM storage size depending on the configuration.

Migration of Configuration

Allocate memory for Em_EEPROM context and configuration structures, and initialize the configuration structure per the Em_EEPROM component configuration:

cy_stc_eeprom_config_t eepromConfig =
{
.eepromSize = <EEPROM Size>,
.simpleMode = 0u,
.wearLevelingFactor = <Wear Level Factor>,
.redundantCopy = <Redundant Copy>,
.blockingWrite = <Use Blocking Write>,
.userFlashStartAddr = (uint32_t)&(emEepromStorage[0u]),
};

where the right side of initialization is the Em_EEPROM Component customizer parameters and "emEepromStorage" is the name of the storage.

Migration of Function

Now, after the storage and configuration are defined, change the names of the functions used in the PSoC Creator project per the following table:

PSoC Creator Em_EEPROM Component ModusToolbox Em_EEPROM Middleware
EEPROM_Init(xxx) Cy_Em_EEPROM_Init(&eepromConfig, &eepromContext)
EEPROM_Write(X1, X2, X3) Cy_Em_EEPROM_Write(X1, X2, X3, &eepromContext)
EEPROM_Read(X1, X2, X3) Cy_Em_EEPROM_Read(X1, X2, X3, &eepromContext)
EEPROM_Erase() Cy_Em_EEPROM_Erase(&eepromContext)
EEPROM_NumWrites() Cy_Em_EEPROM_NumWrites(&eepromContext)

Note The above table shows the function names with an assumption that the PSoC Creator component name is EEPROM.

Supported Software and Tools

This version of the Em_EEPROM Middleware was validated for the compatibility with the following software and tools:

Software and Tools Version
ModusToolbox Software Environment 2.0
PSoC6 Peripheral Driver Library (PDL) 1.2.0
GCC Compiler 7.2.1
IAR Compiler 8.32
Arm Compiler 6 6.11
MBED OS 5.13.1
FreeRTOS 10.0.1

MISRA-C Compliance

The Cy_Em_EEPROM library's specific deviations:

MISRA Rule Rule Class (Required/Advisory) Rule Description Description of Deviation(s)
3.1 R Cast between a pointer to object and an integral type. The cast is used intentionally for the performance reason.
11.3 A
17.4 R Performing pointer arithmetic The pointer arithmetic is used intentionally for the performance reason.

Changelog

VersionChangesReason for Change
2.0 The Em_EEPROM 2.0 is not backward compatible with the previous version. It was significantly rewritten with changing the behavior of operation, adding many improvements and fixing defects.
However, the application programming interface (API) contains only single change and you can seamlessly migrate to 2.0 version. This change is consist in adding the Simple Mode.
Updated major and minor version defines Follow naming convention
Updated documentation User experience improvement
Changed the CY_EM_EEPROM_EEPROM_DATA_LEN macro by adding the simpleMode parameter Added new mode when wear leveling and redundant copy features are disabled
Fixed MISRA violations Improved the middleware robustness
Fixed the defect of the Cy_Em_EEPROM_Read() function when Emulated EEPROM data corruption in some cases caused infinite loop Fixed Defect
Fixed the defect of the Cy_Em_EEPROM_Read() function when the function returns incorrect data after restoring data from the redundant copy Fixed Defect
Added the mechanism to restore the corrupted redundant copy from the main data copy Improved the Em_EEPROM data reliability
Revised the operation of Cy_Em_EEPROM_Read() and Cy_Em_EEPROM_Init() functions by removing the write operation. Improved the Em_EEPROM functionality
Expanded the checksum verification to the entire row. Improved the Em_EEPROM data reliability
1.10 Flattened the organization of the driver source code into a single source directory and a single include directory Simplified the Driver library directory-structure
1.0.1 Added the Em_EEPROM storage allocation note to the Configuration Considerations Documentation update and clarification
1.0 Initial Version

More Information

For more information, refer to the following documents:

Note
The links to the other software component’s documentation (middleware and PDL) point to GitHub to the latest available version of the software. To get documentation of the specified version, download from GitHub and unzip the component archive. The documentation is available in the docs folder.