.. _flash:

Flash
=====

The flash is split into erasable pages of |FLASH_PAGE_SIZE|. The various
sections of flash and their associate linker files are as follows.

-  **Flash Reset Vector Table**: This table holds the reset value of the 
   stack pointer, and the start addresses, also called exception vectors, 
   for all exception handlers. See :ref:`sec-flash-vector-table`
   for more information.

-  **Simple NV (SNV) Area**: used for non-volatile memory storage by the GAP
   Bond Manager and also available for use by the application. See
   :ref:`using-simple-nv` for configuring SNV.

-  **Application's Non Volatile Storage (NVS) Area**: used for non-volatile
   memory storage by the application. See :ref:`using-application-nvs`. TI
   recommends to use the Bond Manager's Simple NV (SNV) Area when the
   amount of application data to store is small (below 100 bytes) and
   not overwritten often. Otherwise, TI recommends using application's
   own Non Volatile Storage (NVS) area.

For projects where the stack project builds a **library**:

-  **Application and Stack Image Code Space**: A single region that contains
   both application and stack code in flash.
   This image is configured in the linker configuration file of the application:
   <device name>\_app\_and\_stack.icf (IAR) and <device name>\_app.cmd (CCS).

.. _using-simple-nv:

Non-Volatile Storage Architecture
---------------------------------

This section will describe the non-volatile storage system that is implemented
and used on the |DEVICE|. This system provides access to non-volatile storage
that can be safely shared between the user application and the protocol stack.

The system has the following properties and offers the following features:

 - Thread safe access to non-volatile memory
 - ID based system that decouples a storage item from its address in memory
 - Space efficient storage with automatic compaction
 - Power loss tolerant data preservation

The implementation of this software system relies on several layers which are
illustrated below.

.. ditaa::
    :--no-separation:

    +-----------------------+
    |       NVINTF    cAAA  |
    |                       |
    +-----------------------+
    |       NVOCMP    cEEE  |
    |                       |
    +-----------------------+
    |       NVS Driver c000 |
    |                       |
    +-----------------------+
    |       Driverlib  cC00 |
    |       Flash APIs      |
    +-----------------------+

Non-Volatile Interface (NVINTF)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The NVINTF is an abstraction layer that defines a common set of APIs for
interacting with non-volatile memory using a ID system. This common set of APIs
allow for new methods of NV storage to be implemented without changing the
API calls in the stack and application. The ID system is most efficient because
it decouples the data stored from its address in flash. This is necessary
because flash banks must have the entire sector erased before writing again
(with the exception of clearing a bit). Using the ID system, when an NV item
needs to be updated, it can simply be invalidated and stored again at a
different address. Once the NV system becomes full of unused items, a compaction
will occur. A compaction is the removal of unused items.

The NVINTF is function pointer based, each underlying transport must plug
a function table and provide an implementation for the common set of APIs.

This interface is defined in ``nvintf.h``. The NVINTF is not intended to be
changed by the customer, but instead used as is.

Non-Volatile On-Chip Multi Page (NVOCMP) Driver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The NVOCMP driver implements a non-volatile memory system that utilizes
multiple consecutive pages of on-chip Flash memory. After initialization, all
pages except one are "active" and the remaining one page is available for
"compaction" when the active pages do not have enough empty space for data
write operation. Compaction can occur "just in time" during a data write
operation or "on demand" by application request. The compaction process
is designed to survive a power cycle before it completes. It will resume
where it was interrupted and complete the process. The number of NV pages
can be set by the `NVOCMP_NVPAGES` preprocessor define. If this is not set,
it will default to 2.

Flash Page Header
"""""""""""""""""

Each flash page contains a "page header" which indicates its current state. The
page header is located at the first byte of the flash page. Following the
page header is the "compact header", which indicates the flash page's
compaction state. The remainder of the flash page contains NV data items which
are packed together following the page header and compact header.

.. _flash_page_header_description:
.. figure:: resources/flash_page_header_description.png
    :align: center

    Flash page header description

The page state value mentioned in :numref:`flash_page_header_description`
is described in :numref:`flash_page_state_description`.

.. _flash_page_state_description:
.. table:: Flash page state description

  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | **Page State** | **Size (bits)**                                                                                | **Value**   |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGNACT         |The page is not active. The first state after erase. Only the page header exists in this state  | 0xFF        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGXDST         |The page is transfer page ready to be moved to during compaction                                | 0xFE        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGRDY          |The page is active page ready to write, but still only page header exists                       | 0x7E        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGACT          |The page is active page where some write is done                                                | 0x7C        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGFULL         |The page is active page where is no more room to write, but update is still possible            | 0x78        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+
  | PGXSRC         |The page is active page where item will be moved from during compaction process                 | 0x70        |
  +----------------+------------------------------------------------------------------------------------------------+-------------+


Data Item
"""""""""

Each NV data item is unique and has two parts:

  1. A data block which is stored first (lower memory address)
  2. An item header following the data block (higher memory address)

The item header (defined by ``NVOCMP_itemHdr_t``) contains status information
required to traverse packed data items in the flash page. An example of the NV
item memory layout storing a single byte of data is illustrated below.

.. _fig-nvintf-header:
.. figure:: resources/nvintf_header.png
    :align: center

**NV Item Header:**

+-------------+-----------------+----------------------------------------------------+
| **Field**   | **Size (bits)** | **Purpose**                                        |
+-------------+-----------------+----------------------------------------------------+
| System ID   | 6               | Indicates the system component identifier          |
+-------------+-----------------+----------------------------------------------------+
| Item ID     | 10              | Indicates the item data identifier                 |
+-------------+-----------------+----------------------------------------------------+
| Sub ID      | 10              | Identifier of the sub-data related to the NV item  |
+-------------+-----------------+----------------------------------------------------+
| Length      | 12              | Length of the data block                           |
+-------------+-----------------+----------------------------------------------------+
| CRC         | 8               | CRC value of NV item                               |
+-------------+-----------------+----------------------------------------------------+
| Status Bits | 2               | Indicates CRC integrity and if item is active      |
+-------------+-----------------+----------------------------------------------------+
| Signature   | 8               | Used to detect presence of a NV item in flash      |
+-------------+-----------------+----------------------------------------------------+

For each NV item that is added or updated in NV storage, the item is written to
the next lowest available memory address in the active flash page. If the NV
item is being updated, the old NV item will be marked as inactive. Inactive
items are removed from memory when a memory compaction takes place.


.. tip::

  Use the NVOCMP Driver to erase the whole NV section.

  .. code-block:: C
    
    #include <ti/common/nv/nvocmp.h>

    NVINTF_nvFuncts_t ncsFuns;            
    NVOCMP_loadApiPtrs(&ncsFuns);            
    ncsFuns.eraseNV(); 
  
  After the call to `eraseNV()` the NVS is erased and is ready to be programmed again.

For more information, see the API documentation in `nvocmp.h` and the design
description in `nvocmp.c`.


Non-Volatile Storage (NVS) Driver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The NVS driver provides reentrant functions for writing to and reading from
flash. It also provides a common interface to both internal and external flash.
More information can be found in the TI Drivers documentation. The stack will
use internal NV, currently this is all that is supported.


Non-Volatile Storage with the BLE-Stack
---------------------------------------

The |STACK| implements some additional layers on top of the NVINTF.
These additional layers define the recommended interaction between BLE enabled
applications, the |STACK|, and the NVINTF implementation.

The additional layers required when using the |STACK| are listed below:

 - ICall: NV interactions occur in stack thread facilitated by ICall
 - OSAL SNV: A wrapper on top of the NVINTF that defines a NV tag structure for
   BLE

The figure below shows the architecture of the entire system.

.. ditaa::
    :--no-separation:

    +-----------------------+
    |       Application     |
    |        cAAA           |
    +-----------------------+
        ^               ^
        |               |
        V               V
    +-----------------------+
    |       ICall    c3B5   |
    +-----------------------+
        ^               ^
        |               |
        V               V
    +-----------------------+     +-----------------------+
    |       OSAL SNV c000   |<--->|       BLE Stack  c0BC |
    |                       |     |       GAP Bond MGR    |
    +-----------------------+     +-----------------------+
    |       NVINTF     cC00 |
    +-----------------------+

OSAL Simple NV (OSAL SNV)
^^^^^^^^^^^^^^^^^^^^^^^^^

The GAP Bond Manager will use OSAL SNV for storing persistent data, such as
encryption keys from bonding. The OSAL SNV layer is implemented via a simple
wrapper that defines a higher level structure on top of the existing
``NVINTF_itemID_t`` structure. At a high level this simply maps the
``osalSnvId_t`` that is used by the stack to ``NVINTF_itemID_t`` that is used
by the NVINTF layer. It will always use ``NVINTF_SYSID_BLE`` when storing
OSAL SNV data. The ID system implemented is detailed below. By default, the IDs
available to the customer are defined in bcomdef.h as shown in
:numref:`lst-inc_flash_snv`

.. _lst-inc_flash_snv:
.. code-block:: c
    :linenos:
    :caption: Usable SNV IDs available to customers
    :emphasize-lines: 16-18

    // Device NV Items -    Range 0 - 0x1F
    #define BLE_NVID_IRK                    0x02   //!< The Device's IRK
    #define BLE_NVID_CSRK                   0x03   //!< The Device's CSRK
    #define BLE_NVID_ADDR_MODE              0x04   //!< The Device's address type (@ref GAP_Addr_Modes_t)
    #define BLE_LRU_BOND_LIST               0x05   //!< The Device's order of bond indexes in least recently used order
    #define BLE_NVID_RANDOM_ADDR            0x06   //!< The Device's random address if set by the current @ref GAP_DeviceInit
    
    // Bonding NV Items -   Range  0x20 - 0xDF    - This allows for 32 bonds
    #define BLE_NVID_GAP_BOND_START         0x20   //!< Start of the GAP Bond Manager's NV IDs
    #define BLE_NVID_GAP_BOND_END           0xDF   //!< End of the GAP Bond Manager's NV IDs Range
    
    // GATT Configuration NV Items - Range  0xE0 - 0xFF - This must match the number of Bonding entries
    #define BLE_NVID_GATT_CFG_START         0xE0   //!< Start of the GATT Configuration NV IDs
    #define BLE_NVID_GATT_CFG_END           0xFF   //!< End of the GATT Configuration NV IDs
    
    // Customer NV Items - Range  0x100 - 0x11F
    #define BLE_NVID_CUST_START             0x100  //!< Start of the Customer's NV IDs
    #define BLE_NVID_CUST_END               0x11F  //!< End of the Customer's NV IDs

    // BLE Mesh NV IDs Start
    #define BLE_NVID_MESH_START            BLE_NVID_CUST_END + 1

The range of NV items reserved for the customer's application can be increase
as much as needed as long as all the IDs remain unique and below 0x03FF.

Additionally it will set a compact level via the GAP Bond Manager which
defaults to 80%. This is set by the ``NV_COMPACT_THRESHOLD`` define.

This layer is implemented by ``osal_snv_wrapper.c``.

Limitations and Intended Use
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The following limitations apply to those using NV alongside the |STACK|.

 - NV implementations (i.e. NVOCMP) should not be used directly; the
   application should access NV through OSAL SNV. See :ref:`lst-snv_api_usage`
 - The application must be careful to only use IDs in the range defined by
   :numref:`lst-inc_flash_snv`
 - The application cannot access the NV regions reserved by the stack directly
   or the internal structure may be corrupted.
 - When using NVOCMP, the memory allocated for internal NVS access must be
   pages of contiguous memory.
 - Since OSAL SNV exists on the stack side of ICall, an application that uses
   OSAL SNV must be ICall enabled.
 - OSAL SNV operations must be called from a task context and not a :term:`Hwi`
   or :term:`SWI` context.
 - Some care must be taken to not be close to 80% (or other compaction
   threshold) utilization of a sector. BLE stack uses 49 bytes to store local
   info (IDs 0x02 to 0x06). In addition, 109 bytes per bond stored are required.
 - Frequent compactions are costly in terms of power consumption
   and can cause resets and lost SNV content (NVOCMP) and will also wear out the
   flash.


OSAL SNV API Set
^^^^^^^^^^^^^^^^

SNV can be read from or written to using the following APIs.

**uint8 osal\_snv\_read( osalSnvId\_t id, osalSnvLen\_t len, void
\*pBuf)**

+------------------+------------------------------------------------+
|                  |   **Read data from NV**                        |
+------------------+------------------------------------------------+
| **Parameters**   |    id - valid NV item                          |
|                  |                                                |
|                  |    len - length of data to read                |
|                  |                                                |
|                  |    pBuf - pointer to buffer to store data read |
+------------------+------------------------------------------------+
| **Returns**      |    Status as defined in ``nvintf.h``           |
+------------------+------------------------------------------------+

**uint8 osal\_snv\_write( osalSnvId\_t id, osalSnvLen\_t len, void
\*pBuf)**

+------------------+---------------------------------------------------------------------------------------------+
|                  |   **Write data to NV**                                                                      |
+------------------+---------------------------------------------------------------------------------------------+
| **Parameters**   |    id - valid NV item                                                                       |
|                  |                                                                                             |
|                  |    len - length of data to write                                                            |
|                  |                                                                                             |
|                  |    pBuf - pointer to buffer containing data to be written. All contents are updated at once.|
+------------------+---------------------------------------------------------------------------------------------+
| **Returns**      |    Status as defined in ``nvintf.h``                                                        |
+------------------+---------------------------------------------------------------------------------------------+


OSAL SNV Example
^^^^^^^^^^^^^^^^

:numref:`lst-snv_api_usage` shows how to read and write an array of bytes from
SNV flash:

.. _lst-snv_api_usage:
.. code-block:: c
    :caption: Using SNV Example Code
    :emphasize-lines: 5, 13, 21, 26

    /*********************************************************************
    * GLOBAL VARIABLES
    */

    #include <icall_ble_api.h> // OSAL SNV operations are defined through ICALL

    // ...

    #define BUF_LEN 4
    #define SNV_ID_APP 0x100   
    uint8 buf[BUF_LEN] ={0,};

    void App_StackInitDoneHandler(gapDeviceInitDoneEvent_t *deviceInitDoneData)
    {
        bStatus_t status = SUCCESS;

        // Open Display.
        openDisplay();

        // Print the device address
        Display_printf(dispHandle, dispIndex, 0,
                      "#%5d    BLE Device Address %s",
                      dispIndex,
                      BLEAppUtil_convertBdAddr2Str(deviceInitDoneData->devAddr)); dispIndex++;

        status = osal_snv_read(SNV_ID_APP, BUF_LEN, (uint8 *)buf);
        if(status != SUCCESS)
        {
            Display_printf(dispHandle, dispIndex, 0, "#%5d    SNV READ FAIL: %d", dispIndex, status); dispIndex++;
          //Write first time to initialize SNV ID
          osal_snv_write(SNV_ID_APP, BUF_LEN, (uint8 *)buf);
        }

        //Increment first element of array and write to SNV flash
        buf[0]++;
        status = osal_snv_write(SNV_ID_APP, BUF_LEN, (uint8 *)buf);
        if(status != SUCCESS)
        {
            Display_printf(dispHandle, dispIndex, 0, "#%5d    SNV WRITE FAIL: %d", dispIndex, status); dispIndex++;
        }
        else
        {
            Display_printf(dispHandle, dispIndex, 0, "#%5d    Num of Resets: %d", dispIndex, buf[0]); dispIndex++;
        }
        //..
    }

No prior initialization of a NV item ID is required; the OSAL SNV manager
initializes the NV ID when first accessed by a successful osal\_snv\_write()
call.

When reading or writing large amounts of data to SNV, TI recommends placing the
read/write data in statically (linker) allocated arrays or buffers allocated
from the heap. Placing large amounts of data in local arrays may result in a
task stack overflow.

Placing OSAL SNV
^^^^^^^^^^^^^^^^

This section details how the SNV flash sector is placed in memory.

The memory placement for the OSAL_SNV is set by Sysconfig in the section *TI Drivers* |rarr| *NVS* as shown in the picture below.

.. image:: ./resources/nvs_sysconfig_cc23xx.png

Placement of this structure is flexible and configurable by the user so long as the intended use `guidelines <./flash_memory-cc23xx.html#limitations-and-intended-use>`__ are followed.

This structure is accessed via the NVINTF through ``NVSCC23XX_*`` APIs.


.. _using-application-nvs:

Application's Non Volatile Storage (NVS)
----------------------------------------

Non Volatile Storage (NVS) regions should be defined in SysConfig.

Depending on the project configuration (for example, if OAD is enabled),
various NVS regions may already be defined. The application should
use its own NVS instance so it does not conflict with others.

The drivers examples `nvsinternal` and `nvsexternal` respectively
showcase how to use the device's internal flash and an external
flash. 
