Hardware Abstraction Layer (HAL)
NVM (Onboard Non-Volatile Memory)

General Description

High level interface to the onboard Non-Volatile memory (Internal Flash, RRAM, OTP region).

Onboard NVM provides non-volatile storage for factory settings, secure data, user firmware, configuration, and bulk data.

This driver allows data to be read from and written to NVM. It also provides the ability to obtain information about the address and characteristics of the NVM block(s) contained on the device. During NVM write time, the device should not be reset (including XRES pin, software reset, and watchdog) or unexpected changes may be made to portions of the NVM. Also, the low-voltage detect circuits should be configured to generate an interrupt instead of a reset.

Note
A Read while Write violation may occur for some devices when a NVM Read operation is initiated in the same or neighboring NVM sector/region where the NVM Write, Erase(if applicable), or Program operation is working. Refer the device datasheet for more information. This violation may cause a HardFault exception. To avoid the Read while Write violation, the user must carefully split the Read and Write operations on NVM sectors/regions which are not neighboring, considering all cores in a multi-processor device. User may edit the linker script to place the code into neighboring sectors/regions. For example, use sectors number 0 and 1 for code and sectors 2 and 3 for data storage.

Features

Code Snippets

Snippet 1: Get NVM Characteristics

Following code snippet demonstrates how to fetch NVM characteristics. Refer mtb_hal_nvm_info_t for more information.

mtb_hal_nvm_t nvm_obj;
uint32_t nvm_start_address = 0;
uint32_t nvm_size = 0;
uint32_t nvm_sector_size = 0;
uint32_t nvm_block_size = 0;
uint8_t nvm_erase_value = 0;
bool is_erase_required = false;
mtb_hal_nvm_setup(&nvm_obj, NULL);
// Get NVM characteristics like NVM type, number of NVM regions and their organization
mtb_hal_nvm_get_info(&nvm_obj, &nvm_info);
for (int index = 0; index < nvm_info.region_count; index++)
{
const mtb_hal_nvm_region_info_t* region_info = nvm_info.regions;
region_info += index;
nvm_type = region_info->nvm_type;
nvm_start_address = region_info->start_address;
nvm_size = region_info->size;
nvm_sector_size = region_info->sector_size;
nvm_block_size = region_info->block_size;
is_erase_required = region_info->is_erase_required;
nvm_erase_value = region_info->erase_value;
}
mtb_hal_nvm_type_t
Enum of Non-volatile memory (NVM) types.
Definition: mtb_hal_nvm.h:137
@ MTB_HAL_NVM_TYPE_FLASH
Internal Flash.
Definition: mtb_hal_nvm.h:139
Information about all of the regions of NVM memory.
Definition: mtb_hal_nvm.h:162
const mtb_hal_nvm_region_info_t * regions
Array of the distinct NVM regions.
Definition: mtb_hal_nvm.h:164
uint8_t region_count
The number of distinct NVM regions.
Definition: mtb_hal_nvm.h:163
Information about a single region of NVM memory.
Definition: mtb_hal_nvm.h:146
uint32_t sector_size
Sector size of the distinct NVM region.
Definition: mtb_hal_nvm.h:152
uint32_t size
Size of the distinct NVM region.
Definition: mtb_hal_nvm.h:151
mtb_hal_nvm_type_t nvm_type
NVM type.
Definition: mtb_hal_nvm.h:147
bool is_erase_required
true = erase required before program, false = erase not required before program.
Definition: mtb_hal_nvm.h:155
uint32_t block_size
Block size (programming granularity) of the distinct NVM region.
Definition: mtb_hal_nvm.h:153
uint8_t erase_value
NVM erase value (if applicable).
Definition: mtb_hal_nvm.h:157
uint32_t start_address
Base address of the distinct NVM region.
Definition: mtb_hal_nvm.h:148
NVM object.
Definition: mtb_hal_hw_types_nvm.h:67

Snippet 2: Blocking NVM Erase-Write and Read

Following code snippet demonstrates blocking NVM write. It uses a constant array with a size equaling the size of one NVM row/block. It uses blocking NVM write operation which blocks the caller until the write is completed. It then verifies the NVM data by comparing the NVM data with the written data.

mtb_hal_nvm_t nvm_obj;
cy_rslt_t result = CY_RSLT_SUCCESS; // NVM Write Status
uint8_t ram_data[512]; // RAM data to be written to NVM
uint8_t nvm_read_data[512]; // RAM data read from NVM for validation
bool compare_status = false; // Compare Status
uint32_t nvm_addr;
mtb_hal_nvm_setup(&nvm_obj, NULL);
// Get NVM characteristics like number of NVM regions, type, and their organization
mtb_hal_nvm_get_info(&nvm_obj, &nvm_info);
// NVM region 0 last block
uint32_t block_num = (nvm_info.regions[0].size/nvm_info.regions[0].block_size) - 1;
// NVM region 0 last block address
nvm_addr = nvm_info.regions[0].start_address + (block_num * nvm_info.regions[0].block_size);
// Initialize the data in RAM that will be written into NVM
for (size_t index = 0; index < sizeof(ram_data); index++)
{
ram_data[index] = (uint8_t)index;
}
if (nvm_info.regions[0].is_erase_required) // Check if erase is required on the given NVM type
{
// Blocking NVM erase prior to NVM write
result = mtb_hal_nvm_erase(&nvm_obj, nvm_addr);
}
if (result == CY_RSLT_SUCCESS)
{
// Blocking NVM write
result = mtb_hal_nvm_program(&nvm_obj, nvm_addr, (const uint32_t*)ram_data);
if (result == CY_RSLT_SUCCESS)
{
// Read NVM data
result =
mtb_hal_nvm_read(&nvm_obj, (uint32_t)nvm_addr, nvm_read_data,
sizeof(nvm_read_data));
if (result == CY_RSLT_SUCCESS)
{
// Verify the data written into NVM by comparing it with the RAM data
if (0 == memcmp(ram_data, nvm_read_data, sizeof(nvm_read_data)))
{
compare_status = true;
}
}
}
}
else
{
// Error erasing NVM
}
cy_rslt_t mtb_hal_nvm_erase(mtb_hal_nvm_t *obj, uint32_t address)
Erase one block of NVM starting at the given address.
Definition: mtb_hal_nvm.c:188
cy_rslt_t mtb_hal_nvm_program(mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
Program one block with the provided data starting at the given address.
Definition: mtb_hal_nvm.c:206
cy_rslt_t mtb_hal_nvm_read(mtb_hal_nvm_t *obj, uint32_t address, uint8_t *data, size_t size)
Read size amount of data starting from the given address of NVM.
Definition: mtb_hal_nvm.c:130
uint32_t cy_rslt_t
Provides the result of an operation as a structured bitfield.
Definition: cy_result.h:481
#define CY_RSLT_SUCCESS
cy_rslt_t return value indicating success
Definition: cy_result.h:508

Snippet 3: Non-blocking NVM Erase-Write and Read

Following code snippet demonstrates non-blocking NVM write. It uses a constant array with a size equaling the size of one NVM row/block. It uses non-blocking NVM write operation which to not block the caller. It then verifies the NVM data by comparing the NVM data with the written data.

Note
When using non-blocking NVM operations:
  • Interrupts must be enabled.
  • NVM memory have to be initialized and configured properly before starting the non-blocking operation.
  • The user must ensure that the CPU is not in critical section for the duration of the non-blocking NVM operation, otherwise NVM operation will not happen and the operation complete mtb_hal_nvm_is_operation_complete() will always return false.
mtb_hal_nvm_t nvm_obj;
cy_rslt_t result = CY_RSLT_SUCCESS; // NVM Write Status
uint8_t ram_data[512]; // RAM data to be written to NVM
uint8_t nvm_read_data[512]; // RAM data read from NVM for validation
bool compare_status = false; // Compare Status
uint32_t nvm_addr;
/* Option 1. Non-blocking NVM operations using polling */
#if defined(CY_IP_MXS40FLASHC)
// Flash initialization required for non-blocking Flash operations
Cy_Flash_Init(false);
#endif /* defined(CY_IP_MXS40FLASHC) */
mtb_hal_nvm_setup(&nvm_obj, NULL);
// Get NVM characteristics like number of NVM regions, type, and their organization
mtb_hal_nvm_get_info(&nvm_obj, &nvm_info);
// NVM region 0 last block
uint32_t block_num = (nvm_info.regions[0].size/nvm_info.regions[0].block_size) - 1;
// NVM region 0 last block address
nvm_addr = nvm_info.regions[0].start_address + (block_num * nvm_info.regions[0].block_size);
// Initialize the data in RAM that will be written into NVM
for (size_t index = 0; index < sizeof(ram_data); index++)
{
ram_data[index] = (uint8_t)index;
}
if (nvm_info.regions[0].is_erase_required) // Check if erase is required on the given NVM type
{
// Non-blocking NVM erase prior to NVM write
result = mtb_hal_nvm_erase_nb(&nvm_obj, nvm_addr);
}
if (result == CY_RSLT_SUCCESS)
{
/* Non-blocking NVM operations with polling */
// Non-blocking NVM write
result = mtb_hal_nvm_program_nb(&nvm_obj, nvm_addr, (const uint32_t*)ram_data);
if (result == CY_RSLT_SUCCESS)
{
// Wait for the operation to complete
{
}
// Read NVM data
result =
mtb_hal_nvm_read(&nvm_obj, (uint32_t)nvm_addr, nvm_read_data,
sizeof(nvm_read_data));
if (result == CY_RSLT_SUCCESS)
{
// Verify the data written into NVM by comparing it with the RAM data
if (0 == memcmp(ram_data, nvm_read_data, sizeof(nvm_read_data)))
{
compare_status = true;
}
}
}
#if defined(CY_IP_MXS40FLASHC)
/* Option 2. Non-blocking NVM operations using flash callbacks.
* Supported on Flash NVM.
*
* For example, flash_irq_complete_callback will be like this
*
* bool flash_operation_complete;
* void flash_irq_complete_callback(void)
* {
* flash_operation_complete = true;
* }
*/
// Flash initialization required for non-blocking Flash operations
Cy_Flash_Init(false);
// Setup flash callbacks for non-blocking operations
cy_stc_flash_callback_t config = {0};
config.callback_operation_complete = flash_irq_complete_callback;
// Register flash callbacks for non-blocking operations
Cy_Flash_RegisterCallback(&config);
mtb_hal_nvm_setup(&nvm_obj, NULL);
// Get NVM characteristics like number of NVM regions, type, and their organization
mtb_hal_nvm_get_info(&nvm_obj, &nvm_info);
// NVM region 0 last block
block_num = (nvm_info.regions[0].size/nvm_info.regions[0].block_size) - 1;
// NVM region 0 last block address
nvm_addr = nvm_info.regions[0].start_address + (block_num * nvm_info.regions[0].block_size);
flash_operation_complete = false;
// Non-blocking NVM write
result = mtb_hal_nvm_write_nb(&nvm_obj, nvm_addr, (const uint32_t*)ram_data);
if (result == CY_RSLT_SUCCESS)
{
// Wait for the operation to complete
while (!flash_operation_complete)
{
}
flash_operation_complete = false;
// Read NVM data
result =
mtb_hal_nvm_read(&nvm_obj, (uint32_t)nvm_addr, nvm_read_data,
sizeof(nvm_read_data));
if (result == CY_RSLT_SUCCESS)
{
// Verify the data written into NVM by comparing it with the RAM data
if (0 == memcmp(ram_data, nvm_read_data, sizeof(nvm_read_data)))
{
compare_status = true;
}
}
}
#endif /* defined(CY_IP_MXS40FLASHC) */
}
else
{
// Error erasing NVM
}
cy_rslt_t mtb_hal_nvm_program_nb(mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
Program one block with the provided data starting at the given address (non-blocking).
Definition: mtb_hal_nvm.c:233
cy_rslt_t mtb_hal_nvm_erase_nb(mtb_hal_nvm_t *obj, uint32_t address)
Erase one block of NVM starting at the given address (non-blocking).
Definition: mtb_hal_nvm.c:215
cy_rslt_t mtb_hal_nvm_write_nb(mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
Write new data into the block starting at the given address (non-blocking).
Definition: mtb_hal_nvm.c:224
bool mtb_hal_nvm_is_operation_complete(mtb_hal_nvm_t *obj)
Check if a non-blocking NVM operation is complete.
Definition: mtb_hal_nvm.c:242
Collaboration diagram for NVM (Onboard Non-Volatile Memory):

API Reference

 NVM HAL Results
 NVM specific return codes.
 

Macros

#define MTB_HAL_API_AVAILABLE_NVM_IS_SECTOR_CORRUPT
 Indicates that mtb_hal_nvm_is_sector_corrupt is available in this version of HAL.
 

Enumerations

enum  mtb_hal_nvm_type_t {
  MTB_HAL_NVM_TYPE_INVALID = 0U ,
  MTB_HAL_NVM_TYPE_FLASH = 1U ,
  MTB_HAL_NVM_TYPE_RRAM = 2U ,
  MTB_HAL_NVM_TYPE_OTP = 3U
}
 Enum of Non-volatile memory (NVM) types. More...
 

Functions

cy_rslt_t mtb_hal_nvm_read (mtb_hal_nvm_t *obj, uint32_t address, uint8_t *data, size_t size)
 Read size amount of data starting from the given address of NVM. More...
 
cy_rslt_t mtb_hal_nvm_erase (mtb_hal_nvm_t *obj, uint32_t address)
 Erase one block of NVM starting at the given address. More...
 
cy_rslt_t mtb_hal_nvm_write (mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
 This function erases the block, if required, and writes the new data into the block starting at the given address. More...
 
cy_rslt_t mtb_hal_nvm_program (mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
 Program one block with the provided data starting at the given address. More...
 
cy_rslt_t mtb_hal_nvm_erase_nb (mtb_hal_nvm_t *obj, uint32_t address)
 Erase one block of NVM starting at the given address (non-blocking). More...
 
cy_rslt_t mtb_hal_nvm_write_nb (mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
 Write new data into the block starting at the given address (non-blocking). More...
 
cy_rslt_t mtb_hal_nvm_program_nb (mtb_hal_nvm_t *obj, uint32_t address, const uint32_t *data)
 Program one block with the provided data starting at the given address (non-blocking). More...
 
bool mtb_hal_nvm_is_operation_complete (mtb_hal_nvm_t *obj)
 Check if a non-blocking NVM operation is complete. More...
 
const mtb_hal_nvm_region_info_tmtb_hal_nvm_get_region_for_address (mtb_hal_nvm_t *obj, uint32_t addr, uint32_t length)
 Find the nvm region based on given address and length. More...
 
bool mtb_hal_nvm_is_blank (mtb_hal_nvm_t *obj, uint32_t addr, uint32_t size)
 Checks whether the NVM region [addr, addr + size] is fully in the erased state. More...
 
bool mtb_hal_nvm_is_sector_corrupt (mtb_hal_nvm_t *obj, uint32_t addr, uint32_t size)
 Checks whether the NVM region [addr, addr + size] contains detectable corruption. More...
 

Enumeration Type Documentation

◆ mtb_hal_nvm_type_t

Enum of Non-volatile memory (NVM) types.

Enumerator
MTB_HAL_NVM_TYPE_INVALID 

Invalid type of NVM.

MTB_HAL_NVM_TYPE_FLASH 

Internal Flash.

MTB_HAL_NVM_TYPE_RRAM 

RRAM.

MTB_HAL_NVM_TYPE_OTP 

OTP.

Function Documentation

◆ mtb_hal_nvm_read()

cy_rslt_t mtb_hal_nvm_read ( mtb_hal_nvm_t obj,
uint32_t  address,
uint8_t *  data,
size_t  size 
)

Read size amount of data starting from the given address of NVM.

Parameters
[in]objThe NVM object.
[in]addressAddress to begin reading from.
[out]dataThe buffer to read data into.
[in]sizeThe number of bytes to read.
Returns
The status of the read request. Returns CY_RSLT_SUCCESS on successful operation.

Refer Snippet 2: Blocking NVM Erase-Write and Read for more information.

◆ mtb_hal_nvm_erase()

cy_rslt_t mtb_hal_nvm_erase ( mtb_hal_nvm_t obj,
uint32_t  address 
)

Erase one block of NVM starting at the given address.

The address must be at block boundary. This will block until the erase operation is complete.

See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values, is erase required/applicable, and the erase block size(if applicable).
Parameters
[in]objThe NVM object
[in]addressThe block address to be erased
Returns
The status of the erase request. Returns CY_RSLT_SUCCESS on successful operation.

Refer Snippet 2: Blocking NVM Erase-Write and Read for more information.

◆ mtb_hal_nvm_write()

cy_rslt_t mtb_hal_nvm_write ( mtb_hal_nvm_t obj,
uint32_t  address,
const uint32_t *  data 
)

This function erases the block, if required, and writes the new data into the block starting at the given address.

The address must be at block boundary. This will block until the write operation is complete.

See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values and the write block size. The provided data buffer must be at least as large as the NVM block_size.
Note
Generally the data to be written must be located in the SRAM memory region.
Parameters
[in]objThe NVM object
[in]addressThe address of the block to be written
[in]dataThe data buffer to be written to the NVM block
Returns
The status of the write request. Returns CY_RSLT_SUCCESS on successful operation.

Refer Snippet 2: Blocking NVM Erase-Write and Read for more information.

◆ mtb_hal_nvm_program()

cy_rslt_t mtb_hal_nvm_program ( mtb_hal_nvm_t obj,
uint32_t  address,
const uint32_t *  data 
)

Program one block with the provided data starting at the given address.

The address must be at block boundary. This will block until the write operation is complete.

Note
This function does not erase the block prior to writing. The block must be erased first via a separate call to erase.
See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values and the total block size. The provided data buffer must be at least as large as the NVM block_size.
Note
Generally the data to be programmed must be located in the SRAM memory region.
Parameters
[in]objThe NVM object
[in]addressThe address of the block to be programmed
[in]dataThe data buffer to be programmed to the NVM block
Returns
The status of the program request. Returns CY_RSLT_SUCCESS on successful operation.

◆ mtb_hal_nvm_erase_nb()

cy_rslt_t mtb_hal_nvm_erase_nb ( mtb_hal_nvm_t obj,
uint32_t  address 
)

Erase one block of NVM starting at the given address (non-blocking).

The address must be at block boundary. This function starts the erase operation and returns immediately. Use mtb_hal_nvm_is_operation_complete() to check completion.

See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values, is erase required/applicable, and the erase block size(if applicable).
Parameters
[in]objThe NVM object
[in]addressThe block address to be erased
Returns
The status of the erase request. Returns CY_RSLT_SUCCESS on successful operation start.

◆ mtb_hal_nvm_write_nb()

cy_rslt_t mtb_hal_nvm_write_nb ( mtb_hal_nvm_t obj,
uint32_t  address,
const uint32_t *  data 
)

Write new data into the block starting at the given address (non-blocking).

The address must be at block boundary. This function starts the write operation and returns immediately. Use mtb_hal_nvm_is_operation_complete() to check completion.

See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values and the write block size. The provided data buffer must be at least as large as the NVM block_size.
Note
Generally the data to be written must be located in the SRAM memory region.
Parameters
[in]objThe NVM object
[in]addressThe address of the block to be written
[in]dataThe data buffer to be written to the NVM block
Returns
The status of the write request. Returns CY_RSLT_SUCCESS on successful operation start.

◆ mtb_hal_nvm_program_nb()

cy_rslt_t mtb_hal_nvm_program_nb ( mtb_hal_nvm_t obj,
uint32_t  address,
const uint32_t *  data 
)

Program one block with the provided data starting at the given address (non-blocking).

The address must be at block boundary. This function starts the program operation and returns immediately. Use mtb_hal_nvm_is_operation_complete() to check completion.

Note
This function does not erase the block prior to writing. The block must be erased first via a separate call to erase.
See also
mtb_hal_nvm_get_info() to get the NVM characteristics for legal address values and the total block size. The provided data buffer must be at least as large as the NVM block_size.
Note
Generally the data to be programmed must be located in the SRAM memory region.
Parameters
[in]objThe NVM object
[in]addressThe address of the block to be programmed
[in]dataThe data buffer to be programmed to the NVM block
Returns
The status of the program request. Returns CY_RSLT_SUCCESS on successful operation start.

◆ mtb_hal_nvm_is_operation_complete()

bool mtb_hal_nvm_is_operation_complete ( mtb_hal_nvm_t obj)

Check if a non-blocking NVM operation is complete.

Parameters
[in]objThe NVM object
Returns
True if operation is complete and false if still in progress.

◆ mtb_hal_nvm_get_region_for_address()

const mtb_hal_nvm_region_info_t* mtb_hal_nvm_get_region_for_address ( mtb_hal_nvm_t obj,
uint32_t  addr,
uint32_t  length 
)

Find the nvm region based on given address and length.

If "length is zero and address is not in any nvm region" or if "length is not zero and address is not in any nvm region" or if "length is not zero and address is one nvm region but address + length goes into another nvm region", the function will return Null.

Parameters
[in]objThe NVM object
[in]addrThe start address of the block
[in]lengthThe legnth to block
Returns
pointer, mtb_hal_nvm_region_info_t, to nvm region

◆ mtb_hal_nvm_is_blank()

bool mtb_hal_nvm_is_blank ( mtb_hal_nvm_t obj,
uint32_t  addr,
uint32_t  size 
)

Checks whether the NVM region [addr, addr + size] is fully in the erased state.

The erased state is only defined for regions that require an erase before programming. For a region whose mtb_hal_nvm_region_info_t::is_erase_required is false, this function always returns false. The value that represents "erased" for a region is reported by mtb_hal_nvm_region_info_t::erase_value. Query the region via mtb_hal_nvm_get_info() / mtb_hal_nvm_get_region_for_address() to distinguish "not erased" from "no erased state".

Note
This function only reports whether the region currently reads as the erase value; it does not detect corruption. A region left in an inconsistent state by an interrupted erase may read as blank while still containing a non-correctable ECC error. Use mtb_hal_nvm_is_sector_corrupt to check for and handle such corruption.
Parameters
[in]objThe NVM object.
[in]addrStart address of the region to check. Must be word aligned.
[in]sizeSize of the region to check, in bytes. Must be a multiple of the word size.
Returns
true if the whole region is erased; false otherwise (including regions that do not require erase, and addresses not within an erasable region).

◆ mtb_hal_nvm_is_sector_corrupt()

bool mtb_hal_nvm_is_sector_corrupt ( mtb_hal_nvm_t obj,
uint32_t  addr,
uint32_t  size 
)

Checks whether the NVM region [addr, addr + size] contains detectable corruption.

All device-specific handling required to probe the region safely is performed internally; the function never accesses the memory in a way that would escalate a detected error into a fault.

Note
On some devices this function transiently modifies global fault-handling state that is shared with the rest of the system. To use it safely the caller must guarantee, for the duration of the call, that:
  • no other NVM operation runs concurrently, and
  • no concurrently executing code requires immediate capture of a hardware fault (such a fault is never lost, but its capture may be deferred for the bounded duration of the probe).

Disabling interrupts around the call is the simplest way to satisfy both constraints and is the recommended approach. It is not strictly required: any other means of enforcing the two constraints above is equally valid. The function does not disable interrupts itself.

Parameters
[in]objThe NVM object.
[in]addrStart address of the region to check. Must be word aligned.
[in]sizeSize of the region to check, in bytes. Must be a multiple of the word size.
Returns
true if corruption is detected in the region; false otherwise (including regions for which corruption detection is not supported, and addresses that are not within any NVM region).