Benutzer-Werkzeuge

Webseiten-Werkzeuge


raspberry_pi_kernelprogrammierung:helloworld

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
raspberry_pi_kernelprogrammierung:helloworld [2024/01/26 14:52] torsten.roehlraspberry_pi_kernelprogrammierung:helloworld [2024/01/26 15:49] (aktuell) – [3. Testen des "Hallo Welt" Moduls] torsten.roehl
Zeile 20: Zeile 20:
 Ein Kernel-Modul zur Ansteuerung des GPIO-Ports des Raspberry Pi kann 250 mal schneller sein als ein herkömmlicher Zugriff auf die Ports! Ein Kernel-Modul zur Ansteuerung des GPIO-Ports des Raspberry Pi kann 250 mal schneller sein als ein herkömmlicher Zugriff auf die Ports!
 </WRAP> </WRAP>
 +
 +==== Voraussetzung ====
 +  * Gute Linuxkenntnisse und C-Programmierung.
 +  * Getestet wurde mit Rasbian Debian-Wheezy, d.h. ein Raspberry Pi mit installiertem Linux-System muss zur Verfügung stehen.
 +<WRAP center round info 100%>
 +Grundsätzlich ist ein //Raspberry Pi// nicht notwendig um ein Kernel-Modul zu programmieren, dann muss aber auf dem Entwicklungsrechner (Hostrechner) eine sogenannte //Cross-Entwicklungsumgebung// eingerichtet werden, worauf dieser Abschnitt aber nicht eingeht (siehe  http://elinux.org/RPi_Kernel_Compilation ). Die in diesem Abschnitt erklärte Methode unterscheidet sich auch von der auf "offiziellen" Methode, wie sie auf //elinux.org// beschrieben wurde. Die dort beschriebene Methode erfordert mehr Fachwissen, insbesondere wenn nicht alles wie vorgegeben abläuft. Die hier vorgestellte Vorgehensweise erstellt auch keinen neuen Kernel, was ausgesprochen bequem ist, denn das erstellen eines Kernel auf dem //Raspberry Pi//  kann 10-12 Stunden dauern.
 +</WRAP>
 +
 +
  
 =====Überblick  ===== =====Überblick  =====
 +Die Quellen des Linux-Kernels müssen installiert werden, um einen Treiber (Treiber werden in der Regel als Kernel-Modul zur Verfügung gestellt) übersetzen zu können. Außerdem muss das System für die Modul Programmierung konfiguriert werden.
 +
 +  - Kernel-Quellen (auch Kernel-Header genannt) herunterladen
 +  - Hallo Welt Modul erstellen und übersetzen (compilieren)
 +  - Testen des "Hallo Welt" Moduls
 +
 ===== Details ===== ===== Details =====
 +==== 1. Kernel-Quellen (auch Kernel-Header genannt) herunterladen ====
 +Es können nicht irgendwelche Kernel-Quellen heruntergeladen werden, sondern nur die, die zu dem installierten Betriebssystem passen. Auch muss das erstellte Kernel-Modul genau (Versionsmatching) zum laufenden Kernel passen, da der Kernel sonst seine Zusammenarbeit verweigert. In diesem Fall können wir das Modul gar nicht erst laden.  Außerdem müssen die verwendeten Programme wie z.B. ''insmod, modprobe, lsmod, rmmod'' oder ''gcc'' zum kompilierten Kernel passen.
 +
 +|{{ :inf:msr:raspi_kernel_1.png? |}}|
 +|Mit ''uname -r'' kann die Version des Installierten Kernel in Erfahrung gebracht werden. Es handelt sich hier um einen Kernel 3.10 (Patchlevel 10, Sublevel 25).|
 +
 +Wir werden deshalb erst einmal den Raspberry Pi auf den aktuellen Stand setzen und anschließend die Kernel-Version ermitteln, die heruntergeladen werden muss.
 +
 +Geben Sie die nachfolgende Zeile auf der Konsole ein:
 +<code> sudo rpi-update</code>
 +
 +
 +
 +<WRAP center round info 100%>
 +Mehr zum rpi-update Programm unter  https://github.com/Hexxeh/rpi-update.
 +
 +Mit ''sudo apt-get install rpi-update'' kann das Programm gegebenenfalls nachinstalliert werden.
 +</WRAP>
 +|{{ :inf:msr:raspi_kernel_3.png? |}}|
 +|Nach dem Update steht jetzt der Kernel 3.12 (Patchlevel  12, Sublevel 19) zur Verfügung. Für diesen Kernel müssen nun die Kernel-Quellen heruntergeladen werden.|
 +
 +Als nächstes müssen die Kernelheader (Kernel-Quellen) installiert werden, damit man in der Lage ist, ein Kernel-Modul auch übersetzen zu können.
 +
 +Falls Sie die nachfolgende Fehlermeldung bekommen wenn Sie ''rpi-source'' aufrufen, sollten Sie die Anweisung in der //RPI-SOURCE Box// berücksichtigen und Anschließend noch einmal ''rpi-source'' aufrufen.
 +<WRAP center round important 100%>
 +<code>ERROR:
 +gcc version check: mismatch between gcc (4.6.3) and /proc/version (4.7.2)
 +Skip this check with --skip-gcc</code>
 +</WRAP>
 +
 +
 +<code>sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source && sudo chmod +x /usr/bin/rpi-source && /usr/bin/rpi-source -q --tag-update
 +
 +rpi-source </code>
 +
 +Die erste Zeile installiert das Programm rpi-source, und in der zweiten Zeile wird es dann aufgerufen. Im Homeverzeichnis wird ein Verzeichnis namens "linux" angelegt. Dieses Verzeichnis ist ein Link auf das Verzeichnis "linux-c3db7205bcd8988cf7c185e50c8849542554b1f5", das sich ebenfalls im Homeverzeichnis befindet. Die heruntergeladene Datei (linux-c3db7205bcd8988cf7c185e50c8849542554b1f5.tar.gz) kann, um Speicherplatz zu sparen, gelöscht werden.
 +
 +<WRAP center  box 100%>
 +Box: RPI-SOURCE 
 +
 +Mehr zum ''rpi-source'' Programm:   https://github.com/notro/rpi-source/wiki
 +
 +Insbesondes wenn Sie die nachfolgende Fehlermeldung bekommen, sollten Sie so vorgehen wie im Link beschrieben, um auch den richtigen Compiler (GCC Version) zu bekommen.
 +
 + Der Link beschreibt warum die folgenden Befehle angewandt werden müssen. Vergessen Sie nicht anschließend, noch einmal rpi-source aufzurufen.
 +<code>sudo apt-get install gcc-4.7 g++-4.7
 +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6
 +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.7
 +sudo update-alternatives --config gcc
 +sudo apt-get install libncurses5-dev</code>
 +</WRAP>
 +
 +
 +==== 2. Hallo Welt Modul erstellen und übersetzen (compilieren) ====
 +Ein minimales Kernel-Modul wird nun übersetzt. Dazu legen wir im Verzeichnis ''/home/pi'' das Verzeichnis ''kernel'' an. Dieses Verzeichnis enthält die Datei ''hello_world.c'' und **Makefile**.
 +
 +
 +<Code C linenums:1>
 + #include <linux/module.h>
 + #include <linux/init.h>
 +
 + /* Metainformation */
 + MODULE_LICENSE("GPL");
 + MODULE_AUTHOR("Torsten Röhl <devel@physics4school.de>");
 + MODULE_DESCRIPTION("Sample hello_world kernel module" ); 
 +
 + /* Loads the module in the kernel */
 + static int __init init_helloworld (void)
 + {
 +     printk("Hello Welt: init_helloworld \n");
 +     return 0;
 + }  
 +
 + /* Removes the module from kernel */
 + static void __exit exit_helloworld(void)
 + {
 +     printk("GoodBye World: exit_helloworld \n");
 + }
 +
 + module_init( init_helloworld );
 + module_exit( exit_helloworld );    
 +</Code>
 +
 +== Erläuterung ==
 +Das Einbinden  der Header-Dateien (*.h). So sind z.B. __init und __exit in init.h definiert.
 +
 +Mit dem MODULE_XXX-Makros können Metainformationen gesetzt werden. Sie können mit dem  modinfo tool ausgelesen werden, lediglich das Makro MODULE_LICENCE ist obligatorisch.
 +
 +Die Funktion init_helloworld   wird beim Laden des Moduls aufgerufen.
 +Die Funktion exit_helloworld   wird beim Entladen des Moduls aufgerufen.
 +
 +Die beiden Makros module_init und module_exit sorgen dafür, dass man die Funktionsnamen (hier  init_helloworld und exit_helloworld) frei wählen kann.
 +
 +
 +
 +
 +Das Einbinden  der Header-Dateien (''*.h''). So sind z.B. ''__init'' und ''__exit'' in ''init.h'' definiert.
 +
 +Mit dem ''MODULE_XXX-Makros'' können Metainformationen gesetzt werden. Sie können mit dem  //modinfo tool// ausgelesen werden, lediglich das Makro ''MODULE_LICENCE'' ist obligatorisch.
 +
 +Die Funktion ''init_helloworld''   wird beim Laden des Moduls aufgerufen.\\
 +Die Funktion ''exit_helloworld''   wird beim Entladen des Moduls aufgerufen.
 +
 +Die beiden Makros ''module_init'' und ''module_exit'' sorgen dafür, dass man die Funktionsnamen (hier  ''init_helloworld'' und ''exit_helloworld'' frei wählen kann.\\
 +Die Datei kann mit einem Editor (z.B. Kate oder vi)  erstellt werden. 
 +
 +
 +
 +=== Vom Quellcode zum Modul: ===
 +
 +Um ein vollständiges Kernel-Modul zu erstellen, muss der Quellcode noch übersetzt werden. Das Übersetzen (Kompilieren) des Quellcodes (Sourcecode) in ein ausführbares Programm erledigt man am besten mit einer Steuerdatei (Makefile) und dem Programm ''make''.
 +
 +
 +
 +
 +<code>ifneq ($(KERNELRELEASE),)
 +   obj-m := hello_world.o
 + 
 + else
 +   KDIR := /lib/modules/$(shell uname -r)/build
 +   PWD := $(shell pwd)
 + 
 + default:
 +   $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
 + endif</code>
 +
 +
 +Beim Makefile ist auf einiges zu achten, z.B.:
 +
 +  * Die Datei muss exakt Makefile geschrieben werden.
 +  * Die Zeilen 2, 5, 6 und 9 müssen mit //"Tab"// (Tabulatortaste) beginnen.
 +
 +Um nicht an dieser Stelle zu scheitern, empfehle ich, dieses Makefile downzuloaden: ''kernel.zip''.
 +Angenommen, im Verzeichnes ''kernel'' befinden sich nun die Dateien ''helloworld.c'' und ''Makefile'', dann genügt ein einfacher Aufruf von ''make'', um das Modul zu erstellen.
 +<code>pi@raspberrypi ~/kernel $ make</code>
 +Damit ''make'' weiß, was es tun soll, sollte man sich im Verzeichnis kernel befinden.
 +
 +==== 3. Testen des "Hallo Welt" Moduls ====
 +
 +
 +Um das Modul zu testen werden die Modul-Utilities benötigt. Darunter versteht man einen Satz von Hilfsprogrammen, um //Kernelmodule// zu laden, entladen u.s.w.
 +
 +Um das Modul zu laden/entladen, werden //Rootrechte// benötigt.  
 +
 +Folgende Programme (''modutils'') werden verwendet:
 +
 +  * ''modinfo'': liefert Informationen über ein Modul 
 +  * ''insmod'': fügt zur Laufzeit Module in den Linux-Kernel ein
 +  * ''lsmod'': zeigt alle geladenen Module an
 +  * ''rmmod'': entfernt Laufzeitmodule aus dem Kernel
 +
 +=== Beispiel ===
 + Hier die Ausgabe des ''modinfo''-Programms:
 +
 +<code>pi@raspberrypi ~/kernel $ modinfo hello_world.ko
 +filename:       /home/pi/kernel/hello_world.ko
 +description:    Sample hello_world kernel module
 +author:         Torsten Röhl <devel@physics4school.de>
 +license:        GPL
 +srcversion:     793A736C473976825C9475C
 +depends:        
 +vermagic:       3.12.19+ preempt mod_unload modversions ARMv6 </code>
 +
 +Laden des Moduls:
 +<code>pi@raspberrypi ~/kernel $ sudo insmod hello_world.ko</code>
 +Überprüfen, ob das Modul korrekt geladen wurde:
 +
 +<code>spi@raspberrypi ~/kernel $ lsmod | grep hello_world
 +hello_world              735  0 </code>
 +
 +Um die Ausgabe von lsmod nicht zu lang zu machen, können wir mit grep hello_world nach hello_world suchen. Die Ausgabe zeigt an, dass die Suche erfolgreich war, d.h. das Modul korrekt geladen wurde.
 +
 +Entladen des Moduls:
 +<code>pi@raspberrypi ~/kernel $ sudo rmmod hello_world.ko</code>
 +
 +Lohnend ist auch ein Blick in die Datei ''/var/log/messages'':
 +
 +<code># cat /var/log/messages
 +May 16 16:24:38  kernel: Hello World: init_helloworld
 +May 16 16:26:16 kernel: GoodBye World: exit_helloworld</code>
 +
 ===== Zusammenfassung ===== ===== Zusammenfassung =====
 +Auch wenn der Quellcode keine zwanzig Zeilen lang ist, gibt es bei der Erstellung jedoch diverse Fehlermöglichkeiten.
 +Wenn alles bis hier geklappt hat, wurde jedoch eine Menge erreicht:
 +
 +  * Die Kernelquellen und modutils sind installiert und lauffähig.
 +  * Der Kompiler und make sind lauffähig.  
 +  * Das fertige Kernel-Modul ''hello_world.ko'' wurde erfolgreich zur Laufzeit in den Kernel geladen und entladen.
 +    Ein komplettes System für die Kernelentwicklung auf dem Raspberry Pi steht nun zur Verfügung.
 +
 +
 ===== Literatur ===== ===== Literatur =====
  
raspberry_pi_kernelprogrammierung/helloworld.1706280746.txt.gz · Zuletzt geändert: 2024/01/26 14:52 von torsten.roehl