How to setting up a development environment for ARM Cortex-M3 microcontroller explained at this post. We decided that two equal choices will do same job – either CodeSourcery G++ Lite or Yagarto. Both use same base of GNU tool-set.
Developing with GCC tools
In order to get a working binary, there is a series tools involved during code development. Several tools are necessary to compile simple applications. These are: compiler, assembler, linker and binary generator. Each of them does it own task in a chain process. When you start compiling your project normally there is a linker invoked, which with correct parameters links libraries, object files.
Image may be NSFW.
Clik here to view.
Once executable is generated, then binary image generator creates binary image (.bin or .hex) that can be uploaded to MCU. We won’t go in to details right now as this will be more convenient to do in later code examples. Lets get directly to code writing part which is very important for linker and tasks before main() routine.
Linker script
Practically speaking, linker script is a file that defines microcontroller specific features like memory map, memory sections, stack location and size. It may also contain application specific information if needed. Usually linker scripts are already written and can be found along example projects. So once set up there is no need to write them each time a new project is started, unless some modifications or additions are needed. Lets look at some key features of linker script.
First of all we need to describe memory blocks and size of microcontroller. There is a MEMORY command used. Further we are going to work with STM32 Discovery kit where STM32F100RB microcontroller is used which has 128KB of Flash and 8KB of SRAM. So first we define our memory types:
MEMORY
{
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
where “rwx” means rewritable and executable, “rx” – read only and executable memory. Executable is meant that code can be run from this memory. In ARM program can be executed directly from Flash or RAM memory. ORIGIN points to start address of memory region and Length defines size of particular memory type.
Each memory type is also divided in memory sections where different type of data is stored. One section is needed for variables, another for constants, code, stack, heap and so on. So we need to show linker how to divide memories in to section. For this command SECTIONS is used. First of all we need to define section where program code will be stored. This section is called .text:
SECTIONS
{
.text :
{
. = ALIGN(4);
KEEP(*(.interrupt_vector))
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
} > FLASH
_data_flash = .;
.data : AT ( _data_flash )
{
. = ALIGN(4);
_data_begin = .;
*(.data)
*(.data*)
. = ALIGN(4);
_data_end = .;
} > RAM
Next section is .bss. This is where undefined/uninitialized variables and globals will be stored.
.bss :
{
_bss_begin = .;
__bss_start__ = _bss_begin;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
__bss_end__ = _bss_end;
} > RAM
And finally we need to define stack.
_stack_size = 1024;
stack_end = ORIGIN(RAM)+LENGTH(RAM);
_stack_begin = _stack_end - _stack_size;
. = _stack_begin;
._stack :
{
. = . + _stack_size;
} > RAM
Last thing to tell linker is where program has to start after reset. So we use simple line:
ENTRY(handler_reset);
This means that before main() program we need to initialize variables – copy constants from Flash to RAM, initialize stack and do other stuff if needed. Initialization is done in startup code. This part will be left for another post. Right now we’ve done following:
Image may be NSFW.
Clik here to view.
I won’t give final working linker script as it must go along with start-up code which will be discussed next.
The post Programming STM32-Discovery using GNU tools: Linker script appeared first on Key to Smart.