Forum: Mikrocontroller und Digitale Elektronik Port mit 200 kHz einlesen


von Gerd (Gast)


Lesenswert?

Hallo zusammen!

Ich möchte die Zustände zweier Ports (Port B, Port C) mit einer Frequenz 
von 200 kHz einlesen. Dazu verwende ich den Timer1 mit entsprechender 
Vorladung im CTC-Modus: Vergleichswert 80, Prescaler 1, f=16MHz.
Laut Simulator benötigt die ISR 31 Takte von der 1. zur letzten 
Code-Zeile, also knapp 2us. Setzen ich einen Breakpoint auf die 1. 
Codezeile und messe die Zeit zwischen 2 Aufrufen der ISR, komme aich auf 
6,69 us -> ca. 150 kHz. Woher kommen die zusätzlichen 4us? Hat das was 
mit dem Stack zutun? Was kann ich tun um die Zeit zu reduzieren?

Gruß

von Thomas (Gast)


Lesenswert?

probiere mal am Anfang und Ende von deinem Code ein Bit zu toggeln und 
mit Oszi die Zeit zu messen, ohne Hardwarebreakpoints, damit kannst du 
dein Ergebnis mal verifizieren :) Womöglich braucht dein Debugging ein 
paar Zyklen, wobei du natürlich gar nicht angegeben hast welchen 
Mikrocontroller du überhaupt verwendest

lg

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Bitte schreibe doch wenigstens, welche Programmiersprache du benutzt. In 
ASM z.B. wäre das Verhalten ungewöhnlich - in C kein bisschen.

von Stefan (Gast)


Lesenswert?

Der µC braucht eine gewisse Anzahl an Takte bis er die ISR ausführt (bis 
zu 50). Beschleunigen kann man das leider nicht wirklich. Aber evtl. 
heit dein µC ja DMA, dann geht das ganze Hardwareseitig

von M.O. (Gast)


Lesenswert?

Gerd schrieb:
> Woher kommen die zusätzlichen 4us?

Das wird an deinem Programm und der Art liegen, wie dein Prozessor die 
ISR abarbeitet. Guck im Simulator einfach im Single Step nach, was 
zwischen den Breakpoints passiert. Dann siehst du vielleich eher, wo dir 
die Zeit verloren geht. Vermutlich macht der Prozessor alles richtig und 
du hast einen Fehler in deiner Rechnung ;-)

von Max M. (jens2001)


Lesenswert?

RTFM!
Der Aufruf der ISR benötigt natürlich auch Zeit.

Aber wozu überhaupt Interups?
Was soll der MC noch in der Loop erledigen?

von Gerd (Gast)


Lesenswert?

Thomas schrieb:
> welchen
> Mikrocontroller du überhaupt verwendest

Atmega8535

Matthias Sch. schrieb:
> Bitte schreibe doch wenigstens, welche Programmiersprache du benutzt.

C - noch...

Max Mustermann schrieb:
> Aber wozu überhaupt Interups?
> Was soll der MC noch in der Loop erledigen?

20 Werte pro Port mit einer (einstellbaren) Frequenz von bis zu 200 kHz 
einlesen. Da die Frequenz einstellbar ist, verwende ich den Timer. Bis 
100 kHz geht es auch.

M.O. schrieb:
> Das wird an deinem Programm und der Art liegen, wie dein Prozessor die
> ISR abarbeitet. Guck im Simulator einfach im Single Step nach, was
> zwischen den Breakpoints passiert. Dann siehst du vielleich eher, wo dir
> die Zeit verloren geht. Vermutlich macht der Prozessor alles richtig und
> du hast einen Fehler in deiner Rechnung ;-)

Die Ausführung der ISR dauert 31 Takte. Das Problem ist die Zeit 
zwischen 2 Aufrufen der ISR, die bei 105 Takten liegt. Mir ist unklar 
was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR 
passiert.

von holger (Gast)


Lesenswert?

>Mir ist unklar
>was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR
>passiert.

Wie soll dir jemand helfen ohne deinen Code zu sehen?

von Brühwürfel (Gast)


Lesenswert?

> Die Ausführung der ISR dauert 31 Takte. Das Problem ist die Zeit
> zwischen 2 Aufrufen der ISR, die bei 105 Takten liegt. Mir ist unklar
> was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR
> passiert.

Vermutlich wird jeweils ein Interrupt vom Controller verpasst.

Ansonsten: Beitrag "Re: Port mit 200 kHz einlesen"

von M.O. (Gast)


Lesenswert?

Gerd schrieb:
> Mir ist unklar was in den 68 Takten nach Ende der ISR und aufruf der
> nächsten ISR passiert.
Da pusht und popt der µC Registerinhalte und rennt im Hauptprogramm rum, 
falls nicht noch andere Interrupts anstehen.

von Max M. (jens2001)


Lesenswert?

Gerd schrieb:
> Mir ist unklar
> was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR
> passiert.

Der MC tut dass was jeder Prozessor bei einem Interupt tut!
Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem 
Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang 
der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und 
Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm 
weiterzumachen.
Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht 
das gleich wieder los mit Register sichern......

von Gerd (Gast)


Lesenswert?

Max Mustermann schrieb:
> Der MC tut dass was jeder Prozessor bei einem Interupt tut!
> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem
> Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang
> der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und
> Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm
> weiterzumachen.
> Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht
> das gleich wieder los mit Register sichern......

Ja, dass wird mein Problem sein... Es gibt wohl keine Möglichkeit der uC 
daran zu hindern? ;-)

Mir bleibt dann für die besagte Frequenz wohl keine andere Möglichkeit, 
als das ohne Timer zu realisieren, oder? Also sozusagen im 
Hauptprogramm. Die erfoderliche Abtastzeit erreiche ich dann durch 
einsetzen von NOPs. Bessere Idee?

von MWS (Gast)


Lesenswert?

Gerd schrieb:
> Max Mustermann schrieb:
>> Der MC tut dass was jeder Prozessor bei einem Interupt tut!
>> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem
>> Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang
>> der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und
>> Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm
>> weiterzumachen.
>> Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht
>> das gleich wieder los mit Register sichern......
>
> Ja, dass wird mein Problem sein... Es gibt wohl keine Möglichkeit der uC
> daran zu hindern? ;-)

Das könnt' schon gerade noch gehen, denn der beschrieben Ablauf ist 
bestenfalls als ganz grobe Umschreibung ok, in Beziehung auf 8Bit AVRs 
in mehrfacher Hinsicht falsch.

Der ATM8535 schiebt im Interruptfall nur den ProgrammCounter auf den 
Stack, sonst macht er nichts, er sichert keine Register, er schiebt 
keinen Stackpointer auf den Stack.

C sichert die verwendeten Register selektiv, je nachdem wie gut die ISR 
geschrieben ist, müssen mehr oder weniger Register gesichert werden.

Das ist entscheidend, denn ein Paar Takte gehen noch für den Ein- und 
Rücksprung in die ISR weg (min. 7 Takte) und dann bleiben bei 31 Takten 
in der ISR für das Sichern und Wiederherstellen 42 Takte, also 21 beim 
Aufruf der ISR, 21 beim Ende. Das ist kanpp, aber nicht unmöglich.

Du wurdest bereits aufgefordert den Code zu zeigen, nur daran kann man 
sehen, ob das klappen kann. Scheinbar verstehst Du das nicht so recht.

von M.O. (Gast)


Lesenswert?

Max Mustermann schrieb:
> Der MC tut dass was jeder Prozessor bei einem Interupt tut!
> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem
> Stack.

Das höre ich zum ersten Mal. Lediglich das Sichern von Statusregister 
und Programmpointer wird man dem µC nicht verwehren können. Alles andere 
ist Sache der Software. Und wenn man genau weiss, welche Register in der 
ISR verändert werden, reicht es auch nur genau diese beim Einsprung in 
die ISR zu sichern.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Max Mustermann schrieb:
> Der MC tut dass was jeder Prozessor bei einem Interupt tut!

Das tut nicht der Prozessor, ein AVR sichert lediglich die 
Rücksprungadresse auf dem Stack von alleine. Alles andere macht die 
Kompilerumgebung. Bei avrgcc besteht aber die Möglichkeit, ISR von 
jeglichem Gedöns zu befreien, wenn du selber weisst, was du tust.
1
ISR(ADC_vector, ISR_NAKED) {}
schafft z.B. eine leere ISR, bei dem die automatische Sicherung von 
Registern wegfällt.
Siehe die Doku zur avrlib.

: Bearbeitet durch User
von M.O. (Gast)


Lesenswert?

Matthias Sch. schrieb:
> ein AVR sichert lediglich die Rücksprungadresse auf dem Stack von alleine.
Das Statusregister wird er sich schon noch zusätzlich sichern müssen. 
Sonst geht das schief. Die Rücksprungadresse alleine reicht nur bei 
einer Subroutine.

von drama (Gast)


Lesenswert?

Die Aufgabe schreit förmlich nach einem MCU mit DMA. Die gibt's doch 
schon billig, sogar bei den AVRs. Da hast du dann sogar noch genug 
CPU-Zeit übrig um was anderes nebenbei zu machen.

von c-hater (Gast)


Lesenswert?

Max Mustermann schrieb:

> Der MC tut dass was jeder Prozessor bei einem Interupt tut!

Das muß schon deshalb grandioser Schwachsinn sein, weil das jeder µC 
anders macht. Da wir inzwischen vom OP wissen, daß es sich um einen 
Atmega8535 handelt...

> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem
> Stack.

...ist zumindest das definitiv Schwachsinn. Ein Atmega sichert genau 
eine Sache von sich aus auf dem Stack, nämlich die Rücksprungadresse. 
Dazu braucht er zwischen 4 (Normalfall) und theoretisch maximal 6 
Takten. Letzteres erfordert aber schon einen Mega, dessen Stack in 
externem RAM liegt. Der 8535 hat keinen externen RAM, das wäre aber z.B. 
beim Mega8515 oder Mega128 immerhin möglich.

Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier 
Takte für reti. Zusammen also genau acht Takte unvermeidlichem 
Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.

Alles, was darüber hinausgeht, ist mehr oder weniger vermeidbar. Wenn 
man in der einzig wahren Sprache für kleine µC programmiert, der 
einzigen, die die volle Kontrolle über alle Aspekte der Hardware 
garantiert. Und die heißt numal einfach nicht C, das ist schon alles, 
was dazu zu sagen ist. Und irgendwie wohl auch oft genug gesagt wurde...

von MWS (Gast)


Lesenswert?

M.O. schrieb:
> Das Statusregister wird er sich schon noch zusätzlich sichern müssen.
> Sonst geht das schief. Die Rücksprungadresse alleine reicht nur bei
> einer Subroutine.

Nö, der Prozessor selbst sichert nur die Rücksprungadresse. Das SREG 
muss dann nicht gesichert werden, wenn man in der ISR ausschließlich 
Opcodes verwendet, die das Statusregister nicht beeinflussen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

M.O. schrieb:
> Das Statusregister wird er sich schon noch zusätzlich sichern müssen.

Nö, tut er nicht. Das musst du selber erledigen.

von Bernie (Gast)


Lesenswert?

Was nützt es, Portpins in der Geschwindigkeit abzufragen,
wenn bei den Standard-µCs nur für einige 1000 Messwerte
Speicherplatz vorhanden ist. Also für einige 100-stel bis
10-tel Sekunden.

Kann man mit nem µC machen, wenn man genau weiß, dass nach einer
Auslösebedingung, nur so wenig "Aufnahmezeit" nötig ist.

Aber, ob da so viel vorher überlegt wurde...

von Rolf M. (rmagnus)


Lesenswert?

c-hater schrieb:
> Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier
> Takte für reti. Zusammen also genau acht Takte unvermeidlichem
> Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.

Nein. Beim Auftreten eines Interrupts muß zunächst mal der aktuell 
abgearbeitete Befehl zuende gebracht werden, also im Falle z.B. eines 
RET bis zu 4 (oder 5 je nach Prozessor-Typ) zusätzliche Takte. Wenn das 
abgeschlossen ist, wird erstmal in die Interrupt-Vektor-Tabelle 
gesprungen, was die von dir erwähnten 4 Takte benötigt. Da findet sich 
dann in der Regel ein RJMP, der nochmal 2 Takte braucht. Das heißt, daß 
es bis zu 10 Takte dauern kann, bevor überhaupt an den Anfang der ISR 
gesprungen wird. Der Rücksprung braucht dann zusätzlich die erwähnten 4 
Takte. Eine komplett leere ISR braucht also schon mal bis zu 14 Takte 
(mal angenommen, daß kein Sleep-Modus benutzt wird, denn sonst 
verlängert sich das nochmal deutlich).
Dann kommt die Register-Sicherung. Selbst minimale Vertreter dieser Art 
sichern normalerweise erstmal ein Register auf dem Stack, um dann über 
dieses das SREG ebenfalls auf dem Stack zu sichern. 2 * PUSH und ein IN, 
macht 5 Takte, am Ende das umgekehrte, nochmal 5 Takte. So sind wir dann 
schon bei 24 Takten und können dann auch schon anfangen, der ISR ihren 
eigentlichen Inhalt zu geben.

von spess53 (Gast)


Lesenswert?

Hi

>Das heißt, daß
>es bis zu 10 Takte dauern kann, bevor überhaupt an den Anfang der ISR
>gesprungen wird.

Wenn du schon so genau sein willst, sind es maximal 9 Takte (10 bei 
22Bit-PC), da ein Befehl schon in Bearbeitung sein muss um noch 
abgearbeitet zu werden.

MfG Spess

von Rolf M. (rmagnus)


Lesenswert?

Für Interrupts, bei denen das Aufreteten Bedingung an den Takt gebunden 
ist, gebe ich dir recht. Beim Timer-Interrupt ist das der Fall.

von drama (Gast)


Lesenswert?

Rolf Magnus schrieb:
> So sind wir dann
> schon bei 24 Takten und können dann auch schon anfangen, der ISR ihren
> eigentlichen Inhalt zu geben.

Tja, und woher kam jetzt nochmal das Gerücht her, dass die ARMs 
besonders lange Interrupt-Latenz haben? Ein Cortex-M3 sichert den 
gesamten Kontext in 12 Zyklen!

von c-hater (Gast)


Lesenswert?

Rolf Magnus schrieb:

> c-hater schrieb:
>> Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier
>> Takte für reti. Zusammen also genau acht Takte unvermeidlichem
>> Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.
>
> Nein. Beim Auftreten eines Interrupts muß zunächst mal der aktuell
> abgearbeitete Befehl zuende gebracht werden

Das ist die variable Interruptlatenz, nicht die konstante. Und diese 
variable Interuplatenz ist zwar sicher oft sehr störend bezüglich der 
Reaktionszeit für die Bearbeitung eines Interrupts (denn sie kann 
sogar noch sehr viel länger sein als nur die Beendigung der aktuellen 
Instruktion, z.B. durch konkurrierende Interrupts oder CLI/SEI-Blöcke in 
main), aber sie ist kein Interrupt-Overhead im engeren Sinne, denn genau 
die Takte, die die ISR dadurch später zur Auführung kommt, kommt ja der 
unterbrochene Code derweil auch noch weiter in seiner Arbeit. Die 
Rechenzeit ist also im Unterschied zur konstanten Latenz nicht verloren, 
die variable Latenz verringert also im Gegensatz zur konstanten nicht 
den Durchsatz des Gesamtsystems.

> Wenn das
> abgeschlossen ist, wird erstmal in die Interrupt-Vektor-Tabelle
> gesprungen, was die von dir erwähnten 4 Takte benötigt. Da findet sich
> dann in der Regel ein RJMP

Und genau das ist schon der erste Punkt, der in Asm nicht mehr zwingend 
ist. Wenn ich eine im Bezug auf den Durchsatz extrem zeitkritische ISR 
habe, kann ich die notfalls auch direkt in den Vektorbereich legen. 
Schlimmstenfalls muß ich dann irgendwas anderes ohne Interrupt lösen, 
weil der zugehörige Vektor nicht mehr verfügbar ist.

> Eine komplett leere ISR braucht also schon mal bis zu 14 Takte

Das ist eindeutig falsch.

> Dann kommt die Register-Sicherung. Selbst minimale Vertreter dieser Art
> sichern normalerweise erstmal ein Register auf dem Stack, um dann über
> dieses das SREG ebenfalls auf dem Stack zu sichern

Auch wieder eine Sache, die in Assembler oft nicht nötig ist, denn es 
gibt erstens viele Instruktionen, die die Flags überhaupt nicht 
anfassen, dementsprechend gibt es dann auch keinen Grund, ebendiese zu 
retten, wenn man eine ISR nur mit solchen Instruktionen gebacken bekommt 
und zweitens kann ich in Assembler bei hinreichender Wichtigkeit der 
ISRs für den Durchsatz des Systems einfach ein Register systemweit für 
den Zweck reservieren, als Scratchregister zum Sichern der Flags in ISRs 
zu dienen. Wenn alle ISRs so kurz sind, daß ich sie vollständig exklusiv 
laufen lassen kann, brauchen dann nichtmal mehr die Flags vom 
Scratchregister auf den Stack, sondern sie bleiben einfach nur dort und 
werden auch von dort wiederhergestellt. Zweimal push gespart, zweimal 
pop gespart, total 8 Takte pro Interrupt. Wenn dabei nur ein einzelner 
Interrupt mit 400kHz ausgelöst wird und das System mit 20 MHz läuft, 
spare ich allein durch diese kinderleichten Manipulationen 3,2MTakte/s. 
Was nichts anderes bedeutet, das ich bezüglich des Durchsatzes mit 
diesem Ansatz Sachen realisieren kann, für die du sonst mindestens 
23,2MHz Systemtakt benötigen würdest. So einfach ist das...

Bezüglich der Reaktionszeiten ist das sogar oft noch extremer, denn hier 
wirkt sich jeder im exklusiven Teil einer ISR unnütz vertrödelte Takt 
auf die variable Latenz aller anderen ISRs gleichermaßen schädlich 
aus. Hier kann bei entsprechender Aufgabenstellung schon ein einziger 
gesparter Takt in irgendeiner ISR über geht oder geht nicht für das 
Gesamtsystem entscheiden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.