STM32 Eclipse JLink Linux/Windows

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Einführung

Da viele Tutorials zur Verwendung von Eclipse mit STM32 auf relativ alten Tools aufsetzen, hier eine Anleitung mit aktuellem (2015) Stand. Hier wird die Programmierung von STM32 (ähnlich auch auf andere Cortex-M anwendbar) mit der Tool-Kombination Eclipse + Segger JLink + GCC-ARM-Embedded + GDB erläutert für Linux und Windows. Die Tools gibt es auch für Mac OS, entsprechende Hinweise zur Benutzung fehlen hier noch. Der J-Link ist zwar relativ teuer (ca. 50€ für Privatpersonen), dafür aber schnell und stabil, kennt (fast?) alle ARM's und funktioniert plattformübergreifend direkt mit der Software vom Hersteller. Diese Kombination ermöglicht:

  • Nutzung der komfortablen und mächtigen Entwicklungsumgebung Eclipse, inkl. Code-Vervollständigung und vielen Plugins wie zB. für Versionsverwaltung
  • Automatische Generierung von makefiles und Aufruf des Compilers, kein manuelles Bearbeiten erforderlich
  • Graphisches und schnelles Flashen und Debugging über JLink und GDB
  • Graphische Anzeige von Registerinhalten beim Debugging
  • Optional: Ausgabe von Texten per printf direkt nach Eclipse
  • Volle Unterstützung der neuen Sprachstandards C11 und C++11
  • Projekte können zwischen Betriebssystemen ausgetauscht werden, Workflow generell fast identisch
  • Voller Support für FPU der Cortex-M4, voller Support für C++, kein Codesize-Limit
  • Es werden generische C/C++ Projekte angelegt; dies ist zwar etwas komplizierter, bietet aber später mehr Einstellungsmöglichkeiten
  • Die Software ist auch für kommerzielle Nutzung komplett gratis und bis auf JLink auch OpenSource. Nur der JLink-Adapter selber ist für kommerzielle Nutzung teurer (aber das ist er bei Verwendung mit anderen IDE's natürlich auch).
  • Da die normale und keine angepasste Eclipse-Version verwendet wird, können in der selben Eclipse-Instanz auch Projekte für völlig andere Plattformen und Sprachen benutzt werden, wie z.B. C/C++ für den PC, Java, ruby usw.

Da Eclipse eine sehr vielseitige Entwicklungsumgebung ist, sind einige Schritte erforderlich, um das Projekt auf die speziellen Anforderungen der Embedded-Entwicklung anzupassen. Diese sind im Folgenden erläutert.

Installation

Beim Durcharbeiten der nachfolgenden Anleitung ist es empfehlenswert auch immer wieder einen Blick auf die Anweisungen und Beschreibungen auf der GNU ARM Eclipse Homepage zu werfen, da die Vorgehensweise dort gut beschrieben ist und sich, je nach Plugin-Version, auch gelegentlich ändert.

JLink

Zunächst die aktuelle Version von der JLink Software herunterladen und installieren. Da es hier regelmäßig neue Versionen gibt, ist es empfehlenswert sich für die E-Mail-Benachrichtigung für neue Versionen einzutragen. Das Installationsverzeichnis für später merken.

GCC-ARM-Embedded

Die aktuelle Version für das jeweilige Betriebssystem herunterladen und entpacken. Es gibt zwar auch Versionen in der Paketverwaltung mancher Linux-Distributionen aber die sind oft veraltet. Dafür bitte einen kurzen Pfad ohne Leerzeichen verwenden:

  • Windows: z.B. C:\gcc-arm-embedded
  • Linux: z.B. "/home/username/gcc-arm-embedded"

Den Pfad für später merken.

Make

  • Linux: Meistens vorinstalliert. Unter Ubuntu im Paket "build-essential" enthalten.
  • Windows: Hier können die MinGW/MSYS Basis Tools verwendet werden:
    • Dazu hier den MinGW Installer herunterladen und ausführen.
    • Als Installation Directory am besten "C:\MinGW" beibehalten.
    • So oft "Continue" anklicken, bis der "MinGW Installation Manager" erscheint und eine Liste installierbarer Pakete anzeigt.
    • In der Liste das Paket "msys-base" mit der rechten Maustaste anklicken und "Mark for Installation" anklicken
    • Im Menü "Installation"->"Apply Changes" anklicken, und mit "Apply" bestätigen.
    • Nachdem der Vorgang abgeschlossen ist, das Programm beenden

Pfade setzen

Vor dem Starten von Eclipse müssen dem System die Pfade der Kommandozeilentools bekannt gemacht werden:

  • Windows:
    • Rechte Maustaste auf den Arbeitsplatz klicken, "Eigenschaften" -> "Erweiterte Systemeinstellungen" -> "Umgebungsvariablen" anklicken.
    • Im unteren Listenfeld den Eintrag "Path" suchen, auf "Bearbeiten" klicken
    • Ans Ende des Textes ein Semikolon hängen (falls nicht schon vorhanden), und durch zwei Semikola getrennt die Pfade zur J-Link Installation, zur GCC-ARM-Embedded -Installation (plus "\bin") und zur MSYS-Installation anhängen. Also zum Beispiel folgenden Text anhängen (Version anpassen) und alles mit OK bestätigen:

;C:\gcc-arm-embedded\bin;C:\Program Files (x86)\SEGGER\JLink_V500e;C:\MinGW\msys\1.0\bin

    • In einem danach erst gestarteten cmd.exe Fenster den Befehl "JLink" eingeben. Es sollte die Lizenzvereinbarung von Segger erscheinen (diese bestätigen), und im Terminal wieder "exit" eingeben. Funktioniert dies nicht, wurde die Umgebungsvariable falsch gesetzt.
    • Im selben Fenster "arm-none-eabi-gcc" eingeben. Es sollte eine Meldung im Stil von "arm-none-eabi-gcc: fatal error: no input files" erscheinen. Falls nicht, wurde die Umgebungsvariable falsch gesetzt.
    • Im selben Fenster "make" eingeben. Es sollte ein Meldung in der Art von "make: *** No targets specified and no makefile found. Stop." erscheinen. Falls nicht, wurde die Umgebungsvariable falsch gesetzt.
  • Linux:
    • Mit einem Texteditor die (versteckte) Datei ".profile" im Home-Verzeichnis öffnen bzw. anlegen falls nicht vorhanden. Folgende Zeile anhägen (Pfad anpassen):

export PATH=$PATH:/home/username/gcc-arm-embedded/bin

    • Den Benutzer ab- und wieder anmelden
    • In einem Terminal-Fenster "JLinkExe" eingeben. Es sollte sich die JLink-Software mit "SEGGER J-Link Commander V5.00c ('?' for help)" melden. Diese wieder mit "exit" beenden. Falls das nicht funktioniert, wurde die Umgebungsvariable falsch gesetzt.
    • Im selben Fenster "arm-none-eabi-gcc" eingeben. Es sollte eine Meldung im Stil von "arm-none-eabi-gcc: fatal error: no input files" erscheinen. Falls nicht, wurde die Umgebungsvariable falsch gesetzt.

Die Umgebungsvariable muss nach jedem Update der JLink-Software neu gesetzt werden, da der Pfad die Versionsnummer enthält.

Eclipse

  • Da Eclipse auf Java basiert, muss dies zuerst installiert werden:
  • Die aktuelle Version von "Eclipse IDE for C/C++ Developers" hier herunterladen. Unter Linux ist eclipse zwar auch oft in der Paketverwaltung enthalten, diese Version ist aber meist stark veraltet. Das heruntergeladene Archiv muss nur in einen beliebigen Ordner entpackt werden und die enthaltene Programmdatei (Linux: "eclipse", Windows: "eclipse.exe") gestartet werden.
  • Den beim ersten Start erscheinenden "Welcome" Tab schließen.
  • Im Menü "Help"->"Install new software" anwählen, unter "Work With" die URL "http://gnuarmeclipse.sourceforge.net/updates" eingeben, Enter klicken, den in der Liste erscheinenden Eintrag "GNU ARM C/C++ Cross Development Tools" auswählen, und mit "Next" und "Finish" installieren. Die Sicherheitsabfrage über unsignierte Software bestätigen, und die Abfrage zum Neustart von Eclipse bestätigen. Die Installation dauert etwas, und funktioniert manchmal nicht wenn die Server überlastet sind. Dann einfach später noch einmal probieren.
  • Nur Windows: Im Menü "Window"->"Preferences" anklicken, in der Baumstruktur des erscheinenden Fensters "Run"->"String Substitution" anwählen, die Zeile mit "jlink_path" auswählen, "Edit" anklicken, und unter "Value" den Pfad zur JLink-Installation, also zB. "C:\Program Files (x86)\SEGGER\JLink_V500e" eintragen. Alles mit OK schließen.
  • In der Toolbar den Eintrag "Make the C/C++ Packs perspective visible" anklicken, und das Symbol mit den gelben Pfeilen ("Update the package definitions from all repositories") anklicken. Dieser Vorgang dauert einige Minuten.
  • In der erscheinenden Baumstruktur im Tab "Packs" unter dem Punkt "Keil" die Mikrocontroller auswählen (Mehrfachauswahl mit der Strg-Taste möglich) für die man programmieren möchte (zB. "STM32F4xx_DFP"), und mit der rechten Maustaste und Klick auf "Install" installieren. Auch dies dauert etwas, der Fortschritt des Vorgangs wird etwas versteckt rechts unten im Fenster angezeigt.
  • Danach wieder mit Klick auf den "C/C++" Button oben rechts in die C/C++ Ansicht wechseln.

Standard Peripheral Library vorbereiten

Um auf die Hardware-Register direkt zuzugreifen oder die Treiberfunktionen von ST zu verwenden, sowie für den Startup-Code & Linkerscript, wird die Library von ST benötigt.

  • Zum Herunterladen die Produktseite des Mikrocontrollers aufrufen (zB hier für STM32F407VG), "Design Resources" anklicken, unter dem Punkt "Related Tools and Software" den Eintrag im Stil von "STM32F4 DSP and standard peripherals library" finden (zB hier für STM32F4). Ganz unten findet sich der "Download" Button.

Leider ist das Archiv nicht gut strukturiert. Daher müssen die entsprechenden Dateien herausgesucht werden:

  • Im enthaltenen Verzeichnis "Project/*** Templates" nach Dateien suchen, die auf *.ld enden und die herauskopieren, deren Name zum verwendeten Mikrocontroller passt, also z.B. "STM32F417IG_FLASH.ld" für den STM32F4. Diese ist das Linkerscript und wird später für jedes Projekt benötigt. Zur Sicherheit sollte diese Datei einmal im Texteditor geöffnet und auf Fehler überprüft werden (ST ist bekannt dafür hier Fehler zu machen):
    • Die Speicher-Größen-Angaben der folgenden Zeilen sollten zum Datasheet passen (ggf. anpassen):
MEMORY
{
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
}
    • Die Angabe der Adresse der Initialen Stack-Adresse sieht oft so aus:
_estack = 0x2001FFFF;    /* end of RAM */
    • Dies ist falsch (ST weiß selber nicht wie der Cortex-M funktioniert). Die angegebene Adresse sollte Anfangsadresse des RAM's (immer 0x20000000) plus RAM-Größe (z.B. beim STM32F407 0x20000 Bytes) sein, also z.B. 0x20020000 für den STM32F407:
_estack = 0x20020000;    /* end of RAM */
    • Ist dies falsch, kann es später zu schwer auffindbaren Problemen im Zusammenhang mit z.B. Floatingpoint-Funktionsargumenten kommen.
  • Im Archiv nach Dateien suchen, deren Namen mit "startup_stm32" beginnt. Eine der Dateien heraussuchen, deren Name zum Mikrocontroller passt, und deren enthaltendes Verzeichnis den Namen TrueSTUDIO trägt, also zB. "Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f40_41xxx.s". Diese Datei herauskopieren, sie ist der Startup-Code und wird später für jedes Projekt benötigt. Dabei die Dateiendung von ".s" auf ".S" ändern, denn sonst erkennt eclipse sie nicht.
  • Im Verzeichnis "Project/*** Templates" die Datei "stm32f***_conf.h" herauskopieren. Diese wird für Einstellungen in der Treiber-Library benötigt.
  • Alles außer dem Verzeichnis "Libraries" löschen.
  • Im Verzeichnis "Libraries" (rekursiv) nach Dateien & Ordnern suchen, die "example" oder "template" im Namen tragen und alle löschen.
  • Die Unterverzeichnisse "Documentation", "Lib", "RTOS", "SVD" löschen. Die Lizenz und Release Notes-Dateien stören zwar nicht, können aber auch gelöscht werden. Im Endeffekt werden nur die .c und .h Dateien benötigt. Die DSP_Lib kann auch gelöscht werden, wenn keine DSP-Funktionen benötigt werden (existiert onehin nur für Cortex-M4 Controller).
  • Leider enthält die Library für alle STM32F4 die Treiber für sowohl den FMC als auch den FSMC, obwohl beide nicht in allen Varianten vorhanden sind. Diese Treiber verursachen Compilerfehler, wenn für den falschen Controller kompiliert. Daher muss die Datei "STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fmc.c" gelöscht werden, wenn kein FMC vorhanden ist (wie beim STM32F40x), bzw. die "STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fsmc.c" wenn kein FSMC vorhanden ist (wie beim STM32F42x).
  • Danach sollte nur noch so eine Struktur übrig bleigen:
./STM32F4xx_StdPeriph_Driver
./STM32F4xx_StdPeriph_Driver/src  -   Hier liegt der Quellcode für die Peripherie-Treiber
./STM32F4xx_StdPeriph_Driver/src/stm32f4xx_wwdg.c
./STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c
...
./STM32F4xx_StdPeriph_Driver/inc  -   Hier liegen die Includes für die Peripherie-Treiber
./STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_wwdg.h
./STM32F4xx_StdPeriph_Driver/inc/stm32f4xx_usart.h
...
./CMSIS
./CMSIS/Include                   -   Hier liegen die Includes für den Prozessorkern (Cortex-M*)
./CMSIS/Include/core_sc300.h
./CMSIS/Include/core_sc000.h
...
./CMSIS/DSP_Lib/Source/TransformFunctions  - Hier liegt die DSP-Library (optional)
./CMSIS/DSP_Lib/Source/TransformFunctions/arm_rfft_q31.c
./CMSIS/DSP_Lib/Source/TransformFunctions/arm_rfft_q15.c
...
./CMSIS/Device/ST/STM32F4xx/Include
./CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h   -   Dies ist die Include-Datei für das Clock Setup
./CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h   -   Dies ist die zentrale Include-Datei für die Register-Definitionen
  • Soll die Standard Peripheral Library nicht genutzt werden, sondern nur direkt die Register-Definitionen, werden nur die letzten beiden Dateien benötigt sowie die im Verzeichnis CMSIS/Include.
  • In der Datei "CMSIS/Device/ST/STM32***/Include/stm32f***.h" befindet sich ganz oben eine Präprozessor-Fallunterscheidung der Form
#if !defined (STM32F40_41xxx) && !defined (STM32F427_437xx) && !defined (STM32F429_439xx) && !defined (STM32F401xx) && !defined (STM32F411xE)
  /* #define STM32F40_41xxx */   /*!< STM32F405RG, STM32F405VG, STM32F405ZG, STM32F415RG, STM32F415VG, STM32F415ZG,  
                                      STM32F407VG, STM32F407VE, STM32F407ZG, STM32F407ZE, STM32F407IG, STM32F407IE, 
                                      STM32F417VG, STM32F417VE, STM32F417ZG, STM32F417ZE, STM32F417IG and STM32F417IE Devices */

  /* #define STM32F427_437xx */  /*!< STM32F427VG, STM32F427VI, STM32F427ZG, STM32F427ZI, STM32F427IG, STM32F427II,  
                                      STM32F437VG, STM32F437VI, STM32F437ZG, STM32F437ZI, STM32F437IG, STM32F437II Devices */

  /* #define STM32F429_439xx */  /*!< STM32F429VG, STM32F429VI, STM32F429ZG, STM32F429ZI, STM32F429BG, STM32F429BI,  
                                      STM32F429NG, STM32F439NI, STM32F429IG, STM32F429II, STM32F439VG, STM32F439VI, 
                                      STM32F439ZG, STM32F439ZI, STM32F439BG, STM32F439BI, STM32F439NG, STM32F439NI,
                                      STM32F439IG and STM32F439II Devices */

  /* #define STM32F401xx */      /*!< STM32F401CB, STM32F401CC,  STM32F401RB, STM32F401RC, STM32F401VB, STM32F401VC  
                                      STM32F401CD, STM32F401RD, STM32F401VD, STM32F401CExx, STM32F401RE and STM32F401VE Devices */

  /* #define STM32F411xE */      /*!< STM32F411CD, STM32F411RD, STM32F411VD, STM32F411CE, STM32F411RE and STM32F411VE Devices */
#endif

Hier mithilfe des Kommentars das Präprozessor-Makro heraussuchen, das zum verwendeten Mikrocontroller passt, also z.B. "STM32F40_41xxx" für den STM32F407VG. Dieses kopieren und für später merken.

Projekt erstellen

Clock-Konfiguration generieren

Zum Initialisieren des Takts wird eine spezielle Funktion benötigt, die je nach Art und Frequenz des Takts spezifisch erzeugt werden muss. ST bietet ein Tool, um diese Datei zu generieren:

  • Auf der Produkt seite des Mikrocontrollers (zB hier für den STM32F407VG) auf "Design Resources" klicken, und den Eintrag in der Art von "Clock configuration tool for STM32F40x/41x microcontrollers (AN3988)" finden.
  • Die Datei herunterladen und mit MS Excel öffnen. Die gewünschte Clock-Konfiguration auswählen, und den Code generieren lassen. Die Datei zB unter dem Namen system_stm32f4xx.c speichern.

Eclipse Projekt konfigurieren

Fertiges Projekt in Eclipse geöffnet

Neue Projekte werden über "File"->"New"->"Project..." angelegt.

  • In der Baumstruktur "C/C++ -> C++ Project" auswählen. Im C++ Projekt kann man natürlich auch einfachen C Code schreiben, aber es ist die Möglichkeit für C++ offen gehalten.
  • In der Baumstruktur "Empty Project" auswählen, und rechts "Cross ARM GCC". Es können zwar auch die einfacheren Vorlagen für spezifische Controller wie "STM32F4xx C/C++ Project" verwendet werden, dies ist aber weniger flexibel, weswegen hier ersteres erläutert wird.
  • Als Namen bitte einen ohne Leerzeichen oder Sonderzeichen verwenden.
  • Mit 2x "Next" und 1x "Finish" das Erstellen abschließen.
  • Das zuvor gesicherte Linkerscript (mit der Endung .ld) in das Projektverzeichnis kopieren. Den Projektnamen links anklicken, rechts Maustaste, und "Refresh" (oder F5) drücken. Das Linker-Script sollte im Dateibaum erscheinen.
  • Im Projekt müssen zunächst einige Einstellungen vorgenommen werden. Dazu mit der rechten Maustaste auf den Projektnamen im linken Fenster anklicken, und "Properties" auswählen.
    • Im erscheinenden Fenster, im DropDown Menü oben "[All Configurations]" auswählen
    • Nur Linux: In der Baumstruktur "C/C++ Build" auswählen, den Reiter "Behaviour" öffnen, den Haken bei "Enable Parallel Build" setzen. Dies beschleunigt die Kompilierung, funktioniert aber nicht unter Windows (beim Kopieren des Projekts beachten).
    • In der Baumstruktur "C/C++ Build" -> "Settings" anwählen. Das Öffnen dauert in aktuellen Versionen etwas, vermutlich ein Bug.
      • In der 2. Baumstruktur "Target processor" auswählen.
        • Unter "ARM family" den gewünschten Prozessor auswählen, also z.B. "cortex-m4" für STMF4 oder "cortex-m3" für STM32F1.
        • Nur bei Cortex-M4 (zB STM32F3 und STM32F4):
          • Unter Float ABI "FP instructions (hard)" auswählen
          • Unter "FPU Type" "fpv4-sp-d16 " auswählen. Siehe hier in der Tabelle für die möglichen Werte der verschiedenen Prozessoren.
      • Es ist zu empfehlen, LTO beim Kompilieren im Release-Modus zu aktivieren. Dies resultiert in kleineren und schnelleren Binaries, erschwert aber das Debugging mit GDB sehr:
        • Oben die Configuration "Release" auswählen
        • In der 2. Baumstruktur "Optimization" auswählen
        • "Link-time optimizer (-flto)" aktivieren
        • Oben wieder "[All configurations]" anklicken
      • In der 2. Baumstruktur "Cross ARM C++ Compiler -> Optimization" anklicken
        • Rechts "Do not use exceptions (-fno-exceptions) anwählen
        • Rechts "Do not use RTTO (-fno-rtti)" anwählen
      • In der 2. Baumstruktur "Cross ARM C++ Linker" -> "General" auswählen
        • In der Toolbar auf "Add" klicken, auf "Workspace" klicken, und das soeben in das Projekt kopierte Linkerscript auswählen.
      • In der 2. Baumstruktur "Cross ARM C++ Linker" -> "Miscellaneous" auswählen
        • Den Haken bei "Use newlib-nano (--specs=nano.specs)" setzen.
        • Optional, nur bei Cortex-M4 (zB STM32F3 und STM32F4):
          • Den Haken bei "Use float with with nano printf (-u _printf_float)" setzen. Dies ermöglicht die Nutzung von "%f" bei "printf", verbraucht aber automatisch eine Menge Flash+RAM und benötigt die Syscalls für malloc (s.u.). Daher ist ggf. zu empfehlen, dies nur in der Debug-Konfiguration zu aktivieren. Dazu in der Dropbown-Box oben vor aktivieren dieser Einstellung auf "Debug" klicken, und danach wieder auf "[All Configurations]".
      • Im Reiter "Devices" in der Baumstruktur den verwendeten Mikrocontroller, wie zB "STM32F407VG" auswählen.
    • In der linken Baumstruktur "C/C++ General"->"Paths and Symbols" auswählen
      • Oben im Drop-Down-Menü "Debug" anklicken
      • Im Reiter "Symbols" rechts auf "Add" klicken und dadurch nacheinander folgende Symbole definieren. Dabei immer beide Häkchen setzen!
        • Name "HSE_VALUE" Value=Takt des Quarzes, z.B. 8000000
        • Name "USE_STDPERIPH_DRIVER" Value leerlassen
        • Name "__FPU_PRESENT" Value=1
        • Das zuvor gemerkte Präprozessor-Makro aus der "stm32f**.h" (zB. STM32F40_41xxx) Value leerlassen
        • Name "ARM_MATH_CM4", "ARM_MATH_CM3", "ARM_MATH_CM0", oder "ARM_MATH_CM0PLUS" je nachdem ob für den Cortex-M4, -M3, -M0, oder -M0+ kompiliert wird; Value leerlassen
    • Das Fenster mit OK schließen.

Nun ist der Compiler an sich richtig konfiguriert. Allerdings fehlt noch die Library von ST:

  • Die zuvor vorbereitete Standard Peripheral Library (d.h. das Verzeichnis "Libraries") in das Projektverzeichnis kopieren. Dies ist leider die einzig sinnvolle & einfache Möglichkeit.
  • Den zuvor gesicherten Startup-Code, also zB. "startup_stm32f40_41xxx.S" in das Projektverzeichnis kopieren
  • Die zuvor gesicherte Datei "stm32f***_conf.h" in das Projektverzeichnis kopieren
  • Die zuvor generierte Datei "system_stm32f**" mit der Clock-Konfiguration in das Projektverzeichnis kopieren

Jetzt müssen dem Compiler noch die Pfade der Header-Dateien der Library mitgeteilt werden:

  • Mit der rechten Maustaste auf den Projektnamen im linken Fenster anklicken, und "Properties" auswählen.
  • Links in der Baumstruktur "C/C++ General" -> "Paths and Symbols" anklicken, und den Reiter "Includes" auswählen.
  • Oben im Drop-Down-Menü "Debug" auswählen.
  • Mit "Add" nacheinander folgende Pfade hinzufügen. Dazu jeweils "Add to all languages" sowie "Add to all configurations" einschalten, und den "Workspace..." Button verwenden.
    • "Libraries/CMSIS/Device/ST/STM32F***/Include"
    • "Libraries/CMSIS/Include"
    • "Libraries/STM32F**_StdPeriph_Driver/inc"
    • Den Pfad, in dem sich die "stm32f***_conf.h" befindet, also typischerweise das Projektverzeichnis selber.
  • Mit OK das Fenster schließen. Danach wird Eclipse die C/C++ Analyse laufen lassen. Dies kann etwas dauern und die weitere Bedienung währenddessen verlangsamen. Der Fortschritt ist unten rechts im Fenster zu sehen.

Linkerscript anpassen

Noch einmal das soeben hineinkopierte Linkerscript (mit der Endung .ld) öffnen. Die Zeile mit "_Min_Heap_Size" gibt die Größe des Heaps, d.h. des für malloc() zur Verfügung stehenden Speichers an. Wird malloc() nicht verwendet, kann dies auf 0 gesetzt werden. Soll printf() verwendet werden, ist zu empfehlen hier mindestens 2048 anzugeben, da printf sonst schnell keinen Speicher mehr hat und es zu komischem Verhalten kommt:

_Min_Heap_Size = 2048;      /* required amount of heap  */

Optional: Syscalls implementieren

Soll im Code printf() und/oder malloc() verwendet werden können, müssen die Syscalls der C-Library implementiert werden. Dazu ist es empfehlenswert, diesen Beispielcode zu verwenden und in das Projektverzeichnis zu kopieren. Er gibt per printf() ausgebenen Texte seriell per SWO aus. Dies ist ein Extra-Pin im SWD-Debug-Interface (bei JTAG nicht verfügbar), der vom JLink eingelesen und über die JLink-Software an Eclipse geschickt wird. Der Code kann auch angepasst werden um den Text zB per UART auszugeben.

Code schreiben und kompilieren

Dem Projekt kann jetzt eine eigene Quellcodedatei hinzugefügt werden. Dazu mit der rechten Maustaste auf den Projektnamen klicken, "New"->"Source file" auswählen. Die Datei z.B. "main.c" (für C) oder "main.cpp" (für C++) nennen. Hier kann ein einfacher Beispielcode für den STM32F407 heruntergeladen werden (funktioniert sowohl mit C als auch C++), der eine LED am Pin PD15 blinken lässt (blaue LED auf dem STM32F4 Discovery Board). Der Code braucht auf jeden Fall eine "main()"-Funktion, sowie im Falle von C++ eine Funktion namens "__cxa_pure_virtual":

extern "C" void __cxa_pure_virtual () {
	// This is an error callback for C++
	__disable_irq ();
	while (1) {
		// Cause debugger breakpoint
		asm volatile ("bkpt");
	}
}

Wird die oben verlinkte syscalls.c Datei nicht eingebunden, wird außerdem auch noch eine _exit Funktion benötigt:

#ifdef __cplusplus
extern "C"
void _exit(int) {
#else
void _exit (int status) {
	((void) status);
#endif
	// Stop controller in case of fatal error
	__disable_irq ();
	while (1) {
		asm volatile ("bkpt");
	}
	 __builtin_unreachable ();
}

Dies sind Callbacks zur Fehlerbehandlung. Durch Überschreiben durch simples Blockieren des Controllers wird das Einbinden der komplexen Fehlerbehandlung der Standardbibliothek verhindert. Danach kann der Code zum ersten Mal kompiliert werden. Dazu das Hammer-Symbol "Build" in der Toolbar benutzen. Fehlermeldungen sollten dem "Console" Fenster entnommen werden, da das "Problems" Fenster nicht immer korrekt funktioniert. Die erzeugten Dateien landen im Unterordner "Debug" bzw. "Release", je nachdem welche Konfiguration gewählt ist. Die generierte Datei mit der Endung .elf (zB Debug/MeinProjekt.elf) enthält den produzierten Code sowie alle Debug-Informationen. Es wird auch eine .hex Datei angelegt, die das erzeugte Flash-Image enthält.

Debugging

Debug Configuration anlegen

Um den Code zu flashen und debuggen, wird eine Debug Configuration benötigt. Dazu im Menü auf "Run"->"Debug Configurations" klicken. Sollen sowohl Debug- als auch Release- Versionen so geflasht/debuggt werden, müssen mehrere Debug Configurations angelegt werden. Dazu ist es am einfachsten, eine anzulegen und mehrfach zu kopieren.

  • Im erscheinenden Fenster in der Liste auf "GDB SEGGER J-Link Debugging" klicken, und oben auf das Symbol "New launch configuration".
  • Im Reiter "Main", unter "C/C++ Application" den Pfad zum kompilierten ELF-File angeben, also zB "Debug/ProjektName.elf".
  • Im Reiter "Startup" sollte "Enable SWO" aktiviert, und daneben die CPU-Frequenz in Hz angegeben werden (zB 168000000 für den STM32F4).
  • Im Reiter "Common" kann in der Liste "Display in favorites menu" ein Haken bei "Debug" gesetzt werden. Dadurch ist diese Debug Configuration schneller über das Käfer-Symbol in der Toolbar im Hauptmenü zugänglich.
  • Über "Apply" und "Close" das Fenster schließen.

Debug Session starten

Laufende Debug-Session

* Auf das kleine schwarze Dreieck neben dem Käfer-Symbol ("Debug") in der Toolbar klicken, und die soeben angelegte Debug-Configuration auswählen. Eclipse wechselt nun in die Debug-Perspektive. Nach Beendigung der Debug-Session kann über den "C/C++"-Knopf oben rechts wieder in die normale Ansicht gewechselt werden.

  • Es ist zu empfehlen die einzelnen Fenster der Ansicht so zu verschieben, dass mehr Code gleichzeitig sichtbar ist.
  • Standardmäßig legt eclipse automatisch einen Breakpoint zu Beginn der "main" Funktion an.
  • Über die Knöpfe "Resume", "Break", "Terminate" kann die Ausführung kontrolliert werden. Durch Doppelklick links neben eine Zeile werden Breakpoints gesetzt.
  • Das ARM Plugin ermöglicht das Betrachten von Peripherie-Registern mit Trennung der einzelnen Felder. Dazu im Fenster "Peripherals" die Peripherie-Einheiten, deren Inhalt man betrachten möchte, auswählen. Im "Memory" Fenster werden dann die Register angezeigt. Die Ansicht wird immer nach jedem Ausführungsschritt aktualisiert, nicht immer sofort. Im Zweifelsfall also eine Zeile weiter laufen lassen, um die Ansicht zu aktualisieren.
  • Ausgaben per "printf" erscheinen automatisch unten in der Konsole.

Siehe auch