mikrocontroller.net

Forum: Compiler & IDEs Inline Asm


Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, ich habe folgenden Code, um in einer Interruptroutine Port D
einzulesen:
unsigned char volatile G_cLastData = 0xAA;

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 bringt mir der Compiler folgende Meldung:
[quote]
../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

[/quote]

Zeile 143 ist:
: "i" (&G_cLastData) 

Kann mir jemand sagen, woher diese Meldung kommt, bzw. wie ich sie weg
bekomme?

Ps:
Für diejenigen, die bei Roboternetz mitlesen, tut mir leid für den
Doppelpost, aber es ist sehr wichtig!

Freundlichen Gruss
Michael

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir scheint die leere Liste von Ausgangsoperanden falsch zu sein. Das i
(&G_cLastData) ist glaub ich auch kein  korrekter Eintrag für die
clobber-Liste. Es scheint alles um eins verschoben zu sein. Mach mal
den ersten Doppelpunkt weg.

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, danke für deine Antwort.
Ich habe jetzt folgendes ausprobiert:
void  __attribute__ ((naked)) SIG_INTERRUPT0 (void){
   __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) 
    );
}
liefert:
[quote]
../Treiber_Parallel.c: In function `__vector_1':
../Treiber_Parallel.c:200: error: invalid lvalue in asm statement
../Treiber_Parallel.c:192: error: output operand constraint lacks `='
C:\AVR\WinAVR\utils\bin\make.exe: *** [Treiber_Parallel.o] Error
1
[/quote]

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich das mit der clobber-Liste richtig verstanden habe teilt diese
doch dem Compiler nur mit, welche Werte sich geändert haben, oder?

Und da ich das Speichern in G_cLastData ja bereits im Asm Code mache,
muss ich als Output nichts angeben?! Ansonsten hätte ich mir das
"sts     %2, r2"      "\n\t" 

sparen können, oder?

Gruss
Michael

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Asm-Code hierzu, wie ich meine dass es ohne Clobber gehört:
void  __attribute__ ((naked)) SIG_INTERRUPT0 (void){
   __asm__ __volatile( 
       "in %0,%1"        "\n\t"
       "reti"
             : "=&r" (G_cLastData) 
             : "I" (_SFR_IO_ADDR(PORTD))
    );
}

wäre
     d5a:  82 b3         in  r24, 0x12  ; 18
     d5c:  18 95         reti
     d5e:  80 93 79 00   sts  0x0079, r24
     d62:  80 91 79 00   lds  r24, 0x0079

allerdings wird hier das R24 verwendet, welches ja vorher nicht
gesichert wird!

Gruss
Michael

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Frage:
Ist groß 'I' eigentlich das Gleiche wie klein 'i'?
Sprich ist das Ganze case sensitiv?

Gruss
Michael

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hatte nicht genau genug hingesehen. Also, du liest aus dem
IO-Register und schreibst in den Speicher. Dann ist _SFR_IO_ADDR(PORTD)
ein Input-Parameter.
Was ist "i" eigentlich für ein Operandentyp? Den kann ich in der
avr-libc-Doku nicht finden. Vielleicht ist das der Fehler?

> Wenn ich das mit der clobber-Liste richtig verstanden habe teilt
> diese doch dem Compiler nur mit, welche Werte sich geändert haben,
> oder?

Ja. Du teilst damit dem Compiler mit, daß deine asm-Routine intern z.B.
mit einem Register arbeitet, das weder input- noch output-Parameter ist
und das von der Routine in geändertem Zustand hinterlassen wird.
Dadurch weiß der Compiler dann, daß er - wenn er den Wert nicht
verlieren darf - diesen sichern muß.

Wegen der Variablen, auf die zugegriffen wird, müßte es eigentlich
reichen, wenn diese als volatile deklariert ist. Als clobber muß man
sie dann nicht mehr angeben.
Ich weiß nur nicht, wie bzw. ob du dieses Adresse als Operand angeben
kannst. Wenn G_cLastData keine globale Variable ist, geht's so eh
nicht, da die Adresse dann erst zur Laufzeit bekannt ist. Bei einer
globalen Variable sehe ich aber das Problem, daß der Compiler die
Adresse noch nicht kennt, da sie erst vom Linker festgelegt wird.
Die avr-libc-Doku schweigt sich leider dazu aus.

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das ganze ist wirklich nicht sonderlich gut dokumentiert.
Ja ich lese PortD ein, und will es in eine globale Variable G_cLastData
schreiben.

Das Problem scheint nur zu sein, dass meine Funktion naked ist. Wenn
ich also im Asm-Teil das Output benutze, habe ich danach keine
Möglichkeit mehr was zu tun, auchnicht das reti!

Gruss
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreib das Teil in eine separate Datei und dort komplett in
Assembler, statt derartige Verrenkungen zu machen.

#include <avr/io.h>

.global SIG_INTERRUPT0
SIG_INTERRUPT0:
  push  r2
  in  r2, _SFR_IO_ADDR(PORTD)
  sts  G_cLastData, r2
  pop  r2
  reti

Das Ganze kommt in eine Datei isr.S (per Konvention ein großes S am
Ende) und wird beim Standard-WinAVR-Makefile unter ASRC angegeben.

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, gute Idee.
Habs gleich ausprobiert und einen Eintrag ASRC = isr.S in meinem
Makefile erzeugt.

Leider bekomme ich dann folgende Meldung:
C:\AVR\WinAVR\utils\bin\make.exe: *** No rule to make target
`isr.o', needed by `AppMain.elf'.  Stop.

Hast du eine Ahnung woran das liegt?

Grüsse
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hast du eine Ahnung woran das liegt?

An deinem Makefile.

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss amn da noch an anderer Stelle etwas mitteilen? Ausser ASRC...

Gruss
Michael

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, offenbar fehlt ihm irgendwie die Regel, wie man aus einer
.S-Datei eine .o-Datei erzeugt.  Er erkennt ja noch, dass er
die zugehörige .o-Datei braucht, aber es fehlen die Kommandos,
sie zu bauen.

# Assemble: create object files from assembler source files.
%.o : %.S
  @echo
  @echo $(MSG_ASSEMBLING) $<
  $(CC) -c $(ALL_ASFLAGS) $< -o $@

Sowas steht in Eric Weddington's Makefile-Template herum, ist
GNU-make
Syntax.  Generische make-Syntax wäre:

# Assemble: create object files from assembler source files.
.S.o:
  $(CC) -c $(ALL_ASFLAGS) $< -o $@

Nur so, mit Groß-/Kleinschreibung hast du dich aber nicht
vertan?  Wenn die Datei Isrs.S heißt, wird das make sie nicht
finden, wenn es isrs.o bauen soll.

Autor: Michael S (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So etwas ähnliches ist mit drin.
Habe mein Makefile mal mit angehängt.
Die Datei auf der Platte heisst isr.S, genauso wie im Makefile..

Gruss
Michael

Autor: Michael S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm lag wohl daran, dass ich ExtCoff erzeugt habe. Hab mal ein Makefile
erstellt, in dem ich nur Coff erzeuge, und dann gehts.

Danke für die Hilfe
Gruss
Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.