PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interruptverarbeitung auf 3 Eingängen ohne Verlust möglich?



Wolfram
07.02.2006, 11:24
Hallo,

ich muß an 3 möglichen Eingängen (X/Y/Z) auf einen Impuls reagieren, der ca. 5us lang ist. Der nächste Impuls kann aber schon 20us später kommen.
Leider kann es passieren, daß die Impulse eben nicht absolut zeitgleich an 1-3 Eingängen auftreten, sondern mit leichter zeitlicher Verzögerung, also etwas 1-2 us später. (wieder 5us lang, 20us später der nächste).

Hat das schon mal jemand gemacht?
Geht das überhaupt mit Bascom oder sollte ich das gleich in ASM probieren?
Als Prozessor habe ich mir den ATmega 88 ausgesucht, wegen der möglichen IR-Ports.
Aber eine Idee wäre doch auch, alle 3 Kanäle zu odern, um dort einen globalen Interrupt an INT0 auszulösen und dann nachzusehen, wie der Status auf den 3 Leitungen ist?
Diesen einlesen, speichern, Flag setzen und raus aus der IR-Routine.
Dann könnte der nächste kommen...

Soweit meine Theorie, denn was passiert in der IR-Routine, wenn der nächste Impuls auftritt, während ich den noch nicht verarbeitet habe?

Hat jemand schon mal mit nem 88 an 3 Eingängen sowas verarbeitet?

Danke für einen Gedankenaustausch und Hinweise,

Gruß Wolfram

ACsenf
07.02.2006, 11:36
Hi!
Ich würde dir vorschlagen mache einen Sammelinterrupt, der von allen 3 Signalen ausgelöst wird und frage dann gleich in der Routine die 3 Leitungen ab, wenn sie nur kurz nacheinander kommen müsste das so klappen. Wenn die Signale aber weiter auseinander sind kann es sein, daß eines verloren geht.
Bei einzelnen Int Eingängen ist immer der mit der höchsten Prio vorrangig. Ob nun auch die Routine abgebrochen wird und in die mit höherer Priorität gewechselt wird weiß ich nicht.

Gruß

Sven

SprinterSB
07.02.2006, 14:14
Hast du den Analog-Komparator frei? Dann vergleich doch einfach den AIN1-Eingang gegen die interne Bandgap von 1.23V und lasse nen Interrupt triggern (die Polarität ist dann umgedreht, sollte aber egal sein).

Wolfram
07.02.2006, 16:36
Das mit dem AIN1 verstehe ich nicht?!
OK, damit könnte ich den 3ten IR freimachen?
Aber die Idee mit dem Sammelinterrupt wäre doch machbar. Allerdings geht mir dann jedoch ein Signal verloren, wenn ich z.B. in der IR-Serviceroutine bin und dann am Y-Eingang 1 us später ein Puls auftaucht, oder wird der gelatched?
Ich habe darüber im Datenblatt nix gefunden, dort heißt es nur, daß beim Verlassen der Serviceroutine das IRFlag im GIFR-Register dann wieder gecleart wird...
Oder wird die Routine dann nochmals aufgerufen?

Bin etwas verwirrt....

Wolfram

SprinterSB
07.02.2006, 16:45
Größere AVRs haben einen Analog-Comparator (AC). Den AIN1 hängst du an das 3. Signal. AIN1 geht zum invertierenden Eingang des AC.

Den nicht-invertierenden Eingang des AC legst du an die interne Bandgab-Spannung V_BG von 1.23V. Die braucht nach Aktivierung 40µs, bis sie stabil ist, also einmal am Programmstart nach ihrer Aktivierung. Der AIN0-Pin wird dadurch nicht verbraucht, weil der nicht-invertierende Eingang ja nach V_BG verdrahtet ist.

Auf Polaritätswechsel (evtl. auch fallende/steigende Flanke, musst eben nachlesen) kann man eine IRQ triggern lassen. Weil das Signal an den invertierenden Eingang geht, bekommst du bei fallender Signal-Flanke einen IRQ, wenn dieser auf "steigen" eingestellt ist (der n.i. Eingang des AC wird ja dadurch größer als der i. Eingang).

Werner_Just
08.02.2006, 09:11
Hallo Wolfram,

PCINT 0...3 sind veroderte Interrupts für die Pins...
PCINT0: PCINT0...7-Pins
PCINT1: PCINT8...15-Pins
PCINT2: PCINT16...23-Pins

ich würde es trotzdem lassen. Während ein Interrupt ausgeführt wird, wird ein erneutes auftreten den gerade ausgeführten Interupts übersehen.
Während das Programm also einen Sammel-Interrupt abarbeitet wird ein erneutes auftreten des Sammelinterrupts nicht ausgewertet.

Tritt während der Ausführung eines Interrupts jedoch ein anderer Interupt auf, so geht dieser NICHT verloren. Er wird nach Beendigung des aktuell laufenden Interupts abgearbeitet.
Wenn also Int1 ausgelöst wurde und kurz nachher Int0, arbeitet der Atmel erst die Int1-Routine ab und danach die Int0-Routine.
Werden beide Interrupts gleichzeitig ausgelöst, entscheidet die Interupt-Priorität welcher zuerst abgearbeitet wird.

Da Du 3 externe Interrupts benötigst, musst Du schauen welchen Du außer Int0&1 noch nimmst. Hier bietet sich der Analogkomparator, wie schon von Georg-Johann geschrieben, an.


Ciao,
Werner

Wolfram
08.02.2006, 10:23
Hallo Georg - Johann,

danke für die kurze und präzise Info, werde mich mal einlesen.

hallo Werner,

danke, ich denke, ich habe verstanden.
Aber wenn doch eben keiner verloren geht, welchen Nachteil hätte ich denn dann, wenn ich wie folgt verdrahte:

X-Achse: INT0
Y-Achse: INT1
Z-Achse: PCINT0

Wenn ich in der IR-Routine nur kurz den Port einlese, ein Flag setze und wieder abhaue, um den Rest in der Vordergrundschleife zu machen, hätte ich doch die kürzestmögliche Verarbeitungs- und Verzögerungszeit, oder übersehe ich was?

Gruß Wolfram

Werner_Just
08.02.2006, 11:25
Hallo Wolfram,

PCINT reagiert auf jede Zustandsänderung. Afaik ist hier eine Unterscheidung ob LH oder HL-Flanke nicht möglich.

> Wenn ich in der IR-Routine nur kurz den Port einlese, ein Flag setze und
> wieder abhaue [...]
Beim PCINT musst Du den PIN einlesen um LH, HL unterscheiden zu können. Bei INT0, INT1 kannst Du Dir das sparen. Hier kannst Du die Interrupt-Auslösung flankenabhängig konfigurieren.

Das Signalisieren mit Flag und Abarbeiten in der Hauptschleife erzeugt längere Verarbeitungs- und Verzögerungszeiten, da auf den Interrupt erst nach der Rückkehr und beim erreichen der Auswerteroutine reagiert wird. Dafür ist die Verzögerung Deines Hauptprogramms minimal.

Weches Vorgehen sinnvoller ist, hängt vom Umfang und der Häufigkeit der auszulösenden Aktionen ab.

Ciao,
Werner

Werner_Just
08.02.2006, 11:55
Hallo Wolfram,

mir sind gerade erst Deine Angaben zum Timing aufgefallen.

IMO kannst Du das ganze Vergessen, sowohl in Bascom, wie auch in Assembler.

Bei 20µs Impulsabstand hast Du gerademal 400 Takte zeit überhaupt etwas zu tun. (Bei 20MHz Takt des 88er) Mit Bascom ist da nix zu machen und auch in Assembler ist höchstens ein Minimalprogrämmchen möglich.

Bei 1-2 µs (20-40 Takte) Verzögerung zwischen den verschiedenen Interrupts wirst Du Dich aber auch in Assembler verhaspeln, wenn mehr als das Toggeln eines Portpins als reaktion nötig ist.

Ciao,
Werner

SprinterSB
08.02.2006, 12:40
Also in 400 Zyklen geht ne ganze Menge (jedenfalls in Assembler oder C). In der ISR kann man die Ereignisse merken, in einem Puffer oder einer FIFO und im Hauptteil auswerten, oder in eine Interrupt-sichere Variable hochzählen (dann kann man aber die Reihenfolge nicht mehr zuodnen).

Das sollte selbst mit BASCOM gehen, oder ist das wiklich so übel? In 400 Takten sind schon Weltreiche erblüht und wieder versunken...

Interrupts gehen ja keine verloren, falls nicht ein IRQ noch während der "eigenen" ISR auftritt.

Wolfram
08.02.2006, 12:45
Hi Werner,

ui, das wäre schlecht!
Es handelt sich um eine Schrittmotorsteuerung für 3 Achsen, der Impuls soll ein 12Bit Datentelegramm via SPI an einen Controller senden, fast mehr nicht.
Wenn ich in der IR nur auf den Interrupt reagiere, den I/O Port einlese und dann in der Vordergrundschleife die gesetzten Flags abarbeite (= 12 Bit SPI pro aufgetretenem IR), sollte das doch in 400 Zyklen machbar sein, oder?

Es darf nur kein IR verloren gehen, wenn die alle mit einem Delta-T abgearbeitet werden, aber in der richtigen Reihenfolge, dann wäre meine Welt wieder in Ordnung...
Gruß Wolfram

Wolfram
08.02.2006, 12:49
@Georg-Johann:

..puh, das erleichtert mich etwas, ich bekam schon nen Schrecken.
Also dann halte ich mich kurz und mache mir intensiv Gedanken um die optimale Struktur.

Die weiter oben angegebene IR-Belegung (=Priorität (in Grenzen)) sollte dann doch i.O. sein, was schätzt Du?

Danke für die vielen Anregungen, auch nochmals an Werner!

Gruß Wolfram

Werner_Just
08.02.2006, 14:05
Hallo Georg-Johann,

> Das sollte selbst mit BASCOM gehen, oder ist das wiklich so übel?
übel nicht, aber man muß schon ganz genau aufpassen was man wie verwendet.

Was z.B. bereits absolut tödlich ist, ist die Verwendung von Interrupts ohne "nosave". 32 Register pushen a 2 Takte, 32 Register popen a 2 Takte macht 128 Takte nur für einen einzigen Interruptaufruf.
Und wenn man nosave verwendet, dann kann man die Interrupt Routine imo auch gleich in Assembler programmieren. Dann weis man wenigstens welche Register man pushen/popen muss.

Bei Interesse, zähl einfach mal nach, wieviele Takte ein simples 'incr Var' benötigt.
Das hat nix damit zu tun, das Basic schlecht oder übel währe, zum incr Register kommt schlicht das Laden und Speichern der Daten der Variable hinzu. C ist da auch nicht schneller, nur lässt sich in C einfacher direkt mit Registern arbeiten (wobei ich von C keinerlei Ahnung habe).

> In 400 Takten sind schon Weltreiche erblüht und wieder versunken...
Aber nicht in einer Hochsprache. ;-)


@ Wolfram
> Wenn ich in der IR nur auf den Interrupt reagiere, den I/O Port einlese
> und dann in der Vordergrundschleife die gesetzten Flags abarbeite (= 12
> Bit SPI pro aufgetretenem IR), sollte das doch in 400 Zyklen machbar
> sein, oder?

Doch, das ist machbar, zumindest was das Datenhandling angeht.
Um Deine 3x12bits über den SPI zu schieben brauchst Du aber eine beträchtliche Datenrate auf der seriellen Leitung.
36bits alle 20µs sind immerhin 1.800.000 baud. 'nen Kabel kannst Du bei den Datenraten imo nicht mehr dazwischenhängen. Das wirst Du (imo) nicht ohne weiteres stabil ans laufen bekommen.

Ciao,
Werner

P.S. mit 'IRAM' lässt sich eine Bytevariable imo direkt einem Register zuweisen. (Stichwort TINYs ohne eigenes RAM). Leider ist das in der Hilfe mehr als dürftig erklärt. Ob IRAM auch bei nicht TINYs unterstützt wird? -Keine Ahnung!

Wolfram
08.02.2006, 14:36
Ok, das mit dem Aufwand fürs sichern ist klar.
Ich kann ja mal die IR-Routine in mein Basic-Programm als ASM-Quelle einbinden und bei niedriger Taktrate testen.
Da der 88er ja bis zu 10MHz SPI Takt fahren kann, sollte das auch kein Problem sein.
Die anzusteuernden Chips befinden sich auf der Platine, bzw. optional max. 20cm über ein Kabel entfernt, wobei diese Option noch nicht sicher geplant ist.

Auch der SPI Transfer scheint mir in ASM nicht sooo der Knackpunkt zu sein, ich denke, ich kann es ja mal versuchen.

Gruß Wolfram

P.S: Was hat es mit dem IRAM auf sich?

Werner_Just
08.02.2006, 14:59
Hallo Wolfram,

> Was hat es mit dem IRAM auf sich?
AVRs ohne eigenes RAM können Variablen nur in den Registern ablegen.
Die Definition solcher Register-Variablen geschieht mit
"Dim Var As IRAM Byte"

Manipulationen an solchen IRAM-Variablen müssten in BASCOM eigentlich mit voller AVR-Geschwindigkeit ablaufen, da die Variablen weder geladen noch gespeicher werden müssen. Ein INCR Var braucht dann tatsächlich nur 1 Takt und nicht 8 oder 10 Takte wie bei normalen Variablen.
Nachteil, es sind nur 32 Variablen möglich und der Befehlssatz ist stark eingeschränkt. (Vermutlich gehen nur die Befehle, die ein 1:1 pendant in Assembler besitzen.)

Die BASCOM Hilfe schweigt sich dazu leider fast vollständig aus.
Ein bischen was findet man in den Samples zu den Tiny AVRs.

Ciao,
Werner

SprinterSB
08.02.2006, 16:02
Ok, für BASCOM werd ich mich hier nicht aus dem Fenster hängen ;-)

Wenn "nur" eine Ausgabe via SPI zu machen ist, kannst du weiter parallelisieren über die SPI-Hardware. Das erste Byte schreibst du ins SPI und lässt nen IRQ triggern, in dem das zweite Byte nachgeschoben wird. Den SPI-Interrupt würd ich für Interrupts offnen, um die Latenzzeit zu verringern und es für die externen so transparent wie möglich zu halten.

Das erfordert allerdings ne genaue Planung, damit ein externer IRQ nicht zwischen das 1. und 2. Byte was dazwischenfummelt und die einzelnen ISR s sich verstehen. Den SPI kannst du bis F_CPU/2 Takten, also bis 10MHz (kein Problem für die meisten HW-SPIs) bei 20MHz CPU-Takt. Das ist eine theoretische Obergranze von über 1MByte/Sek. Kommt eben drauf an, wie fix deine Software ist.

Nochwas zu "Hochsprache". Hochsprache bedeutet nicht automatisch, daß es langsam ist. Das hängt davon ab, was unter der Oberfläche an Optimierung passiert -- oder eben nicht passiert. Es ist z.B. überflüssig, immer alle 32 Register zu sichern (für Compiler-Entwickler ist es natürlich das bequemste ;-)). Und C mutet aus Sicht moderner objekt- oder aspekt-orientierter Sprachen eher an wie ein portierbarer Assembler, weniger wie eine Hochsprache...

Wolfram
08.02.2006, 18:43
Hmmm, sorry, aber da bin ich nicht ganz mitgekommen..

Wenn "nur" eine Ausgabe via SPI zu machen ist, kannst du weiter parallelisieren über die SPI-Hardware. Das erste Byte schreibst du ins SPI und lässt nen IRQ triggern, in dem das zweite Byte nachgeschoben wird. Den SPI-Interrupt würd ich für Interrupts offnen, um die Latenzzeit zu verringern und es für die externen so transparent wie möglich zu halten.

Kannst Du mir das noch mal erklären bitte?

Danke für Eure Hilfe!

Gruß Wolfram

Werner_Just
09.02.2006, 08:48
Hallo Wolfram,

> Kannst Du mir das noch mal erklären bitte?

Du musst das SPI 2x mit Daten füttern um ein komplette Telegramm abzusetzen.
Um die Wartezeit beim Verarbeiten des Telegramms nicht unnötig zu vertrödeln sollst Du den SPI Interrupt verwenden.

z.B.

- Du prüfst ob der vorherige SPI-Transfer beendet ist. (SPIF Flag = 1)
- Du schiebst das erste Byte in den SPI und enablest den SPI Interrupt (SPIE Flag = 1)
- Im SPI Interrupt schiebst Du das 2 Byte hinterher und disablest den SPI Interrupt. (SPIE Flag = 0)

Sobald SPIF, für das Hauptprogramm sichtbar, 1 wird, ist ein Telegramm komplett übertragen worden. (Zwischen den 2 Bytes eines Telegramms wird das SPIF Flag ebenfalls einmal kurz 1, der Atmel springt dabei aber sofort in den SPI-Interupt.)

Durch das verlagern des 2. Bytes in den Interrupt kannst Du erreichen, das die Telegramme nicht zerstückelt werden können und gleichzeitug Dein Hauptprogramm weiterarbeitet. Der SPI Transfer läuft damit parallel zum Programm praktisch komplett in der Hardware.

Du brauchst dann noch einen Buffer, der bis zu 3 Telegramme aufnehmen kann. (3 Telegramme pro 400-Takte-Zyklus)

Anm. ggf. macht es sinn, auch das Buffer-Handling in den SPI Interrupt zu verlagern.

Kommen eigentlich immer 3 Telegramme, oder können auch nur 2 oder 1 Telegramm pro 400-Takte-Zyklus kommen?


Ich denke, dass wars was Georg-Johann gemeint hat.

Ciao,
Werner

Wolfram
09.02.2006, 09:51
Moin,

danke Werner, werde es mir mal langsam durch den Kopf gehen lassen, denke aber, daß ich noch dahinter komme und es so genau verstehe, daß ich es umsetzen kann.
Habe ja bisher nur in Bascom programmiert und die Hardware für Softwareprofis vorbereitet.
Dieses hier muß ich jetzt aber selber programmieren, bin aber eigentlich guter Dinge....

Es ist eher unwahrscheinlich sondern der Worst case, daß 3 Telegramme innerhalb von 400 Zyklen raus müssen.
Viel wahrscheinlicher ist es, daß eher 1, selten 2, grenzwertig 3 abgearbeitet werden müssen...

Gruß Wolfram