ARM GCC: Unterschied zwischen den Versionen

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche
(Controller-unspezifisches über den GCC für ARM.)
 
 
(20 dazwischenliegende Versionen von 10 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Der [[GCC]] kann auch für [[ARM]] konfiguriert werden. Es gibt diverse fertige Binärdistributionen die für verschiedene Controller mit ARM-Kern verwendet werden können.
ARM-GCC bezeichnet die für [[ARM]]-Mikrocontroller konfigurierte Variante des C- und C++- [[Compiler|Crosscompilers]] GCC.
== GCC Binärdistributionen ==
 
* [http://www.codesourcery.com/gnu_toolchains/arm CodeSourcery CodeBench Lite] Windows, Linux
In diesem Artikel geht es primär um den arm-none-eabi-gcc, der ein für embedded Systems optimiertes ABI (Application Binary Interface) hat. Für ARM-System, die ein eigenständiges OS (wie Linux) haben, gibt es den arm-elf-gcc.
* [https://launchpad.net/gcc-arm-embedded GCC-ARM-Embedded] für Cortex-R4/R5/M0/M3/M4(F)/M0+. Windows, Linux, Mac, bereitgestellt von ARM selbst,  vollständiger Support für FPU's, C++11, kein Code-Size-Limit
 
* [[ARM GCC toolchain for Linux and Mac OS X]]
Es gibt diverse fertige Binärdistributionen die für verschiedene Controller mit ARM-Kern verwendet werden können.  
* [http://www.yagarto.de/ Yagarto] (Windows, mit Eclipse-Integration),
 
* [http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/#winarm WinARM] (wird derzeit nicht gepflegt)
== Bestandteile ==
* [http://gnuarm.com/ GNUARM] (Linux, Windows, wird derzeit nicht gepflegt)
Die Toolchain besteht aus mehreren Kommandozeilen-Programmen, die sich auf einfache Weise in einen Editor oder eine Entwicklungsumgebung einbinden lassen. Weit verbreitet ist die Verwendung von make zur Steuerung.
 
Die Bestandteile im einzelnen:
* Binutils: Assembler, Linker und weitere Hilfsprogramme.
* GCC: Der eigentliche C(++)-Compiler.
* eine C-Standardbibliothek
 
Die vorherrschende C-Bibliothek ist die [https://sourceware.org/newlib/ newlib] (oder auch [https://github.com/32bitmicro/newlib-nano-1.0 newlib-nano]), für andere Optionen siehe [http://wiki.osdev.org/C_Library#Implementations hier].


Bei der Auswahl der Toolchain sollte beachtet werden, dass es größere Unterschiede bei den bereitgestellten C-Bibliotheken gibt. Die Sourcery Codebench Lite-Edition stellt z.B. keine Bibliotheken mit FPU-Unterstützung bereit, so dass trotz vorhandener FPU beim Cortex-M4 nur suboptimaler Code erzegt werden kann. Siehe [http://wiki.debian.org/ArmHardFloatPort/VfpComparison] für ein kleines Beispiel und eine Erklärung.
Bei der Auswahl der Toolchain sollte beachtet werden, dass es größere Unterschiede bei den bereitgestellten C-Bibliotheken gibt. Die Sourcery Codebench Lite-Edition stellt z.B. keine Bibliotheken mit FPU-Unterstützung bereit, so dass trotz vorhandener FPU beim Cortex-M4 nur suboptimaler Code erzegt werden kann. Siehe [http://wiki.debian.org/ArmHardFloatPort/VfpComparison] für ein kleines Beispiel und eine Erklärung.


Die im Netz häufig anzutreffende summon-arm Toolchain hat einen der seltenen Compiler-Bugs [http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg353473.html] und sollte daher nicht verwendet werden, wenn man floatingpoint-Typen einsetzen möchte. Egal ob mit oder ohne FPU.
== Fertige GCC Binärdistributionen ==
* [https://developer.arm.com/open-source/gnu-toolchain/gnu-rm GCC-ARM-Embedded] ([https://launchpad.net/gcc-arm-embedded Ältere Releases]) für Cortex-R4/R5/R7/R8/M0(+)/M3/M4(F)/M7/M23/M33. Windows, Linux, Mac, bereitgestellt von ARM selbst, vollständiger Support für FPUs, C++17, kein Code-Size-Limit
* [https://bugs.launchpad.net/gcc-arm-embedded/+bug/1742188 Windows Windows 64bit Binaries] vom GCC-ARM-Embedded und Anleitung zum Selbstkompilieren; nützlich für extrem speicherhungrige Kompilationen (z.B. bei templates)
* [http://www.mentor.com/embedded-software/codesourcery Mentor Graphics Sourcery Tools (vormals CodeSourcery CodeBench Lite)] Windows, Linux
* [http://sourceforge.net/projects/devkitpro/ devkitPro]
* [http://www.lpcware.com/lpcxpresso/home LPCXpresso] (vormals CodeRed IDE) ist eine IDE von NXP für die LPC-Mikrocontroller die den GCC enthält
* [http://www.yagarto.de/ Yagarto] (Windows, mit Eclipse-Integration) - veraltet
* [http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/#winarm WinARM] - veraltet
* GNUARM - veraltet
* summon-arm Toolchain: hat einen Compiler-Bug [http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg353473.html] und sollte daher nicht verwendet werden, wenn man floatingpoint-Typen einsetzen möchte (egal ob mit oder ohne FPU).


Beim Einsatz des gcc in Verbindung mit in C geschriebenem startup-Code bei den Optimierungslevels "-O2" und "-O3" muss zusätzlich "-fno-gcse" gesetzt werden, da ansonsten die von der CPU benötigte NVIC-Tabelle(n) und zugehörige Funktionen u.U. nicht so aussehen wie sie sollten.
Beim Einsatz des gcc in Verbindung mit in C geschriebenem startup-Code bei den Optimierungsleveln "-O2" und "-O3" muss zusätzlich "-fno-gcse" gesetzt werden, da ansonsten die von der CPU benötigte NVIC-Tabelle(n) und zugehörige Funktionen unter Umständen nicht so aussehen wie sie sollten.
 
Siehe auch [http://embdev.net/topic/129986#1175214 ARM-GCC development resources] im Forum.


== Nutzung mit eigener Umgebung/Kommandozeile ==
== Nutzung mit eigener Umgebung/Kommandozeile ==
Hier einige Hinweise wie man den GCC direkt verwenden kann (zB. mit selbstgebautem makefile), falls man das nicht von einer Entwicklungsumgebung machen lässt.
Hier einige Hinweise wie man den GCC direkt verwenden kann (zB. mit selbstgebautem makefile), falls man das nicht von einer Entwicklungsumgebung machen lässt.
=== Compiler & Linker Flags ===
=== Compiler & Linker Flags ===
Für Eilige, zum Copy&Pasten. Detailinformationen gibt es in der [http://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html#Option-Summary GCC Dokumentation], auch [http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html#ARM-Options speziell für ARM].
Die Flags, die festlegen, welcher Core verwendet wird, sind in der folgenden Tabelle beschrieben:
* Mit Optimierungen:
{| class="wikitable"
{| class="wikitable"
! Option
! style="text-align: center;" | Cortex-M0
! style="text-align: center;" | Cortex-M0+
! style="text-align: center;" | Cortex-M3
! style="text-align: center;" | Cortex-M4
! style="text-align: center;" | Cortex-M7
! style="text-align: center;" | Cortex-M33
! style="text-align: center;" | Cortex-M23
|-
|-
! Tool/Sprache                                          !! Cortex-M3                      !! Cortex-M4F
| CPU
| -mcpu=cortex-m0<sup>[1]</sup>
| -mcpu=cortex-m0plus<sup>[1]</sup>
| -mcpu=cortex-m3
| -mcpu=cortex-m4
| -mcpu=cortex-m7
| -mcpu=cortex-m33
| -mcpu=cortex-m23
|-
|-
| C-Compiler (gcc) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -Os -flto || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -Os -flto
| Float ABI
| colspan="3" style="text-align: center;" | -mfloat-abi=soft
| colspan="3" style="text-align: center;" | -mfloat-abi=soft
 
-mfloat-abi=softfp
 
-mfloat-abi=hard
| style="text-align: center;" | -mfloat-abi=soft
|-
|-
| C++ Compiler (g++) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -Os -flto -fno-rtti -fno-exceptions || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -Os -flto -fno-rtti -fno-exceptions
| FPU
|-
| colspan="3" |  
| Assembler (as) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
| -mfpu=fpv4-sp-d16
|-
| -mfpu=fpv5-d16
| Linken von C Code (mit gcc-Befehl) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -Os -flto -Wl,--gc-sections -static || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -Os -flto -Wl,--gc-sections -static
| -mfpu=fpv5-sp-d16 / -mfpu=fpv5-d16
|-
|  
| Linken von C++ (und C) Code (mit g++-Befehl) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -Os -flto -fno-rtti -fno-exceptions -Wl,--gc-sections -static || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -Os -flto -fno-rtti -fno-exceptions -Wl,--gc-sections -static
|-
|-
| Instruction Set
| colspan="7" style="text-align: center;" | -mthumb
|}
|}
* Ohne Optimierungen, mit Debug-Informationen:
<sup>[1]</sup><small>Anmerkung: Es gibt für diese Cores 2 Optionen (für den Hersteller): diese Betreffen die Multiplikationsbefehle.
* Die übliche Implementierung enthält einen 1-Takt-Multiplizierer
* Für reduzierte Chipfläche kann auche ein 32-Takt-Multiplizierer ausgewählt werden
Um nun bei Multiplikationen mit Konstanten nicht die langsame 32-Takt-Multiplikation zu nutzen kann der Compiler angewiesen werden, dort Shifts oder Ähnliches zu generieren.
Um dem Compiler das mitzuteilen wird der Parameter, der die CPU angibt, abgeändert: -mcpu=cortex-m0[plus].small-multiply</small>
 
Zusätzlich zu diesen Flags gibt es noch die Maschinenunabhängigen Parameter, wovon hier nur einige wichtigen erläutert werden:
 
{| class="wikitable"
{| class="wikitable"
! style="width: 20% | Option !! Erklärung
|-
|-
! Tool/Sprache                                          !! Cortex-M3                      !! Cortex-M4F
| -W[all, extra]
| Lässt den Compiler Warnungen ausgeben.
-Wall gibt nur Standard-Warnungen aus, nicht alle!
-Wextra erzeugt noch einmal mehr Warnungen.
|-
|-
| C-Compiler (gcc) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -g || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -g
| -O[0,1,2,3,s,g]
| Wählt die Art der Optimierung.
-O0: keine Optimierung
-O[1,2,3]: Optimierung auf Ausführungsgeschwindigkeit. Je höher die Stufe, desto aggressiver ist die Optimierung. Das führt unter Umständen zu beträchtlich größerem Code
-Os: Optimierung auf Codegröße
-Og: Optimierung, aber so, dass das Debugging nicht erschwert wird
|-
|-
| C++ Compiler (g++) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -g -fno-rtti -fno-exceptions || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -g -fno-rtti -fno-exceptions
| -fdata-sections
-ffunction-sections
| Teilt jeder Funktion/jeder Variable eine eigene Section zu.Damit kann der Linker mit der Option --gc-sections ungenutzte Funktionen entfernen. Siehe [[GCC:_unbenutzte_Funktionen_entfernen]]
|-
|-
| Assembler (as) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
| -Wl,--gc-sections
| Der Linker verwirft unreferenzierte Sections und packt diese damit nicht ins Binary. Siehe [[GCC:_unbenutzte_Funktionen_entfernen]]
|-
|-
| Linken von C Code (mit gcc-Befehl) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -g -Wl,--gc-sections -static || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -g -Wl,--gc-sections -static
| -g
| Erzeugt Debugging-Informationen.
Siehe auch [https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html GCC Debugging Options]
|-
|-
| Linken von C++ (und C) Code (mit g++-Befehl) || -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -ffunction-sections -fdata-sections -g -fno-rtti -fno-exceptions -Wl,--gc-sections -static || -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -ffunction-sections -fdata-sections -g -fno-rtti -fno-exceptions -Wl,--gc-sections -static
| -fno-rtti
-fno-exceptions
| C++-Optionen
Teilt dem Compiler mit, dass
- keine Runtime Type Information zu generieren sind
- keine Exceptions benutzt werden und damit kein Overhead generiert werden muss.
|-
|-
| -flto
| Link-Time-Optimizations:
Der Linker optimiert den kompletten Code. Da er nicht nur ein Source-File, sondern alle kennt, kann er optimieren, wo dem Compiler  Informationen fehlen.
Achtung: bei älteren Compiler-Versionen muss nach diesem Flag noch einmal die Optimierungsstufe angegeben werden.
|}
|}
Die [http://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html#Option-Summary GCC Dokumentation] listet alle Parameter auf, auch [http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html#ARM-Options Parameter speziell für ARM].


* Siehe auch das [https://launchpadlibrarian.net/135588846/readme.txt Readme vom GCC-ARM-Embedded]
* Siehe auch das [https://launchpadlibrarian.net/135588846/readme.txt Readme vom GCC-ARM-Embedded]
Zeile 55: Zeile 127:
* Die LTO erkennt die ISR's und den Interrupt Vector möglicherweise als "unbenutzt" und optimiert sie daher weg. Dies kann durch Markierung der Funktionen & Variablen mit  "__attribute__ ((used))" verhindert werden.
* Die LTO erkennt die ISR's und den Interrupt Vector möglicherweise als "unbenutzt" und optimiert sie daher weg. Dies kann durch Markierung der Funktionen & Variablen mit  "__attribute__ ((used))" verhindert werden.
* Alle Compileroptionen müssen auch beim Linken mit angegeben werden (ist in obiger Tabelle berücksichtigt), da auch dann u.U. Code generiert werden kann.
* Alle Compileroptionen müssen auch beim Linken mit angegeben werden (ist in obiger Tabelle berücksichtigt), da auch dann u.U. Code generiert werden kann.
=== Startupcode & Linkerscript ===
=== Startupcode & Linkerscript ===
* Damit der compilierte Code an den richtigen Stellen im Controller landet (d.h. dem Flash) muss man dem Linker ein Linkerscript mitgeben. Dies geht per "-T ''pfad_zum_linkerscript.ld''" an den Linker-Befehl. Das Script ist praktisch Controller-spezifisch, es gibt Beispiel-Scripte der Controller-Hersteller.
* Damit der compilierte Code an den richtigen Stellen im Controller landet (d.h. dem Flash) muss man dem Linker ein Linkerscript mitgeben. Dies geht per "-T ''pfad_zum_linkerscript.ld''" an den Linker-Befehl. Das Script ist praktisch Controller-spezifisch, es gibt Beispiel-Scripte der Controller-Hersteller.
* Damit beim Starten die richtigen Initialisierungen vorgenommen werden (wie globale Variablen und bei C++ Konstruktoren globaler Objekt-Instanzen) muss als erstes ein Startupcode laufen, der dann die main()-Funktion aufruft. Der Startupcode ist meistens in Assembler geschrieben, C/C++-Code ist aber auch möglich. Assemblercode kann per arm-none-eabi-as (Flags s.o.) assemblisiert werden, die resultierende .o -Datei normal mitgelinkt. Auch für den Startupcode gibt es Beispiele der Controller-Hersteller.
* Damit beim Starten die richtigen Initialisierungen vorgenommen werden (wie globale Variablen und bei C++ Konstruktoren globaler Objekt-Instanzen) muss als erstes ein Startupcode laufen, der dann die main()-Funktion aufruft. Startupcode im allgemeinen ist meistens in Assembler geschrieben, aber die ARM-Architektur macht aber auch einfacheren C/C++-Code möglich. Auch für den Startupcode gibt es Beispiele der Controller-Hersteller.


Zusammen bieten die beiden Dateien der Anwendung ein Standard-C-Interface, d.h. man kann wie gewohnt globale Variablen verwenden und seinen Code in die main()-Funktion schreiben.
Zusammen bieten die beiden Dateien der Anwendung ein Standard-C-Interface, d.h. man kann wie gewohnt globale Variablen verwenden und seinen Code in die main()-Funktion schreiben.
=== FPU der Cortex-M4F nutzen ===
=== FPU der Cortex-M4F nutzen ===
Um die FPU zu nutzen, muss dem Compiler per [[#Compiler_.26_Linker_Flags|Flag]] dazu gebracht werden, FPU-Instruktionen zu generieren.
Um die FPU zu nutzen, muss der Compiler per [[#Compiler_.26_Linker_Flags|Flag]] dazu gebracht werden, FPU-Instruktionen zu generieren.


Außerdem muss vor Benutzung der FPU-Befehle die FPU aktiviert werden, dies geschieht typischerweise im Startupcode, bevor die main() -Funktion aufgerufen wird. Hier die entsprechenden Befehle, falls sie im verwendeten Startupcode nicht onehin schon enthalten sind:
Außerdem muss vor Benutzung der FPU-Befehle die FPU aktiviert werden, dies geschieht typischerweise im Startupcode, bevor die main() -Funktion aufgerufen wird. Hier die entsprechenden Befehle, falls sie im verwendeten Startupcode nicht onehin schon enthalten sind:
<pre>/*FPU settings*/
<syntaxhighlight lang="asm">/*FPU settings*/
  ldr    r0, =0xE000ED88          /* Enable CP10,CP11 */
  ldr    r0, =0xE000ED88          /* Enable CP10,CP11 */
  ldr    r1,[r0]
  ldr    r1,[r0]
  orr    r1,r1,#(0xF << 20)
  orr    r1,r1,#(0xF << 20)
  str    r1,[r0]</pre>
  str    r1,[r0]
</syntaxhighlight>
In C/C++ unter Verwendung der CMSIS geht es so:
In C/C++ unter Verwendung der CMSIS geht es so:
<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
Zeile 74: Zeile 149:
</syntaxhighlight>
</syntaxhighlight>


Weiterhin sollte die GCC-Distribution auch Laufzeitbibliotheken mit FPU-Unterstützung mitbringen (CodeBench lite und Yagarto werden ohne ausgeleifert, GCC-ARM-Embedded mit).
Weiterhin sollte die GCC-Distribution auch Laufzeitbibliotheken mit FPU-Unterstützung mitbringen (CodeBench lite und Yagarto werden ohne ausgeliefert, GCC-ARM-Embedded mit).


Am Beispiel der STM32F4 mehr dazu in diesem Thread: [http://www.mikrocontroller.net/topic/261021 Floating Pointing Unit STM32F4]
Am Beispiel der STM32F4 mehr dazu in diesem Thread: [http://www.mikrocontroller.net/topic/261021 Floating Pointing Unit STM32F4]
=== Disassemblieren mit GCC ===
arm-none-eabi-objdump -d -t -C pfad_zum_binary.elf


=== Konvertieren zwischen Binary-Formaten beim GCC ===
== Links ==
arm-none-eabi-objcopy -O ''ausgabeformat'' ''eingabe_binary.elf'' ''ausgabe_binary''
* [http://www.mikrocontroller.net/topic/298976#3197418 Hier] finden sich noch ein paar Tipps, für den 1. kann aber mittlerweile der GCC-ARM-Embedded direkt verwendet werden, da er jetzt LTO unterstützt (s.o.).
* [https://www.mikrocontroller.net/topic/178840 Thread]: Unterschied arm-none-eabi-gcc und arm-elf-gcc


Nützlich als Ausgabeformat sind z.B. "ihex" oder "binary".
[[Category:ARM]]
=== Code-Größe optimieren ===
[[Category:Compiler]]
Obige Flags (insbesondere -flto und -Os) verwenden. [http://www.mikrocontroller.net/topic/298976#3197418 Hier] finden sich noch ein par Tips, für den 1. kann aber mittlerweile der GCC-ARM-Embedded direkt verwendet werden, da er jetzt LTO unterstützt (s.o.).

Aktuelle Version vom 5. Juni 2020, 06:30 Uhr

ARM-GCC bezeichnet die für ARM-Mikrocontroller konfigurierte Variante des C- und C++- Crosscompilers GCC.

In diesem Artikel geht es primär um den arm-none-eabi-gcc, der ein für embedded Systems optimiertes ABI (Application Binary Interface) hat. Für ARM-System, die ein eigenständiges OS (wie Linux) haben, gibt es den arm-elf-gcc.

Es gibt diverse fertige Binärdistributionen die für verschiedene Controller mit ARM-Kern verwendet werden können.

Bestandteile

Die Toolchain besteht aus mehreren Kommandozeilen-Programmen, die sich auf einfache Weise in einen Editor oder eine Entwicklungsumgebung einbinden lassen. Weit verbreitet ist die Verwendung von make zur Steuerung.

Die Bestandteile im einzelnen:

  • Binutils: Assembler, Linker und weitere Hilfsprogramme.
  • GCC: Der eigentliche C(++)-Compiler.
  • eine C-Standardbibliothek

Die vorherrschende C-Bibliothek ist die newlib (oder auch newlib-nano), für andere Optionen siehe hier.

Bei der Auswahl der Toolchain sollte beachtet werden, dass es größere Unterschiede bei den bereitgestellten C-Bibliotheken gibt. Die Sourcery Codebench Lite-Edition stellt z.B. keine Bibliotheken mit FPU-Unterstützung bereit, so dass trotz vorhandener FPU beim Cortex-M4 nur suboptimaler Code erzegt werden kann. Siehe [1] für ein kleines Beispiel und eine Erklärung.

Fertige GCC Binärdistributionen

Beim Einsatz des gcc in Verbindung mit in C geschriebenem startup-Code bei den Optimierungsleveln "-O2" und "-O3" muss zusätzlich "-fno-gcse" gesetzt werden, da ansonsten die von der CPU benötigte NVIC-Tabelle(n) und zugehörige Funktionen unter Umständen nicht so aussehen wie sie sollten.

Siehe auch ARM-GCC development resources im Forum.

Nutzung mit eigener Umgebung/Kommandozeile

Hier einige Hinweise wie man den GCC direkt verwenden kann (zB. mit selbstgebautem makefile), falls man das nicht von einer Entwicklungsumgebung machen lässt.

Compiler & Linker Flags

Die Flags, die festlegen, welcher Core verwendet wird, sind in der folgenden Tabelle beschrieben:

Option Cortex-M0 Cortex-M0+ Cortex-M3 Cortex-M4 Cortex-M7 Cortex-M33 Cortex-M23
CPU -mcpu=cortex-m0[1] -mcpu=cortex-m0plus[1] -mcpu=cortex-m3 -mcpu=cortex-m4 -mcpu=cortex-m7 -mcpu=cortex-m33 -mcpu=cortex-m23
Float ABI -mfloat-abi=soft -mfloat-abi=soft

-mfloat-abi=softfp

-mfloat-abi=hard

-mfloat-abi=soft
FPU -mfpu=fpv4-sp-d16 -mfpu=fpv5-d16 -mfpu=fpv5-sp-d16 / -mfpu=fpv5-d16
Instruction Set -mthumb

[1]Anmerkung: Es gibt für diese Cores 2 Optionen (für den Hersteller): diese Betreffen die Multiplikationsbefehle.

  • Die übliche Implementierung enthält einen 1-Takt-Multiplizierer
  • Für reduzierte Chipfläche kann auche ein 32-Takt-Multiplizierer ausgewählt werden

Um nun bei Multiplikationen mit Konstanten nicht die langsame 32-Takt-Multiplikation zu nutzen kann der Compiler angewiesen werden, dort Shifts oder Ähnliches zu generieren. Um dem Compiler das mitzuteilen wird der Parameter, der die CPU angibt, abgeändert: -mcpu=cortex-m0[plus].small-multiply

Zusätzlich zu diesen Flags gibt es noch die Maschinenunabhängigen Parameter, wovon hier nur einige wichtigen erläutert werden:

Option Erklärung
-W[all, extra] Lässt den Compiler Warnungen ausgeben.

-Wall gibt nur Standard-Warnungen aus, nicht alle! -Wextra erzeugt noch einmal mehr Warnungen.

-O[0,1,2,3,s,g] Wählt die Art der Optimierung.

-O0: keine Optimierung -O[1,2,3]: Optimierung auf Ausführungsgeschwindigkeit. Je höher die Stufe, desto aggressiver ist die Optimierung. Das führt unter Umständen zu beträchtlich größerem Code -Os: Optimierung auf Codegröße -Og: Optimierung, aber so, dass das Debugging nicht erschwert wird

-fdata-sections

-ffunction-sections

Teilt jeder Funktion/jeder Variable eine eigene Section zu.Damit kann der Linker mit der Option --gc-sections ungenutzte Funktionen entfernen. Siehe GCC:_unbenutzte_Funktionen_entfernen
-Wl,--gc-sections Der Linker verwirft unreferenzierte Sections und packt diese damit nicht ins Binary. Siehe GCC:_unbenutzte_Funktionen_entfernen
-g Erzeugt Debugging-Informationen.

Siehe auch GCC Debugging Options

-fno-rtti

-fno-exceptions

C++-Optionen

Teilt dem Compiler mit, dass - keine Runtime Type Information zu generieren sind - keine Exceptions benutzt werden und damit kein Overhead generiert werden muss.

-flto Link-Time-Optimizations:

Der Linker optimiert den kompletten Code. Da er nicht nur ein Source-File, sondern alle kennt, kann er optimieren, wo dem Compiler Informationen fehlen. Achtung: bei älteren Compiler-Versionen muss nach diesem Flag noch einmal die Optimierungsstufe angegeben werden.

Die GCC Dokumentation listet alle Parameter auf, auch Parameter speziell für ARM.

  • Siehe auch das Readme vom GCC-ARM-Embedded
  • Um das -flto -Flag verwenden zu können, muss der GCC LTO unterstützen. Beim GCC-ARM-Embedded ist dies ab Version 4.7-2013-q2-update der Fall.
  • Die LTO erkennt die ISR's und den Interrupt Vector möglicherweise als "unbenutzt" und optimiert sie daher weg. Dies kann durch Markierung der Funktionen & Variablen mit "__attribute__ ((used))" verhindert werden.
  • Alle Compileroptionen müssen auch beim Linken mit angegeben werden (ist in obiger Tabelle berücksichtigt), da auch dann u.U. Code generiert werden kann.

Startupcode & Linkerscript

  • Damit der compilierte Code an den richtigen Stellen im Controller landet (d.h. dem Flash) muss man dem Linker ein Linkerscript mitgeben. Dies geht per "-T pfad_zum_linkerscript.ld" an den Linker-Befehl. Das Script ist praktisch Controller-spezifisch, es gibt Beispiel-Scripte der Controller-Hersteller.
  • Damit beim Starten die richtigen Initialisierungen vorgenommen werden (wie globale Variablen und bei C++ Konstruktoren globaler Objekt-Instanzen) muss als erstes ein Startupcode laufen, der dann die main()-Funktion aufruft. Startupcode im allgemeinen ist meistens in Assembler geschrieben, aber die ARM-Architektur macht aber auch einfacheren C/C++-Code möglich. Auch für den Startupcode gibt es Beispiele der Controller-Hersteller.

Zusammen bieten die beiden Dateien der Anwendung ein Standard-C-Interface, d.h. man kann wie gewohnt globale Variablen verwenden und seinen Code in die main()-Funktion schreiben.

FPU der Cortex-M4F nutzen

Um die FPU zu nutzen, muss der Compiler per Flag dazu gebracht werden, FPU-Instruktionen zu generieren.

Außerdem muss vor Benutzung der FPU-Befehle die FPU aktiviert werden, dies geschieht typischerweise im Startupcode, bevor die main() -Funktion aufgerufen wird. Hier die entsprechenden Befehle, falls sie im verwendeten Startupcode nicht onehin schon enthalten sind:

/*FPU settings*/
 ldr     r0, =0xE000ED88           /* Enable CP10,CP11 */
 ldr     r1,[r0]
 orr     r1,r1,#(0xF << 20)
 str     r1,[r0]

In C/C++ unter Verwendung der CMSIS geht es so:

SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */

Weiterhin sollte die GCC-Distribution auch Laufzeitbibliotheken mit FPU-Unterstützung mitbringen (CodeBench lite und Yagarto werden ohne ausgeliefert, GCC-ARM-Embedded mit).

Am Beispiel der STM32F4 mehr dazu in diesem Thread: Floating Pointing Unit STM32F4

Links

  • Hier finden sich noch ein paar Tipps, für den 1. kann aber mittlerweile der GCC-ARM-Embedded direkt verwendet werden, da er jetzt LTO unterstützt (s.o.).
  • Thread: Unterschied arm-none-eabi-gcc und arm-elf-gcc