======A simple C run-time framework for the STM32 processor====== Check out [[arm_cortex-m3:stm32:minimal-c-program|Writing a minimal C program for the STM32]] and [[gnu-tools:essential-ld|Essential GNU Linker Concepts for Embedded Systems Programmers]] before continuing with this page. =====A linker script for the STM32F103RBT6 processor===== The STM32F103RBT6 processor has 128Kb flash (from address 0x08000000 which is also mapped to 0x0) and 20Kb of RAM (at 0x20000000). The stack pointer will be initialized to 0x20005000. The Cortex-M3 core extracts the 4 byte value at address 0x0 and uses it to initialize the stack pointer. The interrupt vector table begins at location 0x4 (0x4 holds the reset vector). We will fill up a few other entries in the table with address of a function which executes an infinite loop.A group of these function pointers are held in a global array which is in a section called //isr_vector//. The linker script directive //KEEP// is used to make sure that this section is not //garbage-collected// even if the linker is invoked with a command line argument which enables GC of unreferenced sections (check out [[http://blog.fosstronics.com/2008/07/02/gnu-toolchain-tips-of-the-week/|this blog entry for more info about linker garbage collection]]). Initialized global variables will be stored immediately after the //text// section (in flash memory); upon reset, the //startup// code will copy this data into RAM at location 0x20000000. Uninitialized global variables will be placed immediately after the block of initialized variables. The startup code will zero this block. The symbol //_extext// is used by the startup code to identify end of the //text// section and beginning of the section (in flash) which holds initialized data. The symbols //_sdata// (start data) and //_edata// (end data) are used by the startup code to identify the bounds of the data section in RAM. The symbols //_sbss// (start bss) and //_ebss// (end bss) are used by the startup code to identify the bounds of the section in RAM which holds uninitialized data. Here is the actual linker script (the script is a cut-down version of the one which comes with CircleOS). MEMORY { RAM (xrw): ORIGIN = 0x20000000, LENGTH = 20K FLASH (rx) : ORIGIN = 0x0, LENGTH = 128K } SECTIONS { .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) . = ALIGN(4); } >FLASH .text : { . = ALIGN(4); *(.text) *(.text.*) *(.rodata) *(.rodata*) . = ALIGN(4); _etext = .; } >FLASH .data : AT ( _etext ) { . = ALIGN(4); _sdata = .; *(.data) *(.data.*) . = ALIGN(4); _edata = .; } >RAM .bss : { . = ALIGN(4); _sbss = .; *(.bss) *(COMMON) . = ALIGN(4); _ebss = .; } >RAM } And here is the startup C code: #define STACK_TOP 0x20005000 void c_startup(void); void dummy_fn(void); __attribute__((section(".isr_vector"))) void (*vectors[])(void) = { STACK_TOP, c_startup, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, dummy_fn, }; void dummy_fn(void) { while(1); } void c_startup(void) { unsigned long *src, *dst; src = &_etext; dst = &_sdata; while(dst < &_edata) *(dst++) = *(src++); src = &_sbss; while(src < &_ebss) *(src++) = 0; main(); } The startup code copies initialized data from flash (stored at end of the //text// section) into RAM using the symbols provided by the linker script. It also zeros all the bytes in the uninitialized data section (the //bss//).