Using Shared Memory With Low Power Radar
Table of Contents
Overview
The purpose of this document is to discuss implementation specific considerations when using shared memory on the low power device platform which includes the xWRL1432, xWRL6432, and xWRL6844.
For general shared memory usage and documentation, please find the links to the SDK below:
xWRLx432 - HWASS/FECSS memory initialization requirements
The 160 KB HWASS RAM and the 96 KB HWASS/FECSS shared RAM both require initialization to be accessed. This has the following implications:
- These areas cannot be used for .text, .data or .ro sections as these regions will not operate as expected before the initialization step and any content that could be loaded would be erased
- After initialization, this area can be used as recommended in the section below
- This limitation can be overcome if a secondary bootloader (SBL) is used to perform this initialization step
- An SBL example can be found in the following SDK directory:
<MMWAVE_SDK5_INSTALL_DIR>\MMWAVE_L_SDK_05_04_xx_xx\examples\drivers\boot\sbl - For now, this is left to the user to implement these steps in the SBL
- An SBL example can be found in the following SDK directory:
xWRLx432 - Avoiding Shared Memory Corruption
As discussed in the AWRL6432 Device Silicon Errata, IWRL6432 Device Silicon Errata, AWRL1432 Device Silicon Errata, and IWRL1432 Device Silicon Errata, when the shared memory is allocated to APPSS/M4F layer, a full word write access to location A followed by a sub-word write access - e.g., byte write - to location B corrupts data in location A due to ECC data transfer logic. As a result, this can limit the flexibility of the shared memory, but there are a few ways to avoid this corruption by doing the following:
1. When shared memory is allocated to the APPSS/M4F, use shared memory for read-only sections
Since this issue partially originates from write accesses, allocating read-only sections, such as program code (.text) and read-only data (.rodata), to the shared memory prevents write accesses from occurring. This can be done by editing the linker file of a project. For example, shown below is a snippet from the linker.cmd file for the mmWave demo where the .text and .rodata sections have been allocated to M4F_SHM_MEM:
SECTIONS
{
/* This has the M4F entry point and vector table, this MUST be at 0x0 */
.vectors:{} palign(8) > M4F_VECS
.bss: {} palign(8) > M4F_RAM12 /* This is where uninitialized globals go */
RUN_START(__BSS_START)
RUN_END(__BSS_END)
.text: {} align(8) >> M4F_SHM_MEM /* This is where code resides */
.data: {} align(8) >> M4F_RAM12 | M4F_RAM3 /* This is where initialized globals and static go */
.rodata: {} align(8) >> M4F_SHM_MEM /* This is where const's go */
.sysmem: {} palign(8) > M4F_RBL /* This is where the malloc heap goes */
.stack: {} palign(8) > M4F_RBL /* This is where the main() stack goes */
.l3: {} palign(8) > HWASS_SHM_MEM /* This is where L3 data goes */
}
MEMORY
{
M4F_VECS : ORIGIN = 0x00400000 , LENGTH = 0x00000200
M4F_RAM12 : ORIGIN = 0x00400200 , LENGTH = (0x00058000 - 0x200) /* 32KB of RAM2 is being used by RBL */
M4F_RBL : ORIGIN = 0x00458000 , LENGTH = 0x8000 /* 32KB of RAM2 is being used by RBL */
M4F_RAM3 : ORIGIN = 0x00460000 , LENGTH = 0x00020000
M4F_SHM_MEM : ORIGIN = 0x00480000 , LENGTH = 0x00040000 /* 256KB in APPSS PD */
HWASS_SHM_MEM : ORIGIN = 0x60000000, LENGTH = 0x00040000 /* 96KB in FECSS PD and 160KB in HWA PD */
}
2. If using a non functional safety device, disable the ECC for shared memories. Note: The ECC for shared memories should already be disabled by the ROM Bootloader (RBL) for non functional safety devices.
To identify whether a device is considered a non functional safety device, connect to the device in the CCS debugger and open up View -> Memory Browser. Navigate to address 0x5A02002C and read the three least significant nibbles which is the part number. If the part number, matches any IDs from the list, it is a non functional safety device, and the shared memory ECCs should be disabled automatically by the RBL.
- 0x011
- 0x012
- 0x0D6
- 0x026
📝 Automotive Restriction
For automotive devices such as the AWRL6432, it is not possible to disable the ECC as they are all functional safety devices.
To identify if an ECC is disabled, the provided function can be used to read ECC enable fields of the control register. It will return either a 0 (ECC disabled) or a 1 (ECC enabled).
#define ECC_VEC_RD_SVBUS_MASK 0x00008000
#define ECC_VEC_RD_SVBUS_DONE_MASK 0x01000000
#define ECC_VEC_APP_SHM_RAM0_ID 0x00000008
#define ECC_VEC_APP_SHM_RAM1_ID 0x00000009
#define ECC_VEC_FEC_SHM_RAM_ID 0x00000002
#define ECC_CON_REG_OFFSET 0x00140000
#define ECC_CON_ECC_EN_MASK 0x000000007
volatile uint32_t* appEccAggEccVector;
volatile uint32_t* appEccAggEccControl;
/* Returns enable status of an ECC given its ID.
status = 0 (ECC disabled) | status = 1 (ECC enabled) */
uint32_t ECC_enableStatus(uint32_t id)
{
appEccAggEccVector = (volatile uint32_t*)0x56F7EC08;
appEccAggEccControl = (volatile uint32_t*)0x56F7EC14;
uint32_t status = 0;
// Read ECC Control Register value
*appEccAggEccVector = (ECC_CON_REG_OFFSET | id); // Set register and endpoint to read
*appEccAggEccVector = (*appEccAggEccVector | ECC_VEC_RD_SVBUS_MASK); // Trigger read
while((*appEccAggEccVector & ECC_VEC_RD_SVBUS_DONE_MASK) != ECC_VEC_RD_SVBUS_DONE_MASK);
// Check enable status
if((*appEccAggEccControl & ECC_CON_ECC_EN_MASK) == ECC_CON_ECC_EN_MASK) status = 0x1;
return status;
}
If the ECC for a shared memory is not being disabled by the RBL, then the following function can also be used to disable all shared memory ECCs. The code utilizes the enable status function previously defined and a new function for writing to the control register.
🛑 DISCLAIMER
TheECC_disable_shared_memory()function must be called before any peripheral drivers are initialized through theDrivers_open()function. Otherwise, the main application code will crash.
#define ECC_VEC_RD_SVBUS_MASK 0x00008000
#define ECC_VEC_RD_SVBUS_DONE_MASK 0x01000000
#define ECC_VEC_APP_SHM_RAM0_ID 0x00000008
#define ECC_VEC_APP_SHM_RAM1_ID 0x00000009
#define ECC_VEC_FEC_SHM_RAM_ID 0x00000002
#define ECC_CON_ECC_EN_MASK 0x00000007
#define ECC_CON_REG_OFFSET 0x00140000
#define TOP_EFUSE_ALL_SHM_EN_MASK 0x00000218
volatile uint32_t* appEccAggEccVector;
volatile uint32_t* appEccAggEccControl;
volatile uint32_t* topEfuseRamEccCfg;
/* Returns enable status of an ECC given its ID.
status = 0 (ECC disabled) | status = 1 (ECC enabled) */
uint32_t ECC_enableStatus(uint32_t id)
{
appEccAggEccVector = (volatile uint32_t*)0x56F7EC08;
appEccAggEccControl = (volatile uint32_t*)0x56F7EC14;
uint32_t status = 0;
// Read ECC Control Register value
*appEccAggEccVector = (ECC_CON_REG_OFFSET | id); // Set register and endpoint to read
*appEccAggEccVector = (*appEccAggEccVector | ECC_VEC_RD_SVBUS_MASK); // Trigger read
while((*appEccAggEccVector & ECC_VEC_RD_SVBUS_DONE_MASK) != ECC_VEC_RD_SVBUS_DONE_MASK);
// Check enable status
if((*appEccAggEccControl & ECC_CON_ECC_EN_MASK) == ECC_CON_ECC_EN_MASK) status = 0x1;
return status;
}
/* Writes a given value to the ECC control register while masking out other bits */
void ECC_controlWrite(uint32_t id, uint32_t mask, uint32_t shift, uint32_t value)
{
appEccAggEccVector = (volatile uint32_t*)0x56F7EC08;
appEccAggEccControl = (volatile uint32_t*)0x56F7EC14;
// Write value to control register of given ECC
*appEccAggEccVector = id; // Select ECC
*appEccAggEccControl = ((*appEccAggEccControl & ~mask) | ((value << shift) & mask)); // Write value to ECC control register
return;
}
/* Disables all shared memory ECCs */
void ECC_disable_shared_memory()
{
appEccAggEccVector = (volatile uint32_t*)0x56F7EC08;
appEccAggEccControl = (volatile uint32_t*)0x56F7EC14;
topEfuseRamEccCfg = (volatile uint32_t*)0x5A0201AC;
// Disable APP SHARED MEM0 ECC
ECC_controlWrite(ECC_VEC_APP_SHM_RAM0_ID, ECC_CON_ECC_EN_MASK, 0, 0);
// Verify respective ECC is disabled. Throw assertion if not disabled.
if(ECC_enableStatus(ECC_VEC_APP_SHM_RAM0_ID)) DebugP_assert(0);
// Disable APP SHARED MEM1 ECC
ECC_controlWrite(ECC_VEC_APP_SHM_RAM1_ID, ECC_CON_ECC_EN_MASK, 0, 0);
// Verify respective ECC is disabled. Throw assertion if not disabled.
if(ECC_enableStatus(ECC_VEC_APP_SHM_RAM1_ID)) DebugP_assert(0);
// Disable FEC SHARED MEM ECC
ECC_controlWrite(ECC_VEC_FEC_SHM_RAM_ID, ECC_CON_ECC_EN_MASK, 0, 0);
// Verify respective ECC is disabled. Throw assertion if not disabled.
if(ECC_enableStatus(ECC_VEC_FEC_SHM_RAM_ID)) DebugP_assert(0);
// Disable RAM ECC configuration for deep sleep exit
*topEfuseRamEccCfg = ((*topEfuseRamEccCfg & ~TOP_EFUSE_ALL_SHM_EN_MASK) | 0);
return;
}
xWRLx432 - Using Low Power Deep Sleep with Shared Memory
When using low power deep sleep (LPDS) with shared memory, there are some extra precautions that must be taken. The resume procedure from LPDS will re-enable the shared memory, and these shared memories will not be available until the device has fully recovered from LPDS. This can cause issues if the code for your LPDS resume hook and other power functions are in the shared memory. The following recommendations should be applied after configuring low power and shared memory.
The power_LPDSresumehook and Power_sleep functions must not be in the shared memory section. To ensure this does not occur, you can follow the steps outlined below:
- Define a section in a non-shared memory region of the RAM. For example, the linker snippet below defines the
.ram3_textsection in theM4F_RAM3region which is a part of the Arm-M4F’s native RAM memory:
- Add the section attribute specifier with the previously defined non-shared memory section for the
power_LPDSresumehookandPower_sleepfunction prototypes. For example, thepower_LPDSresumehookandPower_sleepfunctions are allocated to theram3_textsection as shown below. Thepower_LPDSresumehookis typically found within the power_management.h file of most SDK projects, andPower_sleepcan be found under<MMWAVE_LSDK_INSTALL_DIR>/source/drivers/power.h.
📝 NOTE
Thepower_LPDSresumehookandPower_sleepmay already be allocated to non-shared memory depending on the linker configuration and project build. Double check the .map file generated during compilation to see if both functions are placed within a non-shared memory section. Additionally, the attribute specifier can be applied directly to the function definitions, but this will require recompilation forPower_sleepif utilizing the driver libraries, hence why its recommended to apply the attribute specifier to the prototype instead.
/**
* @b Description
* @n
* This function is user configurable hook after exiting LPDS
*
*/
__attribute__((section(".ram3_text"))) void power_LPDSresumehook()
{...}
/*!
* @brief Transition the device into a sleep state
*
* This function is called from the power policy when it has made a decision
* to put the device in a specific sleep state. This function returns to the
* caller (the policy function) once the device has awoken from sleep.
*
* @warning This function must be called with interrupts disabled, and
* should not be called directly by the application, or by any drivers.
* This function does not check declared constraints; the policy function
* must check constraints before calling this function to initiate sleep.
*
* @param[in] sleepState the sleep state
*
* @retval #Power_SOK on success, the device has slept and is awake again.
*
* @retval #Power_EFAIL if an error occurred during client notifications, or
* if a general failure occurred.
*
* @retval #Power_EINVALIDINPUT if the @p sleepState is invalid.
*
* @retval #Power_EBUSY if another transition is already in progress.
*/
__attribute__((section(".ram3_text"))) int_fast16_t Power_sleep(uint_fast16_t sleepState)
{...}
Need more help?
Please find additional resources relevant to this discussion below:
- AWRL6432 Product Page: https://www.ti.com/product/AWRL6432
- AWRL6432 Datasheet: https://www.ti.com/lit/gpn/awrl6432
- IWRL6432 Product Page: https://www.ti.com/product/IWRL6432
- IWRL6432 Datasheet: https://www.ti.com/lit/gpn/iwrl6432
- xWRLx432 Technical Reference Manual: https://www.ti.com/lit/pdf/swru599