Interrupt

Begonnen von picass, 07.04.2021, 11:59:40 CEST

Vorheriges Thema - Nächstes Thema

picass

Immer wieder beliebt: wie gehe ich mit den IRQ-Registern und Befehlssätzen um?
Meine Frage: Kann ich das Gefummel in dem von mir beabsichtigten Fall weitestgehend ignorieren, rsp. ganz einfach halten?
Die Lage: In dem "Zentral-Steuer"-PIC befindet sich der µC nahezu immer im Sleepmodus und soll aufgeweckt werden durch einen von vier externen Ereignissen, die allesamt je eine Änderung eines Port-Eingangs bewirken. Nach dem Aufwecken soll er die 4 Port-Pinne abfragen und dann entsprechend was tun, aber nur kurz, danach ist wieder Tiefschlaf angesagt.
Wenn ich mir nun das Microchip Datenblatt für den PIC18F14xx anschaue (S.61), dann ist der Zweig der Weiterleitung einer Portänderung ein erfrischend kurzer und führt ausschließlich über 3 OR-Gatter zum Erfolg: dem Aufwachen. Das nehme ich nun mal wieder ganz wörtlich und interpretiere das so, dass es völlig unnötig ist, wenn man lediglich das Aufwachen - und damit verbunden  natürlich das Weiter-Abarbeiten der folgenden Programmschritte - bewirken will, das ganz Gefummel mit dem Setzen diverser IRQ-"Vorraussetzungen" vorzunehmen? Nach meinem ersten Verständnis wäre nicht mal das Setzen des Haupt-IRQ-Bits - des GIE, also bit 6 oder 7 im INTCON - nötig. Für den jeweiligen Port und auch individuell für jeden der 4 Pinne muss natürlich der IRQ freigegeben werden, aber sonst nichts?!
Grüße, picass

vloki

#1
Ja, sieht so aus, als müsste man nur IE, IP am ersten AND, sowie das was unter (1) noch steht entsprechend einstellen.
IF wird man aber wohl löschen müssen.

Probier es doch einfach aus ;-)
MPLABX  XC8  KiCAD

picass

Ich kämpfe zum wiederholten Male meinen Lieblings-Horror-Kampf, den gegen Interrupts.
Wieder Grundlagenforschung am lebenden Objekt, hier dem "PICkit low pin count demo" Board! Da ist ein Schalter drauf, dessen Ausgangssignal im Ruhefall via einem R auf 5 V liegt und an Port A2 führt. Dann noch 4 LEDs an Port C und das wars.
Im Programm existieren quasi nur zwei Schleifen. Die zuerst Angetroffene lässt eine LED blinken und soll den Zustand ohne IRQ anzeigen. Die andere, die zweite Schleife ist dann natürlich für den IRQ-Fall vorgesehen und wird - wie üblich - von der Speicherstelle 0008h des PICa8F14K22 angesprungen und lässt eine andere LED blinken.

Is klar, das war die Theorie: in der Praxis wird die erste Schleife einmal durchlaufen und dann gehts ohne Tastenberührung sofort in die IRQ-Routine! Es hilft auch nichts, gleich am Anfang des Progs eine Sekundenpause einzulegen, damit sich die Hardware ggf. "aneinander gewöhnen" kann und danach erst den IRQ frei zugeben. Kaum ist er das: schwupps und ruptus, alles ohne T-Druck.

Mittlerweile habe ich nach der ersten IRQ-Routine das den Interrupt anzeigende Flag-Bit zurück gesetzt, bzw. das im Prog installiert, dann funktioniert auch bis auf den ersten Durchlauf alles, wie gewünscht: nur bei T-Druck wird in die IRQ-Routine verzweigt, ansonsten läuft die andere.

Aber dennoch dürfte der PIC nicht ohne Tasten-Druck einfach interrupten, das gehört sich nicht! Dass auch hier der Portpin irgendwelchen Störimpulsen unterliegen könnte und wieder erst ein 1 µF Tantal - wie bei meiner Garagentor-Schaltung - den still legen muss, mag ich mir nicht vorstellen. Klar, probiere ich aus, dürfte aber nicht sein. Ach ja: bei diesem PIC-Typ löst nicht eine bestimmte Port-Änderung den IRQ aus, das lässt sich nur für andere Peripherie einstellen, bei Portänderungen ist die Flanke wurscht, es klappt - leider - mit allen.
Grüße, picass

vloki

Wenn wir doch nur alle funktionierende Glaskugeln hätten ;-)

Überspringst du beim Start den Interruptvector?
MPLABX  XC8  KiCAD

picass

Hallo Volker!
Bin gerade etwas abgelenkt, siehe andere Beiträge. Aber morgen kümmere ich mich wieder um den I! Die Nebel müssen endlich weg. >:(
Grüße, Bernd

picass

#5
Ähm....: wie überspringt man einen IRQ-Vektor?
Das Programm beginnt mit den üblichen Initialisierungen und wenn das rum ist, springt es von ORG Ox0000 zum Beginn der eigentlichen Arbeitsroutine. Dort ist erst eine Schleife, die eine LED befeuert, dann erst wird der IRQ freigegeben. Weil es der Globale IRQ ist, lautet dessen Start-Adresse: ORG 0x0008. Von dort sollte es üblich zu einer IRQ-Routine gehen, das habe ich aber geändert und das Prog springt von 0008 direkt in eine zweite Schleife, in welcher eine andere LED beleuchtet wird. Dann wird der IRQ disabled, das ensprechende Flag abgefragt und dann wieder in die erste Schleife gesprungen.

Inzwischen habe ich meine geliebte Sleep-Routine eingearbeit. Irgendwie klappt das sogar: nach erstem Gewusel findet kein Leuchten mehr statt, die LEDs und der Rest sleepen offensichtlich. Drückt man die Taste, gibts die Erweckung und eine Ehrenrunde mit Erleuchtung, dann wieder Schlummern.

Damit könnte ich mich zufrieden geben, is aber nicht so. Was mich verwirrt ist, dass der PIC nach dem Einschalten seltsame Wege nimmt. Er durchläuft die erste Schleife, dann durchläuft er die zweite Schleife ohne dass ein IRQ stattgefunden hätte, und dann erst bequemt er sich zu ordnungsgemäßem und erwartetem Arbeiten.

Sowas fiehl mir in letzter Zeit auch bei meinem "Garagen-PIC" auf. Nach dem ersten Einschalten macht er Quatsch, er reagiert z.B. falsch auf Tastendrücke oder reagiert gar nicht drauf. Erst dann, wenn er eine Runde geschafft hat, in dem Fall einmal das Garagentor komplett bis zur Endposition gezogen und dann - was er nicht sollte - wieder gleich retourniert hatte, dann erst macht er alles, was er soll.
Er gönnt sich eine erste Runde Eigenwilliges, so wie jetzt auch der PIC im kurzen Interrupt-Testprog. Ich starre auf das kurze Listening und sehe nicht, was der Grund für die Fehlläufe beim ersten Mal sein könnte. Und ein Entstörkondensator, welcher beim Garagen-PIC den Durchbruch brachte, ist es hier nicht, der zeitigt keine Auswirkung.
Grüße, picass

vloki

Das hört sich ein bisschen konfus an ;-)

Das Programm beginnt immer an der Adresse 0x00.
Falls man den IR-Vector verwendet, muss man diesen gleich am Start überspringen um zur Initialisierung zu gelangen.

Hier mal ein leicht modifizierter Code aus den mitgelieferten Templates:
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RES_VECT  ORG     0x0000            ; processor reset vector
          GOTO    INIT               ; go to beginning of program

;------------------------------------------------------------------------------
; HIGH PRIORITY INTERRUPT VECTOR
;------------------------------------------------------------------------------

ISRH      ORG     0x0008

          ; Run the High Priority Interrupt Service Routine
          GOTO    HIGH_ISR             

;------------------------------------------------------------------------------
; LOW PRIORITY INTERRUPT VECTOR
;------------------------------------------------------------------------------

ISRL      ORG     0x0018
          
          ; Run the High Priority Interrupt Service Routine
          GOTO    LOW_ISR             

;------------------------------------------------------------------------------
; HIGH PRIORITY INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

HIGH_ISR  

          ; Insert High Priority ISR Here

          RETFIE  FAST

;------------------------------------------------------------------------------
; LOW PRIORITY INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

LOW_ISR
          ; Context Saving for Low ISR
          MOVWF   W_TEMP              ; save W register
          MOVFF   STATUS, STATUS_TEMP ; save status register
          MOVFF   BSR, BSR_TEMP       ; save bankselect register

          ; Insert Low Priority ISR Here

          ; Context Saving for Low ISR
          MOVFF   BSR_TEMP, BSR       ; restore bankselect register
          MOVF    W_TEMP, W           ; restore W register
          MOVFF   STATUS_TEMP, STATUS ; restore status register
          RETFIE



;------------------------------------------------------------------------------
; INITIALIZATION
;------------------------------------------------------------------------------
INIT
          ; Insert User Initialization Here
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
MAIN	

          ; Insert User Program Here

          GOTO $                      ; loop program counter

          END

Besser wäre natürlich noch keinen absoluten Code zu verwenden,
sondern das was man im Ordner mit den "relocatable" Templates findet:
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RES_VECT  CODE    0x0000            ; processor reset vector
          GOTO    INIT              ; go to beginning of program
...
MPLABX  XC8  KiCAD

PICkel

Mal abgesehen davon, dass Peter und vloki Dir die Interrupt- Verwendung schon beschrieben haben: Suchst Du noch nach der Lösung des SLEEP- Problems?
Wenn ja, dann habe ich mal einen Test für Dich programmiert.
Da ich nur einen PIC18F24K22 zum Testen habe, musste ich für Deinen PIC18F14K22 das Programm anpassen ohne Testen zu können. Ich hoffe, ich habe alles richtig gemacht.

Programmablauf:
- Register- Initialisierung
-  :Schleifenbeginn
- 3x blinken
- PORTA lesen in Tempvar, um den aktuellen Status zu haben (ohne Lesen geht es nicht!)
- INTCON-Bit löschen
- Sleep
- GOTO Schleifenbeginn

Statt Tempvar kann man wohl auch in ein unbenutztes Register R0...Rxx schreiben.
Nach 3x Blinken geht der PIC in den SLEEP und kann per Tastendruck aufgeweckt werden. Ein "richtiger" Interrupt wird nicht ausgeführt, lediglich das INTCON-Bit wird benutzt/ausgewertet.
Da ein Pin-change sowohl bei H/L als auch bei L/H erkannt wird, kann man auch den Taster nach dem Aufwachen festhalten bis zum nächsten Sleep und dann loslassen.

Hier das Programm in mBASIC:
program Sleep

' PIC18F14K22 @ 1MHz INTOSC (default)
' Test des SLEEP- Modus
' Taster an PORTA.2
' LED an PORTC.0
' Funktion: 3xblinken -> Sleep -> aufwachen und von vorn beginnen

Dim Tempvar as Byte    ' Hilfsvariable zum Lesen/Aktualisieren

' 1x blinken: 0,5sec ein, 0,5 sec aus
sub procedure blink()
  LATC.0 = 1
  delay_ms(500)
  LATC.0 = 0
  delay_ms(500)
end sub

main:
'   Main program 
clearbit(INTCON, 0)   ' RABIF-Bit löschen
setbit(INTCON, 3)     ' RABIE Interrupt enable
setbit(IOCA, 2)       ' Pin A.2 als Interrupt-On-Change aktivieren
TRISB = 255
TRISC = 0             ' Output
PORTC = 0
ANSEL  = 0            ' PORTA digital setzen

Schleife:

blink()
blink()
blink()

Tempvar = PORTA       ' PORTA lesen, ist wichtig!
clearbit(INTCON, 0)
Sleep

goto schleife

end.

Im Anhang gibt es das Prog. sowie ASM- und HEX-File.

Gruß
PICkel
Sleep.zip

picass

Ne, Jungs, da habt ihr was missverstanden. Meine Programme starten alle so wie in dem Beispiel von Volker ausgeführt: von 0x0000h springt es zum "normalen" Programmablauf, im Falle eines IRQs wird 0x0008h angesprungen und von dort zur IRQ-Routine oder - testweise - zu einem extra Programmteil.

Seit heute Mittag ist meine IRQ-Phobie Geschichte: das Aufwachen aus dem Sleep-Modus funktioniert gänzlich ohne die üblichen IRQ-Befehle. Es werden tatsächlich nur die drei Bits, rsp. Flags benötigt, welche der Auszug aus dem Databook - siehe erster Beitrag und auch nochmal hier - beschreibt. Eine IRQ-Routine wird damit überflüssig, ebenso wie IRQ-Vektoren.
Grüße, picass

PICkel

Na, dann war wohl mein Betrag von 15:23 Uhr  zu spät.
Vielleicht hift's jemand Anderem.

PICkel

vloki

Zitat von: picass in 30.06.2022, 15:44:29 CESTNe, Jungs, da habt ihr was missverstanden...
Ja, die "üblichen Initialisierungen". Darunter hatte ich wohl die Konfiguration von Pins als Ein- oder Ausgänge.
Einstellungen für diverse Peripheriemodule etc., also Programmcode verstanden.

Schlechte Glaskugel eben ;-)
MPLABX  XC8  KiCAD

picass

Zitat von: PICkel in 30.06.2022, 15:23:36 CESTSuchst Du noch nach der Lösung des SLEEP- Problems?
Wenn ja, dann habe ich mal einen Test für Dich programmiert.
Ich hoffe, ich habe alles richtig gemacht.

Auch du, mein Sohn, hast es nun gerafft, also das mit dem Sleepen.
Habe gerade mal dem Wunsch entsprechend getestet: bei TA-Druck leuchtet es, ansonsten wird gepennt.
Grüße, picass

picass

ICH HASSE INTERRUPTS !!!

Habe zwei Tage des Kampfes dagegen hinter mir. Es funktioniert nun zwar, aber manchmal ist Assembler voll der Horror! Zumal sich das Wichtigste von Allem im Datenblatt in einer Fußnote versteckt!

Eigentlich habe ich eigene Vorlagen und auch die funktionierenden Beispiele im Beifang des ,,PICkit Low Pin Count Demo"-Boards mit seinen 13 Musterprogrammen. Eigentlich....... Aber wehe, man möchte z.B. aufgrund abweichender Hardware was ändern oder es kommt noch was Niedliches ins Programm dazu wie der Versuch, diejenige Taste, welche den Interrupt-On-Cange Port bedient, entprellen zu wollen. Voll der...., aber das wurde schon gesagt.

Der Ärger beginnt schon damit, dass laut Simulator noch während der Port-Einstellungen gleich zu Anfang ein Interrupt angezeigt wird, der noch gar nicht stattgefunden hat. So wurde immer das ,,RABIF" gesetzt, das seine Fahne hebt, wenn ein Interrupt durch Port-Change stattfand. Und dieses verdammte Flag lässt sich auch nicht einfach löschen. Da kann man ruhig als Befehl: clr INTCON eingeben, wonach theoretisch alles auf Null sein müsste. ,,RABIF" hebt weiter die rote Fahne!

Letztlich lag es an der ,,Missmatch"-Kondition, welche das Löschen nicht zulassen will. Im Kleinst-Gedruckten findet sich das mit dem Missmatch. Also einmal den fraglichen Port lesen, z.B. mit dem Befehl: movf PORTA,0 (Speichern in W) und dann endlich senkt sich die Flagge – sofern man direkt gleich den Befehl fürs Flaglöschen folgen lässt.

Drollig wirds beim Tastenentprellen, wenn man in tagelangen Kampf zermürbt durch ständige Programmänderungen ist. Die Funktion des Progs – also das Millisekunden Aufblitzen der IR-Sendediode – lässt sich ja nicht mal mit einem Oszi so ohne weiteres verfolgen. Also dafür eine Normalo-LED in visible Rot einbauen und über den Nachbarport ansteuern. Ansteuern....., is klar:
Bit-Set-File Port-Pin, also z.B. bsf LATC,0. Also hantiert man wegen der dauernden Nichtfunktionen: mal will der PIC nicht aus dem Sleep-Modus raus, mal läuft er sofort durch, mal hängt er sich im hinteren Teil des Progs auf, anscheinend manchmal alles aufeinmal. Dauernd wird der Kontrollteil verlagert, und wieder nix. Bis man irgendwann entdeckt, dass beim dauernden Hantieren mit dem LAT-Befehl dieser zur Abfrage eines Ports ja weniger gedacht ist. Also stattdessen READ! Is klar, wenn man den Fehler gefunden hat, ist es sowas von klar und ebenso dürfte klar sein, dass andere – also DU oder auch du – da nicht gestolpert wären. Mich hats zwei Tage gekostet, und die Freude über die Endlich-Funktion hält sich in überschaubaren Grenzen.
Grüße, picass


pic18

#14
Zitatimmer das ,,RABIF" gesetzt
Meinst Du RBIF? Das setzt Du mit:
BCF INTCON,RBIF,ACCESS
zurück.
Du kannst auch den Interrupt ausschalten, in dem Du das Bit RBIE löscht.

alle Interrupts schaltest Du mit
BCF INTCON,GIE,ACCESS
ab. Damit werden alle Interrupt abgeschaltet, auch der low-priority-Interrupt abgeschaltet, da war früher im Datenblatt immer ein Fehler. Ich habe das in C auch schon in einer While Schleife gesehen, glaube aber nicht, das das nötig ist.
Zitatclr INTCON eingeben
evtl. musst du hier noch die BANKED bzw. ACCESS (1..0) eingeben. So etwa:
CLRF INTCON,ACCESS

ich meine wenn du das ACCESS (0) weglässt, dann wird immer BANKED (1) als default angenommen. Dann musst Du BSR mit MOVLB auf 0 setzen.

deswegen kannst Du wahrscheinlich auch den Ausgang nicht setzen. Das TRIS-Bit muss natürlich auch auf Ausgang (0) gesetzt sein. Kennst Du den Befehl BTG? (BTG f,b[,a]) dieser lässt den Ausgang immer drehen (toogle). Damit kannst Du leicht eine LED aufblinken lassen.

Zitatmit dem Befehl: movf PORTA,0 (Speichern in W)
MOVF  f,d,a
d= destination W(0) F(1) hier ist default wahrscheinlich auch F, was bedeutet das der Wert nicht nach W sondern nach F (wo dieser schon steht) geschrieben wird.
a= wieder ACCESS (1) oder Banked hier wird wieder bei default wahrscheinlich Banked angenommen

der ganze Befehlssatz gilt natürlich beim PIC 18F....

Mit dem Simulator bin ich noch nie klar gekommen. Ich benutze einen Bootloader und dann verirrt sich der Simulator. Ich müsste dann jedes mal die Zeiger ändern.



Schnellantwort

Achtung: In diesem Thema wurde seit 120 Tagen nichts mehr geschrieben.
Wenn Sie nicht absolut sicher sind, dass Sie hier antworten möchten, starten Sie ein neues Thema.

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