Forum: Compiler & IDEs Inline-Assembler Delay


von M. F. (sajuuk)


Lesenswert?

Ich würde gern in Assembler ein delay schreiben.
Leider bekomme ich beim compilieren immer eine Fehlermeldung.

Fehlermeldung:
Compiling C: lcd.c
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=8000000UL -O0
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=./lcd.lst  -std=gnu99 -Wundef -MMD -MP
-MF .dep/lcd.o.d lcd.c -o lcd.o
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s: Assembler messages:
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s:38: Error: garbage at end
of line
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s:39: Error: garbage at end
of line
make.exe: *** [lcd.o] Error 1

Als Compiler benutze ich AVR-GCC.
Ich hoffe jemand kann mir weiter helfen. Danke schonmal.

Code:
void __waitXus(u16 time) {
  register u16 __time = time;

  asm volatile (
    "ldi R25,HIGH(%B[waitTime]); \n\t"
    "ldi R24,LOW(%A[waitTime]);  \n\t"
    "Loop:                       \n\t"
    "sbiw R24,1;                 \n\t"
    "brne Loop;                  \n\t"
  :
  :[waitTime] "r" (__time)
  );
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Das haben andere schon vor dir getan.  Sieh dir <util/delay_basic.h>
mal an.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Btw.: der "garbage" da sind die Semikolons, denke ich.  Die verwendung
eines nicht-lokalen labels innerhalb einer inline-asm-Anweisung ist
aber wenig zweckmäßig, und das Überbügeln von r24/25 ist so nicht
akzeptabel.

von M. F. (sajuuk)


Lesenswert?

Danke. deine Info hat mir sehr weiter geholfen.

Mfg Faid

von Stefan E. (sternst)


Lesenswert?

Davon abgesehen, wie soll es möglich sein, per ldi einen variablen Wert 
in die Register zu laden?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Davon abgesehen, wie soll es möglich sein, per ldi einen variablen Wert
> in die Register zu laden?

;-)

Es gibt bei genauerem Hinsehen noch mehr Enten:

. ldi erwartet einen immediate value, aber der constraint gibt
  ein Register vor

. das Schlüsselwort "register" ist Unsinn; es ist ohnehin das
  constraint, das dem Compiler mitteilt, in welcher Form __temp
  implementiert werden muss

. __temp ist ein reservierter Bezeichner, der in einem Nutzerprogramm
  nichts zu suchen hat

. das separate Anlegen der Variablen __temp ist gar nicht nötig, man
  kann gleich den Parameter temp benutzen

. man braucht eigentlich das Registerpaar auch gar nicht im inline
  asm zu laden, sondern kann das komplett dem Compiler über die
  constraints aufdrängeln

Das nur der Vollständigkeit halber, falls jemand noch den Thread
später liest.  Hatte vorhin halt nicht so genau hingeschaut.

von Stefan E. (sternst)


Lesenswert?

Jörg Wunsch schrieb:

> Das nur der Vollständigkeit halber, falls jemand noch den Thread
> später liest.

Ok, dann noch als Ergänzung etwas konkreten Code zu den gemachten 
Einwendungen ;-)
1
void waitXus (uint16_t time) {
2
3
  asm volatile (
4
    "0:                       \n\t"
5
    "sbiw %[waitTime],1       \n\t"
6
    "brne 0b                  \n\t"
7
  :
8
  :[waitTime] "w" (time)
9
  );
10
}

Und als weitere Ergänzung: Die Semikolons sind natürlich nicht der 
"garbage" (die machen ja nur den Rest der Zeile zum Kommentar). Es sind 
diese unsinnigen "HIGH(%B[waitTime])" Konstruktionen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Jörg Wunsch schrieb:
>
>> Das nur der Vollständigkeit halber, falls jemand noch den Thread
>> später liest.
>
> Ok, dann noch als Ergänzung etwas konkreten Code zu den gemachten
> Einwendungen ;-)

Noch ein Einwand: time wird verändert. Falls waitXus einmal als static 
oder inline-Funktion (sehr sinnvoll, also im Header als static inline) 
definiert wird, crasht es früher oder später.

Daher:
1
#include <stdint.h>
2
3
static inline void 
4
waitXus (uint16_t time) 
5
{
6
   __asm__ __volatile__ (
7
     "0: sbiw %[waitTime], 1"     "\n\t"
8
     "brne 0b"
9
       : [waitTime] "+w" (time));
10
}

Das Label hab ich in die gleiche Zeile geschrieben, weil gcc 4 die 
Anzahl der Instruktionen anhand der Zeilen im Inline Asm abschätzt (für 
relative Sprünge darüber).

Johann

von onkelhotte (Gast)


Lesenswert?

Die Funktion soll ja eigentlich x Mikrosekunden warten. Allerdings muss 
dafür ja der CPU-Takt berücksichtigt werden, oder? Wenn ich richtig 
liege, dann benötigt die Abarbeitung der Inline-Funktion 4*time Takte. 
Mikrosekunden sind es also nur bei 4MHz CPU-Takt, oder habe ich da was 
missverstanden?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Lohnt es sich wirklich, dafür die Threadleiche zu exhumieren?

Der Parameter "time" hat ja dort keine Maßeinheit.  Hat also niemand
behauptet, dass es sich um Mikrosekunden handeln würde.

Ja, um mit Absolutzeiten zu arbeiten, muss man mit der CPU-Frequenz
umrechnen.  Dann bist du genau bei den Funktionen aus <util/delay.h>.

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.