Probably the best way to demonstrate LIBMEM is to see it in use. The following example demonstrates copying a block of data into FLASH using a LIBMEM common flash interface (CFI) driver.

int libmem_example_1(void)
{ 
  const int flash1_max_geometry_regions = 4;
  libmem_driver_handle_t  flash1_handle;
  libmem_geometry_t flash1_geometry[flash1_max_geometry_regions];
  libmem_flash_info_t flash1_info;
  uint8_t *flash1_start = (uint8_t *)0x10000000;
  uint8_t *write_dest = flash1_start + 16; 
  const uint8_t write_data[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  int res;

  // Register the FLASH LIBMEM driver
  res = libmem_register_cfi_driver(&flash1_handle,
                                   flash1_start,
                                   flash1_geometry,
                                   flash1_max_geometry_regions,
                                   &flash1_info);
  if (res != LIBMEM_STATUS_SUCCESS)
    return 0;

  // Unlock the destination memory area.
  res = libmem_unlock(write_dest, sizeof(write_data));
  if (res != LIBMEM_STATUS_SUCCESS)
    return 0;

  // Erase the destination memory area.
  res = libmem_erase(write_dest, sizeof(write_data), 0, 0);
  if (res != LIBMEM_STATUS_SUCCESS)
    return 0;

  // Copy write_data to the destination memory area.
  res = libmem_write(write_dest, write_data, sizeof(write_data));
  if (res != LIBMEM_STATUS_SUCCESS)
    return 0;

  // Complete any outstanding transactions and put FLASH memory back into read mode.
  res = libmem_flush();
  if (res != LIBMEM_STATUS_SUCCESS)
    return 0;

  return 1;
}

The following section describes each of the LIBMEM calls in the preceding example in detail.

Before any memory operations can be carried out the LIBMEM drivers that you are going to use must be registered. The following code registers a LIBMEM CFI driver for a FLASH device located at the memory location pointed to by flash1_start.

// Register the FLASH LIBMEM driver
res = libmem_register_cfi_driver(&flash1_handle,
                                 flash1_start,
                                 flash1_geometry,
                                 flash1_max_geometry_regions,
                                 &flash1_info);
if (res != LIBMEM_STATUS_SUCCESS)
  return 0;

This call attempts to detect the type of FLASH and register the correct LIBMEM CFI driver based on the CFI information read out from the FLASH device. Note that using this function will link in all LIBMEM CFI drivers so in your own application you may wish to save memory by using libmem_cfi_get_info to get out the FLASH geometry information and registering a specific CFI driver. You may also save further memory and time by not calling libmem_cfi_get_info and specifying the FLASH geometry yourself.

For each driver you register you must allocate libmem_driver_handle_t structure to act as a handle for the driver. Will the full version of LIBMEM you can register as many drivers as you wish, if you are using the ‘light’ version of LIBMEM you can only register one driver.

Once you have registered your drivers you can use the general LIBMEM memory functions to access and control your memory. The starting address passed to these functions is used to decide which driver to use for the memory operation, operations cannot span multiple drivers.

The next operation the example code carries out it to unlock the FLASH in preparation for the erase and write operations. Unlocking is not necessary on all memory devices and this operation is not implemented in all LIBMEM drivers.

// Unlock the destination memory area.
res = libmem_unlock(write_dest, sizeof(write_data));
if (res != LIBMEM_STATUS_SUCCESS)
  return 0;

Once the memory has been unlocked the FLASH memory is erased. Once again erasing is not necessary on all memory devices and this operation may not be implemented in all LIBMEM drivers.

// Erase the destination memory area.
res = libmem_erase(write_dest, sizeof(write_data), 0, 0);
if (res != LIBMEM_STATUS_SUCCESS)
  return 0;

Parameters three and four of libmem_erase are not used in this example, however they provide a mechanism to allow the caller to determine how much memory was actually erased by the erase operation as it may well be more than requested.

Once the FLASH memory has been erased the FLASH can be programmed using the libmem_write function.

// Copy write_data to the destination memory area.
res = libmem_write(write_dest, write_data, sizeof(write_data));
if (res != LIBMEM_STATUS_SUCCESS)
  return 0;

The final step is to call libmem_flush. Once again flushing is not necessary on all memory devices, but some LIBMEM drivers do not necessarily carry out operations immediately or they may leave the memory in an unreadable state for performance reasons and calling libmem_flush is required to flush outstanding operations and return the device to read mode.

// Complete any outstanding transactions and put FLASH memory back into read mode.
res = libmem_flush();
if (res != LIBMEM_STATUS_SUCCESS)
  return 0;

Typically you would now access the FLASH memory as you would any other memory and read it directly, LIBMEM does however provide the libmem_read function for accessing memory that is not directly accessibly by the CPU.