Файл: ARM cross development with Eclipse, version 2 (J.P. Lynch, 2005).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 12.06.2025
Просмотров: 690
Скачиваний: 1
The next part of the Linker Command Script defines the sections and where they go in memory.
The first thing done within the SECTIONS command is to set the location counter.
The dot means “right here” and this sets the location counter at the beginning to
0x000000.
. = 0; /* set location counter to address zero */
Now we create our first output section, located at address 0x000000. This creates a output section named “startup” and it includes all sections emitted by the assembler and compiler named .startup. In this case, there is only one such section created in crt.s.
This startup output section is to go into FLASH at address 0x000000.
Remember that the startup section has the interrupt vectors (must be placed at
0x000000) and the startup code also sets the stacks, modes and copies the
.data and .bss sections.
startup : { *(.startup) } >flash
Now we can follow the vector table and assembler startup code with all code generated by the assembler and C compiler; this code is normally emitted in
.text sections. However, constants and strings go into sections such as .rodata and .glue_7 so these are included for completeness. These code bits all go into
FLASH memory.
.text : |
/* collect all sections that should go into FLASH after startup */ |
|||
{ |
*(.text) |
/* all .text sections (code) */ |
||
*(.rodata) |
/* all .rodata sections (constants, strings, etc.) |
*/ |
||
*(.rodata*) |
/* all .rodata* sections (constants, strings, etc.) |
*/ |
||
*(.glue_7) |
/* all .glue_7 sections |
*/ |
||
*(.glue_7t) |
/* all .glue_7t sections |
*/ |
||
_etext = .; |
/* define a global symbol _etext after the last code byte */ |
|||
} >flash |
/* put all the above into FLASH */ |
|||
We follow the .text: output section (all the code and constants, etc) with a symbol definition, which is automatically global in the GNU toolset. This basically sets the next address after the last code byte to be the global symbol
_etext (end-of-text).
There are two variable areas, .data and .bss. The initialized variables are contained in the .data section, which will be placed in RAM memory. The big secret here is that an exact copy of the .data section will be loaded into FLASH right after the code section just defined. The onus is on the programmer to copy this section to the correct address in FLASH; in this way the variables are
“initialized” at startup just after a reset.
The .bss section has no initializers. Therefore, the onus is on the programmer to clear the entire .bss section in the startup routine.
Initialized variables are usually emitted by the assembler and C compiler as
.data sections.
.data : |
|
{ |
|
_data = .; |
// global symbol locates the start of .data section in RAM |
*(.data) |
// tells linker to collect all .data sections together |
_edata = .; |
// global symbol locates the end of .data section in RAM |
} >ram AT>flash |
// load data section into RAM, load copy of .data section |
// into FLASH for copying during startup. |
Note first that we created two global symbols, _data and _edata, that locate the beginning and end of the .data section in RAM. This helps us create a copy loop in the crt.s assembler file to load the initial values into the .data section in
RAM.
The command >ram specifies the Virtual Memory Address that the .data section is to be placed into RAM (think of it as the final destination in RAM and all code references to any variables will use the RAM address.
The command AT >flash specifies the load memory address; essentially an exact copy of the RAM memory area with every variable initialized placed in flash for copying at startup.
You might say “why not let the Philips boot loader load the initial values of the
.data section in RAM directly from the hex file?” The answer is that would work once and only once. When you power off and reboot your embedded application, the RAM values are lost.
The copy of the .data area loaded into flash for copying during startup is placed by the GNU linker at the next available flash location. This is conveniently right after the last byte of the .prog section containing all our executable code.
The .bss section is all variables that are not initialized. It is loaded into RAM and we create two global symbols _bss_start and _bss_end to locate the beginning and end for clearing by a loop in the startup code.
.bss :
{
_bss_start = .; *(.bss)
} >ram
. = ALIGN(4);
}
_bss_end = . ; _end = .;
Now let’s diagram just where everything is in RAM and FLASH memory.
RAM
FLASH
0x40010000
High RAM used by Philips ISP
0x4000FEE0
0x4000FFFC
stacks
Unused RAM
0x40000234
.bss uninitialized variables
0x40000218
.data variables
0x40000200
Low RAM used by Philips ISP
0x40000000
0x020000
Unused FLASH
copy of .data variables
0x000268
Constants, strings, etc.
Initialize( )
Feed( )
Main( )
Startup Code
0x000020
Vector Table
0x000000
16 Description of the Makefile
The makefile is the last source file we need to look at. I built the makefile to comply with the GNU make utility and be as simple as possible.
The general idea of the makefile is that a target (could be a file) is associated with one or more dependent files. If any of the dependent files are newer than the target, then the commands on the following lines are executed (to recompile, for instance). Command lines are indented with a Tab character!
main.o: main.c
arm-elf-gcc -I./ -c -O3 -g main.c
In the example above, if main.c is newer than the target main.o, the command or commands on the next line or lines will be executed. The command arm-elf- gcc will recompile the file main.c with several compilation options specified. If the target is up-to-date, nothing is done. Make works its way downward in the makefile, if you’ve deleted all object and output files, it will compile and link everything.
GNU make has a helpful “variables” feature that helps you reduce typing. If you define the following variable:
CFLAGS = -I./ -c -fno-common -O3 -g
You can use this multiple times in the makefile by writing the variable name as follows:
$(CFLAGS) will substitute the string -I./ -c -O3 -g
Therefore, the command-
arm-elf-gcc $(CFLAGS) main.c
is exactly the same as
arm-elf-gcc -I./ -c -O3 -g main.c
Likewise, we can replace the compiler name arm-elf-gcc with a variable too.
CC = arm-elf-gcc
Now the command line becomes
$(CC) $(CFLAGS) main.c
Now our “rule” for handling the main.o and main.c files becomes:
main.o: main.c |
||
Commands MUST be |
||
@ echo ".compiling" |
||
indented with a TAB |
||
$(CC) $(CFLAGS) main.c |
||
character! |
||
It’s worth emphasizing that forgetting to insert the TAB character before the commands is the most common rookie mistake in using the GNU Make system.
The compilation options being used are:
-I./ |
= |
specifies include directories to search first (project directory in this case) |
-c |
= |
do not invoke the linker, we have a separate make rule for that |
-fno-common = |
gets rid of a pesky warning |
|
-O3 |
= |
sets the optimization level (Note: set to –O0 for debugging!) |
-g |
= |
generates debugging information |
The assembler is used to assemble the file crt.s, as shown below:
crt.o: crt.s
@ echo ".assembling"
$(AS) $(AFLAGS) crt.s > crt.lst
In the example above, if the object file crt.o is older than the dependent assembler source file crt.s, then the commands on the following lines are executed.
If we expand the make variables used, the lines would be:
crt.o: crt.s
@ echo ".assembling"
arm-elf-as -ahls -mapcs-32 -o crt.o crt.s > crt.lst
The > crt.lst directive creates a assembler list file.
The assembler options being used are:
-ahls |
= |
listing control, turns on high-level source, assembly and symbols |
-mapcs-32 |
= |
selects 32-bit ARM function calling method |
-o crt.o |
= |
create an object output file named crt.o |
The GNU linker is used to prepare the output from the assembler and C compiler for loading into Flash and RAM, as shown below:
main.out: crt.o main.o demo2106_blink_flash.cmd @ echo "..linking"
$(LD) $(LFLAGS) -o main.out crt.o main.o
If the target output file main.out is older than the two object files or the linker command file, then the commands on the following lines are executed.
The Linker options being used are:
-Map main.map |
= |
creates a map file |
-T demo2106_blink_flash.cmd = identifies the name of the linker script file
Note that I’ve kept this GNU makefile as simple as possible. You can clearly see the assembler, C compiler and linker steps. They are followed by the objcopy utility that makes the hex file for the Philips ISP boot loader and an objdump operation to give a nice file of all symbols, etc.
17 Compiling and Linking the Sample Application
OK, now it’s time to actually do something. First, let’s “Clean” the project; this gets rid of all object and list files, etc. Click on “Project – Clean …” and fill out the Clean dialog window.
To build the project, click on “Project – Build All”. Since we deleted all the object files and the main.out file via the clean operation, this “Build-all” will assemble the crt.s startup file, C compile the main.c function, run the linker and then run the objcopy utility to make a hex file suitable for downloading with the Philips ISP Flash Utility.
We can see the results in the Console Window at the bottom.
18 Setting Up the Hardware
For this tutorial, we’ll be using the Olimex LPC-P2106 Prototype Board. Connect a straight-through 9-pin serial cable from your computer’s COM1 port to the DB-9 connector on the Olimex board. Attach the 9-volt power supply to the PWR connector. Install the BSL jumper and the JTAG jumper.
COM1
Short the BSL jumper to download and program into flash.
Remove the BSL jumper to execute
You can use a standard 9-pin PC serial cable to connect COM1 to the Olimex board.
DB-9
Serial Port
RESET Button
To run the Philips LPC2000 Flash Utility, it’s easiest to just click on the “External Tools” button and its down arrow to pull-down the available tools. Click on “LPC2000 Flash Utility” to start the Philips Boot Loader.
The Philips LPC2000 ISP Flash Programming will start up.
Now fill out the LPC2000 Flash Utility screen. Browse the workspace for the main.hex file. Set the Device to LPC2106. Set the crystal frequency to 14746, as per the Olimex schematic. The default baud rate, COM port and Time-out are OK as is.
Now click on “Upload to Flash” to start the download.
The Philips ISP Flash Utility will now ask you to reset the target system. This is the tiny RST button near the CPU chip.
The download will now proceed; you’ll see a blue progress bar at the bottom and then the status line will say “File Upload Successfully Completed”.
Remove the BSL (boot strap loader) jumper and hit the RST button.
Remove the
BSL jumper
Your application should start up and the LED will start blinking.
To prove that I am as honest as the sky is blue, here it is blinking away!
OK, I admit it; this photo has the reliability of a Bigfoot video!
20 Create a New Project to Run the Code in RAM
Now we will create a new project that will run the blinker code in RAM. Only minor modifications to three files are required. We will show how to run the application using the Philips ISP flash utility. Later, we’ll show how to use this very same RAM-based application with the Eclipse/CDT debugger and a Wiggler JTAG interface.
Using the techniques previously discussed, create a new project named demo2106_blink_ram.
Switch to the C/C++ Perspective and you will see that there are now two projects, although the new one contains no files.
Now using the “File Import” procedure described earlier, fetch the source files for the project demo2106_flash_ram included in the zip distribution for this tutorial.
The files we import are: crt.s demo2106_blink_ram.cmd lpc210x.h
main.c
makefile.mak
Now if you “Clean and Build” you should see a completed project with all the resultant files, as shown below.