STM32 core module¶
lbuild module: modm:platform:core
This module specializes the generic modm:platform:cortex-m
module with
STM32-specific startup code and linkerscripts.
Startup¶
The __modm_initialize_platform()
callback enables the clock to SYSCFG
or
AFIO
and the clock to all internal SRAMs.
Linkerscript¶
For each target a specific linkerscript is generated out of a template, which
move some sections into special RAMs depending on their purpose. You can place
static objects in sections via the modm_section
attribute:
// .data sections get copied from flash to RAM during startup
modm_section(".data_sram1")
uint64_t data = 0x1234567812345678ull;
// .bss sections are not stored in flash but get zeroed during startup
modm_section(".bss_sram2")
uint8_t buffer[1024];
// .noinit sections are left uninitialized
modm_section(".noinit_sram3")
uint8_t display_buffer[480][320];
Note that the absolute addresses shown here are only for reference and usually differ on a specific device.
Static RAM (SRAM)¶
The most common memory map consists out of the internal Flash and one or more
continuous SRAMs, which are grouped together in one large a CONT_SRAM1
memory.
This allows SRAM1 to overflow into SRAM2 and SRAM3 by pushing all sections in
front of it further up and collapsing the heap sections. In that case there is
no guarantee that the SRAM specific sections (.data_sramN
etc) will remain
within their original SRAM section, but you can place large objects into higher
SRAMs explicitly to free up the space in the lower sections.
┌────────────────────────┐◄ __sram3_end
│ (+HEAP_SRAM3) │
│ (.noinit_sram3) │
│ (.bss_sram3) │ only if SRAM3 exists
SRAM3 │ (.data_sram3) │
0x2003 0000 ├────────────────────────┤◄ __sram2_end, __sram3_start
│ (+HEAP_SRAM2) │
│ (.noinit_sram2) │
│ (.bss_sram2) │ only if SRAM2 exists
SRAM2 │ (.data_sram2) │
0x2002 0000 ├────────────────────────┤◄ __sram1_end, __sram2_start
│ +HEAP_SRAM1 │
│ .noinit_sram1 │
│ .noinit │
│ .faststack │
│ .bss_sram1 │
│ .bss │
│ .data_sram1 │
│ .data │
│ .fastdata │
│ .fastcode │
│ (.vector_ram) │◄ only if remapped into RAM
SRAM1 │ +MAIN_STACK_SIZE │◄ __main_stack_top
0x2000 0000 └────────────────────────┘◄ __sram1_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
│ (.data_sram3) │◄ only if SRAM3 exists
│ (.data_sram2) │◄ only if SRAM2 exists
copy │ .data_sram1 │
only │ .data │
│ .fastcode │
│ .fastdata │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
Data Core-Coupled RAM (DCCM)¶
Some STM32F4 have a battery-backed backup SRAM and a single-cycle CCM that is only accessible to the core via the D-Code bus, thus the CCM is not DMA-able. Therefore the main stack is placed into SRAM, even though it is slower than CCM.
┌────────────────────────┐◄ __backup_end
│ +HEAP_BACKUP │
│ .noinit_backup │
│ .bss_backup │
BACKUP │ .data_backup │
0x4002 4000 └────────────────────────┘◄ __backup_start
┌────────────────────────┐◄ __sram3_end
│ (+HEAP_SRAM3) │
│ (.noinit_sram3) │
│ (.bss_sram3) │ only if SRAM3 exists
SRAM3 │ (.data_sram3) │
0x2003 0000 ├────────────────────────┤◄ __sram2_end, __sram3_start
│ (+HEAP_SRAM2) │
│ (.noinit_sram2) │
│ (.bss_sram2) │ only if SRAM2 exists
SRAM2 │ (.data_sram2) │
0x2002 0000 ├────────────────────────┤◄ __sram1_end, __sram2_start
│ +HEAP_SRAM1 │
│ .noinit_sram1 │
│ .noinit │
│ .faststack │
│ .bss_sram1 │
│ .bss │
│ .data_sram1 │
│ .data │
│ .fastcode │
│ (.vector_ram) │◄ only if remapped into RAM
SRAM1 │ +MAIN_STACK_SIZE │◄ __main_stack_top
0x2000 0000 └────────────────────────┘◄ __sram1_start
┌────────────────────────┐◄ __ccm_end
D-Code │ +HEAP_CCM │
only │ .noinit_ccm │
access │ .bss_ccm │
│ .data_ccm │
CCM │ .fastdata │
0x1000 0000 └────────────────────────┘◄ __ccm_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
│ (.data_sram3) │◄ only if SRAM3 exists
│ (.data_sram2) │◄ only if SRAM2 exists
│ .data_sram1 │
copy │ .data_ccm │
only │ .data_backup │
│ .data │
│ .fastdata │
│ .fastcode │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
Instruction Core-Coupled RAM (ICCM)¶
Some STM32F3, STM32L4 and STM32G4 devices have a single-cycle CCM that is accessible to the core via the I-Code and D-Code interface. Note that the CCM is not DMA-able.
┌────────────────────────┐◄ __sram3_end
│ (+HEAP_SRAM3) │
│ (.noinit_sram3) │
│ (.bss_sram3) │ only if SRAM3 exists
SRAM3 │ (.data_sram3) │
0x2003 0000 ├────────────────────────┤◄ __sram2_end, __sram3_start
│ (+HEAP_SRAM2) │
│ (.noinit_sram2) │
│ (.bss_sram2) │ only if SRAM2 exists
SRAM2 │ (.data_sram2) │
0x2002 0000 ├────────────────────────┤◄ __sram1_end, __sram2_start
│ +HEAP_SRAM1 │
│ .noinit_sram1 │
│ .noinit │
│ .faststack │
│ .bss_sram1 │
│ .bss │
│ .data_sram1 │
│ .data │
SRAM1 │ +MAIN_STACK_SIZE │◄ __main_stack_top
0x2000 0000 └────────────────────────┘◄ __sram1_start
┌────────────────────────┐◄ __ccm_end
│ +HEAP_CCM │
D-Code │ .noinit_ccm │
I-Code │ .bss_ccm │
only │ .data_ccm │
access │ .fastdata │
│ .fastcode │
CCM │ .vector_ram │
0x1000 0000 └────────────────────────┘◄ __ccm_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
│ (.data_sram3) │◄ only if SRAM3 exists
│ (.data_sram2) │◄ only if SRAM2 exists
│ .data_sram1 │
copy │ .data_ccm │
only │ .data_backup │
│ .data │
│ .fastdata │
│ .fastcode │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
Tightly-Coupled RAM (TCM)¶
The STM32F7 devices include an Instruction TCM (ITCM) and a data TCM (DTCM). Note that the DTCM section will overflow into the SRAM½ sections.
┌────────────────────────┐◄ __backup_end
│ +HEAP_BACKUP │
│ .noinit_backup │
│ .bss_backup │
BACKUP │ .data_backup │
0x4002 4000 └────────────────────────┘◄ __backup_start
┌────────────────────────┐◄ __sram2_end
│ +HEAP_SRAM2 │
│ .noinit_sram2 │
│ .bss_sram2 │
SRAM2 │ .data_sram2 │
0x2002 0000 ├────────────────────────┤◄ __sram1_end, __sram2_start
│ +HEAP_SRAM1 │
│ .noinit_sram1 │
│ .bss_sram1 │
SRAM1 │ .data_sram1 │
0x2001 0000 ├────────────────────────┤◄ __dtcm_end, __sram1_start
│ +HEAP_DTCM │
│ .noinit_dtcm │
│ .noinit │
│ .faststack │
D-Code │ .bss_dtcm │
only │ .bss │
access │ .data_dtcm │
│ .data │
│ .fastdata │
DTCM │ +MAIN_STACK_SIZE │◄ __main_stack_top
0x2000 0000 └────────────────────────┘◄ __dtcm_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
│ .data_sram2 │
│ .data_sram1 │
│ .data_dtcm │
copy │ .data_itcm │
only │ .data_backup │
│ .data │
│ .fastdata │
│ .fastcode │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
┌────────────────────────┐◄ __itcm_end
│ +HEAP_ITCM │
│ .noinit_itcm │
│ .bss_itcm │
│ .data_itcm │
│ .fastcode │
ITCM │ .vector_ram │
0x0000 0000 └────────────────────────┘◄ __itcm_start
The STM32H7 memory map is more complex with multiple SRAM regions in seperate
power domains D1, D2 and D3. Note that the main .data
and .bss
sections are
placed into the D1_SRAM section because the TCMs can't be accessed by
peripheral DMA transfers, but only the MDMA.
┌────────────────────────┐◄ __backup_end
│ +HEAP_BACKUP │
│ .noinit_backup │
│ .bss_backup │
BACKUP │ .data_backup │
0x3880 0000 └────────────────────────┘◄ __backup_start
┌────────────────────────┐◄ __d3_sram_end
│ +HEAP_D3_SRAM │
│ .noinit_d3_sram │
│ .bss_d3_sram │
D3_SRAM │ .data_d3_sram │
0x3800 0000 └────────────────────────┘◄ __d3_sram_start
┌────────────────────────┐◄ __d2_sram3_end
│ (+HEAP_D2_SRAM3) │
│ (.noinit_d2_sram3) │
│ (.bss_d2_sram3) │ only if D2_SRAM3 exists
D2_SRAM3 │ (.data_d2_sram3) │
0x3004 0000 ├────────────────────────┤◄ __d2_sram2_end, __d2_sram3_start
│ +HEAP_D2_SRAM2 │
│ .noinit_d2_sram2 │
│ .bss_d2_sram2 │
D2_SRAM2 │ .data_d2_sram2 │
0x3002 0000 ├────────────────────────┤◄ __d2_sram1_end, __d2_sram2_start
│ +HEAP_D2_SRAM1 │
│ .noinit_d2_sram1 │
│ .bss_d2_sram1 │
D2_SRAM1 │ .data_d2_sram1 │
0x3000 0000 └────────────────────────┘◄ __d2_sram1_start
┌────────────────────────┐◄ __d1_sram3_end
│ (+HEAP_D1_SRAM3) │
│ (.noinit_d1_sram3) │
│ (.bss_d1_sram3) │ only if D1_SRAM3 exists
D1_SRAM3 │ (.data_d1_sram3) │
0x240A 0000 ├────────────────────────┤◄ __d1_sram2_end, __d1_sram3_start
│ (+HEAP_D1_SRAM2) │
│ (.noinit_d1_sram2) │
│ (.bss_d1_sram2) │ only if D1_SRAM2 exists
D1_SRAM2 │ (.data_d1_sram2) │
0x2404 0000 ├────────────────────────┤◄ __d1_sram1_end, __d1_sram2_start
│ +HEAP_D1_SRAM1 │
│ .noinit_d1_sram1 │
│ .noinit │
│ .faststack │
│ .bss_d1_sram1 │
│ .bss │
│ .data_d1_sram1 │
D1_SRAM1 │ .data │
0x2400 0000 └────────────────────────┘◄ __d1_sram1_start
┌────────────────────────┐◄ __dtcm_end
│ +HEAP_DTCM │
D-Code │ .noinit_dtcm │
only │ .bss_dtcm │
access │ .data_dtcm │
│ .fastdata │
DTCM │ +MAIN_STACK_SIZE │◄ __main_stack_top
0x2000 0000 └────────────────────────┘◄ __dtcm_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
│ .data_d3_sram │
│ (.data_d2_sram3) │◄ only if D2_SRAM3 exists
│ .data_d2_sram2 │
│ .data_d2_sram1 │
│ (.data_d1_sram3) │◄ only if D1_SRAM3 exists
│ (.data_d1_sram2) │◄ only if D1_SRAM2 exists
copy │ .data_d1_sram1 │
only │ .data_dtcm │
│ .data_itcm │
│ .data_backup │
│ .data │
│ .fastdata │
│ .fastcode │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
┌────────────────────────┐◄ __itcm_end
│ +HEAP_ITCM │
│ .noinit_ccm │
│ .bss_itcm │
│ .data_itcm │
│ .fastcode │
ITCM │ .vector_ram │
0x0000 0000 └────────────────────────┘◄ __itcm_start
Static RAM (SRAM) with vector table remap on F0 devices¶
This memory map is identical to the SRAM default one, except that
.vector_ram
is placed at the beginning of SRAM1. It is used on STM32F0
devices in case the platform-specific vector table relocation option
modm:platform:core:vector_table_location
is set to ram
.
┌────────────────────────┐◄ __sram1_end
│ +HEAP_SRAM1 │
│ .noinit_sram1 │
│ .noinit │
│ .faststack │
│ .bss_sram1 │
│ .bss │
│ .data_sram1 │
│ .data │
│ .fastdata │
│ .fastcode │
│ +MAIN_STACK_SIZE │◄ __main_stack_top
SRAM1 │ .vector_ram │
0x2000 0000 └────────────────────────┘◄ __sram1_start
┌────────────────────────┐◄ __flash_end
│ (unused) │
├────────────────────────┤◄ __rom_end
│ .table.heap │
│ .table.copy.extern │
tables │ .table.zero.extern │
│ .table.copy.intern │
│ .table.zero.intern │
│ │
copy │ .data_sram1 │
only │ .data │
│ .fastcode │
│ .fastdata │
│ │
│ .note.gnu.build-id │
│ .assertion │
│ .hardware_init │
│ (.eh_frame) │
read │ (.ARM.exidx) │ only with C++ exceptions enabled
only │ (.ARM.extab) │
│ .init_array │
│ .init │
│ .rodata │
│ .text │
FLASH │ .vector_rom │
0x0800 0000 └────────────────────────┘◄ __rom_start, __flash_start
This module is only available for stm32.
Options¶
main_stack_location¶
SRAM (default) or DTCM (faster, but not DMA-capable)
This option is only available for stm32h7.
Default: sram
Inputs: [dtcm, sram]
vector_table_location¶
Vector table location in ROM or RAM on F0 devices
STM32 devices with a Cortex-M0 core provide a platform-specific method to place the interrupt vector table in SRAM although the core does not support vector table relocation. It is only available on STM32F0 since all other devices can remap the vector table in the Cortex-M core.
When this method is activated the vector table is copied to the start of SRAM1
by the startup script. The SYSCFG->CFGR1
register is set to remap the
beginning of SRAM to the vector table location at 0x0000 0000
.
You can modify the RAM vector table using the CMSIS NVIC functions:
void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)
uint32_t NVIC_GetVector(IRQn_Type IRQn)
This remapping method allows to easily boot an application from a custom bootloader even if the Cortex-M0 core does not support relocation.
For applications that do not modify the vector table at runtime, relocation to RAM is not necessary and can save a few hundred bytes of static memory.
On Interrupt Latency
Placing main stack and vector table into the same memory can significantly slow down interrupt latency, since both I-Code and D-Code memory interface need to fetch from the same access port.
This option is only available for stm32f0.
Default: rom
Inputs: [ram, rom]
Dependencies¶
Limited availability: Check with 'lbuild discover' if this module is available for your target!