Forum: Mikrocontroller und Digitale Elektronik ATmega128 External Interrupt Problem


von Stefan F. (stefan_h1)


Lesenswert?

Hallo,

ich habe vor Kurzem mit Assembler angefangen und bin nun bei Interrupts 
angelangt.
Dazu habe ich ein kurzes Beispielprogramm geschrieben, nur funktioniert 
es nicht so wie ich es mir vorstelle.

Ich habe PORTA als Output und PE6 als Input für den Interrupt 
eingestellt. Eigentlich wollte ich, dass PORTA bei jedem Interrupt eins 
hochzählt.
Stattdessen leuchtet PORTA die ganze Zeit, nur beim Interrupt wird das 
Muster 0x55 angezeigt. Mehr oder weniger das Gegenteil von dem was ich 
wollte.

Ich probiere jetzt schon seit Stunden herum und habe auch schon im 
Internet gesucht, aber finde den Fehler leider nicht.
Ich benutze einen Atmega128 auf einem BIGAVR6.

Vielleicht kann mir jemand helfen, bin schon total verzweifelt.
1
.NOLIST
2
.INCLUDE "m128def.inc"
3
.LIST
4
5
.equ    temp, 0x10
6
7
.text
8
.org    0x00
9
    jmp    init
10
.org    INT6addr*2
11
    jmp    int6
12
13
.text
14
15
init:
16
    ldi    temp, lo8(RAMEND)
17
    out    SPL, temp
18
    ldi    temp, hi8(RAMEND)
19
    out    SPH, temp
20
21
    ldi    temp, 0x00
22
    out    DDRE, temp  
23
    out   PORTE, temp
24
  
25
    ldi    temp, 0xff
26
    out    DDRA, temp  
27
  
28
    ldi    temp, 1<<PE6  
29
    out    PORTE, temp
30
31
    lds    temp, EICRB
32
    ori    temp, 1<<ISC61
33
    sts    EICRB, temp
34
35
    in     temp, EIMSK
36
    ori    temp, 1<<INT6
37
    out    EIMSK, temp  
38
  
39
    ldi    temp, 0x55
40
    out    PORTA, temp
41
42
    sei              
43
44
    ldi    temp, 1<<SE
45
    out    MCUCR, temp
46
47
main:  
48
    sleep
49
    rjmp   main
50
  
51
int6:
52
    in     temp, PORTA
53
    dec    temp  
54
    out    PORTA, temp  
55
    reti

von Dirk (Gast)


Lesenswert?

.org nt6addr *1
probiert?

von Falk B. (falk)


Lesenswert?

Hatten wir das nicht eben erst?

Beitrag "AVR External Interrupt Hilfe"

von Dirk (Gast)


Lesenswert?

fast. aber die Verwendung von Bezeichneten kann auch schiefgehen

von Stefan F. (stefan_h1)


Lesenswert?

Dirk schrieb:
> .org nt6addr *1
> probiert?

Ja, brachte leider nichts. Dann hab ich nur das Muster 0x55 am PORTA und 
der Interrupt wurde nie ausgeführt.

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


Lesenswert?

M103C-Fuse abgeschaltet?

Ansonsten rennt dein Stack in irgendwelche IO-Register rein.

von Stefan F. (stefan_h1)


Lesenswert?

hhh

Jörg W. schrieb:
> M103C-Fuse abgeschaltet?
>
> Ansonsten rennt dein Stack in irgendwelche IO-Register rein.

Ja, ist deaktiviert. Vielleicht liegt es aber generell an irgendwelchen 
Fuse-Bits?

von MWS (Gast)


Lesenswert?

Stefan F. schrieb:
> .org    INT6addr*2

In so einem Fall sieht man sich die Herkunft des Symbols an, es muss ja 
irgendwo definiert worden sein, also öffnet man die zugehörige *.inc und 
findet dort:

> .equ INT6addr = $00e

Da hat doch tatsächlich jemand berücksichtigt, dass es bei diesem 
Controllertyp mehr Speicher für die IVT braucht. Mit mal 2 definierst Du 
einen anderen Interrupt und wo der richtige stehen sollte, ist's leer, 
bzw. fordert den Controller zum Reset auf.

Stefan F. schrieb:
> Dirk schrieb:
>> .org nt6addr *1
>> probiert?
>
> Ja, brachte leider nichts.

Falscher Controller eingestellt?

von Stefan F. (stefan_h1)


Lesenswert?

MWS schrieb:
> Stefan F. schrieb:
>> .org    INT6addr*2
>
> In so einem Fall sieht man sich die Herkunft des Symbols an, es muss ja
> irgendwo definiert worden sein, also öffnet man die zugehörige *.inc und
> findet dort:
>
>> .equ INT6addr = $00e
>
> Da hat doch tatsächlich jemand berücksichtigt, dass es bei diesem
> Controllertyp mehr Speicher für die IVT braucht. Mit mal 2 definierst Du
> einen anderen Interrupt und wo der richtige stehen sollte, ist's leer,
> bzw. fordert den Controller zum Reset auf.

Ok, klingt einleuchtend. Danke schonmal.
Aber aus irgendeinem Grund funktioniert es nicht. Wenn ich den Button an 
PE6 drücke ändert sich leider nichts.

> Stefan F. schrieb:
>> Dirk schrieb:
>>> .org nt6addr *1
>>> probiert?
>>
>> Ja, brachte leider nichts.
>
> Falscher Controller eingestellt?

Habe es gerade noch mal kontrolliert, ist auch der Richtige.

von MWS (Gast)


Lesenswert?

SEI steht übrigens falsch, besonders da temp auch in der ISR Verwendung 
findet. Nimm an dass EIFR.INTF6 zu diesem Zeitpunkt gesetzt ist, dann 
sollte der Controller unmittelbar nach SEI den Int6-Vektor ausführen.
Macht er das, dann wäre alles noch gut.

Wenn er jedoch noch ldi temp, 1<<SE abarbeitet und erst dann den Vektor 
anspringt, dann wird temp zerstört und mit dem Inhalt des PORTA geladen.

Dieser Inhalt setzt nicht mehr MCUCR.SE, sondern macht irgendwas anderes 
recht Lustiges.

Stefan F. schrieb:
> sei
> ldi    temp, 1<<SE

> int6:
> in     temp, PORTA

Sowas vermeidet man, indem man a) INTF6 vor Freigabe der Interrupts 
löscht, b) Konfigurationssequenzen atomar macht (CLI/SEI) oder c) SEI 
erst dann schreibt, wenn man mit der Konfiguration durch ist. Auch a, b 
und c zusammen ist nicht verkehrt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Stefan F. schrieb:
> Aber aus irgendeinem Grund funktioniert es nicht. Wenn ich den Button an
> PE6 drücke ändert sich leider nichts.

 Dann lese doch in einem Loop mit PINE.6 was dein uC am Pin sieht und
 zeige es mit LED an PORTA (LED=ON / Pin = 1). Oder umgekehrt, egal.

 Wenn die LED nicht auf Button reagiert, stimmt irgendetwas mit Pull-Up
 bzw. Eingang nicht.
 Wenn die LED reagiert, stimmt irgendetwas mit deinem INT nicht.

 So schwer ?

 P.S.
 Bedenke aber, dass 0xFF von uC als NOP gesehen wird.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> ... bin nun bei Interrupts angelangt.

Das heißt, dass zuvor (auf diesem uC) der Aufruf (und die Rückkehr aus) 
einer normalen Subroutine funktioniert hat?

Beitrag #5584533 wurde vom Autor gelöscht.
von Dirk B. (Gast)


Lesenswert?

Marc V. schrieb:

>  Bedenke aber, dass 0xFF von uC als NOP gesehen wird.
das könnte zumindest die Belanglosigkeit *1/*2 in dem frühem Stadium 
erklären wenn, bzw. da mangels Alternativen, $ffff (eigentlich UOP) als 
NOP ($0000) gesehen wird und interessante Folgen (bei allen ints 
passiert das gleiche, obwohl es funktioniert hat) verursachen.

Noch ein Bedenkungsvorschlag:
falls sich der Bezeichner EICRB als minderwertig (<$40) herausstellen 
sollte bspw. als $3a  Wert, dann  wäre
out    DDRA, temp; $1a sts $1a+$20,temp
und
sts    EICRB, temp;$3a out $1a,temp
äquivalent und
out   EICRB, temp;$3a
für den mutmaßlichen Plan geeigneter

von Stefan F. (stefan_h1)


Lesenswert?

Dirk B. schrieb:
> Marc V. schrieb:
>
>>  Bedenke aber, dass 0xFF von uC als NOP gesehen wird.
> das könnte zumindest die Belanglosigkeit *1/*2 in dem frühem Stadium
> erklären wenn, bzw. da mangels Alternativen, $ffff (eigentlich UOP) als
> NOP ($0000) gesehen wird und interessante Folgen (bei allen ints
> passiert das gleiche, obwohl es funktioniert hat) verursachen.
>
> Noch ein Bedenkungsvorschlag:
> falls sich der Bezeichner EICRB als minderwertig (<$40) herausstellen
> sollte bspw. als $3a  Wert, dann  wäre
> out    DDRA, temp; $1a sts $1a+$20,temp
> und
> sts    EICRB, temp;$3a out $1a,temp
> äquivalent und
> out   EICRB, temp;$3a
> für den mutmaßlichen Plan geeigneter


Danke für euren Input. Dadurch hab ich den Fehler gefunden.

Statt
1
lds    temp, EICR
2
ori    temp, 1<<ISC61
3
sts    EICRB, temp

gehört nämlich.
1
in    temp, EICR
2
ori    temp, 1<<ISC61
3
out    EICRB, temp

Wieder was gelernt.
Danke nochmal allen die mir geholfen haben.

von S. Landolt (Gast)


Lesenswert?

Dass das der ursprüngliche Fehler gewesen sein soll, kann ich nicht 
glauben. Wie Dirk B. schrieb, wird mit
1
lds    temp, EICRB
2
ori    temp, 1<<ISC61
3
sts    EICRB, temp
DDRA verändert, da dieses jedoch bereits auf 0xFF steht, bewirkt das 
ori gar nichts. Und dass EICRB nicht beschrieben wird, heißt 
lediglich, dass INT6 nicht durch 'falling edge', sondern durch 'low 
level' getriggert wird. Statt einige Male durch das Prellen wird also 
vielfach, solange der Taster gedrückt ist, getriggert, wie ließe sich 
damit die Aussage

> Stattdessen leuchtet PORTA die ganze Zeit, nur beim Interrupt
> wird das Muster 0x55 angezeigt.

erklären?

von Karl M. (Gast)


Lesenswert?

Hallo,

wenn man mal endlich den kompletten Code mit allen Zeilen sehen könnte.
Dann noch das Makefile dazu und jeder könnte gegen testen.

Wir verwenden solch zwei Macros für das Lesen und Setzen der Register, 
dann spart man sich das nachsehen für jeden AVR µC in der 
Registerbeschreibung.
1
.macro xIn
2
.if @1<64
3
in    @0,@1
4
.else
5
lds    @0,@1
6
.endif
7
.endmacro
8
9
.macro xOut
10
.if @0<64
11
out    @0,@1
12
.else
13
sts    @0,@1
14
.endif
15
.endmacro

von S. Landolt (Gast)


Lesenswert?

... was sich speziell beim ATmega128 empfiehlt, denn hier ist die 
Zuordnung doch etwas wirr, so liegt z.B., wie gesehen, EICRB mit 0x3A im 
I/O-Bereich, EICRA hingegen ist mit 0x6A 'memory mapped'.

von Dirk B. (Gast)


Lesenswert?

S. Landolt schrieb:
> Dass das der ursprüngliche Fehler gewesen sein soll, kann ich nicht
> glauben.
bislang sind 3 bekannt:
1)INT6addr*2: wg. NOP Lesung von UOP wohl praktisch folgenlos
2)praktisch Level statt Flanke (aktuell bzw. aktuell nicht mehr)
3) SEI zum unglücklichen Zeitpunkt. Getriggert könnte MCUCR ca. mit 
$55-1 initialisiert werden und das MCUCR hat auch 
Interruptvectorselect...für 'ne abschließende Erklärung noch zu knapp, 
aber evtl. interrupt via bootloadervector --> Nop/UOP-Slide-->reset .org 
0 (aus vector_table_0)
vom Gefühl dürfte das Muster $55 nicht konstant angezeigt worden sein, 
sondern nur sichtbar. Vielleicht fehlt noch Vcc o.ä. Kleinigkeiten, was 
auch schwer erklärbare Fehler/Funktionieren verursachen kann.

>...hier ist die Zuordnung doch etwas wirr
nette Verharmlosung: praktisch sind Bezeichner die ihre Funktion/Zweck 
(Vereinfachung kontrollierter Programmierung) nicht erfüllen ein 
heftiger Naming-Bug, allerdings hätte die Behebung für (A)SM bspw. 
EICRA_m EICRB DDRA DDRF_m Bugs für (B)asic,(C),Pascal verursacht und der 
von Karl vorgestellte mini-compiler kann den BUG für die erste Sprache 
ASM des ABC zumindest etwas verharmlosen ;-
Kompatibilität geht manchmal sehr spezielle Wege...

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.