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
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?
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.
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
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).
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