Memory Map

The CC26x2 contains several memory regions including RAM, ROM, and Flash. This section aims to show how these memory regions are utilized by the stack and user application.

The stack library configuration memory map can be seen below. See Stack Library Configuration for more information on the configuration.

Memory Section Starting Address Size (bytes) Description
Flash 0x00000000 64 Cortex Interrupt Vecs
Application / Stack Code
SNV=0,1,2 0, 8K, 16K Simple Non-Volatile Storage
End of Flash - 88 Customer Configuration
ROM 0x10000000 0x40000 TI-RTOS, BLE5-Stack, Crypto, Driverlib, Boot
RAM 0x20000000 200 Interrupt Vector Table in RAM for dynamic Hwi creation
0x20000100 24 Reserved for pointers for TI-RTOS in ROM
.bss and .data
ICall heap
TI-RTOS kernel system stack (CSTACK)

Flash

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

  • Flash Reset Vector Table: This table holds the first 16 reset vectors that are critical for booting up the device. These vectors are set at build time and cannot be dynamically changed. See Flash Vector Table below for more information.
  • Simple NV (SNV) Area: used for nonvolatile memory storage by the GAP Bond Manager and also available for use by the application. See Using Simple NV for Flash Storage for configuring SNV. When configured, the SNV flash storage area is part of the stack image.

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).

Flash Vector Table

This table contains the first 16 critical interrupt vectors required for the bootup process. The location of this table is controlled by m3Hwi.resetVectorAddress within the TI-RTOS config file (*.cfg), it defaults to address 0x00000000. At bootup time, the TI-RTOS kernel will run a first function to initialize the Hwi module. At this time the flash vector table will be copied to the RAM location shown in Table 9. and the VTOR register will be moved to point to the RAM table. For more information about the vector table format, please refer to Cortex-M3 Vector Table.

For more information on the kernel boot process and first functions, please see: SYS/BIOS Boot Wiki.

Using Simple NV for Flash Storage

The Simple NV (SNV) area of flash is used for storing persistent data, such as encryption keys from bonding or to store custom defined parameters. The protocol stack can be configured to reserve up to two 4kB flash pages for SNV, although valid data is only stored in one active flash page. To minimize the number of erase cycles on the flash, the SNV manager performs compaction on the flash sector (or sectors) when the sector has 80% invalidated data. A compaction is the copying of valid data to a temporary area followed by an erase of the sector where the data was previously stored. Depending on the OSAL_SNV value as described in OSAL_SNV Values, this valid data is then either placed back in the newly erased sector or remains in a new sector. The number of flash sectors allocated to SNV can be configured by setting the OSAL_SNV preprocessor symbol in the stack project. Table 10. lists the valid values that can be configured as well as the corresponding trade-offs.

Table 10. OSAL_SNV Values
OSAL_SNV Value Description
0 SNV is disabled. Storing of bonding keys in NV is not possible. Maximizes code space for the application and/or stack project. GAP Bond Manager must be disabled. In the Stack project, set pre- processor symbol NO_OSAL_SNV and disable GAP Bond Manager. See Stack Configurations for configuring Bluetooth low energy protocol stack features.
1 (default) One flash sector is allocated to SNV. Bonding information is stored in NV. Set preprocessor symbol OSAL_SNV=1 in the Stack project.
2 Two flash sectors are allocated to SNV. Bonding information is stored in NV. SNV data is protected against power-loss during compaction.

Other values for OSAL_SNV are invalid. Using less than the maximum value has the net effect of allocating more code space to the application or stack project. 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

SUCCESS: NV item read successfully

NV_OPER_FAILED: failure reading NV item

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

SUCCESS: NV item write successfully

NV_OPER_FAILED: failure writing NV item

Because SNV is shared with other modules in BLE5-Stack such as the GAP Bond Manager, carefully manage the NV item IDs. By default, the IDs available to the customer are defined in bcomdef.h as shown in Listing 94.

Listing 94. Usable SNV IDs available to customers
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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 - 0x5F    - This allows for 10 bondings
#define BLE_NVID_GAP_BOND_START         0x20  //!< Start of the GAP Bond Manager's NV IDs
#define BLE_NVID_GAP_BOND_END           0x5f  //!< End of the GAP Bond Manager's NV IDs Range

// GATT Configuration NV Items - Range  0x70 - 0x79 - This must match the number of Bonding entries
#define BLE_NVID_GATT_CFG_START         0x70  //!< Start of the GATT Configuration NV IDs
#define BLE_NVID_GATT_CFG_END           0x79  //!< End of the GATT Configuration NV IDs

// Customer NV Items - Range  0x80 - 0x8F - This must match the number of Bonding entries
#define BLE_NVID_CUST_START             0x80  //!< Start of the Customer's NV IDs
#define BLE_NVID_CUST_END               0x8F  //!< End of the Customer's NV IDs

Listing 95. shows how to read and write an array of bytes from SNV flash:

Listing 95. Using SNV Example Code
/*********************************************************************
* GLOBAL VARIABLES
*/
#define BUF_LEN 4
#define SNV_ID_APP 0x80
uint8 buf[BUF_LEN] ={0,};

static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
{
  // Initialize application
  SimpleBLEPeripheral_init();
  uint8 status = SUCCESS;

  status = osal_snv_read(SNV_ID_APP, BUF_LEN, (uint8 *)buf);
  if(status != SUCCESS)
  {
    Display_print1(dispHandle, 0, 0, "SNV READ FAIL: %d", status);
    //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_print1(dispHandle, 0, 0, "SNV WRITE FAIL: %d", status);
  }
  else
  {
    Display_print1(dispHandle, 0, 0, "Num of Resets: %d", buf[0]);
  }

  // Application main loop
  for (;;)
  {
  //...
  }
}

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.

By default, osalSnvId_t and osalSnvLen_t are type defined as uint8. To use uint16-type definitions, define the preprocessor symbol OSAL_SNV_UINT16_ID in both the application and stack projects.

Using osal_snv_read and osal_snv_write is only permitted from within a task context. Calling this API is not possible from within Swis or Hwis.

Customer Configuration (CCFG) Table

The CCFG is placed at the end of the last flash page and lets customer configure various chip and system parameters in the Customer Configuration (CCFG) table. The CCFG table is defined in ccfg_app_ble.c, which can be found in the Startup folder of the application project. The last (sizeof(ccfg_t)) bytes of the CCFG sector are reserved by the system for the CCFG table. By default, the linker allocates the unused flash of the last flash page to the application image for code and data use.

See the CC26x2 Technical Reference Manual for details on CCFG fields and related configuration options, including how to set the CCFG to disable access to internal flash memory contents.

Note

The CCFG cannot be relocated, and must reside at the end of the last page of flash. Consult the CC26x2 Technical Reference Manual for more information.

RAM

There is 80kB of RAM available in the system. The various sections of RAM and their associated linker files are as follows.

  • CSTACK: This the system callstack used by the C main function and HWIs. See System Stack for more information
  • RAM Reset Vector Table: This table holds entries for all 50 supported reset vectors. It is initialized from the flash reset vector table at boot time and is used to plug interrupt table entries at runtime. See RAM Vector Table for more information.
  • ROM Reserved RAM: When building a configuration that links to code in ROM certain sections of RAM must be reserved for the static allocations performed in ROM. This includes the RTOS in ROM Reserved RAM and the ROM Reserved RAM sections in Table 9.. If the active configuration doesn’t use ROM,these sections may be used for other purposes.
  • HEAP: All configurations require that a heap must be present for dynamic memory allocation. This heap is shared between the app and stack. There are multiple configurations of the heap that may be used, each has associated tradeoffs. See Dynamic Memory Allocation for information about heaps. Additionally see Debugging Common Heap Issues for more information on debugging common heap issues.

For projects where the stack project builds a library:

  • Application and Stack statically allocated data: This includes any initialized and uninitialized variables used by the application or stack. (.data,.bss)

RAM Vector Table

As detailed in the Flash Vector Table section, this table is intialized at kernel boot time with the contents of the flash vector table. The location of this table is controlled by m3Hwi.vectorTableAddress within the TI-RTOS config file (*.cfg), it defaults to address 0x20000000. The VTOR register will point to this table, which allows the creation of dynamic interrupts at runtime. This table will contain entries for all 50 supported interrupts.

For more information about the vector table format, please refer to Cortex-M3 Vector Table.

System Stack

As described in Tasks, each task has its own runtime stack for context switching. Another runtime stack is used by the RTOS for main(), HWIs, and SWIs. This system stack is allocated in the application linker file to be placed at the end of the RAM of the application.

For IAR, this RTOS system stack is defined by the CSTACK symbol:

////////////////////////////////////////////////////////////////////////////////
// Stack
define symbol STACK_SIZE            = 0x400;
define symbol STACK_START           = RAM_END + 1;
define symbol STACK_END             = STACK_START - STACK_SIZE;
//
define symbol STACK_TOP             = RAM_END + 1;
export symbol STACK_TOP;

// Runtime Stack
define block CSTACK with alignment = 8, size = STACK_SIZE { section .stack };
place at end of RAM { block CSTACK };

In IAR, to change the size of the CSTACK, adjust the STACK_SIZE symbol value in the linker configuration file (.icf) of the application.

For CCS, depending on the project’s current build configuration the RTOS system stack is defined by the Program.stack parameter in the ble_debug.cfg or ble_release.cfg RTOS configuration file:

/* ================ Program configuration ================ */
/* main() and Hwi, Swi stack size */
Program.stack = 1024;

and placed by the linker in the RAM space of the application:

/* Create global constant that points to top of stack */
/* CCS: Change stack size under Project Properties */
__STACK_TOP = __stack + __STACK_SIZE;

Dynamic Memory Allocation

The system uses a single heap for dynamic memory allocation. This heap is shared between TI-RTOS, the protocol stack, and the application.

The RTOS configuration file that configures the heap depends on the project’s build configuration. If the project’s current build configuration is FlashROM_Debug the file that configures the heap is ble_debug.cfg. If the project’s current build configuration is FlashROM_Release the file that configures the heap is ble_release.cfg.

Using the RTOS configuration file above the heap can be configured in one of three ways. Regardless of the underlying heap implementation, the APIs to access the heap are common.

  • OSAL Heap (legacy) - This is the legacy heap manager created to work with the stack. It is implemented by rtos_heaposal.h. The OSAL heap suppports creating variable sized blocks as well as freeing blocks.
  • TI-RTOS HeapMem - The most flexible heap implementation offered by the TI-RTOS kernel. HeapMem supports creating variable sized blocks as well as freeing blocks. It is implemented by rtos_heapmem.h when using RTOS in ROM and by direct calls when using RTOS in flash. See HeapMem with TI-RTOS in ROM for details on using the HeapMem module in ROM with the stack.
  • TI-RTOS HeapMem with HeapTrack - The most flexible heap implementation offered by the TI-RTOS kernel. HeapMem suppports creating variable sized blocks as well as freeing blocks. It is implemented by rtos_heaptrack.h when using RTOS in ROM and by direct calls when using RTOS in flash. On top of the functionality offered by HeapMem, HeapTrack offers additional debugging capability, at the cost of runtime performance. See HeapMem with TI-RTOS in ROM for details on using the HeapMem module in ROM with the stack.

Configuring the Heap

The active heap configuration is set via the HEAPMGR_CONFIG variable. If auto heapsizing is not used, the size of the heap is controlled via HEAPMGR_SIZE.The location of both the HEAPMGR_CONFIG and HEAPMGR_SIZE variables are dependent on the project’s current build configuration. If the project’s current build configuration is FlashROM_Debug these variables are located in ble_debug.cfg. If the project’s current build configuration is FlashROM_Release these variables are located in ble_release.cfg.

The system will default to using the OSAL heap with auto heap size. The table below shows the possible configurations of the heap along with their associated values of HEAPMGR_CONFIG and HEAPMGR_SIZE.

HEAPMGR_CONFIG Active Heap Configuration Heap Size
0x00 OSAL HeapMgr, static heap size Set by HEAPMGR_SIZE
0x80 OSAL HeapMgr, automatic heap size Automatically determined by the amount of free space available at link time between heapStart and heapEnd symbols
0x01 HeapMem, static heap size Set by HEAPMGR_SIZE
0x81 HeapMem, automatic heap size Automatically determined by the amount of free space available at link time between heapStart and heapEnd symbols
0x02 HeapMem + HeapTrack, static heap size Set by HEAPMGR_SIZE
0x82 HeapMem + HeapTrack, automatic heap size Automatically determined by the amount of free space available at link time between heapStart and heapEnd symbols

Warning

If autoheap size is to be used, heapStart and heapEnd symbols must be defined in the linker file. See your application’s map file for the location of these sections in the StackLibrary configuration.

  • heapStart – Placed at end of static allocation section
  • heapEnd – Placed right before beginning of CSTACK section

See the snippet below from ble_release.cfg to see how to change the active heap configuration. Change the variable in the highlighted line to one of the values supported in the table above.

1
2
3
4
var Memory = xdc.useModule('xdc.runtime.Memory');
var HEAPMGR_CONFIG = 0x00;  //set to OSAL HeapMgr, static heap size
var HEAPMGR_SIZE   = 30000; //only valid if static size is used. This is the
                            //size of the buffer allocated for Heap.

HeapMem with TI-RTOS in ROM

When using any HeapMem based configuration combined with TI-RTOS in ROM, the heap will be implemented by HeapCallback module. HeapCallback will call a user defined function whenever a dynamic memory operation is required. The user defined functions are located in the following files.

  • rtos_heapmem.h – HeapMem
  • rtos_heaptrack.h – HeapMem + HeapTrack

This is required because the HeapMem implementation in ROM uses the GateMutex module, which prevents malloc() from being called in a hwi or swi. In order to allow safe use of the heap a GateHWI must be used. To work around this, the HeapCallback implementation will wrap any access to the heap in a HWI lock. See the following example from rtos_heapmem.h.

/* Protect since HeapMem_allocUnprotected does not */
hwikey = (uint_least16_t)Hwi_disable();

/* Using the default system heap for this example */
tmp = HeapMem_allocUnprotected(stackHeap, size, FORCED_ALIGNEMENT);

// ..

/* restore the hwi mutex */
Hwi_restore(hwikey);

Note

Note that the legacy OSAL heap always protects heap operations with a HWI lock.

When using a flash based kernel, the HeapMem module is configured to use a GateHWI, see the following excerpt from ble_debug.cfg.

Program.global.stackHeap = HeapMem.create(heapMemParams);
var GateHwi = xdc.useModule('ti.sysbios.gates.GateHwi');
HeapMem.common$.gate = GateHwi.create();
Memory.defaultHeapInstance = Program.global.stackHeap;

Profiling the Heap

Refer to Debugging Common Heap Issues for tips on debugging common heap issues. Each heap implementation has its benefits for debugging and some come with performance tradeoffs. Note the metrics function may be used by any supported heap configuration.

Note

The auto heap size feature does not determine the amount of heap needed for the application. The system designer must ensure that the heap has the required space to meet the application’s runtime memory requirements.

Heap APIs

Note that regardless of the heap implementation selected, the APIs are compatible across all supported heap implementations. The following APIs may be used to access the heap:

  • ICall_heapMalloc – Dynamically allocate a block of memory
  • ICall_heapFree – Dynamically free a block of memory
  • ICall_heapRealloc – Resize an existing heap block
  • ICall_heapGetStats – Get information about the state of the heap

The following is an example of dynamically allocating a variable length (n) array using the ICall heap:

//define pointer
uint8_t *pArray;
// Create dynamic pointer to array.
if (pArray = (uint8_t*)ICall_malloc(n*sizeof(uint8_t)))
{
//fill up array
}
else
{
//not able to allocate
}

The following is an example of freeing the previous array:

ICall_free(pMsg->payload);

Cache

The cache is an 8 KB section of the device’s RAM reserved for the processor. The cache module temporarily stores data that has been read from the Flash, so that frequently used data is not fetched from Flash on each access. This reduces the number of CPU wait-states and saves power. When the cache is not used, it is not powered. This is true for Standby and Idle states where the cache is not in use.

AUX RAM

The AUX RAM is a 2 KB memory area belonging to the Sensor Controller.