Inline Assembler übersetztung

OP #702059
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
Angehängte Dateien:
Persönliche Seite #702085
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
Persönliche Seite #702237
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>
OP #702366
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!
Angehängte Dateien:
Persönliche Seite #702384
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
}
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren