Echtzeiterweiterung für Linux

Echtzeiterweiterung für Linux
RTAI-Linux
Echtzeiterweiterung für Linux
Fachbereich:
Elektro- und Kommunikationstechnik, Burgdorf
Abteilung für Technische Informatik
Autor:
Niklaus Burren
Datum:
Juni 2006
Inhaltsverzeichnis
1. Funktionsprinzip .................................................................................................. 1
1.1.
Architektur...................................................................................................1
1.2.
Realtime Hardware Abstraction Layer RTHAL ..........................................................2
1.3.
Interrupt-Handling..........................................................................................3
1.4.
Scheduler ....................................................................................................3
1.4.1. Uni-Prozessor-Scheduler (UP).....................................................................4
1.4.2. SMP-Scheduler (SMP) ...............................................................................4
1.4.3. Multi-Uni-Porzessor-Scheduler (MUP) ...........................................................4
1.5.
Timer .........................................................................................................4
1.6.
Intertask-Kommunikation..................................................................................4
1.6.1. Mailboxen ............................................................................................5
1.6.2. Semaphoren .........................................................................................5
1.7.
Kommunikation mit Linux-Prozessen ....................................................................5
1.7.1. FIFOs..................................................................................................5
1.7.2. Shared Memory......................................................................................6
1.8.
LXRT ..........................................................................................................6
2. Installation .......................................................................................................... 7
2.1.
Versionswahl.................................................................................................7
2.2.
Installation der Linux-Distribution .......................................................................7
2.3.
Echtzeit-Kernel erstellen ..................................................................................7
2.3.1. Arbeitsverzeichnis ..................................................................................7
2.3.2. Laden der Kernelquellen ..........................................................................8
2.3.3. Laden der RTAI-Quellen ...........................................................................8
2.3.4. RTAI-Patch ...........................................................................................8
II
RTAI-Linux | Inhaltsverzeichnis
2.3.5. Kernel konfigurieren ...............................................................................9
2.3.6. Kernel kompilieren ............................................................................... 14
2.3.7. Kernel installieren................................................................................ 14
2.4.
RTAI-Module erstellen.................................................................................... 17
2.4.1. RTAI konfigurieren................................................................................ 17
2.4.2. RTAI kompilieren ................................................................................. 17
2.4.3. RTAI installieren .................................................................................. 18
2.4.4. Neustart............................................................................................ 18
2.5.
RTAI testen ................................................................................................ 19
2.5.1. Testprogramm rt_process ....................................................................... 19
2.5.2. Echtzeitfähigkeit eines Systems................................................................ 21
2.5.3. Test- und Beispielapplikationen................................................................ 21
3. Interrupt-Latenzzeiten ....................................................................................... 22
3.1.
Latenzzeit-Messung mit LabVIEW ...................................................................... 22
3.1.1. Messprinzip ........................................................................................ 22
3.1.2. LabVIEW-Programm .............................................................................. 23
3.2.
Belastungsarten ........................................................................................... 23
3.2.1. Script busy.sh ..................................................................................... 23
3.2.2. Programm load-i386.............................................................................. 24
3.2.3. Programm load-arm .............................................................................. 24
3.3.
Axotec Phoenix-SBC-500 Board ......................................................................... 25
3.3.1. Technische Daten................................................................................. 25
3.3.2. Messschaltung ..................................................................................... 25
3.3.3. Interrupt-Handling................................................................................ 26
3.3.4. Messresultate...................................................................................... 27
3.4.
Evaluation-Kit SmartModule 855 MSEBX855........................................................... 31
3.4.1. Technische Daten................................................................................. 31
3.4.2. Messschaltung ..................................................................................... 31
3.4.3. Interrupt-Handling................................................................................ 32
3.4.4. Messresultate...................................................................................... 33
3.5.
Übersicht Messresultate ................................................................................. 37
3.6.
Auswertung ................................................................................................ 37
3.6.1. Axotec Phoenix-SBC-500 Board ................................................................. 37
3.6.2. Evaluation-Kit SmartModule 855 MSEBX855 .................................................. 37
Literaturverzeichnis ................................................................................................. 38
Anhang A: Kurzanleitung RTAI-Installation ............................................................. A-1
III
RTAI-Linux | Inhaltsverzeichnis
Echzeit-Kernel erstellen ........................................................................................ A-2
Arbeitsverzeichnis erstellen (Kapitel 2.3.1) ......................................................... A-2
Kernelquellen laden und entpacken (Kapitel 2.3.2) ............................................... A-2
RTAI-Quellen laden und entpacken (Kapitel 2.3.3) ................................................ A-2
RTAI-Patch (Kapitel 2.3.4) ............................................................................. A-2
Echtzeit-Kernel konfigurieren (Kapitel 2.3.5)....................................................... A-2
Echtzeit-Kernel kompilieren (Kapitel 2.3.6)......................................................... A-2
Echtzeit-Kernel installieren (Kapitel 2.3.7) ......................................................... A-2
RTAI-Module erstellen........................................................................................... A-3
RTAI konfigurieren (Kapitel 2.4.1) .................................................................... A-3
RTAI kompilieren (Kapitel 2.4.2) ...................................................................... A-3
RTAI installieren (Kapitel 2.4.3)....................................................................... A-3
Neustart (Kapitel 2.4.4) ................................................................................ A-3
RTAI testen........................................................................................................ A-3
Anhang B: Kernel-Module zur Latenzzeitmessung.................................................... B-1
Kernel-Modul elineb-latency-test.c ........................................................................... B-2
Source-Code .............................................................................................. B-2
Makefile ................................................................................................... B-4
RTAI-Modul elineb-rtai-latency-test.c ........................................................................ B-5
Source-Code .............................................................................................. B-5
Makefile ................................................................................................... B-6
Kernel-Modul smartmodule-latency-test.c................................................................... B-7
Source-Code .............................................................................................. B-7
Makefile ................................................................................................... B-8
RTAI-Modul smartmodule-rtai-latency-test.c................................................................ B-9
Source-Code .............................................................................................. B-9
Makefile ..................................................................................................B-10
IV
1. Funktionsprinzip
1.1. Architektur
Die Grundlange von RTAI-Linux ist ein normaler Linux-Kernel, der mit dem RTAI-Patch (Realtime Application Interface) erweitert wird. Wie in Abbildung 1.1 zu sehen ist, fügt der Patch einen EchtzeitKernel zwischen der Hardware (Prozessor) und dem Linux-Kernel ein. Dieser übernimmt die Interruptverwaltung des Prozessors. Das heisst Software auf der Kernel-Ebene kann keine Interrupts mehr blockieren oder freigeben. Die dafür verwendeten Befehle cli() und sti() ersetzt RTAI durch Makros
und ist somit in der Lage den Kernel-Code zu unterbrechen.
Abbildung 1.1: RTAI-Architektur [7]
Der Linux-Kernel selbst ist ebenfalls ein Echtzeit-Task. Er besitzt jedoch die kleinste Priorität (IdleTask) und wird immer nur dann ausgeführt, wenn die Echtzeit-Tasks nichts zu tun haben. Nach dem
Ausführen eines Echtzeit-Tasks werden alle Register wiederhergestellt, so dass der Kernel die Unterbrechung nicht bemerkt. [7]
1
RTAI-Linux | Funktionsprinzip
1.2. Realtime Hardware Abstraction Layer RTHAL
Damit deterministische Interrupt-Latenzzeiten erzielt werden können, muss die Interruptverwaltung an
RTAI übergeben werden. Die Umleitung der Interrupt-Kontrolle wird mit Hilfe des Realtime Hardware
Abstraction Layers (RTHAL) realisiert. RTHAL wird mit dem RTAI-Patch in den Source-Code des LinuxKernels integriert.
In Abbildung 1.2 sind die möglichen Kommunikationswege innerhalb eines modifizierten Kernels dargestellt. Im Fall A ist die Abstraktion transparent, dass heisst die Interrupt-Kontrolle liegt nach wie vor
beim Linux-Kernel, was der Nutzung eines Standard-Kernels entspricht. Bei B wird dem Linux-Kernel die
direkte Kontrolle über die Interrupts entzogen und der Echtzeiterweiterung zugewiesen.
Abbildung 1.2: Interrupt-Kontrollflüsse [6]
RTAI arbeitet autonom von Linux auf der Hardware. Abgefangene Interrupts werden auch an RTHAL
weitergegeben, damit der Kernel darauf entsprechend reagieren kann. RTAI wird durch verschiedene
Kernel-Module implementiert. Solange diese Module nicht geladen sind, behält der Linux-Kernel die
Interrupt-Kontrolle (Fall A). Erst beim Laden der RTAI-Module wird die direkte Interrupt-Kontrolle an
RTAI übertragen (Fall B). So kann die Echtzeiterweiterung während der Laufzeit nach Belieben in den
Kernel eingefügt und wieder entfernt werden. Dank dieser modularen Struktur lassen sich Fehlerquellen
leichter isolieren. Arbeitet z.B. ein RTAI-System fehlerhaft, kann man einfach die RTAI-Module entfernen, um zu Testen, ob der Fehler bei Linux oder RTAI liegt.
struct rt_hal
{
struct desc_struct *idt_table;
void (*disint) (void);
void (*enint) (void);
unsigned int (*getflags) (void);
void (*setflags) (unsigned int flags);
void (*mask_and_ack_8259A) (unsigned int irq);
void (*unmask_8259A_irq) (unsigned int irq);
void (*ack_APIC_irq) (void);
void (*mask_IO_APIC_irq) (unsigned int irq);
void (*unmask_IO_APIC_irq) (unsigned int irq);
unsigned long *io_apic_irqs;
void *irq_controller_lock;
void *irq_desc;
int *irq_vector;
void *irq_2_pin;
void *ret_from_intr;
struct desc_struct *gdt_table;
volatile int *idle_weight;
void (*lxrt_cli)(void);
} rthal;
Listing 1.1: RTHAL-Struktur in system.h [7]
2
RTAI-Linux | Funktionsprinzip
RTHAL besteht im Wesentlichen aus einer Struktur von Funktionspointern (Listing 1.1), welche beim
Systemstart auf die Interrupt-Handling-Funktionen des Linux-Kernels zeigen. Beim Laden der RTAIModule werden die Funktionspointer auf RTAI interne Funktionen umgelenkt. So übernimmt RTAI die
Interrupt-Kontrolle, ohne dass der Linux-Kernel etwas davon bemerkt. Nach dem Entfernen der RTAIModule zeigen die Pointer der Struktur rthal wieder auf die Standard-Kernel-Funktionen. [6], [7]
1.3. Interrupt-Handling
Wenn RTAI die Interrupt-Kontrolle übernimmt, werden interruptspezifische Funktionsaufrufe des LinuxKernels mit Hilfe von RTHAL an RTAI interne Funktionen umgeleitet. So implementiert RTAI z.B. einen
Ersatz für das Funktionspaar sti() und cli(). Diese RTAI-Funktionen setzen Flags in RTAI internen
Datenstrukturen, um festzuhalten, ob Linux über eingehende Interrupts informiert werden möchte
(sti) oder nicht (cli). So wird sichergestellt, dass der Kernel keine Interrupts mit Hilfe der Funktion
cli() deaktivieren kann. RTAI gibt die mit der Funktion sti() angeforderten Interrupts nach dem
Ausführen der Echtzeit-Interrupt-Handler an den Linux-Kernel weiter.
In Abbildung 1.3 wird mit Hilfe eines Flussdiagramms dargestellt, wie ein eingehender Interrupt von
RTAI verarbeitet wird. Zuerst prüft der RTAI Dispatcher, ob eine Echtzeit-Applikation einen Handler für
diesen Interrupt registriert hat. Falls entsprechende Interrupt-Handler vorhanden sind werden diese
ausgeführt.
Abbildung 1.3: Interrupt-Handling im modifizierten Linux-Kernel [6]
Danach prüft RTAI anhand der internen Datenstrukturen, ob der Linux-Kernel den Interrupt ebenfalls
mit sti() aktiviert hat. Bei einem positiven Prüfergebnis wird der Linux Dispatecher gestartet und
somit die Verarbeitung des Interrupts auf der Kernel-Ebene eingeleitet. Falls der Linux-Kernel den betreffenden Interrupt nicht aktiviert hat, verlässt RTAI sofort den Interrupt-Kontext und führt das unterbrochene Programm wieder aus. [6]
1.4. Scheduler
RTAI unterstützt drei verschiedene Scheduling-Varianten. Diese sind entweder für den Einsatz auf Unioder auf Multiprozessor-Systemen spezialisiert. Alle Scheduler können sowohl im so genannten Oneshotoder Periodic-Mode betrieben werden (Kapitel 1.5). Die verschiedenen Scheduler werden in den Modulen rtai_sched_up.ko, rtai_sched_smp.ko und rtai_sched_mup.ko implementiert. Das entsprechende Scheduler-Modul wird jeweils nach dem RTAI-Modul rtai_hal.ko mit insmod in den Kernel eingefügt. [6]
3
RTAI-Linux | Funktionsprinzip
1.4.1. Uni-Prozessor-Scheduler (UP)
Dieser Scheduler ist für Plattformen mit einem Prozessor vorgesehen, welche den 8254 als Timer benutzen. Der Aufbau des Schedulers ist recht einfach. Er besteht im Wesentlichen aus mehreren Listen mit
verschiedenen Prioritäten, welche er linear abarbeitet. Dabei erhält jeweils der Task mit der höchsten
Priorität Zugriff auf die CPU. Der Linux-Kernel selbst ist ebenfalls ein Echtzeit-Task, allerdings mit der
geringsten Priorität. [6]
1.4.2. SMP-Scheduler (SMP)
Der SMP-Scheduler (Symetric Multiprocessing) ist für Multiprozessor-Systeme gedacht, die entweder
8254 oder APIC basiert sind. Der APIC ist der so genannte Advanced Programmable Interrupt Controller
in Multiprozessor-Systemen. Dieser hat unter anderem die Aufgabe, die auftretenden Interrupts den
einzelnen CPUs zuzuteilen. Tasks können an eine CPU gebunden werden oder symmetrisch auf einen
Cluster von CPUs laufen. Der Scheduler kann auch auf Systemen eingesetzt werden, die nur einen Prozessor haben, aber deren Kernel mit SMP-Option kompiliert wurde. [8]
1.4.3. Multi-Uni-Porzessor-Scheduler (MUP)
Wie es der Name schon sagt, sieht dieser Scheduler ein Multiprozessor-System als eine Ansammlung von
mehreren Einzelprozessoren. Dies hat den Vorteil, dass im Gegensatz zum SMP-Scheduler jeder Prozessor seine Timer unabhängig von den anderen programmieren kann. Also können die Timer-Modi Periodic- und Oneshot-Mode abhängig von der CPU verschieden sein. [6]
1.5. Timer
Die Ausführung von Echtzeit-Tasks in RTAI ist timergesteuert. RTAI bietet die Wahl zwischen den beiden
Timer-Modi Periodic- und Oneshot-Mode. Periodisch bedeutet, dass der Timer in regelmässigen Intervallen ein Interrupt auslöst, der ein Rescheduling veranlasst. Im Gegensatz dazu steht das OneshotVerfahren. Hierbei wird der Timer so programmiert, dass er nach einer festgelegten Zeitspanne genau
einen Interrupt auslöst, der den Scheduler aufruft. Für die Generierung eines weiteren Interrupts muss
der Timer neu programmiert werden, was einen grösseren Aufwand bedeutet, als beim periodischen
Verfahren. Jedoch sind so auch unterschiedlich lange Intervalle möglich, nach denen ein Rescheduling
erfolgen kann. [7], [8]
Bei der Initialisierung des Programms muss ein Modus gewählt werden. Dies geschieht indem eine der
beiden folgenden Funktionen aufruft:
• rt_set_periodic_mode()
Timer läuft im Periodic-Mode.
• rt_set_oneshot_mode()
Timer läuft im Oneshot-Mode.
1.6. Intertask-Kommunikation
Für die Kommunikation und Synchronisation zwischen Echtzeit-Tasks im Kernel-Space stellt RTAI die für
ein Echtzeitbetriebsystem üblichen Mechanismen zur Verfügung. Diese werden in den Kernel-Modulen
der Scheduler implementiert:
• Mailboxen
• Semaphoren
• Nachrichten und Remote-Procedure-Calls
4
RTAI-Linux | Funktionsprinzip
1.6.1. Mailboxen
Mit Hilfe von Mailboxen ist eine asynchrone Inter-Prozess-Kommunikation möglich. Ein Task kann Nachrichten asynchron an die Mailbox eines anderen Tasks senden. Wenn der Empfänger bereit ist die empfangenen Nachrichten zu bearbeiten kann er sie aus der Mailbox holen. In diesem Fall arbeitet die Mailbox wie eine FIFO (first in first out), deren Funktionalität vollständig vom jeweiligen Task entkoppelt ist
und keine Synchronisationsmechanismen benötigt. [6]
Hier die wichtigsten RTAI-Funktionen zum Arbeiten mit Mailboxen:
• rt_mbx_init()
Initialisiert eine Mailbox mit einer definierten Grösse.
• rt_mbx_delete()
Löscht die von einer Mailbox genutzten Ressourcen.
• rt_mbx_send()
Sendet eine Nachricht mit definierter Grösse an die Mailbox.
• rt_mbx_receive()
Empfängt eine Nachricht mit definierter Grösse von einer Mailbox.
1.6.2. Semaphoren
Eine Semaphore ist eine Art Schlüssel, den ein Task z.B. benötigt, um auf eine gemeinsame Ressource
zuzugreifen. Wurde die Semaphore bereits von einem anderen Task geholt, wird der anfragende Task in
den Wartezustand gesetzt, bis der aktuelle Besitzer die Semaphore wieder zurückgibt. Eine Semaphore
beinhaltet eine geschützte Variable (binär oder counting), welche die noch freien Zugriffe auf eine
Ressource angibt. In einer Queue werden die Tasks vermerkt, die auf die Semaphore warten. Wird die
Semaphore zurückgegeben erhält sie der erste Task in der Queue.
Folgende Funktionen stehen zum Arbeiten mit Semaphoren in RTAI zur Verfügung:
• rt_sem_init()
Initialisiert eine Semaphore mit gegebenem Wert.
• rt_sem_delete()
Löscht die gegebene Semaphore.
• rt_sem_signal()
Gibt die Semaphore zurück.
• rt_sem_wait()
Wartet auf eine Semaphore.
1.7. Kommunikation mit Linux-Prozessen
RTAI stellt mit FIFOs und Shared Memory auch zwei Mechanismen zur Verfügung, die es den EchtzeitTasks ermöglicht mit normalen Linux-Prozessen im User-Space zu kommunizieren.
1.7.1. FIFOs
Ein FIFO ist ein Puffer-Speicher, über den Daten zwischen einem RTAI-Task und einem normalen LinuxProzess im User-Space ausgetauscht werden können. Theoretisch ist ein FIFO bidirektional. In der Praxis
wird jedoch meistens nur eine Richtung benutzt. Zum gegenseitigen Austausch von Daten verwendet
man zwei FIFOs, einen zum Senden von Befehlen und einen weiteren zum Empfangen der entsprechenden Antworten.
Abbildung 1.4: RTAI FIFO
5
RTAI-Linux | Funktionsprinzip
Linux-Prozesse können auf einen FIFO wie auf eine normale Datei zugreifen. Anstelle einer Datei öffnet
man mit der Funktion open() einen speziellen Device-Node im /dev-Verzeichnis (rtf0 bis rtf63
siehe Kapitel 2.4.3). Anschliessend kann man mit den Funktionen read() und write() Daten lesen
und schreiben. Im Kernel-Space stellt die RTAI-API folgende Funktionen zum Arbeiten mit FIFOs für die
Echtzeit-Tasks zur Verfügung:
• rtf_create()
Erzeugt einen FIFO mit gegebner Grösse und Nummer.
• rtf_destroy()
Löscht einen FIFO.
• rtf_reset()
Löscht den Inhalt eines FIFO.
• rtf_put()
Schreibt Daten in den FIFO.
• rtf_get()
Liest Daten aus dem FIFO.
• rtf_create_handler()
Registriert einen Handler, der beim Eintreffen von Daten
ausgeführt wird.
1.7.2. Shared Memory
Shared Memory ist wie es der Name schon sagt, ein Speicherbereich, der sich Linux-Prozess und RTAITask teilen. Shared Memory wird hauptsächlich dann eingesetzt, wenn mehrere Linux-Prozesse Zugriff
auf die Daten eines RTAI-Task benötigen oder eine grosse Datenmenge in kurzer Zeit von einem RTAITask an einen Linux-Prozess übertragen werden müssen. [6]
1.8. LXRT
Um die Entwicklung von Echtzeit-Tasks zu erleichtern, wurde in RTAI das LXRT-Modul eingeführt. Dieses
Modul erlaubt die Entwicklung von Echtzeit-Tasks im User-Space, mit der Möglichkeit, auf die API von
RTAI zuzugreifen.
Dies ist eine Besonderheit, die nur in RTAI existiert und die Entwicklung sehr vereinfachen kann, da sich
Fehler in einem User-Space Prozess in der Regel nicht auf die Stabilität des Gesamtsystems auswirken.
Fehler in Kernel-Modulen können oft zum Absturz des gesamten Systems führen. Zudem kann man im
User-Space im Gegensatz zum Kernel-Space mit einem normalen Debugger (z.B. GDB) arbeiten.
LXRT ist nur als Testwerkzeug gedacht und kann keine Echtzeiteigenschaften garantieren. Deshalb portiert man LXRT-Programme nach der Testphase in normale Kernel-Module. Da das LXRT-Modul die RTAIAPI im User-Space zu Verfügung stellt, kann der Code des LXRT-Programms ohne grosse Änderungen für
das Kernel-Modul übernommen werden. [8]
6
2. Installation
Die Installation der Echtzeiterweiterung RTAI erfolgt in zwei Schritten. Zuerst wird ein normaler LinuxKernel mit dem RTAI-Patch erweitert und kompiliert. Danach werden die eigentlichen RTAI-Module
erzeugt und auf dem System installiert. In diesem Kapitel wird jeder Installationsschritt ausführlich
beschrieben. Eine Kurzanleitung für die Installation von RTAI ist in Anhang A zu finden.
2.1. Versionswahl
Die verschiedenen RTAI-Versionen beinhalten jeweils nur für die beim Release aktuellen Linux-Kernel
einen Patch. Deshalb muss man bei der Wahl der RTAI-Version darauf achten, dass ein RTAI-Patch für
den in der Linux-Distribution verwendeten Kernel vorhanden ist. In diesem Beispiel wurden folgende
Softwarepakete gewählt:
• Ubuntu 5.04 "Hoary Hedgehog" (Kernel 2.6.10)
• RTAI 3.2
2.2. Installation der Linux-Distribution
Zuerst wird die gewählte Linux-Distribution installiert. Bei Ubuntu mussten folgende Pakte zusätzlich
mit dem Synamptic-Paketmanager nachinstalliert werden:
make, gcc, g++, libncurses5-dbg, libncurses5-dev
2.3. Echtzeit-Kernel erstellen
Bei der Integration der Echtzeiterweiterung in den Linux-Kernel müssen diverse Änderungen in dessen
Source-Code vorgenommen werden. Dazu spielt man den entsprechenden RTAI-Patch in die Kernelquellen ein. Danach muss der Kernel konfiguriert und neu kompiliert werden.
2.3.1. Arbeitsverzeichnis
Zuerst legt man am besten eine Ordnerstruktur im eigenen Home-Verzeichnis an, in der die Quelldateien der Echtzeiterweiterung und des Kernels abgelegt werden können:
$
$
$
$
cd /home/username
mkdir rtai
cd rtai
mkdir src
7
RTAI-Linux |Installation
2.3.2. Laden der Kernelquellen
Der Source-Code des entsprechenden Linux-Kernels kann man auf der Website www.kernel.org herunterladen. Für die Ubuntu-Distribution laden wir den Kernel 2.6.10 in unser src-Verzeichnis:
$ cd /home/username/rtai/src
$ wget ftp://ftp.de.kernel.org/pub/linux/kernel/v2.6/linux-2.6.10.tar.bz2
Danach entpacken wir mit Hilfe des tar-Befehls das erhaltene Archiv. Dabei entsteht das Verzeichnis
linux-2.6.10, das die Quelldateien des Kernels enthält:
$ cd /home/username/rtai
$ tar xvfj src/linux-2.6.10.tar.bz2
2.3.3. Laden der RTAI-Quellen
Die RTAI-Quellen werden auf der RTAI-Website www.rtai.org veröffentlicht. Wir werden mit der
Version 3.2 arbeiten und speichern das entsprechende Archiv im src-Verzeichnis:
$ cd /home/username/rtai/src
$ wget https://www.rtai.org/RTAI/rtai-3.2.tar.bz2
Anschliessend entpacken wir die RTAI-Quellen ebenfalls mit dem tar-Befehl. Die RTAI-Quellen befinden
sich danach im Verzeichnis rtai-3.2:
$ cd /home/username/rtai
$ tar xvfj src/rtai-3.2.tar.bz2
2.3.4. RTAI-Patch
Um die in einer Patch-Datei gespeicherten Änderungen an der Originaldatei durchzuführen, benötigt
man das Programm patch. Im einfachsten Fall ruft man patch einfach in dem Verzeichnis auf, in dem
sich die Originaldatei befindet, und übergibt das Patchfile auf der Standardeingabe:
$ patch < patchfile
Den Dateinamen des Originals muss man nicht angeben, da dieser bereits in der Patch-Datei gespeichert
ist. Oftmals enthält eine Patch-Datei allerdings nicht nur die Unterschiede einer einzelnen Datei, sondern es sind die Unterschiede ganzer Unterverzeichnisse wie beim RTAI-Patch darin abgelegt. In einem
solchen Fall befindet sich nicht nur der Dateiname sondern auch der Pfad der Datei in der Patch-Datei.
Nun kann es passieren, dass sich der Verzeichnisbaum beim Empfänger in einem anderen Verzeichnis
befindet als beim Ersteller des Patchs. In einem solchen Fall würde der Befehl patch die Dateien, die
bearbeitet werden sollen, nicht finden.
Dieses Problem kann mit der Option "-p <Zahl>" gelöst werden. Die Zahl gibt an, wie viele Unterverzeichnisebenen von den Pfadangaben in der Patch-Datei abgeschnitten werden sollen. Der RTAI-Patch
geht davon aus, dass sich der Kernel im Unterverzeichnis linux/ befindet. Liegen die Kernelquellen an
einem anderen Ort z.B. unter /home/username/rtai/linux-2.6.10, wechselt man in dieses Verzeichnis und ruft den RTAI-Patch mit der Option -p1 auf. Diese entfernt dann das führende linux/ in
der Pfadangabe und die neuen relativen Angaben passen somit zur Struktur in /home/username/
rtai/linux-2.6.10.
$ cd /home/username/rtai/linux-2.6.10
$ patch –p1 < ../rtai-3.2/base/arch/i386/patches/hal-linux-2.6.10-i386r9.patch
Bevor der Befehl patch eine Datei modifiziert, legt es eine Sicherheitskopie mit der Endung .orig an.
Diese kann man, wenn man sie nicht benötigt, mittels find suchen und löschen lassen:
$ find . -name "*.orig" | xargs rm
Wenn es keinen RTAI-Patch für die gewünschte Kernel-Version gibt, kann man es mit einem Patch für
eine Vorgängerversion versuchen. In einem solchen Fall kann es jedoch vorkommen, dass das patchProgramm nicht weiss, wie es den Patch anwenden soll. Die Teile der Patch-Datei, mit denen patch
nichts anfangen kann, werden in Dateien mit der Endung .rej abgelegt. Unterscheiden sich die Origi-
8
RTAI-Linux |Installation
naldateien nicht zu stark, kann man diese Patchs auch noch per Hand einbauen. Falls keine .rejDateien entstanden sind, kann davon ausgegangen werden, dass das Patchen erfolgreich verlaufen ist.
Die .rej-Dateien können auf dieselbe Weise wie die .orig-Dateien gelöscht werden:
$ find . -name "*.rej" | xargs rm
2.3.5. Kernel konfigurieren
Die gesamten Konfigurationsdaten eines Linux-Kernels befinden sich in der Datei .config im Stammverzeichnis der Kernelquellen (linux-2.6.10). Wenn man einen neuen Kernel von www.kernel.org
verwendet, fehlt eine solche Konfigurationsdatei. Deshalb muss vor dem Kompilieren zuerst eine
.config-Datei mit der entsprechenden Kernel-Konfiguration erstellt werden.
Standard-Konfiguration
Für jede Prozessor-Architektur wird die Standard-Konfigurationsdatei defconfig definiert. Mit Hilfe
dieser Datei kann ein Minimalsystem für den entsprechenden Prozessortyp erzeugt werden. Die defconfig-Datei für PCs mit Intel-Prozessor befindet sich in folgendem Unterverzeichnis:
linux-2.6.10/arch/i386/defconfig
Wenn man diese Standardkonfiguration verwenden möchte, kopiert man die Datei defconfig in das
Stammverzeichnis des Echzeitkernels und gibt ihr den Namen .config. Anschliessend wird die neue
Konfigurationsdatei mit dem Befehl make oldconfig aktualisiert:
$ cp arch/i386/defconfig .config
$ make oldconfig
Besitzt der Kernel neue Features, die noch nicht in der Konfigurationsdatei definiert wurden, muss der
Benutzer diese beim Ausführen vom make oldconfig konfigurieren. Ein Beispiel für ein neues KernelFeature ist der Adeos Nanokernel, der mit dem RTAI-Patch dem Kernel neu hinzugefügt wird.
Konfiguration der Linux-Distribution
Alternativ zu defconfig kann man auch die Konfigurationsdatei des aktuellen Kernels verwenden. Dies
hat den Vorteil, dass der neue Echtzeit-Kernel automatisch dieselbe Funktionalität wie der Kernel der
Linux-Distribution aufweist. Bei Ubuntu befindet sich die Konfigurationsdatei des Kernels im bootVerzeichnis:
/boot/config-2.6.10-5-686
Um die Konfiguration des aktuellen Kernels zu übernehmen, geht man auf dieselbe Weise vor wie bei
der Standartkonfiguration. Zuerst kopiert man die Konfigurationsdatei des aktuellen Linux-Kernels
(config-2.6.10-5-686) vom boot-Verzeichnis in das Stammverzeichnis des Echzeitkernels, ändert
den Namen der Datei und führt make oldconfig aus:
$ cp /boot/config-2.6.10-5-686 .config
$ make oldconfig
Bei den heutigen Linux-Distributionen werden beinahe alle Kernel-Features in der Konfigurationsdatei
aktiviert, damit der Kernel auf möglichst viele verschiedene Hardwarekonfigurationen vorbereitet ist.
Dies steigert jedoch die Kompilierzeit des Kernels erheblich (Das Erzeugen eines Standard-Kernels dauert auf einem 3 GHz Pentium 4 ca. 10 bis 30 min während das Kompilieren eines kompletten Kernels
mehrere Stunden in Anspruch nimmt). Deshalb ist die Standardkonfiguration oft der schnellere Weg.
Sollten bei den Standardeinstellungen gewisse Funktionalitäten fehlen, können diese immer noch nachträglich hinzugefügt werden.
9
RTAI-Linux |Installation
Vorgehen
Welche Konfigurationsart auch gewählt wird, man geht immer nach folgendem Schema vor:
1. Existierende Konfigurationsdatei in das Stammverzeichnis des Echzeit-Kernels kopieren und umbenennen (.config).
2. Mit dem Befehl make oldconfig die neue Konfigurationsdatei aktualisieren (Eventuell neue Kernel-Features konfigurieren).
3. Letzte Feineinstellungen mit dem Befehl make menuconfig in der Kernel-Konfiguration vornehmen.
Feineinstellungen RTAI 3.2
Nachdem eine Konfigurationsdatei für den Kernel gewählt und aktualisiert wurde, können nun letzte
Feineinstellungen in der Kernel-Konfiguration vorgenommen werden. Dazu führt man folgenden Befehl
aus:
$ make menuconfig
Es erscheint ein grafischer Konfigurationsdialog (Abbildung 2.1), in dem die Einstellungen für die einzelnen Kernel-Optionen vorgenommen werden können. Mit Hilfe der Pfeiltasten kann man durch das
Konfigurationsmenu navigieren.
Abbildung 2.1: Kernel-Konfigurationsdialog
In ein Untermenü gelangt man mit Hilfe der Enter-Taste. Die verschiedenen Funktionen kann man mit
der M-Taste als Modul oder mit der Y-Taste fest in den Kernel einbinden. Möchte man eine Funktion
wieder entfernen drückt man die N-Taste:
• Funktion deaktivieren
[ ]
(N-Taste)
• Funktion fest einbinden
[*]
(Y-Taste)
• Funktion als Modul einbinden [M]
(M-Taste)
10
RTAI-Linux |Installation
Insbesondere wenn man die Standardkonfiguration gewählt hat, sollte man vor dem Kompilieren überprüfen, ob folgende Optionen korrekt gesetzt wurden:
Processor type and features Æ Processor family
Unter "Processor family" wählt man den Prozessortyp des verwendeten PCs aus.
Abbildung 2.2: Verwendeter Prozessor Typ auswählen (Pentium M)
Device drivers Æ Networking support Æ Ethernet (10 or 100Mbit)
In diesem Untermenü kann man einen passenden Treiber für die Netzwerkkarte des PCs auswählen. Gibt
es keinen passenden Treiber, wählt man einen Standard-Treiber.
Abbildung 2.3: Netzwerkkartentreiber auswählen (Intel(R) Pro/100+ support)
11
RTAI-Linux |Installation
Device drivers Æ Block devices Æ Loopback device support
Diese Funktion muss aktiviert werden, damit später eine Initial Ramdisk (initrd) für den neuen Echtzeit-Kernel erzeugt werden kann.
Abbildung 2.4: Loopback device support aktivieren
Loadable module support
Damit später die Echtzeitmodule von RTAI geladen werden können, sollten im Menü "Loadable module
support" die in Abbildung 2.5 gezeigten Funktionen aktiviert werden.
Abbildung 2.5: Loadable module support aktivieren
Weiterhin ist darauf zu achten, dass die Funktion "Module versioning support" deaktiviert ist, da diese
laut dem FAQ von www.rtai.org Probleme in Verbindung mit RTAI verursachen kann [1].
12
RTAI-Linux |Installation
Adeos Support
Diese Option erscheint nur, wenn zuvor der RTAI-Patch installiert wurde. Wenn man beim Aktualisieren
der Konfigurationsdatei mit make oldconfig den Standardwert für diese neue Option gewählt hat,
sollte der "Adeos Support" bereits aktiviert sein. Der Adeos Nano-Kernel ist für die Verteilung der Interrupts an den RTAI- und den Linux-Kernel zuständig.
Abbildung 2.6: Adeos Support aktivieren
Kernel hacking
Man sollte überprüfen, ob die Option "Compile the kernel with frame pointers" deaktiviert ist, da diese
in Verbindung mit RTAI ebenfalls Probleme verursachen kann [1].
Abbildung 2.7: Compile the kernel with frame pointers muss deaktiviert werden
Nach Abschluss der Konfiguration verlässt man den Dialog mit "Exit" und speichert die Änderungen in der
.config-Datei.
13
RTAI-Linux |Installation
Feineinstellungen RTAI 3.3
Beim Wechsel der RTAI-Version von 3.2 zu 3.3 gab es bei der Konfiguration des Echtzeit-Kernels verschiedene Änderungen. Zum Beispiel gibt es keine Option mehr zum Aktivieren des Adeos Nano-Kernels.
Verwendet man RTAI 3.3, sollte man vor dem Kompilieren mit make menuconfig folgende Einstellungen kontrollieren:
Processor tpye and features
Im Menü "Processor type and features" muss die Option "Use register arguments" deaktiviert und "Interrupt pipeline" aktiviert werden.
Abbildung 2.8: Interrupt pipline aktivieren
Loadable module support
Zum laden der Echtzeitmodule müssen im Menü "Loadable module support" die in Abbildung 2.5 gezeigten Funktionen aktiviert werden. Ebenfalls ist darauf zu achten, dass die Funktion "Module versioning
support" deaktiviert ist.
2.3.6. Kernel kompilieren
Nun kann der Echtzeit-Kernel kompiliert werden. Mit dem Befehl make bzImage kann man ein Bootsektor-Image erzeugen, das anschliessend in das boot-Verzeichnis kopiert wird. Danach werden mit dem
Befehl make modules alle Kernel-Module erzeugt:
$ make bzImage
$ make modules
Der ganze Build-Prozess kann ohne Root-Rechte ausgeführt werden. Es genügt also, wenn man als normaler Benutzer eingeloggt ist. Wenn die Konfigurationsdatei der Linux-Distribution verwendet wird,
dauert das Erzeugen der Kernel-Module wesentlich länger als das Erzeugen des Bootsektor-Images.
2.3.7. Kernel installieren
Bei der Installation des Kernels werden alle relevanten Dateien in das boot- und das lib-Verzeichnis
kopiert. Ausserdem muss der Bootloader entsprechend modifiziert werden, damit man beim Systemstart
den neuen Echtzeit-Kernel laden kann.
14
RTAI-Linux |Installation
Kernel-Module installieren
Zuerst werden die Kernel-Module installiert. Dazu sind Root-Rechte erforderlich. Der Befehl make modules_install kopiert die Kernel-Module in das Verzeichnis /lib/modules/2.6.10-adeos.
$ sudo make modules_install
Der Name von diesem Verzeichnis (2.6.10-adeos) hängt vom Versionsstring des neuen Kernels ab. Der
Versionsstring des Echtzeit-Kernels wird durch den RTAI-Patch ergänzt. Wenn man nicht sicher ist, wie
der Versionsstring des neuen Kernels lautet, wechselt man nach dem Ausführen vom make modules_install in das Verzeichnis /lib/modules und überprüft den Name des neu erstellten ModulVerzeichnisses.
Initial Ramdisk erstellen
Die Initial Ramdisk (initrd) ist ein kleines Dateisystem, das der Kernel ins RAM laden kann. Es stellt
eine minimale Linux-Umgebung bereit, die das Ausführen von Programmen ermöglicht, bevor das eigentliche Root-Dateisystem gemountet wurde. So müssen zum Beispiel mit Hilfe der Initial Ramdisk die
entsprechenden Treiber geladen werden, damit der Kernel auf den Datenträger mit dem RootDateisystem zugreifen kann.
Die Ramdisk für den Echtzeit-Kernel kann mit Hilfe des Befehls mkinitrd erzeugt werden:
$ sudo mkinitrd –o /boot/initrd.img-2.6.10-adeos 2.6.10-adeos
Mit dem zweiten Argument, dem Versionsstring des Echtzeit-Kernel, wird der Funktion mitgeteilt, wo
die zur Erzeugung der Ramdisk benötigten Dateien abgelegt sind. Der Name der Initial Ramdisk wird mit
dem ersten Argument definiert und setzt sich aus dem String "initrd.img" und dem Versionsstring des
Echtzeit-Kernels zusammen.
Ab Kernel-Version 2.6.14 verwendet man den Befehl mkinitramfs:
$ sudo mkinitramfs –o /boot/initrd.img-2.6.15-adeos 2.6.15-adeos
Bootsektor-Image installieren
Ebenfalls mit Root-Rechten wird das Bootsektor-Image in das boot-Verzeichnis der Linux-Distribution
kopiert.
$ sudo cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.10-adeos
Bei den meisten Distributionen wird das Bootsektor-Image bzImage beim Kopieren in das bootVerzeichnis umbenannt. Grundsätzlich spielt der Name des Bootsektor-Images keine Rolle, solange der
Name in der Konfigurationsdatei des Bootloader korrekt definiert wird. Am besten hält man sich an die
Namenskonventionen der installierten Distribution.
System Map installieren
Im boot-Verzeichnis befindet sich auch die Datei System.map. Setzt man mehrere Kernel ein, besitzt
man für jeden Kernel eine solche Datei, die im Dateinamen den Versionsstring des zugehörigen Kernels
enthält. System.map ist in diesem Fall nur eine symbolischer Link, der auf die entsprechende MapDatei verweist.
$ sudo cp System.map /boot/System.map-2.6.10-adeos
$ sudo ln –s /boot/System.map-2.6.10-adeos /boot/System.map
Bootloader aktualisieren
Damit der neue Echtzeit-Kernel beim Systemstart geladen werden kann, muss noch die Konfigurationsdatei des Bootloaders angepasst werden. Die meisten Linux-Distributionen, dazu gehört auch Ubuntu,
verwenden heute den GRUB-Bootloader. Die Konfigurationsdatei von GRUB befindet sich in folgendem
Verzeichnis:
/boot/grup/menu.lst
15
RTAI-Linux |Installation
In dieser Datei muss nun das neue Bootsektor-Image und die Initial Ramdisk, wie Listing 2.1 (Zeile 25 bis
30) zu sehen ist, eingetragen werden. Wenn dieser Eintrag korrekt vorgenommen wurde, erscheint beim
Systemstart im Bootloader-Menü eine neue Boot-Option für den Echzeit-Kernel mit dem in der Konfigurationsdatei definierten Titel (Zeile 25).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
## ## End Default Options ##
title
root
kernel
splash
initrd
savedefault
boot
Ubuntu, kernel 2.6.10-5-686
(hd0,0)
/boot/vmlinuz-2.6.10-5-686 root=/dev/hda1 ro quiet
title
root
kernel
initrd
savedefault
boot
Ubuntu, kernel 2.6.10-5-686 (recovery mode)
(hd0,0)
/boot/vmlinuz-2.6.10-5-686 root=/dev/hda1 ro single
/boot/initrd.img-2.6.10-5-686
title
root
kernel
savedefault
boot
Ubuntu, kernel memtest86+
(hd0,0)
/boot/memtest86+.bin
title
root
kernel
initrd
savedefault
boot
Ubuntu, kernel 2.6.10-adeos RTAI
(hd0,0)
/boot/vmlinuz-2.6.10-adeos root=/dev/hda1 ro lapic
/boot/initrd.img-2.6.10-adeos
/boot/initrd.img-2.6.10-5-686
### END DEBIAN AUTOMAGIC KERNELS LIST
Listing 2.1: Auszug aus der GRUB-Konfigurationsdatei menu.lst
Die einzelnen Boot-Optionen werden durchnumeriert, wobei die Nummerierung bei 0 beginnt. Der Bootloader startet beim Systemstart normalerweise die erste Boot-Option mit der Nummer 0. Wenn man
standardmässig, den Echtzeit-Kernel starten möchte, trägt man die Nummer der entsprechenden BootOption wie in Listing 2.2, Zeile 7 beschrieben in die Konfigurationsdatei menu.lst des Bootloaders ein.
01
02
03
04
05
06
07
08
...
## default num
# Set the default entry to the entry number NUM. Numbering starts
# from 0, and the entry number 0 is the default if the command is
# not used.
...
#default 3
...
Listing 2.2: Auszug aus der GRUB-Konfigurationsdatei menu.lst
16
RTAI-Linux |Installation
2.4. RTAI-Module erstellen
2.4.1. RTAI konfigurieren
Für die Echtzeiterweiterung RTAI kann wie beim Linux-Kernel mit dem Befehl make menuconfig ein
Konfigurationsdialog gestartet werden. In der Installationsanleitung von RTAI wird empfohlen die RTAIModule in einem separaten Build-Verzeichnis zu erzeugen.
Deshalb erstellt man am besten ein neues Verzeichnis (rtai-build) und ruft anschliessend in diesem
den Befehl make menuconfig auf. Dabei muss zusätzlich noch der Pfad zum RTAI-Makfile mit der Option f definiert werden:
$
$
$
$
cd /home/username/rtai
mkdir rtai-build
cd rtai-build
make –f ../rtai-3.2/makefile menuconfig
Im Konfigurationsdialog von RTAI nimmt man dann folgende Einstellungen vor:
Generel Æ Linux source tree
Bei der Erzeugung der RTAI-Module werden die Kernelquellen des Echtzeit-Kernels benötigt. Deshalb
muss man unter "Linux source tree" den Pfad zum Stammverzeichnis des Echtzeit-Kernels
(/home/username/rtai/linux-2.6.10) definieren:
Abbildung 2.9: Pfad zum Verzeichnis des Echtzeit-Kernel setzen
Danach kann man die Konfiguration speichern und den Dialog beenden. Beim Verlassen des Dialogs
werden alle benötigten Makefiles erzeugt.
2.4.2. RTAI kompilieren
Das Erzeugen der RTAI-Module ist nun sehr einfach. Man führt lediglich den Befehl make im BuildVerzeichnis von RTAI (rtai-build) aus:
$ cd /home/username/rtai/rtai-build
$ make
17
RTAI-Linux |Installation
2.4.3. RTAI installieren
Nachdem die RTAI-Module erfolgreich erzeugt wurden, müssen sie im System mit dem Befehl make
install installiert werden. Dazu sind Root-Rechte erforderlich:
$ sudo make install
Die RTAI-Module und diverse Testprogramme werden in das Verzeichnis /usr/realtime kopiert. Im
dev-Verzeichnis werden zudem verschiedene Device-Nodes erstellt, die z.B. die Kommunikation zwischen RTAI-Modulen und normalen User-Space-Programmen via FIFOs ermöglichen. Diese Device-Nodes
gehen jedoch beim Neustart des Systems verloren. Deshalb erstellt man am besten ein kleines Script,
das beim Systemstart die benötigten Device-Nodes im dev-Verzeichnis erzeugt:
#!/bin/bash
mknod –m 666 /dev/rtai_shm c 10 254
for n in `seq 0 9`
do
f=/dev/rtf$n
mknod –m 666 $f c 150 $n
done
Listing 2.3: Script zum erstellen der RTAI-Device-Nodes
Damit das Script beim Systemstart automatisch aufgerufen wird, erstellt man das Script im Verzeichnis
/etc/init.d und fügt anschliessend im Verzeichnis /etc/rcS.d einen symbolischen Link ein, der auf
das erstellte Script verweist:
$ sudo vi /etc/init.d/makeRTF.sh
$ sudo chmod 755 /etc/init.d/makeRTF.sh
$ sudo ln –s /etc/init.d/makeRTF.sh /etc/rcS.d/S00makeRtf
2.4.4. Neustart
Wenn der Echtzeit-Kernel und die RTAI-Module installiert wurden, muss das System neu gestartet werden:
$ sudo shutdown –r now
Beim Systemstart sollte man durch drücken der ESC-Taste in das Boot-Menü des Bootloaders GRUB
wechseln und überprüfen, ob die neue Boot-Option für den Echtzeit-Kernel vorhanden ist. Wenn in der
Konfigurationsdatei des Bootloaders nicht der Echtzeit-Kernel als Standard-Boot-Option gewählt wurde,
muss dieser jeweils manuell im Boot-Menü ausgewählt werden.
Abbildung 2.10: Boot-Menü des Bootloaders GRUB
18
RTAI-Linux |Installation
Schliesslich startet man den Echtzeit-Kernel. Wenn Fehlermeldungen erscheinen, dass die Initial Ramdisk oder das neue Bootsektor-Image nicht vorhanden sind, wurden höchstwahrscheinlich falsche Angaben in der Konfigurationsdatei menu.lst von GRUB gemacht. Um diese zu korrigieren startet man das
System mit dem alten Kernel, überarbeitet die Konfigurationsdatei und versucht dann erneut mit dem
Echtzeit-Kernel starten.
Kann der Echtzeit-Kernel auch weiterhin nicht gestartet werden, kann man einen Kernel ohne RTAIPatch erzeugen, um zu Testen, ob der Fehler durch den RTAI-Patch verursacht wird oder ein Problem in
der Kernel-Konfiguration vorliegt. Wenn man bei der Konfiguration des Kernels defconfig als Grundlage verwendet hat, kann man versuchen, ob es mit der Konfigurationsdatei der Linux-Distribution besser
funktioniert.
2.5. RTAI testen
Im Verzeichnis /usr/realtime/testsuite befinden sich diverse Testprogramme, mit deren Hilfe
man die korrekte Funktion von RTAI und die Echtzeitfähigkeit des Systems testen kann.
2.5.1. Testprogramm rt_process
Funktionsweise
Das Programm rt_process startet zuerst einen periodischen RTAI-Task, der alle 100 us aufgerufen
wird (Abbildung 2.11). Dieser Task erfasst als erstes die CPU-Zeit. Danach wartet er eine Periode. In
dieser Zeit werden die Systemressourcen für einen anderen Prozess freigegeben.
Abbildung 2.11: Flussdiagramm von rt_process.c [2]
19
RTAI-Linux |Installation
Nach einer Periode nimmt der RTAI-Task seine Arbeit, ausgelöst durch einen Interrupt, wieder auf und
holt erneut die CPU-Zeit. Danach berechnet er anhand der beiden Zeitstempel die tatsächliche Periodendauer und die Abweichung von der Soll-Periodendauer. In der Konsole gibt das Programm laufend
den Durchschnitt, den Minimal- und den Maximalwert der Abweichung aus.
Da das RTAI-Programm ein Kernel-Modul ist, können die berechneten Daten nicht direkt in der Konsole
ausgegeben werden. Deshalb übergibt der periodische Task die Werte über eine FIFO in den User-Space,
wo sie von einer kleinen Applikation in der Konsole ausgegeben werden (Abbildung 2.12). Die Messung
wird solange wiederholt, bis der Benutzer das Testprogramm mit der Tastenkombination CTRL+C beendet.
Abbildung 2.12: Übertragung der Messdaten vom Kernel-Space via FIFO in den User-Space [4]
Wenn man den PC belastet, kann man beobachten, wie die Abweichung von der Soll-Periode zunimmt.
Wird die Abweichung bei Belastung sehr gross oder schwankt die Abweichung sowohl im lastfreien als
auch im belasteten Fall sehr stark, ist der verwendete Rechner vermutlich nicht echtzeitfähig.
Starten und stoppen
Das Programm rt_process bindet sich im Verzeichnis /usr/realtime/testsuite/
kern/latency und kann wie folgt gestartet werden:
$ cd /usr/realtime/testsuite/kern/latency
$ sudo ./run
Möchte man das Programm wieder beenden drückt man CTRL+C.
Abbildung 2.13: Testprogramm rt_process.c
20
RTAI-Linux |Installation
2.5.2. Echtzeitfähigkeit eines Systems
Es gibt verschiedene Gründe, welche dazu führen, dass ein Rechner trotz der RTAI-Erweiterung nicht
echtzeitfähig ist:
• Starke DMA-Aktivität (z.B. Festplatte, PCI-Geräte, …)
• Beschleunigter X-Server
• USB-Unterstüzung
• Power-Management (APM und ACPI)
• Variable CPU-Frequenz (z.B. bei Pentium M)
Features wie Power-Management oder variable CPU-Frequenz sollten deshalb sowohl im Echtzeit-Kernel
als auch im BIOS des Rechners deaktiviert werden. [3]
2.5.3. Test- und Beispielapplikationen
Auf folgender Webseite gibt es gute Test- und Beispielapplikationen die den Einstieg in die RTAIProgrammierung erleichtern:
www.captain.at/rtai.php
21
3. Interrupt-Latenzzeiten
Um die Echtzeitfähigkeit von RTAI zu testen, wurde auf verschiedenen Systemen die Interrupt-Latenzzeit bei verschiedenen Belastungszuständen gemessen. Grössere Abweichungen bei den InterruptLatenzzeiten werden oft erst sichtbar, wenn man das Verhalten eines Systems über einen grösseren
Zeitraum (z.B. 10 bis 20 min) beobachtet.
Folgende Hardware-Plattformen kamen zum Einsatz:
• Axotec Phoenix SBC (ARM7, 74 MHz)
• Evaluation-Kit SmartModule 855 MSEBX855 (Intel Pentium M, 1.4 GHz)
3.1. Latenzzeit-Messung mit LabVIEW
3.1.1. Messprinzip
Damit man die Latenzzeit-Messungen effizient durchführen kann, ist es erforderlich die Messwerte laufend in einer Text- oder Excel-Datei abzuspeichern. Zuerst sollte ein PC basierter Logic-Analyzer diese
Aufgabe übernehmen. Da der Analyzer jedoch nur einen Bruchteil einer Sekunde aufzeichnen kann, ist
er für eine längere Messung nicht geeignet.
Die folgenden Messresultate wurden deshalb mit einem Oszilloskop gemessen, das über eine GPIBSchnittstelle verfügt. Die Messwerte werden mit Hilfe von LabVIEW (Abbildung 3.1) periodisch per GPIB
ausgelesen und in einem Textfile gespeichert.
Abbildung 3.1: Latenzzeitmessung mit LabVIEW
Mit dem Oszilloskop LeCroy 9314CM kann die Pulsbreite eines Rechteckimpulses bestimmt und mit LabVIEW ausgelesen werden. Baut man die Messschaltung (Kapitel 3.3.2) so auf, dass die InterruptLatenzzeit durch einen Rechteckimpuls abgebildet wird, kann die Latenzzeit direkt ohne aufwendige
Differenzmessungen mit dem Oszilloskop gemessen werden.
22
RTAI-Linux |Interrupt-Latenzzeiten
3.1.2. LabVIEW-Programm
Da auf der Webseite von National (www.ni.com/support) ein LabVIEW-Treiber für das verwendete Oszilloskop LeCroy 9314CM zur Verfügung gestellt wird, konnte das LabVIEW-Programm (Abbildung 3.2) recht
einfach gehalten werden. Mit dem Block Initialize wird die Verbindung zum Oszilloskop aufgebaut.
Wichtig dabei ist, dass die Korrekte GPIB-Adresse des Messgeräts angegeben wird. Nach der Initialisierung der Kommunikationsverbindung tritt das Programm in eine while-Schleife ein und liest mit dem
Block PAR.VAL periodisch die vom Oszilloskop gemessene Pulsbreite (= Interrupt-Latenzzeit) ein. Der
aktuelle Messwert wird bei jedem Schleifendurchlauf zusammen mit einem Zeitstempel in einem zweidimensionalen Array abgelegt.
Abbildung 3.2: LabVIEW-Programm zum Aufzeichnen der Interrupt-Latenzzeiten
Nachdem 10’000 Messwerte im Array gesammelt wurden, wird die while-Schleife abgebrochen und die
Verbindung zum Oszilloskop mit dem Block Close wieder geschlossen. Die Messwerte im Array werden
mit Hilfe des Blocks TXT in ein tabulatorgetrenntes Textfile (C:\data.txt) gespeichert. Das LabVIEWProgramm benötigt für das Sammeln der 10’000 Messwerte durchschnittlich 670 s. Demnach erfasst das
Programm die Interrupt-Latenzzeiten mit einer Samplingrate von ca. 15 Hz.
3.2. Belastungsarten
Um die verschiedenen Hardware-Plattformen während der Latenzzeit-Messungen zu belasten wurde das
Script busy.sh und das Programm load geschrieben.
3.2.1. Script busy.sh
Das Script busy.sh durchsucht das gesamte Dateisystem des Linux-Systems und gibt die Pfade aller
Dateien und Verzeichnisse in der Konsole aus. Liegt das Dateisystem auf einer Festplatte, führt dies zu
viel Festplattenaktivität.
01
02
03
04
05
06
#!/bin/sh
while true
do
find / -name ‘*’
done
Listing 3.1: Script busy.sh
23
RTAI-Linux |Interrupt-Latenzzeiten
3.2.2. Programm load-i386
Das Programm load-i386 liest zur Belastung des Prozessors in einer while-Schleife die Systemzeit
aus. Da das Lesen der Systemzeit einen Hardwarezugriff erfordert, ist der Compiler nicht in der Lage
das Programm zu optimieren oder zu vereinfachen. So kann eine kontinuierliche Belastung des Prozessors gewährleistet werden.
In Listing 3.2 ist der Source-Code von load-i386 zu sehen. Das Programm liest beim Start zuerst die
aktuelle Systemzeit aus und speichert sie in der Variable startTime (Zeile 10). Danach wird die aktuelle Systemzeit laufend in einer while-Schleife ausgelesen (Zeile 18 bis 21). Die Schleife wird solange
ausgeführt, bis die mit LOAD_TIME definierte Zeit verstrichen ist. Danach wird load-i386 beendet.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#define LOAD_TIME 250
int main (int argc, char *argv[])
{
// Startzeit ermitteln
time_t startTime = time(NULL);
time_t currentTime;
printf("Program Load in progress\n");
alarm(LOAD_TIME+2);
// Systemzeit auslesen bis LOAD_TIME verstrichen ist
while (difftime(currentTime, startTime) <= LOAD_TIME)
{
currentTime = time(NULL);
}
printf("Program Load stopped\n");
return 0;
}
Listing 3.2: Source-Code von Program load-i386
Auf Zeile 15 wird zusätzlich ein Zeitgeber mit der Funktion alarm() gestartet. Sollte das Programm
nach Ablauf von LOAD_TIME aufgrund von Problemen immer noch in Betrieb sein, sendet der Zeitgeber
zwei Sekunden später das Signal SIGALRM an das Programm, um es zu beenden.
3.2.3. Programm load-arm
Das Programm load-arm ist identisch mit dem Programm load-i386 (Kapitel 3.2.2) bis auf die Tatsache, dass es für den Prozessor ARM720 des Axotec Phoenix-SBC-500 Boards (Kapitel 3.3) kompiliert wurde.
24
RTAI-Linux |Interrupt-Latenzzeiten
3.3. Axotec Phoenix-SBC-500 Board
3.3.1. Technische Daten
Das Phoenix-ECM Embedded Computer Modul (Abbildung 3.3 rechts) von Axotec (www.axotec.com) ist
ein Single-Board-Computer im Kreditkartenformat. Das Modul basiert auf einem ARM 7TDMI Prozessor
mit MMU (74 MHz) und hat eine Vielzahl von Peripherie-Schnittstellen integriert. Das Phoenix-ECM Embedded Computer Modul ist für die anwendungsspezifische Integration konzipiert. Die Verbindung zwischen dem Phoenix-ECM und der Trägerhardware erfolgt über zwei Steckverbinder.
Abbildung 3.3: Phoenix-SBC-500 Board (links), Phoenix-ECM Embedded Computer Modul (rechts)
Zur Messung der Interrupt-Latenzzeiten wurde das Phoenix-SBC-500 Board (Abbildung 3.3 links) von
Axotec verwendet. Dieses führt die verschiedenen Schnittstellen des ECM-Moduls heraus und enthält
einen Speisungsteil.
• Software
Kernel 2.4.18, Busybox 1.1.2 (Buildroot), RTAI 24.1.9
• Prozessor
ARM 7TDMI / 74MHz Prozessor mit MMU und I-/D-cache
• Flash
Flash 16 MB
• RAM
DRAM 32 MB
• Netzwerk
10-BAST-T Ethernet RJ45
• Serial
2 x Serial RS232-Interface, Standard DSUB9 Steckverbinder
• Digitale I/O
GPIO, 3 x 8 Bit + 1 x 3 Bit bitweise I/O programmierbar
• Video
LCD-Controller für direkten Anschluss eines Vollgrafik LC-Displays
• Tastatur
Matrixkeyboard-Anschluss
• Timer
Programmierbarer Timer
• Interrupt
Programmierbarer Interrupt-Kontroller
• Audio
DAI Interface für direkten Anschluß eines Stereo D/A und A/D Wandler
• Leistungsaufnahme 380 mW (maximal)
3.3.2. Messschaltung
Für die Interrupt-Latenzzeitmessungen wurde der erste externe Interrupt des ARM7-Prozessor EINT1
gewählt. Der zustandsgesteuerte Interrupt wird aktiviert, wenn der entsprechende Pin des Prozessor
auf low gesetzt wird. Setzt man den Pin wieder auf high, wird der Interrupt gelöscht. Damit die Interrupt-Service-Routine des Interrupts jeweils nur einmal und nicht gleich mehrmals aufgerufen wird,
wurde die in Abbildung 3.4 gezeigte Schaltung für die Latenzzeitmessung verwendet.
25
RTAI-Linux |Interrupt-Latenzzeiten
Der Rechteckgenerator G1 generiert ein Taktsignal (30 Hz) für das JK-Flipflop IC1. Da der J-Eingang des
Flipflops auf high gesetzt ist, wird es bei jeder negativen Flanke des Taktsignals gesetzt. Das heisst der
invertierte Ausgang des Flipflops wechselt auf low und der Interrupt EINT1 des ARM-Prozessors wird
ausgelöst. In der Interrupt-Service-Routine von EINT1 wird als erstes der Pin PA7 auf low gesetzt. Dadurch wird das JK-Flipflop wieder zurückgesetzt und der externe Interrupt gelöscht. Vor dem Verlassen
der Interrupt-Service-Routine wird Pin PA7 wieder high gesetzt, damit das Flipflop von der nächsten
negativen Taktflanke wieder gesetzt werden kann.
Abbildung 3.4: Messschaltung Axotec Phoenix-SBC-500 Board (ARM720)
Der nichtinvertierende Ausgang Q des Flipflops wird also beim Auslösen des Interrupts EINT1 gesetzt
und beim Ausführen des ersten Befehls in der Interrupt-Service-Routine wieder gelöscht. Die Pulsdauer
an Ausgang Q entspricht somit der Interrupt-Latenzzeit des Axotec Phoenix Board. Genau genommen
enthält die Pulsdauer auch noch die Laufzeit, die beim Löschen des Flipflops vergeht. Diese Laufzeit ist
jedoch mit 18 ns [5, S. 5] sehr klein und kann für eine Messung im μs-Bereich vernachlässigt werden.
Die Pulsdauer am Ausgang Q wird mit Hilfe eines Oszilloskops K1 gemessen. Die Messdaten werden via
GPIB-Bus an einen PC übertragen und von einem LabVIEW-Programm in einem Textfile gespeichert.
Wie in Kapitel 3.1.2 gezeigt wurde, liest LabVIEW die von Oszilloskop K1 gemessene Impulsdauer etwa
mit einer Samplingrate von 15 Hz aus. Damit ausgeschlossen werden kann, dass derselbe Messwert
mehrmals ausgelesen wird, wurde für die Frequenz des Generators G1 der doppelte Wert der LabVIEWSamplingrate (30 Hz) gewählt.
Label
U1
G1
K1
B1
Bezeichnung
ISBE Power Supply
HAMEG Function Generator HM 8030-3
LeCroy 9314CM QUAD 400 MHz Oscilloscope
ELinEB (Axotec Phoenix-SBC-500 Board)
Nummer
223022
MV 402-4
MK 309-04
IC 403-06
Tabelle 3.1: Messmittel für Axotec Phoenix-SBC-500 Board
3.3.3. Interrupt-Handling
Wie in Kapitel 3.3.2 erläutert wurde, muss zur Messung der Interrupt-Latenzzeit eine Interrupt-ServiceRoutine erstellt werden, deren erster Befehl das JK-Flipflop löscht. Damit die Interrupt-Latenzzeiten
von RTAI mit denen eines normalen Linux-Kernels verglichen werden können, wurde ein Kernel-Modul
(elineb-latency-test.c) und ein RTAI-Modul (elineb-rtai-latency-test.c) erstellt, die
einen solchen Interrupt-Handler für den Interrupt EINT1 implementieren. Der Source-Code der beiden
Module ist in Anhang B zu finden.
elineb-latency-test.c
In der Intitialisierungsmethode des Kernel-Moduls latency_test_init() muss zuerst der Adressbereich der benötigen Prozessor-Register (Port A, Interrupt-Mask-Regsiter) in den virtuellen Adressbereich
des Kernels gemappt werden. Danach wird mit Hilfe der Funktion request_irq() eine HandlerFunktion für den Interrupt EINT1 registriert. Am Ende der Intitialisierungsmethode wird schliesslich
noch der Interrupt durch setzen des entsprechenden Bits im Interrupt-Mask-Regsiter aktiviert. In der
Handler-Fuktion irqHandler() wird Pin PA6 kurzzeitig auf low gesetzt und somit das JK-Flipflop gelöscht.
26
RTAI-Linux |Interrupt-Latenzzeiten
elineb-rtai-latency-test.c
Im RTAI-Modul muss zuerst ebenfalls der Adressbereich der entsprechenden Prozessorregister gemappt
werden. Das Registrieren der Handler-Funktion und das Aktivieren des Interrpts wird jedoch nun mit
Hilfe der RTAI-Funktionen rt_request_global_irq() und rt_enable_irq() ausgeführt.
3.3.4. Messresultate
Messung 1.1: Interrupt-Latenzzeiten ohne RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Axotec Phoenix-SBC-500 Board
elineb-latency-test.o
busy.sh
siehe Kapitel 3.3.2
17. Juli 2006, 16:08 Uhr
Tabelle 3.2: Übersicht Messung 1.1
Im Zeitintervall von 200 bis 470 s wurde der ARM720-Prozessor mit dem Script busy.sh belastet. Unter
dieser Last steigen die Interrupt-Latenzzeiten von durchschnittlich 8 μs auf 22 μs an. Während der Belastungsphase kam es auch zu grösseren Ausreissern (max. 61.01 μs).
Erstaunlich ist die Tatsache, dass bei der Belastung neben einer grösseren Dichte bei 22 μs auch Latenzzeiten im gesamten Bereich von 8 bis 22 μs auftreten. Diese Erscheinung konnte nur beim Phoenix-SBC500 Board mit der Last busy.sh beobachtet werden.
65
60
55
50
Interrupt-Latenzzeit [us]
45
40
35
30
25
20
15
10
5
0
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.5: Interrupt-Latenzzeiten ohne RTAI, Last: busy.sh (Axotec Phoenix-SBC-500)
• Maximale Interrupt-Latenzzeit:
61.01 μs
• Minimale Interrupt-Latenzzeit:
6.17 μs
• Durchschnittliche Interrupt-Latenzzeit:
11.20 μs
27
RTAI-Linux |Interrupt-Latenzzeiten
Messung 1.2: Interrupt-Latenzzeiten ohne RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Axotec Phoenix-SBC-500 Board
elineb-latency-test.o
load-arm
siehe Kapitel 3.3.2
14. Juli 2006, 10:22 Uhr
Tabelle 3.3: Übersicht Messung 1.2
In einer weiteren Messung wurde der ARM720-Prozessor im Zeitintervall von 190 bis 440 s mit dem Programm load-arm belastet. Unter dieser Last steigen die Interrupt-Latenzzeiten von durchschnittlich
8 μs auf 18 μs an. Grössere Ausreisser in der Belastungsphase bleiben aus.
Anders als bei Messung 1.1 sind bei dieser Messung erwartungsgemäss alle Interrupt-Latenzzeiten während der Belastungsphase deutlich grösser als im Leerlauf.
65
60
55
50
45
Latenzzeit [us]
40
35
30
25
20
15
10
5
0
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.6: Interrupt-Latenzzeiten ohne RTAI, Last: load-arm (Axotec Phoenix-SBC-500)
• Maximale Interrupt-Latenzzeit:
31.20 μs
• Minimale Interrupt-Latenzzeit:
6.42 μs
• Durchschnittliche Interrupt-Latenzzeit:
11.95 μs
28
RTAI-Linux |Interrupt-Latenzzeiten
Messung 1.3: Interrupt-Latenzzeiten mit RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Axotec Phoenix-SBC-500 Board
elineb-rtai-latency-test.o
busy.sh
siehe Kapitel 3.3.2
17. Juli 2006, 16:45 Uhr
Tabelle 3.4: Übersicht Messung 1.3
Verwendet man für die Messung der Interrupt-Latenzzeiten das RTAI-Modul elineb-rtai-latencytest.o erhält man im Belastungsfall (busy.sh) bessere Werte. Die Interrupt-Latenzzeiten steigen
während der Belastungsphase (200 bis 500 s) von durchschnittlich 8 μs auf 16 μs an und sind somit wesentlich tiefer als bei Messung 1.1 mit dem normalen Kernel-Modul elineb-latency-test.o.
Auch beim RTAI-Modul ist auf dem Phoenix-SBC-500 Board eine starke Streuung der Interrupt-Latenzzeiten zu beobachten, wenn als Last das Script busy.sh verwendet wird.
65
60
55
50
Interrupt-Latenzzeit [us]
45
40
35
30
25
20
15
10
5
0
0
100
200
300
400
500
600
700
800
t [s]
Abbildung 3.7: Interrupt-Latenzzeiten mit RTAI, Last: busy.sh (Axotec Phoenix-SBC-500)
• Maximale Interrupt-Latenzzeit:
24.98 μs
• Minimale Interrupt-Latenzzeit:
6.02 μs
• Durchschnittliche Interrupt-Latenzzeit:
9.76 μs
29
RTAI-Linux |Interrupt-Latenzzeiten
Messung 1.4: Interrupt-Latenzzeiten mit RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Axotec Phoenix-SBC-500 Board
elineb-rtai-latency-test.o
load-arm
siehe Kapitel 3.3.2
14. Juli 2006, 11:07 Uhr
Tabelle 3.5: Übersicht Messung 1.4
Kommt das Programm load-arm als Last zum Einsatz, ist eine leichte Anhäufung der InterruptLatenzzeiten bei 14 μs erkennbar. Jedoch treten während der Belastungsphase (190 bis 440 s) sehr viele
massive Ausreisser bis über 100 μs auf.
Somit schneidet das RTAI-Modul elineb-rtai-latency-test.o bei diesem Belastungsfall erstaunlicherweise erheblich schlechter ab als das normale Kernel-Modul elineb-latency-test.o in
Messung 1.2.
120
110
100
90
Latenzzeit [us]
80
70
60
50
40
30
20
10
0
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.8: Interrupt-Latenzzeiten mit RTAI, Last: load-arm (Axotec Phoenix-SBC-500)
• Maximale Interrupt-Latenzzeit:
118.83 μs
• Minimale Interrupt-Latenzzeit:
5.57 μs
• Durchschnittliche Interrupt-Latenzzeit:
22.36 μs
30
RTAI-Linux |Interrupt-Latenzzeiten
3.4. Evaluation-Kit SmartModule 855 MSEBX855
3.4.1. Technische Daten
Die SmartModule von Digital Logic (www.digitallogic.com) beinhalten die gesamte Funktionalität eines
normalen PCs. Alle Signale und Schnittstellen sind auf einem einzigen Bus, dem SmartBus480, zusammengefasst, so dass bei der Integration in kundenspezifische Anwendungen keinerlei Verkabelung notwendig ist. Das SmartModule 855 (Abbildung 3.9 rechts) ist mit einem Pentium M MLV 738 Prozessor (1.4
GHz) von Intel ausgestattet. Alle üblichen Peripherie-Schnittstellen sind verfügbar.
Abbildung 3.9: Evaluation-Kit SmartModule 855 MSEBX855 (links), SmartModule 855 (rechts)
Für die Messungen kam das Evaluation-Kit SmartModule 855 MSEBX855 (Abbildung 3.9 links) zum Einsatz.
Das Kit beinhaltet neben dem SmartModule 855 und den Peripherieschnittstellen ebenfalls eine Festplatte (20 GB), ein DVD- und Diskettenlaufwerk. Da das Kit die Funktionalität eines normalen PCs aufweist, wurde nicht ein Embedded-Linux, sondern eine normale Linux-Distribution (Ubuntu 5.04 "Hoary
Hedgehog") verwendet.
• Software
Ubuntu 5.04 "Hoary Hedgehog", Kernel 2.6.10, RTAI 3.2
• Prozessor
Intel Pentium M LV 738 1.4 GHz, 2048 kB 2nd Level Cache
• RAM
DRAM 1024 MB
• Festplatte
20 GB
• Netzwerk
100/10 BASE-T Ethernet RJ45
• Serial
2 x Serial RS232-Interface
• USB
6 x USB V2.0
• LPT
1 x Parallel LPT-Interface
• Video
i855GME, SVGA-Interface, DVI-Interface, LCD-Interface 18/24 Bit LVDS
• Tastatur/Maus
PS/2-Interface
• Audio
AC97, 5.1
• Leistungsaufname
20 W (maximal)
3.4.2. Messschaltung
Zur Messung der Interrupt-Latenzzeiten wurde die Parallelschnittstelle gewählt und die in Kapitel 3.3.2
beschriebene Messschaltung entsprechend angepasst (Abbildung 3.10). Interrupt 7 des Prozessors wird
dem Acknowledge-Pin der Parallel-Schnittstelle zugeordnet. Da eine positive Signalflanke den Interrupt
31
RTAI-Linux |Interrupt-Latenzzeiten
aktiviert, muss der Acknowledge-Pin an den nichtinvertierenden Ausgang des JK-Flipflops IC1 angeschlossen werden.
Abbildung 3.10: Messschaltung Evaluation-Kit SmartModule 855 MSEBX855
Das Flipflop wird beim Eintritt in die Interrupt-Service-Routine mit der Datenleitung D0 gelöscht. Da die
Signalpegel der Datenleitungen beim SmartModule 855 gerade einer Spannung von 5 V entsprechen,
kann das Flipflop IC1 mit einer Datenleitung (D7) gespiesen werden. Ansonsten ist das Messprinzip identisch mit der Messung beim Axotec Phoenix-SBC-500 Board (Kapitel 3.3.2).
Label
G1
K1
B1
Bezeichnung
HAMEG Function Generator HM 8030-3
LeCroy 9314CM QUAD 400 MHz Oscilloscope
Evaluation-Kit SmartModule 855
Gerätenummer
MV 402-4
MK 309-04
IC 421-1
Tabelle 3.6: Messmittel für Evaluation-Kit SmartModule 855 MSEBX855
3.4.3. Interrupt-Handling
Zur Implementation der Interrupt-Service-Routine wurden für das SmartModule ebenfalls ein normales
Kernel-Modul (smartmodule-latency-test.ko) und ein RTAI-Modul (smartmodule-rtailatency-test.ko) geschrieben.
Die beiden Module registrieren einen Interrupt-Handler für den Interrupt des Acknowledge-Pins der
Parallel-Schnittstelle (Interrupt 7). Da eine Standard-PC-Schnittstelle verwendet wird, sind die entsprechenden Register bereits in den virtuellen Adressraum des Kernels gemappt. Deshalb kann auf ein Mapping in den beiden Modulen verzichtet werden. Der Source-Code und die Makefiles der beiden Module
sind in Anhang B zu finden.
32
RTAI-Linux |Interrupt-Latenzzeiten
3.4.4. Messresultate
Messung 2.1: Interrupt-Latenzzeiten ohne RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Evaluation-Kit SmartModule 855 MSEBX855
smartmodule-latency-test.o
busy.sh
siehe Kapitel 3.4.2
24. Mai 2006, 09:53 Uhr
Tabelle 3.7: Übersicht Messung 2.1
Im Zeitintervall von 200 bis 470 s wurde der Pentium-M-Prozessor des SmartModuls mit dem Script busy.sh belastet. Im Leerlauf liegen die Interrupt-Latenzzeiten im Mittel bei 8.5 μs und nehmen bei
Belastung nur minimal zu. Während der Belastungsphase kommt es jedoch zu einigen massiven Ausreissern bis über 400 μs.
Grundsätzlich scheint das Script den Prozessor nicht allzu stark zu belasten, führt aber zu einigen groben Ausreissern bei den Interrupt-Latenzzeiten.
450
400
350
Interrupt-Latenzzeit [us]
300
250
200
150
100
50
0
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.11: Interrupt-Latenzzeiten ohne RTAI, Last: busy.sh (SmartModule 855 MSEBX855)
• Maximale Interrupt-Latenzzeit:
435.90 μs
• Minimale Interrupt-Latenzzeit:
7.00 μs
• Durchschnittliche Interrupt-Latenzzeit:
9.01 μs
33
RTAI-Linux |Interrupt-Latenzzeiten
Messung 2.2: Interrupt-Latenzzeiten ohne RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Evaluation-Kit SmartModule 855 MSEBX855
smartmodule-latency-test.o
load-i386
siehe Kapitel 3.4.2
17. Juli 2006, 09:35 Uhr
Tabelle 3.8: Übersicht Messung 2.2
Wie bei Messung 2.1 liegen die Interrupt-Latenzzeiten sowohl im Leerlauf als auch im Belastungsfall
durchschnittlich bei 8.5 μs. Allerdings führt das Last-Programm load-i386 zu wesentlich mehr und
grösseren Ausreissern (max. 1.68 ms) in der Belastungsphase (190 bis 440 s).
1700
1600
1500
1400
1300
1200
Interrupt-Latenzzeit [us]
1100
1000
900
800
700
600
500
400
300
200
100
0
0
100
200
300
400
500
600
700
t[s]
Abbildung 3.12: Interrupt-Latenzzeiten ohne RTAI, Last: load-i386 (SmartModule 855 MSEBX855)
• Maximale Interrupt-Latenzzeit:
1680.00 μs
• Minimale Interrupt-Latenzzeit:
4.00 μs
• Durchschnittliche Interrupt-Latenzzeit:
35.14 μs
34
RTAI-Linux |Interrupt-Latenzzeiten
Messung 2.3: Interrupt-Latenzzeiten mit RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Evaluation-Kit SmartModule 855 MSEBX855
smartmodule-rtai-latency-test.o
busy.sh
siehe Kapitel 3.4.2
24. Mai 2006, 13:50 Uhr
Tabelle 3.9: Übersicht Messung 2.3
Mit dem RTAI-Modul smartmodule-rtai-latency-test.o treten in der Belastungsphase (200 bis
450 s) im Vergleich zu den Messungen 2.1 und 2.2 keine nennenswerten Ausreisser auf. Die InterruptLatenzzeiten liegen bei Leerlauf im Mittel bei 8.5 μs und nehmen durch die Last des Scripts busy.sh
nur minimal zu.
Während der Belastungsphase gibt es vermehrt kleine Ausreisser, die jedoch mit maximal 12.2 μs um
ein vielfaches kleiner sind, als die bei den Messungen ohne RTAI.
28
27
26
25
24
23
22
21
Interrupt-Latenzzeit [us]
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.13: Interrupt-Latenzzeiten mit RTAI, Last: busy.sh (SmartModule 855 MSEBX855)
• Maximale Interrupt-Latenzzeit:
12.20 μs
• Minimale Interrupt-Latenzzeit:
7.17 μs
• Durchschnittliche Interrupt-Latenzzeit:
8.54 μs
35
RTAI-Linux |Interrupt-Latenzzeiten
Messung 2.4: Interrupt-Latenzzeiten mit RTAI
Hardware
Interrupt-Handling
Belastungsart
Messschaltung, Messmittel
Datum, Zeit
Evaluation-Kit SmartModule 855 MSEBX855
smartmodule-rtai-latency-test.o
load-i386
siehe Kapitel 3.4.2
14. Juli 2006, 14:05 Uhr
Tabelle 3.10: Übersicht Messung 2.4
Auch diese Messung mit RTAI zeigt im Vergleich zu Messung 2.2 wesentlich bessere Ergebnisse bei der
gleichen Belastungsart. Der Anstieg der Interrupt-Latenzzeiten im Belastungsfall (200 bis 450 s) ist kaum
wahrnehmbar. Ausserdem kann während der Belastungsphase keine Zunahme der Ausreisser, wie bei
den drei anderen Messungen, beobachtet werden.
28
27
26
25
24
23
22
21
Interrupt-Latenzzeit [us]
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
0
100
200
300
400
500
600
700
t [s]
Abbildung 3.14: Interrupt-Latenzzeiten mit RTAI, Last: load-i386 (SmartModule 855 MSEBX855)
• Maximale Interrupt-Latenzzeit:
11.42 μs
• Minimale Interrupt-Latenzzeit:
7.17 μs
• Durchschnittliche Interrupt-Latenzzeit:
8.42 μs
36
RTAI-Linux |Interrupt-Latenzzeiten
3.5. Übersicht Messresultate
In Tabelle 3.11 werden die Eckwerte der Interrupt-Latenzzeitmessungen noch einmal im Überblick dargestellt:
Phoenix-SBC-500
ohne RTAI
mit RTAI
busy.sh
load-arm
busy.sh
load-arm
1
2
3
61.01
6.17
11.20
31.20
6.42
11.95
24.98
6.02
9.76
118.83
5.57
22.36
SmartModule 855
ohne RTAI
mit RTAI
busy.sh
load-i386
busy.sh
load-i386
435.90
7.00
9.01
1680.00
4.00
35.14
12.20
7.17
8.54
11.42
7.17
8.42
Tabelle 3.11: Eckwerte der Interrupt-Latenzzeitmessungen im Überblick
1:
2:
3:
Maximale Interrupt-Latenzzeit
[μs]
Minimale Interrupt-Latenzzeit
[μs]
Durchschnittliche Interrupt-Latenzzeit [μs]
3.6. Auswertung
3.6.1. Axotec Phoenix-SBC-500 Board
Die Echtzeiterweiterung RTAI scheint auf dem Axotec Phoenix-SBC-500 Board nicht korrekt zu arbeiten.
Je nach Belastungsart werden mit dem RTAI-Modul viel schlechtere Resultate als mit dem normalen
Kernel-Modul erzielt. Die genaue Ursache für das Versagen von RTAI auf dem ARM7-Board konnte nicht
bestimmt werden. Jedoch können folgende Tatsachen für die schlechten Resultate von RTAI verantwortlich sein:
• Die aktuellen RTAI-Versionen enthalten keinen Kernel-Patch für ARM7-Prozessoren mehr. Deshalb
kam eine sehr alte RTAI-Version (24.1.9), die noch einen ARM7-Patch enthielt, zum Einsatz.
• Beim verwendeten RTAI-Patch patch-2.4.x-rmk-arm-rthal handelt es sich um einen UniversalPatch, der nicht genau auf die verwendete Kernel-Version (2.4.18) abgestimmt ist.
• Laut der Readme-Datei von RTAI 24.1.9 hat die integrierte ARM-Portierung erst den Status einer
Beta-Version. Nachfolgende RTAI-Versionen enthielten entweder keinen passenden RTAI-Patch oder
waren für das Axotec-Board nicht kompilierbar.
3.6.2. Evaluation-Kit SmartModule 855 MSEBX855
Die Interrupt-Latenzzeit ist beim SmartModule mit durchschnittlich 8.5 μs nicht kleiner als ohne RTAI,
jedoch wesentlich stabiler. Während beim normalen Kernel-Modul bei Belastung viele Ausreisser mit
Latenzzeiten bis zu 1.68 ms auftraten, betrug die maximale Interrupt-Latenzzeit bei den RTAIMessungen lediglich 12.2 μs.
Auf dem SmartModule 855 Evaluation-Kit kann die Stabilität der Interrupt-Latenzzeiten mit RTAI erheblich verbessert werden.
37
Literaturverzeichnis
[1]
Short, Keith: A Guide to Installing RTAI Linux, Anglo-Australian Observatory 2004
http://www.aao.gov.au/local/www/ks/documents/RTAI_Install.pdf
[2]
Dekert, David: Aufbau und Inbetriebnahme eines Linux-Echtzeit-Frameworks, Fachhochschule
Merseburg 2004
http://opus.fh-merseburg.de/opus/volltexte/2004/202/pdf/Dekert_kl_stud_arb.pdf
[3]
Racciu, Giovanni; Mantegazza, Paolo: RTAI 3.3 User Manual rev 0.2, 2006
http://www.rtai.org
[4]
Blattner, Jörg: Hart im nehmen? Linux in Echtzeit, Hochschule Zürich Winterthur 2005
http://www.ictnet.ch/docs/articles/blattner_zhw.pdf
[5]
M74HC76 - Dual J-K Flip Flop with Preset and Clear, Datenblatt, SGS-THOMSON 1994
http://noel.feld.cvut.cz/hw/st/2002.pdf
[6]
Yaghmour, Karim: The Real-Time Application Interface, 2001
http://www.opersys.com/publications/rtai-ols-2001.pdf
[7]
Abbott, Doug: Linux for Embedded and Real-time Applications, Burlington (USA) 2003, Elsevier
Science, ISBN 0-7506-7546-2
[8]
Düding, Dirk: Ein Beitrag zum Einsatz von echtzeitfähigen Linux-Varianten in der Automatisierungstechnik, Dissertation, Dortmund 2003, Universität Dortmund
https://eldorado.uni-dortmund.de/bitstream/2003/2822/1/dueding2.pdf
38
Anhang A
Kurzanleitung RTAI-Installation
A-1
RTAI-Linux | Anhang A
Echzeit-Kernel erstellen
Arbeitsverzeichnis erstellen (Kapitel 2.3.1)
$
$
$
$
cd /home/username
mkdir rtai
cd rtai
mkdir src
Kernelquellen laden und entpacken (Kapitel 2.3.2)
$
$
$
$
cd /home/username/rtai/src
wget ftp://ftp.de.kernel.org/pub/linux/kernel/v2.6/linux-2.6.10.tar.bz2
cd /home/username/rtai
tar xvfj src/linux-2.6.10.tar.bz2
RTAI-Quellen laden und entpacken (Kapitel 2.3.3)
$
$
$
$
cd /home/username/rtai/src
wget https://www.rtai.org/RTAI/rtai-3.2.tar.bz2
cd /home/username/rtai
tar xvfj src/rtai-3.2.tar.bz2
RTAI-Patch (Kapitel 2.3.4)
$ cd /home/username/rtai/linux-2.6.10
$ patch –p1 < ../rtai-3.2/base/arch/i386/patches/hal-linux-2.6.10-i386r9.patch
Echtzeit-Kernel konfigurieren (Kapitel 2.3.5)
Für Standardkonfiguration:
$ cp arch/i386/defconfig .config
Für Konfiguration der Linux-Distribution:
$ cp /boot/config-2.6.10-686 .config
$ make oldconfig
$ make menuconfig
Echtzeit-Kernel kompilieren (Kapitel 2.3.6)
$ make bzImage
$ make modules
Echtzeit-Kernel installieren (Kapitel 2.3.7)
$ sudo make modules_install
Kernel < 2.6.14:
$ sudo mkinitrd –o /boot/initrd.img-2.6.10-adeos 2.6.10-adeos
Kernel ≥ 2.6.14:
$ sudo mkinitramfs –o /boot/initrd.img-2.6.15-adeos 2.6.15-adeos
$ sudo cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.10-adeos
$ sudo cp System.map /boot/System.map-2.6.10-adeos
$ sudo ln –s /boot/System.map-2.6.10-adeos /boot/System.map
A-2
RTAI-Linux | Anhang A
$ cd /boot/grub
$ vi menu.lst
RTAI-Module erstellen
RTAI konfigurieren (Kapitel 2.4.1)
$
$
$
$
cd /home/username/rtai
mkdir rtai-build
cd rtai-build
make –f ../rtai-3.2/makefile menuconfig
RTAI kompilieren (Kapitel 2.4.2)
$ make
RTAI installieren (Kapitel 2.4.3)
$
$
$
$
sudo
sudo
sudo
sudo
make install
vi /etc/init.d/makeRTF.sh
chmod 755 /etc/init.d/makeRTF.sh
ln –s /etc/init.d/makeRTF.sh /etc/rcS.d/S00makeRtf
Neustart (Kapitel 2.4.4)
$ sudo shutdown –r now
RTAI testen
$ cd /usr/realtime/testsuite/kern/latency
$ sudo ./run
A-3
Anhang B
Kernel-Module zur Latenzzeitmessung
B-1
RTAI-Linux | Anhang B
Kernel-Modul elineb-latency-test.c
Source-Code
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
#define MODULE_NAME "Elineb Latency Test"
// IO address space base and register offsets
#define CS_IO_BASE
0x80000000
// Begin internal register addr space
#define PPA_DATA
0x0
// Port A Data Register offset
#define PPA_DIR
0x40
// Port A Direction Register offset
#define INT_SR1
0x240
// Interrupt Status Register 1 offset
#define INT_MR1
0x280
// Interrupt Mask Register 1 offset
#define CS_IO_LEN
0x130
// Address space length
#define INT_EINT1
5
// EINT1 INT number
#define BIT_EINT1
0x20
// EINT1 bit in the INTMR1 (is bit 5)
#define EINT1_DEVID
#define EINT1_DEVNAME
"Eint1Id"
"Eint1Dev"
// Device id for EINT1
// Device name for EINT1
// Global Variables
static u32 intMaskReg1;
// Interrupt mask register 1
static char *io_base = NULL;
// Base address returned by ioremap()
static struct resource *pres = NULL; // Resource is memory regions
// Interrupt Handler
static void irqHandler(int irq, void *dev_id, struct pt_regs *regs)
{
// Clear pin PA6 (Clear JK-Flipflop)
writeb(0x00, io_base + PPA_DATA);
// Set pin PA6
writeb(0x40, io_base + PPA_DATA);
}
// Init Function
static int __init latency_test_init(void)
{
printk(KERN_INFO MODULE_NAME " (compiled: %s %s)\n", __DATE__, __TIME__);
// Get memory region
if ((pres = request_mem_region(CS_IO_BASE, CS_IO_LEN, "ppadrv")) != 0)
{
printk(KERN_WARNING MODULE_NAME ": Could not get I/O resource\n");
}
// Map memory region
io_base = ioremap(CS_IO_BASE, CS_IO_LEN);
if (!io_base)
{
printk (KERN_WARNING MODULE_NAME ": Unable to remap I/O adress\n");
if (pres)
{
release_mem_region(CS_IO_BASE, CS_IO_LEN);
pres = NULL;
B-2
RTAI-Linux | Anhang B
}
return -EIO;
}
// Set Port A to output mode
writeb(0xff, io_base + PPA_DIR);
// Set pin PA6
writeb(0x40, io_base + PPA_DATA);
// Install interrupt handler
if (request_irq(INT_EINT1, irqHandler, SA_INTERRUPT, EINT1_DEVNAME,
EINT1_DEVID) != 0)
{
printk(KERN_INFO MODULE_NAME " could not request irq%d (%s)\n",
INT_EINT1, EINT1_DEVNAME);
}
// Enable interrupt EINT1
intMaskReg1 = readl(io_base + INT_MR1);
intMaskReg1 |= BIT_EINT1;
writel(intMaskReg1, io_base + INT_MR1);
printk(KERN_INFO MODULE_NAME " loaded.\n");
return(0);
}
// Exit Function
static void __exit latency_test_exit(void)
{
// Disable interrupt EINT1
intMaskReg1 = readl(io_base + INT_MR1);
intMaskReg1 &= ~BIT_EINT1;
writel(intMaskReg1, io_base + INT_MR1);
// Release interrupt handler
free_irq(INT_EINT1, EINT1_DEVID);
// Unmap memory region
if (io_base)
{
// Clear Port A
writeb(0, io_base + PPA_DIR);
iounmap(io_base);
io_base = NULL;
}
// Release memory region
if (pres)
{
release_mem_region(CS_IO_BASE, CS_IO_LEN);
pres = NULL;
}
printk(KERN_INFO MODULE_NAME " unloaded\n");
return;
}
module_init(latency_test_init);
module_exit(latency_test_exit);
Listing 3.3: Kernel-Modul elineb-latency-test.c
B-3
RTAI-Linux | Anhang B
Makefile
TARGET
= elineb-latency-test
CROSS_COMPILE
CC
LD
CFLAGS
INCLUDE
LDFLAGS
INSTALL_DIR
=
=
=
=
=
=
=
arm-linux$(CROSS_COMPILE)gcc
$(CROSS_COMPILE)ld
-O0 -Wall -DMODULE -D__KERNEL__ -DLINUX
-I/opt/elin/target/kernel/include
-static
/opt/elin/share/latencytests/nonrealtime
all: $(TARGET).o
$(TARGET).o: $(TARGET).c
$(CC) $(CFLAGS) ${INCLUDE} -o $(TARGET).o -c $(TARGET).c
install:
cp ${TARGET}.o ${INSTALL_DIR}
clean:
rm ${TARGET}.o
B-4
RTAI-Linux | Anhang B
RTAI-Modul elineb-rtai-latency-test.c
Source-Code
#include <linux/module.h>
#include <linux/ioport.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
#define MODULE_NAME
"Elineb Latency Test Realtime"
#define
#define
#define
#define
#define
#define
//
//
//
//
//
//
IO_BASE
IO_LEN
INT_SR_1
INT_MR_1
PA_DATA
PA_DIR
0x80000000
0x1300
0x240
0x280
0x00
0x40
// Global Variables
static char *io_base;
static struct resource *pres;
Begin internal register addr space
Address space length
Interrupt status register 1
Interrupt mask register 1
Port A data register
Port A direction register
// Virtual I/O base address after ioremap()
// Memory region
static void irqHandler(void)
{
// Clear pin PA6 (Clear JK-Flipflop)
writeb(0x00, io_base + PA_DATA);
// Set pin PA6
writeb(0x40, io_base + PA_DATA);
}
int init_module(void)
{
// Get memory region
if ((pres = request_mem_region(IO_BASE, IO_LEN, MODULE_NAME)) == NULL)
{
printk(KERN_WARNING MODULE_NAME ": Could not get I/O resource\n");
}
// Map memory region
io_base = ioremap(IO_BASE, IO_LEN);
if (!io_base)
{
printk(KERN_WARNING MODULE_NAME ": Unable to remap I/O address\n");
if (pres)
{
release_mem_region(IO_BASE, IO_LEN);
pres = NULL;
}
return(-EIO);
}
// Set port A to output mode
writeb(0xff, io_base + PA_DIR);
// Set pin PA6
writeb(0x40, io_base + PA_DATA);
B-5
RTAI-Linux | Anhang B
// Enable externel interrupt 1 EINT1
rt_request_global_irq(5, (void *)irqHandler);
rt_enable_irq(5);
printk(KERN_INFO MODULE_NAME " loaded\n\n");
return 0;
}
void cleanup_module(void)
{
// Unmap memory region
if (io_base)
{
iounmap(io_base);
io_base = NULL;
}
// Release memory region
if (pres)
{
release_mem_region(IO_BASE, IO_LEN);
pres = NULL;
}
// Disable externel interrupt 1 EINT1
rt_disable_irq(5);
rt_free_global_irq(5);
printk(KERN_INFO MODULE_NAME " unloaded\n\n");
}
Listing 3.4: RTAI-Modul elineb-rtai-latency-test
Makefile
TARGET
= elineb-rtai-latency-test
CROSS_COMPILE
CC
LD
CFLAGS
INCLUDE
=
=
=
=
=
LDFLAGS
INSTALL_DIR
arm-linux$(CROSS_COMPILE)gcc
$(CROSS_COMPILE)ld
-O0 -Wall -DMODULE -D__KERNEL__ -DLINUX
-I/opt/elin/target/kernel/include
-I/opt/elin/target/rtai/include
= -static
= /opt/elin/share/latencytests/realtime
all: $(TARGET).o
${TARGET}.o: ${TARGET}.c
$(CC) $(CFLAGS) ${INCLUDE} -o $(TARGET).o -c $(TARGET).c
install:
cp ${TARGET}.o ${INSTALL_DIR}
clean:
rm ${TARGET}.o
B-6
RTAI-Linux | Anhang B
Kernel-Modul smartmodule-latency-test.c
Source-Code
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#define MODULE_NAME
"Latency-Test i386 nonrealtime"
#define
#define
#define
#define
#define
0x378
0x37A
7
"LPT1"
0
LPT1_DATA
LPT1_DIR
INT_LPT1
INT_LPT1_DEVNAME
INT_LPT1_DEVID
// LPT data register
// LPT direction register
// Interrupt number
MODULE_LICENSE("GPL");
static int irqHandler(void)
{
// Clear pin D0 (Clear JK-FLipflop)
outb_p(0x80, LPT1_DATA);
// Set pin D0
outb_p(0x81, LPT1_DATA);
return IRQ_HANDLED;
}
int xinit_module(void)
{
// Register interrupt handler
if (request_irq(INT_LPT1, irqHandler, SA_INTERRUPT, INT_LPT1_DEVNAME,
INT_LPT1_DEVID) != 0)
{
printk(KERN_INFO MODULE_NAME " could not request irq%d (%s)\n",
INT_LPT1, INT_LPT1_DEVNAME);
}
// Enable interrupt 7
enable_irq(INT_LPT1);
// Set port to interrupt mode; pins are output
outb_p(0x10, LPT1_DIR);
// Clear port
outb_p(0x00, LPT1_DATA);
// Set Pin D0 and D7 (JK-Flip-Flop Power Supply)
outb_p(0x81, LPT1_DATA);
printk(KERN_INFO MODULE_NAME " loaded\n");
return 0;
}
void xcleanup_module(void)
{
// Disable interrupt 7
disable_irq(INT_LPT1);
free_irq(INT_LPT1, INT_LPT1_DEVID);
// Clear port
outb_p(0x00, LPT1_DATA);
B-7
RTAI-Linux | Anhang B
printk(KERN_INFO MODULE_NAME " unloaded\n");
}
module_init(xinit_module);
module_exit(xcleanup_module);
Makefile
obj-m := smartmodule-latency-test.o
KDIR
PWD
:= /lib/modules/$(shell uname -r)/build
:= $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
B-8
RTAI-Linux | Anhang B
RTAI-Modul smartmodule-rtai-latency-test.c
Source-Code
#include
#include
#include
#include
<linux/module.h>
<rtai.h>
<rtai_sched.h>
<rtai_fifos.h>
#define MODULE_NAME
"Latency-Test i386 realtime"
#define LPT1_DATA
#define LPT1_DIR
#define INT_LPT1
0x378
0x37A
7
// LPT data register
// LPT direction register
// Interrupt number
MODULE_LICENSE("GPL");
static void irqHandler(void)
{
// Clear pin D0 (Clear JK-FLipflop)
outb_p(0x80, LPT1_DATA);
// Set pin D0
outb_p(0x81, LPT1_DATA);
rt_ack_irq(7);
}
int xinit_module(void)
{
// Enable parallel port interrupt
if (rt_request_global_irq(INT_LPT1, (void *)irqHandler) != 0)
{
printk(KERN_INFO MODULE_NAME " could not request irq%d\n", INT_LPT1);
}
// Enable interrupt 7
rt_enable_irq(7);
// Set port to interrupt mode; pins are output
outb_p(0x10, LPT1_DIR);
// Clear port
outb_p(0x00, LPT1_DATA);
// Set Pin D1 (CLR) and D7 (JK-Flip-Flop Power Supply)
outb_p(0x81, LPT1_DATA);
printk(KERN_INFO MODULE_NAME " loaded\n");
return 0;
}
void xcleanup_module(void)
{
// Enable interrupt 7
rt_disable_irq(7);
rt_free_global_irq(7);
// Clear port
outb_p(0x00, LPT1_DATA);
printk(KERN_INFO MODULE_NAME " unloaded\n");
}
B-9
RTAI-Linux | Anhang B
module_init(xinit_module);
module_exit(xcleanup_module);
Makefile
obj-m
:= smartmodule-rtai-latency-test.o
KDIR
:= /lib/modules/$(shell uname -r)/build
PWD
:= $(shell pwd)
EXTRA_CFLAGS := -I/usr/realtime/include -I/usr/include/
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
B-10
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement