Servus,
ich habe ein Programmierbroblem bei dem ihr mir vielleicht helfen könnt
den Fehler zu finden.
Ich möchte mit einem atmega328 einen "Burst" erzeugen. Als Hardware habe
ich einen Arduino nano Klon.
Ich habe mir das so gedacht, dass ich Timer2 benutzen kann mit fast PWM
generierung mit ocr2a als top Wert.
* Der ist zuerst auf 0, damit der Timer sozusagen auf 0 festgetackert
ist.
* In ocr2b kommt die gewünschte Breite, also halbe Frequenz des burst.
Bei compare match soll der Ausgang dann gsetzt werden.
* Wenn der Burst starten soll schreibe ich in ocr2a den doppelten Wert
von ocr2b, damit die Schwingung symmetrisch ist.
* In dem COMPB Interrupt zähle ich die Halbwellen mit und setzte nach
der Breite des bursts ocr2a wieder auf 0 zum anhalten.
1
#define WIDTH 5
2
#define TOP_COUNT 2*WIDTH
3
#define BURST_LENGTH 2
4
#define BURST_TRIGGER() do{ OCR2A = TOP_COUNT; } while(0) //wird am Anfang Probleme machen je nach Triggerzeit
5
6
volatileuint8_tburst=BURST_LENGTH;
7
8
staticvoidInitBurst(void)
9
{
10
TCCR2B=0;//stop
11
TCNT2=0;
12
OCR2A=0;//zuerst blockieren
13
OCR2B=WIDTH;
14
TCCR2A=_BV(COM2B0)|_BV(COM2B1)|_BV(WGM20)|_BV(WGM21);//set on match, Fast PWM, clear bot, top ocra
15
TCCR2B=_BV(WGM22)|_BV(CS20);
16
DDRD=_BV(3);
17
TIMSK2|=(1<<OCIE2B);//Compare ch B
18
sei();
19
}
20
21
22
//TIMER2_OVF_vect
23
//TIMER2_COMPB_vect
24
ISR(TIMER2_COMPB_vect)
25
{
26
if(--burst==0)
27
{
28
OCR2A=0;//wieder blockieren
29
burst=BURST_LENGTH;
30
}
31
}
32
33
34
voidsetup()
35
{
36
InitBurst();
37
}
38
39
voidloop(){
40
delay(10);
41
42
BURST_TRIGGER();
43
}
Funktioniert aber leider nicht so ganz. Wenn ich BURST_LENGTH = 1 setze,
kommen 3 Schwingungen raus, bei BURST_LENGTH = 2 ebenfalls und bei
BURST_LENGTH = 3 sind es derer 7.
Ich erkenne an dem Fehlerbild gar nichts. Möglicherweise hat es etwas
mit dem Interrupt und einer zu naiven Vorstellung davon zu tun?
Über sachdienliche Hinweise bin ich sehr froh :-)
P.S.
ach so: wenn ich das Datenblatt richtig verstehe wird der Wert für ocr2a
aktualisiert wenn der Timer auf Bottom steht, also wenn er gerade wieder
genullt wurde. Wenn ich im Compare match von ocr2b den Wert für ocr2a
ändere, gilt der alte bis zum Umbruch, oder?
MacFly schrieb:> Wenn ich BURST_LENGTH = 1 setze
Ohne Prescaler hat die CPU schlichtweg keine Zeit, Befehle auszuführen.
Schon ein leerer Interrupt dauert 10 Zyklen.
Ahhhh mir fehlt gerade der emoji für den facepalm :-)
Zu simpel um darauf zu kommen offenbar.
Welche Zeit ich einhalten könnte ist aber schwierig abzuschätzen denke
ich, weil der avr hat ja keine Prioritäten bei den Interrupts und könnte
durch etwas längeres lahmgelegt sein?
Ich wollte mit der oben gezeigten Art etwas rumspielen, das erschien mir
elegant. Wäre es da für die Praxis sinnvoller einen Timerinterrupt zu
nutzen und den Ausgangspin einfach zu Fuß zu toggeln?
MacFly-Nachtrag schrieb:> Ich wollte mit der oben gezeigten Art etwas rumspielen, das erschien mir> elegant. Wäre es da für die Praxis sinnvoller einen Timerinterrupt zu> nutzen und den Ausgangspin einfach zu Fuß zu toggeln?
Kann man machen, muss man nicht. So oder so muss man die Anzahl der
Pulse per CPU und Interrupt zählen und verwalten. Dabei kann man
nicht beliebig schnell werden, sprich, die Periodendauer eines Pulses
muss einen Mindestwert von ??? Takten haben, in deinem Programm WIDTH.
Wenn man maximale Geschwindigkeit haben will/braucht, muss man die ISRs
in Assembler schreiben. Ich würde reinen Assembler in einer .S Datei
nehmen, Hardcore-Freaks Inline-ASM ;-)
Für kleine Timerwerte sollte der Prescaler >=64 sein. Dann bleibt noch
etwas Zeit für die Mainloop.
Der AVR führt zwischen 2 Interrupts mindestens einen Befehl der Mainloop
aus.
Im Gegensatz dazu der ARM, der läßt die Mainloop komplett verhungern.
Wenn es nicht unbedingt ein 328p sein muß, nimm einen AVR, der einen
Output Modulator hat, z.B. den Mega2560. Damit geht das einfacher, auch
bei hohen Taktraten.
Oliver
Oliver S. schrieb:> ... nimm einen AVR, der einen Output Modulator hat, z.B. den Mega2560
Wenn es doch ein ATmega328 sein soll ...
Man könnte auch ein FPGA nehmen, ist hier aber nicht das Thema.
MacFly schrieb:> Ich möchte mit einem atmega328
Deswegen werden zeitkritische Operationen in Assembler geschrieben, so
daß man wirklich genau weiß, was der Prozessor macht. Ansonsten braucht
man sofort einen vielfach schnelleren Prozessor.
Edit:
Der Code ist auch mal wieder nicht vollständig. Dazu noch verschiedene
Stile in einem Listing ("InitBurst();" und "BURST_TRIGGER();"), dazu
noch so viel Caps... neee neee neee nee ne!
Hallo,
der Code ist schon vollständig, nur mit dem define ein absolut blöder
Syntax. Eine Funktion mit #define, dass geht gar nicht. Alle defines
Variablen hier kann man mit eindeutigen Datentypen definieren.
Wir reden hier vom Timer Mode 7 "Fast PWM" mit TOP = OCR2A.
OCR2A = 0; ist nicht blockieren.
Das sorgt jedoch für falsche Timereinstellung und der Timer spielt
verrückt, wenn COMPARE größer TOP ist. COMPARE darf nie größer TOP sein.
Wenn die Frequenz konstant bleiben soll muss man TOP nie ändern und
sollte ihn nie ändern. Den Timer schaltet man ab indem man die Prescaler
Bits auf 0 setzt.
In dem Fall hier benötigt man einen Zähler der die ausgegebenen Takte
zählt. Das geht nicht mit beliebig hoher Frequenz. Selbst wenn man
extern einen Schieberegister als Zähler an einen Interrupt anklemmt,
muss der Controller "genügend" Zeit zum reagieren haben.
Wenn die Frequenz wirklich so extrem hoch sein soll, dann ist das der
falsche Controller dafür. Habe es noch nicht probiert, aber ein
Controller mit CCL und Eventsystem könnte das vielleicht. Ein zweiter
Timer zählt die Pulse und schaltet mit mittels CCL den Takt nach außen
ab. Wenn man denn bei AVR bleiben möchte wäre das vielleicht mit einem
AVR DA/DB möglich.
Ansonsten Frequenz runter. Richtwert erstmal unter 100kHz.
Guten Morgen und danke für die Antworten!
Glaube das Problem ist gelöst. Der Formalismus kam bei den letzten Posts
ja etwas nach oben, daher erlaube ich mir mal nach zu fragen.
>Das sorgt jedoch für falsche Timereinstellung und der Timer spielt>verrückt, wenn COMPARE größer TOP ist. COMPARE darf nie größer TOP sein.
Das habe ich ehrlich gesagt bei studium des Datenblattes nicht bemerkt.
Für mich generiert in dem Modus der ocra einen Reset des Timers und der
ocrb den Vergkleichswert. Wenn ocra kleiner als ocrb ist zieht der
compare Wert halt den kürzeren. Also so habe ich das interpretiert; bist
du dir da sicher dass nicht nicht sein darf? Manchmal ist ja ein
Nebensatz entscheidend.
>Edit:>Der Code ist auch mal wieder nicht vollständig. Dazu noch verschiedene>Stile in einem Listing ("InitBurst();" und "BURST_TRIGGER();"), dazu>noch so viel Caps... neee neee neee nee ne!
Ich habe mir angewöhnt, Funktionen als "DasIstMeineFunktion" zu
schreiben und Variablen in "meine_variable", sowie #defines groß. Da
behalte ich den besten Überblick. Was spräche denn da generell gegen?
(Außer dass man sofern man Arduino library zusätzlich benutzt dabei mixt
- die Nano sind aber angenehm, weil man die direkt aus dem Editor
flashen kann, kein Netzteil braucht etc)
>Eine Funktion mit #define, dass geht gar nicht.
Das ist doch an sich nur eine lesbare Abkürzung um das Register zu
setzen.
MacFly schrieb:>>Das sorgt jedoch für falsche Timereinstellung und der Timer spielt>>verrückt, wenn COMPARE größer TOP ist. COMPARE darf nie größer TOP sein.>> Das habe ich ehrlich gesagt bei studium des Datenblattes nicht bemerkt.
Was daran liegt, daß das da auch nicht drin steht. Wenn compare größer
Top ist, passiert genau das, was man erwartet, nämlich gar nichts. Es
gibt halt keinen compare Match, das war’s.
Im O-Text:
„ When changing the TOP value the program must ensure that the new TOP
value is higher or equal to the value of all of the Compare Registers.
If the TOP value is lower than any of the Compare Registers, a compare
match will never occur between the TCNTn and the OCRnx. “
Oliver
MacFly schrieb:>>Das sorgt jedoch für falsche Timereinstellung und der Timer spielt>>verrückt, wenn COMPARE größer TOP ist. COMPARE darf nie größer TOP sein.>> Das habe ich ehrlich gesagt bei studium des Datenblattes nicht bemerkt.> Für mich generiert in dem Modus der ocra einen Reset des Timers und der> ocrb den Vergkleichswert. Wenn ocra kleiner als ocrb ist zieht der> compare Wert halt den kürzeren.
Das ist auch so.
> Also so habe ich das interpretiert; bist> du dir da sicher dass nicht nicht sein darf?
Doch, das darf so sein, es passiert dann halt nix.
>>Der Code ist auch mal wieder nicht vollständig. Dazu noch verschiedene>>Stile in einem Listing ("InitBurst();" und "BURST_TRIGGER();"), dazu>>noch so viel Caps... neee neee neee nee ne!>> Ich habe mir angewöhnt, Funktionen als "DasIstMeineFunktion" zu
AKA CamelCase, sprich ein Großbuchstabe am Wortanfang, keine
Unterstriche.
> schreiben und Variablen in "meine_variable",
Das ist die Schreibweise mit Unterstrich.
> sowie #defines groß. Da> behalte ich den besten Überblick. Was spräche denn da generell gegen?
Gar nichts, das sind gängige, akzeptierte Schreibweisen.
>>Eine Funktion mit #define, dass geht gar nicht.>> Das ist doch an sich nur eine lesbare Abkürzung um das Register zu> setzen.
Eben, Macros als kompakte (Inline)Funktionen sind üblich, wenn gleich
man das diskutieren kann.
Falk B. schrieb:> Eben, Macros als kompakte (Inline)Funktionen sind üblich, wenn gleich> man das diskutieren kann.
In wenigen Super-Sonder-Spezialfällen ist das hilfreich. Ansonsten
stammt das aus einer Zeit, als man hoffte, daß solche
Define-Maros-Funktionen schnelleren Code erzeugen würden . Die Zeiten
sind aber lange vorbei. Funktionen sind ein (durchaus elementarer)
Bestandteil der Sprache C(++), und ja, man darf die tatsächlich ohne
Nachteile auch benutzen. Der Compiler kriegt das mit den "kompakten
inline-Funktionen" schon hin.
Oliver
Ich hab das auch mal probiert, siehe Anhang. Einmal mit ISR in C, einmal
ISR in handpoliertem Assembler. In C braucht es 24 Takte bis zum
Ausschalten des Timers, in ASM 15.
ISR vom C-Compiler, am rechten Rand die CPU Takte/Befehl
1
ISR(TIMER2_COMPB_vect) { ; 5
2
678: 1f 92 push r1 ; 2
3
67a: 0f 92 push r0 ; 2
4
67c: 0f b6 in r0, 0x3f ; 63 ; 1
5
67e: 0f 92 push r0 ; 2
6
680: 11 24 eor r1, r1 ; 1
7
682: 8f 93 push r24 ; 2
8
9
if (--burst == 0) {
10
684: 80 91 21 02 lds r24, 0x0221 ; 2
11
688: 81 50 subi r24, 0x01 ; 1
12
68a: 80 93 21 02 sts 0x0221, r24 ; 2
13
68e: 81 11 cpse r24, r1 ; 2
14
690: 02 c0 rjmp .+4 ; 0x696 <__vector_14+0x1e>
15
TCCR2B = 0; // Timer 2 STOP
16
692: 10 92 b1 00 sts 0x00B1, r1 ; 2 , 24 Takte von ISR Anfang bis hier her
17
}
18
}
19
696: 8f 91 pop r24
20
698: 0f 90 pop r0
21
69a: 0f be out 0x3f, r0 ; 63
22
69c: 0f 90 pop r0
23
69e: 1f 90 pop r1
24
6a0: 18 95 reti
handgeklöppelte Assembler-ISR
1
; Takte
2
TIMER2_COMPB_vect: ; 5, ISR call
3
push r16 ; 2
4
push r17 ; 2
5
in r17, _SFR_IO_ADDR(SREG) ; 1, save SREG
6
7
lds r16, burst ; 2
8
dec r16 ; 1
9
brne TIMER2_COMPB_vect_not_done ; 1
10
sts TCCR2B, r16 ; 2, 16 Takte vom ISR Start bis hier her
11
; r16 is now zero, stop timer 2
12
TIMER2_COMPB_vect_not_done:
13
sts burst, r16 ; 2
14
15
out _SFR_IO_ADDR(SREG), r17 ; 1
16
pop r17 ; 2
17
pop r16 ; 2
18
reti ; 5
Es braucht mindestens diese Anzahl Takte vom Ende des Pulses bis zum
Ende der Periode des zählers, damit die CPU diesen vor der nächsten
Periode abschalten kann. Real braucht es ca. 5 Takte mehr, warum auch
immer. Ich hab noch 5 Takte Panikreserve draufgepackt ;-) Ebenso dürfen
dabei keine anderen Interrupts aktiv sein, denn die können das Timing
zum Abschalten versauen.
Siehe Anhang.
Wenn man minimal externe Hardware einsetzen will, nimmt man ein
AND-Gatter und verknüpft die OCx zweier Timer, z.B. Timer 2 und 1. Timer
2 macht dabei das Pulssignal, wie hier schon gezeigt. Timer 2
konfiguriert man so, daß damit die Torzeit für den Burst erzeugt wird,
also N*Periode. Am Ende müssen aber auch dort wieder ausreichend Takte
übrig bleiben, bis die neue Periode von Timer 1 beginnt, damit die CPU
diesen stoppen kann. Aber da ist man DEUTLICH flexibler, denn man kann
Timer 1 ja passend einstellen, die Periodendauer ist nahezu frei
wählbar, dazu kommt der Prescaler.
Veit D. schrieb:> Hallo,>> wie bekommt man den Assemblerteil in den C Code?
Gar nicht, deswegen ist es ja eine eigene Datei.
>Bzw. wie inkludiert man> die isr.S ?
Man muss sie nur im Projektbaum einbinden, wie jede andere Quelldatei.
Sowohl das alte AVR-Studio als auch das hippe Microchip Studio erkennen
Assemblerdateien und assemblieren und linken sie, ganz so wie C-Dateien.
Auch die Arduino-IDE macht das automatisch. Irgendwie clever, was? ;-)
Falk B. schrieb:> Real braucht es ca. 5 Takte mehr, warum auch> immer.
Erstmal muß der laufende Befehl (1..4) beendet werden, dann der PC
gepusht und die IV-Table angesprungen (4) und dann der rjmp zum Handler
(2).
Bei den großen AVRs mit 3 Byte PC nochmal 3 Zyklen mehr.
Peter D. schrieb:> Erstmal muß der laufende Befehl (1..4) beendet werden, dann der PC> gepusht und die IV-Table angesprungen (4) und dann der rjmp zum Handler> (2).
Schon klar, aber der push des PC + Jump dauern beim Mega laut Datenblatt
5 Takte. Deine extra 2 Takte werden nicht benötigt.
> Bei den großen AVRs mit 3 Byte PC nochmal 3 Zyklen mehr.
Das hier ist vom 128er, das 256er Datenblatt hab ich gerade nicht. Dort
steht 5 statt 4.
"Interrupt Response
Time
The interrupt execution response for all the enabled AVR interrupts is
four clock cycles minimum. After four clock cycles, the program vector
address for the actual interrupt handling routine is executed. During
this 4-clock cycle period, the Program Counter is pushed onto the Stack.
The vector is normally a jump to the interrupt routine, and this jump
takes three clock cycles. If
an interrupt occurs during execution of a multi-cycle instruction, this
instruction is completed before the interrupt is served."
Falk B. schrieb:> Das hier ist vom 128er, das 256er Datenblatt hab ich gerade nicht. Dort> steht 5 statt 4.
Der TO hat einen 328p…
Die 3-Byte-PC-AVRs brauchen einen Takt mehr für den Einsprung in die ISR
(5 statt 4), und ebenfalls einen Takt mehr fürs Reti (Ebenso 5 statt 4),
weil halt jedes Mal ein Byte mehr gepusht/gepopt werden muß.
Oliver
Falk B. schrieb:> Veit D. schrieb:>> Hallo,>>>> wie bekommt man den Assemblerteil in den C Code?>> Gar nicht, deswegen ist es ja eine eigene Datei.>>>Bzw. wie inkludiert man>> die isr.S ?>> Man muss sie nur im Projektbaum einbinden, wie jede andere Quelldatei.> Sowohl das alte AVR-Studio als auch das hippe Microchip Studio erkennen> Assemblerdateien und assemblieren und linken sie, ganz so wie C-Dateien.> Auch die Arduino-IDE macht das automatisch. Irgendwie clever, was? ;-)
Danke schön.
S. Landolt schrieb:> Etwas aufpoliert: out GPIOR1,r16> out GPIOR2,r17> ...> ...> in r17,GPIOR2> in r16,GPIOR1
Es geht noch sparsamer. Man reserviert sich einige der 32 Register für
die Sicherung:
Falk B. schrieb:> Deine extra 2 Takte werden nicht benötigt.
Aber nur wenn die nachfolgen Vektoren nicht benötigt werden. Den Code
direkt in die Tabelle zu plazieren, ist also die absolute Ausnahme.
Peter D. schrieb:> Es geht noch sparsamer. Man reserviert sich einige der 32 Register für> die Sicherung:
Toll, und wie sagst du das dem C-Compiler? Das #define reicht mal sicher
nicht.
Peter D. schrieb:>> Deine extra 2 Takte werden nicht benötigt.>> Aber nur wenn die nachfolgen Vektoren nicht benötigt werden. Den Code> direkt in die Tabelle zu plazieren, ist also die absolute Ausnahme.
Davon rede ich gar nicht! In den 4 bzw. 5 Takten ist der Sprung AUS der
Vektortabelle schon drin! Siehe mein Zitat aus dem Datenblatt!
Falk Brunner schrieb:
> Schweigen heißt zustimmen.
Natürlich nicht. Man kann aus Höflichkeit schweigen, oder weil man von
der Sache zu wenig versteht; weil man es für zu offensichtlich absurd
hält; oder, auch wenn es jetzt politisch wird, weil man die Folgen des
Widerspruchs fürchtet.
an Peter Dannegger:
Da die ISR ja in ein C-Programm eingebunden werden soll, die Frage:
lässt sich über r14,15 frei verfügen?
Falk B. schrieb:> Toll, und wie sagst du das dem C-Compiler?
Müßte man mal in der GCC-Doku nachlesen. Mikrooptimierung hat mich nie
ernsthaft interessiert.
Falk B. schrieb:> In den 4 bzw. 5 Takten ist der Sprung AUS der> Vektortabelle schon drin!
Probiers im Simulator aus. Ein leerer Interrupt
(Tabelleneinsprung+rjmp+reti) kostet 10 Zyklen.
Peter D. schrieb:> Müßte man mal in der GCC-Doku nachlesen. Mikrooptimierung hat mich nie> ernsthaft interessiert.
Deine Codebeispiele hier an diversen Stellen behaupten das Gegenteil.
Peter D. schrieb:> Probiers im Simulator aus. Ein leerer Interrupt> (Tabelleneinsprung+rjmp+reti) kostet 10 Zyklen.
Das war gar nicht die Frage! Es gib um das Erreichen es ISR ANFANGs, um
den Timer schnellstmöglich abzuschalten! Und da ist es egal, wie lange
ein reti oder sonstwas dauert, das NACH dem Abschalten des Timers
passiert.
Trink mal nen Kaffee, dann klappt's vielleicht besser mit dem
Textverständnis.
Falk B. schrieb:> Es gib um das Erreichen es ISR ANFANGs, um> den Timer schnellstmöglich abzuschalten! Und da ist es egal, wie lange> ein reti oder sonstwas dauert
Nö, das rjmp mußt Du schon noch ausführen, ehe irgendwelcher ISR-Code
kommt, d.h. mindestens 6 Zyklen Delay nach Ende der aktuellen
Instruktion.
Probiers aus.
Peter D. schrieb:> Den MOWV Trick hatte ich mal in pure Assembler beim ATtiny13 verwendet,> um Code zu sparen. Ist schon sehr lange her.
Wenn man schon exclusive Register für eine ISR reserviert, dann kann man
sie direkt nutzen, da muss man nicht erst andere Register dort
reinspeichern.
Aber um nochmal Klarheit zum Thema Interruptreaktionszeiten zu bekommen.
- Interrupt wird angefordert
- aktuellen Befehl beenden (1-3 Takte)
- PC (program counter) auf Stack schieben, PC mit passendem
Interruptverktor laden und den im Normalfall dort liegenden RJMP oder
JMP Befehle ausführen = 4 Takte (bei großen AVRs mit PC > 5 Takte) Das
alles ist eine atomare Operation!
der erste ISR-Befehl kann ausgeführt werden, Verzögerung 5-7 CPU-Takte
(6-8 bei den großen AVRs)
Siehe Datenblatt, "Interrupt response time", her vom mega 2561
"7.8.1 Interrupt Response Time
The interrupt execution response for all the enabled AVR interrupts is
five clock cycles minimum. After five clock cycles the program vector
address for the actual interrupt handling routine is executed. During
these five clock cycle period, the Program Counter is pushed onto the
Stack. The vector is normally a jump to the interrupt routine, and this
jump takes three clock cycles. If an interrupt occurs during execution
of a multi-cycle instruction, this instruction is completed before the
interrupt is served. If an interrupt occurs when the MCU is in sleep
mode, the
interrupt execution response time is increased by five clock cycles.
This increase comes in addition to the start-up time from the selected
sleep mode.
A return from an interrupt handling routine takes five clock cycles.
During these five clock cycles, the Program Counter (three bytes) is
popped back from the Stack, the Stack Pointer is incremented by three,
and the I-bit in
SREG is set."
Peter D. schrieb:> Nö, das rjmp mußt Du schon noch ausführen, ehe irgendwelcher ISR-Code> kommt, d.h. mindestens 6 Zyklen Delay nach Ende der aktuellen> Instruktion.> Probiers aus.
Du hast es nicht verstanden bzw. bist im Irrtum. Oder die Datenblätter
von Atmel stimmen nicht.
Falk B. schrieb:> Deine Codebeispiele hier an diversen Stellen behaupten das Gegenteil.
Dann schau mal auf das Datum dieser Beispiele bzw. es sind nur
Fragmente, keine komplette Anwendungen. Ab WINAVR hab ich Assembler
fallen gelassen, wie eine heiße Kartoffel.
Falk B. schrieb:> Oder die Datenblätter> von Atmel stimmen nicht.
Nö, die sind schon vollkommen korrekt:
"4.7.1 Interrupt Response Time
The interrupt execution response for all the enabled AVR interrupts is
four clock cycles mini-um. After four clock cycles the Program Vector
address for the actual interrupt handling routine is executed. During
this four clock cycle period, the Program Counter is pushed onto the
Stack. The vector is normally a jump to the interrupt routine, and this
jump takes three clock cycles."
Das sagt eindeutig, daß nach 4 Zyklen Minimum Du erst in der Tabelle
gelandet bist. Und dort steht dann typisch der Sprung zur ISR.
Peter D. schrieb:> Das sagt eindeutig, daß nach 4 Zyklen Minimum Du erst in der Tabelle> gelandet bist. Und dort steht dann typisch der Sprung zur ISR.
Hmmm, hab ich irgendwie missverstanden. OK, mein Fehler!