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.

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.

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.
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.

https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/
To be continued
Recommended Reading

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

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

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

