Problem mit Assembler (ATmega8 / AVR-GCC)

OP #4288572
Lesenswert?

Hallo, ich versuche mich gerade etwas in Assembler einzuarbeiten.
Als ersten Schritt habe ich versucht ein kleines Programm zu schreiben, 
für einen ATmega8 mit 2 Tastern und 2 LEDs angeschlossen. Ziel ist es 
einfach nur den ATmega8 dazu zu bringen pro Taster eine LED 
einzuschalten.
Das sind meine ersten Gehversuche, ich hoffe ich habe alles richtig 
verstanden bisher.

1
#include "avr/io.h"
2

3
#define click R16
4

5
init:
6
  SER  click
7
  OUT  DDRC,  click  ; DDRC mit 0xFF beschreiben: Ausgänge
8
  CLR  click
9
  OUT  DDRB,  click  ; DDRB mit 0x00 beschrieben: Eingänge  
10
  OUT  PORTC,  click  ; LEDs ausschalten 
11
  OUT  PORTB,  click  ; und PullUps deaktivieren
12

13
  
14
loop:
15
  IN  click,  PINB    ; die Taster auslesen und
16
  OUT  PORTD,  click  ; und auf die LEDs spiegeln
17
  RJMP  loop        ; und nochmal...


Das ganze funktioniert allerdings leider gar nicht. Ich habe mir dann 
mal mit objdump das ganze nochmal disassembliert angesehen:

1
00000000 <init>:
2
   0:  0f ef         ldi  r16, 0xFF  ; 255
3
   2:  04 bf         out  0x34, r16  ; 52
4
   4:  00 27         eor  r16, r16
5
   6:  07 bf         out  0x37, r16  ; 55
6
   8:  05 bf         out  0x35, r16  ; 53
7
   a:  08 bf         out  0x38, r16  ; 56
8

9
0000000c <loop>:
10
   c:  06 b7         in  r16, 0x36  ; 54
11
   e:  02 bf         out  0x32, r16  ; 50
12
  10:  00 c0         rjmp  .+0        ; 0x12 <loop+0x6>


Was micht jetzt sehr wundert ist das der rjmp nach 0x12 geht, und nicht 
nach 0xC.

Wäre sehr froh wenn mir eben jemand aufzeigen könnte, wo mein Fehler 
ist.

Die Taster hängen mit 10k Ohm als PullDown-Widerstand und 
Entprellkondensator an PB0 und PB1. Die LEDs and PC0 und PC1.
Gast #4288634
Lesenswert?

1
.include "m8def.inc"; darf nicht fehlen
2

3

4
#define click R16
5

6
init:
7
  SER  click
8
  OUT  DDRC,  click  ; DDRC mit 0xFF beschreiben: Ausgänge
9
  CLR  click
10
  OUT  DDRB,  click  ; DDRB mit 0x00 beschrieben: Eingänge  
11
  OUT  PORTC,  click  ; LEDs ausschalten 
12
  OUT  PORTB,  click  ; und PullUps deaktivieren
13

14
  
15
loop:
16
  IN  click,  PINB    ; die Taster auslesen und
17
  OUT  PORTC,  click  ; und auf die LEDs spiegeln
18
  RJMP  loop        ; und nochmal...
Macht im Simulator was es soll. Ev. mal deine Hardware posten.

Viel Erfolg!
Gast #4288917
Lesenswert?

Pull downs? Muss das sein?
Maches doch richtig: Interne und/oder externe Pull Ups an den Eingängen, 
LED mit Rv an +Ub hängen.
Dann gehts auch.
Ist natürlich nicht verboten, Pull Downs zu benutzen. Aber bitte miss 
die Pegel an den Eingängen nach.
OP #4289049
Lesenswert?

Wenn ich ein ähnliches Programm in C schreiben funktioniert die ganze 
Sache, also meine Schaltung ist richtig. Allerdings ist mir aufgefallen 
das ab einer bestimmten größe der Hex-Datei das überspielen nicht mehr 
funktioniert. Entweder ist der Programmer oder der ATmega hinüber. 
Außerdem macht er lustige sachen wenn ich ihn berühre. Ich melde mich 
nochmal wenn ich Sicher funktionierende Hardware habe...
#4289186
Lesenswert?

Stefan E. schrieb:
> Das ist vermutlich ungelinkter Code.

An der Stelle muss nichts gelinkt werden. Der muss dort 3 
Speicherstellen zurück springen. (Der PC steht bei der Ausführung von 
RJMP schon auf der nächsten Stelle) Dort sollte immer -3 stehen!

BTW:

Benedikt W. schrieb:
> #include "avr/io.h"

Wozu soll das sein?
Mir fehlt ehr sowas wie

.include "m8def.inc"

DA steht drin, wo sich die Ports befinden.

Worin programmierst Du Deinen Code?

Edit: Musste gerade nochmal die Werte editieren, weil ich den 
Schwachsinn aus Deinem Debuger geglaubt habe.
Der gibt vorne nicht die Adresse, sondern die Bytes an. **kopfschüttel*


Gruß

Jobst
Gast #4289233
Lesenswert?

Hi
Benedikt W. schrieb:
> loop:
>   IN  click,  PINB    ; die Taster auslesen und
>   OUT  PORTD,  click  ; und auf die LEDs spiegeln
>   RJMP  loop        ; und nochmal...

Nun, Assembler ist genauso funktionstüchtig wie C und vermutlich 
funktioniert deine kleine Übung, wenn du auch dem Port C die Taster 
zuweist. Und nicht Port D!
Gruß oldmax
#4289401
Lesenswert?

Eine fehlerträchtige Konstruktion ist noch
1
  SER  click
2
  OUT  DDRC,  click  ; DDRC mit 0xFF beschreiben: Ausgänge
3
  CLR  click
Es kommt hier nicht darauf an, in einem Register alle Bits zu setzen, 
sondern es soll danach ein Port konfiguriert werden. Okay, hier betrifft 
es zuuufällig alle Bits.
Übersichtlicher:
1
.equ config  0b11111111
2

3
  ldi  click, config
4
  OUT  DDRC,  click  ; 'kann weg': DDRC mit 0xFF beschreiben: Ausgänge
5
  ldi  click, ~config
Jetzt erklärt sich der Quellcode fast von selbst. Außerdem muss zum 
Ändern der Konfiguration nur eine Konstante geändert werden.
#4289413
Lesenswert?

Jobst M. schrieb:
> An der Stelle muss nichts gelinkt werden. Der muss dort 3
> Speicherstellen zurück springen. (Der PC steht bei der Ausführung von
> RJMP schon auf der nächsten Stelle) Dort sollte immer -3 stehen!

Dass es im konkreten Fall eigentlich nicht nötig wäre, ist irrelevant. 
Da der Linker durchaus auch Änderungen am Code vornehmen kann, ist 
selbst im Fall eines relativen Sprungs zu einem für den Assembler 
sichtbaren Label die Distanz dem Assembler nicht immer eindeutig 
bekannt. Warum sollte er also versuchen, eine Fallunterscheidung (kann 
Adresse/Distanz selber eintragen oder muss vom Linker gemacht werden) zu 
machen, wenn es der einfachere und sichere Weg ist, es immer dem Linker 
zu überlassen.

Jobst M. schrieb:
> Benedikt W. schrieb:
>> #include "avr/io.h"
>
> Wozu soll das sein?

Das ist korrekt so (abgesehen davon, dass <> statt "" angebracht wäre).

Jobst M. schrieb:
> Worin programmierst Du Deinen Code?

Steht doch im Titel.
#4290136
Lesenswert?

Jobst M. schrieb:
> BTW:
>
> Benedikt W. schrieb:
>> #include "avr/io.h"
>
> Wozu soll das sein?
> Mir fehlt ehr sowas wie
>
> .include "m8def.inc"
>
> DA steht drin, wo sich die Ports befinden.

avr/io.h ist eine allgemeine io header-Datei für gcc-avr oder avr-as.
Beim Aufruf von gcc-avr oder avr-as gibt man mit der Option
 -mmcu=atmega8
an, aus welcher header-Datei die controller-spezifischen Parameter
gelesen werden.

Oben in der Datei io.h wird beschrieben, wie das funktioniert:
...
    This header file includes the apropriate IO definitions for the
    device that has been specified by the <tt>-mmcu=</tt> compiler
    command-line switch.
...
OP #4295971
Lesenswert?

Ich hab den Fehler gefunden. Wer lesen kann ist klar im Vorteil ;)

Falls es jemanden Interessiert:

AVR-GCC sieht vor bei Schlüsselwörtern wie PORTB oder DDRA nicht die 
Port-Adresse, sondern die Adresse im Speicher anzusprechen. Sprich das 
funktioniert mit IN/OUT nicht. Um das zum laufen zu bekommen muss man 
_SFR_IO_ADDR(Port) verwenden, welches die Portadresse ausspuckt.

Hier der funktionierende Code:
1
#include <avr/io.h>
2

3
#define click  R16
4
#define input  0b11111100
5
#define output  0b11111111
6

7
init:
8
  LDI  click,  output
9
  OUT  _SFR_IO_ADDR(DDRC),  click  ; Ausgänge
10
  LDI  click,  input
11
  OUT  _SFR_IO_ADDR(DDRB),  click  ; Eingänge  
12
  LDI  click,   0x00
13
  OUT  PORTC,  click      ; LEDs ausschalten 
14
  OUT  PORTB,  click      ; und PullUps deaktivieren
15

16
  
17
loop:
18
  IN  click,  _SFR_IO_ADDR(PINB)  ; die Taster auslesen und
19
  OUT  _SFR_IO_ADDR(PORTC),  click  ; und auf die LEDs spiegeln
20
  RJMP  loop        ; und nochmal...

Falls es noch jemanden interessiert wie ich das in die ihex-Form 
gebracht habe:

Ich hab mir da ein mini-Shellscript geschrieben.
1
#!/bin/sh
2

3
avr-gcc -mmcu=$2 -c $1 -o tmp.elf -O0 -Wall
4
avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex tmp.elf flash.hex
5
rm tmp.elf

Anwendungsbeispiel:
1
script.sh sourcecode.sx atmega8
Danach hat man (wenn alles geklappt hat) eine flash.hex die man dem 
avrdude füttern kann.

-----

Alternativ könnte man Das programm auch ohne _SFR_IO_ADDR schreiben, was 
dann so aussehen würde:

1
#include <avr/io.h>
2

3
#define click  R16
4
#define input  0b11111100
5
#define output  0b11111111
6

7

8
main:
9
  LDI  click,  output
10
  STS  DDRC,  click  ; Ausgänge
11
  LDI  click,  input
12
  STS  DDRB,  click  ; Eingänge  
13
  LDI  click,   0x00
14
  STS  PORTC,  click  ; LEDs ausschalten 
15
  STS  PORTB,  click  ; und PullUps deaktivieren
16

17
  
18
loop:
19
  LDS  click,  PINB  ; die Taster auslesen und
20
  STS  PORTC,  click  ; und auf die LEDs spiegeln
21
  RJMP  loop    ; und nochmal...
#4296035
Lesenswert?

Benedikt W. schrieb:
> AVR-GCC sieht vor bei Schlüsselwörtern wie PORTB oder DDRA nicht die
> Port-Adresse, sondern die Adresse im Speicher anzusprechen.

Dazu noch eine Bemerkung: Wie Du richtig schreibst, ist es wichtig
das hier der avr-gcc bzw. indirekt der (gnu) avr-as verwendet wird.
Mit dem Atmel Assembler oder auch avra kann man die Befehle
"in" und "out" in der "loop" verwenden.

Z.B. (nicht von mir)
1
; Atmel Assembler oder avra!
2
; Port C: Ausgabe PC7 .. PC0 acht LEDs über 150R an 5 V
3
; Port B: Eingabe PB7 .. PB0 acht Taster gedrückt an Masse
4
; Beschaltung LEDs und Taster z.B. wie Atmel STK500
5

6
        .INCLUDE  "m8def.inc"   ; Deklarationen für Mega8
7
        .DEF    click = r16     ; Arbeitsregister
8

9
init:   ldi     click,$ff       ; Bitmuster 1111 1111
10
        out     DDRC,click      ; Port C ist Ausgang
11
                                ; Port B ist Eingang (default)
12

13
loop:   in      click,PINB      ; Eingabe Pin B  
14
        out     PORTC,click     ; Ausgabe Port C
15
        rjmp    loop
16
        .EXIT

Edit: Code formatiert.
Edit: Beschaltung beschrieben.

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