7. Example of Memory Programming

In general, the application image, besides the SysCPU code, may also include the CMAC and/or the SNC code. In case of CMAC, the CMAC code is included as a library and is loaded in RAM10.

If CMAC code and data are larger than RAM10’s size, RAM9 will also be used, otherwise, both RAM9 and the rest of RAM10 can be used by the SysCPU. In case of SNC, the code is included as a header file and the SysCPU code copies it in the beginning of RAM1. All projects use linker scripts to place the pieces of code and data in the RAM. In this section, DA1470x SNC template project is used as example project to describe and analyze the use of these scripts. The SNC template project refer to two separate applications and corresponding projects, os_app_retarget and os_snc_retarget. In this example, the os_snc_retarget application, the SNC code sends every 1 second some data (a timestamp and a counter value) to the SysCPU, which the SysCPU then prints to console through the UART, as implemented in the os_app_retarget application.

These two applications exchange data through RAM8, that is the shared memory RAM cell. The os_snc_retarget application defines a sector in this cell, for its own data, and the symbols that are to be shared are published to the os_app_retarget application at runtime. The os_app_retarget application will take into account the starting address and the size of SNC defined section in the shared memory in order to avoid using the same space in the shared RAM cell. When building the os_snc_retarget application, a header file is produced, namely snc_fw_embed.h, which contains a hex table with the SNC image, a void table for SNC shared space and all necessary definitions for os_app_retarget. Those definitions include the starting address of SNC shared space and the size of it, the size of SNC firmware and the address of a structure used by SNC and SysCPU to publish shared symbols to each other. This file must be copied to the os_app_retarget application. On the other hand, the os_app_retarget application will use this header file in order to load the SNC firmware to the correct place in RAM and get access to SNC shared space.

All projects use two different kind of linker scripts, the memory (mem.ld) and the sections (sections.ld), which are produced in the output folder after compilation. These scripts are produced from the memory (mem_*.ld.h) and sections (sections_*.ld.h) header files, respectively, located in the ldscripts/ble_projects folder of the SDK.

7.1. Programming with Linker Scripts

7.1.1. os_snc_retarget Application Linker Scripts

The mem.ld linker script of the os_snc_retarget application is presented below:

__SNC_BASE = 0x00000000;
__SNC_SIZE = 64K;
__SHARED_BASE = 0x00030000;
__SHARED_SIZE = 128K;
MEMORY
{
   SNC (rwx) : ORIGIN = __SNC_BASE, LENGTH = __SNC_SIZE
   SHARED (rw) : ORIGIN = __SHARED_BASE, LENGTH = __SHARED_SIZE
}

The whole memory is divided into areas. Each area has a name (i.e. SNC and SHARED), base address, size and attributes (rwx). These areas are used by the sections.ld linker script. In the sections.ld linker script, the user declares the memory sections and defines the name, the contents and the memory area to be placed in for each section, as the example presented below:

.retention_ram_zi (NOLOAD) :
     {
             __retention_ram_zi_start__ = .;
             *(privileged_data_zi)
             *(retention_mem_zi)
             __retention_ram_zi_end__ = .;
     } > SNC

More specifically, section retention_ram_zi is defined, which includes all the variables of privileged_data_zi and retention_mem_zi type. This section will be loaded in the SNC memory area, which is defined in the mem.ld linker script. The output of this in the map file is presented below:

.retention_ram_zi
                0x000047f8     0x293c
                0x000047f8                __retention_ram_zi_start__ = .
*(privileged_data_zi)
privileged_data_zi
                0x000047f8     0x2728 ./sdk/dgCoRoutines/portable/MemMang/heap_4.o
privileged_data_zi
                0x00006f20      0x110 ./sdk/dgCoRoutines/dialog_croutine.o
                0x00006f70                pxCurrentTCB
privileged_data_zi
                0x00007030       0x20 ./sdk/dgCoRoutines/dialog_queue.o
                0x00007030                xQueueRegistry
privileged_data_zi
                0x00007050       0x3c ./sdk/dgCoRoutines/dialog_timers.o
*(retention_mem_zi)
retention_mem_zi
                0x0000708c        0x2 ./startup/config.o
*fill*         0x0000708e        0x2
retention_mem_zi
                0x00007090       0x4e ./sdk/sys_man/sys_power_mgr_da1470x.o
*fill*         0x000070de        0x2
retention_mem_zi
                0x000070e0        0xc ./sdk/sys_man/sys_tcs_da1470x.o
*fill*         0x000070ec        0x4
retention_mem_zi
                0x000070f0       0x14 ./sdk/sys_man/sys_timer.o
                0x00007100                lp_last_trigger
retention_mem_zi
                0x00007104        0x4 ./sdk/snc/api/src/snc.o
retention_mem_zi
                0x00007108       0x18 ./sdk/peripherals/src/hw_timer.o
retention_mem_zi
                0x00007120        0x4 ./sdk/peripherals/src/hw_watchdog.o
retention_mem_zi
                0x00007124       0x10 ./sdk/peripherals/src/hw_wkup_v2.o
                0x00007134                __retention_ram_zi_end__ = .

There are macros that can be used in the SNC code to declare a variable as privileged_data_zi or retention_mem_zi type and, therefore, determine which specific memory area will be placed to. The macros for the cases of this example are the following:

#define PRIVILEGED_DATA                __attribute__((section("privileged_data_zi")))
and
#define __RETAINED                     __attribute__((section("retention_mem_zi")))

This way, all the variables of the project are placed in a memory area. In case no macros are used, all global zero initialized or uninitialized variables and all static zero initialized or uninitialized variables are placed in the bss section. The global and static initialized variables are placed in the data section which is included in the retention_ram_init section. In the os_snc_retarget application, the linker scripts are quite simple, since all code and data are linked to the SNC memory area The last 0x300 bytes of RAM2, as defined by __STACK_SIZE macro, are used for stack, as presented below:

.stack (ORIGIN(SNC) + LENGTH(SNC) - 0x300) (COPY) :
{
        . = ALIGN(8);
        __StackLimit = .;
        KEEP(*(.stack*))
        . = ALIGN(8);
        __StackTop = .;
} > SNC

The size of stack is configurable by the __STACK_SIZE definition in the custom_config_snc.h header file of os_snc_retarget project.

7.1.2. os_app_retarget Application Linker Scripts

Build configurations in os_app_retarget application provide the option to execute SysCPU code either from OQSPI XIP Flash or RAM.

7.1.2.1. Flash Build Configuration

The mem.ld linker script of the os_app_retarget application for Flash build configuration is presented below:

MEMORY
{
        IVT : ORIGIN = 0x0F000000 + 0x200, LENGTH = 8K - 0x200
        SNC : ORIGIN = 0x20000000, LENGTH = 64K
        SHARED : ORIGIN = 0x20110000, LENGTH = 128K
}
        MEMORY
        {
                CMAC : ORIGIN = (0x20150000 + ((0x30000) - ((0x30000) - (0)))), LENGTH = (((0x30000) - (0)))
        }
        MEMORY
        {
                RAMC (x) : ORIGIN = 0x00000000, LENGTH = 256K
                RAMS (rwx) : ORIGIN = 0x20050000, LENGTH = 768K
        }

There are totally seven different memory areas defined. Two of them have the same name as in os_snc_retarget application, namely SNC and SHARED. They also have the same size but different base addresses, adjusted to each CPU’s address range, so that both can refer to the same place in RAM (i.e. RAM1, RAM2 and RAM8). There are also areas defined for the Interrupt Vector Table (IVT) in RAM0, an area for the extra CMAC code (CMAC) in RAM10, the retention code (RAMC) and data (RAMS) in RAM3, and code and data which reside in Flash memory (FLASH). Since we are using the Instruction Cache controller to run the retention code, the base address for RAMC is 0x10010000 which physically is the same as 0x20010000, used as base address in RAMS memory. There is a mechanism used to avoid overlapping code and data in this memory area, presented later in this section. If the project does not use SNC, then RAMC can also include RAM1 and RAM2, thus starting from address 0x10000000. Furthermore, the OQSPI XIP Flash is remapped to 0, therefore the base address of FLASH memory is 0x00000000. In the flash build configuration, the flash is powered down when SysCPU goes to sleep. Therefore, the code executed after the flash is powered down until SysCPU finally goes to sleep and after SysCPU wakes up until the flash is finally powered up again, is retained in RAM, and is called retained code. Retained data are the data that need to be maintained while SysCPU is in sleep mode.

In the sections.ld linker script, all non- retained code and constant data sections are placed to the FLASH memory area, retained code is placed in RAMC, retained data, bss and stack in RAMS, CMAC code and data in CMAC and the shared retained data in SHARED memory area. In order to force pieces of code and variables to be placed to retained sections there are appropriate macros, such as __RETAINED_CODE for code and __RETAINED, __RETAINED_RW, __RETAINED_UNINIT etc, to be used in the declaration of variables and functions. The RAMS memory area, in the os_app_retarget application, has a size of 1152K, which means that it includes all RAM cells from RAM3 till RAM8, as presented below:

#     ifdef CONFIG USE_SNC
            /* reserve first 64K for SNC */
#           define RAMC_ORG 6x1e016800
#           define RAMS ORG 6x2ee18e880
#           define SNC_MEM_LEN 6
#     else
#           define RAMC_ORG 6x1e900000
#           define RAMS ORG 6x28000806
#           define SNC_MEM_LEN 64K
#     endif

#     if (dg_configUSE_CMAC_MEMORIES FOR _DATA == @)
#           define CMAC_MEM_LEN 6
#     else
#           define CMAC_MEM_LEN 320K
#     endif

#     define RAMS LEN (896K + SNC_MEM_LEN + CMAC_MEM_LEN)

Since SNC is used in os_app_retarget application, RAM1 and RAM2 are not available for SysCPU execution context. Therefore, SNC_MEM_LEN is 0. CMAC_MEM_LEN is also 0, since CMAC memory cells are not available for SysCPU data as part of RAMS region. If all of them are available, as implied by an application project which uses neither CMAC nor SNC, RAMS_LEN will increase to 1152 + 320 + 64 = 1536K, including RAM1, RAM2, RAM9 and RAM10, which is the maximum RAM space of the system.

All retained data are placed in the RAMS memory area which occupies a memory area from RAM3 cell up to RAM8 cell, RAM8 included. The retained code is stored in the RAMC memory area, which resides in RAM3 cell. The linker script uses a symbol to mark the end of code and data sections that are stored in the FLASH memory area. This symbol will be used during creation of the loading image, as the load address of the RAMC memory area code. The data of the RAMS memory area, will use the same symbol (__etext) and the START/END linker script symbols of the RAMC memory area (i.e. __retention_text_start__ / __retention_text_end__) to be loaded in the image right after the RAMC code and data.

Since both RAMC and RAMS, though they have different base addresses, are placed in the same physical RAM cell (RAM3), it is necessary not to link different pieces of code and data to the same place. This is achieved by using RAM_UNUSED_THROUGH_CPU_S section, as presented below:

.retention_text : AT (0x0 + __etext)
{
        . = ALIGN(4);
        __retention_text_start__ = .;
        *(text_retained)
        *libnosys.a:sbrk.o (.text*)
        *libgcc.a:_aeabi_uldivmod.o (.text*)
        *libgcc.a:_muldi3.o (.text*)
        *libgcc.a:_dvmd_tls.o (.text*)
        *libgcc.a:bpabi.o (.text*)
        *libgcc.a:_udivdi3.o (.text*)
        *libgcc.a:_clzdi2.o (.text*)
        *libgcc.a:_clzsi2.o (.text*)
        . = ALIGN(4);
        __retention_text_end__ = .;
} > RAMC
.RAM_UNUSED_THROUGH_CPU_S (NOLOAD) :
{
        . += (__retention_text_end__ - __retention_text_start__);
} > RAMS
.retention_ram_init : AT (0x0 + __etext + (__retention_text_end__ - __retention_text_start__))
{
        . = ALIGN(4);
        __retention_ram_init_start__ = .;
        *(privileged_data_init)
        *(.retention)
        *(vtable)
        *(retention_mem_init)
        *(retention_mem_const)
        *libg_nano.a:* (.data*)
        *libnosys.a:* (.data*)
        *libgcc.a:* (.data*)
        *libble_stack_da1470x.a:* (.data*)
        *crtbegin.o (.data*)
        KEEP(*(.jcr*))
        . = ALIGN(4);
        __retention_ram_init_end__ = .;
} > RAMS

The RAM10 cell is used by SysCPU for storing data of Deterministic Random Bit Generator (DRBG), True Random Number Generation (TRNG) and CHACHA20 Random Generator. If the project doesn’t use CMAC, just like the current example, then these data are placed in the beginning of the RAM10 cell. Otherwise, it is placed just after the reserved space for CMAC code, which is controlled by the following definitions:

#define CMAC_AREA_SIZE (139)
and
#define CMAC_AREA_BYTES \
     (CMAC_AREA_SIZE > 0 ? (CMAC_AREA_SIZE * 1024) :  0)

Reserving memory space for SysCPU in order to store DRBG and application data in RAM10 cell is enabled with the use of the following definitions. Similar definitions need to be defined for reserving space in RAM9 cell (i.e. size needs to be defined as a >0 value), provided that CMAC code and data size does not exceed the size of RAM10 cell.

#define dg_configUSE_CMAC_RAM9_BASE                     (0)
#define dg_configUSE_CMAC_RAM9_SIZE                     (0)
and
#define dg_configUSE_CMAC_RAM10_BASE                    (0)
#define dg_configUSE_CMAC_RAM10_SIZE                    (0)

In case specific application symbols, i.e. variables or functions, need to be placed in RAM9 or RAM10 cells, the following definitions need to be used for each RAM cell, respectively.

#if (__RAM9_SIZE_FOR_MAIN_PROC > 0)
/**
 * \brief Attribute for data to be placed in RAM9
* (which has slower access times for the MAIN PROCESSOR)
 */
# define __IN_CMAC_MEM2                 __attribute__((section("m33_data_in_ram9"))

/**
* \brief Attribute for uninitialized data to be placed in RAM9
* (which has slower access times for the MAIN PROCESSOR)
 */
# define __IN_CMAC_MEM2_UNINIT          __attribute__((section("m33_uninit_data_in_ram9")))
#endif

#if (__RAM10_SIZE_FOR_MAIN_PROC > 0)
/**
* \brief Attribute for data to be placed in RAM10
* (which has slower access times for the MAIN PROCESSOR)
*/
# define __IN_CMAC_MEM1                 __attribute__((section("m33_data_in_ram10")))

/**
* \brief Attribute for uninitialized data to be placed in RAM10
* (which has slower access times for the MAIN PROCESSOR)
*/
# define __IN_CMAC_MEM1_UNINIT          __attribute__((section("m33_uninit_data_in_ram10")))
#endif

Finally, the last sections linked in the RAMS memory area are the stack section for application stack, and the .bss section, which contains the static variables of the application. The default size of stack is 0x200 bytes, as defined by the macro __STACK_SIZE in the bsp_memory_defaults.h header file.

.stack_section (NOLOAD) :
{
        . = . + 1;
        . = ALIGN(8);
        __StackLimit = .;
        KEEP(*(.stack*))
        . = ALIGN(8);
        __StackTop = .;
        PROVIDE(__stack = __StackTop);
} > RAMS

.bss :
{
        . = ALIGN(4);
        __bss_start__ = .;
        *(EXCLUDE_FILE(*libg_nano.a:* *libnosys.a:* *libgcc.a:* *libble_stack_da1470x.a:* *crtbegin.o) .bss*)
        *(COMMON)
        . = ALIGN(4);
        __bss_end__ = .;
} > RAMS

7.1.2.2. RAM Build Configuration

The mem.ld linker script of the os_app_retarget application for RAM build configuration is presented below:

MEMORY
{
        IVT : ORIGIN = 0x0F000000 + 0x200, LENGTH = 8K - 0x200
        SNC : ORIGIN = 0x20000000, LENGTH = 64K
        SHARED : ORIGIN = 0x20110000, LENGTH = 128K
}
        MEMORY
        {
                CMAC : ORIGIN = (0x20150000 + ((0x30000) - ((0x30000) - (0)))), LENGTH = (((0x30000) - (0)))
        }
        MEMORY
        {
                RAMC (x) : ORIGIN = 0x00000000, LENGTH = 256K
                RAMS (rwx) : ORIGIN = 0x20050000, LENGTH = 768K
        }

As expected, IVT, SNC, SHARED and CMAC memory areas are the same as in the case of the Flash build, but in this case, there is no FLASH memory area. Moreover, since OQSPI XIP Flash is not used and RAM1 and RAM2 cells host the SNC code, the RAM3 cell must be remapped to 0. Therefore, the base address of RAMC now becomes 0x00000000, while RAMS area now starts from the RAM4 cell (i.e. 0x20050000) and also includes RAM5, RAM6 and RAM7 cells. Compared to the section.ld linker script created for the FLASH build, the RAM build defines a new memory area, called LMA_RAM (Load Memory Address RAM) which replaces the FLASH memory area maintaining the same pieces of code and data. This is necessary since the code is linked as if running from 0x0, but will be loaded at physical address of RAM3 start address (i.e. 0x20010000), until remapping of RAM3 to 0x0 is executed. The rest of the sections are similar to the FLASH build output, which has been discussed in the previous section.

7.1.3. SHARED Memory Area Analysis

Both SysCPU and SNC applications define and use the SHARED memory area to communicate and exchange data to each other. The section allocated in the SHARED memory area of the os_snc_retarget application is presented below:

.snc_shared (NOLOAD) :
{
        __snc_shared_start__ = .;
        . = ALIGN(4);
        __snc_shared_space_start__ = .;
        KEEP(*(retention_mem_shared_zi))
        __snc_shared_space_end__ = .;
        . = ALIGN(4);
        __snc_exception_space_start__ = .;
        KEEP(*(nmi_info))
        KEEP(*(hard_fault_info))
        __snc_exception_space_end__ = .;
        . = ALIGN(4);
        __snc_shared_end__ = .;
} > SHARED

The .snc_shared section includes all the symbols defined with one of the attributes retention_mem_shared, nmi_info and hard_fault_info. On the other side, the section allocated in the SHARED memory area of the os_app_retarget application is presented below:

.shared_section_retained_zi (NOLOAD) :
{
        __shared_section_retained_zi_start__ = .;
        KEEP(*(.snc_shared_ram_area*))
        . = ALIGN(4);
        *(retention_mem_shared_zi)
        __shared_section_retained_zi_end__ = .;
} > SHARED

The .shared_section_retained_zi section includes all the symbols defined with attributes snc_shared_ram_area and retention_mem_shared_zi. The SNC application code defines a structure located at retention_mem_shared_zi area, called snc_shared_space_info, and so, it will be linked in the SHARED memory area. This structure is part of the communication interface between SysCPU and SNC applications, as it includes the addresses of SNC’s shared structures (NMI info, Hard Fault info, HW SYS info, TCS info and Application info). The SNC code defines two more structures, app_shared_info and app_shared_data, which are located at retention_mem_shared_zi area, too, and they are also linked in the SHARED memory area. The addresses of those two structures are registered in the app_info member of the snc_shared_space_info structure of SNC application presented below:

typedef  struct  {
      /* Indication  of  SNC correct start-up  */
      volatile uintl6_t snc_is_ready   :   1;

      /*  Indication of SNC error  */
      volatile  uintl6_t snc_error_val;
      volatile  uintptr_t snc_error_args;

#if (HAVE_APP_DEFTNED_HANDLES)
      /* Shared space areas defined by the application  */
      volatile uintptr_t app_info[SNC_SHARED_SPACE_APP_COUNT] ;
#endif

      /* Shared space area for NMI exception information */
      volatile uintptr_t nmi_info;

      /* Shared space area for Hard Fault exception information */
      volatile uintptr_t hard_fault_info;

      /* Shared space area for system information */
      volatile uintptr_t hw_sys_info;

      /* Shared space area for tcs information */
      volatile uintptr_t sys_tcs_info;

#if dg_configUSE_MAILBOX
      /* Shared space area for mailbox information */
      volatile uintptr_t mailbox_info;
#endif

#if dg_config_USE_RPMSG_LITE
      /* Shared space area for RPMsg_Lite base addressinformation */
      volatile uintptr_t rpmsg_lite_base_address_info;

      /*Shared space area for RPMsg_Lite pending interrupt information */
      volatile uintptr_t rpmsg_lite_isr_pending_info;
#endif /* dg_config_USE_RPMSG_LITE */
} snc_shared_space_info_t;

The variables and definitions of a produced snc_fw_embed.h file is presented below:

/** SNC firmware symbol addresses */
#define SNC__ETEXT_ADDRESS             ( 0x00003f00 )
#define SNC__DATA_START ADDRESS        ( 0x00003f00 )
#define SNC_CONFIG_ADDRESS             ( 0x0000694c )
#define SNC_SHARED_SPACE_START_ADDRESS ( 0x00030000 )
#define SNC_SHARED_SPACE_INFO_ADDRESS  ( 0x00030008 )

/** SNC firmware shared space size */
#define SNC_SHARED_SPACE_SIZE ( 132 )

/** SNC firmware code size ( 4-byte padded) */
#define SNC_FW_CODE_SIZE ( 16498 )

/** SNC shared space area in shared RAM */
volatile uint32_t snc_shared_space_area[SNC_SHARED_SPACE_SIZE / 4] __atribute__(( section ( " .snc_sha red_ram_area " )));

|** SNC firmware image(Header plus Code and Padding)*/
const uint32_t snc_fw_area[7 + (SNC_FW_CODE_SIZE / 4)] __attribute__((section(".snc_fw_area")))= {
      // Header, 28 bytes
      0x78434e53, 0x00004018, 0x20434e53, 0x302e3176, 0x0000302e, 0x30000000, 0x6lefdd40,
      // Code, 16408 bytes
      0x000l0000, 0x00000379, 0x000003f9, 0x00000415, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
      0x00000000, 0x00000000, 0x00000000, 0x00002185, 0x00000000, 0x00000000, 0x00002205, 0x00000431,
      0x00001055, 0x00000431, 0x00000431, 0x0000lf85, 0x0000lfa5, 0x0000lfbd, 0x0000lfd5, 0x0000l4dl,
      0x0000l4ed, 0x00001509, 0x00001525, 0x00001541, 0x00001139, 0x00000431, 0x0000155d, 0x00001071,
__

      0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
      0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
      0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
      0x000a0l0l, 0x04000401, 0x5c347018, 0x00071060, 0x04000102, 0x00000003,
};

The snc_fw_embed.h file is included in the os_app_retarget application and, therefore, the table snc_shared_space_area[] , which comprises of the shared memory space defined in os_snc_retarget application, is defined and linked in the SHARED memory area, since it is an snc_shared_ram_area variable. The size of this table, which is the same as the size of the shared memory space defined in the os_snc_retarget application, is defined by the SNC_SHARED_SPACE_SIZE macro.

Also, a pointer snc_shared_space_info_ptr is defined, which is initialized with the address of the communication interface structure snc_shared_space_info. This address is also included in the snc_fw_embed.h file, under the SNC_SHARED_SPACE_INFO_ADDRESS macro. The SysCPU code initializes SNC, downloads SNC code into RAM1 and RAM2 cells, starts execution of the SNC code, and waits until SNC code sets the snc_is_ready member of snc_shared_space_info structure to true. This means that the SNC code has been initialized. Then, the SysCPU code accesses the snc_shared_space_info structure and retrieves the addresses of the app_shared_info and app_shared_data structures. The interface between the applications in the two CPUs is now established and data exchange is ready to start. In the os_snc_retarget application’s map file, the user can find all the aforementioned structures which are defined in the .snc_shared section, as shown below:

.snc_shared     0x00030000       0x84
                0x00030000                __snc_shared_start__ = .
                0x00030000                . = ALIGN (0x4)
                0x00030000                __snc_shared_space_start__ = .
 *(retention_mem_shared_zi)
 retention_mem_shared_zi
                0x00030000        0x8 ./sdk/sys_man/sys_bsr.o
 retention_mem_shared_zi
                0x00030008       0x20 ./sdk/snc/api/src/snc.o
 retention_mem_shared_zi
                0x00030028       0x14 ./interface/snc_shared_space.o
                0x00030028                app_data
                0x00030030                app_info
                0x0003003c                __snc_shared_space_end__ = .
                0x0003003c                . = ALIGN (0x4)
                0x0003003c                __snc_exception_space_start__ = .
 *(nmi_info)
 nmi_info       0x0003003c       0x24 ./sdk/peripherals/src/hw_watchdog.o
                0x0003003c                nmi_event_data
 *(hard_fault_info)
 hard_fault_info
                0x00030060       0x24 ./sdk/peripherals/src/hw_hard_fault.o
                0x00030060                hardfault_event_data
                0x00030084                __snc_exception_space_end__ = .
                0x00030084                . = ALIGN (0x4)
                0x00030084                __snc_shared_end__ = .

All the retention_mem_shared_zi variables of file sdk/snc/api/src/snc.c are placed in address 0x00030008. In this file, the only variable of this type is snc_shared_space_info structure. So, the address of snc_shared_space_info structure is 0x00030008. The size of the SHARED area is 0x84 bytes. On the other side, the memory map file of the SHARED memory area of the os_app_retarget application is presented below:

.shared_section_retained_zi
            0x20110000 ex67¢
            0x20110000        _shared_section_retained__= .
*(.sne_shared_ram_area*)
.sn¢_shared_ram_area
            0x20110000 @x84   ./sdk/snc/api/src/snc.o
            0x20110000           snc_shared_space_area
            0x20110084           . = ALIGN (0x4)
*(retention_mem_shared_zi)
retention_mem_shared_zi
            0x20110084 0x28   ./sdk/sys_man/sys_bsr.o
retention_mem_shared_zi
            0x2011eeac 0x5de0 ./sdk/sys_man/sys_tcs_da147@x.o
            0x2011067c              __shared_section_retained_zi_end__ = .

The snc_shared_space_area[] table is allocated in the beginning of the os_app_retarget application’s SHARED memory area (i.e. 0x20110000) and it occupies all necessary space of 0x84 bytes.

7.2. Changing Linker Scripts

The user can modify the memory map of the os_app_retarget and os_snc_retarget applications, by applying corresponding changes to the linker scripts. In the following sections some basic changes that can be made are presented.

7.2.1. Add New Memory Area and Section in SysCPU Code

In this section, using the previous example, it is presented how to add some code and data in the os_app_retarget application, in a specific RAM cell, e.g. RAM7. This means that, first, the user must create a new memory area located in the RAM7 cell and then some of the existing areas must be re-defined too. The build configuration used for this example is the OQSPI XIP Flash build, and the header file mem_da1470x.ld.h needs to be changed as follows. Note that all new lines that are added have the comment “NEW” at the end. The lines that are removed or altered have the comment “OLD”.

/*
* Region for data (connected to AHB CPUS)
*/
RAMS (w)        : ORIGIN = RAMS_ORG, LENGTH = RAMS_LEN

RAM7 (rwx)      : ORIGIN = 0x200F0000, LENGTH = 128K            //NEW

A new memory area has been added, named “RAM7”, which includes the whole RAM7 cell. Since the RAM7 cell is included in the RAMS memory area, the user also needs to limit RAMS up to cell RAM6.

//#       define RAMS_LEN                  (1152K + SNC_MEM_LEN + CMAC_MEM_LEN) //OLD
#       define RAMS_LEN                    (896K + SNC_MEM_LEN + CMAC_MEM_LEN)  //NEW

Then, the user has to add a new section in the sections_da1470x.ld.h header file in order to steer the new code and data to the RAM7 memory area. For minimum changes, the new section is added at the end of the image, as shown below:

      .bss :
      {
         . = ALGIN(4);
         __bss_start__ = .;
#if DEVICE_FPGA
            *(EXCLUDE_FILE(*libg_nano.a:* *libnosys.a:* *libble_stack_d2798_00.a:*\
             *libad9361_radio.a:* *crtbegin.o) .bss*)

#else
            *(EXCLUDE_FILE(*libg_nana.a:* *libnosys.a:* *libble_stack_da1470x.a:*\
             *crtbegin.o) .bss*)
#endif
            *(COMMON)
            . = ALIGN(4);
            __bss_end__ = .;
      } > DATA

      .ram7_init : __AT__ (__etext + RETENTION_TEXT_SIZE + RETENTION_RAM_INIT_SIZE \
      + NON_RETENTION_RAM_INIT_SIZE + RAM9_DATA_FOR_M33_SIZE + RAM10_DATA_FOR_M33_SIZE)   //NEW
      {                                                              //NEW
            . = ALIGN(4);
            __ram7_init_start__ = .;
            *(text_ram7)
            . = ALIGN(4);
            *(data_ram7)
            . = ALIGN(4);
            __ram7_init_end__ = .;
      } > RAM7

The new section, called .ram7_init, includes all code and data of type text_ram7 and data_ram7, respectively. All contents are linked in the address of RAM7 cell and are loaded at the end of the image, right after the RAM10 data for SysCPU. To do that, some more changes in the file are required: ○ Define the new section’s size.

#  define RETENTION TEXT_SIZE             (__retention_text_end_ - __retention_text_start_)
#  define RETENTION_RAM INIT_SIZE         (_retention_ram_init_end__ - __retention_ram_init_start__)
#  define NON_RETENTION RAM_INIT_SIZE     (_non_retention_ram_init_end_ - __non_retention_ram_init_start__)
#  define RAM7_INIT_SIZE                  (__ram7_init_end__ - _ram7_init_start_)         //NEW

○ Update the copy.table, which contains the code and initialized data of RAM:

      .copy.table :
      {
            . = ALIGN(4);
            __copy_table_start__ = .;

#if CODE_IS_IN FLASH

            LONG (__etext)
            LONG (__retention_text_start__)
            LONG (RETENTION _TEXT_STZE)

            LONG (__etext + RETENTION _TEXT_SIZE)
            LONG (__retention_ram_init_start__)
            LONG (RETENTION_RAM_INIT_SIZE)

            LONG (__etext + RETENTION TEXT SIZE + RETENTION_RAM_INIT_SIZE)
            LONG (__non_retention_ram_init_start__)
            LONG (NON_RETENTION RAM_INIT_SIZE)

#endif /* CODE_IS_IN FLASH */

#if (__RAM9_SIZE_FOR MAIN PROC > 0)
            LONG (__etext + RETENTION _TEXT_SIZE + RETENTION RAM INIT_SIZE + NON_RETENTION RAM_INIT_SIZE)
            LONG (__ram9_area_for_m33_start__)
            LONG (RAM9_DATA_FOR_M33_SIZE)
#endif

#if (__RAM10_SIZE_FOR_MAIN PROC > 0)
            LONG (__etext + RETENTION TEXT SIZE + RETENTION _RAM_INIT_SIZE + NON_RETENTION RAM INIT_SIZE \
                  + RAM9_DATA_FOR_M33_SIZE)
            LONG (__ram10_area_for_m33_start__)
            LONG (RAM10_DATA_FOR_M33_SIZE)
#endif
            LONG (__etext + RETENTION _TEXT_SIZE + RETENTION_RAM_INIT_SIZE + NON_RETENTION RAM_INIT_SIZE \
                  + RAM9_DATA FOR_M33_SIZE + RAM1@_DATA_FOR_M83_SIZE)               //NEW
            LONG (__ram7_init_start__)                                        //NEW
            LONG (RAM7_INIT_SIZE)                                             //NEW

            __copy_table_end__ = .;

      } > TEXT __TEXT_LMA_

○ Update the Image size.

//#define IMAGE_SIZE \
//          (__etext + RETENTION_TEXT_SIZE + RETENTION_RAM_INIT_SIZE + NON_RETENTION RAM_INIT_SIZE \
//                + RAM9_DATA_FOR_M33_SIZE + RAMI@_DATA_FOR_M33_SIZE)                        //0LD
#tdefine IMAGE_SIZE \
         (__etext + RETENTION_TEXT_SIZE + RETENTION_RAM_INIT_SIZE + NON_RETENTION_RAM_INIT_SIZE \
               + RAM9_DATA_FOR_M33_SIZE + RAM10_DATA_FOR_M33_SIZE + RAM7_INIT_SIZE)             //NEW

Now, the user must add the data and code to the new memory area, using the corresponding macros. First, for the needs of the example, in the main.c file a new table is added (i.e. extra_data_table[]) of 4000 bytes and a new function (i.e. calc_extra_data()), which calculates and fills the content of the new table:

#define __RAM7_CODE                      __attribute__((section("text_ram7")))
#define __RAM7_DATA                      __attribute__((section("data_ram7")))

__RAM7_DATA uint32_t extra_data_table[1000];

__RAM7_CODE uint32_t calc_extra_data(app_shared_data_t *p)
{
     uint32_t index = p->buffer[1] % 1000;

     extra_data_table[index] = p->buffer[0] * 1000;
     return extra_data_table[index] / p->buffer[1];
}

After building the project, both the data and the code are placed to the RAM7 cell, as shown in the map file below:

.ram7_init     0x200f0000     0xfc8 load address 0x@001371c
               0x200f0000           . = ALIGN(4)
               0x200f0000           __ram7_init_start__ = .
*(text_ram7)
text_ram7      0x200f0000     0x28 ./main.o
               0x200f0000           calc_extra_data
               0x200f0028           . ALIGN (0x4)
*(data_ram7)
data_ram7      0x200f0028     0xfa0 ./main.o
               0x200f0028           extra_data_table
               0x200f0fc8           . = ALIGN (0x4)
               0x200f0fc8           __ram7_init_end__ = .
               0x200f0fc8           __FLASH_BUILD__ = .
               0x200f0fc9           __unused_ram_start__ = (. + 0x1)

7.2.2. Add Extra SNC Data in SHARED Memory Area

7.2.2.1. SNC-only Data

These data is of SNC usage only, thus, adding it in the shared structure for SNC-SysCPU data exchange is not necessary. In order to do that, first, a new data type is added in the section .snc_shared of the sections_da1470x-snc.ld.h header file, as presented below:

.snc_shared (NOLOAD) :
{
        __snc_shared_start__ = .;
        . = ALIGN(4);
        __snc_shared_space_start__ = .;
        KEEP(*(retention_mem_shared_zi))
        __snc_shared_space_end__ = .;
        . = ALIGN(4);
        __snc_exception_space_start__ = .;
        KEEP(*(nmi_info))
        KEEP(*(hard_fault_info))
        __snc_exception_space_end__ = .;
        . = ALIGN(4);
        __snc_shared_end__ = .;
} > SHARED

Then, new macros can be created, with which the user can define data of this type in the code, and thus, place them in the specific memory area:

#define __SNC_EXTRA_SHARED            __attribute__((section("snc_extra_shared_zi")))

e.g.

__SNC_EXTRA_SHARED uint32_t snc_extra_data_table[10];

The SNC map file then includes the new table snc_extra_data_table[] with size of 40 bytes, located in the .snc_shared section. This is presented below:

.snc_shared     0x00030000       0x84
                0x00030000                __snc_shared_start__ = .
                0x00030000                . = ALIGN (0x4)
                0x00030000                __snc_shared_space_start__ = .
 *(retention_mem_shared_zi)
 retention_mem_shared_zi
                0x00030000        0x8 ./sdk/sys_man/sys_bsr.o
 retention_mem_shared_zi
                0x00030008       0x20 ./sdk/snc/api/src/snc.o
 retention_mem_shared_zi
                0x00030028       0x14 ./interface/snc_shared_space.o
                0x00030028                app_data
                0x00030030                app_info
                0x0003003c                __snc_shared_space_end__ = .
                0x0003003c                . = ALIGN (0x4)
                0x0003003c                __snc_exception_space_start__ = .
 *(nmi_info)
 nmi_info       0x0003003c       0x24 ./sdk/peripherals/src/hw_watchdog.o
                0x0003003c                nmi_event_data
 *(hard_fault_info)
 hard_fault_info
                0x00030060       0x24 ./sdk/peripherals/src/hw_hard_fault.o
                0x00030060                hardfault_event_data
                0x00030084                __snc_exception_space_end__ = .
                0x00030084                . = ALIGN (0x4)
                0x00030084                __snc_shared_end__ = .

This change in the size of SNC shared area leads to a new snc_fw_embed.h file, that must be included in SysCPU code build configuration. SNC_SHARED_SPACE_SIZE is now defined 40 bytes larger, from 132 to 172 bytes:

/** SNC firmware shared space size */
#define SNC_SHARED_SPACE_SIZE           ( 172 )

7.2.2.2. SNC and SysCPU Shared Data

In case the user wants to add data in the SHARED memory area, accessed both by SysCPU and SNC, then the address of the extra data in the shared area has to be registered in the communication interface structure at runtime. So, first, the user needs to expand this structure’s type (i.e. snc_shared_space_info_t), and more specifically the member app_info, which is a table that holds the addresses of all registered shared data to be exchanged between SNC and SysCPU. In the custom_config_xx.h header files of both applications, the user must make the following change in order to increase the number of registered shared data structures to 3. .. code-block:: c

#define SNC_SHARED_SPACE_APP_COUNT ( 3 )

In the os_snc_retarget application, the user must define the type of the new structure to add, e.g.

typedef struct {
     volatile uint32_t buffer[10];
     volatile uint32_t size;
} app_shared_extra_data_t;

as well as a new unique handle id for it, e.g.:

typedef enum {
 APP_SHARED_SPACE_CTRL,      /**< Handle id for control data in shared space */
 APP_SHARED_SPACE_DATA,      /**< Handle id for application data in shared space */
 APP_SHARED_SPACE_EXTRA_DATA,    /**< Handle id for application extra data in
                                      shared space */
} APP_SHARED_SPACE_TYPE;

Then, in the main.c file, the user must define a structure of this type, which will be placed in the SHARED memory area, just like in Section 5.2.2.1, e.g.:

#define __SNC_EXTRA_SHARED  __attribute__((section("snc_extra_shared_zi"))) \
            __SNC_EXTRA_SHARED app_shared_extra_data_t snc_extra_data;

After that, the user must initialize this structure and register its address to the snc_shared_space_info structure:

/* Set application shared space extra data. */
memset(&snc_extra_data, 0, sizeof(app_shared_extra_data_t));
snc_extra_data.size = 10;
snc_set_shared_space_addr(&snc_extra_data,
            SNC_SHARED_SPACE_APP(APP_SHARED_SPACE_EXTRA_DATA));

After that, the user must build the os_snc_retarget application and copy the snc_fw_embed.h file to the os_app_retarget application. The new map file of the shared area of os_snc_retarget application is presented below:

.snc_shared     0x00030000       0x84
                0x00030000                __snc_shared_start__ = .
                0x00030000                . = ALIGN (0x4)
                0x00030000                __snc_shared_space_start__ = .
 *(retention_mem_shared_zi)
 retention_mem_shared_zi
                0x00030000        0x8 ./sdk/sys_man/sys_bsr.o
 retention_mem_shared_zi
                0x00030008       0x20 ./sdk/snc/api/src/snc.o
 retention_mem_shared_zi
                0x00030028       0x14 ./interface/snc_shared_space.o
                0x00030028                app_data
                0x00030030                app_info
                0x0003003c                __snc_shared_space_end__ = .
                0x0003003c                . = ALIGN (0x4)
                0x0003003c                __snc_exception_space_start__ = .
 *(nmi_info)
 nmi_info       0x0003003c       0x24 ./sdk/peripherals/src/hw_watchdog.o
                0x0003003c                nmi_event_data
 *(hard_fault_info)
 hard_fault_info
                0x00030060       0x24 ./sdk/peripherals/src/hw_hard_fault.o
                0x00030060                hardfault_event_data
                0x00030084                __snc_exception_space_end__ = .
                0x00030084                . = ALIGN (0x4)
                0x00030084                __snc_shared_end__ = .

In the os_app_retarget application, the user needs also to define a pointer of the new type of data:

__RETAINED app_shared_extra_data_t *app_shared_extra_data_ptr;

After SNC code is downloaded and initialization is finished, the user needs to initialize that pointer with the address of the new data that is registered in the app_info table of the snc_shared_space_info structure:

/* Get the address of application shared extra data. */
app_shared_extra_data_ptr =
   snc_get_shared_space_addr(SNC_SHARED_SPACE_APP(APP_SHARED_SPACE_EXTRA_DATA));

After that, the SysCPU code can access the extra data added in the shared memory by the SNC code.