- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 4 von 4

Thema: Inline Asm Rückgabe

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    17.01.2004
    Ort
    Erlangen, Bayern
    Alter
    42
    Beiträge
    253

    Inline Asm Rückgabe

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hi,
    muss in einer c-Funktion aus Zeitgründen Asm verwenden. Bisher musste ich hierfür allerdings noch nie einen Wert zurückgeben.

    Problem:
    Ich muss in einer Interruptroutine so schnell wie möglich Port D lesen.
    Ich habe hierfür folgende Routine erstellt:
    Code:
    volatile unsigned char G_cLastData = 0xAA;
    
    EXTINT_INTERRUPT_HANDLER(SIG_INTERRUPT0){
        asm volatile(
    		"IN		%0, %1"	"\n\t"
    		: "=r" (G_cLastData)			//Output
    		: "I"  (_SFR_IO_ADDR(PORTD))	//Input
    	);
    }
    Das produziert folgenden Asm Code
    Code:
    EXTINT_INTERRUPT_HANDLER(SIG_INTERRUPT0){
         d70:	1f 92       	push	r1
         d72:	0f 92       	push	r0
         d74:	0f b6       	in	r0, 0x3f	; 63
         d76:	0f 92       	push	r0
         d78:	11 24       	eor	r1, r1
         d7a:	8f 93       	push	r24
         d7c:	cf 93       	push	r28
         d7e:	df 93       	push	r29
         d80:	cd b7       	in	r28, 0x3d	; 61
         d82:	de b7       	in	r29, 0x3e	; 62
        asm volatile(
         d84:	82 b3       	in	r24, 0x12	; 18
         d86:	80 93 79 00 	sts	0x0079, r24
         d8a:	80 91 79 00 	lds	r24, 0x0079
         d8e:	df 91       	pop	r29
         d90:	cf 91       	pop	r28
         d92:	8f 91       	pop	r24
         d94:	0f 90       	pop	r0
         d96:	0f be       	out	0x3f, r0	; 63
         d98:	0f 90       	pop	r0
         d9a:	1f 90       	pop	r1
         d9c:	18 95       	reti

    Meine Fragen nun:
    -Funktioniert das so?
    -Wie kann ich dem Compiler sagen, dass er mir den Stack vorher nicht aufräumen muss, da im Code die Register nicht verwendet werden?


    Gruss
    Michael

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Du machst eine naked Funktion, siehe auch das Beispiel bei GCC im Abschnitt Interrupts.

    Code:
    #include <avr/io.h>
    
    uint8_t register G_cLastData asm ("r2");
    
    void __attribute__ ((naked)) 
    SIG_INTERRUPT0 (void)
    {
      // Port D
       __asm__ __volatile (
          "in r2, %0" "\n\t"
          "reti"
             : 
             : "M" (_SFR_IO_ADDR (PORTD))
       );
    }
    GCC macht daraus:
    Code:
    .global	__vector_1
    	.type	__vector_1, @function
    __vector_1:
    	in r2, 24
    	reti

    Wichtig ist, daß in ALLEN deinen Modulen R2 so als Register deklariert ist, damit GCC nicht auf die Idee kommt, nach R2 Werte zu allokieren. Das gilt auch für Module, die G_cLastData nicht verwenden!

    Oder du must anfangen, zu sichern mit push/pop:

    Code:
    #include <avr/io.h>
    
    uint8_t volatile G_cLastData;
    
    void __attribute__ ((naked)) 
    SIG_INTERRUPT0 (void)
    {
      // Port D
       __asm__ __volatile (
          "push r2"   "\n\t"
          "in r2, %1" "\n\t"
          "sts %2, r2" "\n\t"
          "pop r2" "\n\t"
          "reti"
             : 
             : "M" (_SFR_IO_ADDR (PORTD)) : "i" (&G_cLastData)
       );
    }
    Das führt zu
    Code:
    .global	__vector_1
    	.type	__vector_1, @function
    __vector_1:
    	push r2
    	in r2, 18
    	sts G_cLastData, r2
    	pop r2
    	reti
    Wichtig ist, daß dabei keine Instruktion den Status ändert (SREG). Daß R2 verwendet wird, braucht GCC nicht zu interessieren. Falls man GCC die Register-Allokierung überlässt, weiß man nicht, wofür er sich entscheidet. Und da GCC kein Epilog machen soll (naked), geht das auch gar nicht, weil das Register nicht wieder hergestellt werden könnte. Daher wird auch das Speichern in die Variable im Asm gemacht.

    Zu den Zeiten der ISR-Befehlen muss noch die Interrupt-Respond-Zeit hinzugezählt werden (IRQ-Latenz) und die Zeit für den Sprung aus der Vektor-Tabelle, sie ist also davon abhängig, welche IRQs sonst noch aktiv sind und wie deren ISRs aussehen.
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    17.01.2004
    Ort
    Erlangen, Bayern
    Alter
    42
    Beiträge
    253
    Hi, danke für deine Kompetente Hilfe.
    Ich habe nun folgendes in meinen Code eingefügt:
    Code:
    void __attribute__ ((naked)) SIG_INTERRUPT0 (void) { 
      // Port D einlesen
       __asm__ __volatile( 
          "push 	r2"   			"\n\t" 
          "in 		r2, %1" 		"\n\t" 
          "sts 		%2, r2" 		"\n\t" 
          "pop 		r2" 			"\n\t" 
          "reti" 
          : 
          : "M" (_SFR_IO_ADDR(PORTD)) 
          : "i" (&G_cLastData) 
       ); 
    }
    Leider liefert mir der Compiler die Fehlermeldung
    ../Treiber_Parallel.c: In function `__vector_1':
    ../Treiber_Parallel.c:143: error: parse error before '(' token
    C:\AVR\WinAVR\utils\bin\make.exe: *** [Treiber_Parallel.o] Error 1
    Zeile 143 ist die Zeile:
    Code:
          : "i" (&G_cLastData)
    Hast du eine Ahnung, woran das liegen könnte?

    Gruss
    Michael

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    17.01.2004
    Ort
    Erlangen, Bayern
    Alter
    42
    Beiträge
    253
    Habe mir noch das Totorial von der avrlibc zum Thema inline durchgelesen, werde allerdings trotzdem nicht schlau daraus, was falsch sein könnte.

    Grüsse
    Michael

Berechtigungen

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

Solar Speicher und Akkus Tests