Hallo, An meinem atmega8 löse ich einen externen interrupt aus. In der ISR wird lediglich ein Ausgang auf high gesetzt (1 Zeile Code). Die Reaktionszeit beträgt bei 16MHz ca 1,25 Mikrosekunden. Woran liegt das? Gibt es eine Möglichkeit das Ganze etwas zu beschleunigen?
Hi 0,063µs / Takt -> ~20 Takte Sprung zur ISR 2/3 Takte Setzen des IO ebenfalls um den Dreh Bis auf dem PC-Int reagiert wird, vergehen auch 1/2 Takte im Simulator Wie viele Takte hattest Du erwartet? Was spricht der Simulator, wie viele Takte es sein sollten? Womit hast Du die 1,25µs ermittelt? Reproduzierbar? MfG
Ich habe so an die 5-6 Takte erwartet, sprich ca 400ns. Ist das realistisch? Mit dem Simulator habe ich nicht getestet. Gemessen habe ich mit dem Oszi direkt am Ausgangspin.
Hier als Anhang die Oszi-Aufnahme und der Code:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #define F_CPU 16000000UL
|
4 | #include <util/delay.h> |
5 | |
6 | int main(void) |
7 | {
|
8 | |
9 | DDRB = 0xff; |
10 | DDRC = 0xff; |
11 | PORTD = 0xff; |
12 | GICR |= (1 << INT1); |
13 | MCUCR |= (1 << ISC10)|(1<<ISC11); |
14 | sei(); |
15 | |
16 | while(1){ |
17 | PORTC=0xff; |
18 | _delay_ms(1); |
19 | PORTC=0x00; |
20 | _delay_ms(1); |
21 | |
22 | }
|
23 | }
|
24 | |
25 | ISR(INT1_vect) |
26 | {
|
27 | PORTB=0xff; |
28 | PORTB=0x00; |
29 | }
|
Ein Signal des PortC wird dabei zum Test auf den INT1/PD3 gegeben. Zum Oszibild: blau PortC und gelb PortB
14 Takte werden verschwendet? Ins Assemblerlisting schauen, ob der Compiler beim Eintritt in die ISR mehrere Register sichert.
fixi schrieb: > An meinem atmega8 löse ich einen externen interrupt aus. In der ISR wird > lediglich ein Ausgang auf high gesetzt (1 Zeile Code). Die Reaktionszeit > beträgt bei 16MHz ca 1,25 Mikrosekunden. Woran liegt das? Schlechte Programmierung, falsche Sprache. > Gibt es eine > Möglichkeit das Ganze etwas zu beschleunigen? Klar: Assembler. Damit ist bei Interruptsteuerung ein progagation delay für eine einzelne Flanke von 6 Takten möglich, bei einer Endlosschleife sind's sogar nur 4. Sprich, bei 16MHz: 375 bzw. 250ns.
fixi schrieb: > Gibt es eine Möglichkeit Assembler im C-Code zu verwenden? Das brauchst Du nicht. Auf den Prolog und Epilog kannst Du durch das Attribute ISR_NAKED verzichten. Dann werden r0, r1 und SREG (und evtl. andere Register) nicht gesichert.
:
Bearbeitet durch User
fixi schrieb: > Ich habe so an die 5-6 Takte erwartet, sprich ca 400ns. Ist das > realistisch? Absolut nein. Der AVR ist ein RISC, da sind 50 Takte nichts. Schon der nackte Interrupteinsprung + Return kostet 10 Takte. Dann noch Prolog, Epilog (Register retten). Auch muß man damit rechnen, daß ja gerade eine anderer Interrupt in Arbeit sein könnte. Assembler ist daher nur selten zielführend. Kalkuliere nen Interrupthandler mit ~200 Takten, das reicht für die meisten kleineren Sachen.
Peter D. schrieb: > Kalkuliere nen Interrupthandler mit ~200 Takten, das reicht für die > meisten kleineren Sachen. Das ist aber schon Schwarzmalerei. Sofern keine anderen Interrupts aktiv sind oder diese passend programmiert werden, ist eher von 30 - 50 Takten auszugehen.
m.n. schrieb: > Sofern keine anderen Interrupts aktiv > sind Genau das ist der Pferdefuß. Eine Applikation soll ja in der Regel noch viel mehr machen. Ein Interrupthandler darf nicht so tun, als wäre er ganz allein auf der Welt (im Flash). Er muß den anderen Tasks auch CPU-Zeit zugestehen.
Peter D. schrieb: > m.n. schrieb: >> Sofern keine anderen Interrupts aktiv >> sind und weiter zitiert: ... oder diese passend programmiert werden. Wenn man hohe Interruptlast im System hat, muß man sich auch ein paar Gedanken über die Prioritäten machen. Nur sehe ich diese Probleme beim TO überhaupt nicht. Wilhelm M. schrieb: > Auf den Prolog und Epilog kannst Du durch das Attribute ISR_NAKED > verzichten. > Dann werden r0, r1 und SREG (und evtl. andere Register) nicht gesichert. Das ist selbst schon bei dieser einfachen ISR tödlich! Transparente und schnelle ISRs programmiert man in Assembler, wo nur die Register gerettet werden, die unbedingt gebraucht werden mit SREG an allererster Stelle. Aber gut, dazu ist schon an anderen Stellen bis zum Abwinken diskutiert worden.
Kann jemand meinen Code so umschreiben, dass die Reaktionszeit besser wird? Wenn es sein muss, kann ich auch mit Assembler in der ISR leben.
Wie so oft: Vielleicht ist es auch an der Zeit zu erörtern was eigentlich das Ziel des ganzen Unternehmens sein soll, denn die schnelle ISR zu schreiben soll ja wohl keinen reinen Selbstzweck erfüllen. Sonst werden hier ja nur reihenweise die Pferde scheu gemacht für nix und wieder nix ....
m.n. schrieb: > Das ist selbst schon bei dieser einfachen ISR tödlich! Nö. Aus
1 | ISR(TIMER0_COMPA_vect, ISR_NAKED) { |
2 | PORTB = 0xff; |
3 | reti(); |
4 | }
|
wird
1 | .global __vector_14 |
2 | .type __vector_14, @function |
3 | __vector_14: |
4 | /* prologue: naked */
|
5 | /* frame size = 0 */
|
6 | /* stack size = 0 */
|
7 | .L__stack_usage = 0 |
8 | ldi r24,lo8(-1) ; tmp43, |
9 | out 0x5,r24 ; MEM[(volatile uint8_t *)37B], tmp43 |
10 | reti
|
11 | /* epilogue start */
|
12 | /* #NOAPP */
|
13 | .size __vector_14, .-__vector_14 |
Arduinoquäler schrieb: > denn die schnelle > ISR zu schreiben soll ja wohl keinen reinen Selbstzweck > erfüllen. Und falls doch, dann ist ein ATmega8 mit 8kB Flash für ein <100Byte Progrämmchen leicht oversized.
Peter D. schrieb: > Und falls doch, dann ist ein ATmega8 mit 8kB Flash für ein <100Byte > Progrämmchen leicht oversized. Wenn es um den eigentlichen Sinn der Übung geht (es soll ja keine Übung sein?) wird es sehr schnell sehr ruhig. Eine oft gemachte Erfahrung hier .... fixi schrieb: > Kann jemand meinen Code so umschreiben, dass die Reaktionszeit besser > wird?
fixi schrieb: > Kann jemand meinen Code so umschreiben, dass die Reaktionszeit besser > wird? Wenn es sein muss, kann ich auch mit Assembler in der ISR leben. Hast Du denn schon selbst mal die Vorschläge (ISR_NAKED) ausprobiert? Bzw. den Assembler-Code untersucht?
:
Bearbeitet durch User
Arduinoquäler schrieb: > Wie so oft: > > Vielleicht ist es auch an der Zeit zu erörtern was eigentlich > das Ziel des ganzen Unternehmens sein soll, denn die schnelle > ISR zu schreiben soll ja wohl keinen reinen Selbstzweck > erfüllen. > > Sonst werden hier ja nur reihenweise die Pferde scheu gemacht > für nix und wieder nix .... Finde ich nicht! Es ist ein MCVE, das ausreicht. Und ein klare Frage.
Wilhelm M. schrieb: > Es ist ein MCVE, das ausreicht. Malaysia Commercial Vehicle Expo reicht aus? Aha ... so so .... sehr interessant .... deine eigene Welt ...
Arduinoquäler schrieb: > Wilhelm M. schrieb: >> Es ist ein MCVE, das ausreicht. > > Malaysia Commercial Vehicle Expo reicht aus? > > Aha ... so so .... sehr interessant .... deine eigene Welt ... Wohl kaum! Schon mal gegoogelt: MCVE code -> erster Eintrag.
Wilhelm M. schrieb: > Wohl kaum! Schon mal gegoogelt: MCVE code -> erster Eintrag. Zu deiner eigenen Welt gehört dazu dass du es dem Suchenden überlässt wie er sucht. Also: MCVE --> Malaysia Commercial Vehicle Expo Zu deiner eigenen Welt gehört auch dazu dass du ohne Not irgedwelche Abkürzungen verwendest die kein Schwein kennt.
m.n. schrieb: > Wilhelm M. schrieb: >> Nö. > > Und Du meinst, man könne R24 mal eben so zerschießen? In diesem, sehr speziellen Fall ist das aber kein Problem! Schau Dir hast Listing genau an:
1 | .file "bm99a.c" |
2 | __SP_H__ = 0x3e |
3 | __SP_L__ = 0x3d |
4 | __SREG__ = 0x3f |
5 | __tmp_reg__ = 0 |
6 | __zero_reg__ = 1 |
7 | .section .text.startup,"ax",@progbits |
8 | .global main |
9 | .type main, @function |
10 | main: |
11 | /* prologue: function */
|
12 | /* frame size = 0 */
|
13 | /* stack size = 0 */
|
14 | .L__stack_usage = 0 |
15 | ldi r24,lo8(-1) |
16 | out 0x4,r24 |
17 | out 0x7,r24 |
18 | out 0xb,r24 |
19 | in r24,0x35 |
20 | ori r24,lo8(12) |
21 | out 0x35,r24 |
22 | /* #APP */
|
23 | ; 32 "/home/lmeier/Projekte/wmucpp/doc/bmcpp99/bm99a.c" 1 |
24 | sei
|
25 | ; 0 "" 2 |
26 | /* #NOAPP */
|
27 | ldi r24,lo8(-1) |
28 | .L2: |
29 | out 0x8,r24 |
30 | ldi r30,lo8(3999) |
31 | ldi r31,hi8(3999) |
32 | 1: sbiw r30,1 |
33 | brne 1b |
34 | rjmp . |
35 | nop
|
36 | out 0x8,__zero_reg__ |
37 | ldi r30,lo8(3999) |
38 | ldi r31,hi8(3999) |
39 | 1: sbiw r30,1 |
40 | brne 1b |
41 | rjmp . |
42 | nop
|
43 | rjmp .L2 |
44 | .size main, .-main |
45 | .text |
46 | .global __vector_2 |
47 | .type __vector_2, @function |
48 | __vector_2: |
49 | /* prologue: naked */
|
50 | /* frame size = 0 */
|
51 | /* stack size = 0 */
|
52 | .L__stack_usage = 0 |
53 | ldi r24,lo8(-1) |
54 | out 0x5,r24 |
55 | out 0x5,__zero_reg__ |
56 | /* epilogue start */
|
57 | .size __vector_2, .-__vector_2 |
58 | .ident "GCC: (GNU) 8.0.0 20170502 (experimental)" |
... also r24 wird mit demselben Wert überschieben ;-) Aber Du hast natürlich recht: ich hatte die Schleife in main() nicht beachtet ...
Arduinoquäler schrieb: > Wilhelm M. schrieb: >> Wohl kaum! Schon mal gegoogelt: MCVE code -> erster Eintrag. > > Zu deiner eigenen Welt gehört dazu dass du es dem Suchenden > überlässt wie er sucht. > > Also: MCVE --> Malaysia Commercial Vehicle Expo > > Zu deiner eigenen Welt gehört auch dazu dass du ohne Not > irgedwelche Abkürzungen verwendest die kein Schwein kennt. Schon mal was von StackOverflow gehört ... (wer ist das Schwein?)
:
Bearbeitet durch User
Wilhelm M. schrieb: > Es ist ein MCVE, das ausreicht. Und ein klare Frage. MCVE nimmt man für Bugreports. Hier handelt es sich aber um keinen Bug, sondern um falsche Erwartungen bezüglich der Ausführungszeit. Und zur Klarheit fehlen noch sämtliche wichtigen Randbedingungen (wie oft, welche anderen Tasks usw.). Unter speziellen Bedingungen kann man auf eine externe Flanke innerhalb 2..3 Takten einen Pin setzen: Timer als Zähler, Auswahl der Flanke, Signal an den Timereingang, Set Output-Pin on Compare, Comparewert auf Timer+1.
Peter D. schrieb: > Wilhelm M. schrieb: >> Es ist ein MCVE, das ausreicht. Und ein klare Frage. > > MCVE nimmt man für Bugreports. Nope, generell überall für jede Art von Frage, die mit einem bestimmten Codeverhalten (bug oder auch nicht) zu tun hat: FYI: https://stackoverflow.com/help/mcve FYI: for your interest HTH HTH: Hope that helps AFAIK, hat das aber alles nichts mit der Frage zu tun... http://www.catb.org/jargon/html
Meiner Meinung nach baut man sich mit ISR_NAKED eine Zeitbombe in den Code. Da nicht definiert ist, welche Register der Compiler für die folgenden Befehle benutzt, ist eine manuelle Sichtung des Outputs eigentlich unumgänglich. Spätestens bei einer Änderung der Compilereinstellungen oder einem Compilerupdate können ganz andere Register zu sichern sein. Und ich finde es auch nicht wirklich sinnvoll. Wenn man nicht gerade Funktionen im ISR aufruft, die nicht im gleichen C-File implementiert sind, dann sichert der gcc die Register sehr sparsam. Meiner Erinnerung sind es ein, höchstens 2 Register, die man händisch einsparen könnte. Falls man tatsächlich einen derart zeitkritischen Code hat, dann sollte man auf eingebetteten Asm-Code innerhalb von ISR_NAKED ausweichen. Gruß, Stefan
Stefan K. schrieb: > Meiner Meinung nach baut man sich mit ISR_NAKED eine Zeitbombe in den > Code. Sehe ich genauso. Aber die Frage war nach den Möglichkeiten ... > Und ich finde es auch nicht wirklich sinnvoll. Wenn man nicht gerade > Funktionen im ISR aufruft, die nicht im gleichen C-File implementiert > sind, dann sichert der gcc die Register sehr sparsam. Oder er macht ein inlining der Funktion. Wenn man Templates (C++) verwendet sogar (fast) immer (da es dieselbe TU, ups, Übersetzungseinheit ist).
fixi schrieb: > Ich habe so an die 5-6 Takte erwartet, sprich ca 400ns. Ist das > realistisch? Minimum: 2 Takte Flankenerkennung 4 Takte Interrupt response time 2 Takte rjmp IRQ-Vector 1 Takt Ausgang setzen (per sbi) In C ohne "naked" kommen da im Idealfall noch 2 Takte zur Rettung des Status Registers dazu. Oliver
1 | ISR(TIMER0_COMPA_vect, ISR_NAKED) { |
2 | asm volatile ( |
3 | "push r16" "\n\t" |
4 | "ldi r16, 0xFF" "\n\t" |
5 | "out %0, r16" "\n\t" |
6 | "pop r16" "\n\t" |
7 | :
|
8 | : "M" (_SFR_IO_ADDR (PORTB)) |
9 | );
|
10 | asm volatile ( "reti" ); |
11 | }
|
oh, ich überlas, es ging um den INT1-Interrupt... dann eben so...
1 | ISR(INT1_vect, ISR_NAKED) { |
2 | asm volatile ( |
3 | "push r16" "\n\t" |
4 | "ldi r16, 0xFF" "\n\t" |
5 | "out %0, r16" "\n\t" |
6 | "pop r16" "\n\t" |
7 | :
|
8 | : "M" (_SFR_IO_ADDR (PORTB)) |
9 | );
|
10 | asm volatile ( "reti" ); |
11 | }
|
Asche über mein Haupt.
Dorftrottel schrieb: > oh, ich überlas, es ging um den INT1-Interrupt... > ... > Asche über mein Haupt. ... war wohl ursprünglich mein Fehler ...
Wilhelm M. schrieb: > ... war wohl ursprünglich mein Fehler ... Dem ist wohl so, ärgere mich dennoch über diesen peinlichen Lapsus, so entstehen Fehler.
Der Ablauf ist eigentlich recht einfach: 1. Es dauert ein bisschen, bis eine Unterbrechung erkannt wird (1 bis 2 Takte). Üblicherweise sind die ja auch asynchron. Siehe Handbuch. 2. Nicht jeder Befehl kann unmittelbar unterbrochen werden, manche müssen halt beendet werden (1 bis 2 Takte). 3. Die Rücksprungadresse muss auf dem Stapel abgelegt werden (2 Bytes Push). 4. Die neue "Arbeitsadresse" muss in den Programmzähler geholt werden. 5. Arbeitest Du nicht im Assembler, so wird hier praktisch immer noch das Statusregister gesichert. 6. MACH DEIN DING. Zusätzlich fast immer 1 X Push und 1 X Pop. 7. Ein Compiler wird hier das Statusregister restaurieren. 8. Interrupt beenden meist mittel IRET. Also mindestens 2 X Pop. Also: Auch wenn Du in Assembler programmierst, gibt es einige Sachen, die unumgänglich sind. Die Meisten sind mit etwas Nachdenken einfach nachzuvollziehen. Natürlich fällt, bei den heutigen Compilern, kein "alle Register sichern" und kein "alle Register restaurieren" am Ende der Routine mehr an. Habe bestimmt den einen oder anderen Takt vergessen.
Klar ist der Code etwas primitiv. Es geht aber erstmal nur darum die Reaktionszeit zu testen, bevor es ans eigentliche Projekt geht. Dafür sollte dieses Beispiel ausreichend sein. Wie es aber scheint, gibt es (noch) keine Lösung für ein schnelleres ansprechen :( Später soll das Programm doch etwas umfangreicher werden. Dorftrottel schrieb: > oh, ich überlas, es ging um den INT1-Interrupt... > dann eben so...ISR(INT1_vect, ISR_NAKED) { > asm volatile ( > "push r16" "\n\t" > "ldi r16, 0xFF" "\n\t" > "out %0, r16" "\n\t" > "pop r16" "\n\t" > : > : "M" (_SFR_IO_ADDR (PORTB)) > ); > asm volatile ( "reti" ); > } > Asche über mein Haupt. das funktioniert so leider nicht ganz - PORTB ist dauerhaft auf high.
Hi Wie sieht es aus, die scheinbar nicht auszumerzenden Takte durch brachiale Prozessor-Geschwindigkeit anszutricksen? Wenn bei Deiner aktuellen Geschwindigkeit 40 Takte vergehen, wo Du mit maximal 4 Takten leben kannst - Tiger in den Tank und Quarz x10 in den Slot - die Wartetakte hast Du zwar immer noch, sind aber viel schneller vorbei. MfG PS: fixi schrieb: > das funktioniert so leider nicht ganz - PORTB ist dauerhaft auf high. Dann ersetze versuchshalber "ldi r16, 0xFF" "\n\t" durch "ldi r16, 0x00" "\n\t"
:
Bearbeitet durch User
1 | ISR(INT1_vect, ISR_NAKED) { |
2 | PORTB = 0xff; |
3 | PORTB = 0x00; |
4 | reti(); |
5 | }
|
Damit beträgt die Reaktionszeit nur noch 600ns. Leider immernoch etwas zu langsam... Aber wie ich den Reaktionen entnehmen kann, sollte ich lieber die Finger von diesem Ansatz lassen?
Patrick J. schrieb: > Dann ersetze versuchshalber > "ldi r16, 0xFF" "\n\t" > > durch > > "ldi r16, 0x00" "\n\t" Nun ist PORTB dauerhaft low
Hi Darauf wollte ich hinaus - wenn im ISR steht, daß der Port bei JEDEM Abarbeiten komplett auf HIGH oder LOW gesetzt wird, wird der Port wohl so gesetzt. Sofern das Hauptprogramm da Nichts dran ändert. Da Das das einzige Register war, was eine Information enthielt und hier wohl PortB beschrieben wurde, ging ich davon aus, daß das Port nun 'anders herum' bleibt. Wenn Du nur ein Toggel pro ISR möchtest, kannst Du PinB mit 0xFF beschreiben - Das sollte Dir alle PortB-Bits 'umdrehen'. (zumindest beim ATtiny ... vll. reicht der Verwandtschaftsgrad ja bis hier hin) MfG
fixi schrieb: > Wie es aber scheint, gibt es > (noch) keine Lösung für ein schnelleres ansprechen :( Doch, gibt es. Ein STM32F4xx schafft es schneller. Mit der richtigen Hardware geht es noch viel schneller ;-) > Später soll das Programm doch etwas umfangreicher werden. Dann sag besser schon jetzt, was später sein soll. Ein ATmega8 ist heutzutage ja nicht mehr der absolute Renner - in jeder Beziehung.
fixi schrieb: > Später soll das Programm doch etwas umfangreicher werden. Dann ist Dein Test vollkommen nutzlos. Du hast nur eine CPU und die muß auch im worst-case alles in der geplanten Zeit ausführen können. Die oben genannten ~200 Zyklen je Interrupthandler sind eine brauchbare Praxisabschätzung. Anfänger können auch deutlich mehr brauchen.
fixi schrieb: > Damit beträgt die Reaktionszeit nur noch 600ns. Leider immernoch etwas > zu langsam... Was wäre denn schnell genug? Denn schneller als 562ns geht's halt mit dem Prozessor bei dem Takt nicht. Klingt blöd, ist aber so. Oliver
fixi schrieb: > ISR(INT1_vect, ISR_NAKED) { > PORTB = 0xff; > PORTB = 0x00; > reti(); > } willst Du sowas?
1 | ISR(INT1_vect, ISR_NAKED) { |
2 | asm volatile ( |
3 | "push r16" "\n\t" |
4 | "ldi r16, 0xFF" "\n\t" |
5 | "out %0, r16" "\n\t" |
6 | :
|
7 | : "M" (_SFR_IO_ADDR (PORTB)) |
8 | );
|
9 | asm volatile ( |
10 | "ldi r16, 0x00" "\n\t" |
11 | "out %0, r16" "\n\t" |
12 | "pop r16" "\n\t" |
13 | :
|
14 | : "M" (_SFR_IO_ADDR (PORTB)) |
15 | );
|
16 | asm volatile ( "reti" ); |
17 | }
|
wird zu:
1 | PUSH R16 Push register on stack |
2 | SER R16 Set Register |
3 | OUT 0x18,R16 Out to I/O location |
4 | LDI R16,0x00 Load immediate |
5 | OUT 0x18,R16 Out to I/O location |
6 | POP R16 Pop register from stack |
7 | RETI Interrupt return |
Dorftrottel schrieb: > LDI R16,0x00 Load immediate Wenn R16 vorher 0xff ist, könnte man es auch durch INC R16 auf 0x00 bringen ;-)
m.n. schrieb: > Wenn R16 vorher 0xff ist, könnte man es auch durch INC R16 auf 0x00 > bringen ;-) Nö. Denn laut ATMEL beeinflußt die INCrementierung die Flags Z, N & V im Statusregister. Keine gute Idee in nem naked_Interrupt. ;-)
Danke für die zahlreichen Vorschläge. Ich komme mit dem testen noch nicht ganz hinterher. Das werde ich aber demnächst ausführlich machen. Eine Altnernative wäre den Atmega88a einzusetzen. Dieser kann laut Datenblatt 20MHz. Gibt es abgesehen von der höheren Frequenz evtl weitere Auswirkungen auf die Reaktionszeit?
Dorftrottel schrieb: > Keine gute Idee in nem naked_Interrupt. Und darum sollte man ISRs, deren endgültige Funktion noch nicht feststeht, nicht auf Glück programmieren. m.n. schrieb: > Transparente und schnelle ISRs programmiert man in Assembler, wo nur die > Register gerettet werden, die unbedingt gebraucht werden mit SREG an > allererster Stelle.
m.n. schrieb: > m.n. schrieb: >> Transparente und schnelle ISRs programmiert man in Assembler, wo nur die >> Register gerettet werden, die unbedingt gebraucht werden mit SREG an >> allererster Stelle. Je nun, was anderes macht der Compiler auch nicht... Oliver
Oliver S. schrieb: > Je nun, was anderes macht der Compiler auch nicht... Stimmt, der macht sogar noch viel mehr ;-) ISR(INT1_vect) { 5f0: 1f 92 push r1 5f2: 0f 92 push r0 5f4: 0f b6 in r0, 0x3f ; 63 5f6: 0f 92 push r0 5f8: 11 24 eor r1, r1 5fa: 8f 93 push r24 PORTB=0xff; 5fc: 8f ef ldi r24, 0xFF ; 255 5fe: 85 b9 out 0x05, r24 ; 5 PORTB=0x00; 600: 15 b8 out 0x05, r1 ; 5 } 602: 8f 91 pop r24 604: 0f 90 pop r0 606: 0f be out 0x3f, r0 ; 63 608: 0f 90 pop r0 60a: 1f 90 pop r1 60c: 18 95 reti
Wie schnell wäre denn die Reaktion bei aktivem Warten durch polling auf einen Spannungspegel am Pin?
Oliver S. schrieb: > Je nun, was anderes macht der Compiler auch nicht... Doch, das tut er durchaus, es sei denn, es ist ein "guter" UND man ist sehr mit seinen Eigenheiten vertraut und benutzt sie auch kompetent. Aber selbst wenn die Kenntnisse da sind und der Compiler zumindest potentiell wirklich alle wesentlichen Tricks ermöglicht, die in Asm möglich sind, stellt sich am Ende des Tages immer noch die Frage: warum zum Teufel muss man das nun unbedingt in C programmieren? Bilanz: 1. Der Einsatz von C bringt in einem solchen "engen" Szenario keinerlei Vorteile, weil's entweder garnicht geht oder zumindest die "Portabilität" als einziger nennenswerter Vorteil von C gegenüber Asm praktisch vollständig entfällt. 2. Es macht mehr Arbeit, weil man neben der allfälligen Kenntnis der Zielarchitektur und seiner Assemblersprache auch noch die konkreten Features des Compilers perfekt beherrschen muss (weit jenseits der C-Sprachstandards). Fazit: Wer in solchen Szenarien trotzdem C benutzt, hat einfach irgendwie nicht alle Latten am Zaun. Das kann nur ein eingefleischter C-Wanker sein, der nix anderes will (und nix anderes kann)...
Was um alles in der Welt soll: Out ff direkt gefolgt von Out 0 ? Liegt Deine Reaktionszeit nicht in der Größenordnung eines Oszilloskops, "siehst" Du nur 00. Inc r16 verkürzt nur die "Ein-zeit".
Sebastian S. schrieb: > Inc r16 > verkürzt nur die "Ein-zeit". Nein, nicht einmal das. Es sollte nur unbemerkt das SREG zerschiessen. fixi schrieb: > Wie schnell wäre denn die Reaktion bei aktivem Warten durch polling auf > einen Spannungspegel am Pin? Wie wäre es denn, uns einmal zu sagen, was es werden soll?
@ m.n. Es ist natürlich ein sehr seltener Sonderfall, aber die Sequenz: >PUSH R16 Push register on stack >SER R16 Set Register >OUT 0x18,R16 Out to I/O location >LDI R16,0x00 Load immediate >OUT 0x18,R16 Out to I/O location >POP R16 Pop register from stack >RETI Interrupt return lässt das Statusregister in Ruhe. Deshalb gilt: >Nein, nicht einmal das. Es sollte nur unbemerkt das SREG zerschiessen. nicht.
Sebastian S. schrieb: > Es ist natürlich ein sehr seltener Sonderfall, aber die Sequenz: Soll ich jetzt noch meine Scherze erklären?
Ist die Reaktion beim aktiven Warten durch polling auf ein High signal am Pin schneller als bei einem externen Interrupt?
Du verschweigst auch auf diverse Nachfragen beharrlich Deine genauen Anforderungen. Da hat man doch keine Lust mehr, auf nachgelegte Fragen zu antworten.
Die Anforderung ist ganz klar eine möglichst schnelle Reaktion eines Ausgangs auf ein Eingangssignal :) Alles andere würde nur zu Abschweifungen führen.
fixi schrieb: > Ist die Reaktion beim aktiven Warten durch polling auf ein High signal > am Pin schneller als bei einem externen Interrupt? Wie wäre es denn wenn du so einen einfachen Sachverhalt einfach schnell selbst duch Eigeninitiative in der Praxis klärst. Die Voraussetzungen dazu hast du ja offensichtlich: fixi schrieb: > An meinem atmega8 löse ich einen externen interrupt aus. In der ISR wird > lediglich ein Ausgang auf high gesetzt (1 Zeile Code). Die Reaktionszeit > beträgt bei 16MHz ca 1,25 Mikrosekunden. Andererseit drängst sich bei solchen Fragen und Handlungs- zusammenhängen deinerseits der Verdacht auf dass hier im Thread etwas gefaked wird, oder getrollt.
Arduinoquäler schrieb: > Andererseit drängst sich bei solchen Fragen und Handlungs- > zusammenhängen deinerseits der Verdacht auf dass hier im Thread > etwas gefaked wird, oder getrollt. Ich hab ja sonst nichts zu tun... Es ist doch ganz einfach. Ich habe kaum Zeit um das auszutesten und will einfach nur wissen wie die Erfolgsaussichten sind, bevor ich damit anfange. Darum wende ich mich hier an das Forum. Und genau das ist doch Sinn und Zweck eines Forums. Es ist doch eine ganz einfach Frage. Entweder man weiß die Antwort und hilft, oder man lässt es eben sein. Aussagen wie "such doch selbst" oder "teste es doch" sind hier das eigentliche rumgetrolle.
fixi schrieb: > Es ist doch ganz einfach. Ich habe kaum Zeit um das auszutesten und will > einfach nur wissen wie die Erfolgsaussichten sind, bevor ich damit > anfange. Verstehe. Bei solch einem aufwendigen, umfangreichen Test muss man sich schon gut überlegen ob, wie und wann man diesen Aufwand treibt. Ich veranschlage mal ca vier Wochen Arbeit a 50 Stunden für das Schreiben von 10 Zeilen Code, das Hochladen auf den Controller und das Anschliessen eines Oszilloskops. Betrachten und Analysieren des Ergebnisses noch nicht einbezogen. Alternativ dazu drei Wochen Arbeit für das Schreiben von 10 Zeilen Code und das analysieren des compilierten C-Codes auf Assembler-Ebene.
fixi schrieb: > Die Anforderung ist ganz klar eine möglichst schnelle Reaktion eines > Ausgangs auf ein Eingangssignal Wenn das alle Anforderungen sind, dann ist Dein Ansatz falsch. Dieses Verhalten kannst Du mit einem Timer-Eingang und seinem OCR-Ausgang lösen. Dazu ist keine CPU-Interaktion erforderlich.
Grundsätzlich würde ich erst mal auf: ISR(INT1_vect, ISR_NAKED) { PORTB = ~PORTB; reti(); } Umsteigen. Wie bereits gesagt natürlich nur, wenn Deine Reaktionszeit unter der eines Oszilloskops liegt;-) Wie es mit den minimal möglichen Zeiten aussieht wurde bereits gesagt: "Unterbrechung erkennen" Automatisch, abhängig vom Zeitpunkt und gerade aktuellem Befehl Variabel PUSH PC Automatisch Fixzeit Load Interruptvector -> PC Automatisch Fixzeit PUSH Work Dein Ding PUSH Fixzeit MOV Dein Ding Hole Status Fixzeit PUSH Status Dein Ding PUSH Fixzeit „Hau rein“ Dein Ding akt. Status holen 1) Fixzeit Dein Ding invertieren und 2) Fixzeit Dein Ding zurückschreiben 3) Fixzeit POP Status Dein Ding POP Fixzeit MOV Status Dein Ding Fixzeit POP Work Dein Ding POP Fixzeit POP PC Dein Ding Indirekt durch IRET Fixzeit In diesem Falle muss auch das Statusregister gesichert werden, da der Befehl: COM wahrscheinlich den Status ändert. Besondere Wünsche sehen weder der Compiler noch die Befehlsliste vor.
fixi schrieb: > Die Anforderung ist ganz klar eine möglichst schnelle Reaktion eines > Ausgangs auf ein Eingangssignal :) Wie wäre es, einen Draht vom Eingang zum Ausgang zu löten. Schneller gehts dann nicht mehr.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.