Zitat Zitat von NRicola Beitrag anzeigen
Auch hier (mit den internen 16MHz Clock) habe ich einen Verzug zwischen den Flanken von 11µs (=176 Clock cycles). So etwas fundamentales kann ja eigentlich nicht mehr falsch zwischen C und ASM implementiert sein. Oder etwa doch??
Daher wäre meine Vermutung, dass es eher noch etwas systematisches ist. Was könnte ich vergessen haben oder welches Register könnte mich noch ausbremsen? Ist dem interrupt-Prozess noch irgendein Timer oder anderer Trigger hinterlegt? Nach dem Schaubild "9-1 Intterrupt Logic" im Datenblatt eigentlich nicht.
Ich habe bis jetzt vorwiegend mit den high/low Prioritäten des Interrupts herumgespielt. Das lief alles auf's gleiche hinaus.
Zwei Vorbemerkungen: Die Interruptpriorität spielt nur eine Rolle, wenn zwei Interrupte gleichzeitig eintreffen. Das ist hier aber nicht der Fall. Und der CPU-Takt ist ein Viertel des Systemtaktes. die 176 Clock cycles sind also 44 Befehlstakte.

Aber mal ganz allgemein zu Interrupten und Interrupthandlern. Ein Interrupt kann jederzeit eintreten, daher muß der Prozessor nach abbarbeiten des Handlers 100% im gleichen Zustand sein, wie davor. Ansonsten würde das Haupprogramm nicht mehr richtig funktionieren. Ein Teil wird automatisch passieren, kost aber auch seine Zeit. So muß der Programmcounter auf dem Stack gesichert werden und die Anfangsadresse des Handlers muß geladen werden. Jeder Speicherzugriff dauert mindestens einen Prozessortakt, wieviel das in Summe bei einem PIC18 sind, weiß icht jetzt nicht. Jetzt ist der Prozessor also im Interrupthandler und muß als erstes alle Prozessorflags sichern, ohne sie dabei zu verändern. Da ein Interrupthandler eine normale C-Funktion ist, müssen dann alle Register gerettet werden, die der Compiler benutzt. Dazu gehören auch die, die in irgendwelchen Systemfunktionen für die Behandlung von longs oder für Multiplikation und Division benutzt werden, der Interrupt könnte ja gerade in der Bearbeitung einer solchen Funktion aufgetreten sein.

Auch kann der Compiler nicht vorhersagen, welche Register eine Libraryfunktion benutzt, die später nur als Objectcode dazugelinkt wird. Ich halte also die 44 Prozessorzyklen für die Interruptpräambel und für den Code, der vor deinem Portbitsetzen abläuft für nichts ungewöhnliches. Das Wiederherstellen des Prozessorzustands am Ende des Interrupts wird ähnlich lange dauern.

In Assembler wird das nur marginal besser. Bei ganz simplen Aufgaben des Interrupts kann man da besser sein, man muß aber bei jedem Befehl, den man schreibt, genau überlegen, was man tut. Und das auch, wenn man (oder auch ein anderer Programmierer) das Programm Monate oder Jahre später debugged. In C ist das kein Problem, ein paar Zeilen mehr im Interrupthandler und das Hauptprogramm läuft immer noch ungestört.

Zitat Zitat von Siro Beitrag anzeigen
zudem würde ich mir mal den Assemblercode von der Interruptfunktion ansehen.
Ich weis nicht was der Compiler dort für einen "overhead" für Register sichern usw. reinbaut.
Bei einer Free Version von Microchip hab ich hier schon haarsträubenden code erlebt....
Wenn er erstmal 50 Zeilen Code abarbeiten muss bis er deinen Zeile zum Bitsetzen erreicht
kommt da natürlich einiges an Zeit zusammen.
Mit Begriffen wie "haarsträubenden" wäre ich zurückhaltend. Es klingt so, als wären die Compilerprogrammier Vollpfosten und hätten ihr Handwerk nicht gelernt. Ich würd mir das erst erlauben, wenn ich selbst einen Compiler geschrieben hätte, der alle Regressionstest besteht.

Und die Vorstellung, daß ein Optimizer da viel machen kann, ist irrig. Auch der kann später hinzugelinkten Objectcode nicht wirklich analysieren. Ein 8-Bit Prozessor braucht für die Behandlung der in C gängigen Datentypen wie int oder long nun mal mehrere Register. Bei "großen" Prozessoren wird das mit den Registern besser, dafür ist der Code des Interrupthandlers wahrscheinlich nicht im Cache und muß erst aus dem langsamen Hauptspeicher geladen werden (und verdrängt dabei möglicherweise den Code des Hauptprogramms). Das ist dann zwar anders, aber nicht unbedingt besser.

MfG Klebwax