One of the most overlooked processes in embedded software development is the microcontroller boot process. The reason for this is that silicon toolchains have become very good at providing and abstracting out the boot process so that developers generally don’t think about it. Unfortunately this can lead to a lack of understanding how the microcontroller start-ups, initializes itself and eventually finds its way to the all too familiar main function. This article will explore the boot process and elucidate what is happening behind the scenes.
The microcontroller boot process starts by simply applying power to the system. Once the voltage rails stabilize, the microcontroller looks to the reset vector for the location in flash where the start-up instruction can be found. The reset vector is a special location within the flash memory map. For example, taking a look at Figure 1, it can be seen that at address 0x0002 is where the reset vector is located within the memory map.
Figure 1 – Reset Vector Location
The address that is stored at the reset vector is loaded by the microcontroller and the instructions that are contained there are then loaded and executed by the CPU. Now these first instructions aren’t the start of main that the developer created. Instead, these are instructions on how to start-up the microcontroller.
The first thing that usually occurs is that the vector tables that are stored in flash are copied to RAM. They are copied from and to the location that is specified in the linker file at the time the executable program is created. One reason for copying the vector tables to RAM is that it is faster to execute from RAM than flash. This helps to decrease the latency of any interrupt calls within the system. Depending on the particular architecture of the microcontroller there may then be an instruction to update a vector table register so that the microcontroller knows where the start of the RAM table is.
Next the initialized data sections are copied into RAM. This is usually variables that are stored in the .data section of the linker. Examples of initialized data would be static, global and static local variables that have been provided with an initialization value during compile time. These are explicit definitions such as int Var = 0x32;.
Following the copy of the data section, the .bss section is also copied. The .bss section contains variables that are not initialized explicitly or that have been initialized to a value of zero. A simple example is that the variable static int Var; would be contained within this section.
Finally, the microcontroller will copy any RAM functions from flash to RAM. Once again it is sometimes worthwhile to execute certain functions out of RAM rather than flash due to the execution speed being slightly faster. These are functions usually decided upon by the developer and purposely placed there in the linker file prior to compiling the program.
This entire process is often known as the “C Copy Down”. Without performing this copy down the C environment would not be properly setup in order to execute the program. Usually once the copy down has been completed the microcontroller then jumps to the start of main where the developers application then begins.
The microcontroller boot process is actually relatively straight forward. Often times though it is written in assembly language or some other obscure and sparsely documented way so that it is difficult to get a clear understanding of how the microcontroller actually gets to main. Instead it looks like a very complex and nearly unknowable process which then makes custom development of boot code a potentially painful process.