Controller

      JTAG debugging mit Code::Blocks


Home ARM-Projekt Startupcode Bootloader myprintf() ECLIPSE Code::Blocks Em::Bitz Funksteck- dosen DCF77 Funkuhr


  ARM-HW debuggen mit Code:Blocks und OpenOCD

Voraussetzung:
Damit läuft das Programmieren ja schon mal sehr stabil. Wem das Printf-Debugging nicht mehr reicht, dem hilft diese Seite weiter.

  Installation des FTDI-Treibers

Der zum JTAG adapter (z.B. Turtelizer 2) mitgelieferte Treiber ist meist schnell installiert. Damit openocd ihn auch findet, muß der installierte JTAG-Treiber allerdings auf einen libusb-Treiber umgebogen werden. Dazu läd man sich das OpenOCD Paket von Freddie Chopin herunter. Im Windows-Gerätemanager unter "USB-Controller" ersetzt man den entsprechenden Treiber. So muß es aussehen:


Anstelle eines auf FTDI basierenden JTAG-Adapters eignet sich auch super der STM32link/V2.

  Test der Verbindung zwischen OpenOCD und FTDI-HW

Dazu rufen wir in der DOS-Box im openocd\bin Verzeichnis folgendes auf:
       openocd-0.7.0.exe -f interface/turtelizer2.cfg -f target/stm32f1x.cfg
       openocd-0.8.0.exe -f interface/stlink-v2.cfg -f target/stm32_stlink.cfg

Damit sollte er schon die Ziel-HW (hier ein STM32-Prozessor mit Turtelizer-JTAG-Adapter) finden.

  Einrichtung von Code::Blocks

Zunächst muß man dem Code::Blocks die Pfade des zu verwendenden Compilers bekanntgeben und ein einfaches makefile-Projekt einrichten.
   



Meist braucht man zum Upload des Binaries oder IHEX files ein Kommandozeilentool, das man z.B als separates Tool einrichten kann:



Sloadhost.exe --serialdev COM1: --baudrate 115200 --getid --erase --loadfile out/$(PROJECT_NAME).bin --write 0x08000000

...seriell oder per JTAG:

c:\Programm\openocd-0.7.0\bin\openocd-0.7.0.exe -d0 -f interface/turtelizer2.cfg -f target/stm32f1x.cfg -c "reset_config trst_and_srst" -c init -c targets -c "reset" -c "halt" -c "flash write_image erase out/SolarSW.elf" -c "verify_image out/SolarSW.elf" -c "reset run" -c shutdown


Wenn wir schon dabei sind, erzeugen wir auch gleich ein Tool-Eintrag für den freien OOCD debugger:


 
openocd-0.7.0.exe -f interface/turtelizer2.cfg -f target/stm32f1x.cfg -c "reset_config trst_and_srst"


und / oder

openocd-0.8.0.exe -f interface/stlink-v2.cfg -f target/stm32_stlink.cfg

Jetzt rufen Sie OOCD aus der Code::Blocks-Oberfläche auf. OpenOCD stellt nun einen Server zur Verfügung, der bei Windows über den  localhost:port 3333 zu erreichen ist. Dieser Server bleibt während der ganzen Sitzung gestartet. Die Firewall darf diesen Port 3333 natürlich nicht blocken!

Der eigentliche Chopin-BleedingEdge GCC-debugger kommuniziert über den TCP/IP port 3333 mit dem OOCD und muß zunächst das passende .elf file aus dem vorangegangenen make Prozess kennen.
       symbol out/$(PROJECT_NAME).elf


     

Für das Debuggen braucht man kaum Settings.
monitor reset halt  resettet den Prozessor (falls Leitung vorhanden), stoppt das Programm
load
 läd den aktuellen Code
tbreak main  Setzt den ersten Breakpoint auf main()

Mit "continue" sollte man vorsichtig sein, das bringt die Code::Blocks MMI durcheinander.

  Kopieren einer Code::Blocks - Konfiguration

Die Konfigurationsdaten liegen in 2 Files
  1. file.cpb  liegt im Projektordner und enthält projektbezogene Einstellungen
  2. ApplicationData/codeblocks/default.conf enthält die Recherbezogenen Einstellungen
Wenn man, wie oben beschrieben, die Files und Pfade mit Makros ausgestaltet, dann ist das Kopieren oder Umziehen z.B. auf einen anderen Rechner verhältnismäßig einfach.

 Typische Probleme mit OOCD

  • OOCD verbindet sich nicht
Abhilfe: googeln Sie mal nach verschiedenen -c "reset_config ..."  -Konfigurationen für Ihr Board oder
    Ihren Prozessor. z.B:
    STM32F207:  -c "reset_config srst_only srst_nogate"
    STM32F103:   -c "reset_config trst_and_srst"

  • OOCD startet mit 
Error: JTAG-DP OVERRUN        oder
Error: jtag status contains invalid mode value - communication failure
Abhilfe: Das ONCHIP debugging der ARM-Prozessoren verträgt sich nur mäßig mit Interrupts und
    mit Stromsparmechanismen wie
asm("wfi");
    verträgt es sich überhaupt nicht. Für's Debugging verzichtet man darauf besser. Mit dem
    folgenden C-Kommando kann man das Problem aber umgehen:
DBGMCU->CR |= DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STOP | DBGMCU_CR_DBG_STANDBY;

 Typische Probleme mit GDB

  • Der Debugger stoppt am Breakpoint, Code::Blocks findet jedoch nicht die richtige Stelle im C code. Das geschieht z.B. dann, wenn der Linker ungenutzten Code eliminiert hat. Die Zeilen danach findet Code::Blocks eventuell nicht.
Abhilfe: Verschiebe vorauss. ungenutzten Code ans Ende eines jeden C files.

  • Manchmal springt der Debugger scheinbar wild in einer Funktion umher. Das könnte an einer zu hohen Optimierung beim Compilieren liegen.
Abhilfe: Ändern Sie im make-File die Optimierung auf -O0 oder -O1. Das führt zwar zu doppelt so großem Code als bei -O2 oder-Os , macht das Debuggen aber angenehmer.

  • FW-Upload: Der debugger kann das *.elf File (vor dem debuggen) nicht in die Ziel-HW laden. Hier kursieren verschiedene Tipps, zusätzliche Befehle in die Debugger Run Configurations einzutragen. Die Befehle für OpcenOCD werden per monitor Befehl an den Debugger gesendet (z.B. halt und reset). Hier gibt es etwas Spielraum, da nicht jede HW alle Befehle unterstützt.
    Für STM 32 sollte man z.B die Interrupts während des FW-Upgrades verbieten.

 Fazit

Wenn das Debuggen aber erstmal läuft, dann kann man Breakpoints setzen, bequem durchsteppen und Variablen überwachen (Watches setzen), ganz wie das Entwicklerherz begehrt.

 Links

Bleeding Edge Toolchain schneller abgestrippter GCC-ARM compiler
OpenOCD Paket              Debug server, Bindeglied zwischen GCC-GDB und JTAG-HW
Code::Blocks einrichten
Code::Blocks Pathvariablen
Yagarto GCC compiler    freier GCC-ARM compiler
Embedded GCC               GCC-ARM compiler, managed by ARM