[ion] N0200: improve code spliting between internal/external flash

Part I: move peripherals initiation to be executed from the external
flash to avoid many dependencies to limit the number of functions that
are forced in internal flash.
This commit is contained in:
Émilie Feral
2019-04-30 11:47:30 +02:00
parent 51cb00baea
commit 1c3c170aaa
5 changed files with 61 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
#include <drivers/board.h>
#include <drivers/cache.h>
#include <drivers/config/clocks.h>
#include <drivers/external_flash.h>
#include <regs/regs.h>
#include <ion.h>
@@ -85,7 +86,7 @@ void initMPU() {
Cache::isb();
}
void init(bool initBacklight) {
void init() {
initFPU();
initMPU();
initClocks();
@@ -106,7 +107,7 @@ void init(bool initBacklight) {
GPIO(g).PUPDR()->set(0x00000000); // All to "None"
}
initPeripherals(initBacklight);
ExternalFlash::init();
// Initiate L1 cache after initiating the external flash
Cache::enable();
}

View File

@@ -48,12 +48,12 @@ SECTIONS {
/* Internal flash memory */
/* We link 'non_inlined_ion_main' in a separate section from text.internal.
/* We link 'jump_to_external_flash' in a separate section from text.internal.
* Indeed, it is the only internal flash symbol that refers the external
* flash. This way we can assert that there are no cross references from the
* internal flash to the external flash. */
.text.internal_to_external : {
*(.text._ZL20non_inlined_ion_mainv)
*(.text._ZL22jump_to_external_flashv)
} >INTERNAL_FLASH
/* Use boot routine and required dependencies */
@@ -61,38 +61,44 @@ SECTIONS {
* done with -fdata-sections -ffunction-sections */
.text.internal : {
. = ALIGN(4);
*(.text.__assert)
*(.text.start)
*(.text.abort)
*(.text.isr_systick)
*(.text.__assert)
*(.text.memcpy)
*(.text.memset)
/*
*(.text.strlen)
*(.text.strncmp)
*(.text.strlcpy)
*(.text.strcmp)
*(.text.memset)
*(.text.memmove)
*(.text._ZN3Ion*)
*(.text._ZNV3Ion*)
*(.text._ZNK3Ion*)
*(.text.LZ4_*)
*/
/* 'start' dependecies */
*(.text.start)
*(.text._ZN3Ion6Device5Board4initEv)
*(.text._ZN3Ion6Device5Board7initFPUEv)
*(.text._ZN3Ion6Device5Board7initMPUEv)
*(.text._ZN3Ion6Device5Board10initClocksEv)
*(.text._ZNV3Ion6Device4Regs8Register*)
*(.text._ZN3Ion6Device4Regs8Register*)
*(.text._ZNK3Ion6Device4Regs9AFGPIOPin*)
*(.text._ZN3Ion6Device13ExternalFlash*)
*(.text._ZN3Ion6Device5Cache*)
*(.text._ZN3Ion6Timing6usleepEj)
/* 'abort' dependcies */
*(.text._ZN3Ion6Device5Reset4coreEv)
/**(.text._ZN3Ion5Power7suspendEb)*/
/* Optimization */
*/libgcc.a:(.text)
} >INTERNAL_FLASH
.rodata.internal : {
. = ALIGN(4);
*(.rodata.dfu_bootloader)
*(.rodata)
*(.rodata.str1.1)
*(.rodata._ZN3Ion*)
*(.rodata._ZZN3Ion*)
*(.rodata._ZNK3Ion*)
*(.rodata._ZTVN3Ion6*)
*(.rodata._ZN3KDColor*)
*(.rodata._ZL11KDColor*)
*(.rodata._ZL12KDColor*)
*(.rodata._ZL13KDColor*)
*(.rodata._ZN3Ion6Device13ExternalFlash*)
} >INTERNAL_FLASH
/* External flash memory */
@@ -103,6 +109,7 @@ SECTIONS {
} >EXTERNAL_FLASH
.rodata.external : {
*(.rodata)
*(.rodata.*)
} >EXTERNAL_FLASH

View File

@@ -27,7 +27,23 @@ void abort() {
#endif
}
/* This additional function call 'non_inlined_ion_main' serves two purposes:
/* In order to ensure that this method is execute from the external flash, we
* forbid inlining it.*/
static void __attribute__((noinline)) external_flash_start() {
/* Init the peripherals. If there is the on boarding app, do not initialize the
* backlight so that the user does not see the LCD tests. The backlight will
* be initialized after the Power-On Self-Test.*/
#if EPSILON_ONBOARDING_APP == 0
Ion::Device::Board::initPeripherals(true);
#else
Ion::Device::Board::initPeripherals(false);
#endif
return ion_main(0, nullptr);
}
/* This additional function call 'jump_to_external_flash' serves two purposes:
* - By default, the compiler is free to inline any function call he wants. If
* the compiler decides to inline some functions that make use of VFP
* registers, it will need to push VFP them onto the stack in calling
@@ -40,16 +56,20 @@ void abort() {
* start(), we isolate it in its very own non-inlined function call.
* - To avoid jumping on the external flash when it is shut down, we ensure
* there is no symbol references from the internal flash to the external
* flash except the jump to ion_main. In order to do that, we isolate this
* flash except this jump. In order to do that, we isolate this
* jump in a symbol that we link in a special section separated from the
* internal flash section. We can than forbid cross references from the
* internal flash to the external flash. */
static void __attribute__((noinline)) non_inlined_ion_main() {
return ion_main(0, nullptr);
static void __attribute__((noinline)) jump_to_external_flash() {
external_flash_start();
}
void start() {
/* When 'start' is executed, the external flash is supposed to be shutdown. We
* thus forbid inlining to prevent executing this code from external flash
* (just in case 'start' was to be called from the external flash). */
void __attribute__((noinline)) start() {
/* This is where execution starts after reset.
* Many things are not initialized yet so the code here has to pay attention. */
@@ -90,16 +110,12 @@ void start() {
}
#endif
/* Init the board. If there is the on boarding app, do not initialize the
* backlight so that the user does not see the LCD tests. The backlight will
* be initialized after the Power-On Self-Test.*/
#if EPSILON_ONBOARDING_APP == 0
Ion::Device::Board::init(true);
#else
Ion::Device::Board::init(false);
#endif
Ion::Device::Board::init();
non_inlined_ion_main();
/* At this point, we initialized clocks and the external flash but no other
* peripherals. */
jump_to_external_flash();
abort();
}

View File

@@ -42,11 +42,9 @@ void initPeripherals(bool initBacklight) {
Console::init();
SWD::init();
Timing::init();
ExternalFlash::init();
}
void shutdownPeripherals(bool keepLEDAwake) {
ExternalFlash::shutdown();
Timing::shutdown();
SWD::shutdown();
Console::shutdown();

View File

@@ -5,7 +5,7 @@ namespace Ion {
namespace Device {
namespace Board {
void init(bool initBacklight = true);
void init();
void shutdown();
void initFPU();