TIMER0 Normal Mode bei 2560

OP #5485317
Lesenswert?

Hallo liebe Leute,

ich hätte da mal eine Frage an die ATmega Cracks... :)

Ich programmiere gerade mit einem Arduino mit dem ATmega2560 per Atmel 
Studio in Assembler, um mich da ein wenig einzuarbeiten.

Konkret geht es um die Timer.

Ich habe (nachfolgend) ein Programm, das den TIMER0 nutzt. Per ISR wird 
ein Ausgangspin (Digital Pin 11) getoggelt UND per CompareMatch-Einheit 
soll der zugehörige Ausgang OC0A (Digital Pin 13) im Toggle Modus 
betrieben werden.

Der ISR-Teil läuft auch, aber am Digital Pin 13 (OC0A) erscheint NICHT 
das Rechtecksignal...

Sieht jemand einen Grund dafür?

Eine weitere Frage hätte ich noch...bei der Initialisierung von TIMSK0 
funktioniert der Befehl "out" nicht...ich muss hier statt dessen "sts" 
verwenden...das ist mir völlig unklar...

Nachtrag: Ich verwende das Atmel Studio in der Version 7.0.1931 mit den 
installierten Packages in der Version 7.0.122
Der Assembler meldet mir bei Verwendung von out bei dem Beschreiben von 
TIMSK0 den Fehler "Operand 1 out of range: 0x6e"


LG Uwe
1
;==============================================================================
2
; Normal-Mode.asm
3
; Verwendet Digital Pin 13 für OC0A und Digital Pin 11 per Overflow Interrupt
4
;
5
; Using the Output Compare to generate waveforms in Normal mode is not
6
; recommended, since this will occupy too much of the CPU time.
7
; (Datasheet Seite 120)
8
;
9
; Created: 12.07.2018 18:40:14
10
; Author : Uwe
11
;==============================================================================
12

13
.ORG 0x0000            ; Nachfolgenden Programmcode
14
                ; ab der Speicherstelle
15
                ; 0x0000 ablegen
16

17
;==============================================================================
18
; Interrupt-Handler
19
;==============================================================================
20
  jmp    INIT        ; Interruptvektoren überspringen
21
                ; und zum Hauptprogramm
22
.org OVF0addr
23
  jmp    TIM0_OVR_ISR
24

25
;==============================================================================
26
; Initialisierung nach Neustart
27
;==============================================================================
28
INIT:
29
  cli              ; Alle Interrupts sperren
30

31
  ldi    r16, HIGH(RAMEND)   ; Stackpointer initialisieren
32
  out    SPH, r16
33
  ldi    r16, LOW(RAMEND)
34
  out    SPL, r16
35

36
  sbi    DDRB, PORTB5        ; Pin 5 ist Ausgang
37
  sbi    DDRB, PORTB7        ; Pin 7 ist Ausgang
38
  
39
  call  INIT_TMR0      ; Unterprogramm zur Initialisierung
40
                ; von TIMER0 aufrufen
41

42
  sei              ; Alle Interupts freigeben
43
  
44
  jmp    MAIN_LOOP      ; Sprung zur Endlosschleife
45

46
;==============================================================================
47
; Initialisierung von TIMER0, bedient per ISR PORTB5 (Digitalpin 11)
48
; Modus: Normal (WGM02:0 = 0)
49
; Prescaler: 1024 (CS02:0 = 5)
50
; Compare Output Mode: Toggle (COM0A1:0 = 1) --> OC0A (Digitalpin 13)
51
; Timer0 Overflow Interrupt nutzen
52
;==============================================================================
53
INIT_TMR0:
54
  ldi    r16, 100      ; Zählregister vorladen --> höhere Frequenz
55
  out    TCNT0, r16      ; ansonsten Zählregister = 0
56

57
  ldi    r16, 0
58
  out    TCCR0A, r16      ; Beide Steuerregister = 0
59
  out    TCCR0B, r16
60

61
  ldi    r16, (1<<COM0A0)      ; Modus einstellen
62
  out    TCCR0A, r16
63

64
  ldi    r16, (1<<CS02)|(1<<CS00)  ; Prescaler einstellen
65
  out    TCCR0B, r16
66

67
  ldi    r16, (1<<TOV0)    ; eventuellen TOV0 Interrupt löschen
68
  out    TIFR0, r16
69

70
  ldi    r16, (1<<TOIE0)    ; TOV0 Interrupt aktivieren
71
  sts    TIMSK0, r16
72
  
73
  ret              ; Rücksprung
74

75
;==============================================================================
76
; Interrupt-Service-Routine
77
; TIMER0: OVERFLOW
78
; bedient PORTB5 (Digitalpin 11)
79
;==============================================================================
80
TIM0_OVR_ISR:
81
  push  r16          ; verwendete Register sichern
82
  push  r17
83

84
  in    r16, SREG
85
  push  r16          ; Statusregister sichern
86

87
  ldi    r16, 100
88
  out    TCNT0, r16      ; Zählregister vorladen --> höhere Frequenz
89

90
  in    r16, PORTB      ; PORTB einlesen
91
  ldi    r17, (1<<PORTB5)  ; PORTB Bit5 setzen
92
  eor    r16, r17      ; PortB Bit5 toggeln
93
  out    PORTB, r16      ; auf PORTB ausgeben
94

95
  pop    r16
96
  out    SREG, r16      ; Statusregister zurückladen
97

98
  pop    r17          ; verwendete Register zurückladen
99
  pop    r16
100

101
  reti
102

103
;==============================================================================
104
; Programm-Endlosschleife
105
;==============================================================================
106
MAIN_LOOP:
107
  nop
108
  jmp  MAIN_LOOP      ; the reset vector: jump to "main"
#5485372
Lesenswert?

Uwe H. schrieb:
> bei der Initialisierung von TIMSK0
> funktioniert der Befehl "out" nicht...ich muss hier statt dessen "sts"
> verwenden...das ist mir völlig unklar...

in und out können nur die Adressen 0-63 ansprechen. Darüber muss man 
ld(s) und st(s) verwenden. Steht aber so im Datenblatt Kapitel "AVR 
Memories". siehe dazu auch die "Register Summary".
Gast #5485387
Lesenswert?

Hi

>Der ISR-Teil läuft auch, aber am Digital Pin 13 (OC0A) erscheint NICHT
>das Rechtecksignal...

Setze mal das OCR0A-Register auf einen Wert zwischen 100 und 255.

>Eine weitere Frage hätte ich noch...bei der Initialisierung von TIMSK0
>funktioniert der Befehl "out" nicht...ich muss hier statt dessen "sts"
>verwenden...das ist mir völlig unklar...

in/out können nur die Register im IO-Breich ($00..$3F) adressieren. Das 
sind die Register die im Datenblatt in 'Register Summary' mit zwei 
Adressen gekennzeichnet sind. TIMSK0 (Adresse $6E) liegt aber im 
erweiterten IO-Bereich der nur mit sts ansprechbar ist.

MfG Spess
OP #5485498
Lesenswert?

Herzlichen Dank für die fachkundige Antwort hinsichtlich IN/OUT bzw. 
LDS/STS!

Habe es gerade nachgeschlagen...Unterschied ist, das IN/OUT nur einen 
Maschinenzyklus benötigen, LDS/STS jedoch zwei Maschinenzyklen.

Hinsichtlich des fehlenden Signals an OC0A haben Eure Hinweise leider 
nicht geholfen. Ich habe die Timer0 Initialisierung nun wie folgt 
geändert. Es erscheint trotzdem kein Signal.

Any further hints?
1
;==============================================================================
2
; Initialisierung von TIMER0, bedient per ISR PORTB5 (Digitalpin 11)
3
; Modus: Normal (WGM02:0 = 0)
4
; Prescaler: 1024 (CS02:0 = 5)
5
; Compare Output Mode: Toggle (COM0A1:0 = 1) --> OC0A (Digitalpin 13)
6
; Timer0 Overflow Interrupt nutzen
7
;==============================================================================
8
INIT_TMR0:
9
  ldi    r16, 100      ; Zählregister vorladen --> höhere Frequenz
10
  out    TCNT0, r16      ; ansonsten Zählregister = 0
11

12
  ldi    r16, 0
13
  out    TCCR0A, r16      ; Beide Steuerregister = 0
14
  out    TCCR0B, r16
15

16
  ldi    r16, (1<<COM0A0)      ; Compare Output einstellen
17
  out    TCCR0A, r16
18

19
  ldi    r16, (1<<CS02)|(1<<CS00)  ; Prescaler einstellen
20
  out    TCCR0B, r16
21

22
  ldi    r16, 100      ; OCR0A auf 100 vorladen
23
  out    OCR0A, r16      ; 
24

25
  ldi    r16, (1<<TOV0)    ; eventuellen TOV0 Interrupt löschen
26
  out    TIFR0, r16
27

28
  ldi    r16, (1<<TOIE0)    ; TOV0 Interrupt aktivieren
29
  sts    TIMSK0, r16
30
  
31
  ret              ; Rücksprung
Gast #5485609
Lesenswert?

Uwe H. schrieb:
> soll der zugehörige Ausgang OC0A (Digital Pin 13)

Bist du sicher, dass der OC0A an Digital Pin 13 liegt? Ich meine mich 
dunkel zu erinnern, dass die OCs alle in den analog Bereich geroutet 
sind?! Zumindest schließe ich aus dem Digital Pin, dass du mit nem 
Arduino Mega2560 rummachst. Evtl einfach mal die anderen Pins nach ner 
Reaktion belauschen.

MfG Chaos
Gast #5485673
Lesenswert?

Hallo Uwe H.,

wir verwenden Diese Macros zum einfacheren Lesen und Setzen von IO 
Ports.
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

Dies ist auch noch erweiterbar auf Bit IO Zugriffe:
1
.macro gCbi
2
.if @0<32
3
cbi    @0,@1
4
.else
5
xIn    WL,@0
6
cbr    WL,(1<<@1)
7
xOut  @0,WL
8
.endif
9
.endmacro
10

11
.macro gSbi
12
.if @0<32
13
sbi    @0,@1
14
.else
15
xIn    WL,@0
16
sbr    WL,(1<<@1)
17
xOut  @0,WL
18
.endif
19
.endmacro

Für spezielle Zugriffe sind diese auch sinnvoll:
1
.macro gSbic
2
.if @0<32
3
sbic  @0,@1
4
.else
5
xIn  WL,@0
6
sbrc  WL,@1
7
.endif
8
.endmacro
9

10
.macro gSbis
11
.if @0<32
12
sbis  @0,@1
13
.else
14
xIn  WL,@0
15
sbrs  WL,@1
16
.endif
17
.endmacro

Wir nutzen darüber hinaus noch folgende Aliase der Registernamen.
Eine Expansion von W nach WH_WL bis Z nach ZH:ZL erfolgt automatisch.
1
;low block A
2
.def  _LA0    = R0
3
.def  _LA1    = R1
4
.def  _LA2    = R2
5
.def  _LA3    = R3
6
;low block B
7
.def  _LB0    = R4
8
.def  _LB1    = R5
9
.def  _LB2    = R6
10
.def  _LB3    = R7
11
;temp block A
12
.def  _TMP0    = R8
13
.def  _TMP1    = R9
14
.def  _TMP2    = R10
15
.def  _TMP3    = R11
16
;temp block B
17
.def  _TMPA    = R12
18
.def  _TMPB    = R13
19
.def  _TMPC    = R14
20
.def  _TMPD    = R15
21
;high block A
22
.def  _HA0    = R16
23
.def  _HA1    = R17
24
.def  _HA2    = R18
25
.def  _HA3    = R19
26
;high block B
27
.def  _HB0    = R20
28
.def  _HB1    = R21
29
.def  _HB2    = R22
30
.def  _HB3    = R23
31
;pointers
32
.def  WL    = R24
33
.def  WH    = R25
34
.def  XL    = R26
35
.def  XH    = R27
36
.def  YL    = R28
37
.def  YH    = R29
38
.def  ZL    = R30
39
.def  ZH    = R31
OP #5485695
Lesenswert?

Liebe Helfer,

danke für die Hinweise mit dem Makros ;) auch wenn das nichts mit der 
Frage nach dem fehlenden Signal zu tun hat, aber wohl mit dem IN/OUT 
bzw. LDS/STS wie ich vermute...

Mittlerweile habe ich mir für alle sechs Modi (CTC, Fast PWM etc.) 
Testprogramme geschrieben und die arbeiten auch alle wie erwartet.

Nur im Normal-Mode bekomme ich am Pin OC0A (Ja, beim Arduino mit dem 
2560 ist das der DigitalPin 13) einfach kein Signal erzeugt.

Im Datenblatt des ATmega 2560 findet sich auf Seite 120 folgender 
Hinweis:
"Using the Output Compare to generate waveforms in Normal mode is not 
recommended, since this will occupy too much of the CPU time."

Ob im Rahmen eines Re-Designs vom 2560 diese Betriebsart einfach deshalb 
entfernt wurde und deshalb nichts am Pin liefert?

Reine Spekulation!

LG Uwe Homm

Kurzer Nachtrag: Ich kontrolliere die Signale mit einem Oszilloskop.
Gast #5486362
Lesenswert?

> alle sechs Modi ... die arbeiten auch alle wie erwartet.

Da zögere ich jetzt mit meiner Vermutung, trotzdem: OC0A liegt beim 
ATmega2560 auf B7, wurde dieser Pin als Ausgang definiert? In INIT_TMR0 
sehe ich davon nichts, dort hätte ich es erwartet.
Gast #5486374
Lesenswert?

Danke, dass Du Dich nochmal mit meinem Problem beschäftigst!

Ja, POPRTB7 ist als Ausgang definiert...siehe mein erstes Posting. Ich 
habe das ganz am Anfang in dem Bereich "Initialisierung nach Neustart" 
gemacht.

LG
Uwe Homm
Gast #5486378
Lesenswert?

Tja, ich habe keinen ATmega2560 (geschweige denn einen Arduino), aber 
auf dem verwandten ATmega1284 läuft es, und in dessen Datenblatt steht 
derselbe zitierte Hinweis; der sich übrigens wohl nur auf die 
Interruptverwendung bezieht, denn davor steht: "The Output Compare Unit 
can be used to generate interrupts at some given time."
OP #5486425
Lesenswert?

Das Testprogramm hat sich NUR dahingehend geändert, dass ich auf den 
Vorschlag von Thomas F. (igel) (13.07. um 11:31) und dessen Vorgänger 
das Register OCR0A bei der Timerinitialisierung mit einem Wert vorbelegt 
habe (siehe meinen Post vom 13.07. um 12:48 Uhr). Inwiefern ich TCCR0A 
falsch eingestellt hätte, ist mir unklar.

DAS war die einzige Änderung gegenüber meinem ersten Posting.

LG
Uwe Homm
1
;==============================================================================
2
; TIMER0-Normal-Mode0
3
; Verwendet Digital Pin 13 für OC0A und Digital Pin 11 per Overflow Interrupt
4
; DigitalPin 11: T ~ 19ms, Tastgrad = 0,5
5
; DigitalPin 13: kein Signal
6
;
7
; Using the Output Compare to generate waveforms in Normal mode is not
8
; recommended, since this will occupy too much of the CPU time.
9
; (Datasheet Seite 120)
10
;
11
; Created: 12.07.2018 18:40:14
12
; Author : Uwe
13
;==============================================================================
14

15
.ORG 0x0000            ; Nachfolgenden Programmcode
16
                ; ab der Speicherstelle
17
                ; 0x0000 ablegen
18

19
;==============================================================================
20
; Interrupt-Handler
21
;==============================================================================
22
  jmp    INIT        ; Interruptvektoren überspringen
23
                ; und zum Hauptprogramm
24
.org OVF0addr
25
  jmp    TIM0_OVR_ISR
26

27
;==============================================================================
28
; Initialisierung nach Neustart
29
;==============================================================================
30
INIT:
31
  cli              ; Alle Interrupts sperren
32

33
  ldi    r16, HIGH(RAMEND)   ; Stackpointer initialisieren
34
  out    SPH, r16
35
  ldi    r16, LOW(RAMEND)
36
  out    SPL, r16
37

38
  sbi    DDRB, PORTB5    ; Pin 5 ist Ausgang
39
  sbi    DDRB, PORTB7    ; Pin 7 ist Ausgang
40
  
41
  call  INIT_TMR0      ; Unterprogramm zur Initialisierung
42
                ; von TIMER0 aufrufen
43

44
  sei              ; Alle Interupts freigeben
45
  
46
  jmp    MAIN_LOOP      ; Sprung zur Endlosschleife
47

48
;==============================================================================
49
; Initialisierung von TIMER0, bedient per ISR PORTB5 (Digitalpin 11)
50
; Modus: Normal (WGM02:0 = 0)
51
; Prescaler: 1024 (CS02:0 = 5)
52
; Compare Output Mode: Toggle (COM0A1:0 = 1) --> OC0A (Digitalpin 13)
53
; Timer0 Overflow Interrupt nutzen
54
;==============================================================================
55
INIT_TMR0:
56
  ldi    r16, 100      ; Zählregister vorladen --> höhere Frequenz
57
  out    TCNT0, r16      ; ansonsten Zählregister = 0
58

59
  ldi    r16, 0
60
  out    TCCR0A, r16      ; Beide Steuerregister = 0
61
  out    TCCR0B, r16
62

63
  ldi    r16, (1<<COM0A0)    ; Compare Output einstellen
64
  out    TCCR0A, r16
65

66
  ldi    r16, (1<<CS02)|(1<<CS00); Prescaler einstellen
67
  out    TCCR0B, r16
68

69
  ldi    r16, 100      ; OCR0A auf 100 vorladen
70
  out    OCR0A, r16      ; 
71

72
  ldi    r16, (1<<TOV0)    ; eventuellen TOV0 Interrupt löschen
73
  out    TIFR0, r16
74

75
  ldi    r16, (1<<TOIE0)    ; TOV0 Interrupt aktivieren
76
  sts    TIMSK0, r16
77
  
78
  ret              ; Rücksprung
79

80
;==============================================================================
81
; Interrupt-Service-Routine
82
; TIMER0: OVERFLOW
83
; bedient PORTB5 (Digitalpin 11)
84
;==============================================================================
85
TIM0_OVR_ISR:
86
  push  r16          ; verwendete Register sichern
87
  push  r17
88

89
  in    r16, SREG
90
  push  r16          ; Statusregister sichern
91

92
  ldi    r16, 100
93
  out    TCNT0, r16      ; Zählregister vorladen --> höhere Frequenz
94

95
  in    r16, PORTB      ; PORTB einlesen
96
  ldi    r17, (1<<PORTB5)  ; PORTB Bit5 setzen
97
  eor    r16, r17      ; PortB Bit5 toggeln
98
  out    PORTB, r16      ; auf PORTB ausgeben
99

100
  pop    r16
101
  out    SREG, r16      ; Statusregister zurückladen
102

103
  pop    r17          ; verwendete Register zurückladen
104
  pop    r16
105

106
  reti
107

108
;==============================================================================
109
; Programm-Endlosschleife
110
;==============================================================================
111
MAIN_LOOP:
112
  nop
113
  jmp  MAIN_LOOP      ; the reset vector: jump to "main"
Gast #5486428
Lesenswert?

Uwe Homm schrieb:
> habe das ganz am Anfang in dem Bereich "Initialisierung nach Neustart"
> gemacht.

Habe das mal in der Arduino IDE getestet.....
PB7 und PB5 flackern friedlich vor sich hin
1
int main() 
2
{
3
  DDRB  |= _BV(PB5)|_BV(PB7);
4
  TCNT0  = 100;
5
  OCR0A  = 101; // setze OCR0A < 101, und die LED bleibt aus)
6
  TCCR0A = (1<<COM0A0);
7
  TCCR0B = (1<<CS02)|(1<<CS00);
8
  TIFR0  = (1<<TOV0);
9
  TIMSK0 = (1<<TOIE0);
10
  sei();
11
  for(;;);
12
}
13

14
ISR(TIMER0_OVF_vect) 
15
{
16
   TCNT0 = 100;
17
   PINB  = (1<<PB5);
18
}


Dein Fehler ist offensichtlich!
Du setzt bei jeder Gelegenheit TCNT0 = 100.
Aber  OCR0A steht auf Auslieferungszustand == 0
Selbst 100 reicht nicht.
Der Schwellwert wird nie durchlaufen.
Damit bleibt PB7 dauerhaft aus.

OCR0A MUSS größer 100 eingestellt werden.
Gast #5486444
Lesenswert?

Und da es zuletzt nur um OC0A ging (und ursprünglich um Assembler), hier 
in Ergänzung zu ufufs äußerst prompt bereitgestellten Programm:
1
/*
2
SLdt 180714
3

4
toggle OC0A == B7   (B3 auf ATmega1284)
5
*/
6

7
;.include "m1284Pdef.inc"
8
.include "m2560def.inc"
9

10
.def    tmp0                = r16
11

12
.org 0
13
    rjmp    main
14

15
main:
16
;   sbi     DDRB,3
17
    sbi     DDRB,7
18
    ldi     tmp0,(1<<COM0A0)
19
    out     TCCR0A,tmp0
20
    ldi     tmp0,(1<<CS02)+(1<<CS00)
21
    out     TCCR0B,tmp0
22
main_loop:
23
  rjmp      main_loop

Ohne diesen OVF-Interrupt wird es recht kompakt.
Gast #5486490
Lesenswert?

S. Landolt schrieb:
> Ihre Hilfe
? ?
Deine!
Ansonsten, danke für die Blumen.


Irgendwie bin ich überrascht, dass meins geholfen hat.
Denn, dass, und auch mit welchem Wert OCR0A vorbesetzt werden muss, 
wurde ja schon im Thread genannt.

Als da keine (positive) Reaktion drauf erfolgte, musste es getestet 
werden.
Gast #5486494
Lesenswert?

Dass ich geduzt werde, daran habe ich mich gewöhnt (werd's ja sogar auf 
Wahlplakaten von Laternenpfählen herunter). Selbst jedoch mir sonst 
völlig unbekannte Menschen zu duzen, daran werde ich wohl nie gewöhnen. 
Lassen wir es dabei bewenden, und nichts für ungut.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren