Memory Hierarchy for RTL87x3D
This document introduces the memory system of RTL87x3D generally. RTL87x3D's memory system consists of ROM, RAM, SPIC Flash, and eFuse, all of which has a flexible configuration mechanism. The flexible configurability and extensibility make RTL87x3D support a wide range of applications with different memory usage.
Memory Type |
Start Addr |
End Addr |
Size (KB) |
Block Size and Count |
|---|---|---|---|---|
ROM |
0x00000000 |
0x0011FFFF |
1152 |
|
DATA RAM |
0x00200000 |
0x0021FFFF |
128 |
4 x 32KB |
BUFFER RAM |
0x00280000 |
0x0028FFFF |
64 |
4 x 16KB |
COMMON0 RAM |
0x00300000 |
COMMON0 End Address |
COMMON0 Size |
N* x 32KB |
COMMON1 RAM |
COMMON1 Start Address |
COMMON1 End Address |
256KB - N* x 32KB |
N* x 32KB |
COMMON2 RAM (Shared from DSP as General RAM) |
0x00500000 |
COMMON2 End Address |
<=512 |
<= (16 x 32KB) |
0x02000000 |
0x03FFFFFF |
|||
Noncache Mapping Address to SPIC0 |
0x04000000 |
0x05FFFFFF |
||
SPIC1 QPI PSRAM; QPI Flash |
0x06000000 |
0x07FFFFFF |
||
SPIC2 QPI PSRAM; QPI Flash |
0x08000000 |
0x09FFFFFF |
||
SPIC3 QPI PSRAM; QPI Flash |
0x10000000 |
0x1FFFFFFF |
||
SPIC4 QPI PSRAM; QPI Flash |
0xC0000000 |
0xCFFFFFFF |
||
eFuse |
||||
PSRAM LPC CTRL OPI PSRAM |
0xA6000000 |
0xA7FFFFFF |
Note
COMMON0 and COMMON1 Size are configurable in
mem_config.hfor the application project and the total size is 256KB (COMMON0 and COMMON1 RAM are 32K bytes aligned). Recommend Settings: Text section located in COMMON0 RAM and data section located in COMMON1 RAM.The address and size of COMMON2 RAM depend on configuration, which should match with DSP images.
DSP RAM is not shared as general RAM by default.
eFuse doesn't support access directly by address.
ROM
Many fundamental functions are built in ROM, such as Bootloader, RTOS, Bluetooth Stack, and IO Drivers. The ROM code is located at 0x00000000 - 0x00120000 RTK offers abundant API for users to access most ROM functions, which can improve users' development efficiency and reduce code size.
RAM
RTL87x3D has three types of RAM: DATA, BUFFER, and COMMON (including COMMON0, COMMON1, and COMMON2). All types of memory could be used to store data and execute code. In the current SDK, Data RAM and Buffer RAM are provided for the vendor, and common RAM is provided for the user. COMMON1 RAM is used to store data while COMMON0 RAM is used to run RAM code.
The following picture shows the default RAM configuration. Some parts are already used by RTK internal functions marked as reserved used. The remaining parts should be allocated for global variables, RAM code, and heap area. Users can configure these parts with the header file mem_config.h:
The COMMON0 is recommended to be configured as
APP RAM TEXT.The COMMON1 is recommended to be configured as
APP GLOBALandAPP HEAP.

RAM Configuration
There are several physical heap areas, but all of them are connected logically. Users can use malloc() to request RAM from the heap area dynamically. Total heap RAM size is 218KB by default, and some of it has already been used, which will be slightly different with different configurations generated by the MCUConfig Tool. As for the heap for the application, the RTK framework will cost about 37KB, which size will change when different features are supported.
Heap Size
The size of APP RAM TEXT is 15KB (varies according to diffe rent applications) by default, which is used to run RAM code. The size of the APP GLOBAL area is 12KB (varies according to different applications) by default, which is used to store global variables. And RTK libs will cost about 4.3KB global size. Users can configure them by modifying two macros in mem_config.h and other macros cannot be modified in mem_config.h.
#define APP_RAM_TEXT_SIZE (15*1024)
#define APP_GLOBAL_SIZE (12*1024)
APP Global Size
Users can use API malloc() to allocate RAM from the heap. If the heap is insufficient, a hardfault is generated. In this case, you can see from the following log. It is necessary to confirm whether too many features are opened, or there is a problem in the code writing, and there is a memory leak, resulting in the heap consumption.
0007138 03-02 09:29:53.651 154 0319630.477 [PATCH] !!!ALLOC FAIL!RAM type:5,wanted sz:2056,remain sz:4176
FAQs
-
How to get the current remaining heap size?
The
mem_peek()API inos_mem.hcan return the current remaining heap size. -
How to get heap water level and task stack water level?
The
monitor_memory_and_timer()API inos_ext.hwill set up a timer to periodically print the heap water level, the current heap remaining size, the number of remaining timers, and the water levels of each task stack. -
How to get the heap size used by a piece of code?
Refer to the following code.
size_t free_heap_start = mem_peek(); test_api(); size_t free_heap_end = mem_peek(); size_t used_heap = free_heap_start - free_heap_end;
-
How to get the size currently used by
APP RAM TEXTandAPP GLOBAL?The
app.mapfile shows the size currently used byAPP_RAM_TEXTandAPP_RAM_GLOBAL.Execution Region RAM_TEXT (Exec base: 0x00208800, Load base: 0x021453cc, Size: 0x000011fc, Max: 0x00001400, ABSOLUTE) Execution Region RAM_GLOBAL (Exec base: 0x002c0000, Load base: 0x02144d0c, Size: 0x00002918, Max: 0x00003800, ABSOLUTE)
Flash
The RTL87x3D supports external SPI flash memory. Onboard SPI flash is controlled by an SPIC that maps memory accordingly. The flash size mapping varies with different SPICs: up to 32MB for SPIC0 and SPIC1, 8MB for SPIC2, and 256MB each for SPIC3 and SPIC4. The RTL87x3D features a flash cache for SPIC0, which enhances data read and code execution efficiency from SPI flash. Additionally, it provides a mapping address range from 0x4000000 to 0x5FFFFFF, enabling the CPU to access the SPIC0 flash directly. For further details, please refer to Flash.
eFuse
eFuse is a block of one-time programming memory that is used to store important and fixed information, such as UUID, security key, and many other configurations. Only certain sections can be modified by the user. A single bit of eFuse cannot be changed from 0 to 1, and there is no erase operation for eFuse, so be careful when updating eFuse.
PSRAM
The RTL87x3D chipset supports external memory via SPI PSRAM, which is managed by an SPIC. The onboard SPI PSRAM is controlled by the SPIC, which maps memory to it. The maximum mapping size varies based on the different SPIC mapping memory ranges: up to 32MB for SPIC0 and SPIC1, 8MB for SPIC2, and 256MB for both SPIC3 and SPIC4. OPI PSRAMs and QPI PSRAM are supported. Specifically, the RTL87x3D supports the APS1604M PSRAM model through SPIC1, SPIC2, and SPIC3.
As for OPI PSRAM, RTL87x3D supports external Winbond hyper bus interface PSRAM (HyperRAM) by installing a PSRAM Low Pin Count Controller (PSRAM LPC CTRL). The Winbond OPI PSRAM onboard is controlled by the PSRAM LPC CTRL which has a mapping memory to it. The maximum OPI PSRAM size considering PSRAM LPC CTRL mapping memory range is 32M bytes. RTL87x3D supports two OPI PSRAMs: W955D8MBYA whose size is 4M bytes and W956D8MBKX whose size is 8M bytes. Further, Realtek offers APIs to initialize both OPI and QPI PSRAM where PSRAM can be read and written like SRAM after being initialized.
PSRAM Type |
Chip Models |
Support SPIC |
Selection Basis |
|---|---|---|---|
QPI PSRAM |
APS6408L, W955D8MBYA |
SPIC1 |
Low power consumption and simple design. |
OPI PSRAM |
APS6404L |
SPIC2, SPIC3, SPIC4 |
High transmission rate requirements. |
How to Init PSRAM?
Before using PSRAM, you must initialize it. For example, to initialize a Winbond OPI-interface PSRAM, use the following code:
if (fmc_psram_winbond_opi_init(FMC_SPIC_ID_1))
{
DBG_DIRECT("WB OPI psram init success!");
}
else
{
DBG_DIRECT("WB OPI psram init fail!");
}
Note
Different hardware platforms may support different types or brands of PSRAM. Please refer to the relevant hardware documentation to ensure PSRAM compatibility and correct initialization procedures.
fmc_psram_winbond_opi_initis used to initialize the Winbond OPI PSRAM on the SPIC1 controller.
How to Use PSRAM?
This guide provides examples of how to place code and global data in PSRAM using Keil and GCC toolchains.
Placing Code in PSRAM
-
Add a PSRAM text section.
-
For Keil (
app.sct):PSRAM_TEXT PSRAM_CODE_START_ADDR PSRAM_CODE_SIZE { * (.psram.text) }
-
For GCC (
app.ld):MEMORY { // other sections PSRAM_TEXT(rw) : ORIGIN = 0x4000000, LENGTH = 0x400000 // user defined // other sections } PSRAM_TEXT_SECTION : { __psram_text_start = .; *(.psram.text) __psram_text_end = .; } > PSRAM_TEXT AT > FLASH __psram_text_length__ = __psram_text_end - __psram_text_start; __psram_text_load_addr__ = LOADADDR(PSRAM_TEXT_SECTION); __psram_text_dst_addr__ = ADDR(PSRAM_TEXT_SECTION);
-
-
Define the section macro in
mem_config.h:#define PSRAM_TEXT_SECTION __attribute__((section(".psram.text"))) -
Copy code from flash to PSRAM:
void prepare_psram_text_to_ram(void) { #ifdef __CC_ARM extern unsigned int Image$$PSRAM_TEXT$$Base; extern unsigned int Load$$PSRAM_TEXT$$Base; extern unsigned int Image$$PSRAM_TEXT$$Length; void *image_base = (void *)&Image$$PSRAM_TEXT$$Base; void *load_base = (void *)&Load$$PSRAM_TEXT$$Base; unsigned int size = (unsigned int)&Image$$PSRAM_TEXT$$Length; memcpy(image_base, load_base, size); #elif defined(__GNUC__) extern char __psram_text_start[]; extern char __psram_text_end[]; extern char __psram_text_load_addr__[]; uint32_t len = __psram_text_end - __psram_text_start; memcpy(__psram_text_start, __psram_text_load_addr__, len); #endif }
-
Mark functions for placement in PSRAM using the macro:
PSRAM_TEXT_SECTION void psram_test_code(void) { // function implementation }
Placing Global Data in PSRAM
-
Add a PSRAM data section.
-
For Keil (
app.sct):PSRAM_DATA PSRAM_DATA_START_ADDR PSRAM_DATA_SIZE { * (.psram.data) }
-
For GCC (
app.ld):MEMORY { // other sections PSRAM_DATA(rw) : ORIGIN = 0x4000000, LENGTH = 0x400000 // user defined // other sections } PSRAM_DATA_SECTION : { __psram_data_start = .; *(.psram.data) __psram_data_end = .; } > PSRAM_DATA AT > FLASH __psram_data_length__ = __psram_data_end - __psram_data_start; __psram_data_load_addr__ = LOADADDR(PSRAM_DATA_SECTION); __psram_data_dst_addr__ = ADDR(PSRAM_DATA_SECTION);
-
-
Define the section macro in
mem_config.h:#define PSRAM_DATA_SECTION __attribute__((section(".psram.data"))) -
Copy data from flash to PSRAM before use:
void prepare_psram_data_to_ram(void) { #ifdef __CC_ARM extern unsigned int Load$$PSRAM_DATA$$RW$$Base; extern unsigned int Image$$PSRAM_DATA$$RW$$Base; extern unsigned int Image$$PSRAM_DATA$$RW$$Length; extern unsigned int Load$$PSRAM_DATA$$ZI$$Base; extern unsigned int Image$$PSRAM_DATA$$ZI$$Base; extern unsigned int Image$$PSRAM_DATA$$ZI$$Length; uint32_t load_addr = (uint32_t)&Load$$PSRAM_DATA$$RW$$Base; uint32_t dest_addr = (uint32_t)&Image$$PSRAM_DATA$$RW$$Base; uint32_t len = (uint32_t)&Image$$PSRAM_DATA$$RW$$Length; memcpy((uint8_t *)dest_addr, (uint8_t *)load_addr, len); dest_addr = (uint32_t)&Image$$PSRAM_DATA$$ZI$$Base; len = (uint32_t)&Image$$PSRAM_DATA$$ZI$$Length; memset((uint8_t *)dest_addr, 0, len); #elif defined(__GNUC__) extern char __psram_data_start[]; extern char __psram_data_end[]; extern char __psram_data_load_addr__[]; uint32_t len = __psram_data_end - __psram_data_start; memcpy(__psram_data_start, __psram_data_load_addr__, len); #endif }
-
Mark global variables for placement in PSRAM using the macro:
PSRAM_RAM_DATA_SECTION uint32_t psram_global = 0
See Also
Please refer to the relevant API Reference: