Programming STM32-Discovery using GNU tools. Startup code

Startup code is executed just after microcontroller is reset before the main program. As linker script, startup code usually is implemented as universal code for all the same microcontroller type. So often you don’t need to write one from scratch. Anyway, it is good to know what happens there anyway.

As we said, linker script has to go along with the startup code. This means that it will initialize MCU automatically according to data defined in the linker. Startup code initializes variables, copies defined variables from Flash to RAM, initializes stack and then gives resources to the main program. You will find that startup codes usually are written in assembly language, but this can also be done in C, which is easier to read and modify if necessary. First of all, in linker script we have pointed entry point to startup with the following command:

ENTRY(handler_reset)

So in startup code, this will be the first function called.

void handler_reset(void)
{
unsigned long *source;
unsigned long *destination;
// Copying data from Flash to RAM
source = &_data_flash;
for (destination = &_data_begin; destination < &_data_end;)
{
*(destination++) = *(source++);
}
// default zero to undefined variables
for (destination = &_bss_begin; destination < &_bss_end;)
{
*(destination++) = 0;
}
// starting main program
main();
}

Startup code takes to source and destination addresses from linker script as external variables:

extern unsigned long _data_flash;
extern unsigned long _data_begin;
extern unsigned long _data_end;
extern unsigned long _bss_begin;
extern unsigned long _bss_end;
extern unsigned long _stack_end;

These we defined when described sections. So the only thing left for startup code is taken values from source addresses in Flash memory and copy them to RAM’s destination addresses. Also, variables stored in the .bss section have defaulted to zero values—so no need to null them in the source when used.

Next step is that the startup does to allocate exception handler vector table. Due to ARM Cortex architecture, the first address in the vector table is used to store the stack end address. This is a convenient and efficient way to define it.

__attribute__ ((section(".interrupt_vector")))
void (* const table_interrupt_vector[])(void) =
{
(void *) &_stack_end, // 0 - stack
handler_reset, // 1
handler_default, // 2
handler_default, // 3
handler_default, // 4
handler_default, // 5
handler_default, // 6
0, // 7
0, // 8
0, // 9
0, // 10
handler_default, // 11
handler_default, // 12
0, // 13
handler_default, // 14
handler_default, // 15
// peripherals
handler_default, // 0
handler_default, // 1
handler_default, // 2
handler_default, // 3
handler_default, // 4
-//-
handler_default, // 59
handler_default // 60
};

In linker script, we defined that “.interrupt_vector” section is starting at 0x00000000 address, so stack pointer is located at 0x00000000 address of Flash. Then it goes reset handler which then copies variable data to RAM and nulls undefined variables. Then it is over with startup code, and all resources are allocated to the main() routine.

void handler_default(void)
{
while (1)
{
//loop
}
}

Default routine handles unexpected interrupts and puts MCU to an endless loop. This is a very simplified version of the linker script and startup code. Ir explains thing pretty well, I guess. It is probably best for starters to find a working example of Arm Cortex M3 GCC code copy linker script and startup code as they are and focus on software writing. Barely you’ll need to change these soon.

3 Comments:

  1. hi,

    i am new to embeddeds system and i was trying since one month to make a linker script and startup file for Arm7tdmi – TMS470R1B1M chip, to be compiled under GNU GCC ARM Non-EABI tool chain in code-sourcery lite version.

    I would be great help if you provide the startup and linker file for above which can work with interrupts also.

    If you can’t, it would be a great help if you just provide what changes has to be made to the linker and startup files explained by you on this webpage.

    Thanks.

  2. Hi,
    I really do not speak English.
    You can go to my site.
    http://ziblog.ru/category/mikrokontrolleryi/stm32/
    (with the help of google translator)
    as I have access code with interrupts
    http://ziblog.ru/forum/viewtopic.php?f=6&t=3

  3. Hi,
    this is very good to read, now a days everything is ready and we don’t came across these things even though for experienced developers.
    Thanks for this article.

Comments are closed