Forum: Mikrocontroller und Digitale Elektronik "Burst" mit atmega328 erzeugen


von MacFly (Gast)


Lesenswert?

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
volatile uint8_t burst = BURST_LENGTH;
7
8
static void InitBurst(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
void setup() 
35
{
36
  InitBurst();
37
}
38
39
void loop() {
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 :-)

von MacFly-Nachtrag (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von MacFly-Nachtrag (Gast)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

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 ;-)

von Peter D. (peda)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von my2ct (Gast)


Lesenswert?

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

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

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!

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

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.

von MacFly (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wie bekommt man den Assemblerteil in den C Code? Bzw. wie inkludiert man 
die isr.S ?

von MacFly (Gast)


Lesenswert?

Danke für die Info, Falk.

Ich mache das ja aus Vergnügen, da freue ich mich evtl. über Ostern 
etwas zum frickeln zu haben.

von Falk B. (falk)


Lesenswert?

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? ;-)

von Dieter R. (drei)


Lesenswert?

Falk B. schrieb:
> handgeklöppelte Assembler-ISR

Ginge es nicht noch etwas kürzer, wenn man eines der GPIOR-Register 
verwendet?

von Falk B. (falk)


Lesenswert?

Dieter R. schrieb:
> Ginge es nicht noch etwas kürzer, wenn man eines der GPIOR-Register
> verwendet?

Was soll da kürzer werden?

von Dieter R. (drei)


Lesenswert?

out gpior1, r16
in r16, sreg
out gpior2, r16

2 Zyklen weniger. Bin mir unsicher, nicht getestet, scheint mir aber 
richtig.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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."

von Oliver S. (oliverso)


Lesenswert?

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

von Veit D. (devil-elec)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

Keiner, dem Dieter Rs Idee gefällt? Brächte immerhin 4 Takte.

Etwas aufpoliert:
1
  out   GPIOR1,r16
2
  out   GPIOR2,r17
3
  ...
4
  ...
5
  in    r17,GPIOR2
6
  in    r16,GPIOR1
Oder spricht aus C-Sicht etwas dagegen?

von Falk B. (falk)


Lesenswert?

S. Landolt schrieb:
> Keiner, dem Dieter Rs Idee gefällt? Brächte immerhin 4 Takte.

Schweigen heißt zustimmen. Ja, ist ein cleverer Trick.

von Peter D. (peda)


Lesenswert?

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:
1
#define saveregs r15:r14
2
  movw saveregs, r17:r16
3
  ; interrupt code
4
  movw r17:r16, saveregs
5
  reti

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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!

von S. Landolt (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Den MOWV Trick hatte ich mal in pure Assembler beim ATtiny13 verwendet, 
um Code zu sparen. Ist schon sehr lange her.

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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."

von Falk B. (falk)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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!

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.