RAM

There is 80 kB of RAM available in the CC13x2x1 or CC26x2x1, 144 kB in CC13x2x7 or CC26x2x7, and 32 kB in CC13x1x3 or CC26x1x3. 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 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. If the active configuration doesn’t use ROM, these sections may be used for other purposes.

  • HEAP: See Dynamic Memory Allocation for information about heaps.

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

This table is initialized at kernel boot time with the contents of the flash vector table. The location of this table is controlled by SysConfig in the TI RTOS configuration settings, 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.

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 in the .icf file. To change the size of the CSTACK, adjust the STACK_SIZE symbol value (see highlighted line).

     ////////////////////////////////////////////////////////////////////////////////
     // 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;
////////////////////////////////////////////////////////////////////////////////
// Memory Placement
////////////////////////////////////////////////////////////////////////////////

//...

      // Runtime Stack
      define block CSTACK with alignment = 8, size = STACK_SIZE { section .stack };

//...

      define block END_OF_RAM with fixed order {
                                      block HEAP_END,
                                      block CSTACK
                                    };

place at end of RAM { block END_OF_RAM };

For CCS, the RTOS system stack size is defined in the linker file as shown below:

--stack_size=1024   /* C stack is also used for ISR stack */

Dynamic Memory Allocation

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

The heap configuration is configured via SysConfig inside TI-RTOSBIOSDefault Heap Settings. Using SysConfig, the heap can be configured in a few ways. Regardless of the underlying heap implementation, the APIs to access the heap are common.

  • TI-RTOS7 HeapMem - The flexible heap implementation offered by the TI-RTOS7 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.

  • TI-RTOS7 HeapMem with HeapTrack - The most flexible heap implementation offered by the TI-RTOS7 kernel. HeapMem supports 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. To enable HeapTrack, select the Use HeapTrack with system default heap option in SysConfig.

Configuring the Heap

The heap configuration is configured via SysConfig inside TI-RTOSBIOSDefault Heap Settings.

For more information regarding configuration options, please refer to Section 7.4 Heap Implementations of the TI-RTOS7 Kernel (SYS/BIOS) User’s Guide.

Hint

When using static heap size, it’s a good idea to review the heap size thoroughly.

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.

Using the Cache as RAM

The cache can be disabled temporarily or permanently and used as RAM instead. A disabled cache will result in a slower execution time for software because all data needs to be fetched from flash. This increases the device power consumption. If you want to temporarily disable the chache for extra RAM at runtime, jump ahead to the Dynamic GPRAM section. If you want to permanently allocate cache for RAM usage, see the Configure the Cache as GPRAM section.

If your application needs more memory, or if you need more space in SRAM, the cache can be re-purposed as RAM. This will allow the linker to store parts of the compiled application in this section of the RAM. This section will be referred to as the general purpose RAM (GPRAM). This will cause the program to run at a slightly reduced speed, and it will increase the device power consumption in sleep. This is because the GPRAM, contrary to a cache, will have to be powered even when the device is sleeping. The current consumption in standby mode with and without cache retained is listed in the CC13xx or CC26xx datasheet. How this will affect the device power consumption will depend on application. For some applications the added power consumption will be very small, but for processing intensive application it will be slightly higher. Please verify your application current consumption by using the method described in the Measuring CC13xx and CC26xx current consumption (SWRA478).

Configure the Cache as GPRAM

In order to enable using the cache as RAM, two things need to be done. Firstly, the program must be told to retain the cache/GPRAM when it’s being used. Secondly, the linker must be told to allocate the memory region used as cache to GPRAM, and what parts of code to store in the GPRAM. This is done in the linker command/configuration file. The syntax for the linker command/configuration file is slightly different in CCS and IAR. To read more about the CCS linker command file, see the article Linker Command File Primer. To read more about the IAR linker, see IAR C/C++ Development Guide.

If you want to use the cache as RAM in a project, follow these steps:

Note

The steps will be different for CCS users and IAR users. The steps will also differ depending on what example project your project is based on. For the example projects found in the BLE5-Stack folder, only step 1-5 will be required.

1. In the syscfg file, go to TI DevicesDevice Configuration and select Disable Flash Cache

  1. In main(), add the following code:

Listing 187. Retain cache in sleep.
#ifdef CACHE_AS_RAM
// retain cache during standby
Power_setConstraint(PowerCC26XX_SB_VIMS_CACHE_RETAIN);
Power_setConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
#else
// Enable iCache pre-fetching
VIMSConfigure(VIMS_BASE, TRUE, TRUE);
// Enable cache
VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED);
#endif //CACHE_AS_RAM

Important

Please make sure your program is not using VIMS while using cache as RAM.

In the same file, include the following files:

/* Power Driver */
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
/* Header files required to enable instruction fetch cache */
#include <ti/devices/cc26x0r2/inc/hw_memmap.h>
#include <ti/devices/cc26x0r2/driverlib/vims.h>
  1. Go to the compiler predefines and add CACHE_AS_RAM.

4. The GPRAM memory area must be defined in the linker command file. This syntax is different for the CCS and IAR linker. IAR specific instructions will follow the CCS specific instructions.

In CCS, the linker command file ends with .cmd (e.g. cc13x2_cc26x2_app.cmd).

Listing 188. CCS Linker File. Under Memory Sizes, add defines for GPRAM start and length.
  /*******************************************************************************
   * Memory Sizes
   */
  #define FLASH_BASE   0x00000000
  #define GPRAM_BASE   0x11000000
  #define RAM_BASE     0x20000000
  #define ROM_BASE     0x10000000

  #define FLASH_SIZE   0x00058000
  #define GPRAM_SIZE   0x00002000
  #define RAM_SIZE     0x00014000
  #define ROM_SIZE     0x00040000
Listing 189. Add GPRAM under Memory Definitions.
  /*******************************************************************************
   * GPRAM
   */

  #ifdef CACHE_AS_RAM
    #define GPRAM_START GPRAM_BASE
    #define GPRAM_END   (GPRAM_START + GPRAM_SIZE - 1)
  #endif /* CACHE_AS_RAM */
Listing 190. In MEMORY{}, allocate room for GPRAM.
    #ifdef CACHE_AS_RAM
      GPRAM(RWX) : origin = GPRAM_START, length = GPRAM_SIZE
    #endif /* CACHE_AS_RAM */
Listing 191. In SECTIONS{}, move .bss from SRAM to GPRAM.
  GROUP > SRAM
  {
    .data
    #ifndef CACHE_AS_RAM
    .bss
    #endif /* CACHE_AS_RAM */
    .vtable
    .vtable_ram
    vtable_ram
    .sysmem
    .nonretenvar

  } LOAD_END(heapStart)

  .stack            :   >  SRAM (HIGH) LOAD_START(heapEnd)

  #ifdef CACHE_AS_RAM
  .bss :
  {
    *(.bss)
  } > GPRAM
  #endif /* CACHE_AS_RAM */

Rebuild your application. This will move .bss from SRAM to GPRAM and place the auto-heap size start after. Other objects can also be moved. See Using the AUX RAM as RAM for an example of this.

In IAR, the linker configuration file ends with .icf (e.g. cc26xx_app.icf).

Listing 192. IAR Linker File. Add defines for GPRAM start and length under Memory Definitions.
  //////////////////////////////////////////////////////////////////////////////
  // GPRAM
  //
  if ( isdefinedsymbol(CACHE_AS_RAM) )
  {
    define symbol GPRAM_START           = 0x11000000;
    define symbol GPRAM_SIZE            = 0x2000;
    define symbol GPRAM_END             = GPRAM_START + GPRAM_SIZE;
  }
Listing 193. Under Memory Regions, allocate room for GPRAM.
  if ( isdefinedsymbol(CACHE_AS_RAM) )
  {
    define region GPRAM               = mem:[from GPRAM_START to GPRAM_END];
  }
Listing 194. Under Memory Placement, move .bss from SRAM to GPRAM.
  if ( isdefinedsymbol(CACHE_AS_RAM) )
  {
    // GPRAM
    define block GPDATA { section .bss };
    place in GPRAM { block GPDATA } except { object ll.o };
  }

Rebuild your application. This will move .bss from SRAM to GPRAM. Other objects can also be moved. See Using the AUX RAM as RAM for an example of this.

Dynamic GPRAM

In this mode, the cache will be temporarily used as RAM. At all other times, the cache will operate as normal. The current consumption changes are described in the Configure the Cache as GPRAM section.

An example use-case is a device that sometimes receives or sends a data stream with a high throughput. When the device is not streaming, it can use the cache as usual. When the device receives the signal to start streaming, the device disables the cache and uses the GPRAM to store a buffer for the stream. When the device receives the command to stop streaming, the memory is freed and the cache is re-enabled.

To use the GPRAM to dynamically store a data buffer, follow these steps:

  1. In order to use this functionality, the following files should be included:

#include <ti/sysbios/family/arm/m3/Hwi.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/devices/cc13x2_cc26x2/driverlib/vims.h>

2. In the application, make sure you disable the cache when before you start using the memory area. Use VIMS and the power driver.

/*********************************************************************
* @fn      SimplePeripheral_disableCache
*
* @brief   Disables the instruction cache and sets power constaints
*          This prevents the device from sleeping while streaming
*
* @param   None.
*
* @return  None.
*/
static void SimplePeripheral_disableCache()
{
    uint_least16_t hwiKey = Hwi_disable();
    Power_setConstraint(PowerCC26XX_SB_VIMS_CACHE_RETAIN);
    Power_setConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
    VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_DISABLED, true);
    Hwi_restore(hwiKey);
}
  1. Make sure to re-enable the cache after you are finished using it.

/*********************************************************************
* @fn      SimplePeripheral_enableCache
*
* @brief   Enables the instruction cache and releases power constaints
*          Allows device to sleep again
*
* @param   None.
*
* @return  None.
*/
static void SimplePeripheral_enableCache()
{
    uint_least16_t hwiKey = Hwi_disable();
    Power_releaseConstraint(PowerCC26XX_SB_VIMS_CACHE_RETAIN);
    Power_releaseConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
    VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_ENABLED, true);
    Hwi_restore(hwiKey);
}

4. We will use the GPRAM_BASE define from hw_memmap.h. hw_memmap.h contains defines for the base addresses of the memories and peripherals on the CC13xx or CC26xx.

#define GPRAM_BASE   0x11000000

In the application file, initialize the buffer:

// Initialize buffer
static int16_t *gpram_buffer = NULL;

// Disable instruction cache to use for the buffer
SimplePeripheral_disableCache();
gpram_buffer = (int16_t *)GPRAM_BASE;
  1. Use the buffer:

if (gpram_buffer)
{
    // Use buffer
    gpram_buffer[0] = 0;
    gpram_buffer[0]++;
}

Remember to free the memory and re-enable the cache when the buffer is no longer in use.

//Buffer no longer needed
if (gpram_buffer)
{
    gpram_buffer = NULL;
}
SimplePeripheral_enableCache();

AUX RAM

The AUX RAM is a 4 kB memory area belonging to the Sensor Controller. This is not available on CC13x1x3 or CC26x1x3 devices.

Using the AUX RAM as RAM

For variants other than the CC13x1x3 or CC26x1x3, you can use this memory as RAM for your application if the Sensor Controller is not used. However, access to this memory is significantly slower than access to the SRAM. This may lead to increased power consumption and slower program execution. Additionally, if using the AUX RAM as RAM it is important that you test thoroughly. Certain objects, when put in AUX RAM can cause the application to crash. One should test for each object they want to store in AUX RAM.

Important

The user application can do other tasks while the data is being transferred to AUX RAM, but if the bus buffer gets full during back to back writes, it will stall the AP until there is free space in the buffer. After you write a series of data to AUX RAM you should implement a singe read access to make sure all the data has been written. The read access will stall the AP until all the data has been transferred to AUX RAM.

Modifying the application

  1. Open the project properties and add the symbol AUX_AS_RAM=1 to the linker options:

  • In CCS, right click on the Project → select Properties → Build → ARM Linker → Advanced Options → Command File Preprocessing. Click on the small Add… button at the top right of the box Pre-define preprocessor macro _name_to_value_ and type the symbol AUX_AS_RAM=1.

  • In IAR, right click on the Project → Options → Linker. Locate the box Configuration file symbol definitions and type the symbol AUX_AS_RAM=1.

  1. Modify the linker command/configuration file. Each toolchain has different options, pragmas and syntax, therefore check the steps below for the three supported toolchains: TI ARMCL, TI ARM Clang and IAR.

TI ARMCL:

  • In the linker command file cc26xx_app.cmd, define the AUX_RAM memory area:

    #ifdef AUX_AS_RAM
    #define AUX_RAM_BASE            0x400E0000
    #define AUX_RAM_SIZE            0x800
    #endif /* AUX_AS_RAM */
    
  • Create a AUX_RAM memory section in MEMORY{}

#ifdef AUX_AS_RAM
AUX_RAM (RWX) : origin = AUX_RAM_BASE, length = AUX_RAM_SIZE
#endif /* AUX_AS_RAM */
  • Add sections of memory or code to AUX_RAM in SECTIONS{}

    Listing 195. Move object files into AUX_RAM. Example from simple_peripheral (cc26xx_app.cmd).
    #ifdef AUX_AS_RAM
      reorganized_into_auxram
      {
        simple_peripheral.obj(.data)
        devinfoservice.obj(.data)
        simple_gatt_profile.obj(.data)
        icall.obj(.data)
        board.obj(.bss)
        } > AUX_RAM
    #endif/* AUX_AS_RAM */
    

The .obj files are listed in the FlashROM folder of the app project. They are also listed with size in the .map file. A detailed description of the linker command file and memory sections is given in this article Linker Command File Primer.

If you want more control over what is stored in AUX_RAM, individual variables can be stored there with the #pragma DATA_SECTION command. Please note that this is only possible for global variables.

Listing 196. Move the global display handle variable into a new AUX RAM section called my_section.
// Display Interface
#pragma DATA_SECTION(dispHandle, "my_section")
Display_Handle dispHandle = NULL;

You can find my_section in the map-file. Here you will find the names of the objects included in my_section. In this case, the object is simple_peripheral.obj (my_section).

Listing 197. In the linker command file (cc26xx_app.cmd), add the section to AUX_RAM.
#ifdef AUX_AS_RAM
  reorganized_into_auxram
  {
    simple_peripheral.obj(my_section)
  } > AUX_RAM
#endif /* AUX_AS_RAM */

Important

When making alterations only to the linker command file, please make sure to press Rebuild, not just Build. (CCS will not recognize that you have made changes to the project before you press Rebuild.)

TI ARM Clang:

The linker command file is very similar to the TI ARMCL toolchain. For additional details, check chapter 5 of the TI ARM Clang User’s Guide.

  • In the linker command file cc26xx_app.cmd, define the AUX_RAM memory area:

    #ifdef AUX_AS_RAM
    #define AUX_RAM_BASE            0x400E0000
    #define AUX_RAM_SIZE            0x800
    #endif /* AUX_AS_RAM */
    
  • Create a AUX_RAM memory section in MEMORY{}

#ifdef AUX_AS_RAM
AUX_RAM (RWX) : origin = AUX_RAM_BASE, length = AUX_RAM_SIZE
#endif /* AUX_AS_RAM */
  • Add sections of memory or code to AUX_RAM in SECTIONS{}

    Listing 198. Move object files into AUX_RAM. Example from simple_peripheral (cc26xx_app.cmd).
    #ifdef AUX_AS_RAM
      reorganized_into_auxram
      {
        simple_peripheral.o(.data)
        devinfoservice.o(.data)
        simple_gatt_profile.o(.data)
        icall.o(.data)
        board.o(.bss)
        } > AUX_RAM
    #endif/* AUX_AS_RAM */
    

The .o files are listed in the FlashROM folder of the app project. They are also listed with size in the .map file. A detailed description of the linker command file and memory sections is given in this article Linker Command File Primer.

If you want more control over what is stored in AUX_RAM, individual variables can be stored there with the __attribute__((section("section_name"))) command. Please note that this is only possible for global variables.

Listing 199. Move the global display handle variable into a new AUX RAM section called my_section.
// Display Interface
__attribute__((section("my_section")))
Display_Handle dispHandle = NULL;

You can find my_section in the map-file. Here you will find the names of the objects included in my_section. In this case, the object is simple_peripheral.o (my_section).

Listing 200. In the linker command file (cc26xx_app.cmd), add the section to AUX_RAM.
#ifdef AUX_AS_RAM
  reorganized_into_auxram
  {
    simple_peripheral.o(my_section)
  } > AUX_RAM
#endif /* AUX_AS_RAM */

Important

When making alterations only to the linker command file, please make sure to press Rebuild, not just Build. (CCS will not recognize that you have made changes to the project before you press Rebuild.)

IAR:

  • Open the linker configuration file cc26xx_app.icf. Under Memory Definitions, add

    ////////////////////////////////////////////////////////////////////////////////
    // AUX_RAM
    //
    if ( isdefinedsymbol(AUX_AS_RAM) )
    {
      define symbol AUX_RAM_START        = 0x400E0000;
      define symbol AUX_RAM_SIZE         = 0x800;
      define symbol AUX_RAM_END          = AUX_RAM_START + AUX_RAM_SIZE;
    }
    
  • Under Memory Regions, add

    if ( isdefinedsymbol(AUX_AS_RAM) )
    {
      define region AUX_RAM               = mem:[from AUX_RAM_START to AUX_RAM_END];
    }
    
  • Under Memory Placement, add

    Listing 201. Move object files into AUX_RAM. Example from simple_peripheral (cc26xx_app.icf).
    if ( isdefinedsymbol(AUX_AS_RAM) )
    {
      // AUX_RAM
      define block AUXDATA { section .data object simple_peripheral.o,
                             section .data object devinfoservice.o,
                             section .data object simple_gatt_profile,
                             section .data object icall.o,
                             section .data object board.o};
      place in AUX_RAM { block AUXDATA };
    }
    

The .o-files are listed in the .map file. For more information on the linker configuration file, please see IAR C/C++ Development Guide.

If you want more control over what is stored in AUX_RAM, individual variables can be stored there with the #pragma location command. Please note that this is only possible for global variables.

Listing 202. Move the global display handle variable into a new Cache RAM section called my_section.
// Display Interface
#pragma location="my_section"
Display_Handle dispHandle = NULL;

You can find my_section in the map-file. Here you will find the names of the objects included in my_section. In this case, the object is simple_peripheral.o (my_section).

Listing 203. In the linker configuration file (cc26xx_app.cmd), add the section to AUX_RAM.
if ( isdefinedsymbol(AUX_AS_RAM) )
{
  // AUX_RAM
  define block AUXDATA { section my_section object simple_peripheral.o };
  place in AUX_RAM { block AUXDATA };
}