Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support vector table in RAM for most CM0(+) devices #773

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions examples/nucleo_f042k6/vector_table_ram/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2021, Christopher Durand
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>

using namespace Board;

// Blink LED with timer 14 interrupt. A custom handler is configured at runtime
// in the vector table located in SRAM.

// If the LED is blinking with a period of 1 second, the vector table has been
// successfully relocated to ram.
// Set the option "modm:platform:core:vector_table_location" in project.xml
// to place the vector table in ram on F0 devices without vector table relocation
// support in the Cortex M0 core.

static void tim14Handler()
{
Timer14::acknowledgeInterruptFlags(Timer14::InterruptFlag::Update);
LedD13::toggle();
}

int
main()
{
Board::initialize();
LedD13::setOutput();

// Set custom handler, only works if vector table is in RAM
NVIC_SetVector(TIM14_IRQn, reinterpret_cast<uintptr_t>(&tim14Handler));

Timer14::enable();
Timer14::setMode(Timer14::Mode::UpCounter);
Timer14::setPeriod<Board::SystemClock>(500'000 /* us */);
Timer14::applyAndReset();
Timer14::start();
Timer14::enableInterrupt(Timer14::Interrupt::Update);
Timer14::enableInterruptVector(true, 5);

uint32_t counter{0};
while (true)
{
modm::delay(100ms);
MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
}

return 0;
}
11 changes: 11 additions & 0 deletions examples/nucleo_f042k6/vector_table_ram/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<library>
<extends>modm:nucleo-f042k6</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_f042k6/vector_table_ram</option>
<option name="modm:platform:core:vector_table_location">ram</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:platform:timer:14</module>
</modules>
</library>
54 changes: 54 additions & 0 deletions examples/nucleo_l031k6/vector_table_ram/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2021, Christopher Durand
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>

using namespace Board;

// Blink LED with timer 2 interrupt. A custom handler is configured at runtime
// in the vector table located in SRAM.

// If the LED is blinking with a period of 1 second, the vector table has been
// successfully relocated to ram.
// Set the option "modm:platform:cortex-m:vector_table_location" in project.xml
// to place the vector table in ram.

static void tim2Handler()
{
Timer2::acknowledgeInterruptFlags(Timer2::InterruptFlag::Update);
LedD13::toggle();
}

int
main()
{
Board::initialize();
LedD13::setOutput();

// Set custom handler, only works if vector table is in RAM
NVIC_SetVector(TIM2_IRQn, reinterpret_cast<uintptr_t>(&tim2Handler));

Timer2::enable();
Timer2::setMode(Timer2::Mode::UpCounter);
Timer2::setPeriod<Board::SystemClock>(500'000 /* us */);
Timer2::applyAndReset();
Timer2::start();
Timer2::enableInterrupt(Timer2::Interrupt::Update);
Timer2::enableInterruptVector(true, 5);

uint32_t counter{0};
while (true)
{
modm::delay(100ms);
MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
}

return 0;
}
11 changes: 11 additions & 0 deletions examples/nucleo_l031k6/vector_table_ram/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<library>
<extends>modm:nucleo-l031k6</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_l031k6/vector_table_ram</option>
<option name="modm:platform:cortex-m:vector_table_location">ram</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:platform:timer:2</module>
</modules>
</library>
5 changes: 4 additions & 1 deletion src/modm/platform/core/cortex/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
# -----------------------------------------------------------------------------

def common_vector_table_location(env):
if env.get(":platform:core:vector_table_location", "rom") == "ram":
return "ram"
return env.get(":platform:cortex-m:vector_table_location", "rom")


def common_vector_table(env):
"""
Computes vector table properties:
Expand Down Expand Up @@ -201,7 +204,7 @@ def prepare(module, options):
memories = listify(options[":target"].get_driver("core")["memory"])

# Cortex-M0 does not have remappable vector table, so it will remain in Flash
if not options[":target"].has_driver("core:cortex-m0*"):
if options[":target"].get_driver("core")["type"] != "cortex-m0":
default_location = "rom"
if any((m["name"] == "ccm" and "x" in m["access"]) or m["name"] == "dtcm" for m in memories):
default_location = "ram"
Expand Down
4 changes: 3 additions & 1 deletion src/modm/platform/core/cortex/startup.c.in
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ void __modm_startup(void)
SCB_EnableICache();
%% endif

%% if "m0" not in core
%% if core != "cortex-m0"
// Set the vector table location
SCB->VTOR = (uint32_t)__vector_table_{{ vector_table_location }}_start;
%% endif
chris-durand marked this conversation as resolved.
Show resolved Hide resolved

%% if "m0" not in core
// Enable trapping of divide by zero for UDIV/SDIV instructions.
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
%% endif
Expand Down
16 changes: 15 additions & 1 deletion src/modm/platform/core/stm32/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,25 @@ def prepare(module, options):
if options[":target"].identifier.platform != "stm32":
return False

if options[":target"].get_driver("core")["type"] == "cortex-m0":
module.add_option(
EnumerationOption(
name="vector_table_location",
description=FileReader("option/vector_table_location.md"),
enumeration=["rom", "ram"],
default="rom")
)

module.depends(":platform:cortex-m")
return True


def build(env):
target = env[":target"].identifier
env.substitutions = {"target": target}
env.substitutions = {
"target": target,
"vector_table_location": env.get(":platform:core:vector_table_location", "rom")
}
env.outbasepath = "modm/src/modm/platform/core"
# startup helper code
env.template("startup_platform.c.in")
Expand Down Expand Up @@ -74,6 +86,8 @@ def post_build(env):
env.outbasepath = "modm/link"

linkerscript = "../cortex/ram.ld.in"
if env.get(":platform:core:vector_table_location", "rom") == "ram":
linkerscript = "ram_remap_vector_table.ld.in"
for memory in env.substitutions["memories"]:
if memory["name"] == "ccm":
if "x" in memory["access"]:
Expand Down
52 changes: 52 additions & 0 deletions src/modm/platform/core/stm32/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,55 @@ placed into the 128kB DTCM, but cannot overflow into D1_SRAM section.
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

```
26 changes: 26 additions & 0 deletions src/modm/platform/core/stm32/option/vector_table_location.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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.

!!! warning "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.
45 changes: 45 additions & 0 deletions src/modm/platform/core/stm32/ram_remap_vector_table.ld.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
%% import "../cortex/linker.macros" as linker with context
{{ linker.copyright() }}

{{ linker.prefix() }}
%% set table_heap = []
%% set table_copy = []
%% set table_zero = []

SECTIONS
{
{{ linker.section_rom_start("FLASH") }}

{{ linker.section_vector_rom("FLASH") }}

{{ linker.section_rom("FLASH") }}

{{ linker.section_vector_ram(cont_ram_regions[0].cont_name|upper, table_copy) }}

{{ linker.section_stack(cont_ram_regions[0].cont_name|upper) }}

{{ linker.section_ram(cont_ram_regions[0].cont_name|upper, "FLASH", table_copy, table_zero,
sections_data=["fastdata", "fastcode", "data_" + cont_ram_regions[0].contains[0].name],
sections_bss=["bss_" + cont_ram_regions[0].contains[0].name],
sections_noinit=["faststack"]) }}

{{ linker.all_heap_sections(table_copy, table_zero, table_heap) }}

%% if with_crashcatcher
%#
/* Bottom of crash stack for `modm:platform:fault` */
g_crashCatcherStack = . - 500;
%#
%% endif

%% if linkerscript_sections
{{ linkerscript_sections | indent(first=True) }}
%#
%% endif

{{ linker.section_tables("FLASH", table_copy, table_zero, table_heap) }}

{{ linker.section_rom_end("FLASH") }}

{{ linker.section_debug() }}
}
6 changes: 6 additions & 0 deletions src/modm/platform/core/stm32/startup_platform.c.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (c) 2016-2017, Fabian Greif
* Copyright (c) 2016-2017, 2019, Niklas Hauser
* Copyright (c) 2021, Raphael Lehmann
* Copyright (c) 2021, Christopher Durand
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -71,4 +72,9 @@ __modm_initialize_platform(void)
PWR->CR2 |= PWR_CR2_IOSV;
#endif
%% endif

%% if vector_table_location == "ram"
// Remap SRAM to 0x0 for vector table relocation without VTOR register
SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE;
%% endif
chris-durand marked this conversation as resolved.
Show resolved Hide resolved
}