Attiny25 Interrupt wird (selten) ingnoriert

OP #5865152
Hallo,
habe mit einem Attiny25 einen Aufbau zur Verzögerung und Formung von 
Pulsen:

- Das prellfreie Eingangssignal (20-200Hz) geht auf den als INT0 
konfigurierten PB2, irq auf fallende Flanke.

- In der INT0 Serviceroutine wird für den frei laufenden Zähler 1 das 
Output compare auf einen Wert von einigen us in der Zukunft vorgeladen 
und an PORT B1=1 gekoppelt. OC irq wird aktiviert.

- In der OC Serviceroutine wird das Output compare auf einen Wert von 
250us in der Zukunft geladen und auf PORT B1=0 gekoppelt.

- beim 2. Sprung in die OC Routine wird der OC irq abgeschaltet, das 
Spiel kann von vorn beginnen.

Es soll also auf das Eingangssignal zeitverzögert ein 250us langer Puls 
auf PORT B1 folgen.

Zu 99% klappt das auch. Der Puls ist praktisch jitterfrei, aber selten 
fehlt er.
Gemessen mit 50Hz als Eingangssignal und geeigneter Triggerbedingung auf 
PB1.

Nach längerer Suche frage ich mich was einen Interrupt verhindern kann?
Ein zufällig parallel aktiver wohl kaum (hab noch parallel Timer 0 mit 
TOV laufen)

Der Timer 1 Überlauf sollte auch egal sein, addiere immer nur per add 
(ohne Carry) zum timer1 die Verzögerung hinzu und lade die ins Output 
compare Register.
Kann da was schief gehen?
Im Moment weiß ich noch nicht ob’s am INT0 oder dem OC liegt, hätte 
dieselbe Wirkung.
Gast
Wäre es nicht effektiver gewesen, das (doch sicher gut) kommentierte 
Programm auf die betroffenen Funktionen zu reduzieren und hier 
vorzustellen? Und vielleicht fände sich dann sogar jemand, der das eben 
mal bei sich laufen lässt (wenn's nicht gerade eine Exotensprache ist).
a) Ich hab vom ATtiny25 keine Ahnung, nur von neueren.
b) Source Code wäre hilfreich.
c) Funktioniert ein Compare überhaupt, wenn Null im Compare-Register 
steht und der Zähler auf Null überläuft? Das kann bei dem gewählten 
Verfahren nach meinem Verständnis ja immer mal wieder vorkommen.
Gast
Danke für die beiden letzten Kommentare.

- wenns gar nicht anders geht, strippe ich das Assemblerprogramm auf den 
Rumpf ab und baue stubbs rein damits überhaupt läuft und stelle das hier 
rein. Aber vielleichts kommt noch die zündende Idee, weil

- <Dieter R.>: Compare geht nicht bei Null??? Werde mal im Detail 
nachlesen, das wäre eine Erklärung.
Gast
Im Datenblatt steht keine Ausschlußbedingung für bestimmte Werte. Das 
ist es nicht.

Ich denke es liegt eher am INT0. Begründung: selbst wenn ein Compare 
warum auch immer verloren ginge, würde es bei der Zählerfrequenz von 
62,5 kHz nach 4ms wieder zum Compare Match kommen. Passiert aber nicht.
Erst nach 20ms, d.h. nächste fallende Flanke auf INT0 kommt wieder ein 
Puls.
Gast
Wulf D. schrieb:

> habe mit einem Attiny25 einen Aufbau zur Verzögerung und Formung von
> Pulsen:
[...]

Das Konzept ist falsch. Es behandelt nicht die möglichen 
Glitch-Situationen. Daher vermutlich auch nicht dein Code...

Du musst dir in allen Konsequenzen klarmachen, dass der Timer (samt 
seiner OC-Ausgänge) frei laufende Hardware ist, die sich einen feuchten 
Dreck darum schert, was du an Interrupts enabelst oder sperrst.

> Nach längerer Suche frage ich mich was einen Interrupt verhindern kann?

Irgendwelche verhinderten Interrupts sind hier sicher nicht das Problem.

Das Problem ist mit an Sicherheit grenzender Wahrscheinlichkeit die 
Timer-Hardware bzw. genauer: die Tatsache dass diese mit dem 
INT0-Interrupt in keinster Weise synchronisiert ist und deine (nur 
versuchte) Synchronisation in der INT0-ISR eben offensichtlich nicht für 
alle möglichen Fälle korrekt ist.

Man kann sowas lösen (auch auf Basis deines Konzeptes), aber das 
erfordert Assembler-ISRs. Aber selbst, wenn man sowieso in Assembler 
programmiert, versucht man derartig zeitkritische Konstrukte zu 
vermeiden, wann immer möglich.

In deinem Fall ist das relativ einfach durch Änderung des Konzeptes der 
Timernutzung möglich (sprich: Start von 0 in der ISR von INT0). Die 
einzige Gegenanzeige wäre: der Timer steht dir nicht exklusiv zur 
Verfügung, sondern wird mit anderem Code geshared und muss deswegen 
immer durchlaufen.

Dann ist der einzige Ausweg tatsächlich Assembler.
Gast
Die Glitch-Situation würde ich gern erkennen. Sehe die leider nicht. Mir 
ist vollkommen klar, dass die Hardware nichts unterschlägt.

Ich könnte den Timer tatsächlich im INT0 bei $00 starten, würde mich 
dabei aber ein wenig im knappen 8-Bit Wertebereich einschränken oder 
alternativ Jitter durch die SW-Steuerung des Timers auf die Pulslänge 
bringen.
Ich hänge ja zwei OC hintereinander: erst die Verzögerung auf INT0, dann 
die konstante Pulslänge von 250us.
Durch den völlig frei laufenden Zähler hatte ich bisher kein Jitter.
Start bei Null wäre ein Versuch wert.

Ach ja, den Winzling codiere ich in Assembler. Viel Code ist es nicht.
Wulf D. schrieb:
> Danke für die beiden letzten Kommentare.
>
> - wenns gar nicht anders geht, strippe ich das Assemblerprogramm auf den
> Rumpf ab und baue stubbs rein damits überhaupt läuft und stelle das hier
> rein. Aber vielleichts kommt noch die zündende Idee, weil
>
> - <Dieter R.>: Compare geht nicht bei Null??? Werde mal im Detail
> nachlesen, das wäre eine Erklärung.

Naja, ich habe gerade einige bemerkenswerte Erfahrungen mit den neueren 
Series 1 Prozessoren hinter mir und dort insbesondere Timer B. Der macht 
genau das, was im Datenblatt steht, inklusive aller verschleiernd 
formulierten Einschränkungen. Im ATtiny25 Datenblatt steht:

 A compare match does only occur if Timer/Counter1 counts to the OCR1A 
value.

Das kann man durchaus so interpretieren, dass ein Wrap-Around auf Zero 
keinen Match-Interrupt auslöst. Muss nicht so sein, aber die 
Formulierung hat mir zu denken gegeben.
Dieter R. schrieb:
> Wulf D. schrieb:
>
>  A compare match does only occur if Timer/Counter1 counts to the OCR1A
> value.
>
> Das kann man durchaus so interpretieren, dass ein Wrap-Around auf Zero
> keinen Match-Interrupt auslöst. Muss nicht so sein, aber die
> Formulierung hat mir zu denken gegeben.

Also im Abschnitt steht, dass nur das Zählen zum Compare Match führt und 
nicht das manuelle setzen des OCR1x und des TCNTx.

Für den Nulldurchgang ist der OVFx INT vorgesehen.
Gast
Ich bin mir auch sicher, dass ich irgend eine Kleinigkeit übersehen 
habe. Spitzfindigkeiten fielen mir bisher bei den kleinen AVRs bisher 
nicht auf.

Dein Zitat aus dem Datenblatt bezog ich ausschließlich auf den 
nachfolgenden Satz:
A software write that sets TCNT1 and OCR1A to the same value does not 
generate a compare match.

Wie gesagt, ich schreibe überhaupt nicht in den Timer1 rein.
Nutze aber den OCR1A in der Form OCR1A = TCNT1 add Verzögerungswert.
Gast
> Viel Code ist es nicht.

Und das Bisschen lässt sich nicht einfach so vorstellen?
  Stattdessen wird zwei Stunden lang über hier Irrelevantes diskutiert. 
Mein lieber Wulf D., nehmen Sie es mir nicht übel, aber entweder wollen 
Sie sich nur die Zeit vertreiben oder Sie haben in einem Aspekt ein 
grundlegendes Defizit, nämlich was zielgerichtetes Arbeiten betrifft.
Wulf D. schrieb:
> Ich bin mir auch sicher, dass ich irgend eine Kleinigkeit übersehen
> habe. Spitzfindigkeiten fielen mir bisher bei den kleinen AVRs bisher
> nicht auf.
>
Probier es aus und mach als Alternative eine Version, die bei Null den 
Compare-Wert immer auf 1 inkrementiert. Wenn es dann geht, weißt du, 
dass er Null nicht mag. Es hilft nichts, hier herumzuargumentieren. Ich 
habe auf die harte Tour jetzt mehrfach lernen müssen, dass die Dinger 
(Series 1) 1. nicht Bug-free sind, also neben den dokumentieren Errata 
noch weitere (Plural) besitzen und 2. die Dokumentation selbst durchaus 
interpretationsbedürftig ist, man könnte das sehr wohl als spitzfindig 
bezeichnen. Und dann gibt's da noch Sachen (spielt jetzt hier keine 
Rolle, nur anekdotisch), wo detailliert beschrieben wird, mit welchem 
Code man etwas initialisieren muss, und in den Errata steht, dass das 
gar nicht geht. Probieren ergibt, dass es wirklich nicht so geht, aber 
anders, da muss man aber selbst drauf kommen.

Folge: wenn es das dann nicht war, ist es was anderes. Weitersuchen.

@S. Landolt: wieso soll das irrelevant sein? Mich interessiert es, 
obwohl es gerade nicht mein Problem ist. Könnte aber beim nächsten 
Projekt mein Problem werden, deshalb kann ich hier durchaus was lernen.
Gast
Danke euch allen für die Kommentare.
Für heute ist Schluss. Kann eure Vorschläge gerade nicht umsetzen, da 
ich an einem anderen Rechner sitze. Deshalb die Gast-Anmeldung.

Morgen nach der Arbeit, nicht vor 20 Uhr

- werde ich den Timer immer bei $00 starten.
- Den Code posten, falls es noch immer hängt.
Gast
> @S. Landolt: wieso soll das irrelevant sein?

Dies hier zum Beispiel:

> Naja, ich habe gerade einige bemerkenswerte Erfahrungen
> mit den neueren Series 1 Prozessoren hinter mir und
> dort insbesondere Timer B. Der macht genau das,
> was im Datenblatt steht ...

Es geht hier um den ATtiny25.
Gast
Wulf D. schrieb:
> OC irq wird aktiviert.

Würde der Code gezeigt, könnte man sehen, ob ein beliebter (Anfänger-) 
Fehler gemacht wurde, indem das OC-Flag vor Erlauben des Interrupts 
nicht gelöscht wird. In diesem Fall erfolgt der OC-ISR-Aufruf 
unmittelbar nach dem Erlauben und die ganze Mechanik geht in die Hose.

Deswegen taugt Prosa statt Code auch nichts.
S. Landolt schrieb:
>> @S. Landolt: wieso soll das irrelevant sein?
>
> Dies hier zum Beispiel:
>
>> Naja, ich habe gerade einige bemerkenswerte Erfahrungen
>> mit den neueren Series 1 Prozessoren hinter mir und
>> dort insbesondere Timer B. Der macht genau das,
>> was im Datenblatt steht ...
>
> Es geht hier um den ATtiny25.

Danke für den Hinweis. Wäre mir sonst gar nicht aufgefallen. 
Zufälligerweise habe ich allerdings - im Gegensatz zu einem Herrn 
Landolt - aus dem ATtiny25-Manual zitiert und auf eine dortige 
Formulierung verwiesen, die einen Hinweis enthalten könnte, warum der 
Wert Null problematisch sein könnte.

Der Rest war Erläuterung zu dem Satz mit "spitzfindig".

Lesen bildet, Verstehen ist aber auch hilfreich.
Ich dachte auch ich kenn den Tiny25.
Und habe mir gerade 1h um die Ohren geschlagen, um Timer1 als CTC zu 
benutzen.
Sowas bescheuertes - CTC geht nur via OCR1C, bringt aber keinen 
Interrupt zustande... Warum löst der nicht den TOV1 aus? Muss man dann 
OCR1A oder B benutzen, was wiederum bedeutet, dass die für eine genaue 
CTC nicht anderweitig benutzbar sind. Somit die CTC-Funktion  ziemlich 
nutzlos. Muss man nicht verstehen.
Die Register sind schon der Knaller.
Deshalb nehme ich auch am liebsten den Tiny10 für kleine Dinge.
Kann man alles auf einem Arduino testen und dann eben die Pins ändern, 
drauf braten und auflösen.
Habe allerdings schon lange nichts mehr gemacht.
Gast
Hallo,

Ich kann mich nur auf das Datenblatt und meine eigenen Programme 
beziehen.

Es steht geschrieben:
"Bit 2 – TOV1: Timer/Counter1 Overflow FlagIn normal mode (PWM1A=0 and 
PWM1B=0) the bit TOV1 is set (one) when an overflow occurs in 
Timer/Counter1.
The bit TOV1 is cleared by hardware when executing the corresponding 
interrupt handling vector. Alternatively,TOV1 is cleared, after 
synchronization clock cycle, by writing a logical one to the flag.

In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when 
compare match occurs betweenTimer/Counter1 and data value in OCR1C - 
Output Compare Register 1C.
When the SREG I-bit, and TOIE1 (Timer/Counter1 Overflow Interrupt 
Enable), and TOV1 are set (one), theTimer/Counter1 Overflow interrupt is 
executed"

Quelle:
https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf

Das lässt vermuten, es wäre in deinem Programm evtl. möglich den PWM 
Modus zu wählen.
Gast
H.Joachim S. schrieb:

> Sowas bescheuertes - CTC geht nur via OCR1C, bringt aber keinen
> Interrupt zustande... Warum löst der nicht den TOV1 aus?

Tut es. Man muss nur das ganze DB lesen, dann kommt man etwa auf sowas:
1
ldi R16,(1<<CTC1)|(1<<PWM1A)|UARTPRE  ;PWM1A set to force TOV1 on OCR1C compare match
2
out TCCR1,R16
Wulf D. schrieb:
> Ich bin mir auch sicher, dass ich irgend eine Kleinigkeit
> übersehen
> habe. Spitzfindigkeiten fielen mir bisher bei den kleinen AVRs bisher
> nicht auf.
>
> Dein Zitat aus dem Datenblatt bezog ich ausschließlich auf den
> nachfolgenden Satz:
> A software write that sets TCNT1 and OCR1A to the same value does not
> generate a compare match.
>
> Wie gesagt, ich schreibe überhaupt nicht in den Timer1 rein.
> Nutze aber den OCR1A in der Form OCR1A = TCNT1 add Verzögerungswert.

Und was passiert, wenn OCR1A nach der Addition Null wird?

Nachtrag: Das macht ja den Unterschied aus, wenn ich zu Fuß den 
Zählerwert ins TCNT1 lade und dann beim Nulldurchgang (Deine Verzögerung 
bzw. die 250 Mikrosekunden) den OV-Interrupt bekomme oder zyklisch beim 
erreichen des OCR1A-Wertes - wobei der Zähler munter weiterrennt.
c-hater schrieb:
> Tut es. Man muss nur das ganze DB lesen, dann kommt man etwa auf sowas:

Ok, hast Recht, so gehts.
Warum man aber für die CTC-Funktion eines der PWM-Bits setzen muss, 
obwohl es extra ein CTC-Bit gibt, erschliesst sich mir nicht direkt und 
ist auch nicht besonders logisch.
Egal, jetzt gehts, war sowieso eine Ausnahme, dass ich den "besseren" T1 
als schnöde CTC missbraucht habe.
Gast
H.Joachim S. schrieb:

> Warum man aber für die CTC-Funktion eines der PWM-Bits setzen muss,
> obwohl es extra ein CTC-Bit gibt, erschliesst sich mir nicht direkt und
> ist auch nicht besonders logisch.

Da gebe ich dir sowas von vollkommen Recht, das glaubst du garnicht. ;o)

Aber unserer beiden Meinungen werden Atmel bzw. Microchip wohl nicht 
dazu bewegen, etwas an diesem Unsinn zu ändern, der sich bei genauerer 
Betrachtung zu einer simplen unglücklichen symbolischen Benamsung der 
Registerbits auflöst.

Das PWM-Bit tut alleine nicht, was man bei diesem Symbolnamen erwarten 
würde, genausowenig, wie es das CTC-Bit tut. Beide sind jeweils nur für 
Teilaspekte der Sache zuständig, die bei den "richtigen" Timern durch 
die Timermodi abgebildet werden.

Es ist wohl den Entwicklern einfach nur schwer gefallen, für die sich 
ergebenden vier Timer-Modi wirklich griffige Bezeichnungen zu finden.
Wulf D. schrieb:
> Uwe D. schrieb:
>>
>> Und was passiert, wenn OCR1A nach der Addition Null wird?
>>
> Und wo das Problem mit OCR1A=0?
> Fand im DB keines!
>
> Ok, der Brei wird heute Abend serviert. An Bugs im Tiny glaube ich auch
> nicht. Wird irgend eine Race condition sein.

Naja, ich wollte auf folgendes hinaus: Wenn der Timer im CTC Modus 
läuft, dann kann der Zähler (TCNTn) auf Null zurückgesetzt werden. Da 
ich den Quellcode nicht kenne, muss ich raten. Vielleicht lässt Du den 
Zähler ja durchlaufen.
Und wenn jetzt OCRnA=0 ist, wird dann ein Interrupt ausgelöst? Lässt 
sich im Simulator sicher schnell testen.
OP
So, ich habe das Problem stark eingekreist.
Es war nicht nötig, den Timer1 im INT0 jedesmal neu zu starten. Das 
Problem tritt nur auf, wenn der Verzug=1 ist. Null ist ausgeschlossen.
1
  in   tempi,TCNT1  ;Output Compare A mit Verzug vorladen
2
  lds  temp2i, Verzug
3
  add  tempi, temp2i
4
  out  OCR1A, tempi
Habe die Tabelle, aus der der Verzug entnommen wird, auf min 2 begrenzt 
und das Problem ist weg. Siehe Oszibild. Blau triggert INT0, violett ist 
der verzögerte Puls.

Die vier Zeilen sind aus der INT0 ISR, siehe unten. Nehme an im 
Fehlerfall tritt der Compare noch während der INT0 Ausführung auf. Aber 
warum wird dann die OC ISR nicht sofort dannach aufgerufen?
Irgend ein Flag fehlt wohl.

Der gesamte Code. Ist zu wenig um zu reduzieren. Nur die tabelleA: 
fehlt. Läuft noch auf zu niedriger Frequenz, aber das ändert nichts am 
Grundproblem.
1
.include "tn25def.inc"
2

3
.def    temp      =r16  ; temporaer buffer 1
4
.def    temp2      =r17  ; temporaer buffer 2
5
.def    tempi      =r20  ; irq temporaer buffer 1
6
.def    temp2i      =r21  ; irq temporaer buffer 2
7
.def    tempSi      =r22  ; irq SREG buffer 1
8
.def    States    =r25  ; Statebits
9

10
; Hardware connections:
11
.equ DREHZ6    =PORTB0 
12
.equ ZUENDAUS  =PORTB1 
13
.equ ZUENDEIN  =PORTB2
14
.equ ALTERNAT  =PORTB3
15
.equ LED       =PORTB4
16

17
; ----  States fuer diverse Gelegenheiten ---
18
.equ    s_drehz     =0
19
.equ    s_stillstand=1
20
.equ    s_pulsstart =2
21
.equ    s_realdrehz =3
22

23
.DSEG   ; Umschalten auf das SRAM Datensegment
24

25
Verzug:      .BYTE  1
26
Rohdrehzahl:  .BYTE  1
27
Timer0buff:    .BYTE  1
28
DREHPointer:  .BYTE  1
29
DREHWerte:    .BYTE  8
30
DREHreal:     .BYTE  2  ; unbenutzt
31

32

33
; AVR Clock Fuse bits CKSEL[3:0] = 0010 entspricht 8 MHz, ist default
34
; Clock Prescale Register CLKPR[3:0] = 0 entspricht 1
35

36

37
.cseg
38

39
rjmp RESET
40
;.org OC1Baddr
41
;rjmp OC1B_ISR  ; unbenutzt (war Pulslaenge)
42
.org INT0addr
43
rjmp INT0_ISR  ; An Induktivgeber gekoppelt
44
rjmp PCI0_ISR  ; redundant
45
rjmp OC1A_ISR  ; Verzoegerung und Pulslaenge
46
rjmp OVF1_ISR  ; unbenutzt
47
rjmp OVF0_ISR  ; ermittelt Motorstillstand bzw Min-Drehzahl
48

49
.org INT_VECTORS_SIZE  ; Platz für die Interrupttabelle lassen
50

51

52
RESET:  
53
  ldi r16,high(RAMEND)  ; Main program start
54
;   out SPH,r16       ; Set Stack Pointer to top of RAM
55
  ldi r16,low(RAMEND)
56
  out SPL,r16
57

58
  ldi temp, 0b00010010  ; enable outputs , 1=output
59
  out DDRB,temp
60
  ldi temp, 0b00101101   ; 1= pullup on input pin
61
  out PORTB,temp
62
;   TCCR0B - Timer/Counter Control Register B
63
  ldi temp, 0b00000101  ; clk/1024, ca 7,8 kHz
64
  out TCCR0B,temp
65
;   Timer/Counter1 Control Register Bit5:4 Set OC1A output =>PB1 
66
  ldi temp, 0b00111000  ;Bit3:0 CK/128 = 8MHz/128 = 62,5Khz 
67
  out TCCR1,temp
68
;   Timer/Counter Interrupt Mask Register
69
  ldi temp, (1<<TOIE0)  ;TOIE0 = 1, Overflow Interrupt enable
70
  out TIMSK,temp
71
;   MCUCR - MCU Control Register
72
    ldi temp, 0b00000010  ; falling Edge INT0 => PB2
73
  out MCUCR,temp
74
;  GIMSK - General Interrupt Mask Register
75
  ldi temp, (1<<INT0)   ; INT0 aktivieren, liegt auf PB1
76
  out GIMSK,temp
77
;  PCMSK - Pin Change Enable Mask
78
  ldi temp, (1<<PCINT0)  ; PB0 ist Interrupteingang, erstmal nicht benoetigt
79

80
  clr temp
81
  sts DREHPointer, temp  ; das Mittelwert-Array auf Min-Drehzahl $ff setzen
82
  ldi temp, $ff
83
  ldi temp2, 8
84
  ldi  ZL, LOW(DREHWerte)
85
  ldi  ZH, HIGH(DREHWerte)
86
Initloop:  
87
  st Z+, temp
88
  dec temp2
89
  brne Initloop
90
    
91
  clr States
92
  sei        ;Interrupt enable
93

94

95
schleife:       ; Hauptprogrammschleife Anfang ***
96
;
97
sbrc States, s_drehz
98
rcall RechneDrehzahl
99
;
100
sbrc States, s_stillstand
101
rcall Stillstand
102
;
103
rjmp schleife    ; Hauptprogrammschleife Ende ***
104

105

106
OVF0_ISR:    ; bei rund 1850 U/min und darunter Ueberlauf
107
  in    tempSi, SREG
108
  sbr  States, 1<<s_stillstand  ;Motor steht wohl  
109
  out  SREG, tempSi
110
  reti 
111

112
OVF1_ISR:  ; ist unnoetig ...
113
  reti
114

115
RechneDrehzahl: ;(inverse) Drehzahl mitteln, Verzug aus Tabelle holen
116
  lds   temp, Timer0buff ;Timer0 Wert ins Array DREHWerte packen
117
  lds  temp2,DREHPointer
118
  inc   temp2
119
  cpi   temp2, 8
120
  brlo Dreh_jmp
121
  clr  temp2
122
Dreh_jmp:
123
  ldi  ZL, LOW(DREHWerte)  
124
  ldi  ZH, HIGH(DREHWerte)
125
  add  ZL, temp2
126
  st   Z, temp  ; Timerwert an der richtigen Stelle im array speichern
127
  sts   DREHPointer, temp2
128
;---Mittelwert aus den 8 Arraywerten berechnen ---------
129
  ldi temp2, 7  ; richtig???
130
  ldi  ZL, LOW(DREHWerte)
131
  ldi  ZH, HIGH(DREHWerte)
132
  ld   r2, Z+
133
  clr  r3
134
  clr  r1
135
Dreh_jmp2:
136
  ld   temp, Z+
137
  add   r2, temp
138
  adc   r3, r1
139
  dec temp2
140
  brne Dreh_jmp2
141
  ASR r3  ; durch 8 Teilen
142
  ROR r2
143
  ASR r3
144
  ROR r2
145
  ASR r3
146
  ROR r2  ; Ergebnis steht nur in r2
147
  sts Rohdrehzahl, r2
148
;---
149
  ldi ZL, LOW(tabelleA*2) ; Aus Tabelle den Verzug ermitteln
150
  ldi ZH, HIGH(tabelleA*2)
151
  add zl, r2
152
  adc zh, r3
153
  lpm temp, z
154
  sts Verzug, temp
155
  cbr States, 1<<s_drehz
156
  ret
157

158
Stillstand:       ;alte Drehzahlwerte ungueltig,
159
  ldi temp, $ff   ;Drehzahl-Array mit min-Werten vorladen
160
  ldi temp2, 8
161
  ldi  ZL, LOW(DREHWerte)
162
  ldi  ZH, HIGH(DREHWerte)
163
Stillloop:
164
  st Z+, temp
165
  dec temp2
166
  brne Stillloop
167
  ret
168

169
OC1A_ISR:  ; Verzugszeit oder Pulsleange abgelaufen
170
  in    tempSi, SREG
171
  sbrc States, s_pulsstart
172
  rjmp  pulsstart         
173
          ;Zuendimpuls ist AUS, OC1A-irq abschalten
174
  sbi  PORTB, LED    ; Kontroll-LED aus
175
  ldi  tempi, (1<<TOIE0) 
176
  out  TIMSK, tempi
177
  out  SREG,  tempSi
178
  reti
179

180
pulsstart:      ;Zuendimpuls EIN
181
  cbi  PORTB, LED  ; Kontroll-LED ein
182
  in   tempi, TCNT1
183
  ldi  temp2i,15  ; entspricht 250us Pulslaenge
184
  add  tempi, temp2i
185
  out  OCR1A, tempi  
186
;   Timer/Counter1 Control, Bit5:4 Set OC1A output =>PB1 geht AUS 
187
  ldi  tempi, 0b00101000
188
  out  TCCR1,tempi
189
;  cbi  TIFR, OCIE1A
190
;  in   tempi, TIFR  ; OC irq Flag loeschen
191
;  cbr  tempi, OCIE1A
192
;  out  TIFR, tempi
193
  cbr  States, 1<<s_pulsstart   ;DEBUG nn
194
  out  SREG,  tempSi
195
  reti
196
      ;DEBUG nn Ende
197

198

199
INT0_ISR:  ; Induktivgeber der Zuendung
200
  in    tempSi, SREG
201
  in   tempi,TCNT1  ;Output Compare A mit Verzug vorladen
202
  lds  temp2i, Verzug
203
  add  tempi, temp2i
204
  out  OCR1A, tempi
205
;   Timer/Counter1 Control, Bit5:4 Set OC1A output =>PB1 geht EIN 
206
  ldi  tempi, 0b00111000
207
  out  TCCR1,tempi 
208
;  cbi  TIFR, OCIE1A
209
  in   tempi, TIFR  ; OC irq Flag loeschen
210
  cbr  tempi, OCIE1A
211
  out  TIFR, tempi
212
  ldi  tempi, (1<<OCIE1A)|(1<<TOIE0)  ; OC1A irq einschalten
213
  out  TIMSK, tempi
214
  cbr  States, 1<<s_stillstand  ;Motor dreht
215
  sbr  States, 1<<s_pulsstart   ;Merker fuer ersten OC1A Zyklus
216
;  
217
  in   tempi,TCNT0 ;Timer0 fuer Drehzahl in Array DREHWerte sichern
218
  sts  Timer0buff, tempi
219
  clr  tempi
220
  out  TCNT0, tempi
221
  sbr  States, 1<<s_drehz  ;in Programmschleife die 
222
  out  SREG, tempSi    ;inverse Drehzahl ermitteln
223
  reti
224

225

226
PCI0_ISR: ;6x Generatorfrequenz, ist redundant. Konsistenzpruefung?  
227
  reti
228

229

230
.include "tabelleA.asm"
231
;tabelleA:      ; so sieht das Label aus
232
;.db 0x00, 0x22    ; es sind real 256 Werte im Flash
Angehängte Dateien:
Gast
Ich bin mir unsicher, aber Folgendes fällt mir auf:

In INT0_ISR vergehen zwischen 'in tempi,TCNT1' und 'out TCCR1,tempi' 6 
Takte: wenn dazwischen TCNT1=OCR1A erreicht wird, wird OC1A nicht 
gesetzt. 6 Takte von 128, das ist natürlich eher selten.

Hier erschließt sich mir der Sinn nicht:
1
 in   tempi, TIFR  ; OC irq Flag loeschen
2
 cbr  tempi, OCIE1A
3
 out  TIFR, tempi
Wozu soll das OCF1A gelöscht werden? Es dürfte doch eigentlich gar nicht 
gesetzt sein. Abgesehen davon, dass das 'cbr' hier falsch verwendet wird 
und dass es in TIFR kein OCIE1A gibt, dies hat nur zufälligerweise den 
gleichen bit-Wert wie OCF1A.
OP
Ja, da könnte was dran sein. Prüfe ich morgen nach.

Und du hast natürlich Recht mit dem unsinnigen und auch noch falsch 
codierten Flag-löschen. War ein hilfloser Versuch, ist schon wieder 
entfernt. Hatte keinerlei Wirkung.
Gast
Meine obige Vermutung war falsch, mit der vorgegebenen Struktur, d.h. 
durchlaufendem Timer1, klappt es einfach nicht.
  Aber Folgendes möchte ich vorschlagen, Timer1 ständig rücksetzen, 
sollte funktionieren: die ersten 5 Zeilen in INT0_ISR ersetzen durch:
1
INT0_ISR:  ; Induktivgeber der Zuendung
2
  in    tempSi, SREG
3
  ldi  tempi,0
4
  out  TCCR1,tempi
5
  out  TCNT1,tempi
6
  in   tempi,GTCCR
7
  ori  tempi,(1<<PSR1)
8
  out  GTCCR,tempi
9
  lds  tempi,Verzug
10
  out  OCR1A, tempi
Ja, da sind mehrere Sachen unsauber.
Wenn TCNT1 schon weiterzählt, kann das Reload auf +1 nicht mehr einen 
Interrupt auslösen. Ich würde daher T1 anhalten. Oder man macht das 
Rücksetzen des Vorteilers davor.
Und es muß sichergestellt werden, daß im CTC-Mode kein Reload >OCR1C 
erfolgt.
Auch das Löschen von Interrupts ist beim AVR eine Pain, da ein OR 
sämtliche Flags in dem Register löscht, also auch die von T0.
Es geht also nur so:
1
ldi tempi, 1<<OCF1A
2
out TIFR, tempi
Gast
Falls jemand mitraten möchte, hier ein reduziertes Programm für das 
Phänomen: bei Versatz=1 fehlen sporadisch Impulse - warum klappt das 
Umschalten des 'Comparator A Output Mode' hier nicht, bei Versatz>1 aber 
durchaus?
  Ich weiß erstmal nicht weiter.
Angehängte Dateien:
Oliver S. schrieb:
> Die allermeisten haben single bit sbi/cbi, auch der ATiniy25. Einzelne
> Flags löschen ist also kein Problem.

Zumindest beim ADC steht, daß das nicht geht:
"Alternatively, ADIF is cleared by writing a logical one to the flag. 
Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt 
can be disabled. This also applies if the SBI and CBI instructions are 
used."
Gast
> läuft das im Simulator?
Das weiß ich nicht, es läuft hier in "echt". Den Simulator vermeide ich, 
wenn es irgendwie geht (und das ist fast immer).
Schau Dir mal:
Figure 12-2. Timer/Counter 1 Synchronization Register Block Diagram
an.

Da der Timer auch mit der PLL laufen kann, sind da Zwischenregister 
drin.
D.h. TCNT1 kann weiterzählen, nachdem Du ihn gelesen hast.
Mache mal nach dem Prescalerreset noch 3 NOPs rein, bevor Du TCNT1 
liest.
Gast
Sehr schön, wieder was gelernt.
Und falls also Wulf D. nicht wie weiter oben beschrieben den Timer1 in 
INT0_ISR ständig rücksetzen will, so könnte seine Lösung wie folgt 
aussehen:
1
INT0_ISR:  ; Induktivgeber der Zuendung
2
  in    tempSi, SREG
3
  in   tempi,GTCCR
4
  ori  tempi,(1<<PSR1)
5
  out  GTCCR,tempi
6
  nop
7
  nop
8
  nop
9
  in   tempi,TCNT1  ;Output Compare A mit Verzug vorladen
10
  lds  temp2i, Verzug
11
  add  tempi, temp2i
12
  out  OCR1A, tempi
Noch etwas optimiert:
1
INT0_ISR:  ; Induktivgeber der Zuendung
2
  in    tempSi, SREG
3
  in   tempi,GTCCR
4
  ori  tempi,(1<<PSR1)
5
  out  GTCCR,tempi
6
  nop
7
  lds  temp2i, Verzug
8
  in   tempi,TCNT1  ;Output Compare A mit Verzug vorladen
9
  add  tempi, temp2i
10
  out  OCR1A, tempi
OP
Guten Abend,
herzlichen Dank wegen der regen Beteiligung!
Habe soeben beide Lösungsvorschläge ausprobiert. Sowohl das Neustarten 
des Timer1 weitgehend nach dem Codeschnipsel von S. Landolt als auch dem 
Prescaler-Reset nach der Optimierung von Peter D.
Beides funktioniert fehlerfrei, das läßt sich mit dem Digital-Oszi 
sicher nachweisen.
Interesanter Weise sind auch der minimale Abstand von INT0 zu Compare 
Match auf Port B1 bei beiden Methoden gleich.

So ganz habe ich es aber noch nicht verstanden: was verhindert das 
Auslösen des Interrupts?
Auf Seite 84 des Manuals hast Du dieses Bild:

Figure 12-2. Timer/Counter 1 Synchronization Register Block Diagram.

Dort wird beschrieben, dass - wie Peter schon schrieb - neben dem 
Systemtakt auch der PLL als Taktquelle verwendet werden kann. Die 
Synchronisation kostet je nach Taktquelle Zeit. Die Anzahl der Takte ist 
dort angegeben. Deshalb solltest Du mit den eingeschobenen NOP warten 
bis die Register synchronisiert sind.

Verständlich geworden?
Gast
Es sind zwei Punkte:

Bei Verzug=1 kann, in INT0_ISR, TCNT1 schon um ebendieses 1 
weitergezählt haben, je nach momentanem Stand des Vorteilers, noch bevor
1
putii  TCCR1,(1<<COM1A1)+(1<<COM1A0)+(1<<CS13)  ; set  OC1A, /128
durchlaufen wurde, folglich wird OC1A gar nicht gesetzt.

Dies wird verhindert, indem man den Vorteiler zurücksetzt (auf 0), dann 
hat man 128 Takte Zeit. Bis dieses Zurücksetzen aber im Vorteiler 
ankommt, vergeht eine gewisse Zeit (2 oder 3 Takte), da beim Timer1 
Synchronisationregister zwischengeschaltet sind.
Gast
PS:
Nochmal deutlicher: es wird kein "Auslösen des Interrupts", sondern das 
Setzen von OC1A verhindert, folglich kommt gar kein Impuls zustande.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.