Leben ohne Interrupts (Update)

Der Propeller ist ja bekanntlich in seiner Architektur etwas anders als andere Mikrocontroller. Das macht Spaß, aber an der einen oder anderen Stelle ist es für mich persönlich schon etwas mühsam, sich von den bisherigen Denkstrukturen zu lösen.

Eine solche Besonderheit des Propellers – die gegenüber allen anderen Prozessoren und Mikrocontrollern fehlenden Interrupts – möchte ich hier ein wenig zur Diskussion stellen. Wie kommt man ohne Interrupts aus? In den letzten Monaten habe ich im Internet oft Neugierige und Neulinge erlebt, die sich ob der fehlenden Interrupts gleich wieder abgewendet haben. Aber ist das richtig so, sind die fehlenden Unterbrechungsmöglichkeiten so eine große Behinderung?

Meine provokante These zum Thema: Interrupts sind ein Relikt der Computersteinzeit! 😉 Sie sind ein gewolltes, aber nicht wirklich gekonntes Multitasking. Wenn man die Entwicklung von Prozessoren und Mikrocontrollern betrachte und gedanklich die technischen Möglichkeiten und Notwendigkeiten nachvollzieht, so kommt man schnell zu den Wurzeln der Interrupts: Komplexität und Chipfläche waren in der Anfangszeit eine teure und knappe Ressource, an einen solchen Luxus von acht Prozessoren pro Chip, wie wir ihn zur Verfügung haben, war nicht zu denken. Und dennoch mußten diese Computer auf zeitkritische Signale reagieren. Sollten zum Beispiel Daten über eine Schnittstelle empfangen werden, so mußte der Prozessor innerhalb einer definierten Zeitspanne diese Daten einlesen und in entsprechenden Puffern speichern. Aber was macht man, wenn nur ein Prozessor zur Verfügung steht, der auch nur ein Programm abarbeiten kann? Richtig: ein Hardwaresignal, welches mit dem entsprechenden Ereignis gekoppelt ist, unterbricht die aktuelle Programmausführung, sichert den relevanten Prozessorstatus und startet eine „Unterbrechungsbehandlungsroutine“ – unser Interrupt und seine Interruptroutine. Dieser Mechanismus ist also einfach aus der Not geboren, welche eine Architektur mit sich bringt, die nur einen Prozessor verfügbar hat.

Anders der Propeller: Warum soll ich den Aufwand betreiben und einen einzelnen Prozessor in seiner Arbeit unterbrechen – mit allem damit zusammenhängenden Aufwand an Speicherplatz und Rechenzeit – wenn ich auch einen eigenen Prozessor verwenden kann, welcher sich ganz ausschließlich um diese Aufgabe kümmert? Und gerade durch diese Aufteilung der Arbeit auf wirklich real vorhandene Hardware ergibt sich eine sehr deterministische Reaktionszeit des Systems – ein wichtiger Punkt, wenn es um die Bedienung von zeitkitischer Hardware geht.

Ein oft gelesenes Argument gegen den Propeller: Ohne Interrupts muß man alles im Polling machen! Nun ja, dieser Vorwurf gilt nach meiner persönlichen Meinung nur, wenn man das Problem nur oberflächlich betrachtet.

Auch in einem System mit Interrupts gibt es immer eine Stelle an der letztlich Polling stattfindet. Nehmen wir als Beispiel ein Terminalprogramm, welches über eine serielle Schnitstelle kommuniziert. Sicher findet in einem klassischen System die zeitkritische Bedienung der Schnittstelle selbst per Interrupt statt. Aber das Hauptprogramm, welches die Zeichen dann auf dem Bildschirm darstellt, wird letztlich auch wieder nur per Polling genau jene von der Interruptroutine befüllten Puffer überwachen. Mir fällt keine Anwendung ein, wo es die Mischung von Polling und Interruptmechanismen letztlich nicht gibt. Und mir fällt auch keine Anwenung ein, wo eine klare und saubere Verteilung der Funktionen auf real vorhandene Hardware und Verzicht auf die Krücke „Interrupt“ nicht nur Vorteile bringt. Was soll also diese Festhalten am „veralteten“ Interruptsystem, mag man an dieser Stelle gleich fragen?

Ein anderer Punkt: Die Aufteilung der Funktionen im Hive. Getrennt muß man die Aufteilung der Funktionen auf drei separate Mikrocontroller im Hive betrachten. Es ist sicher sinnvoll zusammengehörige Funktionen quasi als Funktionskomplex zu betrachten und einen solchen Komplex nicht aufzutrennen, bzw. auf mehrere Chips zu verteilen. So ist es gut das sich alle Benutzerschnittstellen in Bellatrix befinden: im Extremfall kann so die gesamte Funktionalität einer Benutzeroberfläche in Bellatrix integriert werden. Die Daten von der Maus um zum Beispiel ein Menü zu bedienen, müßen Bellatrix überhaupt nicht verlassen. Erst die Information ob und welcher Menüpunkt angeklickt wurde muß übertragen werden, um die entsprechende Funktion auszuführen.

Also, wie sieht das mit euch und den Interrupts aus? Sehe ich die Sache so falsch, ist der Propeller und seine Struktur eine Sackgasse oder ein Repräsentant der zukünftigen Entwicklung?

Update 03.04.2010:

Nicht ganz unpassend zum Thema gibt es unter den Beiträgen des Parallax Contest 2009/2010 die Implementierung eines RTOS-Kernels für eine Cog. Ein Sheduler verwaltet dabei das Timing und eine Threadliste mit den Vektoren zu den Anwendertasks. So ist es möglich in einer Cog viele verschiedene kleinere Serviceroutinen zu verwalten, ohne dafür eine eigene Cog zu verschwenden. Im Beispielcode findet man ein einfaches Signaldemo mit LED’s und ein Beispiel mit zwei UART-Empfangs- und Senderoutinen.

Link zum Contest-Beitrag: hier lang>>>

Diskussion im Forum zum Thema: Leben ohne Interrupt >>>