Interrupt

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

⏪ vorheriges - nächstes ⏩

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

Schnellantwort

Name:
Verifizierung:
Bitte lassen Sie dieses Feld leer:

2 Beeren und 2 Bananen. Welche Farbe hat die Banane ?:
Tastenkürzel: Alt+S Beitrag schreiben oder Alt+P für Vorschau