System Initialization in Embedded Development

12.2.5

SystemInit()

List 5: 12-5: SystemInit()

Swipe left or right to view the full content

void SystemInit(void) {#if __FPU_USED
/* Enable the FPU only when it is used. * Code taken from Section 7.1, Cortex-M4 TRM (DDI0439C) */
/* Set bits 20-23 (CP10 and CP11) to enable FPU. */
SCB->CPACR = (uint32_t) CP_MASK;
#endif
#if BSP_TZ_SECURE_BUILD
uint32_t * p_main_stack_top = (uint32_t *) __Vectors[0];
*p_main_stack_top = BSP_TZ_STACK_SEAL_VALUE;
#endif
.............. // Code omitted for brevity
/* Call Post C runtime initialization hook. */
R_BSP_WarmStart(BSP_WARM_START_POST_C);
/* Initialize ELC events that will be used to trigger NVIC interrupts. */
bsp_irq_cfg();
/* Call any BSP specific code. No arguments are needed so NULL is sent. */
bsp_init(NULL);
}

This is the first function executed after the MCU enters Reset_Handler. As the function name suggests, it is used to initialize the MCU and the runtime environment. After executing this code, control will pass to the user’s hal_entry function via main. Due to the length of the code, the analysis will be divided into several parts below.

12.2.5.1

Enabling FPU

List 6: 12-6: Enabling FPU

Swipe left or right to view the full content

#if __FPU_USED
/* Enable the FPU only when it is used. * Code taken from Section 7.1, Cortex-M4 TRM (DDI0439C) */
/* Set bits 20-23 (CP10 and CP11) to enable FPU. */
SCB->CPACR = (uint32_t) CP_MASK;
#endif

The FPU (Floating-Point Unit) supports single-precision addition, subtraction, multiplication, division, accumulation, and square root operations. It also provides commands for converting between fixed-point and floating-point data formats and floating-point constants.

12.2.5.2

Sealing the Stack Top

List 7: 12-7: Sealing the Stack Top

Swipe left or right to view the full content

#if BSP_TZ_SECURE_BUILD
uint32_t * p_main_stack_top = (uint32_t *) __Vectors[0];
*p_main_stack_top = BSP_TZ_STACK_SEAL_VALUE;
#endif

Here, the stack pointer is obtained, and the top of the stack is assigned the value “BSP_TZ_STACK_SEAL_VALUE”, which expands to 0xFEF5EDA5. This address cannot be used as a program address because the range from 0xE0000000 to 0xFFFFFFFF is non-executable. This process is known as #Sealing the Stack. If an attack targets the stack, the value at this address will be overwritten, which will be detected and prevented.

System Initialization in Embedded Development

12.2.5.3

Setting the Base Address of the Interrupt Vector Table

List 8: 12-8: Setting the Base Address of the Interrupt Vector Table

Swipe left or right to view the full content

#if !BSP_TZ_NONSECURE_BUILD
SCB->VTOR = (uint32_t) &__Vectors;
#endif

Here, the base address of the interrupt vector table is set by directly assigning a value to SCB->VTOR. This step will be skipped in non-secure projects.

12.2.5.4

Warm Start Callback Function

List 9: 12-9: Warm Start Callback Function

Swipe left or right to view the full content

void R_BSP_WarmStart(bsp_warm_start_event_t event) __attribute__((weak));

void R_BSP_WarmStart(bsp_warm_start_event_t event) {
if (BSP_WARM_START_RESET == event) {
/* C runtime environment has not been setup so you cannot use globals. System clocks are not setup. */
}
if (BSP_WARM_START_POST_CLOCK == event) {
/* C runtime environment has not been setup so you cannot use globals. Clocks have been initialized. */
}
else if (BSP_WARM_START_POST_C == event) {
/* C runtime environment, system clocks, and pins are all setup. */
}
else {
/* Do nothing */
}
}

This function will be called three times, before clock initialization, after clock initialization, and after C runtime environment initialization. This function is declared with the “weak” attribute, allowing users to override it. By default, this function will be overridden in hal_entry.c.

System Initialization in Embedded Development

List 10: 12-10: Overridden Function in hal_entry

Swipe left or right to view the full content

void R_BSP_WarmStart(bsp_warm_start_event_t event) {
if (BSP_WARM_START_RESET == event) {
#if BSP_FEATURE_FLASH_LP_VERSION != 0 // This part can be ignored as it is not available on RA6M5
/* Enable reading from data flash. */
R_FACI_LP->DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event) {
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
}
}

By default, here, pin initialization will only occur after the C runtime environment is initialized, meaning when the function parameter is “BSP_WARM_START_POST_C”; otherwise, no operations will be performed here.

12.2.5.5

Clock Initialization

List 11: 12-11: Clock Initialization

Swipe left or right to view the full content

bsp_clock_init();

This function sets all system clocks according to the settings in bsp_clock_cfg.h, which are derived from the Clocks tab in FSP Configuration.

12.2.5.6

Enabling CORTEX-M33 Stack Monitor

List 12: 12-12: Enabling CORTEX-M33 Stack Monitor

Swipe left or right to view the full content

/* Use CM33 stack monitor. */
__set_MSPLIM(BSP_PRV_STACK_LIMIT);

This sets the main stack pointer limit. Devices without the ARMv8-M main extension (i.e., Cortex-M23) lack the unsafe stack pointer limit register, so this operation is ignored in non-secure mode.

12.2.5.7

Initializing the C Runtime Environment

12.2.5.7.1Initializing the BSS Section

List 13: 12-13: BSS Section Initialization

Swipe left or right to view the full content

/* Zero out BSS */
#if defined(__ARMCC_VERSION)
memset((uint8_t *) &ImageZIBSS$$ZI, $$Length);
#elif defined(__GNUC__)
memset(&__bss_start__, 0U, ((uint32_t) &__bss_end__ - (uint32_t) &__bss_start__));
#elif defined(__ICCARM__)
memset((uint32_t *) __section_begin(".bss"), 0U, (uint32_t) __section_size(".bss"));
#endif

BSS (Block Start by Symbol) is a memory area used to store uninitialized global and static variables. In this section, all data in BSS will be initialized to 0.

12.2.5.7.2Initializing the Data Section

List 14: 12-14: Data Section Initialization

Swipe left or right to view the full content

/* Copy initialized RAM data from ROM to RAM. */
#if defined(__ARMCC_VERSION)
memcpy((uint8_t *) &ImageBase, (uint8_t *) &LoadBase, (uint32_t) &ImageLength);
#elif defined(__GNUC__)
memcpy(&__data_start__, &__etext, ((uint32_t) &__data_end__ - (uint32_t) &__data_start__));
#elif defined(__ICCARM__)
memcpy((uint32_t *) __section_begin(".data"), (uint32_t *) __section_begin(".data_init"), (uint32_t) __section_size(".data"));
#endif

The data section is used to store initialized global variables, static variables, and constants. In this code, data will be copied from ROM to the RAM data section.

12.2.5.7.3Calling Constructors of Global Objects

List 15: 12-15: Calling Constructors of Global or Static Objects

Swipe left or right to view the full content

#if defined(__ARMCC_VERSION)
int32_t count = ImageLimit - ImageBase;
for (int32_t i = 0; i < count; i++) {
void (* p_init_func)(void) = (void (*)(void))((uint32_t) &ImageBase + (uint32_t) ImageBase[i]);
p_init_func();
}
#elif defined(__GNUC__)
int32_t count = __init_array_end - __init_array_start;
for (int32_t i = 0; i < count; i++) {
__init_array_start[i]();
}
#elif defined(__ICCARM__)
void const * pibase = __section_begin("SHT$$PREINIT_ARRAY");
void const * ilimit = __section_end("SHT$$INIT_ARRAY");
__call_ctors(pibase, ilimit);
#endif

The RA series MCUs support development using C++. This code is used to call the constructors of global C++ objects.

12.2.5.8

Initializing the Value of SystemCoreClock

List 16: 12-16: Initializing the Value of SystemCoreClock

Swipe left or right to view the full content

/* Initialize SystemCoreClock variable. */
SystemCoreClockUpdate();

This initializes the value of SystemCoreClock, which represents the frequency of the processor clock, defaulting to 200MHz.

12.2.5.9

Initializing the ICU

List 17: 12-17: Initializing the ICU

Swipe left or right to view the full content

/* Initialize ELC events that will be used to trigger NVIC interrupts. */
bsp_irq_cfg();

This function initializes the ICU (Interrupt Control Unit), which is the interrupt controller, to configure the ELC events that trigger NVIC interrupts.

System Initialization in Embedded Development

Need Technical Support?

If you have any questions while using Renesas MCU/MPU products, you can scan the QR code below or copy the URL into your browser to access the Renesas Technical Forum for answers or online technical support.

System Initialization in Embedded Development

https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/

To be continued

Recommended Reading

System Initialization in Embedded Development

GPIO Input – Practical Guide to Renesas RA Series FSP Library Development (25)

System Initialization in Embedded Development

Key_Scan Key Scanning Function – Practical Guide to Renesas RA Series FSP Library Development (26)

System Initialization in Embedded Development

Detailed Explanation of FSP Library Startup Files – Practical Guide to Renesas RA Series FSP Library Development (27)

System Initialization in Embedded DevelopmentSystem Initialization in Embedded Development

Leave a Comment