Timestamp

Für meinen Logikanalysator brauche ich eine Zeitangabe, wann sich ein Eingang geändert hat. Gibt es dafür eine Hardware-Funktion, die den genauen Zeitpunkt des Wechsels (bei PCINT) irgendwie festhält?

Ein 16-Bit Timer im Interrupt-Capture Modus liefert zusammen mit dem Overflow Interrupt einen Zeitstempel. Und das mit einer Auflösung bis runter zum Prozessor-Takt.

Wenn es weniger genau sein muss, tut es auch millis() oder micros()

Schon, nur wie löse ich dann den Capture-Interrupt aus? Der PCINT triggert ja auf jede Änderung an einem Port, aber eben nur intern.

Die weniger genaue Lösung habe ich schon, aber geht's auch noch genauer?

Momentan polle ich PCIFR und zähle die Schleifendurchläufe mit (byte). Bei einer Änderung wird der Zustand und Schleifenindex abgespeichert, ebenso wenn der Index überläuft. Das endet dann wenn der Speicher voll ist. Da der Speicher knapp ist, startet diese Schleife erst nach einem Triggersignal. Damit bekomme ich zwar keine exakte Zeitangabe, kann aber auch die Abfolge schneller Änderungen feststellen. Auf ISR möchte ich gerne verzichten, die machen alles eher langsamer, d.h. schnell aufeinanderfolgende Änderungen können nicht mehr unterschieden werden.

DrDiettrich:
Schon, nur wie löse ich dann den Capture-Interrupt aus?

Siehe Datenblatt. Geht wie gesagt nur auf 16 Bit Timern, wie Timer 1. Der Pin ist fest

Bei der Flanke (Richtung ist einstellbar) wird dann der Wert des Timer/Counter-Registers in das Interrupt Capture Register kopiert. Wenn man dann gleichzeitig einen Interrupt auslöst, weiß man dass was geschehen ist. Den Wert des Capture Registers muss man dann mit der Anzahl der Überläufe verrechnen um die Zeit zu erhalten.

Diese Library zeigt wie man das macht:
https://www.pjrc.com/teensy/td_libs_FreqMeasure.html

Hier hatte ich die Library mal angepasst um ein PWM Signal zu messen:

Da wird die triggernde Flanke einfach nach jedem Interrupt umgeschaltet (ganz am Ende der ISR). Außerdem habe ich unnötigen Kram zu Teensy Prozessoren rausgeschmissen. Dadurch wird es übersichtlicher.

Es sollen aber mehrere Eingänge überwacht werden, dafür reicht ein einziger Capture-Eingang nicht aus.

Mit dem Capture-Interrupt hatte ich schon beim AltSoftSerial zu tun, das schon bei 115kBaud Änderungen verschlabbert. Deshalb wollte ich eben auf Interrupt-Handler verzichten und stattdessen möglichst schnell pollen.

Dann erkläre mal bitte genauer, was du damit bezwecken willst, was für Signale liegen an. Wenn du von den externen Interrupt Quellen (INT0 / INT1) weggehst, wird es automatisch langsamer! Der AVR (Uno) hat nur 2 externe Interrupts. Bei allen Pin Change Interrupts musst du hingegen auch noch den alten Status sowie auch den aktuellen Status jedes Pins abfragen.

Ich schrieb doch schon, daß ich einen Port mit dem PinChange Flag auf Änderungen überwachen möchte.

DrDiettrich:
Es sollen aber mehrere Eingänge überwacht werden, dafür reicht ein einziger Capture-Eingang nicht aus.

DrDiettrich:
Ich schrieb doch schon, daß ich einen Port mit dem PinChange Flag auf Änderungen überwachen möchte.

Was denn nun?

Aber abgesehen davon, setze den Capture-Pin doch sobald du den PinChange siehst.
Das mit den PinInterrupts funktioniert auch von innen, dh. auf OUTPUT Pins.

Ich würde das aus der ISR tun, das hat zwar einen kleinen Overhead,
aber der ist viel konstanter als der einer Pollig Methode,
es sei denn dein Polling ist wirklich tight-loop.

Für diese Spezialanwendung könntest du auch eine minimale ISR in Assembler verwenden.

Setzen von einem Bit in einem Port-Register erscheint mir einfach.
Ein ausgewachsener Capture Interrupt kann dann die Daten ablegen und das kommunizieren,
bei dem ist das Delay nicht mehr kritsch, der Wert liegt ja im Capture-Register.

Ein Port hat 8 Bit, also können damit bis zu 8 Signale gleichzeitig überwacht und erfaßt werden, je nachdem, wieviele Bits nach außen geführt sind.

Mit dem Interrupt per Software kommen wir der Sache schon näher. Es fragt sich allerdings, ob das überhaupt einen Vorteil bringt. Lt. Datenblatt wird beim Lesen von TCR1L auch TCR1H gesichert, so daß man den Timer direkt schneller lesen kann als über den Umweg über Software-Capture. Aber danke für die Inspiration :slight_smile:

Mit Assembler möchte ich mich eigentlich auch nicht abquälen, zumindest jetzt noch nicht. Das Laden des Index und der Speicheradresse fürs Abspeichern erfordert auch noch das Sichern und Restaurieren einiger Register, das beim Pollen entfallen kann. Dieser Overhead tritt bei jedem Aufruf und Verlassen einer ISR auf.

Jedenfalls habe ich jetzt einige Ideen zum Ausprobieren :slight_smile:

Der Unterschied ist, eine konstante Verzögerung kannst du herausrechnen, eine variable (wie beim Pollen) nicht.

Hmm, das stimmt auch wieder. Jetzt kann nur noch ein Versuch klären, bei welcher Methode weniger Änderungen verschlabbert werden.

Du kannst es ja zunächt mit einer C ISR versuchen,
allerdings würde ich das Capture Bit mit direktem Portzugriff setzen/toggeln.
Da werden dann zu viele Register gerettet, aber für einen Versuch...

Hier die Ergebnisse meiner Tests:

Mit PCINT Interrupt kann ein Rechteck mit 45kHz gerade noch erfaßt werden, also Änderungen fast alle 10µs. Dabei wird nur 1 Byte Zeitinformation (LSB von micros()) gespeichert, bei mehr Bytes bricht die Abtastrate deutlich ein.

Mit Pollen kann noch ein Rechteck mit 370kHz erfaßt werden, also Änderungen schneller als 2µs. Dabei wird ein Schleifenzähler für die Zeitinformation verwendet, was beim Interrupt nicht geht.

DrDiettrich:
Dabei wird nur 1 Byte Zeitinformation (LSB von micros()) gespeichert,

Frage dazu:
wenn ich in eine Byte Variable eine unsign Long (zB micros()) speichere ist dann automatisch das LSB Byte gespeichert ?
ist mein bedenken unbegründet das der Compiler nicht etwa drei benachbarte Bytes im Variablenspeicher überschreibt ?

Der Typ des Ziels bestimmt, wieviele Bytes gespeichert werden. Bei Bedarf werden vor dem Speichern MSB aufgefüllt oder abgeschnitten.

DrDiettrich:
Der Typ des Ziels bestimmt, wieviele Bytes gespeichert werden. Bei Bedarf werden vor dem Speichern MSB aufgefüllt oder abgeschnitten.

Danke!