I want create a project for the STM32F217IG microcontroller.
Then I installed Eclipse and the GNU for ARM embedded GCC cross compiler. I don't think it is the Code Sourcery one. I used it, because it supports floating point and Code Sourcery does not.
Once I did it I tried creating a really small project with only two sources files: test.c and main.c with only written in both of them:
#include <stdlib.h>
#include <stdio.h>
int main (void)
{
printf("Hello, World!");
return 0;
}
I changed the line command in the project property to replace GCC by arm-none-eabi-gcc and then tried to compile the project.
I did not create any make file myself; I used the automatic creation in Eclipse.
The building seems to be fine, but when it comes to the linker I got the following errors in the console:
make all
'Building target: test3'
'Invoking: Cross GCC Linker'
arm-none-eabi-gcc -o"test3" ./main.o ./test3.o
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0x18): undefined reference to `_sbrk'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text._write_r+0x20): undefined reference to `_write'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text._close_r+0x18): undefined reference to `_close'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to `_fstat'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0x18): undefined reference to `_isatty'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-lseekr.o): In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x20): undefined reference to `_lseek'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-readr.o): In function `_read_r':
readr.c:(.text._read_r+0x20): undefined reference to `_read'
collect2: ld returned 1 exit status
make: *** [test3] Erreur 1
I looked on the Internet, and I found that it may be a syscall problem. But I don't know how do I add this library to my project on Linux.
Is it really it? If yes, how do I fix it? And if not, where do that come from?
As someone suggested, I tried "linking" the C runtime library. On Eclipse it seems I have two solutions to do it:
First on the project properties → C/C++ → Build → Settings → Cross linker → libraries. I just add the letter c
and then the error does not change, but there is -lc
at the end of the command line:
make all
'Building target: test3'
'Invoking: Cross GCC Linker'
arm-none-eabi-gcc -o"test3" ./main.o ./test3.o -lc
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0x18): undefined reference to `_sbrk'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text._write_r+0x20): undefined reference to `_write'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text._close_r+0x18): undefined reference to `_close'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to `_fstat'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0x18): undefined reference to `_isatty'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-lseekr.o): In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x20): undefined reference to `_lseek'
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib\libc.a(lib_a-readr.o): In function `_read_r':
readr.c:(.text._read_r+0x20): undefined reference to `_read'
collect2: ld returned 1 exit status
make: *** [test3] Erreur 1
But I don't know if it is really means to add the C runtime library.
Second, I added the libc.a library in the project properties → C/C++ general → Path and symbols → Libraries, and here is what I get (completely different):
make all
'Building target: test3'
'Invoking: Cross GCC Linker'
arm-none-eabi-gcc -o"test3" ./main.o ./test3.o -l"C:/Program\ Files/GNU\ Tools\ ARM\ Embedded/4.6\ 2012q4/arm-none-eabi/lib/armv7-m/libc.a"
c:/program files/gnu tools arm embedded/4.6 2012q4/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/bin/ld.exe: cannot find -lC:/Program\ Files/GNU\ Tools\ ARM\ Embedded/4.6\ 2012q4/arm-none-eabi/lib/armv7-m/libc.a
collect2: ld returned 1 exit status
make: *** [test3] Erreur 1
Then it still does not work, but is it the good way to search on?
Oh and a very interesting fact:
I got the errors only in debug mode. If I am in release mode everything is okay, and I don't have any errors (except if I add the libc.a then I think this is not the good thing to do). Does that mean the problem is the .elf file creation?
I've looked at the toolkit you linked, just to read the following in the readme.txt
:
This toolchain is built and optimized for Cortex-R/M bare metal development.
In other words, this toolchain is specifically configured for embedded systems, perhaps with no operating system running at all. In such case, there's no system to provide e.g. standard output where printf()
is supposed to write, there's no file system, etc. - you have to link against some library providing these basic services, if you want to use them.
That said, your toolkit provides librdimon.a
library which provides all those basic services. This library is actually a part of libgloss compilation. If you want to link against it, try the following command:
arm-none-eabi-gcc --specs=rdimon.specs -Wl,--start-group -lgcc -lc -lm -lrdimon -Wl,--end-group -o test test.c
This links fine on my PC, but whether it's what you really want is another story (where do you expect to see printf()
output, anyway?).
For you chip you should probably look for a library which redirects the standard output to serial port or provides debug output over JTAG. Alternatively, you can use your custom function e.g. sending debug output to serial console instead of printf()
- it's up to you.
If you decide on using printf()
I suggest reading libgloss
documentation.
Also, I suggest looking around for a toolchain which is specifically bundled for STM32 family. Properly configuring all this basic stuff (C library, linker script, etc.) requires a bit of experience.
Edit: Many embedded systems doesn't really use standard C library, starting pretty much from scratch. If you want to go this way, you should pass -nostdlib
to your gcc
invocation. Of course, you'll no longer have things like printf()
available.
Edit 2: Another way is to use standard library (newlib
, I mean) without libgloss
and provide appropriate stubs for things you do not need. You might want to follow this tutorial, where _read
and _write
is implemented over the serial port, and everything else is stubbed. This is most likely what you really want.