Forum: Compiler & IDEs Inline Assembler übersetztung


von R. B. (p1ng)


Angehängte Dateien:

Lesenswert?

Hi Leuti ich hab mal wieder ein echtes Problem ich hab ein C programm 
was nicht funktionieren will, weis auch warum find aber keine lösung in 
Assembler funktioniert das Programm. Jetzt will ich das Stück halt in 
Inline Assembler schreiben leider komm ich da absolut nicht klar. kann 
mir einer das mal schnell Übersetzte wär das möglich wäre super.

Quellcode:

EEWrite:
  out  EEARH,adressH  ;Output address
  out  EEARL,adressL  ;Output adress
  out  EEDR,data    ;Output data
  sbi  EECR,2      ;set EEPROM Write EnabLED
  sbi  EECR,1      ;set EEPROM Write EnabLED
waitEEW:
  sbic  EECR,1    ;wait for Handshake
  rjmp  waitEEW
  ret

und das in Inline-Assembler wäre echt klasse.

Gruß Renaldo

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dein bisheriger C-Code
1
void EEPROM_write(unsigned int uiAddress, unsigned char data)
2
{
3
  while(EECR & (1<<EEWE));
4
  EEAR = uiAddress;
5
  EEDR = ucData;
6
  EECR |= (1<<EEMWE);
7
  EECR |= (1<<EEWE);
8
}

entspricht nicht dem funktionierenden Assembler-Code
1
EEWrite:
2
  out  EEARH,adressH  ;Output address
3
  out  EEARL,adressL  ;Output adress
4
  out  EEDR,data    ;Output data
5
  sbi  EECR,2      ;set EEPROM Write EnabLED
6
  sbi  EECR,1      ;set EEPROM Write EnabLED
7
waitEEW:
8
  sbic  EECR,1    ;wait for Handshake
9
; Teste Bit 1 von EECR und überspringe nächste Anweisung,
10
; wenn Bit 1 gleich 0 ist
11
; if ((EECR & (1<<EEWE)))
12
  rjmp  waitEEW
13
; else // (EECR & (1<<EEWE)) == 0
14
  ret

Ein C-Code entsprechend dem Assembler-Abschnitt würde sp aussehen
1
void EEPROM_write(unsigned int uiAddress, unsigned char data)
2
{
3
  EEARH = uiAddress >> 8;     // siehe #)
4
  EEARL = uiAddress & 0x00FF; // siehe #)
5
  EEDR = ucData;
6
  EECR |= (1<<EEMWE);      // EEMWE == 2 lt. avr/iom8.h
7
  EECR |= (1<<EEWE);       // EEWE  == 1
8
  while(EECR & (1<<EEWE));
9
}

#) Das ist wahrscheinlich zuviel des Guten und EEAR = uiAddress; geht 
auch
http://www.mikrocontroller.net/articles/AVR_Checkliste#16bit-Register_in_richtiger_Reihenfolge_geladen.2Fgelesen.3F_.28Nur_in_Assembler_relevant.29

von R. B. (p1ng)


Lesenswert?

danke aber fuktioniert so auch nicht,

Naja will das ja nicht direct in Assembler in Inline-Assembler haben um 
dies zu testen weist.

von Jörg X. (Gast)


Lesenswert?

1
void EEPROM_write(unsigned int addr, unsigned char value)
2
{
3
    eeprom_write_byte((uint8_t *) addr, value);
4
}
Ginge es so ? :O)
(<avr/eeprom.h> includen...)

hth. Jörg

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


Lesenswert?

Das Problem mit dem C-Code ist, dass er das Timing nicht einhält, wenn
er nicht mit Optmimierung compiliert wird.  Aber genau dafür gibt es
ja auch <avr/eeprom.h>.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Renaldo B. wrote:
> danke aber fuktioniert so auch nicht,
>
> Naja will das ja nicht direct in Assembler in Inline-Assembler haben um
> dies zu testen weist.

Dann hast du einen anderen Bug im Programm.

Dein Assembler-Code weicht übrigens stark von dem Verfahren ab, welches 
Atmel in Datenblatt als Referenzcode angibt.

Der Vollstänigkeit halber eine 1:1 Übersetzung in Inline-ASM für C
1
#include "avr/io.h"
2
3
#define TEST
4
5
void __attribute__ ((noinline)) EEPROM_write(unsigned int uiAddress, unsigned char data)
6
{
7
  asm volatile (
8
    "out  %0+1,%B3"    "\n"
9
    "out  %0,%A3"      "\n"
10
    "out  %1,%4"       "\n"
11
    "sbi  %2,2"        "\n"
12
    "sbi  %2,1"        "\n"
13
    "waitEEW:"               "\n"
14
    "sbic  %2,1"       "\n"
15
    "rjmp  waitEEW"         "\n"
16
    "ret; Problematisch bei Inline-Optimierung!"
17
      :
18
      :
19
      "M" (_SFR_IO_ADDR(EEAR)),
20
      "M" (_SFR_IO_ADDR(EEDR)),
21
      "M" (_SFR_IO_ADDR(EECR)),
22
      "r" (uiAddress),
23
      "r" (data)
24
    );
25
}
26
27
#ifdef TEST
28
int main(void)
29
{
30
    EEPROM_write(0x5678, 0x12);
31
    while(1)
32
        ;
33
34
    return 0;
35
}
36
#endif /* TEST */

Das _attribute_ ((noinline)) ist nötig, damit GCC nicht auf die 
Optimierungsidee kommt, die Funktion als Inline-Funktion in den 
main-Code zu setze.

Durch das manuell eingefügte 'ret' im Assemblerteil wäre das tödlich für 
das Programm.

Das Listing (Ausschnitt) sieht anschliessend so aus:
1
0000005c <EEPROM_write>:
2
3
#define TEST
4
5
void __attribute__ ((noinline)) EEPROM_write(unsigned int uiAddress, unsigned char data)
6
{
7
  5c:  9f bb         out  0x1f, r25  ; 31
8
  5e:  8e bb         out  0x1e, r24  ; 30
9
  60:  6d bb         out  0x1d, r22  ; 29
10
  62:  e2 9a         sbi  0x1c, 2  ; 28
11
  64:  e1 9a         sbi  0x1c, 1  ; 28
12
13
00000066 <waitEEW>:
14
  66:  e1 99         sbic  0x1c, 1  ; 28
15
  68:  fe cf         rjmp  .-4        ; 0x66 <waitEEW>
16
  6a:  08 95         ret
17
  6c:  08 95         ret
18
19
0000006e <main>:
20
  asm volatile (
21
    "out  %0+1,%B3"    "\n"
22
    "out  %0,%A3"      "\n"
23
    "out  %1,%4"       "\n"
24
    "sbi  %2,2"        "\n"
25
    "sbi  %2,1"        "\n"
26
    "waitEEW:"               "\n"
27
    "sbic  %2,1"       "\n"
28
    "rjmp  waitEEW"         "\n"
29
    "ret; Problematisch bei Inline-Optimierung!"
30
      :
31
      :
32
      "M" (_SFR_IO_ADDR(EEAR)),
33
      "M" (_SFR_IO_ADDR(EEDR)),
34
      "M" (_SFR_IO_ADDR(EECR)),
35
      "r" (uiAddress),
36
      "r" (data)
37
    );
38
}
39
40
#ifdef TEST
41
int main(void)
42
{
43
  6e:  62 e1         ldi  r22, 0x12  ; 18
44
  70:  88 e7         ldi  r24, 0x78  ; 120
45
  72:  96 e5         ldi  r25, 0x56  ; 86
46
  74:  f3 df         rcall  .-26       ; 0x5c <EEPROM_write>
47
  76:  ff cf         rjmp  .-2        ; 0x76 <main+0x8>

von R. B. (p1ng)


Angehängte Dateien:

Lesenswert?

mhh naja ich hab das problem jetzt ziemlich stark einschränken können!

Lösung Vorschlag ist so das Fuktutioniert aber so soll das nun doch 
nicht werden.

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
  while(EECR & (1<<EEWE));
  EEAR= uiAddress;
  EEDR = ucData;
  //  EECR |= (1<<EEMWE);      // EEMWE == bit2 lt. avr/iom8.h
  //  EECR |= (1<<EEWE);       // EEWE  == bit1

     asm volatile (
     "sbi 0x1c,2" "\r\n"
     "sbi 0x1c,1" "\r\n"
       );
}

Hier ist der Fehler im Programm aus irgend einem Grund rafft er das 
nicht!!

EECR |= (1<<EEMWE);      // EEMWE == bit2 lt. avr/iom8.h
EECR |= (1<<EEWE);       // EEWE  == bit1

Weis einer warum er das nicht rafft ? ergibt meiner meinung nach keinen 
sinn!

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Was "rafft er nicht"? Wird falscher Code für die Zeilen

EECR |= (1<<EEMWE);      // EEMWE == bit2 lt. avr/iom8.h
EECR |= (1<<EEWE);       // EEWE  == bit1

produziert? Wenn ja, welcher? Und nach deiner Änderung zu asm()-Variante 
funktioniert es?

Wenn ja, dann: Welchen GCC hast du? Bei mir wird durch WinAVR 20070122 
(GCC 4.1.1) bei beiden Varianten der gleiche Code produziert. 
Einstellungen im Makefile s. Anhang (Optimierung: s)

Mein Listing (test.lss, Ausschnitt):
1
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
2
{
3
  5c:  e1 99         sbic  0x1c, 1  ; 28
4
  5e:  fe cf         rjmp  .-4        ; 0x5c <EEPROM_write>
5
6
  while(EECR & (1<<EEWE));
7
8
  EEAR = uiAddress;
9
  60:  9f bb         out  0x1f, r25  ; 31
10
  62:  8e bb         out  0x1e, r24  ; 30
11
12
  EEDR = ucData;
13
  64:  6d bb         out  0x1d, r22  ; 29
14
15
  // ASM-Version
16
     asm volatile (
17
  66:  e2 9a         sbi  0x1c, 2  ; 28
18
  68:  e1 9a         sbi  0x1c, 1  ; 28
19
     "sbi 0x1c,2" "\r\n"
20
     "sbi 0x1c,1" "\r\n"
21
       );
22
23
  // C-Version
24
  EECR |= (1<<EEMWE);      // EEMWE == bit2 lt. avr/iom8.h
25
  6a:  e2 9a         sbi  0x1c, 2  ; 28
26
  EECR |= (1<<EEWE);       // EEWE  == bit1
27
  6c:  e1 9a         sbi  0x1c, 1  ; 28
28
  6e:  08 95         ret
29
}

von R. B. (p1ng)


Lesenswert?

ICh danke euch für eure Hilfe wir wissen warum es nicht geht es liegt am 
Compeiler wir hätten uns noch dusselig suchen können fals es 
Interressiert ich benutze das myAVR Workpad

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.