Autor: | Hubert Hoegl <Hubert.Hoegl@hs-augsburg.de> |
---|---|
Datum: | 2011-11-30 |
URL: http://elk.informatik.fh-augsburg.de/pub/gnublin-lpc3131/gnublin-ug/index.html
Inhalt
Das Gnublin Projektverzeichnis, im weiteren $GNUBLINDIR genannt, ist in
http://elk.informatik.fh-augsburg.de/pub/gnublin-lpc3131
Um mit dem Gnublin Board zu arbeiten, muss man nur zwei Sachen haben:
- Eine Micro SD Karte mit vorinstalliertem GNU/Linux.
- Eine USB Verbindung zwischen der USB Konsolenbuchse auf dem Gnublin Board und einem Entwicklungsrechner (PC) unter GNU/Linux.
Auf dem PC startet man nach dem Anstecken des USB Kabel ein Terminal Emulationsprogramm, z.B. picocom:
sudo picocom -b 115200 /dev/ttyUSB0
Tipp: Aus picocom steigt man wieder aus mit Strg-A Strg-X.
Damit wird der PC zur "Konsole" des Gnublin Boards, das heisst, man sieht die Meldungen des Boards auf dem Bildschirm und Tastatureingaben auf dem PC werden auf das Board weitergeleitet.
Warum ist es wichtig, dass man zuerst die USB Verbindung herstellt und dann das Terminalprogramm startet? Die Antwort ist, dass durch Einstecken des Kables erst eine virtuelle serielle Schnittstelle auf dem PC angelegt wird, diese heisst in der Regel /dev/ttyUSB0, die Zahl am Ende kann auch grösser sein. Erst danach kann picocom mit diesem Gerät als Argument gestartet werden.
Was passiert nach dem Anstecken?
Nachdem das Board über das Konsolen USB Kabel angesteckt wurde, lädt es von der SD Karte zunächst den Apex Bootloader (http://elinux.org/APEX_Bootloader) und führt ihn aus. Der Bootloader ist so konfiguriert, dass er nach einer kurzen Wartepause den Linux Kern von der SD Karte in den Speicher kopiert und dann ausführt. Linux bootet nun und mountet am Schluss das Root Filesystem von der SD Karte. An der Konsole sollte man nun sehen:
... EDLK (Built by Poky 5.0) 5.0 armv5te ttyS0 armv5te login:
Jetzt kann man sich mit dem Namen root anmelden (ohne Passwort) und sieht dann diesen Prompt:
root@armv5te:~#
Nun kann man mit Gnublin (fast) wie auf einem gewöhnlichen GNU/Linux Rechner arbeiten. Das Root Filesystem enthält mit über 600 MByte Grösse eine sehr grosse Auswahl an Programmen, allerdings auch Programme, z.B. das X Window System, das die Gnublin LPC3131 Hardware nicht unterstützt. Auch der mit 8 MByte eher kleine SDRAM Arbeitsspeicher ist für manche Anwendungen zu knapp, z.B. um mit dem GNU C Compiler ein grösseres Programm nativ für den ARM9 zu kompilieren, obwohl es prinzipiell funktioniert.
Die Micro SD Karte
Die benötigte Micro SD Karte ist entweder bei der Lieferung des Gnublin Boards mit dabei oder kann selber mit dem Programm gnublin-card.py hergestellt werden. Der folgende Abschnitt geht darauf ein.
Was kann man mit dem Board machen?
Hier sind ein paar Beispiele, was man mit dem Board machen kann.
Man kann mit dem Board Embedded Linux auf einem ARM Mikrocontroller kennenlernen.
Über die USB OTG high-speed Schnittstelle kann man Gnublin sowohl als USB Gerät an einen USB Host anstecken, z.B. einen PC, oder man kann Gnublin als USB Host zur Ansteuerung von fast beliebigen USB Geräten verwenden.
So kann man Gnublin z.B. über einen USB zu Ethernet Adapter mit einem Computernetzwerk verbinden und alle üblichen Protokolle verwenden, wie z.B. HTTP, SSH, FTP und so weiter.
So ein Adapter kostet nur ein paar Euro. Auf der Abbildung img/usb-ethernet.jpg sieht man so einen Adapter. Mit Hilfe eines USB Adapterkabels kommt man von der Mini USB OTG Buchse auf dem Gnublin Board an ein USB Gerät mit "normalem" USB Stecker. Die Abbildung img/usb-adapterkabel.jpg zeigt zwei Varianten von solchen Adaptern.
Am Gnublin Board funktionieren auch USB-WLAN Adapter, wie z.B. der ASUS WL-167G, siehe Abbildung img/usb-wlan.jpg.
Weiter unten beschreibe ich, welche Kernelmodule man für diese Adapter verwenden muss.
Über die herausgeführten I2C und SPI Schnittstellen kann man viele Hardware-Erweiterungen anschliessen, z.B. Sensoren, Funkmodule. Es steht nichts im Weg um Sensoren einzulesen, z.B. Temperatur und Luftfeuchtigkeit, und die eingelesenen Werte über einen Webserver auszuliefern.
Über ein paar herausgeführte GPIO Leitungen kann man Experimente mit Interrupts machen und z.B. die Interrupt-Antwortzeit messen. Das führt zu dem interessanten Gebiet "Realtime Linux".
Gebäudeautomatisierung
Tragbare Embedded Linux Geräte
Fahrrad-Computer
Vieles mehr
An wen wendet sich das Gnublin Projekt?
Ich stelle mir folgende Benutzergruppen und Ihre Interessen vor:
Anfänger
- Was ist Embedded Linux?
- Kennenlernen der Einzelteile Bootloader, Kernel und Filesystem.
- Kennenlernen eines Mikrocontrollers mit ARM Kern.
- Kennenlernen der Open-Source Entwicklungsmethodik.
Wie starte ich Gnublin?
Wie logge ich mich ein?
Wie kann ich mit einfachen Kommandos auf die Schnittstellen GPIO, SPI und I2C zugreifen?
Wie baue ich eine einfache Anwendung mit Hilfe einer Interpretersprache, z.B. mit Hilfe eines Shell-Skripts oder der Sprache Python. Einfache Anwendungen sind
- Leuchtdioden ein-/ausschalten
- Taster einlesen
- Alphanumerische Displays über SPI anschliesssen
Wie kann ich das selbstgemachte Programm nach dem Booten automatisch ausführen lassen?
Fortgeschrittene
- Den vorhandenen Kernel neu konfigurieren, übersetzen und installieren.
- Neue vorhandene Module in den Kernel einbinden.
- Einfache Änderungen am vorhandenen Root Filesystem machen.
- Das vorhandene Root Filesystem nach eigenen Vorlieben neu kompilieren und installieren.
- Vorhandene Programme für Gnublin crosskompilieren und installieren.
- Eigene Programme für Gnublin in C zu schreiben.
Gurus
- Eigene Kernelmodule schreiben und installieren.
- Einen eigenen Kernel anpassen, so dass er auf Gnublin läuft.
- Eigene Erweiterungen in den Apex Bootloader einbauen.
- Selber ein Root Filesystem für Gnublin zusammenbauen, ohne die Vorgabe durch das ELDK.
- Tiefer in die technischen Details des LPC3131 ARM926 Mikrocontrollers einsteigen, z.B. alternative Möglichkeiten zum Booten ausprobieren.
- Experimente mit Echtzeit-Linux, z.B. Xenomai oder der Echtzeit Erweiterung für den GNU/Linux Kern.
Es gibt mehrere Möglichkeiten, um mit Gnublin zu arbeiten. Die wesentlichen Zutaten sind: Ein PC (oder Notebook, Webbook) als Entwicklungsrechner, ein Gnublin Board und ein paar Verbindungskabel zwischen beiden.
- USB Konsolenverbindung (inklusive Spannungsversorgung). Das ist eine serielle Schnittstelle (UART), die über das USB Kabel geführt wird. Auf dem Gnublin Board befindet sich ein USB-zu-UART Baustein, der zum UART des LPC3131 führt. Um neben den Konsolenzeichen auch Dateien zu übertragen, könnte man die X/Y/Z-Modem Protokolle verwenden.
- Pseudo Netzwerkverbindung über ein USB Kabel vom PC (Host) zum Gnublin Board (Device). Die USB OTG Buchse muss dazu im Device Modus betrieben werden.
- Pseudo Netzwerkverbindung über ein USB Kabel vom PC (Device) zum Gnublin Board (Host). Die USB OTG Buchse muss dazu im Host Modus betrieben werden.
- Richtige Ethernet-Netzwerkverbindung über einen Netzwerkadapter an USB OTG Buchse im Host Modus. Gnublin und der Entwicklungsrechner sind damit über das LAN verbunden. Auch eine drahtlose Verbindung ("WiFi") ist auf diese Art möglich.
Die Konsolenverbindung (A) über USB habe ich bereits in der Einleitung beschrieben.
(B) Pseudo-Netzwerkverbindung über USB OTG im Device Modus.
Auf dem Gnublin Prompt eingeben:
root@armv5te:~# modprobe g_ether root@armv5te:~# ifconfig usb0 192.168.1.100 up
Am PC eingeben:
sudo ifconfig usb0 192.168.1.101 up
Achtung: Möglicherweise kann diese Kommando mit einer vielleicht schon bestehenden Netzwerkverbindung kollidieren. Es kann sein, dass man temporär eine andere Netzwerkschnittstelle abschalten muss, z.B. wie mit sudo ifconfig wlan0 down, später kann man diese wieder mit sudo ifconfig wlan0 up einschalten.
Dateien mit dem "secure copy" Programm scp vom PC zum Gnublin Board übertragen werden. Wenn man die folgende Kommandozeile auf dem PC eingibt, dann wird test.txt übertragen:
scp test.txt root@192.168.1.100:
Wenn nach dem Passwort gefragt wird einfach auf die Eingabetaste (RETURN) drücken. Danach findet man die Datei im Heimatverzeichnis /home/root/ des Anwenders root auf dem Gnublin Board.
Die Übertragung in umgekehrte Richtung geht natürlich auch:
scp root@192.168.1.100:test.txt .
Damit wird test.txt vom Gnublin Board in das aktuelle Verzeichnis auf dem PC kopiert.
Wenn man ein Verzeichnis übertragen möchte, dann muss man die -r Option angeben, wie in folgendem Beispiel:
scp -r testdir root@192.168.1.100:
Über diesen Übertragungskanal kann man bequem ein Anwendungsprogramm, einen Treiber oder einen neuen Kernel (zImage) vom PC (Cross-Kompilierung!) auf das Gnublin Board übertragen. Natürlich muss dazu vorher schon ein funktionierender Kernel laufen.
Die folgende Abbildung zeigt das Gnublin Board, das über zwei USB Kabel mit einem Webbook verbunden ist.
Der gesamte Aufbau mit Gnublin, Webbook und einem Oszilloskop "TDS1002B" von Tektronix. Das Oszilloskop ist gerade mit zwei Kanälen an der SPI Schnittstelle angeklemmt.
Belegung der GPIOs:
GPIO3...........LED1 GPIO11..........X4-2 J5-12 GPIO13.......... GPIO14..........X4-3 J5-11 GPIO15..........X4-4
Nun soll beispielhaft die LED1 (rot) an GPIO3 ein- und ausgeschaltet werden.
Beispielcode für Ausgabe
Mit sysfs auf der Kommandozeile:
root@armv5te:/sys/class/gpio# ls export gpiochip15 gpiochip58 gpiochip68 gpiochip91 unexport gpio3 gpiochip47 gpiochip61 gpiochip84 gpiochip95 gpiochip0 gpiochip57 gpiochip64 gpiochip86 gpiochip96 root@armv5te:/sys/class/gpio# cd gpio3/ root@armv5te:/sys/devices/virtual/gpio/gpio3# ls active_low direction edge power subsystem uevent value root@armv5te:/sys/devices/virtual/gpio/gpio3# echo "high" > direction root@armv5te:/sys/devices/virtual/gpio/gpio3# cat direction out root@armv5te:/sys/devices/virtual/gpio/gpio3# echo 1 > value root@armv5te:/sys/devices/virtual/gpio/gpio3# echo 0 > value root@armv5te:/sys/devices/virtual/gpio/gpio3# echo 1 > value
Mit einem Shell Skript:
# Blink the onboard LED # http://blog.makezine.com/archive/2009/02/blinking-leds-with-the-beagle-board.html GPIO=3 cleanup() { # Release the GPIO port echo $GPIO > /sys/class/gpio/unexport exit } # Open the GPIO port ('high' direction is output) # echo $GPIO > /sys/class/gpio/export echo "high" > /sys/class/gpio/gpio$GPIO/direction trap cleanup SIGINT # call cleanup on Ctrl-C # Blink forever while [ "1" = "1" ]; do echo 1 > /sys/class/gpio/gpio$GPIO/value sleep 1 echo 0 > /sys/class/gpio/gpio$GPIO/value sleep 1 done cleanup # call the cleanup routine
Mit einem Lua Script:
-- blink.lua GPIO = 3 function wait(n) os.execute("sleep " .. tonumber(n)) end function cmd(c) print(c) os.execute(c) end cmd("echo " .. GPIO .. " > /sys/class/gpio/export") cmd("echo out > /sys/class/gpio/gpio" .. GPIO .. "/direction") n = 0 while n < 2 do cmd("echo 1 > /sys/class/gpio/gpio"..GPIO.."/value") wait(1) cmd("echo 0 > /sys/class/gpio/gpio" .. GPIO .. "/value") wait(1) n = n + 1 end cmd("echo "..GPIO.." > /sys/class/gpio/unexport")
Mittlerweile habe ich den Lua Interpreter um os.path_exists() erweitert, so dass man prüfen kann, ob Dateien und Verzeichnisse existieren:
-- blink2.lua -- H. Hoegl, 21. Dec 2011 if os.path_exists("/sys/class/gpio/gpio11") == 1 then print("remove gpio pin") f = io.open("/sys/class/gpio/unexport", "w") f:write("11") f:close() else print("create gpio pin") f = io.open("/sys/class/gpio/export", "w") f:write("11") f:close() end -- und so weiter...
Weitere Interpretersprachen für solche Experimente sind Tcl, besonders die kleinere Variante "Jim Tcl", siehe jimsh, und Perl. Squirrel (sq) als Abkömmling von Lua würde sich auch eignen. Auch Python wäre möglich, allerdings braucht der (grosse) Interpreter lang zum Laden und er läuft bei 8 MByte auch nicht richtig rund.
Beispielcode für Eingabe
Mit der Shell:
#!/bin/sh GPIO=11 cleanup() { # Release the GPIO port echo $GPIO > /sys/class/gpio/unexport exit } echo $GPIO > /sys/class/gpio/export echo "in" > /sys/class/gpio/gpio$GPIO/direction trap cleanup SIGINT # call cleanup on Ctrl-C while [ "1" = "1" ]; do cat /sys/class/gpio/gpio$GPIO/value sleep 1 done cleanup # call the cleanup routine
Mit einem Squirrel Skript:
/* input.nut */ local s, GPIO; GPIO = 11; s = "echo " + GPIO + " > /sys/class/gpio/export"; print(s+"\n"); system(s); s = "cat /sys/class/gpio/gpio" + GPIO + "/value"; print(s+"\n"); system(s) s = "echo " + GPIO + " > /sys/class/gpio/unexport"; print(s+"\n"); system(s);
Beispielcode für Interrupts
XXX to do
Das folgende Foto zeigt, wie ein Taster an den GPIO11 Pin angeschlossen wird. Den Taster habe ich aus einem alten Gerät ausgebaut.
Die Schaltung sieht dabei so aus:
Taster an GPIO11 VCC 3.3V | 10K __T__ | o o---+------> GPIO11 (weiss/blau) | === GND (blau)
Die SPI Signale sind auf dem Stecker J5 wie folgt herausgeführt:
SPI_MOSI........J5-7 SPI_MISO........J5-8 SPI_CLK.........J5-10
Die Signale SPI_CS_OUT0 und SPI_CS_IN sind als Testpunkte herausgeführt. Die Abkürzung CS bedeutet "Chip Select".
Die anderen Chip Select Signale SPI_CS_OUT1 (UART_CTS_N) und SPI_CS_OUT2 (UART_RTS_N) sind nicht herausgeführt.
So gehen wir vor (XXX to do):
Treiber spidev ist bereits im Kernel fest eingebaut.
Der MTD Kerneltreiber für DataFlash Speicher darf im Kernel nicht aktiviert sein, da er auch die SPI Schnittstelle (Chip Select 0) verwendet und andere Anwendungen dadurch nicht mehr darüber kommunizieren können.
Eintrag spi_lpc313x.0 in /sys/devices/platform soll vorhanden sein.
root@armv5te:/sys/devices/platform/spi_lpc313x.0# ls driver modalias power spi0.0 spi_master subsystem ueventEintrag in /sys/class/spi_master/
root@armv5te:# ls /sys/class/spi_master/spi0 device power subsystem ueventDie Gerätedatei heisst /dev/spi0. Falls es sie nicht gibt, legt man sie mit dem Kommando
mknod /dev/spi0 c 153 0an.
Demoprogramm spidev_test_2 auf Gnublin starten. Man findet es in $GNUBLINDIR/work_eplpc3131/prog/spi/.
Der LPC3131 hat zwei separate Schnittstellen. Gnublin führt in der Version 1.2 nur die zweite Schnittstelle (I2C_SDA1, I2C_SCL1) heraus. Die erste (Index 0) ist nicht beschaltet.
Belegung:
I2C_SDA1.......J5-6 I2C_SCL1.......J5-5
Vorgehen:
PCA9555D I/O Expander für I2C. Die über die Pins A0, A1 und A2 kodierten I2C Adressen sind 0x20 (schreiben) und 0x21 (lesen). Siehe Datenblatt.
Kernel-Modul pca953x.
Device anlegen:
root@armv5te:~# echo /dev/pca9555 0x20 > /sys/bus/i2c/devices/i2c-1/new_device i2c i2c-1: The new_device interface is still experimental and may change in a near future i2c i2c-1: new_device: Instantiated device /dev/pca9555 at 0x20 root@armv5te:~#Danach gibt es aber das Device /dev/pca9555 noch nicht.
Device erstellen:
root@armv5te:~# mknod /dev/pca9555 c 89 1Devices auflisten:
root@armv5te:~# ls -l /sys/bus/i2c/devices/ 0-0060 -> ../../../devices/platform/pnx-i2c.0/i2c-0/0-0060 1-0040 -> ../../../devices/platform/pnx-i2c.1/i2c-1/1-0040 i2c-0 -> ../../../devices/platform/pnx-i2c.0/i2c-0 i2c-1 -> ../../../devices/platform/pnx-i2c.1/i2c-1 ls /sys/class/i2c-adapter/i2c-1/ 1-0040 device name power uevent delete_device i2c-dev new_device subsystem ls /sys/devices/platform/pnx-i2c.1/ driver i2c-1 modalias power subsystem ueventDemo Programm:
Programm starten:
root@armv5te:~/i2c-pca9555# ./i2c-test /dev/pca9555Nun sollte eine LED an irgend einem Pin des Port0 vom PCA9555 blinken.
Achtung: Bei der I2C Busadresse des PCA9555 muss man aufpassen. Im ersten Byte auf dem Bus ist die Slave Adresse nur 7 Bit gross (Bit 7 bis Bit1). Das nullte Bit ist das R/notW bit. Bei der Slave Adresse im Linux Anwendungsprogramm nimmt man nur die Bits 7 bis 1. Der PCA9555 mit allen drei Adress Bits A2, A2 und A0 gleich 0 hat daher die Slave Adresse 0x20.
Auf dem folgenden Schirmfoto sieht man das erste Byte (Adresse) bei der I2C Übertragung zum PCA9555. Oben ist das Clock Signal SCL, unten das Datensignal SDA. Man sieht schön das Startbit, die Adresse 0x20, das Acknowledge Bit und das Stopbit.
Literatur:
- Atmel Application Note AVR32412: AVR32 AP7 TWI Driver
- https://github.com/torvalds/linux/blob/master/Documentation/i2c/instantiating-devices
Foto:
![]()
Das Modul mit dem PCA9555D ist über Flugdrähte mit dem Gnublin Board verbunden. Die kleine Adapterplatine kann man unbestückt von http://www.roth-elektronik.com bekommen.
Folgende analogen Eingänge des LPC3131 sind auf dem 14-poligen Erweiterungsstecker J5 herausgeführt:
ADC10B_GPA0........J5-1 ADC10B_GPA1........J5-2 (auch auf X4-1) ADC10B_GPA3........J5-3
XXX to do: Es gibt noch keinen ADC Treiber im Kernel.
Der PWM Ausgang PWM_DATA des LPC3131 ist auf J5-4 herausgeführt.
XXX to do: Es gibt noch keinen PWM Treiber im Kernel.
Die Mini-AB Buchse hat einen ID Pin, der signalisiert, ob die "on-the-go" (OTG) Schnittstelle entweder als Device (ID=1 bzw. offen) oder Host (ID=0) arbeitet. Der ID Pin (Nummer 4) ist direkt dem GND Pin (Nummer 5). Schaut man von hinten auf die Buchse, ist Pin Nummer 5 ganz links.
Üblicherweise steuert die Art des angesteckten USB Kabels den Pegel des ID Pins. Steckt man ein USB Kabel mit einem Mini-A Stecker in die OTG Buchse, wird der ID Pin auf Masse gezogen, das heisst, die USB Protokollsoftware arbeitet damit als Host. Diese Art Kabel ist leider nicht sehr weit verbreitet, da das USB Standardisierungsgremium den Mini-A Stecker als "antiquiert" eingestuft hat. Wenn man sich nicht sicher ist, ob man es mit einem Mini-A Stecker zu tun hat, dann hilft dieser Tipp: Schaut man von vorne auf den Stecker, dann muss die Plastikisolierung darin die Farbe Weiss haben.
Im Gegensatz zum Mini-A Stecker ist der Mini-B Stecker noch ganz modern und auch erlaubt, so dass es viele USB Erweiterungskabel mit diesem Stecker gibt. Wenn man die Möglichkeit hat, den ID Pin der Buchse von Hand zu setzen, dann kann man auch diese Kabel zum Anstecken eines USB Gerätes an Gnublin verwenden. Die Version 1.2 des Boards kann das leider nicht. Man kann jedoch einen Jumper einlöten, wie man das in der folgenden Abbildung sieht.
Die nächste Revision 1.3 des Boards, die gerade gemacht wird, wird diesen Jumper auf dem Board haben.
Zur Zeit werden USB OTG Verbindungen fast nur noch mit Micro-Steckern realisiert, die allerdings vom Aufbau her viel wackeliger wirken als die Mini-A/B Buchsen. Aus diesem Grund haben wir sie nicht bei Gnublin verwendet.
![]()
Das folgende Foto zeigt zwei weit verbreitete Adapter von USB A Buchse (links, zur Aufnahme von Geräten oder Kabeln mit Typ-A Steckern) auf Mini-B Stecker (rechts, zum Einstecken in die Gnublin USB-OTG Buchse). Diese Art Kabel kann ohne Tricks nicht dazu verwendet werden, um USB Geräte an den Gnublin USB Host anzuschliessen. Der Trick besteht darin, den ID Pin der USB-OTG Buchse separat über einen Jumper zu steuern.
Prozesse ansehen mit dem Kommando
root@armv5te:~# ps -efl
Die Ausgabe von meinem Board ist hier: prozesse.txt
Der einzige persistente Speicher auf dem Gnublin LPC3131 Board ist eine Micro SD Karte (SD-HC) mit 1, 2 oder 4 GByte Speicher. Karten von verschiedenen Herstellern (SanDisk, Kingston, Noname) und mit unterschiedlichen Zugriffsklassen sollten funktionieren.
Eine eigene SD Karte erstellen
Mit dem Python Programm gnublin-card.py kann man eine eigene Micro-SD Karte erstellen, die mit dem Gnublin LPC3131 Board funktioniert. Das Programm holt von einem Server im Netz den Apex Bootloader und das Root Filesystem. Es erlaubt die SD Karte neu zu partitionieren und die vorher geholten Programme darauf zu speichern.
Das Programm kann man hier herunterladen:
$GNUBLINDIR/work_eplpc3131/tools/gnublin-card.py
Die wesentlichen Operationen, die das Programm durchführen kann, sind
- Apex Bootloader holen
- Root Filesystem holen
- Partitionen auf der Micro SD Karte löschen
- Neue Partitionen anlegen (BootIt und ext2)
- Ext2 Filesystem auf Partition 1 erstellen
- Partitionen neu beschreiben
Mit der Option -h bekommt man eine Liste aller Optionen:
user@linux:~$ sudo python gnublin-card.py -h gnublin-card.py [opts] -h, --help This usage text --version Print program version -c, --cmdline Run tool interactively (commandline) -i, --info Print device info -d, --device=<device> Device, default /dev/sdb -v, --verbose Be verbose --delete Delete all partitions -p, --partitions Make partitions -e, --ext2 run mke2fs on sd card root partition --apex-path=... Pathname of apex bootloader (default ./apex.bin) -a, --apex Write apex bootloader -r, --root Write root fs to ext2 partition -u Unmount ext2 partition --fetch-apex Fetch apex bootloader from server --fetch-rootfs Fetch root filesystem from server --fetch-kernel Fetch kernel from server (optional!) --all Run all steps to create a Gnublin Micro SD card It may be neccessary to run this tool as user root: sudo python gnublin-card.py [opts]
Alle wesentlichen Teilschritte zum Erstellen einer Micro SD Karte fasst die Option --all zusammen.
user@linux:~$ sudo python gnublin-card.py --all
Da das Root Filesystem mit über 600 MByte ziemlich gross ist, dauert sowohl der Download als auch das Beschreiben der Karte ziemlich lange. Zum Schreiben kann man in etwa von 10 Minuten Zeit ausgehen, der Download hängt natürlich stark von der Geschwindigkeit des Internet Zuganges ab. Nachdem die Daten aber einmal aus dem Netz geladen wurden, werden sie für das Erstellen der nächsten SD Karten wiederverwendet. Alle Daten werden im automatisch angelegten Verzeichnis gnublin-tmp/ abgelegt.
Das Programm hat ausserdem einen interaktiven Modus, der über eine Kommandozeile gesteuert wird. Dazu startet man es mit der -c ("commandline") Option:
user@linux:~$ sudo python gnublin-card.py -c SD card is device '/dev/sdb' 'help' (short 'h') prints a short usage text. gnublin>
Mit dem Kommando h (help) bekommt man eine Liste aller Kommandos:
gnublin> h Use either the long or short names (e.g. 'fetch-apex' or '1'). Multiple commands can be combined on a line, e.g. "1 2 4 5 6 7 8". help h this help quit q quit program fetch-apex 1 fetch apex bootloader (default './apex.bin') fetch-rootfs 2 fetch root filesystem (default 'rootfs.tar.gz') fetch-kernel 3 fetch kernel binary and modules (default 'kernel-7') sd-delete-partitions 4 delete partitions sd-create-partitions 5 make sd card partitions BootIt and ext2 sd-mke2fs 6 create ext2 filesystem on sd card sd-write-apex 7 write apex to sd card BootIt partition sd-write-rootfs 8 write root filesystem to sd card 'ext2' partition sd_info 9 list sd card partitions sd-umount u unmount ext2 sd card partition
Nun kann man auf dem gnublin> Prompt die gewünschten Operationen angeben, z.B.
gnublin> 4 5 6 7
um eine SD Karte neu zu partitionieren, eine Partition mit dem ext2 Filesystem zu versehen und den Apex Bootloader darauf zu schreiben.
Einstellungen
Es kann gut sein, dass die SD Karte an einem anderen Rechner nicht wie bei mir auf /dev/sdb liegt, sondern z.B. auf /dev/sdc. Das muss man dem Programm durch die -d/--device= Option mitteilen:
user@linux:~$ sudo python gnublin-card.py -d /dev/sdc ... user@linux:~$ sudo python gnublin-card.py --device=/dev/sdc ...Das Wurzelverzeichnis des Servers, in dem die Dateien zum Download (Apex, Root Filesystem, Kernel) liegen, wird in gnublin-card.py in der Variable WEBDIR angegeben. Das war am Anfang
WEBDIR = http://elk.informatik.fh-augsburg.de/pub/gnublin-lpc3131Die Dateien liegen nun auch unter:
WEBDIR = "http://www.gnublin.org/downloads"
Mit dem Apex Bootloader kommt der Gnublin Anwender im Normalfall gar nicht in Berührung, da er nur eine schnell durchlaufene Zwischenstation auf dem Weg zum betriebsbereiten Linux ist. Anfänger - siehe meine Einteilung der Benutzergruppen in der Einleitung - sollten dieses Kapitel also erst einmal ignorieren.
Wenn sich Fortgeschrittene einen eigenen Kernel (zImage) kompilieren, dann kann es sein, dass mehrere verschiedene Kernel-Images im Root Filesystem herumliegen und man eines beim Booten auswählen muss. Das geht mit den Apex Kommandos, die weiter unten beschrieben sind.
Die Gurus unter den Anwendern möchten vielleicht eigene Hardware Erweiterungen in den Bootloader einbauen. Dazu ist natürlich unumgänglich, dass man sich näher mit dem Apex Quelltext befasst.
Nachdem man das Gnublin Board an die USB Konsole mit einem USB Kabel angesteckt hat, sollte man auf der Konsole folgende Meldung sehen:
APEX Boot Loader 1.6.8-ep -- Copyright (c) 2004-2008 Marc Singer compiled for Embedded Projects EPLPC3131 on 2011.Sep.28-23:58:20 APEX comes with ABSOLUTELY NO WARRANTY. It is free software and you are welcome to redistribute it under certain circumstances. For details, refer to the file COPYING in the program source. apex => mem:0x11029000+0xd8d8 (55512 bytes) env => lnand:512k+256k (bad-region) Use the command 'help help' to get started. # wait 2
Nachdem Apex startet kann man für kurze Zeit - meist 1 bis 2 Sekunden, gegeben durch die wait Umgebungsvariable in Apex - durch Drücken der Strg-C Kombination den Bootvorgang abbrechen. Danach kann man auf dem apex> Prompt Kommandos eingeben.
Der nächste Schritt im Bootvorgang ist das Laden des GNU/Linux Kernels von der SD Karte in den Hauptspeicher. Das wird mit der Apex Kommandozeile
copy ext2://1/zImage 0x30008000
erledigt. Gestartet wird der Kernel im Speicher durch das Apex Kommando
boot
Beide Kommandos werden automatisch vom Bootloader aufgerufen. Nach dem boot Kommando sollten die Boot-Meldungen des Kernels im Konsolenfenster erscheinen, so wie hier:
Booting kernel at 0x30008000... Uncompressing Linux... done, booting the kernel. Linux version 2.6.33 (hhoegl@gorilla) (gcc version 4.5.1 (GCC) ) #4 Tue Sep 27 1 0:56:20 CEST 2011 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177 CPU: VIVT data cache, VIVT instruction cache Machine: NXP EA313X Memory policy: ECC disabled, Data cache writeback Built 1 zonelists in Zone order, mobility grouping off. Total pages: 2032 Kernel command line: console=ttyS0,115200n8 root=/dev/mmcblk0p1 rw rootwait PID hash table entries: 32 (order: -5, 128 bytes) Dentry cache hash table entries: 1024 (order: 0, 4096 bytes) Inode-cache hash table entries: 1024 (order: 0, 4096 bytes) Memory: 8MB = 8MB total Memory: 5480KB available (2240K code, 144K data, 104K init, 0K highmem) [und so weiter ...]
Mit help bekommt man eine Liste aller Kommandos:
apex> help sorting 29 alias - show or set aliases boot - boot Linux checksum - compute crc32 checksum clock - Get clock speed compare - compare regions copy - copy data between devices crc - compute crc32 checksum using lpc313x tables drvinfo - list available drivers dump - dump data to the console erase - erase device region fill - fill a region with a byte go - execute program at address help - list available commands image - image handling info - display information about a region descriptor mmc - test MMC controller printenv - show the environment reset - reset target saveenv - save environment to non-volatile memory setenv - set environment variable unalias - remove an alias unsetenv - restore environment variable to default version - show version and copyright wait - wait before continuing xreceive - receive data over the serial line
Ein paar oft gebrauchte Kommandos sind info, copy, printenv und boot.
Mit info kann man das Inhaltsverzeichnis einer Partition ausgeben, im folgenden Beispiel ist das die Partition 1:
apex> info ext2://1
Die Ausgabe sieht wie folgt aus:
./ ../ lost+found/ zImage etc/ ...
Mit copy kopiert man eine Datei von der SD Karte in den Speicher. Im folgenden Beispiel ist die Datei zImage auf dem ext2 Filesystem in Partition 1. Das zImage liegt anschliessend ab Adresse 0x30008000 im Speicher:
apex> copy ext2://1/zImage 0x30008000
Damit wird die Apex Umgebungsvariablen ausgegeben.
apex> printenv ext2-drv *= mmc cmdline *= console=ttyS0,115200n8 root=/dev/mmcblk0p1 rw rootwait startup *= wait 2; copy ext2://1/zImage 0x30008000; boot kernelsrc *= lnand:768k+2m bootaddr *= 0x30008000 arch-number *= 9998
Man kann das Kommando auch mit p abkürzen.
Das boot Kommando startet den Kernel im Arbeitsspeicher. Wenn man es ohne weitere Argumente gibt, dann wird die fixe Umgebungsvariable cmdline als Kernel Kommandozeile verwendet.
Man kann die Kernel Kommandozeile auch als Argumente des boot Kommandos angeben, z.B. so wie hier:
boot console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait
Der Apex Quelltext ist in $GNUBLINDIR/work_eplpc3131/apex/.
Anleitung:
Pfade und Umgebungsvariable der ELDK Toolchain setzen. Dazu gibt es das Shell Skript set.sh in $GNUBLINDIR/work_eplpc3131.
So sieht set.sh aus:
P1=/opt/eldk-5.0/armv5te/sysroots/i686-oesdk-linux/usr/bin/armv5te-linux-gnueabi/ P2=/opt/eldk-5.0/armv5te/sysroots/i686-oesdk-linux/bin/armv5te-linux-gnueabi/ export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabi- export PATH=$P1:$P2:$PATHDieses Skript wird "gesourced", man gibt dazu ein . ./set.sh.
Apex Quelltextverzeichnis anlegen:
cd $GNUBLINDIR/work_eplpc3131/apex/ tar zxvf apex-1.6.8.tar.gz mv apex-1.6.8 work_1.6.8Patches anwenden:
cd work_1.6.8 patch -p1 < ../apex-1.6.8_lpc313x.patch patch -p1 < ../ep3131.patchKompilieren:
make menuconfig make apex.binApex auf die SD Karte schreiben. Ich nehme bei dem folgenden Kommando an, dass die Karte als /dev/sdb erkannt wurde und dass sich der Bootloader auf der zweiten Partition befindet:
sudo dd if=src/arch-arm/rom/apex.bin of=/dev/sdb2 bs=512 syncMan kann das auch mit dem gnublin-card.py Programm bequem erledigen, siehe die Beschreibung an anderer Stelle in diesem Text.
Für den LPC3131 von NXP gibt es einen angepassten Linux Kernel für ARM Controller. Genauer gesagt, gibt es mehrere Wege, um zu so einem Kernel zu kommen. Ich habe folgenden Weg gewählt:
Nehme das folgende Git Repository
git://git.lpclinux.com/linux-2.6.33-lpc313x http://git.lpclinux.com/?p=linux-2.6.33-lpc313x.gitund hole den Kernel mit dem Kommando:
git clone git://git.lpclinux.com/linux-2.6.33-lpc313xNach dem Klonen gibt es das Verzeichnis linux-2.6.33-lpc313x, das aktuell etwa 640 MByte gross ist. Das Verzeichnis ist ein lokales Git Repository auf dem Git Kommandos angewendet werden können.
An diesem Punkt gibt es noch keine Kernel Konfiguration .config!
Gehe in das Quelltextverzeichnis:
cd linux-2.6.28.2-lpc313xWende die bisher erstellten Patches an:
patch -p1 < $GNUBLINDIR/work_eplpc3131/kernel/2.6.33/001-mmc-card-detect.patch patch -p1 < $GNUBLINDIR/work_eplpc3131/kernel/2.6.33/002-gpiolib.patch patch -p1 < $GNUBLINDIR/work_eplpc3131/kernel/2.6.33/003-usb-panic.patch
Wende optionale weitere Patches an, die man z.B. hier finden kann:
Umgebungsvariable für den ELDK Cross-Compiler anlegen (siehe auch das Kapitel zum ELDK):
. $GNUBLINDIR/work_eplpc3131/set.shDanach muss die PATH Variable um den Pfad auf den Crosscompiler erweitert sein und es muss die Variablen ARCH und CROSS_COMPILE geben.
Kernel Konfiguration besorgen
Es gibt in arch/arm/configs/ea313x_defconfig eine Default-Konfiguration.
Man gibt das Kommando ein:
make ea313x_defconfigDie Ausgabe ist:
HOSTCC scripts/kconfig/kxgettext.o SHIPPED scripts/kconfig/zconf.tab.c SHIPPED scripts/kconfig/lex.zconf.c SHIPPED scripts/kconfig/zconf.hash.c HOSTCC scripts/kconfig/zconf.tab.o HOSTLD scripts/kconfig/conf # # configuration written to .config #Kernel kompilieren:
make zImageDas letzte Stück der Ausgaben sieht in etwa so aus:
... LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready AS arch/arm/boot/compressed/head.o GZIP arch/arm/boot/compressed/piggy.gzip AS arch/arm/boot/compressed/piggy.gzip.o CC arch/arm/boot/compressed/misc.o SHIPPED arch/arm/boot/compressed/lib1funcs.S AS arch/arm/boot/compressed/lib1funcs.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is readyDas erzeugte zImage kann "zu Fuss" von arch/arm/boot/zImage in das Root Filesystem kopiert werden.
Die Grösse des gesamten Verzeichnisses ist durch diesen Schritt auf etwa 620 MByte gewachsen.
Module kompilieren:
make modulesDie Ausgabe sieht bis auf ein paar "Warnings" so aus:
CHK include/linux/version.h CHK include/generated/utsrelease.h CALL scripts/checksyscalls.sh CC [M] drivers/scsi/scsi_wait_scan.o CC [M] drivers/usb/gadget/fsl_udc_core.o CC [M] drivers/usb/gadget/ether.o CC [M] drivers/usb/gadget/file_storage.o LD [M] drivers/usb/gadget/fsl_usb2_udc.o LD [M] drivers/usb/gadget/g_ether.o LD [M] drivers/usb/gadget/g_file_storage.o Building modules, stage 2. MODPOST 4 modules CC drivers/scsi/scsi_wait_scan.mod.o LD [M] drivers/scsi/scsi_wait_scan.ko CC drivers/usb/gadget/fsl_usb2_udc.mod.o LD [M] drivers/usb/gadget/fsl_usb2_udc.ko CC drivers/usb/gadget/g_ether.mod.o LD [M] drivers/usb/gadget/g_ether.ko CC drivers/usb/gadget/g_file_storage.mod.o LD [M] drivers/usb/gadget/g_file_storage.koDie erzeugten Kernelmodule erkennt man an der Endung .ko ("kernel object").
Module installieren:
make modules_install INSTALL_MOD_PATH=<modules-install-dir>Damit wird der Baum der Module (/lib/modules/2.6.33/...) unter dem Verzeichnis <modules-install-dir> angelegt. Wie das Root Filesystem aufgebaut ist kann man dem Filesystem Hierarchy Standard (FHS) entnehmen.
Nach der Installation im Root Filesystem ist das Kernel zImage direkt im Wurzelverzeichnis / zu finden und die Module sind in /lib/modules/2.6.33/.
Häufig möchte man Änderungen an der Konfiguration des Linux Kernes vornehmen und geht dazu in das Konfigurationsmenü (auch bei diesem Schritt müssen die Variablen in set.sh gesetzt sein!):
make menuconfig
Nach Verlassen von menuconfig hat man eine neue Konfigurationsdatei .config und kann damit den Kernel neu kompilieren. Einige auf diese Weise entstandene neue Konfigurationen habe ich hier gesammelt:
$GNUBLINDIR/work_eplpc3131/kernel/install/
Um die verschiedenen Konfigurationsdateien zu sehen und auch nicht zu verwechseln, habe ich den Punkt durch einen Unterstich ersetzt und an jede eine Nummer angehängt, z.B. _config-8. Falls man den Kernel mit dieser Konfiguration übersetzen möchte, muss man sie wieder in .config kopieren und dann eingeben:
make oldconfig make zImage
Welche Module wurden bereits getestet?
Eine Reihe von Modulen habe ich bereits mit Erfolg beim Gnublin LPC3131 verwendet:
USB gadget device
- g_zero ("zero gadget" für USB)
- g_file_storage (USB gadget)
- g_ether (ethernet gadget für USB)
Insgesamt gibt es alle diese gadget Treiber : g_serial.ko, g_file_storage.ko, g_ether.ko, g_mass_storage.ko, gadgetfs.ko, g_printer.ko, g_cdc.ko, g_zero.ko.
usbnet
asix (D-Link DUB-E100 mit ASIX AX88772 USB 2.0 Ethernet)
Foto: DUB-E100
- pegasus (kleiner blauer USB-zu-Ethernet Stecker mit
ADMtek ADM8511 "Pegasus II" USB Ethernet)
Foto: Pegasus
rt2500usb (ASUS USB WLAN Dongle WL-167G Version 1)
Zusätzlich mussten noch die "wireless tools" crosskompiliert werden, um mit iwconfig die drahtlose Ethneret Schnittstelle zu konfigurieren.
Foto: Asus WL-167G
pca953x
I2C Treiber für PCA953x, PCA9555 I/O Expander und so weiter.
ftdi_sio
USB-zu-UART bzw. zu-RS232 Adapter mit USB Controller von Ftdichip.
usbhid
USB Human Interface Devices (HID), z.B. Tastatur, Maus, Scanner...
Demo-Module im Verzeichnis $GNUBLINDIR/work_eplpc3131/prog/
- gpio-mod
Boot Optionen in Apex
Falls ein Kernel wegen irgendeinem Problem im Init-System hängenbleibt, dann kann man Init testweise durch folgende Kommandozeile in Apex umgehen:
boot console=ttyS0,115200n8 root=/dev/mmcblk0p1 rw rootwait init=/bin/sh
Weiterführende Links
"Vanilla" GNU/Linux Kernel: http://www.kernel.org
Patches von NXP LPC3131 für den Vanilla Kernel
Board Support Package von NXP fuer den LPC3131
Filesystem Hierarchy Standard (FHS)
Newsgroups und Foren
Wir verwenden das ELDK 5.0 von Denx (http://www.denx.de) als Root Filesystem.
Vorteile:
Solide, saubere und reproduzierbare Grundlage, baut auf Yocto (http://www.yoctoproject.org), das wiederum auf Poky Linux (http://pokylinux.org), das wiederum auf OpenEmbedded (http://www.openembedded.org).
Wird aktiv weiterentwickelt. Siehe das Git Repository
git://git.denx.de/eldk.gitDer HTML Zugang für dieses Repository ist hier: http://git.denx.de/eldk.git.
Das ELDK ist hier dokumentiert:
Es enthält sehr viele fertig verwendbare vorkompilierte Programme, was einen Anreiz zum Ausprobieren und Herumspielen gibt. Das kann aber auch als Nachteil empfunden werden (siehe unten). Minimalisten möchten gerne die kleinstmögliche Distribution, um mit dem Board arbeiten zu können.
Nachteile:
- Im Originalzustand ist es mit etwa 600 MB sehr gross. Viele Programme können auf dem Gnublin Board wegen dem kleinen 8 MByte SDRAM Speicher gar nicht genutzt werden, z.B. der GCC Compiler, X11 und Gtk.
In Zukunft sollten wir aus den ELDK Sourcen eine kleinere Distribution erzeugen, die besser an die Bedürfnisse des Gnublin Boards angepasst ist.
Um mit dem ELDK Cross-Compiler zu arbeiten, müssen ein paar Umgebungsvariable gesetzt werden. Ich habe in set.sh alles Wichtige zusammengefasst.
set.sh:
P1=/opt/eldk-5.0/armv5te/sysroots/i686-oesdk-linux/usr/bin/armv5te-linux-gnueabi/ P2=/opt/eldk-5.0/armv5te/sysroots/i686-oesdk-linux/bin/armv5te-linux-gnueabi/ export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabi- export PATH=$P1:$P2:$PATH
Diese Datei muss man "sourcen", das heisst wie folgt aufrufen:
. ./set.sh
Die Datei set.sh ist in $GNUBLINDIR/work_eplpc3131/.
To Do
Bootvorgang (init Skripte). Nötige Änderungen am unbehandelten ELDK 5.
Paketverwaltung
Alternative Root Filesysteme
- Debian/ARM
- Gentoo/ARM
- Fedora/ARM
- Linux-From-Scratch (LFS)
Das Root Filesystem findet man im installierten ELDK 5 auf dem PC an dieser Stelle:
/opt/eldk-5.0/armv5te/rootfs/
Man kann es mi/t ein paar kleineren Aenderungen direkt auf die Micro-SD Karte kopieren.
Ein angepasstes Root Filesystem findet man hier:
http://elk.informatik.fh-augsburg.de/pub/gnublin-lpc3131/
XXX Dieses Kapitel muss ich erst noch schreiben. In etwa sollen folgende Themen angesprochen werden:
Programme in C auf dem Entwicklungsrechner cross-kompilieren. Wir verwenden dazu das ELDK 5.x.
Als Alternative zu C kann man auf dem Entwicklungsrechner Programme in Go (http://golang.org) direkt für ARMv5 erstellen.
Beispiel:
/* hello.go */ package main import "fmt" func main() { fmt.Printf("hello, world\n") }Mit den Kommandos
5g hello.go 5l hello.5wird die ausführbare Datei 5.out erstellt. Der go Cross-Compiler für ARMv5 hat den Namen 5g, der Linker 5l.
Programmieren mit Interpretersprachen
Shell (bash)
Lua
Python. Für den "grossen" Python Interpreter (Version 2.7 der 3.2) hat Gnublin mit 8 MByte knapp zu wenig Speicher. Es gibt die Variante "Python-on-a-Chip", die sich besser eignen würde.
Squirrel
Lisp (Hedgehog Lisp, http://hedgehog.oliotalo.fi)
Pawn
Forth (gforth)
Perl
Programme debuggen mit gdb.
Folgende Programme habe ich ohne viel Aufwand für das Gnublin Board cross-kompiliert:
- curl
- lighttpd-1.4.29
- lynx-2.8.7
- lua-5.1.4
- mongoose
- netcat
- pcre-8.13
- pure-ftdp
- Python-2.7.1
- squirrel
- wget
- wireless_tools
Siehe $GNUBLINDIR/work_eplpc3131/cross-compiled/
Kurze Anleitung für lighttpd
Pfade auf den ELDK Cross-Kompiler setzen:
. ./set.shpcre-8.13 kompilieren mit
CC=arm-linux-gnueabi-gcc RANLIB=arm-linux-gnueabi-ranlib \\ STRIP=arm-linux-gnueabi-strip LD=arm-linux-gnueabi-ld \\ ./configure --host=arm-linux-gnueabi --enable-staticlighttpd kompilieren mit
CC=arm-linux-gnueabi-gcc RANLIB=arm-linux-gnueabi-ranlib \\ STRIP=arm-linux-gnueabi-strip LD=arm-linux-gnueabi-ld \\ ./configure --host=arm-linux-gnueabi --disable-static \\ --enable-shared --without-zlib --without-bzip2
XXX Hello World Demo
Forum
Embedded Projects
http://www.gnublin.org/downloads/ (fuer gnublin-card.py)
Git Repository https://code.google.com/p/gnublin
git clone https://code.google.com/p/gnublin/
Hochschule Augsburg
NXP