Stellaris Launchpad-Toolchain unter Linux

Aus Hobbyelektronik.org

Im folgenden wird beschrieben, wie man sich die Toolchain, Debugger und Flashtools zum Programmieren via USB für das Stellaris Launchpad von Grund auf selber baut. Die Idee dazu kam mir, als ich Probleme mit einem der 32bit Compiler von TI unter einem 64bit Betriebssystem hatten. Außerdem ist es natürlich deutlich "cooler", seine eigenen Compiler zu verwenden! So kann man bei Problemen auch einfach mal im Source Code stöbern.

An dieser Stelle sei gesagt, das dieser Vorgang sehr rechen- und zeitintensiv ist und ihr während des Bauvorgangs deutlich über 10 Tassen Kaffee trinken könnt. Um Missverständnisse auszuräumen sei kurz erwähnt, dass dieses Tutorial für Linuxanwender gedacht ist und eine Portierung auf Windows schwer sein dürfe.

Die komplette Software für die Toolchain kann mittels eines Makefiles (Datei:StellarisToolchainMakefile.h) heruntergeladen und gebaut werden. Am Anfang des Artikels wird die Verwendung dieses Makefiles erklärt. Danach wird auf die einzelnen Komponenten kurz eingegangen.

Warnung: Die hier verwendeten Softwarepakete unterliegen verschiedensten Lizenzen, welche eingehalten müssen werden!

Bauen der Toolchain

Zu Beginn sollte man sich das Makefile herunterladen und in einem beliebigen Ordner speichern:

$ mkdir ~/stellarislaunchpad/
$ wget http://hobbyelektronik.org/w/images/d/d6/StellarisToolchainMakefile.h -O ~/stellarislaunchpad/Makefile

Anschließend folgt das Herunterladen aller Sourcen. Diese haben entpackt eine Größe von ca. 1.4 GiB und liegen in dem Ordner "~/stellarislaunchpad/source". Zur Überprüfung sind hier die heruntergeladen Pakete aufgeführt.

$ make initial -C ~/stellarislaunchpad/
......
$ ls -1 ~/stellarislaunchpad/source/ 
binutils-2.22
gcc-4.9.0
gdb-7.8
lm4tools-master
newlib-2.1.0
openocd-0.8.0
stellarisWare-master
texinfo-5.2

Jetzt kann der eigentliche Bauvorgang gestartet werden. Dieser wird je nach Rechenleistung des Computers mehrere Stunden benötigen. Die Anzahl der Jobs, mit denen gebaut wird, berechnet sich automatisch aus der Anzahl der Prozessoren. Daher das "make" nicht mit mehreren Jobs starten!

$ make all -C ~/stellarislaunchpad/

Das Ergebnis des Bauvorgangs mit Compiler, Gdb, lm4flash, usw. befindet sich in dem Ordner ~/stellarislaunchpad/.

Die wichtigsten Binaries sind:

~/stellarislaunchpad/output/bin/arm-none-eabi-gcc       # c compiler
~/stellarislaunchpad/output/bin/lm4flash                # tool to programm the stellaris launchpad via usb
~/stellarislaunchpad/output/bin/arm-none-eabi-gdb       # gdb
~/stellarislaunchpad/output/arm-none-eabi/sys-include/  # folder with useful header

Nach diesem langwierigem Prozess des Bauens können wir uns endlich der Programmierung des Stellaris Launchpads widmen. Hierfür ist in dem Makefile ein Beispiel vorhanden. Dabei wird das "blinky" Projekt der Stellaris Ware gebaut und auf das Lauchpad gespielt. Dazu muss das Launchpad selbstverständlich am PC via USB eingesteckt sein. Leider ist es mir bis jetzt nicht gelungen, das lm4flash Tool ohne Rootrechte zu starten. Der Systemcall dazu lautet:

$ sudo make example -C ~/stellarislaunchpad/

Ist alles gut gegangen, blinkt das Stellaris Launchpad nun fröhlich in grün vor sich hin. Bei der Stellaris Ware (unter ~/stellarisware/source/stellarisWare-master/) befinden sich noch viele weitere Beispiele, welche zum experimentieren einladen.

Erklärung des Makefiles

Im folgenden wird genauer auf die einzelnen Teile des Makefiles eingegangen.


Verwendete Variablen

Die wichtigsten globalen Variablen des Makefiles werden hier kurz genannt. Nicht aufgeführt sind die Variablen für den Speicherort und Version der einzelnen Pakete.

BASE    = $(shell pwd)                                   # the act. folder
PREFIX  = $(BASE)/output                                 # install folder
SOURCE  = $(BASE)/source/                                # source folder
TARGET  = arm-none-eabi                                  # target name
JOBS    = $(shell cat /proc/cpuinfo | grep MHz | wc -l)  # number of jobs for make
MAKE    = PATH=$(PREFIX)/bin:$${PATH} make -j $(JOBS)    # make variable with modified path and the number of jobs

Texinfo

Texinfo beinhaltet das Programm "makeinfo", welches beim Bauvorgang der Newlib benötigt wird. Nur aus diesem Grund wird dieses relativ kleine Software-Paket mit gebaut.

texinfo:
	cd $(TEXINFO_DIR) && ./configure \
	  --prefix=$(PREFIX)
	$(MAKE) -C $(TEXINFO_DIR) all
	$(MAKE) -C $(TEXINFO_DIR) install


Binutils

Die Binutils beinhalten eine Vielzahl an Werkzeugen, unter anderem zum übersetzen von Code. Mehr Informationen dazu gibt es auf der GNU-Website.

binutils:
	cd $(BINUTILS_DIR) && ./configure  \
	  --target=$(TARGET) \
	  --prefix=$(PREFIX) \
	  --disable-nls	  \
	  --enable-multilib \
	  --with-gnu-as	  \
	  --with-gnu-ld	  \
	  --disable-libssp   \
	  --disable-werror
	$(MAKE) -C $(BINUTILS_DIR) all
	$(MAKE) -C $(BINUTILS_DIR) install

Gcc-initial

Nun wird der eigentliche Gcc Compiler gebaut. Dieser benötigt zum vollständigen Bauen eine Library mit grundlegenden Funktionen und den entsprechenden Header Dateien. Nachdem die glibc Library zu groß für Mikrocontroller ist, bietet sich Newlib an. Zum Bauen der Newlib muss allerdings ein Teil des Gcc bereits vorhanden sein, weshalb der Gcc in zwei Schritten gebaut wird.

Hier die richtige Reihenfolge:

  1. GCC-Configure
  2. GCC-make all-gcc
  3. GCC-make install-gcc
  4. NEWLIB-configure
  5. NEWLIB-make
  6. NEWLIB-make install
  7. GCC-make all
  8. GCC-make install

Erst nach dem erfolgreichen "make install" vom Gcc ist dieser komplett gebaut.

Aber nun zu der Erklärung. Zu Beginn wird im Gcc-Verzeichnis ein neuer Ordner angelegt, weil man den Gcc nicht direkt in dem Verzeichnis der Sourcen bauen kann. Bei der Konfiguration werden eine Vielzahl an Features ausgeschaltet, welche auf dem Mikrocontroller nicht benötigt werden. Wichtig ist das setzen des "--enable-languages" Flag für die gewünschte Sprache. Dazu kommt natürlich das entsprechende Flag für die Newlib("--with-newlib"). Um diese zu verwenden, muss der Headerpfad zu der Newlib entsprechend angegeben werden("--with-headers"). Zudem ist auch die Angabe des CPU-Typs(cortex-m4) wichtig.

gcc-initial:
	mkdir -p $(GCC_DIR)/build
	cd $(GCC_DIR)/build && PATH=$(PREFIX)/bin:$${PATH} ../configure	\
	  --target=$(TARGET)	    \
	  --prefix=$(PREFIX)	    \
	  --enable-languages=c	    \
	  --disable-bootstrap	    \
	  --disable-libgomp         \
	  --disable-libmudflap	    \
	  --enable-multilib	    \
	  --disable-libphobos	    \
	  --disable-decimal-float   \
	  --disable-libffi	    \
	  --disable-libmudflap	    \
	  --disable-libquadmath	    \
	  --disable-libssp	    \
	  --disable-libstdcxx-pch   \
	  --disable-nls		    \
	  --disable-shared	    \
	  --disable-threads	    \
	  --disable-tls		    \
	  --with-gnu-as		    \
	  --with-gnu-ld		    \
	  --with-cpu=cortex-m4	    \
	  --with-tune=cortex-m4	    \
	  --with-mode=thumb	    \
	  --with-newlib             \
	  --with-headers=$(NEWLIB_DIR)/newlib/libc/include/
	$(MAKE) -C $(GCC_DIR)/build/ all-gcc 
	$(MAKE) -C $(GCC_DIR)/build/ install-gcc

Newlib

Vor dem Bauen der Newlib muss die verwendete Version 2.1.0 noch gepatcht werden, weil es sonst zu Komplikationen beim bauen kommt. Der Patch ist in das Makefile integriert und wird sofort nach Herunterladen der Sourcen eingespielt. Hier der Patch:

--- libgloss/arm/cpu-init/Makefile.in	2013-10-14 17:15:12.000000000 +0200
+++ libgloss/arm/cpu-init/Makefile.in	2014-10-17 21:38:32.623317260 +0200
@@ -18,6 +18,7 @@
 tooldir = $(exec_prefix)/$(target_alias)
 
 objtype = @objtype@
+host_makefile_frag = /../../config/default.mh
 
 INSTALL = @INSTALL@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -80,7 +81,7 @@
 install-info:
 clean-info:
 
-Makefile: Makefile.in ../config.status @host_makefile_frag_path@
+Makefile: Makefile.in ../config.status $${host_makefile_frag_path}
 	$$(SHELL) ../config.status --file cpu-init/Makefile
 
 ../config.status: ../configure

Zum Konfigurieren der Newlib gibt es nichts besonders zu erwähnen. Es wird wie beim Gcc natürlich auch unser Target angegeben. Wichtig ist beim installieren, dass hier nicht unsere "$(MAKE)" Variable verwendet wird. Da es sonst beim Verwenden mehrerer Jobs zu Problemen führen kann.

newlib:
	cd $(NEWLIB_DIR) && PATH=$${PATH}/:$(PREFIX)/bin/ ./configure \
	  --target=$(TARGET) \
	  --prefix=$(PREFIX) \
	  --enable-multilib \
	  --disable-libssp \
	  --disable-nls
	$(MAKE) -C $(NEWLIB_DIR) all
	# use normal make without jobs because of issues with multiple jobs
	PATH=$(PREFIX)/bin:$${PATH} make -C $(NEWLIB_DIR) install

Gcc-final

Endlich ist es so weit. Wir können unseren Compiler fertig bauen und installieren. Der Compiler befindet sich anschließend unter output/bin/arm-none-eabi-gcc und kann nun verwendet werden.

gcc-final:
	$(MAKE) -C $(GCC_DIR)/build/ all
	$(MAKE) -C $(GCC_DIR)/build/ install

Lm4flash

Zum Aufspielen der Software auf das Launchpad benötigt man die Lm4flash-tools. Diese brauchen zwingend das Paket libusb und das dazugehörige Developer Package. Unter Arch und Ubuntu können diese leicht über die Paketmanager installiert werden.

lm4tools:
	echo "lm4tools needs libusb dev and pkg(try apt-get install libusb-dev)"
	make -C $(LM4TOOLS_DIR)/lm4flash
	cp $(LM4TOOLS_DIR)/lm4flash/lm4flash $(PREFIX)/bin/

Getestet werden kann Lm4flash einfach mit dem flash-blinky Beispiel des Makefiles. Dazu wird das blinky-Projekt der Stellarisware crosscompiliert und per lm4flash auf das Launchpad via USB gespielt. Möglicherweise wird zum Übertragen der Daten Rootrechte benötigt.

blinky:
	$(MAKE) -C $(STELLARISWARE_DIR)/boards/ek-lm4f120xl/blinky/

flash-blinky: blinky
	$(PREFIX)/bin/lm4flash $(STELLARISWARE_DIR)/boards/ek-lm4f120xl/blinky/gcc/blinky.bin

GDB

Zum Debuggen wird nun noch der entsprechende Gdb benötigt. Auch dieser kann ohne große Mühe gebaut werden. Hier wird nicht weiter auf den Gdb eingegangen, da es genügend ausführliche Anleitungen im Internet gibt.

gdb:
	cd $(GDB_DIR) && ./configure \
	  --target=$(TARGET) \
	  --prefix=$(PREFIX) \
	  --enable-interwork \
	  --enable-multilib
	$(MAKE) -C $(GDB_DIR) all
	$(MAKE) -C $(GDB_DIR) install

OpenOCD

Und für alle Freunde von OpenOCD wird der nötige Bauvorgang kurz gezeigt. Wichtig dabei ist das "--enable-ti-icdi" Flag.

openocd:
	cd $(OPENOCD_DIR) && ./configure \
	  --prefix=$(PREFIX) \
	  --enable-maintainer-mode \
	  --enable-ti-icdi
	$(MAKE) -C $(OPENOCD_DIR) all
	$(MAKE) -C $(OPENOCD_DIR) install