PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer0-Int: TOV0 wird nicht gesetzt



NRicola
18.04.2016, 11:57
Hallo zusammen,

ich versuche mich mal mit den Grundlagen der ASM-Programmierung und bin auf ein Problem gestoßen. In Anlehnung an ein Video-Tutorial für ein atmega8 versuche ich mit einem atmega32 nun per Timer0-Overflow-Int eine LED auf dem rncontrol 1.4 zu schalten. Der Code ist eigentlich copy&paste. Dennoch tut es nicht - weder im AVRstudio-Debugger, noch in Hardware. Im Debugger wird TOV0 trotz Overflow von TCNT0 nicht gesetzt (AVRstudio-Einstellung: Mask Interrupts While Stepping=false).

Ich bin für jede Hilfe dankbar!

Grüß
NRicola



.include "m32def.inc"
.org 0x000
begin:
;--------------------------------------------------
rjmp main ; RESET External Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, and JTAG AVR Reset
reti ; INT0 External Interrupt Request 0
reti ; INT1 External Interrupt Request 1
reti ; INT2 External Interrupt Request 2
reti ; TIMER2 COMP Timer/Counter2 Compare Match
reti ; TIMER2 OVF Timer/Counter2 Overflow
reti ; TIMER1 CAPT Timer/Counter1 Capture Event
reti ; TIMER1 COMPA Timer/Counter1 Compare Match A
reti ; TIMER1 COMPB Timer/Counter1 Compare Match B
reti ; TIMER1 OVF Timer/Counter1 Overflow
reti ; TIMER0 COMP Timer/Counter0 Compare Match
rjmp timer_int ; TIMER0 OVF Timer/Counter0 Overflow
reti ; SPI, STC Serial Transfer Complete
reti ; USART, RXC USART, Rx Complete
reti ; USART, UDRE USART Data Register Empty
reti ; USART, TXC USART, Tx Complete
reti ; ADC ADC Conversion Complete
reti ; EE_RDY EEPROM Ready
reti ; ANA_COMP Analog Comparator
reti ; TWI Two-wire Serial Interface
reti ; SPM_RDY Store Program Memory Ready
;--------------------------------------------------

main:

ldi r16, high(RAMEND)
out SPH, r16
ldi r16, low(RAMEND)
out SPL, r16

ldi r16, 0b11111111 ; Ausgänge=1 Eingänge=0
out DDRC, r16 ; Ausgeben

ldi r16, 0x00
out PortC, r16

; Timer und Interrupt konfigurieren
ldi r16, 6 ; 8bit-Timer-Register vorladen
out TCNT0, r16 ; so sind nur 256-6 / (16MHz/64) = 1ms zu zählen
ldi r16, 0b00000011 ; CS00 & CS01 setzen: Clock/64
out TCCR0, r16
ldi r16, 0b00000001 ; TOIE0 (Timer0-Overflow-Int) setzen
out TIMSK, r16

sei ; Interrupts aktivieren

mainloop:
nop
rjmp mainloop

timer_int:
rcall LEDswitch
ldi r16, 6
out TCNT0, r16
reti

LEDswitch:
in r16, PortC
ldi r17, 0b10000000 ; Bit 7 (LED)
eor r16, r17 ; invertieren
out PortC, r16
ret

Searcher
18.04.2016, 18:26
Hallo,
ich kann keinen Fehler im Programm feststellen. Ich nutze kein AVR-Studio, habe aber schon öfter gelesen, daß es gewisse Einstellungen gibt, um im Simulator erfolgreich Interrupts zu simulieren.

In der HW sollte es laufen. Wie stellst du fest, daß kein Interrupt kommt?

Nach Schaltplan zum RN-Control gibt es switches vor den LEDs. Ist der für PC7 geschlossen und auch nichts anderes an PC7 angeschlossen (außer dem Eingang vom L293)?

Die LED blinkt mit 500Hz (wenn ich richtig gerechnet habe) - da sieht man eigentlich nur ein Glimmen aber kein EIN/AUS.

Irgendwas Besonderes bei den Fuses? JTAG abgeschaltet?

Gruß
Searcher

NRicola
18.04.2016, 20:03
Hallo Searcher,

bei den Fuses gibt es (gefühlt) nichts besonderes, JTAG ist aktiviert. Im davorigen Turorial mit wait-Funktionen blinkte die LED fleißig vor sich hin. Auch hier kann ich beim Initialisieren die LEDs nach Belieben an- und aus schalten. Bei dem Code oben ist die auf Bit7 erstmal aus. Würde der Interrupt auslösen, wäre sie zumindest sichtbar. Leider bleibt das aus.
Ich habe gerade auch mal (nur, um auch ganz sicher zu gehen) auch den atmega getauscht. Das hat allerdings auch nichts gebracht.

Dass der TOV0 nicht gesetzt wird, habe ich dem Debugger entnommen, bzw. der springt dann nicht in die LEDswitch-Funktion. Dass es in Hardware dann den gleichen Grund hat, warum die LED nicht an geht, das vermute ich jetzt lediglich.
Dieses Flag in Hardware zu überprüfen könnte etwas kniffelig werden, oder?
Ich hatte jetzt mal die mainloop zu folgendem abgeändert


mainloop:
in r16, TCNT0
ldi r17, 128
cp r16,r17
brcs LEDswitch
clc
rjmp mainloop
Aber ich zweifle gerade noch daran, dass das überhaupt korrekt ist, um TCNT0 auszulesen. Nimmt r17 Grenzwerte an (10 oder 240), dann sehe ich keine Helligkeitsunterschiede der LED.

Hast du/habt ihr noch eine Idee, wie man das in Hardware überprüfen kann, was der so treibt?

Vielen Dank und Grüß
NRicola


Fuses:


OCDEN
JTAGEN x
SPIEN x
CKOPT
EESAVE
BOOTSZ1
BOOTSZ0
BOOTRST
BODLEVEL x
BODEN x
SUT1 x
SUT0
CKSEL3
CKSEL2 x
CKSEL1 x
CKSEL0
(hfuse: 9F, lfuse: 19)


Ergänzung: In dem Tutorial (https://www.youtube.com/watch?v=-Rntk_PjBPE&list=PLJ1mg9IWNoIDCP_2nV5AKcSJSXHqWof0Z&index=9) funktioniert das auch im Simulator von AVRstudio problemlos. Sehr merkwürdig, wie ich finde... :?

Sisor
18.04.2016, 21:14
Ich hab mir den Code nicht durchgeguckt, aber ich hatte mal genau das gleiche Verhalten: Im Simulator liefs, in Echt nicht.
Grund war die falsch Reihenfolge des Register-Setzens. Erst musste der entsprechende Bereich enabled werden, damit dieser bestromt wurde und so für die weiteren Register-Setzbefehle empfänglich war.

Searcher
19.04.2016, 08:40
Hi,
möglicherweise steht der Interruptvektor für TIMER0 OVF nicht an der richtigen Stelle. An .org 0x000, Programmadresse $000 steht der rjmp zu main. Es folgen viele RETI, die aber jeweils auch nur 2 Byte belegen. Also nur einer Erhöhung des Programmcounters um eins bedürften. Nach der Interruptvectortabelle im Datenblatt zum Mega32 sollte der TIMER0 OVF auf Program Address $016 stehen. Nach deiner Tabelle im Programm komme ich nur auf Program Address $00A.

Jetzt kenne ich den AVR Studio/Assembler nicht und folgende Syntax könnte nicht stimmen:confused: . Um den Vector sicher auf die richtige Speicheradresse zu bringen könntest Du die Tabelle eventuell so aufbauen:



.org 0x000
begin:
;--------------------------------------------------
rjmp main ; RESET External Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, and JTAG AVR (http://www.rn-wissen.de/index.php/AVR-Einstieg_leicht_gemacht) Reset
.org 0x002
reti ; INT0 External Interrupt Request 0
.org 0x004
reti ; INT1 External Interrupt Request 1
.org 0x006
reti ; INT2 External Interrupt Request 2
.org 0x008
reti ; TIMER2 COMP Timer/Counter2 Compare Match
.org 0x00A
reti ; TIMER2 OVF Timer/Counter2 Overflow
.org 0x00C
reti ; TIMER1 CAPT Timer/Counter1 Capture Event
.org 0x00E
reti ; TIMER1 COMPA Timer/Counter1 Compare Match A
.org 0x010
reti ; TIMER1 COMPB Timer/Counter1 Compare Match B
.org 0x012
reti ; TIMER1 OVF Timer/Counter1 Overflow
.org 0x014
reti ; TIMER0 COMP Timer/Counter0 Compare Match
.org 0x016
rjmp timer_int ; TIMER0 OVF Timer/Counter0 Overflow


Gruß
Searcher

NRicola
19.04.2016, 22:55
Hallo zusammen,

@Sisor: ich hatte dann gestern noch mit den Reihenfolgen herumgespielt. Leider brachten alle möglichen Anordnungen keinerlei Besserung.
@Searcher: jup, das war's tatsächlich! Mit dem Code zu


.include "m32def.inc"
.org 0x000 ; Interruptstartposition: 0x000
begin:
;--------------------------------------------------
rjmp main ; RESET External Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, and JTAG AVR Reset
.org 0x016
rjmp timer_int ; TIMER0 OVF Timer/Counter0 Overflow
;--------------------------------------------------

umgeschrieben läuft es nun. Das wirft natürlich die folgende Fragen auf: Woher weiß ich wieviel Speicher ein Befehl einnimmt? Dem Datenblatt konnte ich jetzt erstmal nur entnehmen, wieviele Clock cycles er benötigt. Benötigen alle Befehle 2 Bytes oder gibt es da Unterschiede?

Sehr toll erstmal, hab vielen Dank!

Grüß
NRicola

Searcher
20.04.2016, 05:36
Hallo NRicola,
prima daß es läuft.



Das wirft natürlich die folgende Fragen auf: Woher weiß ich wieviel Speicher ein Befehl einnimmt? Dem Datenblatt konnte ich jetzt erstmal nur entnehmen, wieviele Clock cycles er benötigt. Benötigen alle Befehle 2 Bytes oder gibt es da Unterschiede?

Braucht man selten. Im Datenblatt schaue ich zum Befehlssatz nur manchmal nach, ob es einen Befehl im entsprechenden AVR gibt und ob ein I/O Register anhand seiner Adresse per IN/OUT erreichbar ist oder doch LDS/STS benutzt werden muß. MUL zB gibt es bei den (meisten) ATtiny nicht.

Sonst nehme ich fast nur: http://www.atmel.com/images/atmel-0856-avr-instruction-set-manual.pdf
Am Schluß einer Befehlsbeschreibung steht "Words" vor "Cycles". Words ist die Befehlslänge (1 word gleich 2 bytes)

Fast alle Befehle beim AVR belegen 1 word im Speicher. Ganz wenige wie JMP belegen 2 words. Ich habe bisher nur 1 oder 2 word Befehle gesehen.

Gruß
Searcher

oberallgeier
20.04.2016, 08:51
.. Woher weiß ich wieviel Speicher ein Befehl einnimmt? .. Datenblatt .. nur .. wieviele Clock cycles er benötigt ..Hallo NRicola,
meine Assemblerprogramme bearbeite ich mit AVRStudio4. Das Studio7 hat ne fast deckungsgleiche Hilfe die aber nachinstalliert werden muss.

Im Studio4 gibts in der Menuezeile die Hilfe: [Help] -> [Assembler Help] - - - und schon kommt ein Fenster mit ALLEN Befehlswörtern (z.B. -> Zu suchendes Schlüsselwort) in dem Du für jeden möglichen Befehl die komplette Beschreibung bekommst. Hier das Beispiel für SBI :

SBI - Set Bit in I/O Register


Description:

Sets a specified bit in an I/O register. This instruction operates on the lower 32 I/O registers - addresses 0-31.

Operation:
(i)I/O(A,b) ← 1

Syntax: Operands: Program Counter:
(i)SBI A,b 0 ≤ A ≤ 31, 0 ≤ b ≤ 7 PC ← PC + 1

16-bit Opcode:


1001
1010
AAAA
Abbb




Status Register (SREG) and Boolean Formula:



I
T
H
S
V
N
Z
C


-
-
-
-
-
-
-
-



Example:
out $1E,r0 ; Write EEPROM address
sbi $1C,0 ; Set read bit in EECR
in r1,$1D ; Read EEPROM data

Words: 1 (2 bytes)
Cycles: 2
Cycles xmega/AVR8L: [I]1

Natürlich steht da drin auch z.B. die Länge des Befehls, der Maschinencode für den Befehl selbst sowie die Ausführungsdauer in Maschinencyclen :

16-bit Opcode:


1001
1010
AAAA
Abbb



...
Words: 1 (2 bytes)
Cycles: 2
Etwas anders ist das beim Programmieren von C im Studio, dort kannst Du das ohne Sonderfenster im *.lls-File lesen. Den File "deinCprogramm.lls" im Editor, z.B. notepad, öffnen:

ALCo.elf: file format elf32-avr

Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000b08 00800100 000048fe 000049b2 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 000048fe 00000000 00000000 000000b4 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .bss 0000037a 00800c08 00800c08 000054ba 2**0
ALLOC
3 .eeprom 00000315 00810000 00810000 000054ba 2**0
CONTENTS, ALLOC, LOAD, DATA
4 .debug_aranges 00000020 00000000 00000000 000057cf 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_pubnames 000008ac 00000000 00000000 000057ef 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_info 00002c39 00000000 00000000 0000609b 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_abbrev 000003e9 00000000 00000000 00008cd4 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_line 000039cd 00000000 00000000 000090bd 2**0
CONTENTS, READONLY, DEBUGGING
9 .debug_frame 000005a0 00000000 00000000 0000ca8c 2**2
CONTENTS, READONLY, DEBUGGING
10 .debug_str 000007bc 00000000 00000000 0000d02c 2**0
CONTENTS, READONLY, DEBUGGING
11 .debug_loc 000013b9 00000000 00000000 0000d7e8 2**0
CONTENTS, READONLY, DEBUGGING
12 .debug_ranges 000001b0 00000000 00000000 0000eba1 2**0
CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
0: 0c 94 46 00 jmp 0x8c ; 0x8c <__ctors_end>
4: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
8: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
10: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
14: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
18: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
1c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
20: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
24: 0c 94 45 0a jmp 0x148a ; 0x148a <__vector_9>
28: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
2c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
30: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
34: 0c 94 e6 06 jmp 0xdcc ; 0xdcc <__vector_13>
38: 0c 94 cc 09 jmp 0x1398 ; 0x1398 <__vector_14>
3c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
40: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
44: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
48: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
4c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
50: 0c 94 a4 00 jmp 0x148 ; 0x148 <__vector_20>
54: 0c 94 d3 00 jmp 0x1a6 ; 0x1a6 <__vector_21>
58: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
5c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
60: 0c 94 26 0b jmp 0x164c ; 0x164c <__vector_24>
64: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
68: 0c 94 48 01 jmp 0x290 ; 0x290 <__vector_26>
6c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
70: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
74: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
78: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
7c: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
80: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
84: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>
88: 0c 94 65 00 jmp 0xca ; 0xca <__bad_interrupt>

0000008c <__ctors_end>:
8c: 11 24 eor r1, r1
8e: 1f be out 0x3f, r1 ; 63
90: cf ef ldi r28, 0xFF ; 255
92: d0 e4 ldi r29, 0x40 ; 64
94: de bf out 0x3e, r29 ; 62
96: cd bf out 0x3d, r28 ; 61

00000098 <__do_copy_data>:
98: 1c e0 ldi r17, 0x0C ; 12
9a: a0 e0 ldi r26, 0x00 ; 0
9c: b1 e0 ldi r27, 0x01 ; 1
9e: ee ef ldi r30, 0xFE ; 254
a0: f8 e4 ldi r31, 0x48 ; 72
a2: 00 e0 ldi r16, 0x00 ; 0
a4: 0b bf out 0x3b, r16 ; 59
a6: 02 c0 rjmp .+4 ; 0xac <__do_copy_data+0x14>
a8: 07 90 elpm r0, Z+
aa: 0d 92 st X+, r0
ac: a8 30 cpi r26, 0x08 ; 8
ae: b1 07 cpc r27, r17
b0: d9 f7 brne .-10 ; 0xa8 <__do_copy_data+0x10>

000000b2 <__do_clear_bss>:
b2: 1f e0 ldi r17, 0x0F ; 15
b4: a8 e0 ldi r26, 0x08 ; 8
b6: bc e0 ldi r27, 0x0C ; 12
b8: 01 c0 rjmp .+2 ; 0xbc <.do_clear_bss_start>

000000ba <.do_clear_bss_loop>:
ba: 1d 92 st X+, r1

000000bc <.do_clear_bss_start>:
bc: a2 38 cpi r26, 0x82 ; 130
be: b1 07 cpc r27, r17
c0: e1 f7 brne .-8 ; 0xba <.do_clear_bss_loop>
c2: 0e 94 1a 22 call 0x4434 ; 0x4434 <main>
c6: 0c 94 7d 24 jmp 0x48fa ; 0x48fa <_exit>

000000ca <__bad_interrupt>:
ca: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

000000ce <init_uart0>:
// count up and wrap around

// ================================================== ============================ =
void init_uart0( u16 bauddivider )
{
UBRR0H = bauddivider >> 8;
ce: 90 93 c5 00 sts 0x00C5, r25
UBRR0L = bauddivider; // set baud rate
d2: 80 93 c4 00 sts 0x00C4, r24
UCSR0A = 0; // no U2X, MPCM
d6: 10 92 c0 00 sts 0x00C0, r1
UCSR0C = 1<<UCSZ01^1<<UCSZ00 // 8 Bit
da: 86 e0 ldi r24, 0x06 ; 6
dc: 80 93 c2 00 sts 0x00C2, r24
#ifdef URSEL0
^1<<URSEL0 // if UCSR0C shared with UBRR0H
#endif
;
UCSR0B = 1<<RXEN0^1<<TXEN0^ // enable RX, TX
e0: 88 e9 ldi r24, 0x98 ; 152
e2: 80 93 c1 00 sts 0x00C1, r24
1<<RXCIE0; // enable RX interrupt
rx_in = rx_out; // set buffer empty
e6: 80 91 8b 0c lds r24, 0x0C8B
ea: 80 93 8a 0c sts 0x0C8A, r24
tx_in = tx_out;
ee: 80 91 0d 0d lds r24, 0x0D0D
f2: 80 93 0c 0d sts 0x0D0C, r24
}
f6: 08 95 ret

000000f8 <ukbhit0>:
// ================================================== ============================ =
Da siehst Du am Fortschritt des Programmcounters (Beispiel rot markiert) - ob der um zwei oder vier Registerzellen weiterzählt (na ja, müsste ausführlicher beschrieben werden) - die Länge des Befehls.

NRicola
20.04.2016, 21:33
Hallo Searcher, Hallo Oberallgeier,

habt vielen Dank! Eure Hinweise helfen sehr für einen guten Einstieg in die Sache. Die Studio-Hilfe habe ich soeben um diese Bibliothek ergänzt. Damit sollte ich für die kommenden Programmierversuche und Tutorials gut gerüstet sein. :)

Dank nochmal und Grüß
NRicola