Ein Embedded-Echtzeit-Linux-System aufsetzen (Teil 1)

Anbieter zum Thema

Ein Embedded-Board, eine JTAG-Schnittstelle und freie Software – mehr braucht man nicht für ein fertiges Entwicklungssystem für Embedded-Echtzeit-Linux. Dieses Tutorial zeigt Ihnen, wie das geht.

Das Installationsziel: Auf diesem Embedded-Board vom Typ pure.box 2 von Wiesemann & Theis wird das Embedded-Linux installiert und konfiguriert.
Das Installationsziel: Auf diesem Embedded-Board vom Typ pure.box 2 von Wiesemann & Theis wird das Embedded-Linux installiert und konfiguriert.
(Wiesemann & Theis)

Dieses Tutorial beschreibt, wie man von der Hardware in Form eines Embedded-Boards über JTAG (Joint Test Action Group) und den Bootloader U-Boot bis zum fertigen Embedded-Echtzeit-Linux-System kommt. Die hier vorgestellte Vorgehensweise wurde so allgemein wie möglich gehalten, um die Nachvollziehbarkeit und gegebenenfalls notwendige Abwandlungen durchführen zu können. Trotzdem wurde als Anschauungsobjekt ein konkretes Board gewählt. So kann der Leser bei Bedarf jeden einzelnen Schritt nachvollziehen.

Die erste Aufgabe besteht darin, eine Verbindung vom Entwicklungsrechner zum Zielsystem (Target) aufzubauen und damit zuerst den Bootloader zu installieren.

Dafür wurden die JTAG-Schnittstelle und darauf aufbauend OpenOCD (Open On-Chip-Debugger, im Netz unter der Adresse http://openocd.sourceforge.net/ zu finden) als Software gewählt. OpenOCD ist sowohl ein Daemon (also ein ohne User-Interface laufender Prozess) als auch die ausführende Einheit im Zusammenhang mit dem JTAG-Debugging. Bei der hier beschriebenen Vorgehensweise wird er als Interpreter von JTAG-Kommandos verwendet. Mit diesem Programm ist es deshalb möglich, den Bootloader zu debuggen und zu flashen.

Sobald der Bootloader läuft, hat man bereits Software, mit der man kommunizieren kann und die es erlaubt, den Rest des Systems aufzubauen. Der Bootloader namens U-Boot übernimmt das Starten eines provisorischen Linux-Kernels mit einer RAM-Disk sowie das Flashen des Kernels. Das Root-Filesystem wird hier durch den intermediären Kernel per RAM-Disk erstellt.

Die Beispiele in diesem Artikel beziehen sich auf ein Board von Wiesemann und Theis (pure.box2) mit einer ARM-Marvell-CPU. Es verfügt über ein Standard-ARM-JTAG-Interface, 1 Gigabyte NAND-Flash, eine serielle Schnittstelle sowie Ethernet und weitere Peripherie. Das JTAG-Interface wird mit einem JTAG-Adapter von Olimex an den USB-Port des Entwicklungsrechners angeschlossen.

Der dafür eingesetzte Chip ist der weit verbreitete Mikrocontroller FTDI-2232. Zwischen dem Board und dem verwendeten JTAG-Adapter ist ein Flachbandkabel mit einer 26-poligen zweireihigen Buchsenleiste (2,54 mm) auf eine 20-polige Steckerleiste (2,00 mm) notwendig, das sich einfach herstellen lässt. Die PIN-Belegung entspricht dem ARM-Standard und muss nicht geändert werden.

Gezielt entwickelt: Schema des Targetings des Zielsystems vom Testrechner aus
Gezielt entwickelt: Schema des Targetings des Zielsystems vom Testrechner aus
(IT-Klinger)

Die JTAG-Verbindung zum Zielsystem aufbauen

Auf Seiten des Entwicklungsrechners muss die USB-Seite des JTAG-Adapters angesprochen werden können. Dafür wird OpenOCD verwendet. Dieser Dämon kommuniziert mit dem JTAG-Adapter auf der einen Seite und bietet auf der anderen Seite folgende Server-Socket-Schnittstellen als Interface:

  • Terminal (Port 4444) – Interaktive Schnittstelle zur Verwendung von JTAG
  • Debugger (Port 3333) – Schnittstelle mit mi-Protokoll zur Verwendung durch den GNU-Debugger gdb.

Die JTAG-Verbindung zum Zielsystem erfolgt von OpenOCD über den USB-Treiber für FTDI-Chips namens libftdi zum JTAG-Adapter. Dieser steht unter der Adresse http://www.intra2net.com/en/developer/libftdi/download.php im Netz.

Zwingende Voraussetzung für libftdi ist die Bibliothek libusb für den systemübergreifenden USB-Zugriff, die zuerst installiert sein muss. Danach kann die Treiberbibliothek libftdi aus dem Internet geladen und installiert werden:

cd /home/linux/inst-wut

tar -xvzf libftdi-0.19.tar.gz

cd libftdi-0.19

./configure --prefix=/usr

make

make install

Anschließend wird der Open On-Chip-Debugger OpenOCD aus dem GIT-Repository geholt, erstellt und mit dem folgenden Skript installiert:

cd /home/linux/inst-wut

git clone

git://openocd.git.sourceforge.net/

gitroot/openocd/openocd

cd openocd

./bootstrap

./configure --enable-maintainer-mode

--enable-ft2232_libftdi

--prefix=/usr

make

make install

Übersetzungsinstanz: Das Schaubild veranschaulicht die Funktion des Daemons OpenOCD
Übersetzungsinstanz: Das Schaubild veranschaulicht die Funktion des Daemons OpenOCD
(IT-Klinger)

Die Konfiguration des Daemons OpenOCD ausführen

Die Installation von OpenOCD erfolgte im Verzeichnispfad /usr/share/openocd/. Im Unterverzeichnis scripts/board der OpenOCD-Installation befinden sich bereits vorgefertigte Skripte für eine ganze Reihe an Boards. Selbstverständlich wird man in aller Regel versuchen, ein vorhandenes Skript zu verwenden und dieses so zu modifizieren, dass es zum jeweils gerade verwendeten Board passt.

Zweckmäßig ist es, sich hierzu das entsprechende Skript ins Arbeitsverzeichnis unter dem Namen openocd.cfg zu kopieren, dann wird es als Default-Skript verwendet, z. B.:

cp /usr/share/openocd/scripts/

board/sheevaplug.cfg

/home/linux/inst-wut/openocd.cfg

In dem vorgefundenen und verwendeten Skript sind einige Anpassungen notwendig, zuvorderst:

CPU-Architektur (source cpu/...)

JTAG-Interface (source interface/...)

Jetzt Newsletter abonnieren

Verpassen Sie nicht unsere besten Inhalte

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung

JTAG-Geschwindigkeit (jtag_khz)

Notwendige Register-Einstellungen (mww ...) für boardspezifische Initialisierungen in der Prozedur sheevaplug_init(); diese wird in wut_init() umbenannt

OpenOCD installiert eine ausführliche Dokumentation, die beispielsweise mit der folgenden Zeile eingesehen werden kann:

info openocd

Auf der Homepage des Autors ist das angepasste Konfigurationsskript erhältlich.

Start und Verwendung des Daemons OpenOCD

Zur Verwendung von OpenOCD sind zwei bzw. drei Terminals notwendig:

  • Start des OpenOCD-Dämons in einem Terminal-Fenster
  • Verbindung mit dem Dämon zur Kommando-Eingabe als Socket-Client (netcat)
  • Verbindung des gdb mit dem Dämon zum Debuggen.

Der Dämon wird mit der folgenden Zeile gestartet:

openocd

Zur standardmäßigen Konfiguration wird die ins Arbeitsverzeichnis kopierte Datei openocd.cfg verwendet. Wenn sich der Dämon nicht beendet, dann ist eine Verbindung vorhanden. Erscheinen dagegen beim Start des Daemons Fehlermeldungen, dann kommen folgende typische Ursachen in Betracht:

  • Das falsche Device-ID vom Interface-Adapter (USB-JTAG-Umsetzer) wird erkannt;
  • Gegebenenfalls ist die JTAG-Geschwindigkeit zu hoch eingestellt (jtag_khz) ;
  • Oder es ist ein falscher Adapter-Typ angegeben (source interface/...);
  • Ein falscher oder unpassender CPU-Typ ist eingestellt (source cpu/...);
  • Die Bibliothek libftdi kann nicht benutzt werden;
  • Gegebenenfalls wird OpenOCD unter einem nicht privilegierten User ausgeführt (Tipp: User root verwenden);
  • Die JTAG-Belegung zwischen dem Adapter und dem Target passt nicht; als eventuelle Ursache kommt ein wackeliger Kontakt in Frage.

In einer weiteren Shell wird das Socket-Terminal-Programm netcat oder auch kurz nc gestartet:

netcat localhost 4444 oder

nc localhost 4444

Hier können Befehle von OpenOCD eingegeben oder auch eigene Prozeduren aus der Konfigurationsdatei aufgerufen werden. Zur Orientierung kann man einfach

> help

> help [Kommando]

eingeben und sich die Kurzbeschreibung der eingebauten Befehle anschauen.

Die OpenOCD-Konfiguration einrichten

Für die boardspezifischen Initialisierungen legt man sich zweckmäßig eine Prozedur in der Konfigurationsdatei openocd.cfg an. In dieser Datei werden das JTAG-Interface zurückgesetzt sowie die Register der CPU richtig eingestellt. Ein Beispiel dafür befindet sich in der Konfigurationsdatei sheevaplug.cfg als Prozedur sheevaplug_init. Wir verwenden diese Prozedur als Ausgangspunkt und nennen unsere wut_init.

Nach dem Start von OpenOCD können wir diese Prozedur im Kommando-Terminal direkt aufrufen: > wut_init

Den Bootloader können wir bei bestehender JTAG-Verbindung jetzt ganz einfach testen. Die Erstellung des Bootloaders wird im zweiten Teil des Tutorials beschrieben. Vom Entwicklungsrechner ins RAM auf dem Target kopieren wir ihn mittels:

> load_image /home/linux/u-boot/u-boot

Dieser Aufruf gibt die Adresse zurück, an die der Bootloader kopiert wurde. Nun können wir die Ausführung an der entsprechenden Adresse fortsetzen:

> resume 0x600000

Soll der Bootloader debugged werden, so wird einfach eine Instruktion an der betreffenden Adresse ausgeführt:

> step 0x600000

Die Ausführung hält an und man kann sich von einem anderen Terminal aus mit dem Debugger gdb verbinden. Die Ausgaben des Bootloaders sollten über eine serielle Schnittstelle sowie einer Terminal-Emulation sichtbar sein.

Debugging der JTAG-Verbindung

Zum JTAG-Debuggen mittels OpenOCD startet man ein eigenes Terminal und wechselt in das Verzeichnis des Bootloaders:

cd /home/linux/u-boot

Dort kann der Debugger aus der Cross-Development-Toolchain mit der folgenden Zeile gestartet werden:

arm-linux-gdb ./u-boot

Nun muss man sich mit dem Target verbinden. Als Übermittler fungiert hier der Daemon OpenOCD:

(gdb) target remote localhost:3333

Jetzt kann das Debuggen beginnen, beispielsweise folgendermaßen:

(gdb) b start_armboot Breakpoint

(gdb) c Continue --> Target läuft

(gdb) n Zeile überspringen

(gdb) s Hineinspringen

(gdb) p abc Variable ausgeben

...

Zum Testen des Bootloaders verbindet man sich durch ein serielles Nullmodemkabel mit dem Board und startet in einer weiteren, neuen Shell ein Terminalprogramm:

minicom -s

(Schnittstelle einstellen: 115,2k 8N1, kein Handshake)

Den Bootloader auf das Flash schreiben

Nachdem der Bootloader funktioniert und alle Probleme beseitigt sind, kann dieser persistent auf das Flash geschrieben, sprich geflashed werden. Dies erfolgt im Kommando-Terminal durch Initialisieren der Hardware, Erasen und Beschreiben des Flash:

> wut_init

> nand probe 0

> nand erase 0 0x0 0x100000

> nand write 0 /home/linux/u-boot.kwb

0x0 oob_softecc_kw

Im Kommandoterminal von OpenOCD startet man den Bootloader mit folgendem Befehl:

> resume

Wenn der Bootloader durchstartet, kann das JTAG-Interface vom Board getrennt und erneut gestartet werden.

In Teil zwei des Tutorials erfahrt Ihr, wie der Bootloader erstellt und für unsere Zwecke modifiziert wird, Außerdem kümmern wir uns um den Linux-Kernel und das Root-Filesystem.

* Andreas Klinger ist selbstständiger Diplom-Ingenieur (FH) und bietet Seminare zu Embedded- und Echtzeit-Linux an. Er ist außerdem beliebter Referent der Embedded Linux Woche. Kontakt: ak@it-klinger.de

(ID:31572750)