Forum: Mikrocontroller und Digitale Elektronik ATtiny26 mag rcall nicht


von Achim (Gast)


Lesenswert?

Hallo zusammen,

ich habe das Problem, das der Attiny26-16 den rcall Befehl nicht mag, er 
bleibt da immer hängen. Ich benutze AtmelStudio 6.0 und schreibe in asm.
Das Programm läuft ohne Probleme auf dem ATtiny13-20 mit rcall. Wenn ich
die Unterprogramme ins Hauptprogramm hole, läuft auch der ATtiny26.
Die inc. Datei habe ich natürlich umgestellt. Programmieren läst sich 
der ATtiny 26 ohne probleme. Keine Fehlermeldung.

Hoffe es kann mir bei diesem Problem jemand weiterhelfen.

l.g. Achim

von Walter S. (avatar)


Lesenswert?

Achim schrieb:
> Hoffe es kann mir bei diesem Problem jemand weiterhelfen.

ohne Programm sicher nicht

von (ungebetener) (Gast)


Lesenswert?

Schon mal ins Datenblatt geschaut, ob der rcall im Mikrocode vorhanden 
ist?

von Hannes L. (hannes)


Lesenswert?

Walter S. schrieb:
> ohne Programm sicher nicht

Doch, der Tiny13 initialisiert seinen Stackpointer per Hardware beim 
Reset, beim Tiny26 muss man den Stackpointer von Hand initialisieren.

Achim schrieb:
> Wenn ich
> die Unterprogramme ins Hauptprogramm hole, läuft auch der ATtiny26.

Eben, das deutet darauf hin, dass der Stackpointer nicht initialisiert 
ist...

...

von Achim (Gast)


Lesenswert?

Den Befehl gibt es, geht auch wenn ich ihn nur ein mal aufrufe, aber 
beim zweiten mal aus einem billigen Blikprogramm mit zwei LED bleib er 
stehen.

.include "tn26def.inc"

rjmp     Anfang

Anfang:
   ldi     r16,0xff
   out     ddra,r16
   ldi     r16,0x18
   out     ddrb,r16

Schleife:
   ldi     r16,0x10
   out     portb,r16
;Warte:
      ldi     r17,255
   Warte1:
      ldi     r18,255
      Warte2:
       dec     r18
         brne    Warte2
       dec     r17
       brne    Warte1
;ret     ;Rücksprung
   ;rcall   Warte
   ldi     r16,0x0
   out     portb,r16
;Pause:
      ldi     r17,255
   Pause1:
      ldi     r18,255
      Pause2:
       dec     r18
         brne    Pause2
       dec     r17
       brne    Pause1
;ret     ;Rücksprung
   ;rcall   Pause

   ldi     r16,0x8
   out     portb,r16
;Warte:
      ldi     r17,255
   Warte3:
      ldi     r18,255
      Warte4:
       dec     r18
         brne    Warte4
       dec     r17
       brne    Warte3
;ret     ;Rücksprung
   ;rcall   Warte
   ldi     r16,0x0
   out     portb,r16
;Pause:
      ldi     r17,255
   Pause3:
      ldi     r18,255
      Pause4:
       dec     r18
         brne    Pause4
       dec     r17
       brne    Pause3
;ret     ;Rücksprung
   ;rcall   Pause
rjmp     Schleife

von Achim (Gast)


Lesenswert?

Wie initaliesiert man einen Stckpionter?

von Spess53 (Gast)


Lesenswert?

Hi

Hannes hatte Recht:

>Eben, das deutet darauf hin, dass der Stackpointer nicht initialisiert
>ist...

MfG Spess

von Achim (Gast)


Lesenswert?

Danke, und wie mache ich das mit dem Stackpointer?

von Hannes L. (hannes)


Lesenswert?

Achim schrieb:
> Wie initaliesiert man einen Stckpionter?

Man setzt SPL und ggf. SPH auf RAMEND.

...

von Spess53 (Gast)


Lesenswert?

Hi

>Wie initaliesiert man einen Stckpionter?

Für den ATTiny26:

ldi r16,Low(RAMEND)
out SPL,r16

MfG spess

von Achim (Gast)


Lesenswert?

Hallo Hannes, könnten Sie mir das bitte als asm vorschreiben, da ich 
nicht weiß, was SPL, SPH und Ramend ist. Ich übe erst seit zwei Wochen 
mit dem ATtiny13, doch da geht es super. Mir haben nur die ein und 
Ausgänge nicht gereicht.

l.g. Achim

von Achim (Gast)


Lesenswert?

Danke Spess53, werde ich mal so probieren. Das ganze soll mal eine 
Schrittmotorsteuerung werden, wenns fertig ist. Mit 3 ATtiny13 geht es 
schon.

l.g. Achim

von Spess53 (Gast)


Lesenswert?

Hi

Korrektur:

out SPL,r16 ->out SP,r16

S.57 in

http://www.atmel.com/Images/doc1477.pdf

MfG Spess

von Hannes L. (hannes)


Lesenswert?

Achim schrieb:
> könnten Sie mir das bitte als asm vorschreiben,

Hat Spess bereits gemacht.

> da ich nicht weiß, was SPL, SPH und Ramend ist.

Dann könnte man diese Begriffe als Suchbegriffe im Datenblatt-PDF 
benutzen.

...

von Achim (Gast)


Lesenswert?

Werde es auf jeden fall nachlesen, will ja wissen was die Befehle 
machen.
Ich danke euch beiden für eure Hilfe.

PS: Bin Modellbauer, Eisenbahn, Spur Z, 46Jahre.

von Achim (Gast)


Lesenswert?

So läuft das Programm optimal.

1
.include "tn26def.inc"
2
3
rjmp     Anfang
4
5
Anfang:
6
   ldi     r16,low(Ramend)     ;Einfügen für rcall
7
   out     sp,r16              ;Einfügen für rcall
8
   ldi     r16,0x18
9
   out     ddrb,r16
10
11
Schleife:
12
   ldi     r16,0x10
13
   out     portb,r16
14
   rcall   Warte
15
   ldi     r16,0x0
16
   out     portb,r16
17
   rcall   Warte
18
   ldi     r16,0x8
19
   out     portb,r16
20
   rcall   Warte
21
   ldi     r16,0x0
22
   out     portb,r16
23
   rcall   Warte
24
rjmp     Schleife
25
26
Warte:
27
      ldi     r17,255
28
   Warte1:
29
      ldi     r18,255
30
      Warte2:
31
       dec     r18
32
         brne    Warte2
33
       dec     r17
34
       brne    Warte1
35
ret



Danke für die hilfe.

von Hannes L. (hannes)


Lesenswert?

Achim schrieb:
> Bin Modellbauer, Eisenbahn, Spur Z,

Ich mag's ein bissel größer, beschränke mich aber mehr auf die 
Elektronik und Elektrik, mit dem Bauen von Modellen habe ich es nicht 
so...
http://www.hanneslux.de/ Da findest Du vielleicht ein paar nützliche 
Tipps betreffs Einstieg in AVR-Assembler.

> 46Jahre.

Das war ein schönes Alter, ist aber schon verdammt lange her... ;-)

...

von Rolf H. (flash01)


Lesenswert?

he...was soll ich denn erst sagen mit meine 78 Jahre!
Spur H0 Fleischmann mit Roco kombiniert.
Anlage voll elektronisch ausgerüstet mit uralten ATARI in GFA-Basic.
Zwei Tiny2313 steuern einen Märklin-Kran und Container-Kran von Brawa.

Interessant, was Achim da vorzeigt.

Grüße

Rolf

von Rolf H. (flash01)


Lesenswert?

Hallo Achim,
ich habe mir nochmal Deinen Quelltext angeschaut, und da ist mir
was merkwürdiges aufgefallen.

im Anfang

ldi    r16,0x18   ;0b0001 1000
out    ddrb,r16   ;also PORTB,PB4 + PB3 = Output


in der Schleife kommt nach dem zweiten rcall

ldi    r16,0x8    ;das wäre 0b1000 0000
out    portb,r16

aber Du hast doch im Anfang im Datenrichtungs-Register PB7
garnicht als Output gesetzt, oder?

Evtl. kann auch ich einen Denkfehler haben!

Grüße

Rolf

von Karl H. (kbuchegg)


Lesenswert?

Rolf H. schrieb:

> ldi    r16,0x8    ;das wäre 0b1000 0000

No.
Genau lesen. Da ist eine führende 0 nicht geschrieben worden.

  0x8   ist dasselbe wie
  0x08


Und gerade bei Hex-Zahlen (oder auch Binärzahlen) die eine starke 
Affinität zur Bitdarstellung haben, ist es unklug, führende 0-en 
wegzulassen. Führt auf lange Sicht praktisch immer zu derartigen 
Missverständnissen. An dieser Stelle ist es besser die führenden 0-en zu 
schreiben und so wieder in das 8-Bit Schema zu kommen, welches zentral 
für die Arbeit auf Bitebene ist.
Nicht alles, was technisch erlaubt ist, ist programmiertaktisch 
sinnvoll.

von Helmut L. (helmi1)


Lesenswert?

Rolf H. schrieb:
> ldi    r16,0x8    ;das wäre 0b1000 0000
> out    portb,r16

Ne Rolf,

ldi    r16,0x8    ;ist 0b0000 1000

und damit Ok.

von Karl H. (kbuchegg)


Lesenswert?

Noch besser wäre es allerdings, das ganze so zu schreiben

  ldi    r16, (1<<PB4) | (1<<PB3)
  out    ddrb,r16


bzw.

  ldi    r16, (1<<PB4)
  out    portb,r16


Denn jetzt stehen die Bitnamen direkt dort und kein Mensch muss mehr 
überlegen, welche Bits sich eigentlich hinter 0x18 bzw. 0x8 verstecken.

von Helmut L. (helmi1)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Noch besser wäre es allerdings, das ganze so zu schreiben
>
>   ldi    r16, (1<<PB4) | (1<<PB3)
>   out    ddrb,r16
>
>
> bzw.
>
>   ldi    r16, (1<<PB4)
>   out    portb,r16

Und noch besser ist es direkt sprechende Namen zu verwenden.

    ldi    r16, SIGNAL1

von Karl H. (kbuchegg)


Lesenswert?

Helmut Lenzen schrieb:

> Und noch besser ist es direkt sprechende Namen zu verwenden.
>
>     ldi    r16, SIGNAL1

Absolut.

Und die Moral von der Geschichte:
Man kann alleine durch unterschiedliche Schreibweisen steuern, wie gut 
oder schlecht ein Code zu lesen bzw. zu verstehen ist. Und das sogar mit 
relativ wenig Aufwand, der einen riesen Unterschied ausmachen kann.

von Rolf H. (flash01)


Lesenswert?

Karl Heinz Buchegger schrieb:
> ldi    r16, (1<<PB4)
>
>   out    portb,r16


Hast Recht Karl Heinz Buchegger, das werde ich mir mal angewöhnen.

Wieder was gelernt!

Grüße

Rolf

von Rolf H. (flash01)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> Und noch besser ist es direkt sprechende Namen zu verwenden.
>
>>
>
>>     ldi    r16, SIGNAL1


dann muß ich aber doch am Anfang PB4 als SIGNAL1 definieren.
Macht man das mit .equ   PB4=SIGNAL

von Karl H. (kbuchegg)


Lesenswert?

Rolf H. schrieb:
> Karl Heinz Buchegger schrieb:
>>> Und noch besser ist es direkt sprechende Namen zu verwenden.
>>
>>>
>>
>>>     ldi    r16, SIGNAL1
>
>
> dann muß ich aber doch am Anfang PB4 als SIGNAL1 definieren.

Ja und?
Spätestens wenn die LED wegen Hardware Problemen vom Pin PB4 auf PB2 
'umziehen' muss, bist du froh drüber, wenn du nur an einer Stelle die 
neue Belegung einträgst und nicht quer durch das ganze Programm hirschen 
und alle relevanten Hex-Zahlen finden und anpassen musst.

> Macht man das mit .equ   PB4=SIGNAL

fast
a) anders rum. In den meisten Programmiersprachen steht immer links
   vom = das Ergebnis und rechts davon, wie  man zu diesem Ergebnis
   kommt.
b) so wie das verwendet wird, muss da stehen

.equ     SIGNAL1 = (1<<PB4)

Nur dann ist

   ldi   r16, (1<<PB4)

und

   ldi   r16, SIGNAL1

auch gleichwertig.

von Rolf H. (flash01)


Lesenswert?

Karl Heinz Buchegger schrieb:
> ldi    r16, (1<<PB4)
>
>   out    portb,r16

richtig wäre es aber wenn:

ldi   r16,0x8      ;0x08 = 0b0000 1000
out   portb,r16


ldi    r16, (1<<PB3)  ;oder hab ich wieder nen Denkfehler?

Grüße

Rolf

von Karl H. (kbuchegg)


Lesenswert?

Rolf H. schrieb:
> Karl Heinz Buchegger schrieb:
>> ldi    r16, (1<<PB4)
>>
>>   out    portb,r16
>
> richtig wäre es aber wenn:
>
> ldi   r16,0x8      ;0x08 = 0b0000 1000
> out   portb,r16
>
>
> ldi    r16, (1<<PB3)  ;oder hab ich wieder nen Denkfehler?

Ne. stimmt schon.
Ich hab jetzt nicht auf die Pin-Nummern geachtet.

Vergleich mal mit
1
.include "tn26def.inc"
2
3
.equ     LED_PORT = PORTB
4
.equ     LED_DDR  = DDRB
5
6
.equ     LEFT_LED  = (1<<PB4)
7
.equ     RIGHT_LED = (1<<PB3)
8
9
   rjmp     Anfang
10
11
Anfang:
12
   ldi     r16,low(Ramend)     
13
   out     sp,r16              
14
15
   ldi     r16, LEFT_LED | RIGHT_LED
16
   out     LED_DDR, r16
17
18
Main:
19
   ldi     r16, LEFT_LED
20
   out     LED_PORT, r16
21
   rcall   Warte
22
   ldi     r16, 0x0
23
   out     LED_PORT, r16
24
   rcall   Warte
25
   ldi     r16, RIGHT_LED
26
   out     LED_PORT, r16
27
   rcall   Warte
28
   ldi     r16, 0x0
29
   out     LED_PORT, r16
30
   rcall   Warte
31
   rjmp    Main
32
33
Warte:
34
   ldi     r17,255
35
Warte1:
36
   ldi     r18,255
37
Warte2:
38
   dec     r18
39
   brne    Warte2
40
   dec     r17
41
   brne    Warte1
42
   ret


Spielt es jetzt wirklich noch eine große Rolle, wo die LDE angeschlossen 
ist?
Nicht wirklich. Wenn die eine LED (sagen wir mal die rechte) nicht an 
PB3 angeschlossen ist, sondern an PB2, dann änder ich einfach
1
  ...
2
.equ     RIGHT_LED = (1<<PB2)
3
  ...

und fertig. Den Rest der Programmanpassung macht der Assembler.

Und das ist noch lange nicht alles, was man in diesem Programm 
verbessern kann. Zb. sollten einem die 'Komplett'-Zugriffe auf den Port 
ein Dorn im Auge sein. Mittels
1
   ldi     r16, LEFT_LED
2
   out     LED_PORT, r16
verändert man ja nicht nur den einen Pin, sondern alle anderen Pins 
gleich mit! Solange man nur 1 oder 2 LED an einem Port hat, mag das ja 
noch angehen. Aber wenn du 3 LED, 2 Summer, und 3 Taster am Port hängen, 
dann wirds aufwändig, das immer alles im Kopf zu behalten, welcher Pin 
jetzt gerade wie stehen muss und welchen Wert man daher an das 
Port-Register zuweisen muss, damit wieder alles stimmt.
Genau aus dem Grund gibt es die SBI und CBI Instruktionen, mit denen man 
tatsächlich nur 1 Bit und nicht mehr manipuliert.
1
.include "tn26def.inc"
2
3
.equ     LED_PORT = PORTB
4
.equ     LED_DDR  = DDRB
5
6
.equ     LEFT_LED  = PB4
7
.equ     RIGHT_LED = PB3
8
9
   rjmp     Anfang
10
11
Anfang:
12
   ldi     r16,low(Ramend)     
13
   out     sp,r16              
14
15
   ldi     r16, (1<<LEFT_LED) | (1<<RIGHT_LED)
16
   out     LED_DDR, r16
17
18
Main:
19
   sbi     LED_PORT, LEFT_LED
20
   rcall   Warte
21
   cbi     LED_PORT, LEFT_LED
22
   rcall   Warte
23
24
   sbi     LED_PORT, RIGHT_LED
25
   rcall   Warte
26
   cbi     LED_PORT, RIGHT_LED
27
   rcall   Warte
28
29
   rjmp    Main
30
31
Warte:
32
   ldi     r17,255
33
Warte1:
34
   ldi     r18,255
35
Warte2:
36
   dec     r18
37
   brne    Warte2
38
   dec     r17
39
   brne    Warte1
40
   ret


Aber: All das steht ja auch mehr oder weniger im
AVR-Tutorial
Wenn auch nicht in den Feinheiten von Anfang an.

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.