PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Timer1, Interrupt wird nur einmal ausgeführt



Helmut1234
20.03.2019, 21:21
Hallo liebe Gemeinde,

ich habe nur ein bescheidene Frage.
Bei meinem Assembler Programm (auf dem RN-Control) sollen alle LEDs an PORTC im sekunden Takt blinken.
Dies habe ich mit dem Timer1 (16-Bit) umgesetzt. Mein Problem ist nur, dass der Interrupt nur einmal ausgeführt wird. Die LEDs leuchten für eine Sekunde und gehen dann aus.
Meine Vermutung ist, dass das Zählregister nicht zurückgesetzt wird, aber das ist nur eine Vermutung.

Hat vielleicht jemand einen Hinweis was ich vergessen haben könnte oder vielleicht falsch gemacht habe?

Viele Grüße
Helmut



##########
#PROGRAMM#
##########


; definitions
.def temp = R16
.def temp_1 = R17

; interrupt vectors
.org 0x000 ; reset handler
rjmp main

.org 0x00E ; Timer1 CompareA Handler
rjmp interrupt_compare_A

.org 0x010 ; Timer1 CompareB Handler
rjmp interrupt_compare_B


main: ; main programm

;;; Timer Counter
;; Control Register A
LDI temp, 0x00 ; normal & Clear Timer on Compare Match (CTC) Mode -> own overflow value
OUT TCCR1A, temp ; Control Register A
;; Control Register B
LDI temp, 0b00011101 ; Timer prescaler of 1024 & Clear Timer on Compare Match (CTC) Mode -> self adjust overflow value
OUT TCCR1B, temp ; Control Register B
;; Output Compare Register 1 A for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00001001
OUT OCR1AL, temp
LDI temp, 0b00111101
OUT OCR1AH, temp
;; Output Compare Register 1 B for CTC
; write value 31,250 -> 31,250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b00010010
OUT OCR1BL, temp
LDI temp, 0b01111010
OUT OCR1BH, temp


;;; PORTC set as output
LDI temp, 0xFF ; Register komplett auf 1 setzen / LDI geht nur von R16 bis R31
OUT DDRC, temp ; durch DDRC wird festgelegt ob die Pins von PORTC als Ausg. (1) oder Eing. (0) definiert werden
; DDRC wird nun mit den Werten aus R16 befüllt

;;; Interrupt handling
;; for timer 1
LDI temp, 0x08 ; Bit 4 – OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
OUT TIMSK, temp ; Timer/Counter Interrupt Mask Register
;; global
sei ; set global interruptenable


loop:
rjmp loop ; endless loop



;-------------------------------------------------------------------------------------------
; interrupts

interrupt_compare_A: ; interrupt routine for compare register 1 B
IN temp_1, SREG ; save status register
LDI temp, 0x00
OUT PORTC, temp ; LEDs on
OUT SREG, temp_1 ; restore status register
reti

interrupt_compare_B: ; interrupt routine for compare register 1 A
IN temp_1, SREG ; save status register
LDI temp, 0xFF
OUT PORTC, temp ; LEDs off
OUT SREG, temp_1 ; restore status register
reti

;-------------------------------------------------------------------------------------------

Searcher
20.03.2019, 23:34
Hallo Helmut1234,
es gibt eine Menge Macken in Deinem Code. Zunächst solltest Du ihn in die CODE Tags einschließen. Dann bleibt die Formatierung erhalten und ist viel besser lesbar.. Code Tags erreichbar in der "Erweitert" bzw "Vorschau" Ansicht mit dem # Zeichen oder [ CODE] ...prg... [ /CODE] ohne die Leerzeichen in den Klammern schreiben.

Zum Programm selbst:
Zum Nachschlagen im Datenblatt gehe ich mal von einem ATmega32 als µC auf dem RN-Control aus.


main: ; main programm

;;; Timer Counter
;; Control Register A
LDI temp, 0x00 ; normal & Clear Timer on Compare Match (CTC) Mode -> own overflow value
OUT TCCR1A, temp ; Control Register A
;; Control Register B
LDI temp, 0b00011101 ; Timer prescaler of 1024 & Clear Timer on Compare Match (CTC) Mode -> self adjust overflow

value
OUT TCCR1B, temp ; Control Register B

Mit dem Bitmuster 0b00011101 wird zwar CTC aber mit ICR1 als TOP Wert eingestellt.
Das 16Bit Register ICR1 hat einen Initialwert von 0 und Du schreibst keinen anderen Wert hinein :-(
Der Timer wird also nach Setzen des Prescalers los laufen und immer wegen ICR1=0 den TCNT1 gleich wieder rücksetzen.
Warum ein Interrupt einmal ausgeführt wird möchte ich ertsmal nicht versuchen zu erklären, da Du auch die 16Bit Register in der falschen Reihenfolge beschreibst.

;; Output Compare Register 1 A for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00001001
OUT OCR1AL, temp
LDI temp, 0b00111101
OUT OCR1AH, temp
;; Output Compare Register 1 B for CTC
; write value 31,250 -> 31,250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b00010010
OUT OCR1BL, temp
LDI temp, 0b01111010
OUT OCR1BH, temp

Werte nicht nachgerechnet aber beide Register werden in der falschen Reihenfolge beschrieben. Auszug aus dem Datenblatt, Abschnitt "Accessing 16-bit Registers":
To do a 16-bit write, the high byte must be written before the low byte. For a 16-bit read, the low
byte must be read before the high byte


;;; PORTC set as output
LDI temp, 0xFF ; Register komplett auf 1 setzen / LDI geht nur von R16 bis R31
OUT DDRC, temp ; durch DDRC wird festgelegt ob die Pins von PORTC als Ausg. (1) oder Eing. (0) definiert werden
; DDRC wird nun mit den Werten aus R16 befüllt

;;; Interrupt handling
;; for timer 1
LDI temp, 0x08 ; Bit 4 – OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
OUT TIMSK, temp ; Timer/Counter Interrupt Mask Register
;; global

Anders als im Kommentar ist der Wert 0x8 das Bit 3 und setzt das OCIE1B Bit - deshalb geht die LED auch aus.
Compare A Interrupt wird nie enabled.

sei ; set global interruptenable


loop:
rjmp loop ; endless loop



;-------------------------------------------------------------------------------------------
; interrupts

interrupt_compare_A: ; interrupt routine for compare register 1 B
IN temp_1, SREG ; save status register

Kommentar irreführend.
Kein Fehler aber Sichern des SREG und Wiederherstellen ist nicht notwendig, da die nachfolgenden Kommandos bis reti das Statusregister nicht ändern.

LDI temp, 0x00
OUT PORTC, temp ; LEDs on
OUT SREG, temp_1 ; restore status register
reti

interrupt_compare_B: ; interrupt routine for compare register 1 A
IN temp_1, SREG ; save status register

Kommentar irreführend.
Kein Fehler aber Sichern des SREG und Wiederherstellen ist nicht notwendig, da die nachfolgenden Kommandos bis reti das Statusregister nicht ändern.

LDI temp, 0xFF
OUT PORTC, temp ; LEDs off
OUT SREG, temp_1 ; restore status register
reti

;--------------------------------------------------------------------------

Helmut1234
21.03.2019, 14:59
Hallo Searcher,

vielen Dank für deine schnelle Antwort und für den Hinweis mit dem [ CODE]. Das hatte ich gesucht nur leider nicht gefunden, sorry.
Deine Hinweise habe ich wie folgt umgesetzt, nur leider ist es das gleiche Verhalten wie zuvor. :(



Mit dem Bitmuster 0b00011101 wird zwar CTC aber mit ICR1 als TOP Wert eingestellt.


Das Bitmuster habe ich jetzt auf 0b00001101 geändert.


;; Control Register B
LDI temp, 0b00001101 ; Timer prescaler of 1024 & Clear Timer on Compare Match (CTC) Mode -> self adjust overflow value
OUT TCCR1B, temp ; Control Register B






Werte nicht nachgerechnet aber beide Register werden in der falschen Reihenfolge beschrieben. Auszug aus dem Datenblatt, Abschnitt "Accessing 16-bit Registers":
To do a 16-bit write, the high byte must be written before the low byte. For a 16-bit read, the low
byte must be read before the high byte


Die Reihenfolge habe ich nun geändert.


;; Output Compare Register 1 A for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00111101
OUT OCR1AH, temp
LDI temp, 0b00001001
OUT OCR1AL, temp
;; Output Compare Register 1 B for CTC
; write value 31,250 -> 31,250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b01111010
OUT OCR1BH, temp
LDI temp, 0b00010010
OUT OCR1BL, temp





Kommentar irreführend.
Kein Fehler aber Sichern des SREG und Wiederherstellen ist nicht notwendig, da die nachfolgenden Kommandos bis reti das Statusregister nicht ändern.


Das Sichern des SREG habe ich eingefügt, weil ich es machen wollte. Also als Übung und Vorsatz damit ich mir das angewöhne.


Beste Grüße
Helmut

Searcher
21.03.2019, 15:24
..., nur leider ist es das gleiche Verhalten wie zuvor. :(


Hallo Helmut,

auch im TIMSK mit Wert 0x18 (dez 24 bzw 0b000011000 bzw OCIE1A und OCIE1B) Bit 3 und 4 :-) beide Compareinterrupts frei gegeben?

Und dann bitte nochmal das ganze Programm einstellen.

Gruß
Searcher

Helmut1234
21.03.2019, 15:43
Hallo Helmut,

auch im TIMSK mit Wert 0x18 (dez 24 bzw 0b000011000 bzw OCIE1A und OCIE1B) Bit 3 und 4 :-) beide Compareinterrupts frei gegeben?

Und dann bitte nochmal das ganze Programm einstellen.

Gruß
Searcher



Das ist nun auch eingefplegt, aber leider auch kein Erfolg. Jetzt blinkt gar nichts mehr, jetzt leuchten die LEDs nur noch.



; definitions
.def temp = R16
.def temp_1 = R17

; interrupt vectors
.org 0x000 ; reset handler
rjmp main

.org 0x00E ; Timer1 CompareA Handler
rjmp interrupt_compare_A

.org 0x010 ; Timer1 CompareB Handler
rjmp interrupt_compare_B





;Mnemonic target, source



main: ; main programm


;;; Timer Counter
;; Control Register A
LDI temp, 0x00 ; normal & Clear Timer on Compare Match (CTC) Mode -> own overflow value
OUT TCCR1A, temp ; Control Register A
;; Control Register B
LDI temp, 0b00001101 ; Timer prescaler of 1024 & Clear Timer on Compare Match (CTC) Mode -> self adjust overflow value
OUT TCCR1B, temp ; Control Register B

;; Output Compare Register 1 A for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00111101
OUT OCR1AH, temp
LDI temp, 0b00001001
OUT OCR1AL, temp
;; Output Compare Register 1 B for CTC
; write value 31,250 -> 31,250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b01111010
OUT OCR1BH, temp
LDI temp, 0b00010010
OUT OCR1BL, temp


;;; PORTC set as output
LDI temp, 0xFF ; Register komplett auf 1 setzen / LDI geht nur von R16 bis R31
OUT DDRC, temp ; durch DDRC wird festgelegt ob die Pins von PORTC als Ausg. (1) oder Eing. (0) definiert werden
; DDRC wird nun mit den Werten aus R16 befüllt

;;; Interrupt handling
;; for timer 1 Interrupt Mask Register
LDI temp, 0b00001100 ; Bit 4 – OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
OUT TIMSK, temp
;; global
sei ; set global interruptenable


loop:
rjmp loop ; endless loop



;-------------------------------------------------------------------------------------------
; interrupts

interrupt_compare_A: ; interrupt routine for compare register 1 B
IN temp_1, SREG ; save status register
LDI temp, 0x00
OUT PORTC, temp ; LEDs on
OUT SREG, temp_1 ; restore status register
reti

interrupt_compare_B: ; interrupt routine for compare register 1 A
IN temp_1, SREG ; save status register
LDI temp, 0xFF
OUT PORTC, temp ; LEDs off
OUT SREG, temp_1 ; restore status register
reti

;-------------------------------------------------------------------------------------------

Searcher
21.03.2019, 15:56
Also ;), jetzt gaaanz in Ruhe und langsam. TIMSK nochmal überprüfen! - mit Datenblatt und meinen post in der Hand :-) Muß gleich weg also restliches Programm überprüfen braucht noch was.

Gruß
Searcher

Helmut1234
21.03.2019, 16:10
Da hast du Recht. Ich mache das nachher ganz in Ruhe und gehe die ganzen Flags noch mal durch.

Grüße
Helmut

Searcher
21.03.2019, 18:05
Hallo Helmut,
ich glaub viel fehlt nicht mehr wenn das TIMSK richtig gesetzt ist. Was passiert im Mode 4, also CTC mit OCR1A als TOP?:



;; Output Compare Register 1 A for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00111101
OUT OCR1AH, temp
LDI temp, 0b00001001
OUT OCR1AL, temp
;; Output Compare Register 1 B for CTC
; write value 31,250 -> 31,250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b01111010
OUT OCR1BH, temp
LDI temp, 0b00010010
OUT OCR1BL, temp
.
.
.
.
.
;-------------------------------------------------------------------------------------------
; interrupts

interrupt_compare_A: ; interrupt routine for compare register 1 B
IN temp_1, SREG ; save status register
LDI temp, 0x00
OUT PORTC, temp ; LEDs on
OUT SREG, temp_1 ; restore status register
reti

interrupt_compare_B: ; interrupt routine for compare register 1 A
IN temp_1, SREG ; save status register
LDI temp, 0xFF
OUT PORTC, temp ; LEDs off
OUT SREG, temp_1 ; restore status register
reti

;-----------------------------------------------------------------------------------


Der Timer läuft nur bis 15625 da OCR1A mit 15625 gesetzt ist. Interrupt Flag wird gesetzt wg. Compare1a Interrupt. Interrupt Compare1A wird ausgeführt und LEDs werden in der ISR eingeschaltet. Der Timer läuft nicht weiter hoch sondern setzt sich auf 0 (Null) wegen CTC. Er erreicht also die 31250 für Compare1B Match gar nicht da TCNT1 vorher zurück gesetzt wird. Compare1B Interrupt kann also nicht eintreten und die LED nie ausgeschaltet werden.

Also einfach die 15625 ins OCR1B schreiben und die 31250 in OCR1A. Damit läuft der Timer zwei Sekunden hoch. "Oben" schaltet er über den Compare1A Interrupt die LEDs ein und auf dem Weg nach oben über den Compare1B Interrupt die LEDs aus.

Übrigens um genau zwei Sekunden zu erreichen sollte der Wert 31249 statt 31250, da der Timer noch einen Timertick braucht um auf Null zu kommen. Spiegelt sich auch im Datenblatt in der Formel zur Frequenzberechnung mit der -1 wieder. Eventuell auch die 15625 um eins vermindern?

So bin gespannt was sich tut.

Gruß
Searcher

Helmut1234
21.03.2019, 19:34
Vielen Dank Search, es bliiiiinkt! :) :cool:
Ohne dich hätte ich das glaube ich nicht hinbekommen. Ich hoffe ich brauche das dann auch in meinen Projekten. ;)

Zum einen lag es an den TIMSK Flags, die waren um eine Bitstelle verschoben.
Zum anderen an der zuvor von dir erwähnten Reihenfolge der Faktoren, spricht den Werten in den Vergleichsregistern (OCR1A und OCR1B).



Also einfach die 15625 ins OCR1B schreiben und die 31250 in OCR1A. Damit läuft der Timer zwei Sekunden hoch. "Oben" schaltet er über den Compare1A Interrupt die LEDs ein und auf dem Weg nach oben über den Compare1B Interrupt die LEDs aus.






Übrigens um genau zwei Sekunden zu erreichen sollte der Wert 31249 statt 31250, da der Timer noch einen Timertick braucht um auf Null zu kommen. Spiegelt sich auch im Datenblatt in der Formel zur Frequenzberechnung mit der -1 wieder. Eventuell auch die 15625 um eins vermindern?

Die ausgerechnete Zeit muss nicht ganz genau sein. Ich wollte einfach nur im ca. 1 Sekundentakt blinkende LEDs haben.


Falls also jemand mal einen funktionierenden Code braucht mit blinkenden LEDs (ca. 1s), hier ist er.



; Programm : This programm is written and tested on an Atmega32. It causes the LEDs on PORTC to blink on a frequency of 1 second.
; To do so it uses the timer 1 (16-Bit) on CTC mode with a prescaler of 1024. To reach the frequency of 1 second
; the compare register B has the value 15625 and register A the value 31250. The demension of these values result in
; the system clock of 16MHz.
; 1024 * 15625 = 16000000
; 1024 * 31250 = 32000000



; definitions
.def temp = R16
.def temp_1 = R17

; interrupt vectors
.org 0x000 ; reset handler
rjmp main

.org 0x00E ; Timer1 CompareA Handler
rjmp interrupt_compare_A

.org 0x010 ; Timer1 CompareB Handler
rjmp interrupt_compare_B


;Mnemonic target, source


main: ; main programm

;;; PORTC set as output
LDI temp, 0xFF
OUT DDRC, temp ; DDRC defines if PORTC is an output (1) or input (0)


;;; Timer Counter in CTC Mode -> self defined value; if timer reaches value, interrupt accours
;; Control Register A
LDI temp, 0x00 ; normal & Clear Timer on Compare Match (CTC) Mode
OUT TCCR1A, temp ; Control Register A
;; Control Register B
LDI temp, 0b00001101 ; Timer prescaler of 1024 & Clear Timer on Compare Match (CTC) Mode -> self adjust overflow value
OUT TCCR1B, temp ; Control Register B


;; Output Compare Register 1 A for CTC
; write value 31250 -> 31250 * 1024 = 32MHz -> 2 seconds count
LDI temp, 0b01111010
OUT OCR1AH, temp ; first write high register then low
LDI temp, 0b00010010
OUT OCR1AL, temp
;; Output Compare Register 1 B for CTC
; write value 15625 -> 15625 * 1024 = 16MHz -> 1 second count
LDI temp, 0b00111101
OUT OCR1BH, temp ; first write high register then low
LDI temp, 0b00001001
OUT OCR1BL, temp


;;; Interrupt handling
;; for timer 1 Interrupt Mask Register
LDI temp, 0b000011000 ; OCIE1A and OCIE1B -> Output Compare A and B Match Interrupt Enable
OUT TIMSK, temp
;; global interrupt enable
sei


loop:
rjmp loop ; endless loop



;-------------------------------------------------------------------------------------------
; interrupts
;-------------------------------------------------------------------------------------------

interrupt_compare_A: ; interrupt routine for compare register 1 B
IN temp_1, SREG ; save status register
LDI temp, 0x00
OUT PORTC, temp ; LEDs on
OUT SREG, temp_1 ; restore status register
reti ; finishes interrupt and enables global interrupt

interrupt_compare_B: ; interrupt routine for compare register 1 A
IN temp_1, SREG ; save status register
LDI temp, 0xFF
OUT PORTC, temp ; LEDs off
OUT SREG, temp_1 ; restore status register
reti ; finishes interrupt and enables global interrupt

;-------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------

Ceos
22.03.2019, 07:29
Übrigens um genau zwei Sekunden zu erreichen sollte der Wert 31249 statt 31250, da der Timer noch einen Timertick braucht um auf Null zu kommen. Spiegelt sich auch im Datenblatt in der Formel zur Frequenzberechnung mit der -1 wieder. Eventuell auch die 15625 um eins vermindern?

Das ist nicht ganz richtig, ich habe beim Support nachgewühlt, weil wir einen Glitch hatten und das Ergebnis war dass der Timer nicht einen "Timertick" sondern einen "Clocktick" braucht, also nur einen Prozessortakt, hat man also einen großen ClockDivider, wirkt sich der extra takt kaum aus, aber je kleiner der Divider desto stärker der Einfluss des zusätzlichen Takt


Timer/Counter1 is reset to $00 in the CPU clock cycle after a compare
match with OCR1A register

Searcher
22.03.2019, 07:29
...
Super Rückmeldung. Auch vielen Dank.

Gruß
Searcher

Helmut1234
22.03.2019, 11:29
Aber ist nicht ein Timertick gleich einen Clocktick? Also Zählt der timer nicht durch den Clock?

Gruß
Helmut

oberallgeier
22.03.2019, 12:06
Aber ist nicht ein Timertick gleich einen Clocktick? Also Zählt der timer nicht durch den Clock? ..Das Verhältnis Timerticks zu Clockticks wird durch den entsprechenden Prescaler bestimmt.


..The Timer/Counter can be clocked internally, via the prescaler, or by an external clock source on
the T1 pin. The Clock Select logic block controls which clock source and edge the Timer/Counter
uses to increment (or decrement) its value. The Timer/Counter is inactive when no clock source
is selected. The output from the clock select logic is referred to as the timer clock (clkT1)..

Siehe auch Figure 40. 16-bit Timer/Counter Block Diagram a.a.O.

Ceos
22.03.2019, 13:23
Was ich nicht verstehe, warum der Timer Takt dadurch verzögert wird ... eigentlich sollte doch bei einem PreScale > 1 die Nullung des Registers fertig sein, bevor der Timer inkrementiert wird, aber scheinbr glitcht auch der prescaler dabei um einen Takt mit, aber das scheint wohl ein Atmel Problem zu sein

Helmut1234
22.03.2019, 13:40
Das Verhältnis Timerticks zu Clockticks wird durch den entsprechenden Prescaler bestimmt.



Siehe auch Figure 40. 16-bit Timer/Counter Block Diagram a.a.O.


Super, danke!

Gruß
Helmut

Searcher
22.03.2019, 14:39
Was ich nicht verstehe, warum der Timer Takt dadurch verzögert wird ... eigentlich sollte doch bei einem PreScale > 1 die Nullung des Registers fertig sein, bevor der Timer inkrementiert wird, aber scheinbr glitcht auch der prescaler dabei um einen Takt mit, aber das scheint wohl ein Atmel Problem zu sein

Hallo Ceos,
ich habe etwas an einem ATmega88 herum gemessen.
Prozessortakt 1MHz
TIMER0 im CTC (kein PWM) mit OCR0A als TOP
kein Presacaler (Timertakt = 1MHz) und OCR0A=0
HW-Timerausgang OC0A an PD6 mit COM0A0 toggeln lassen

Zweikanal Oszi mit einem Kanal auf CLKO um Systemtakt zu sehen, den anderen Kanal auf OC0A

Bei jeder steigenden Systemtaktflanke wurde OC0A getoggelt. Es gab dort keine Verzögerungen des Timertaktes. Auch bei OCR0A mit 1 oder höher sah es nicht so aus, als wenn irgendwo Takte beim Timing verloren gingen.

Allerdings wenn man die Portpins im Interrupt toggeln läßt, gehen Systemtakte "verloren". Messungen versuche ich noch "auf die Reihe" zu kriegen, da sie von der Abarbeitungsgeschwindigkeit der ISR abhängen und ich noch keine Regel erkennen kann.

Ich denke, daß der Timer keine irgenwie geartete Verzögerungen beim Rücksetzten zeigt, sondern es bei der Erkennung der ISR-Anforderung zu Verzögerungen kommt.

Oder hab ich das Problem falsch verstanden?

Gruß
Searcher

Ceos
22.03.2019, 14:44
valider Punkt, das habe ich so noch garnicht betrachtet

in dem konkreten Fall reizen wir den Controller aber auch bis ans limit aus, weil er bis auf diesen glitch absolut zuverlässig (vorhersagbar) arbeitet und genau den Zweck bedienen kann.

Searcher
22.03.2019, 19:24
Hallo,

Eine Messung weiter:

Aus dem ATmega32 Datenblatt zum TIFR1 Register:


• Bit 4 – OCF1A: Timer/Counter1, Output Compare A Match Flag
This flag is set in the timer clock cycle after the counter (TCNT1) value matches the Output
Compare Register A (OCR1A).


Für mich ist die Formulierung "in the timer clock cycle" nicht genau.
ATmega88:
Ich habe wieder den CTC modus mit OCR1A als TOP und lasse OC1A bei TOP toggeln.
Systemtakt und Timertakt gleich mit einem MHz.
Außerdem wird über den Compare1A Interrupt der PC0 Pin über eine ISR softwaremäßig getoggelt; OCR1A Comparewert auf 12.
Im Simulator ist nach Auftreten des Interrupts der PC0 mit dem siebten Takt getoggelt (sbi asm Befehl ins PINC ausgeführt)

Ich gehe davon aus, daß OC1A ohne Verzögerung bei Compare Match getoggelt wird.
Vergleich mit Oszi zeigt, daß der PC0 bei Prescaler=1 acht Takte nach OC1A getoggelt wird.

Bei Prescaler 8, 64, 256, 1024 wird PC0 neun Takte nach OC1A getoggelt.

Das Compare Match Flag OCF1A scheint also wirklich obigem Zitat folgend nicht mit, sondern nach dem Compare Match gesetzt. Allerdings wird es nicht, wie man vermuten könnte, einen Timertakt danach, sondern in diesem Fall nur ein oder zwei Systemtakte nach dem Comparematch gesetzt und auch sofort das Interrupthandling gestartet.

Keine Ahnung, wie das nun einzuordnen ist. Wird der ISR-Start nicht gestört, dürfte das erzeugte Timing über die Compare Match Interrupts immer gleichmäßig sein.

Gruß
Searcher

Ceos
22.03.2019, 22:35
Wir hatten auch den Timer zur Erzeugung definierter Pulse verwendet und dabei diesen glitch erlebt, wir brauchten halt einen timer mit variabler Pulsbreite und Frequenz