Forum: Mikrocontroller und Digitale Elektronik Attiny25 Interrupt wird (selten) ingnoriert


von Wulf D. (holler)


Lesenswert?

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.

von Uwe D. (monkye)


Lesenswert?

Der Fehler ist in Zeile 42...

von Bernd (Gast)


Lesenswert?

> Re: Attiny25 Interrupt wird (selten) ingnoriert

Das ist nicht richtig.

von S. Landolt (Gast)


Lesenswert?

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

von Dieter R. (drei)


Lesenswert?

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.

von Wulf D. (Gast)


Lesenswert?

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.

von Wulf D. (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Wulf D. (Gast)


Lesenswert?

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.

von Dieter R. (drei)


Lesenswert?

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.

von Uwe D. (monkye)


Lesenswert?

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.

von Wulf D. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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

von Dieter R. (drei)


Lesenswert?

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.

: Bearbeitet durch User
von Wulf D. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> @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.

von MWS (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> Deswegen taugt Prosa statt Code auch nichts.

Dem ist nichts hinzuzufügen.

von Dieter R. (drei)


Lesenswert?

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.

von H.Joachim S. (crazyhorse)


Lesenswert?

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.

von F. F. (foldi)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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

von Uwe D. (monkye)


Lesenswert?

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.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Schon lustig, wie lange man um den heißen Brei reden kann, ohne den Brei 
jemals gesehen zu haben.

Ich hab jedenfalls mit dem ATtiny25 immer das hingekriegt, was ich 
wollte. Bugs habe ich nicht feststellen können.

von Wulf D. (holler)


Lesenswert?

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.

von H.Joachim S. (crazyhorse)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Uwe D. (monkye)


Lesenswert?

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.

von Wulf D. (holler)


Angehängte Dateien:

Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

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.

von Wulf D. (holler)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

: Bearbeitet durch User
von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

Peter D. schrieb:
> 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.

Die allermeisten haben single bit sbi/cbi, auch der ATiniy25. Einzelne 
Flags löschen ist also kein Problem.

Oliver

von Peter D. (peda)


Lesenswert?

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."

von Wulf D. (holler)


Lesenswert?

Oliver S. schrieb:
> Die allermeisten haben single bit sbi/cbi, auch der ATiniy25. Einzelne
> Flags löschen ist also kein Problem.
>
Klappt bei den i/o Ports, aber die Timer liegen außerhalb der 
Reichweite.

von Wulf D. (holler)


Lesenswert?

S. Landolt schrieb:
> Falls jemand mitraten möchte, ...
Hey Klasse, läuft das im Simulator?
Für mich geht erst Abends weiter, jetzt ist die Arbeit dran.

Ich fand deine Erklärung von gestern Abend plausibel. Prüfe ich dann.

von S. Landolt (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

Prima!
Mit 2 nops wird es stabil, zumindest soweit ich es auf dem 
Analogoszilloskop sehen kann.

von S. Landolt (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

Peter Dannegger kann's nicht lassen:
> Noch etwas optimiert

Kommt der alte Assemblerprogrammierer doch wieder zum Vorschein.

von Wulf D. (holler)


Lesenswert?

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?

von Uwe D. (monkye)


Lesenswert?

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?

von S. Landolt (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

PS:
Nochmal deutlicher: es wird kein "Auslösen des Interrupts", sondern das 
Setzen von OC1A verhindert, folglich kommt gar kein Impuls zustande.

von Wulf D. (holler)


Lesenswert?

Ja danke euch beiden, ich hab's jetzt!
Schönen Abend noch.

von S. Landolt (Gast)


Lesenswert?

Danke, ebenfalls schönen Abend.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.