Forum: Mikrocontroller und Digitale Elektronik AVR Assembler Probleme/Fragen Interrupt


von Quantum (Gast)


Lesenswert?

Hallo Community,

ich bin gerade am Verzweifeln. Meine Erfahrung mit Assembler 
Programmierung ist ziemlich dürftig. Deshalb drehe ich mich wohl seit 
knapp 3 Std im Kreis.
Als Hardware wird ein Atmega644P verwendet. Hier der Code:
(Fragen stehen danach)
1
;
2
;Includes
3
.include "PFAD/m644Pdef.inc"
4
5
6
;LEDs
7
.EQU LED_1 = 6
8
.EQU LED_2 = 5
9
.EQU LED_3 = 4
10
11
;Registernamen
12
.def temp1 = r16
13
.def zeichen = r17
14
15
;Berechnen der UBRR_VAL anhand der Baud und der CPU Frequenz
16
.equ BAUD = 9600
17
.equ F_CPU = 19660800
18
.equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1)
19
20
21
;Interrupts
22
.org 0x0000    ;Beginn des Programms (Bei Reset oder Power-Down)
23
  jmp MAIN
24
.org 0x0004
25
  jmp ISR_INT1
26
27
28
;;;;;;
29
;MAIN;
30
;;;;;;
31
MAIN:  
32
  call INIT
33
  ldi zeichen, "b"
34
  call UARTOUT
35
  
36
LOOP:
37
  ldi temp1, (1 << LED_1) | (1 << LED_2) | (1 << LED_3)
38
  out PORTD, temp1
39
  jmp LOOP
40
41
;;;;;;;;;;;
42
;Interrupt;
43
;;;;;;;;;;;
44
ISR_INT1:
45
LOOP1:
46
  ldi temp1, (0 << LED_1) | (0 << LED_2) | (0 << LED_3)
47
  out PORTD, temp1
48
  jmp LOOP1
49
  reti
50
51
UARTOUT:
52
  lds temp1, UCSR0A
53
  sbrs temp1, UDRE0
54
  jmp UARTOUT
55
  sts UDR0, zeichen
56
  ret
57
58
;;;;;;;;;;;;;;;;;
59
;INITIALISIERUNG;
60
;;;;;;;;;;;;;;;;;
61
62
INIT:
63
64
;PORT D
65
  ldi temp1, (1 << LED_1) | (1 << LED_2) | (1 << LED_3)
66
  out DDRD, temp1
67
  out PORTD, temp1
68
69
;UART Initiaisierung
70
  ldi temp1, (1 << RXEN0) | (1 << TXEN0)
71
  sts UCSR0B, temp1
72
  ldi temp1, (1 << UCSZ00) | (1 << UCSZ01)
73
  sts UCSR0C, temp1
74
75
;Baudrate festlegen
76
  ldi temp1, HIGH(UBRR_VAL)
77
  sts UBRR0H, temp1
78
  ldi temp1, LOW(UBRR_VAL)
79
  sts UBRR0L, temp1
80
81
;Pin Change Interrupt
82
  ldi temp1, 1 << PCIE2
83
  sts PCICR, temp1
84
  ldi temp1, (1 << PCINT16) | (1 << PCINT20)
85
  sts PCMSK2, temp1
86
87
;Externe Interrupts
88
  ldi temp1, 1 << ISC11
89
  sts EICRA, temp1
90
  ldi temp1, 1 << INT1
91
  sts EIMSK, temp1
92
93
;Stack Initialisieren
94
  ldi temp1, LOW(RAMEND)
95
  out SPL, temp1
96
  ldi temp1, HIGH(RAMEND)
97
  out SPH, temp1
98
99
  sei ;Interrupts aktivieren
100
101
  ret

1. Der Interrupt wird nicht ausgelöst. Mir ist wohl klar, dass es nicht 
sinnvoll ist den Controller in der ISR "gefangen" zu halten. Die 
Intention ist einfach die, dass die LEDs sichtbar angehen. Ich hab 
allerdings keine Erklärung dafür, die Interruptsregister sind gesetzt, 
die Globalen Interrupts aktiviert und die Einsprungadressen definiert.

2. Des Weiteren ist zu sehen, dass ein Zeichen ausgegeben wird, nachdem 
die Initiaisierung aufgerufen wurde. Dieses Zeichen gibt er aber nur 
dann aus, wenn Controller

a) Programmiert wurde
b) Aus/Eingeschalten wurde

NICHT aber wenn der RESET Knopf betätigt wurde. Warum ?

Alls Assembler wurde der gavrasm unter Linux verwendet. Der code wird 
fehlerfrei assembliert.

Freue mich auf eure Hilfe

Hochachtungsvoll
Quantum

von Thomas P. (topla)


Lesenswert?

Einen Call init zu machen und erst danach den Stack zu initialisieren 
ist keine gute Idee.

Thomas

von spess53 (Gast)


Lesenswert?

Hi

>ISR_INT1:
>LOOP1:
>  ldi temp1, (0 << LED_1) | (0 << LED_2) | (0 << LED_3)
>  out PORTD, temp1
>  jmp LOOP1
>  reti

Und wie soll der Controller hier wieder rauskommen?

MfG Spess

von Quantum (Gast)


Lesenswert?

Thomas P. schrieb:
> Einen Call init zu machen und erst danach den Stack zu initialisieren
> ist keine gute Idee.
>
> Thomas

Danke, dass löst schonmal das Problem mit dem Resettaster.


spess53 schrieb:
> Hi
>
>>ISR_INT1:
>>LOOP1:
>>  ldi temp1, (0 << LED_1) | (0 << LED_2) | (0 << LED_3)
>>  out PORTD, temp1
>>  jmp LOOP1
>>  reti
>
> Und wie soll der Controller hier wieder rauskommen?
>
> MfG Spess
Das ist rein zum Testen. Will erstmal dass er überhaupt reinspringt. 
Wenn er das dann tun sollte wird das mit sinnvollem Code belegt.

Grüße

von Sascha W. (sascha-w)


Lesenswert?

wie hast du INT1 am Contoller beschaltet?

es ist keine gute Idee den PCINT einzuschalten, aber keine entsprechende 
ISR zu haben - dann springt er dir u.U. irgendwo ins Programm rein.
Am besten immer die komplette Interrupttabelle ins Program einbauen, und 
alle nicht benötigten ISR's mit RETI 'kurzschließen'!

Sascha

von Quantum (Gast)


Lesenswert?

Sascha Weber schrieb:
> wie hast du INT1 am Contoller beschaltet?
>
> es ist keine gute Idee den PCINT einzuschalten, aber keine entsprechende
> ISR zu haben - dann springt er dir u.U. irgendwo ins Programm rein.
> Am besten immer die komplette Interrupttabelle ins Program einbauen, und
> alle nicht benötigten ISR's mit RETI 'kurzschließen'!
>
> Sascha

Danke für deine Antwort

Die ISR, die den PCINT2 abarbeitet ist implementiert. Übersichshalber 
hab ich den Code etwas gekürzt. Nach weiterem experimentieren ist mir 
aufgefallen, dass der PCINT16 Pin auf einen Interrupt anspricht. Der 
PCINT20 jedoch nicht. Bei beim INT1 Interrupt hat sich immer noch nichts 
getan.

Der INT1 Pin ist mit nem PullUp und nem Taster beschalten, der den Pin 
dann auf Masse zieht.

Gruß

von Mark L. (m2k10) Benutzerseite


Lesenswert?

Quantum schrieb:
> Der
> PCINT20 jedoch nicht.

JTAG aktiviert??

von Uwe (Gast)


Lesenswert?

> UARTOUT:
>   lds temp1, UCSR0A
>   sbrs temp1, UDRE0
>   jmp UARTOUT
>   sts UDR0, zeichen
>   ret

sbrs templ,UDRE0

hmm hieß sbrs nicht "skip if bits in Register are set" und als operand 
dahinter eine Bitmaske ?
also : sbrs templ,1<<UDRE0

von spess53 (Gast)


Lesenswert?

Hi

>hmm hieß sbrs nicht "skip if bits in Register are set" und als operand
>dahinter eine Bitmaske ?
>also : sbrs templ,1<<UDRE0

Nein.

MfG Spess

von Quantum (Gast)


Lesenswert?

Mark L. schrieb:
> Quantum schrieb:
>> Der
>> PCINT20 jedoch nicht.
>
> JTAG aktiviert??

JTAG hab ich mithilfe den Fuses deaktiviert

Uwe schrieb:
>> UARTOUT:
>>   lds temp1, UCSR0A
>>   sbrs temp1, UDRE0
>>   jmp UARTOUT
>>   sts UDR0, zeichen
>>   ret
>
> sbrs templ,UDRE0
>
> hmm hieß sbrs nicht "skip if bits in Register are set" und als operand
> dahinter eine Bitmaske ?
> also : sbrs templ,1<<UDRE0

Wenn ich das so mache bringt mir der Assembler einen Fehler. Die Ausgabe 
funktioniert ja auch.

Danke für die Hilfe

Gruß

von Quantum (Gast)


Lesenswert?

Hab jetzt kurz ne kleine C Routine geschrieben, da funktionieren beide 
Interrupts tadellos. An dem Prozessor kann es also nicht liegen.

Grüße

von Mark L. (m2k10) Benutzerseite


Lesenswert?

Bist du sicher, dass kein Kurzschluss zwischen PD3 und PD4 ist? Du 
könntest auch mal einfach in der Hauptschleife den Taster abfragen und 
die LEDs ohne INT1 schalten.

Ha, nochmal in's Datenblatt geschaut: Hab den Fehler! (glaub ich)
sts EIMSK ist falsch, muss out EIMSK sein!

Mark

von Quantum (Gast)


Lesenswert?

Mark L. schrieb:
> Bist du sicher, dass kein Kurzschluss zwischen PD3 und PD4 ist? Du
> könntest auch mal einfach in der Hauptschleife den Taster abfragen und
> die LEDs ohne INT1 schalten.
>
> Ha, nochmal in's Datenblatt geschaut: Hab den Fehler! (glaub ich)
> sts EIMSK ist falsch, muss out EIMSK sein!
>
> Mark

Danke !!
Es funktioniert :)

Darf ich erfahren wie du das herausgefunden hast, bzw wo das steht. Was 
hat dieses Register mit den I/O Registern zu tun ? Oder hab ich das mit 
dem out falsch verstanden ?

Das Problem mit dem Pin Chang Interrupt auf PCINT20 bleibt allerdings. 
PCINT16 funktioniert. Obwohl ich beide eingeschalten habe.

von spess53 (Gast)


Lesenswert?

Hi

>Das Problem mit dem Pin Chang Interrupt auf PCINT20 bleibt allerdings.
>PCINT16 funktioniert. Obwohl ich beide eingeschalten habe.

Hast du die Frage

Beitrag "Re: AVR Assembler Probleme/Fragen Interrupt"

beachtet?

MfG Spess

von Quantum (Gast)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Das Problem mit dem Pin Chang Interrupt auf PCINT20 bleibt allerdings.
>>PCINT16 funktioniert. Obwohl ich beide eingeschalten habe.
>
> Hast du die Frage
>
> Beitrag "Re: AVR Assembler Probleme/Fragen Interrupt"
>
> beachtet?
>
> MfG Spess

Wie ich schon geschrieben habe, ist JTAG abgeschaltet. Die ISR wird mit 
einem entsperechendem C Programm problemlos, an beiden Pins, aufgerufen

von spess53 (Gast)


Lesenswert?

Hi

Außer deinem, jetzt unbekanntem, Programm und dem JTAG-Interface gibt es 
nichts, was den Interrupt verhindern könnte.

MfG Spess

von Mark L. (m2k10) Benutzerseite


Lesenswert?

Quantum schrieb:
> Darf ich erfahren wie du das herausgefunden hast, bzw wo das steht. Was
> hat dieses Register mit den I/O Registern zu tun ? Oder hab ich das mit
> dem out falsch verstanden ?

Das out geht für alle Register bis 0x5F Die Adresse ist bei out aber um 
0x20 versetzt. Alles was mit out erreichbar ist, steht auch mit der 
out-Adresse in der *def.inc, daher führt sts zum Beschreiben eines 
falschen IO-Registers. Ist manchmal etwas nervig bei den Atmels, gibt 
immer wieder Unterschiede. Steht einmal in der *def.inc und im 
Datenblatt die IO-Register mit den doppelten Adressen.

In kurzen Programmen sind das und die sbr/sbrs-Geschichte so 
Fehlerquellen, die man einfach nicht direkt sieht und die die 
Fehlersuche selbst in einem 20-Zeiler zur nervenaufreibenden Sache 
werden lassen.

Mark

von Jobst M. (jobstens-de)


Lesenswert?

Mark L. schrieb:
> Das out geht für alle Register bis 0x5F Die Adresse ist bei out aber um
> 0x20 versetzt. Alles was mit out erreichbar ist, steht auch mit der
> out-Adresse in der *def.inc, daher führt sts zum Beschreiben eines
> falschen IO-Registers. Ist manchmal etwas nervig bei den Atmels, gibt
> immer wieder Unterschiede.


IN, LD, LDI, LDD, LDS, MOV, OUT, ST, STD, STS

... und dann auch noch mit unterschiedlichen Adressen, je nach Befehl 
...
Manchmal habe ich den Eindruck, daß hier völlige Anfänger den 
Befehlssatz entworfen haben. Man könnte meinen, daß sie nicht mal den 
8051 kannten. Dort gibt es einen Befehl für alle diese (und noch 
weitere) Aktionen: MOV
Um den Rest kümmert sich der Kompiler. Und genau von dem erwarte ich 
diese Leistung!

Wenn man ein Programm von einem AVR in einen anderen überträgt, kann es 
bei SFRs die dort an anderer Stelle hocken, passieren, daß man IN und 
OUT gegen LDS und STS tauschen muß. Es gibt nicht mal eine Meckermeldung 
vom Kompiler. Also muß ich von Hand heraussuchen, welches SFR nun in 
welchem Bereich sitzt. Da kann ich die Adresse auch gleich von Hand 
eintragen!

*kopfschüttel** - Die Dinger sind eigentlich völliger Murks!


Gruß

Jobst

von Thomas P. (topla)


Lesenswert?

Jobst M. schrieb:
> Manchmal habe ich den Eindruck, daß hier völlige Anfänger den
> Befehlssatz entworfen haben. Man könnte meinen, daß sie nicht mal den
> 8051 kannten.

Den gleichen Eindruck habe ich auch seit dem Umstieg an die AVRs. Im 
Gegensatz zum 51er ist der Befehlssatz aus Sicht eines 
Assemblerprogrammierers einfach Schrott.

Thomas

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

>Den gleichen Eindruck habe ich auch seit dem Umstieg an die AVRs. Im
>Gegensatz zum 51er ist der Befehlssatz aus Sicht eines
>Assemblerprogrammierers einfach Schrott.

Dann macht doch einen eigenen Thread dazu auf. Dort könnt ihr euren 
Frust in aller Ruhe ausdiskutieren.

@Quantum (Gast)

Im Anhang ein kurzer Test. Funktioniert problemlos.

MfG Spess

von Quantum (Gast)


Lesenswert?

Mark L. schrieb:
> Quantum schrieb:
>> Darf ich erfahren wie du das herausgefunden hast, bzw wo das steht. Was
>> hat dieses Register mit den I/O Registern zu tun ? Oder hab ich das mit
>> dem out falsch verstanden ?
>
> Das out geht für alle Register bis 0x5F Die Adresse ist bei out aber um
> 0x20 versetzt. Alles was mit out erreichbar ist, steht auch mit der
> out-Adresse in der *def.inc, daher führt sts zum Beschreiben eines
> falschen IO-Registers. Ist manchmal etwas nervig bei den Atmels, gibt
> immer wieder Unterschiede. Steht einmal in der *def.inc und im
> Datenblatt die IO-Register mit den doppelten Adressen.
>
> In kurzen Programmen sind das und die sbr/sbrs-Geschichte so
> Fehlerquellen, die man einfach nicht direkt sieht und die die
> Fehlersuche selbst in einem 20-Zeiler zur nervenaufreibenden Sache
> werden lassen.
>
> Mark

Danke, hab´s nun verstanden. In der *def.inc ist das sehr übersichtlich 
dargestellt.

spess53 schrieb:
> Hi
>
>>Den gleichen Eindruck habe ich auch seit dem Umstieg an die AVRs. Im
>>Gegensatz zum 51er ist der Befehlssatz aus Sicht eines
>>Assemblerprogrammierers einfach Schrott.
>
> Dann macht doch einen eigenen Thread dazu auf. Dort könnt ihr euren
> Frust in aller Ruhe ausdiskutieren.
>
> @Quantum (Gast)
>
> Im Anhang ein kurzer Test. Funktioniert problemlos.
>
> MfG Spess

Es funktioniert nun auch, lag an der externen Beschaltung.
Ich bedanke mich bei allen Problemlösern. Habt mir wirklich sehr 
geholfen.

Grüße

von Sascha W. (sascha-w)


Lesenswert?

man kann sich das Leben mit ein paar Macros einfacher machen z.B. für 
out
1
.macro  out_
2
.if (@0 <= 63)
3
  out  @0,@1
4
.else
5
  sts  @0,@1
6
.endif
7
.endmacro
im Program dann einfach immer 'out_' schreiben, das Macro beutzt dann 
den richtigen Befehl.

Sascha

von Jobst M. (jobstens-de)


Lesenswert?

Ach was, die Macros werden erst nach der Adressumsetzung aufgerufen?
So genau habe ich mich damit noch nie befasst ...

Danke für den Hinweis.
Ich glaube, ich werde mal einen kleinen Pre-Compiler schreiben und 
diesen dann hier veröffentlichen ...

MOV, ich komme :-D


Gruß

Jobst

von spess53 (Gast)


Lesenswert?

Hi

>Ich glaube, ich werde mal einen kleinen Pre-Compiler schreiben und
>diesen dann hier veröffentlichen ...

Meine Codegenerierung macht das schon seit Jahren richtig.

MfG Spess

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.