HALFRED  0.4.0
NV memory module

Introduction.

The NV module provides API to access a non volatile memory in a uniform manner. This allows to store and retrieve data without knowledge about internals of a physical storage. From the developer perspective there are present some memory device (or devices) with simple write/read access to it. In the multitasking environment (e.g. RTOS) it is also possible to perform the asynchronous write operations (with notification about result). All the read/write operations are always serialized. It means that they will be handled in order of arrival and no operation can be interrupted by another one.

Memory device.

The memory device is represented by the NV_MemDevice type. It is a handle to the structure holding information required to access (physical) devices which require serialized access e.g. attached to the same communication bus, in general - sharing the same (physical) resource). The (de)initialization and processing NV API is using handle (the NV_MemDevice type) to memory devices.

NV Memory.

The NV memory is represented by the NV_Memory type. It is a handle to the structure holding information required to access particular physical device (e.g. chip). The NV API for writing and reading is using handle (the NV_Memory type) to NV memory.

NV setup.

To setup the NV module the application shall initialize appropriate data (NV memories and memory devices) and then call the NV_MemDeviceDeInit function. In case when there is enabled asynchronous write operation then there should be also created a semaphore pool. The user should take into account that initialization procedure uses a real dynamic allocation functions and thus it should be avoided when real time tasks are already started. The recommended way of NV initialization is to do it before RTOS scheduler is executed. Below there is an example how to setup NV module for accessing a AT45DB chip attached to the SPI1 IO.

static uint8_t at45db_buf[NV_AT45DB_SMALL_PAGE_SIZE];
NV_AT45DB_MEM_DECLARE(nvmem_at45db, IO_SPI1);
static NV_Memory devs[1] = { &nvmem_at45db };
static NV_MemDevice_T nvdev_at45db = NV_INIT_MEMDEVICE(devs, 1);
nv_buf_pool = BP_Create(9, NV_AT45DB_SMALL_PAGE_SIZE);
NV_MemDeviceInit(&nvdev_at45db, 4, 3, at45db_buf, nv_buf_pool);

Using the NV module

uint8_t rw_buf[2*NV_AT45DB_SMALL_PAGE_SIZE];
volatile NV_OpResult async_result;
NV_OpResult result;
result = NV_WriteSync(&nvmem_at45db, address, sizeof(rw_buf), rw_buf);
result = NV_ReadSync(&nvmem_at45db, address, sizeof(rw_buf), rw_buf);
result = NV_WriteAsync(&nvmem_at45db, address, sizeof(rw_buf), rw_buf, &async_result);

If we want to use asynchronous write operation then there is required to setup separate OS task to perform operations in background. Keep in mind that priority used for NV worker task is strictly connected to priorities of tasks using NV module and amount of available resources (semaphores and buffers). It is because physical non volatile memory operations are very time consuming (comparing to typical microcontroller operations) and resources are blocked for relatively long periods.

OSTASK_Create(nv_worker_task, NV_WORKER_TASK_PRIORITY, 2 * configMINIMAL_STACK_SIZE, &nvdev_at45db);
static void nv_worker_task(void *pvParameters)
{
for ( ;; ) {
NV_ProcessRequests((NV_MemDevice) pvParameters);
}
}

Module configuration.

To enable the NV module, HAL_ENABLE_NV definition must be set to 1, in hal_config.h.

To enable asynchronous operations the HAL_NV_USE_WORKER_TASK must be set to 1, in hal_config.h. In such case there also have to be enabled a buffer pool functionality (HAL_ENABLE_BP). Additionally to enable non polling operation for worker task with semaphore usage the HAL_NV_USE_SEM_TO_PROCESS_IDLE must be set to 1, in hal_config.h (otherwise the function NV_ProcessRequests should be called periodically).