Forum: Mikrocontroller und Digitale Elektronik Problem: INT0/1 auf Arduino


von Simon E. (eingehirner)


Lesenswert?

Hallo zusammen,

ich komme nicht mehr weiter. Eigentlich ein einfaches Problem: den INT0 
und/oder INT1 auf einem Arduino Uno mit ATmega328P zum Laufen zu 
kriegen. Mein Code:
1
.include "../m328Pdef.inc"
2
3
.CSEG ; Program and flash data section
4
5
.org 0x0000     jmp     RESET           ; Reset Handler
6
.org 0x0002     jmp     EXT_INT0        ; IRQ0 Handler
7
.org 0x0004     jmp     EXT_INT0        ; IRQ1 Handler
8
...
9
10
.org 0x0034
11
RESET:
12
; Init stack pointer
13
  ldi r16, HIGH(RAMEND)
14
  out SPH, r16
15
  ldi r16, LOW(RAMEND)
16
  out SPL, r16
17
18
  ; Init INT0 pin
19
  cbi DDRD, 2 ; input
20
  sbi PORTD, 2 ; pull-up ON
21
22
  ; Init INT1 pin
23
  cbi DDRD, 3 ; input
24
  sbi PORTD, 3 ; pull-up ON
25
26
  ; Init LED pin
27
  sbi DDRB, 5 ; output
28
  cbi PORTB, 5 ; set to OFF
29
30
  ; Init counter pins PC0-3
31
  sbi DDRC, 0
32
  sbi DDRC, 1
33
  sbi DDRC, 2
34
  sbi DDRC, 3
35
36
  cbi PORTC, 0
37
  cbi PORTC, 1
38
  cbi PORTC, 2
39
  cbi PORTC, 3
40
41
  ; Interrupt register EICRA/B
42
  ; EICRA:    ISC11:0   11
43
  ;           ISC01:0   11
44
  ; EIMSK:    INT1      1 (enabled)
45
  ;           INT0      1 (enabled)
46
47
  lds r16, EICRA
48
  ori r16, 0x0F ; ISCx1:0 = 0b11
49
  sts EICRA, r16
50
51
  lds r16, EIMSK
52
  ori r16, 0x03 ; INT0/1 enable
53
  sts EIMSK, r16
54
55
  ; Activate interrupts
56
  sei
57
58
Loop:
59
  ; on-board LED on half brightness to show the loop is running
60
  sbi PORTB, 5
61
  nop
62
  nop
63
  nop
64
  nop
65
  nop
66
  nop
67
  nop
68
  nop
69
  cbi PORTB, 5
70
  nop
71
  nop
72
  nop
73
  nop
74
75
  rjmp Loop
76
; ======== ISR ===========
77
EXT_INT0:
78
  push r16
79
  in r16, SREG
80
  push r16
81
82
  ; Just count up in PORTC0-3
83
  in r16, PORTC
84
  inc r16
85
  andi r16, 0x0F
86
  out PORTC, r16
87
88
  pop r16
89
  out SREG, r16
90
  pop r16
91
reti

Nicht extrem komplex, sollte man meinen. Hab ich irgendwo ein massives 
Brett vor dem Kopf?
- Spannungsversorgung: stabil (USB)
- Pin D2/D3 lebendig: ja (kann als Nicht-Interrupt sowohl Signale 
erkennen als auch ausgeben)
- Loop läuft (LED gedimmt an)
- getestete Modi: Trigger bei level low, bei any logical change, bei 
falling flank und rising flank
- versuchte Aktivierung mit Jumperkabel an GND, an VCC
- mit und ohne internem Pull-Up getestet
- mit externem Pull-Down von 4,7kO getestet
- Interrupt-Vektoren sind an der richtigen Stelle (mit TIM0_OVF 
getestet)

Der Arduino hat einen Bootloader drauf, BOOTRST-Fuse ist programmiert, 
Bootsize ist 256 words; trotzdem ist mein RESET-Sprungbefehl an .org 
0x0000 (statt, wie im AVR-Datenblatt beschrieben, bei 0x3C00). Wenn ich 
ihn auf 0x3C00 umschreibe, läuft mein Programm nicht mehr und macht 
merkwürdige Sprünge, deshalb hab ich's (wider besseres Wissen(?)) so 
gelassen. Da der TIM0_OVF korrekt funktioniert, sollten INT0 und INT1 
das auch tun - oder?

(Dass bei INT0 und INT1 dieselbe ISR angesprungen wird, ist Absicht.)

Hat irgendwer eine Idee oder sieht sofort, was ich nach einer Woche 
Suchen noch nicht entdeckt hab? Macht der Arduino-Bootloader 
irgendwelche komischen Sachen, die ich später nicht mehr umdefinieren 
kann?

Viele Grüsse,
Simon

von Wolfgang (Gast)


Lesenswert?

Simon E. schrieb:
> Hat irgendwer eine Idee oder sieht sofort, was ich nach einer Woche
> Suchen noch nicht entdeckt hab?

Im Simulator verhält sich das Programm so wie von dir erwartet?

von Einer K. (Gast)


Lesenswert?

Simon E. schrieb:
> Der Arduino hat einen Bootloader drauf, BOOTRST-Fuse ist programmiert,
> Bootsize ist 256 words; trotzdem ist mein RESET-Sprungbefehl an .org
> 0x0000 (statt, wie im AVR-Datenblatt beschrieben, bei 0x3C00).

Das ist schon OK so.
Bei 0x3C00 wohnt der Bootloader.

Das Lable RESET: sollte nicht RESET heißen, sondern Init !
Dann wird klarer, was es tut.

von Chris H. (Firma: Selbständig Denkender) (keiningenieur)


Lesenswert?

Simon E. schrieb:
> lds r16, EIMSK
>   ori r16, 0x03 ; INT0/1 enable
>   sts EIMSK, r16

Die EIMSK liegt unter $3f und muss mit in/out angesprochen werden

Simon E. schrieb:
> sbi DDRC, 0
>   sbi DDRC, 1
>   sbi DDRC, 2
>   sbi DDRC, 3
>
>   cbi PORTC, 0
>   cbi PORTC, 1
>   cbi PORTC, 2
>   cbi PORTC, 3

so kompliziert 4 Zeilen reichen auch

ldi r16,$0e
out ddrc, r16

clr  r16
out  PortC,r16

Simon E. schrieb:
> ; Init INT0 pin
>   cbi DDRD, 2 ; input
>   sbi PORTD, 2 ; pull-up ON
>
>   ; Init INT1 pin
>   cbi DDRD, 3 ; input
>   sbi PORTD, 3 ; pull-up ON

  ldi r16,(1<<pd3 | 1<<pd2)
  out portd,r16

: Bearbeitet durch User
von Simon E. (eingehirner)


Lesenswert?

Chris H. schrieb:
> Die EIMSK liegt unter $3f und muss mit in/out angesprochen werden

Das war's. Hammer! Brett vorm Kopf weg! Vielen, vielen Dank!

Beim Compilieren (mit avrasm2.exe) kommt kein Fehler, wenn ich mit 
lds/sts arbeite. Gibt es irgendeine "sinnvolle" Anwendung dafür, 
Register unter 0x3F00 damit anzusprechen?

Und: Woher weiss man sowas? Bisher war ich davon ausgegangen, dass 
in/out einfach effizientere, sprich schnellere Befehle sind, die man 
deshalb vorzugsweise nimmt (aber nicht nehmen muss). Die Doku von 
Atmel/Microchip gibt da nicht viel her:

IN:
1
Loads data from the I/O Space (Ports, Timers, Configuration registers etc.) into register Rd in the register file.
2
3
Operation:
4
5
(i)Rd ← I/O(A)
6
7
Syntax: Operands: Program Counter:
8
9
IN Rd,A 0 ≤ d ≤ 31, 0 ≤ A ≤ 63 PC ← PC + 1

LDS:
1
Loads one byte from the data space to a register. For parts with SRAM, the data space consists of the register file, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space consists of the register file only. The EEPROM has a separate address space.
2
3
A 16-bit address must be supplied. Memory access is limited to the current data segment of 64K bytes. The LDS instruction uses the RAMPD register to access memory above 64K bytes. To access another data segment in devices with more than 64K bytes data space, the RAMPD in register in the I/O area has to be changed.
4
5
This instruction is not available in all devices. Refer to the device specific instruction set summary. In particular, notice that ATtiny10-based devices use the LDS instead of this instruction.
6
7
Operation:
8
9
(i)Rd ← (k)
10
11
Syntax: Operands: Program Counter:
12
13
(i)LDS Rd,k 0 ≤ d ≤ 31, 0 ≤ k ≤ 65535 PC ← PC + 2
14
                        AAAAAAAAAAAAA

Oder kommt es darauf an?
1
A 16-bit address must be supplied.
Aber wie berücksichtigt man das?

Viele Grüsse,
Simon

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Simon E. schrieb:
> Bisher war ich davon ausgegangen, dass
> in/out einfach effizientere, sprich schnellere Befehle sind, die man
> deshalb vorzugsweise nimmt

Wenn du dir das Datenblatt, und hier vor allem die Register Summary 
anschaust, sieht du, das Register unterhalb der Adresse 0x3F zwei 
Adressen haben. Die eine gilt für die Addressierung mit IN/OUT, die 
andere für STS/LDS. Du kannst EIMSK mit STS und mit IN/OUT ansprechen, 
musst aber dann die andere Adresse benutzen, die Definition im Header 
für EIMSK gilt für In/Out, wimre. Das ganze kommt daher, das heutige AVR 
viel mehr Register haben, die mit In/Out nicht mehr erreichbar wären. 
(und auch heute noch nicht bitadressierbar sind).

: Bearbeitet durch User
von Chris H. (Firma: Selbständig Denkender) (keiningenieur)


Lesenswert?

https://www.sparkfun.com/datasheets/Components/SMD/ATMega328.pdf

Datenblatt S.20 I/O-Memory und
RegisterSummery S.428 mal lesen ;)

von Simon E. (eingehirner)


Lesenswert?

Jep:
1
When addressing I/O Registers as data space using LD and ST instructions, 0x20 must be added to these addresses.

Nur dass ich unter "I/O registers" immer lediglich die Ports verstanden 
hab...

Super, danke für eure Hilfe! Ist lang her, dass ich das vollständig 
gelesen hab und damals vermutlich eher für den ATTiny2313, mit dem ich 
mehr Projekte realisiert hab... Immer dieser Tradeoff zwischen Effizienz 
und Korrektheit :-/

Jedenfalls läuft das Tierchen jetzt :-)

Viele Grüsse,
Simon

: Bearbeitet durch User
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.