ARM Cortex Memory Map : This article provides an in-depth exploration of the System Address Map of the ARM Cortex-M4 processor, covering the entire 4 GB memory space from 0x00000000
to 0xFFFFFFFF
. Through a clear breakdown of each memory region—including Code, SRAM, Peripheral, External RAM, External Devices, Private Peripheral Bus, and Vendor-Specific Memory—readers gain a thorough understanding of how the Cortex-M4 organizes memory for efficient execution, data handling, peripheral control, and debugging.
The article also explains the purpose, size, and use cases for each region, making it ideal for embedded systems developers, students, and engineers working with ARM Cortex-M microcontrollers. Whether you are writing a bootloader, configuring peripherals, or optimizing memory layout, this guide will help you navigate the memory system effectively.
ARM Cortex Memory Map
1. Code Region
- Address Range:
0x00000000 – 0x1FFFFFFF
- Size: 512 MB (0.5 GB)
- Purpose:
- Executable code (Flash memory)
- Vector table typically resides here
- Alias regions may mirror flash memory for bootloader support
2. SRAM Region
- Address Range:
0x20000000 – 0x3FFFFFFF
- Size: 512 MB (0.5 GB)
- Purpose:
- On-chip SRAM (internal RAM)
- Stack, heap, global/static variables
- DMA may access this region for fast data transfer
3. Peripheral Region
- Address Range:
0x40000000 – 0x5FFFFFFF
- Size: 512 MB (0.5 GB)
- Purpose:
- Memory-mapped I/O (MMIO)
- Peripheral registers like UART, SPI, GPIO, ADC, timers, etc.
- Read/write access by CPU and DMA
4. External RAM
- Address Range:
0x60000000 – 0x9FFFFFFF
- Size: 1 GB
- Purpose:
- External RAM (connected via external memory interface)
- Useful for large applications like GUIs, file buffers, image processing
5. External Device
- Address Range:
0xA0000000 – 0xDFFFFFFF
- Size: 1 GB
- Purpose:
- External peripherals (e.g., FPGA, display controller, sensor interface)
- Memory-mapped communication with external hardware
6. Private Peripheral Bus (PPB)
- Address Range:
0xE0000000 – 0xE00FFFFF
- Size: 1 MB
- Purpose:
- System control registers for Cortex-M core
- Includes:
- NVIC
- SysTick
- SCB
- MPU
- Debug registers (ITM, DWT, FPB, etc.)
Refer to the earlier detailed post for this section 👉 System Control Space Explained
7. Vendor-specific Memory
- Address Range:
0xE0100000 – 0xFFFFFFFF
- Size: 511 MB
- Purpose:
- Chip-specific use (reserved for vendor extensions)
- May include boot ROM, custom peripherals, configuration registers, security zones
Cortex-M4 Memory Map Summary Table
Region | Address Range | Size | Purpose |
---|---|---|---|
Code | 0x00000000 – 0x1FFFFFFF | 0.5 GB | Flash, boot code |
SRAM | 0x20000000 – 0x3FFFFFFF | 0.5 GB | Internal SRAM |
Peripheral | 0x40000000 – 0x5FFFFFFF | 0.5 GB | On-chip peripherals |
External RAM | 0x60000000 – 0x9FFFFFFF | 1.0 GB | External RAM |
External Device | 0xA0000000 – 0xDFFFFFFF | 1.0 GB | External devices (e.g. FPGA) |
Private Peripherals | 0xE0000000 – 0xE00FFFFF | 1.0 MB | System control and debug |
Vendor-specific | 0xE0100000 – 0xFFFFFFFF | 511 MB | Chip-specific custom usage |
Real-World Application Example:
Let’s say you’re writing firmware for a Cortex-M4 microcontroller:
- Place interrupt vector table at
0x00000000
. - Stack pointer and data sections start at
0x20000000
(SRAM). - Configure UART at
0x40011000
. - Use NVIC from
0xE000E100
to enable interrupts. - Debug using ITM at
0xE0001000
.
Conclusion
The ARM Cortex-M4 memory map is fixed and standardized, which makes firmware development and porting between vendors easier. Each memory region has a specific role, and understanding this layout is essential for:
- Embedded firmware
- RTOS integration
- Memory protection
- Debugging and performance tuning
1. Code Region (0x00000000
)
This is typically where your Flash and reset vector table are located. You don’t manually write here in user code, but the compiler/linker places your startup and main code here.
int main(void)
{
// Your application starts here after reset
while (1) {
// main loop
}
}
2. SRAM Region (0x20000000
)
This is where global/static variables and stack/heap are allocated.
Example: Define variables in SRAM
uint32_t sensor_data[100]; // Placed in SRAM
char message[] = "Hello from SRAM!";
3. Peripheral Region (0x40000000
)
You can access memory-mapped I/O registers here.
Example: Toggle GPIO pin using direct memory access (STM32 GPIO)
#define RCC_AHB1ENR (*(volatile uint32_t*)0x40023830)
#define GPIOD_MODER (*(volatile uint32_t*)0x40020C00)
#define GPIOD_ODR (*(volatile uint32_t*)0x40020C14)
void gpio_init(void)
{
RCC_AHB1ENR |= (1 << 3); // Enable clock for GPIOD
GPIOD_MODER |= (1 << (2 * 12)); // Set PD12 as output
}
void gpio_toggle(void)
{
GPIOD_ODR ^= (1 << 12); // Toggle PD12
}
4. External RAM Region (0x60000000
)
Some boards (e.g. with FSMC or FMC) map external SDRAM to this region.
Example: Access external RAM (assumes SDRAM is initialized)
#define EXT_SDRAM_BASE 0x60000000
volatile uint32_t* ext_buffer = (uint32_t*)EXT_SDRAM_BASE;
void fill_ext_ram(void)
{
for (int i = 0; i < 1024; i++) {
ext_buffer[i] = i;
}
}
5. External Device Region (0xA0000000
)
Used for memory-mapped external peripherals (like LCD controllers or FPGAs). Example access:
#define FPGA_REG (*(volatile uint32_t*)0xA0000000)
FPGA_REG = 0xABCD1234; // Write data to external device
6. Private Peripheral Bus (PPB: 0xE0000000
)
Used for NVIC, SysTick, SCB, etc.
Example: Use SysTick Timer (from 0xE000E010
)
#define SYST_CSR (*(volatile uint32_t*)0xE000E010)
#define SYST_RVR (*(volatile uint32_t*)0xE000E014)
#define SYST_CVR (*(volatile uint32_t*)0xE000E018)
void systick_init(void)
{
SYST_RVR = 16000000 - 1; // 1 second @ 16 MHz
SYST_CVR = 0;
SYST_CSR = 0x07; // Enable SysTick, use processor clock, enable interrupt
}
7. Vendor-Specific Memory (0xE0100000
and above)
This region is MCU-dependent, so access depends on what the chip vendor puts there. Sometimes it’s used for factory configuration registers, security fuses, etc.
Example: Not available without vendor documentation.
Important Notes:
- Always refer to the vendor’s datasheet or reference manual to confirm the exact addresses and availability of regions.
- Use
volatile
to prevent compiler optimization from removing memory-mapped I/O operations. - Peripheral and system register addresses can differ between microcontrollers, so adapt the base addresses accordingly.
📦 CODE Region Overview
- Address Range:
0x00000000
to0x1FFFFFFF
- Size: 512 MB
✅ Key Points Explained
- Purpose of CODE Region:
- This region is reserved for the MCU vendor to connect CODE memory.
- It’s where the processor expects executable instructions (i.e., firmware, application code).
- Types of Memory Connected Here:
- Embedded Flash
- ROM (Read-Only Memory)
- OTP (One-Time Programmable memory)
- EEPROM (Electrically Erasable Programmable Read-Only Memory)
- Vector Table Location:
- At reset, the processor automatically fetches the vector table (interrupt vectors, reset handler, etc.) from this region.
- The first address (
0x00000000
) is usually where the vector table is located, making it critical for system startup.
⚙️ Use in Embedded Systems
- Developers and toolchains place startup code, interrupt handlers, and application logic in this region.
- This mapping helps the processor know where to begin execution after power-on or reset.
Part 1: How Linker Scripts Place Code into the CODE Region
🔧 What is a Linker Script?
A linker script (e.g., linker.ld
or .ld
file) tells the linker where to place different sections of your compiled code (like .text
, .data
, .bss
, etc.) in memory.
🧠 Typical Layout for CODE Region (Simplified)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.text :
{
KEEP(*(.isr_vector)) /* Vector table */
*(.text*) /* Program code */
*(.rodata*) /* Read-only data */
} > FLASH
.data :
{
*(.data*)
} > RAM AT > FLASH /* Initialized data */
.bss :
{
*(.bss*)
} > RAM
}
🔍 Explanation:
FLASH
corresponds to the CODE region (for example, at0x08000000
in STM32)..text
section contains the actual instructions/code, placed in FLASH..isr_vector
holds the vector table, placed at the beginning of FLASH, usually at0x08000000
, which is often aliased to0x00000000
after reset using memory remapping.
Part 2: Structure of the Vector Table
📚 Vector Table Format (for ARM Cortex-M)
Located at the start of the CODE region (e.g., 0x00000000
):
Offset | Content | Description |
---|---|---|
0x00 | Initial Stack Pointer | Loaded into SP on reset |
0x04 | Reset Handler | Entry point of the program |
0x08 | NMI Handler | Non-Maskable Interrupt |
0x0C | Hard Fault Handler | On serious error |
… | Other exception handlers | Interrupt handlers |
💡 Written in C (startup code):
extern uint32_t _estack; // Stack end
void Reset_Handler(void);
void Default_Handler(void);
__attribute__ ((section(".isr_vector")))
uint32_t *vector_table[] = {
(uint32_t *) &_estack, // Initial Stack Pointer
(uint32_t *) Reset_Handler, // Reset Handler
(uint32_t *) Default_Handler, // NMI
(uint32_t *) Default_Handler, // Hard Fault
// ... other IRQ handlers
};
Summary:
- The CODE region is where executable code lives.
- The linker script ensures that startup code, vector table, and app logic are placed properly in FLASH.
- The processor fetches the vector table from the start of the CODE region (
0x00000000
) immediately after reset.
What is the SRAM Region?
- SRAM (Static RAM) is read/write memory used for variables, stacks, heaps, and sometimes even executable code.
- In ARM Cortex-M architectures, it’s part of the processor’s memory map.
Address Map Breakdown (Based on ARM Cortex-M Architecture)
Address Range: 0x2000_0000
to 0x3FFF_FFFF
This is a 512 MB range allocated to SRAM and bit-band operations.
Internal Structure:
- Bit-Band Region
- Address Range:
0x2000_0000
to0x200F_FFFF
- Size: 1 MB
- ⚡ Used to access individual bits as if they were memory-mapped bytes.
- Mainly used in real-time systems for atomic bit manipulation (e.g., toggling an LED or a flag).
- Address Range:
- Bit-Band Alias
- Address Range:
0x2200_0000
to0x23FF_FFFF
- Size: 32 MB
- Each bit in the Bit-Band Region is mapped to a 32-bit word in this region.
- Writing
1
or0
here sets or clears individual bits in the Bit-Band Region.
- Address Range:
- General SRAM
- Above the alias region up to
0x3FFF_FFFF
. - Typically used for data storage, stack, heap, etc.
- You can also execute code from here if your system allows (e.g., for bootloaders or RAM-based firmware).
- Above the alias region up to
📌 Key Points from the Right Panel of the Image:
- ✅ Next 512MB after the CODE region
→ SRAM comes after the CODE region in memory layout (CODE region:0x0000_0000
–0x1FFF_FFFF
). - ✅ Primarily for connecting on-chip SRAM
→ Microcontrollers map their internal RAM into this region. - ✅ First 1MB = Bit-Band Region
→ Special feature for atomic bit-level operations. - ✅ Executable Region
→ Some MCUs allow code execution from SRAM (e.g., during firmware update or bootloaders).
🔍 Example Use Case for Bit-Banding
Instead of:
GPIO_PORT |= (1 << 5);
Use Bit-Banding:
#define BITBAND_SRAM_REF 0x20000000
#define BITBAND_ALIAS_REF 0x22000000
#define BITBAND(addr, bit) ((BITBAND_ALIAS_REF + ((addr - BITBAND_SRAM_REF) * 32) + (bit * 4)))
*(volatile uint32_t*)BITBAND(0x20000000, 5) = 1; // Set bit 5 at address 0x20000000
🧭 Memory Map Overview: Peripherals Region
📌 Address Range: 0x4000_0000
to 0x5FFF_FFFF
- Total Size: 512 MB
- Used for: On-chip peripheral registers (like GPIO, UART, SPI, I2C, timers, etc.)
📂 Sub-regions:
1. 🔶 Bit-Band Region
- Range:
0x4000_0000
to0x400F_FFFF
(1 MB) - Purpose: Enables bit-level access to peripheral registers.
- Example: You can set/clear an individual bit (e.g., a GPIO pin) using a memory-mapped operation.
2. 🔶 Bit-Band Alias
- Range:
0x4200_0000
to0x43FF_FFFF
(32 MB) - Each bit in the 1MB Bit-Band Region maps to a 4-byte word here.
- Writing
1
or0
to these addresses will set or clear specific bits in the Bit-Band Region.
3. 🟨 Remaining Peripherals
- Address range: From
0x4010_0000
onwards to0x5FFF_FFFF
- These addresses are used for memory-mapped I/O access to various hardware peripheral registers.
⚠️ Key Notes:
- 🧠 Bit-banding is optional and depends on the MCU implementation.
- ❌ This is an XN (eXecute Never) region:
- You cannot execute code from here.
- Any attempt to run code from this memory region triggers a fault exception (to prevent code from executing in peripheral space).
- ✅ It’s common to read/write to peripheral registers here (e.g., writing to GPIO).
🧪 Example Use Case
Suppose you want to set bit 3 of a register at address 0x4000_0000
(within Bit-Band Region):
#define BITBAND_PERIPH_BASE 0x42000000
#define PERIPH_BASE 0x40000000
#define BITBAND_ADDR(addr, bit) \
(BITBAND_PERIPH_BASE + ((addr - PERIPH_BASE) * 32) + (bit * 4))
// Set bit 3
*(volatile uint32_t*)BITBAND_ADDR(0x40000000, 3) = 1;
// Clear bit 3
*(volatile uint32_t*)BITBAND_ADDR(0x40000000, 3) = 0;
✅ Summary
Region | Address Range | Size | Purpose |
---|---|---|---|
Bit-Band Region | 0x4000_0000 - 0x400F_FFFF | 1 MB | Bit-level access to peripheral registers |
Bit-Band Alias | 0x4200_0000 - 0x43FF_FFFF | 32 MB | Maps each bit to a word address |
Peripherals | 0x4000_0000 - 0x5FFF_FFFF | 512 MB | On-chip peripherals (e.g., GPIO, UART) |
eXecute Never (XN) | ✅ Entire Peripheral Region | — | Code execution not allowed |
🧠 Memory Region: External RAM
📌 Address Range: 0x6000_0000
to 0x9FFF_FFFF
- Size: 1 GB
- Label:
External RAM
🧾 Key Characteristics:
- 🏗️ Intended for:
- On-chip or off-chip memory
- Typically used for external SDRAM, SRAM, or memory-mapped devices connected via external memory interfaces (like FSMC or FMC).
- 🧬 Code Execution:
✅ You can execute code from this region (unlike peripheral regions which are XN – eXecute Never).
Useful for:- Bootloaders in external memory
- Running large programs that don’t fit in internal flash
💡 Example Use Case:
💾 External SDRAM:
Many embedded boards (e.g., STM32F7/H7, NXP i.MX) support external SDRAM connections via Flexible Memory Controllers.
You might:
- Map external SDRAM to
0x60000000
- Link heap and stack to reside here for large data usage
- Optionally execute code directly from it if it’s fast enough
MEMORY
{
RAM (xrw) : ORIGIN = 0x60000000, LENGTH = 8M
}
SECTIONS
{
.data : { *(.data) } > RAM
.bss : { *(.bss) } > RAM
}
✅ Summary Table:
Feature | Description |
---|---|
Address Range | 0x6000_0000 – 0x9FFF_FFFF |
Size | 1 GB |
Execution | ✅ Allowed |
Intended Use | External RAM (e.g., SDRAM) |
Boot Possible | ✅ Yes, if memory is initialized |
Memory Region: External Device
📌 Address Range:
From: 0xA000_0000
To: 0xDFFF_FFFF
Size: 1 GB
📌 Key Characteristics:
- 💻 Purpose:
- Used to interface with external peripherals/devices (e.g., Ethernet controllers, external flash, FPGA).
- Can also be used for shared memory between processors or DMA-capable peripherals.
- ❌ eXecute Never (XN):
- This region is XN, meaning code execution is not allowed here.
- You can read/write data but cannot run instructions from this memory.
🧾 Use Case Examples:
Use Case | Description |
---|---|
🧠 Memory-mapped peripherals | Interface to external devices like an LCD controller or FPGA |
📶 Shared Memory | For inter-processor communication (e.g., with a co-processor) |
💾 External Flash | Accessing external NOR/NAND flash as raw storage |
⚠️ Important Notes:
- If you try to execute code from this region, the CPU will trigger a fault due to the XN attribute.
- Ideal for control registers, buffers, and data exchange, but not for program execution.
✅ Summary Table:
Feature | Description |
---|---|
Address Range | 0xA000_0000 – 0xDFFF_FFFF |
Size | 1 GB |
Execution | ❌ Not allowed (XN) |
Intended Use | External devices, shared memory, buffers |
Access Type | Read/Write only |
Memory Region: Private Peripheral Bus (PPB)
Address Range:
From: 0xE0000000
To: 0xE00FFFFF
Size: 1 MB (but only usable part is within this range — ignore the left-side “0xA0000000” to “0xDFFFFFFF” in this specific image; that seems mistakenly reused)
Key Characteristics:
- 💡 Purpose:
- This region holds core system control registers that are private to the Cortex-M processor.
- It contains the following:
- NVIC (Nested Vectored Interrupt Controller) – for interrupt handling.
- System Timer (SysTick) – for generating system ticks.
- System Control Block (SCB) – for controlling system configuration (like fault handlers, CPU ID, etc.).
- ❌ eXecute Never (XN):
- This region is marked as XN, meaning no code execution is allowed here.
- You can read/write control registers, but you cannot run instructions from this memory.
Summary Table:
Feature | Description |
---|---|
Address Range | 0xE0000000 – 0xE00FFFFF |
Size | 1 MB |
Execution | ❌ Not allowed (XN) |
Contains | NVIC, SysTick, SCB |
Usage | Interrupt control, system config, timers |
Access Type | Read/Write only (to registers) |
🧾 Use Case Examples:
Module | Function |
---|---|
NVIC | Enables/disables interrupts and sets their priorities. |
SysTick | Generates periodic interrupts for OS tick or delay. |
SCB | Provides system-level control: vector table offset, fault config, CPU ID, etc. |
🔧 Example in C (accessing SysTick):
#define SYSTICK_BASE 0xE000E010
#define SYSTICK_CTRL (*(volatile uint32_t*)(SYSTICK_BASE + 0x00))
// Enable SysTick with processor clock and interrupt
SYSTICK_CTRL = 0x07;
Leave a Reply