-         

Seite 1 von 4 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 35

Thema: Sammel-Interrupt mit avr-gcc

  1. #1
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801

    Sammel-Interrupt mit avr-gcc

    Anzeige

    Hallo,

    ich würde gerne mit avr-gcc einen Sammel-Interrupt machen, und zwar für zwei ISRs. Der Code ist praktisch der gleiche, so daß ich den Codevarbrauch an der Stelle gerne halbieren würde.

    Ich hab zwar eine Lösung, aber das ist HACK, ich trau mich garnicht, das hier zu posten.

    Probleme:
    1. AVR setzt das jeweilige Flag beim Auslösen der IRQ zurück, ich kann's also nicht testen
    2. Funktionen stehen im asm möglicherweise in anderer Reihenfolge als in der C-Quelle
    3. In den umzubiegenden ISRs dürfen weder Register verwendet werden, noch das SREG verändert werden (oder man braucht nen ISR-Prolog, und die Codeersparnis ist futsch).

    Jemand ne zündende Idee?
    Disclaimer: none. Sue me.

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    Warum nicht einfach aus der ISR jeweils dieselbe Funktion aufrufen:

    Code:
    SIGNAL( SIG_INTERRUPT0 )
    {
    	serveISR();
    }
    
    SIGNAL( SIG_INTERRUPT1 )
    {
    	serveISR();
    }
    
    void serveISR()
    {
    }
    Unterm Strich sorgt das Makro SIGNAL nur dafür, dass ein entsprechendes GCC __attribute(signal) hinter die Funktionsdefinition gesetzt wird, was den Compiler anweist, die Adresse der Funktion in der Interruptvektortabelle zu hinterlegen. Das einizige, was hier hinzu kommt, ist ein weiterer Funktionsaufruf.

  3. #3
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Es kommt noch mehr dazu. Ein ISR-Prolog/Epilog ist wesentlich länger, als ein normaler Funktions-Prolog, zumal wenn in der ISR eine Funktion aufgerufen wird.

    Ursprünglich geplant war so was:
    Code:
    void __attribute__ ((naked))
    SIG_INTERRUPT0()
    {
       // fallthru
    }
    
    SIGNAL (SIG_INTERRUPT1)
    {
       // serve ISR
    }
    Aber in INT1 sehe ich nicht, ob ich von 0 oder von 1 komme. Ich hatte geplant, das USR-Bit zu verwenden, aber das geht auch nicht, weil die ISRs selbst in einer ISR "scharf gemacht werden", und im Epilog natürlich wieder das SREG hergestellt wird.
    Disclaimer: none. Sue me.

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    Ich fürchte, dass ich's noch nicht ganz verstanden habe.

    Sobald Du in C eine SIGNAL Routine schreibst, wird das SREG gerettet und am Ende der Routine wieder restauriert. Es gehen aber keine Interrupts verloren. Es sei denn, Deine ISR dauert so lange, dass mehrer Interrupts auf ein und derselben Quelle angekommen.

    Wenn Du aus den ISRs jeweils diesselbe Funktion aufrufst verschenkst Du praktisch nur zwei Byte Flash für den Sprungbefehlt, die Dir der Optimizer vielleicht sogar wieder gibt.

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Nicht ganz, das SREG (oder was auch immer) wird nur gerettet, wenn ich der ISR einen Pro/Epilog gebe, was ich aber mit naked verhindern kann.

    Zunächst mal eine minimal-ISR, die nix macht:
    Code:
    SIGNAL (SIG_INTERRUPT1)
    {
    }
    
    00000060 <__vector_2>:
      60:	1f 92       	push	r1
      62:	0f 92       	push	r0
      64:	0f b6       	in	r0, 0x3f	; 63
      66:	0f 92       	push	r0
      68:	11 24       	eor	r1, r1
      6a:	0f 90       	pop	r0
      6c:	0f be       	out	0x3f, r0	; 63
      6e:	0f 90       	pop	r0
      70:	1f 90       	pop	r1
      72:	18 95       	reti
    Dann eine ISR, die nix macht, ausser eine parameterlose Func zu rufen:
    Code:
    SIGNAL (SIG_INTERRUPT1)
    {
    	foo();
    }
    
    00000060 <__vector_2>:
      60:	1f 92       	push	r1
      62:	0f 92       	push	r0
      64:	0f b6       	in	r0, 0x3f	; 63
      66:	0f 92       	push	r0
      68:	11 24       	eor	r1, r1
      6a:	2f 93       	push	r18
      6c:	3f 93       	push	r19
      6e:	4f 93       	push	r20
      70:	5f 93       	push	r21
      72:	6f 93       	push	r22
      74:	7f 93       	push	r23
      76:	8f 93       	push	r24
      78:	9f 93       	push	r25
      7a:	af 93       	push	r26
      7c:	bf 93       	push	r27
      7e:	ef 93       	push	r30
      80:	ff 93       	push	r31
      82:	ec df       	rcall	.-40     	; 0x5c
      84:	ff 91       	pop	r31
      86:	ef 91       	pop	r30
      88:	bf 91       	pop	r27
      8a:	af 91       	pop	r26
      8c:	9f 91       	pop	r25
      8e:	8f 91       	pop	r24
      90:	7f 91       	pop	r23
      92:	6f 91       	pop	r22
      94:	5f 91       	pop	r21
      96:	4f 91       	pop	r20
      98:	3f 91       	pop	r19
      9a:	2f 91       	pop	r18
      9c:	0f 90       	pop	r0
      9e:	0f be       	out	0x3f, r0	; 63
      a0:	0f 90       	pop	r0
      a2:	1f 90       	pop	r1
      a4:	18 95       	reti
    Der Rahmen ist deutlich fetter, und da sind noch keine Werte übergeben. Ausserdem wird das in jeder ISR wiederholt, die foo() aufruft.

    Was ich gerne hätte, wäre so was:
    Code:
    0000005e <__vector_1>:
      5e:	00 c0       	rjmp	.+0      	; 0x60
    
    00000060 <__vector_2>:
      60:	1f 92       	push	r1
      62:	0f 92       	push	r0
      64:	0f b6       	in	r0, 0x3f	; 63
      66:	0f 92       	push	r0
      68:	11 24       	eor	r1, r1
      6a:	0f 90       	pop	r0
      6c:	0f be       	out	0x3f, r0	; 63
      6e:	0f 90       	pop	r0
      70:	1f 90       	pop	r1
      72:	18 95       	reti

    was etwa durch die naked-Sequenz erzeugt wird
    Code:
    void __attribute__ ((naked))
    SIG_INTERRUPT0()
    {
       asm volatile ("rjmp __vector_2");
    }
    
    SIGNAL (SIG_INTERRUPT1)
    {
    }
    Was fehlt, ist die Unterscheidung, ob ich von INT0 komme oder von INT1...

    Für den Eintrag in die Vektortabelle ist übrigens nicht das signal- oder interrupt-Attribut verantwortlich, sondern alleine der spezielle Name der Funktion __vector_n, die dem Linker bekannt ist (der Linker weiss eh nix von Attributen). Wenn du also ne Funktion schreibst
    Code:
    void __vector_10()
    {}
    dann wird ein Eintrag in die VecTab gemacht!
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    Oh, wieder was gelernt!

    Warum dann nicht einfach in __vector_10 und __vector11 die Funktion foo( paramVonWoIchKomme) aufrufen?

    Code:
    __vector_10( void )
    {
        foo( 10 );
    }
    
    __vector_11( void )
    {
        foo( 11 );
    }

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    *AUTSCH* dann schmiert's ab, weil die ISRs keinen passenden Rahmen haben und nicht mit reti verlassen werden. Nur ein Eintrag in die VecTab reicht nicht, um eine Funktion zur ISR zu machen:
    Code:
    00000074 <__vector_10>:
      74:	8a e0       	ldi	r24, 0x0A	; 10
      76:	90 e0       	ldi	r25, 0x00	; 0
      78:	f1 df       	rcall	.-30     	; 0x5c
      7a:	08 95       	ret
    
    0000007c <__vector_11>:
      7c:	8b e0       	ldi	r24, 0x0B	; 11
      7e:	90 e0       	ldi	r25, 0x00	; 0
      80:	ed df       	rcall	.-38     	; 0x5c
      82:	08 95       	ret
    Der Zusatzaufwand bei Aufruf von foo (natürlich verpackt in ISR-Rahmen) ist schon fast mehr, als foo selber lang ist! Und foo als inline machen bringt auch nix, dann könnte ich die ISRs auch normal machen, und einfach alles austexten (austexten/inline wiederholt ja auch den Code n mal) würde also auch nix sparen
    Disclaimer: none. Sue me.

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    Kürzer als das folgende bekomme ich es nicht hin:

    Code:
    #include <avr/signal.h>
    #include <avr/interrupt.h>
    #include <inttypes.h>
    
    void foo( uint8_t param );
    
    // key press down
    SIGNAL( SIG_INTERRUPT0 )
    {
    	foo( 0 );
    }
    
    
    void _VECTOR(2)( void )  __attribute__ ((naked));
    void _VECTOR(2)( void )
    {
    	foo(3);
    	 __asm__ __volatile__ ("reti" ::);
    }
    
    void foo( uint8_t param )
    {
    }
    Aus Vector(2) wird dann
    Code:
    /* function __vector_1 size 43 (3) */
    .LFE3:
    	.size	__vector_1, .-__vector_1
    .global	__vector_2
    	.type	__vector_2, @function
    __vector_2:
    .LFB4:
    .LM3:
    /* prologue: frame size=0 */
    /* prologue: naked */
    /* prologue end (size=0) */
    .LM4:
    	ldi r24,lo8(3)
    	call foo
    .LM5:
    /* #APP */
    	reti
    Das Retten und Restaurieren von SREG muss dann von Hand rein.

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Und was ist mit R24?
    Disclaimer: none. Sue me.

  10. #10
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    Da steht der Übergabeparameter an foo(3) drin. Das optimiert der Compiler so (ist so auch der kleinste Code). Ansonsten wäre das ja
    Code:
    ldi r24, lo(3) 
    push r24; das kann wegoptimiert werden
    GCC nutzt aber einige Register stets zur Parameterübergabe (bei eingeschalteter Optimierung).

Seite 1 von 4 123 ... LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •