Timer1 Interrupt : nix mit ruptus

Begonnen von picass, 27.07.2025, 15:21:40 CEST

Vorheriges Thema - Nächstes Thema

picass

Mal wieder meine Haß-Liebe mit und zu Interrupts: ein PIC18F14K22 soll in seiner Counter-Funktion genutzt werden, wozu ich zwecks der 16-bit den Timer1 ausgewählt hatte. Das Prog ist erfrischend kurz: der PIC bewegt sich gemütlich (31 kHz) in einer Nichts-Tun-Schleife und soll durch den Ablauf des Timers1 in die Irq-Routine springen, in welcher er eigentlich auch nur - zunächst aus Testgründen - eine LED toggeln soll. Das im Kreis-Laufen funktioniert, aber der Irq klemmt wieder, der PIC kommt nicht in seine Service-Routine. Der PIC zählt an seinem Port A5 einen externen Takt. Der wird abgeleitet aus der Netzfrequenz. Über einen Optokoppler wird je nur die positive Halbwelle genutzt, was zu sehr sauberem Rombus an a5 führt. Der Counter1 wird mit seinem Maximalwert minus 50 befüllt, will sagen, der müsste noch genau 50 positive Schwinger abzählen - was einer Sekunde entsprechen sollte  - und dann überlaufen. Und Interrupten. Aber da hat der andere Vorstellungen.

Der Umgang mit Timern ist mir nur rudimentär geläufig, bei einem Timer0 ohne Irq klappte das mal. Wenn ich das Datenblatt richtig verstehe, wird das sonst unvermeidbare INTCON-Register gar nicht benötigt. Das Prog ist von allem Unnötigen befreit und meiner Meinung nach gut lesbar. Das ASM-File ist hier als Text-File angefügt. Ach ja, das Prog läuft mit dem "mittleren" Assembler, also MPLAB X 5.20 (geht bis 5.35). Vielleicht schaut ja jemand mal rein. Is klar, da fehlt - wie so üblich - ein "nur........". Seufz, wenn nur das "nur" nicht wäre!
Grüße, picass
stundenzaehler03.txt

picass

Kaum eingestellt und auf dem Weg zum Kaffee-Zubereiten. aber zu spät für eine sofortige Korrektur  fiel mir auf, wo im obigen Prog ein "NUR" zu finden ist: falsche Zuordnung beim Rücksprung nach einem Durchlauf der Dauerschleife. Da wurde etwas zu weit zurück gesprungen und dadurch das 16-bit-Counter-Register immer wieder neu befüllt. Das ist nun geändert. Aber der IRQ klemmt nach wie vor. Auch im Simulator wird der Überlauf zwar angezeigt, aber nix weiter passiert, also kein Einsprung in die IRQ-Routine. Hier das überarbeitete Prog:
Grüße, picass
stundenzaehler03.txt

PICkel

Hallo picass,

ich nutze ASM zwar nur, wenn es absolut nötig ist, aber ich sehe kein setzen des GIE- Bit!?

Gruß
PICkel

pic18

Du bist wieder beim Pic zurück! 8)
Welches Signal hast Du denn? Ist es ein sauberes Rechtecksignal? Ansonsten würde ich es zuerst über einen Schmitt-Tricker aufbereiten. (z.B. 7414)

Ich würde folgender Maßen vorgehen.
Zuerst nach dem Start würde ich alle Parameter initialisieren. Ich habe jetzt im Überflug nicht gesehen, wo der Port als Eingang für den Timer initialisiert ist.

INTCON Byte setzen:
GIE/GIEH PEIE/GIEL TMR0IE INT0IE RABIE TMR0IF INT0IF RABIF
GIE muss gesetzt werden
PEIE
IPR1,TMR1IP (HI Prio)
PIE1,TMR1IE (1)
PIR1,TMR1IF (0)

T1CON Byte setzen, 
TMR1CS: Timer1 Clock Source Select bit
TMR1ON
T1CKPS<1:0>: Timer1 Input Clock Prescale Select bits
T1RUN: Timer1 System Clock Status bit

Nach der Initialisierung würde ich im Hauptprogramm (Main) eine Endlosschleife machen.
zb. 
main nop
bra main

im Interrupt:
hier würde ich zuerst einmal abfragen, ob der Interrupt vom Timer ausgelöst wurde. 
wenn ja, dann das TMR1IF löschen.
nicht das TMR1IE, das wird noch benötigt. 
nun kannst Du im Interrupt den Zählstand abfragen. Ich meine der Timer zählt rückwärts. Und bei erreichen den Zählerstand neu setzen, bzw den Zähler-Offset einfach Timerwert hinzuaddieren bzw abziehen
Den Interrupt beendest Du mit.
RETFIE (Return from Interrupt), kein Sprung nach Main oder sonst wohin!!

pic18

Ich habe im Archiv ein Beispiel gefunden, dies ist ein Zeitprogramm welches mit dem Systemtakt ich meine 40Mhz arbeitet. Ich hatte dies im meiner Anfangszeit programmiert, heute würde ich es etwas anders machen. Nicht den Timer direkt setzen, sondern die Zyklen abziehen. Dadurch gibt es keine Ungenauigkeiten. interr_b_txt.txt

picass

Zitat von: pic18 in 27.07.2025, 20:05:34 CESTIch meine der Timer zählt rückwärts.
Über das "Zurück-beim PIC" schreibe ich an anderer Stelle.
Nix, der Timer/Counter zählt nach oben:"The TMR1 register pair (TMR1H:TMR1L) increments
from 0000h to FFFFh and rolls over to 0000h." So das Datenblatt.

Das INICON-Register ! Das beschäftigt mich auch, schon alleine, weil man bei Interrupts bislang an dem nicht vorbei kam. Aber......, da gibt es gleich mehrere "Aber": aber für den Time/Counter1 gibt es ein eigenes Register, über welchen der IRQ ein- u. ausgeschaltet wird. Und das Reg wird in jedem Fall benötigt. Käme nun das INTCON auch noch dazu, würde doppelt gemoppelt und welche Ein-oder-Ausschaltung würde denn dann greifen? Weiter: in dem Beispiel-Code für Timer1 im Datenblatt steht nix von INTCON, nur das Sonder-Reg..

Muss da mal 'ne gehörige Runde experimentieren, gleich heute Nachmittag gehts los.
Ach ja, wie schon beschrieben: das Taktsignal ist ausgesprochen sauber zwischen 0,6 Volt und 4,9 Volt. Der Port A Eingang hat eine Schmitt-Trigger-Funktion.
Grüße, picass

PICkel

Zitat von: picass in 28.07.2025, 12:39:29 CESTDas INICON-Register !

Um das INTCON- Register kommt man halt nicht drumherum!
Und das 7. Bit im INTCON ist das GIE-Bit. GIE = Global Interrupt Enable, dieses Bit schaltet also alle Interrupts ein oder aus, egal welche Interrupts (TMR0IE, TMR1IE,...) aktiviert sind.
Das ist wichtig, um bspw. in der Interruptroutine das "dazwischenfunken" eines weiteren INT's bei mehreren möglichen Interruptquellen zu verhindern. Man setzt also am Anfang der INT-Routine
  bcf    INTCON,GIE
und am Ende
  bsf    INTCON,GIE   
  RETFIE


Außerdem müsste doch wohl in Deinem Prog. statt
blink:                   ;
     bsf    PIE1,TMR1IF  ;enable timer1 interrupt

stehen:

blink:
     bsf    PIE1,TMR1IE  ;enable timer1 interrupt

Gruß
PICkel
(der hoffentlich die paar ASM- Zeilen richtig geschrieben hat  :)  )

pic18

Das INTCON Register ist schon wichtig, zum einen schaltest du den Interrupt ein, zum anderen kannst Du auch den Lo Interrupt einschalten. Ich kann mich erinnern, das früher ein Fehler in der Doku war das der Lo Interrupt auch ohne Hi Interrupt eingeschaltet werden kann. Dies ist aber nicht so. 
T1CON wird auch benötigt, zum einen wegen der Zählung 8 oder 16 Bit  T1CKPS1 benötigst Du für den Vorteiler.
So weit erstmal, ich melde mich später wieder

pic18


Ich habe hier die Register mal herauskopiert
Name Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Reset Values on page 
INTCON GIE/GIEH PEIE/GIEL TMR0IE INT0IE RABIE TMR0IF INT0IF RABIF 245 
IPR1 — ADIP RCIP TXIP SSPIP CCP1IP TMR2IP TMR1IP 248 
PIE1 — ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE 248 
PIR1 — ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF 248 
TMR1H Timer1 Register, High Byte 246 
TMR1L Timer1 Register, Low Byte 246 
TRISA — — TRISA5 TRISA4 —(1) TRISA2 TRISA1 TRISA0 248 
T1CON RD16 T1RUN T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON 246

picass

Einige Strampelübungen weiter...., aber nur Teilerfolge. Zunächst war eine der beiden Kontroll-LEDs am falschen Portpin angeschlossen...Shit happens. Aber die andere wollte ja genauso wenig. Das lag dann wiederum daran, dass ich nur ganz rasch im Vorbeigehen auf ein andere, als die bislang genutzte interne Osillator-Quelle geschaltet hatte, nämlich auf den LP-Oszillator. Der machte dann alles derart grauenhaft langsam, dass ich allein deswegen an Defekte dachte. Nu flitzt wieder alles und die LEDs blinken, wie sie sollen. Und dann das INTCON-Reg. Wie konnte ich das nur verschmähen?! Das ist nun wieder im Spiel. Nutzt nur auch nichts, der IRQ klemmt nach wie vor: die IRQ-Routine wird nicht angesprungen.
Das RETFIE ist die übliche Variante, es geht aber auch mit Sprüngen in andere Progteile. Aber dessen Einfügen konnte nichts nützen, soweit kam der PIC erst gar nicht. Jetzt findet sich alles, was in einem meiner erfolgreichen IRQ-Programme auch findet, nur das dort ein Port-on-Change interruptet wird, hier halt der Timer1...... oder halt gerade leider nicht. Es läuft auf das völlig Übliche raus: irgendwo sitzt der dicke Floh und grinst sich einen! :-[ Grüße, picass

^Cobra

Stell Mal den aktuellen Code rein. 
Bei dein alten waren ja einige Fehler drin welche genannt wurden.
Ich würde im simolator Mal die Register kontrollieren. Eventuell wird auf einer falschen Bank noch geschrieben o.ä. 

pic18

@ PICkel 
Zitat von: PICkel in 28.07.2025, 13:40:16 CESTMan setzt also am Anfang der INT-Routine
  bcf    INTCON,GIE
und am Ende
  bsf    INTCON,GIE   
  RETFIE
ich denke dass dies nicht notwendig ist, der PIC sichert ja die Parameter und ich denke dass er einen zweiten Interrupt nicht zu lässt. Es sei dem es wird in einem Lo Interrupt ein Hi Interrupt ausgelöst. Dieser hat natürlich Vorrang. Beim Lo-Interrupt müssen natürlich auch die Statusregister usw. separat gesichert werden.
Zitat von: PICkel in 28.07.2025, 13:40:16 CESTbsf    PIE1,TMR1IF  ;enable timer1 interrupt
bsf PIR1, TMR1IF  

@picass 
hast Du mal meine Beispiele angeschaut, diese müssten eigentlich funktionieren. Es muss nur der Vorteiler geändert werden. Du arbeitest ja mit nur 31Khz
Zitat von: picass in 28.07.2025, 16:34:42 CESTDas RETFIE ist die übliche Variante, es geht aber auch mit Sprüngen in andere Progteile
ich bezweifle, dass du dann aus dem Interrupt wieder richtig zurückkommst. Außerdem läuft der bei ständigen Sprungbefehlen der 31-Level-Stack über. Ein Absturz ist dann programmiert. 
Bei RETFIE und RETURN würde ich FAST nehmen. Ich glaube das macht der Compiler automatisch. 

Du kannst ja mal dein überarbeitest Prog. hochladen, dann schaue ich mir es mal an. 

^Cobra

Zumindest die 'alten' Pics wie 16f628 war es nötig am Anfang einer int Routine GIE aus zu schalten. Ansonsten könnte es passieren das man nie mehr aus der Schleife kam weil ein Ereignis eintrat bevor die Routine komplett durch lief. 
Nach meinen Erinnerungen noch... Oder habe ich das nur aus Bauchgefühl gemacht?







picass

#13
Verdammt, ich bekomme dieses Exopand, rsp. das Verkürzen nicht raus. Oder doch jetzt?
Zitat von: pic18 in 29.07.2025, 08:46:18 CEST@ PICkel

Zitat von: PICkel in 28.07.2025, 13:40:16 CESTbsf    PIE1,TMR1IF  ;enable timer1 interrupt

bsf PIR1, TMR1IF
;--------------------------------------

Ja Jungs, das ist so was mit den Assembeler-Direktriven!
Der gerötete Befehlssatz ist nicht zum Ein-(Aus-)Schalten des timer1-Irq's, das ist dasjenige Flag, welche beim Überlauf des Counters anzeigt.

Versuche mich gleich im Einzelschritt-Debuggen.
Im wahren PIC-Leben wäre im Falle meiner Anwendung eine Störung durch erneuten Irq während des Ablaufes der Irq-Routine nicht zu befürchten. Der gezählte externe Takt der 50-Hz-Netzfrequenz liegt bei 20 mS. In dieser Zeit kann auch der gemütliche 31 kHz-PIC 'ne Menge Cyclen abarbeiten, die arsch-kurze Irqu-Routine allemal.
Muss jetzt wech' und erst mal einen Einzelschritt-Taktgenerator erstellen und dann ein scharfes Auge auf das Counter-Register-Paar werfen.
Grüße, picas

^Cobra

also geht es jetzt?

TMR1IF wird ja automatisch gesetzt beim Überlauf und die Routine muss diese zurücksetzen.
Naürlich muss aber TMR1IE gesetzt sein.


PICkel

@^Cobra, @pic18:

Also es wirklich so, dass beim PIC18F14K22 und anderen das GIE-Bit beim Eintritt in den Interrupt gelöscht und bei RETFIE wieder gesetzt wird. Das wusste ich noch nicht.

Siehe DaBla Punkt 7.3:
7.3 Interrupt Response
When an interrupt is responded to, the global interrupt
enable bit is cleared to disable further interrupts.

Und weiter unten steht:
The "return-from-interrupt" instruction, RETFIE, exits
the interrupt routine and sets the GIE bit (GIEH or GIEL
if priority levels are used), which re-enables interrupts.

Das liest sich m.E. aber so, dass bei einem normalen Rücksprung (RETURN) dieses Bit nicht wieder gesetzt wird. Ganz zu schweigen davon, dass der Stack beim Interrupt-Eintritt gefüllt, aber bei den ganzen Sprungbefehlen (BC,BN,...,BRA,...) nicht wieder geleert wird und irgendwann überläuft.

Gruß
PICkel
Like Like x 2 View List

picass

Das Einzelschritt-Debuggen musste noch warten, auch wenn der dazu nötige Schrittgeber mit einem LM555 verwirklicht werden konnte. Erst hatte ich noch die zu dem Counter und Interrupt gehörenden Befehle überarbeitet, was auch notwendig war. Das erneut korrigierte Prog-File ist unten angefügt. Auch das externe Taktsignal wurde noch mal bearbeitet, sodass die "null"-Schwelle auf ca. 0,3 Volt absackert. Nutzte aber alles nichts, nach wie vor wird die IRQ-Routine noch nicht angesprungen. Gettz ab zum Kaffetrinken und wenn meine Frau nicht dazwischen grätscht, geht es gleich danach weiter.
Grüße, picass
clock-signal.jpgstundenzaehler05.txt


PICkel

#17
Hallo picass,

in der Programmscheife blink: wird mit
bsf    LATB,7       ;test-led an
PORTB.7 eingeschaltet, aber nicht wieder ausgeschaltet.

Setze doch mal
bcf    LATB,7       ;test-led aus
vor den BRA blink - Befehl.
Damit solltest Du (ohne Interrupt- Signal) mit dem Oszi an PORTB.7 einen Takt von ca. 1kHz messen können.
Damit ist erstmal sichergestellt, dass der PIC korrekt arbeitet.
Gruß
PICkel

picass

#18
Es gibt einen Teilerfolg: im Simulator funktioniert das zuletzt eingestellte Prog in der Version "05" ! Weil man im Simulatorbetrieb die Port-Eingänge stimulieren kann, ist es möglich, mit Einzelschritt (F7-Taste) und entsprechendem Stimulieren des Port A,5-Pins den Timer zu Überlauf zu bewegen. Sobald das Low-Register des Zähler-Paares von h'ff' auf h'00' springt, wird im Register PIR1 das TMR1IF-Flag gesetzt. Und - tusch - der Simulator springt zur Speicherstelle 00008, wo der Irq-Vektor für die High-Irq's hinterlegt ist. Von dort in die Irq-Routine, löscht brav das Irq-Flag, toggelt die dortige LED und springt nach "retfie" wieder an die vorige Position in der nop-Schleife.

Also dann ist sowohl die Irq-Einstellung als auch die Timer-Einstellung passend - so meine Schlussfolgerung. Was nicht passt ist das Fehlen des Zählens: die externen Impulse kommen nicht durch. Passend dazu ist auch jeder Test mit dem Debugger, als der Live-Test-Version, ein Fehlschlag. Da kann ich mit dem Einzelschritt-Generator noch so viele Schritte auslösen, nix ist mit counten. Das Taktsignal ist ein super Rechteck zwischen 0,3 und 4,7 Volt. Da in der Praxis der Port A,5 Pin als Eingang geschaltet und die digitale Signalform gewählt ist, arbeitet der Pin als Schmitt-Trigger. Der muss schalten. Das tut er wohl auch, aber das Signal wird nicht weiter gereicht.

Hmmmmmm..... jetzt muss noch ein Test her, welcher nur das Verarbeiten des externen Counter-Taktes überprüft.
Grüße, picass

PICkel

#19
Beim Timer1 gibt es ein spezielles 7.Bit: RD16 im T1CON- Register. Der Timer1 stellt für den Zugriff eine spezielle Funktion zum Lesen und Schreiben beider Bytes bereit. Das ist bei Dir aktiviert:
movlw  b'10000111'  ;timer1 controll reg:16bit/timer1-oszi aus/keine
Stelle mal testweise um auf:
movlw  b'00000111'
Vielleicht hilft das weiter, es kann ja sein, dass beim Schreiben von TMR1H und TMR1L irgendwas schiefgeht.

PICkel

Schnellantwort

Name:
Verifizierung:
Bitte lassen Sie dieses Feld leer:
Geben Sie die Buchstaben aus dem Bild ein
Buchstaben anhören / Neues Bild laden

Geben Sie die Buchstaben aus dem Bild ein:

Tastenkürzel: Alt+S Beitrag schreiben oder Alt+P für Vorschau

🡱 🡳