Reset Sequence in ARM Cortex-M4

As you are an embedded engineer, have you think anytime, what happens when you press the reset button (Reset Sequence in ARM Cortex-M4)? How it is calling the main() function in your application automatically? And also, If you are attending any interviews, the interviewer might have asked you this question. Okay, Let’s discuss the reset sequence in the microcontroller.

You can also read ESP32 Introduction and its flow, LPC2148 Keil Installation, LPC2148 FreeRTOS porting, LPC2148 Introduction, Linux device driver tutorial.

Reset Sequence in ARM Cortex-M4

Before starting this we must know about the microcontroller memory architecture. Please find the below image to know about the Memory map of ARM Cortex-M4.

Reset Sequence in ARM Cortex-M4

Here, we have a code region, where we are going to write our final binary. That memory is starting from 0x00000000 to 0x1FFFFFFF. Now we will forget about other regions. We will take only the SRAM and Code region. We know that the code region has the final output of our program (.hex or .bin or etc). SRAM will be having stack, heap, global RW variables, and Static variables, etc.

Memory layout of the program

Now we have to know how the final output of our program is stored in the code region. The below image will explain how our program is stored in the code region. Reset Sequence in ARM Cortex-M4As you can see from the above image, the final output of our program will be ordered in this way by using a linker. If you want to know the memory layout of the program, you can refer to this tutorial. So, the vector table is starting from 0x00000000.

Note: By default vector table will be starting from 0x00000000.

Vector table of ARM Cortex_M4

That vector table will contain all the locations of the exception and interrupt ISR. As Cortex-M4 has below exceptions, interrupts and those things are ordered in the below image.

Reset Sequence in ARM Cortex-M4So, 0x00000000 address contains initial Stack Pointer Value. Then 0x00000004 has the address of the reset handler. Once you press the reset button or power up the controller, below things will happen.

What happens When you press the reset button in ARM Cortex-M4?

  1. PC (Program Counter) will be loaded with 0x00000000. So will start from the address 0x00000000.
  2. Since the address has an Initial Stack Pointer value, It will be fetched to the MSP (Main Stack Pointer). So, that value will be starting of the stack.
  3. Then PC will be loaded with the Reset handler’s address.

Note: These above 3 steps are done by the hardware (This is architecture-specific).

4. After that, the reset handler will perform the below operations.

      1. Initialize the system.
      2. Copy the Initialized global variable, static variable (.data) to SRAM.
      3. Copy the Un-initialized data (.bss) to SRAM and initialize it to 0.
      4. It Calls main().

This is how your main() is getting called while power-up or press the reset button. You may understand clearly if you see the execution below.

Reset Sequence in ARM Cortex-M4 – Example execution

I am using IAR IDE and STM32. Each controller has a specific startup file that has all the ISR’s addresses (vector table). In my case, I have startup_stm32l4xx.s file. I am going to run through a debugger (J-Link). Using that we will step by step.

I have attached some lines of the startup file.

__vector_table
        DCD     sfe(CSTACK)
        DCD     Reset_Handler             ; Reset Handler

        DCD     NMI_Handler               ; NMI Handler
        DCD     HardFault_Handler         ; Hard Fault Handler
        DCD     MemManage_Handler         ; MPU Fault Handler
        DCD     BusFault_Handler          ; Bus Fault Handler
        DCD     UsageFault_Handler        ; Usage Fault Handler
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     SVC_Handler               ; SVCall Handler
        DCD     DebugMon_Handler          ; Debug Monitor Handler
        DCD     0                         ; Reserved
        DCD     PendSV_Handler            ; PendSV Handler
        DCD     SysTick_Handler           ; SysTick Handler

The above code is not a full code. I just provided some lines for your understanding. If you see the above code, the vector table’s first place contains Stack. This is the initial SP. Then after that, they have passed the Reset_Handler‘s address.

Now I am going to start debugging.

  • Refer to the below image, the cursor points to Reset_Handler and SP also points to 0x20000800. And other registers are initialized to zero. Now loading the SystemInit into R0 register.

Reset Sequence in ARM Cortex-M4

  • Then using the BLX command, it is branching to SystemInit function. There it will initialize the system.
  • Once it’s done with the system initialize, it will load the __iar_program_start to R0 register. Check out the below Image.

  • Since we are using IAR it using __iar_program_start function. This is IAR specific function.
  • You can not find the source of the __iar_program_start. But you can see those kinds of stuff in the Disassembly window of IAR.
  • There you can see that it is going into __iar_init_vfp, which initializes the hardware floating-point unit (FPU). Check out the below Image.

Reset Sequence in ARM Cortex-M4

  • Then there is it will jump to ?main function. Check out the below Image.

  • In ?main, it calls, __low_level_init. This function is intended to perform a customized initialization of your hardware that either must occur very early on or can speed up the startup process. For example, if you plan to increase the CPU clock speed, it’s better to do it sooner so that the rest of the startup code will execute faster. Check out the below Image.

  • As you can see by the test of the R0 register, __low_level_init returns a value that determines whether to go straight to calling main or to perform a data initialization. It returns a non-zero value, so the function __iar_data_init3 is called. Check out the below Image.

Reset Sequence in ARM Cortex-M4

  • __iar_data_init3 will copy the data to SRAM (.data). And also copy the .bss data to SRAM and initialize it to 0 with the help of __iar_zero_init3.  Check out the below Image.

  • After that, finally, it calls _call_main function. In that _call_main function, we are calling the original main() function. Check out the below Image.

Reset Sequence in ARM Cortex-M4

That’s all.

Summary

  • When you press the reset button, it will copy the Stack pointer to MSP (Main Stack Pointer) from the location of 0x00000000.
  • Then it moves to Reset_Handler.
  • In the Reset_handler, it will initialize the hardware (system), then copy the initialized data (Initialized global variable and static variable) to SRAM.
  • Then copy the uninitialized data to SRAM and initialize with 0.
  • Finally, it calls our main function.

Note: This process is applicable when you don’t have a bootloader. If you have a bootloader, then it will execute in a different way.

What happens when you have a bootloader?

When your project has a bootloader, then you will be having two binaries. One is a Bootloader image and another one is an application. The bootloader will be placed in the 0x00000000 with its Vector Table. The application will be placed in another area of the flash memory with its vector table.

  • When you press the reset button, it will start from the bootloader. So, it will copy the Stack pointer to MSP (Main Stack Pointer) from the location of 0x00000000.
  • Then it moves to the bootloader’s reset handler.
  • The bootloader will do some operations based on your need like check for firmware version, upgrade the firmware, etc.
  • Once it has done with its operation, it will jump to the application’s vector table.
  • Then it will initialize the MSP (Main Stack Pointer) again.
  • Now we have to tell the controller to use the application’s vector table instead of using the bootloader’s vector table. That will be done using the Vector Table Offset Register (VTOR).
  • Then it goes to the application’s reset handler. There it will copy and initialize the data segments to the RAM (Global, Static variables).
  • Finally, it moves to the main function of the application.

If you want to learn about the bootloader, then we have provided a separate bootloader series for you. Please check it out.

Now you know how our main function is getting called? Good. Happy programming :-P.

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
Bootloader TutorialsRaspberry PI Pico Tutorials

5 3 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
2
0
Would love your thoughts, please comment.x