29. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
C Startup
It is not possible to directly execute C code, when the processor comes out of
reset. Since, unlike assembly language, C programs need some
basic pre-requisites to be satisfied. This section will describe the
pre-requisites and how to meet the pre-requisites.
We will take the example of C program that calculates the sum of an array as
an example.
And by the end of this section, we will be able to perform the necessary
setup, transfer control to the C code and execute it.
29
30. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
C Startup
a small block of assembly language code that prepares the way for the execution of software written
in a high-level language.
Startup code for C programs usually consists of the following series of actions:
Disable all interrupts.
Copy any initialized data from ROM to RAM.
Zero the uninitialized data area.
Allocate space for and initialize the stack.
Initialize the processor’s stack pointer.
Create and initialize the heap
Enable interrupts.
Call main.
the startup code will also include a few instructions after the call to main. These instructions will be executed only
in the event that the high-level language program exits (i.e., the call to main returns).
30
35. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
Global Variables
When C code is compiled, the compiler places initialized global variables in the .data
section. So just as with the assembly, the .data has to be copied from Flash to RAM.
The C language guarantees that all uninitialized global variables will be initialized to zero.
When C programs are compiled, a separate section called .bss is used for uninitialized
variables. Since the value of these variables are all zeroes to start with, they do not have
to be stored in Flash. Before transferring control to C code, the memory locations
corresponding to these variables have to be initialized to zero.
35
47. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
ARM system emulated with QEMU
qemu-system-arm is the software that emulates a VersatilePB platform
For more information “VersatilePB physical Board’
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dsi0034a/index.html
http://www.arm.com/products/tools/development-boards/versatile-express
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0224i/index.html
47
49. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
Lab: Steps
The QEMU emulator supports the VersatilePB platform, that contains an ARM926EJ-S
core and, among
other peripherals, four UART serial ports;
the first serial port in particular (UART0) works as a terminal
when using the -nographic or “-serial stdio” qemu option. The memory map of the
VersatilePB board is implemented in QEMU in this board-specific C source;
note the address where the UART0 is mapped: 0x101f1000.
49
51. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
Lab: Steps
The QEMU emulator supports the VersatilePB platform, that contains an ARM926EJ-S
core and, among
other peripherals, four UART serial ports;
the first serial port in particular (UART0) works as a terminal
when using the -nographic or “-serial stdio” qemu option. The memory map of the
VersatilePB board is implemented in QEMU in this board-specific C source;
note the address where the UART0 is mapped: 0x101f1000.
51
52. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
To implement the simple “Hello world!”
printing, you should write this test.c file:
52
volatile unsigned int * const UART0DR = (unsigned int *)0x101f1000;
void print_uart0(const char *s) {
while(*s != '0') { /* Loop until end of string */
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
void c_entry() {
print_uart0("Hello world!n");
}
• The volatile keyword is necessary to instruct the compiler that the memory
pointed by UART0DR can
change or has effects independently of the program.
• The unsigned int type enforces 32-bits read and write access.
62. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
To Debug the Code
Using gdb, because QEMU implements a gdb connector using a TCP connection. To do so, run
the emulator with the correct options as follows
$ qemu-system-arm -M versatilepb -m 128M -nographic -s -S -kernel test.bin
This command freezes the system before executing any guest code, and waits for a connection
on the TCP port 1234.
From ARM ToolChan terminal, run arm-none-eabi-gdb and enter the commands:
62
68. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
Makefile 1
68
#prebared by Keroles Shenouda (Learn In Depth)
helloworld: test.c
arm-none-eabi-as -mcpu=arm926ej-s -g startup.s -o startup.o
arm-none-eabi-gcc -c -mcpu=arm926ej-s -g test.c -o test.o
arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf
arm-none-eabi-objcopy -O binary test.elf test.bin
If you put this rule into a file called Makefileor makefileand then type makeon the command line it will execute
the compile command as you have written it in the makefile. Note that makewith no arguments executes the first
rule in the file. Furthermore, by putting the list of files on which the command depends on the first line after the :, make knows
that the rule helloworldOne very important thing to note is that there is a tab before the gcc command in the makefile. There
must be a tab at the beginning of any command, and make will not be happy if it's not there.
73. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
Describe deeply the compilation
process
73
Preprocessing It is the first stage of compilation. It
processes preprocessor directives like include-files,
conditional compilation instructions and macros.
Compilation It is the second stage. It takes the output of
the preprocessor with the source code, and generates
assembly source code.
Assembler stage It is the third stage of compilation. It
takes the assembly source code and produces the
corresponding object code.
Linking It is the final stage of compilation. It takes one or
more object files or libraries and linker script as input and
combines them to produce a single executable file. In doing
so, it resolves references to external symbols, assigns final
addresses to procedures/functions and variables, and revises
code and data to reflect new addresses (a process called
relocation).
File.map
74. https://www.facebook.com/groups/embedded.system.KS/
Follow us
Press
here
#LEARN_IN DEPTH
#Be_professional_in
embedded_system
For example
perform the three separate tasks (compiling, linking,
and locating) also you can automate the build
procedure with makefiles.
The compiler will generate the object files
led.o and blink.o. linker performs the linking
and locating of the object files.
For the third step, locating, there is a linker script
file named viperlite.ld that we input to ld in order to
establish the location of each section
74
The .map file gives a complete listing of all code and data addresses for the final software image. If you
have never seen such a map file before, be sure to take a look at this one before reading on. It provides
information similar to the contents of the linker script described earlier. However, these are results rather
than instructions and therefore include the actual lengths of the sections and the names and locations of the
public symbols found in the relocatable program. We’ll see later how this file can be used as a debugging aid.