|
Interrupts
Der 68HC11 verfügt über insgesamt 21 externe und interne Interruptquellen.
Entsprechend Komplex ist seine Interruptstruktur. Hier nochmals zur Erinnerung der Ablauf eines Interrupts: Auslösen einer Unterbrechung
Signal | RESET | Unbedinger Abbruch und Neustart | Signal | XIRQund (X-Bit = 0) | Unbedingte Unterbrechung (non maskable interrupt) | Signal | IRQ und (I-Bit = 0) | Bedingte Unterbrechung (interrupt request) (kann auch interne Ursachen haben) | Befehl | SWI | Befehlsgesteuerte Unterbrechung (software interrupt) | Befehl | Illegal Opcode | Nicht implementierter Befehl |
Interrupt-Vektoren
Priorität | Name | Adresse | Interrupt-Quelle | 21 | SCIINT | $FFD6 | SCI serial system | 20 | SPIINT | $FFD8 | SPI serial system | 19 | PAIINT | $FFDA | Pulse Accumulator Input Edge | 18 | PAOVINT | $FFDC | Pulse Accumulator Overflow | 17 | TOINT | $FFDE | Timer Overflow | 16 | TOC5INT | $FFE0 | Timer Output Compare 5 |
15 | TOC4INT | $FFE2 | Timer Output Compare 4 |
14 | TOC3INT | $FFE4 | Timer Output Compare 3 |
13 | TOC2INT | $FFE6 | Timer Output Compare 2 |
12 | TOC1INT | $FFE8 | Timer Output Compare 1 |
11 | TIC3INT | $FFEA | Timer Input Capture 3 |
10 | TIC2INT | $FFEC | Timer Input Capture 2 |
9 | TIC1INT | $FFEE | Timer Input Capture 1 |
8 | RTIINT | $FFF0 | Real Time Interrupt |
7 | IRQINT | $FFF2 | IRQ External Interrupt |
6 | XIRQINT | $FFF4 | XIRQ External Interrupt |
5 | SWIINT | $FFF6 | Software Interrupt |
4 | BADOPINT | $FFF8 | Illegal Opcode Trap Interrupt |
3 | NOCOPINT | $FFFA | COP Failure (Reset) |
2 | CMEINT | $FFFC | COP Clock Monitor Fail (Reset) |
1 | RESETINT | $FFFE | RESET Interrupt |
Die nicht maskierbaren Interrupts wie RESET, CMF, COP, XIRQ, Ill. Opcode oder SWI
haben eine feste Priorität. Bei den anderen Interrupts läßt sich die
Priorität ändern. Die vier Bits PSEL0 bis PSEL3 im HPRIO-Register legen fest,
welche Interruptquelle die höchste Priorität besitzen soll.
PSEL3 | PSEL2 | PSEL1 | PSEL0 | Interrupt-Quelle |
0 | 0 | 0 | 0 | Timer Overflow |
0 | 0 | 0 | 1 | Pulse Accumulator Overflow |
0 | 0 | 1 | 0 | Pulse Accumulator Input Edge |
0 | 0 | 1 | 1 | SPI serial system |
0 | 1 | 0 | 0 | SCI serial system |
0 | 1 | 0 | 1 | Reserve |
0 | 1 | 1 | 0 | IRQ External Interrupt |
0 | 1 | 1 | 1 | Real Time Interrupt |
1 | 0 | 0 | 0 | Timer Input Capture 1 |
1 | 0 | 0 | 1 | Timer Input Capture 2 |
1 | 0 | 1 | 0 | Timer Input Capture 3 |
1 | 0 | 1 | 1 | Timer Output Compare 1 |
1 | 1 | 0 | 0 | Timer Output Compare 2 |
1 | 1 | 0 | 1 | Timer Output Compare 3 |
1 | 1 | 1 | 0 | Timer Output Compare 4 |
1 | 1 | 1 | 1 | Timer Output Compare 5 |
Eine besonders wichtige Rolle in jedem Mikroprozessorsystem spielen die nicht maskierbaren
Interrupts. Sie sind speziell für das Auslösen lebenswichtiger Funktionen
vorgesehen, wie zum Beispiel zur Erkennung eines Versorgungsspannungsausfalls. Da der
Mikroprozessor 68HC11 über die Möglichkeit verfügt, seine interne
Organisation zu modifizieren, ist für den externen nicht maskierbaren Interrupt
XIRQ ein spezielles Bit im Condition-Code-Regisier vorgesehen, mit dem dieser
direkt nach einem Reset-Vorgang maskiert wird. Dies ist kein Widerspruch, denn wenn
das Anwenderprogramm die interne Organisation (Speicheraufteilung, Festlegung des
Registerblocks, Initialisierung des Stackpointers) durchgeführt hat, kann dieses
Bit nur ein einziges Mal auf 0 gesetzt werden. Ein erneutes Maskieren des XIRQ ist
danach nicht mehr möglich, so daß man von diesem Zeitpunkt an von
einem echten nicht maskierbaren Interrupt sprechen kann.
Während der Organisationsphase ist es in jedem Fall zwingend notwendig,
keinen Interrupt zuzulassen, denn ein während dieses Zeitraumes aufgerufenes
Interrupt-Programm würde auf Resourcen zurückgreifen wollen, die unter
Umständen noch nicht verfügbar sind.
Eine zweite nicht maskierbare Interrupt-Quelle ist eine Erkennungsschaltung für
illegale Befehlscodes (Illegal Opcode Trap). Da nicht alle möglichen
Bitkombinationen mit gültigen Befehlen besetzt sind, besteht die Möglichkeit,
daß die CPU durch einen Fehler im Programm oder durch einen Störimpuls von
außen einen ungültigen Befehl bekommt. In einem solchen Fall wird ein
spezieller Interruptvektor angesprungen, der auf eine Fehlerbehandlungsroutine
zeigen sollte. Wird dieser Vektor nicht vom Anwender initialisiert, dann kann es
passieren, daß er auf einen weiteren ungültigen Befehl zeigt und die
CPU damit in eine Endlosschleife gerät.
Eine ähnliche Funktion hat der Softwareinterrupt SWI, der häufig während
der Test- und Emulationsphase eines Programms benutzt wird. Er stellt einen normalen
gültigen Befehl der CPU dar. Der Software-Interrupt wird in erster Linie von
Emulations-Systemen zur Manipulation des Zielprozessors benutzt. Man kann ihn
aber auch für Sytemaufrufe verwenden, wenn im 68HC11 ein Mini-Betriebssystem
implementiert wird.
Alle weiteren Interrupt-Quellen des 68HC11 können durch das 1-Bit im
Condition-Code-Register maskiert werden. Wenn dieses Bit gesetzt ist, sind alle
diese Interrupt-Quellen gesperrt. Jeder Reset-Vorgang setzt dieses Bit. Es ist Aufgabe
des Anwenderprogramms, den Interrupt nach sinnvoller Initialisierung des Systems gezielt
freizugeben.
Jeder Eintritt in ein Interruptprogramm setzt das I-Bit, um eine weitere Unterbrechung durch
einen neuen Interrupt zu verhindern. Nach Beendigung des Interruptprogramms durch einen
RTI-Befehl wird es automatisch wieder gelöscht, so daß erneute Interrupts
wieder zugelassen sind.
Zur Erweiterung der Interrupt-Struktur steht der Eingang IRQ zur Verfügung. Hier
können beliebig viele externe Interrupt-Quellen angeschlossen werden. Zu diesem
Zweck ist dieser Pin nach einem Reset auf Pegelabhängigkeit geschaltet (
Möglichkeit des "wired or" mehrerer Interruptquellen), um mit externen Peripherie-ICs
kompatibel zu sein. Die Konfiguration als flankenempfindlicher Eingang wird seltener
angewendet, da sie nur mit einer einzigen externen Interrupt-Quelle zusammenarbeiten
kann.
Zusammenfassung der notwendigen Voraussetzungen zum Arbeiten mit Interrupts:
- Der IRQ-Ausgang eines externen Peripheriebausteins muß mit einem der
Prozessor-Interrupt-Eingänge verbunden sein: IRQ, XIRQ, RESET (Hardware-Design).
Interne Peripheriekomponenten sind natürlich schon verbunden.
- Der Stackpointer muß per LDS-Befehl gesetzt worden sein, damit die Register
beim Interrupt in den beabsichtigten Stackbereich gerettet werden.
- Die Interrupt-Service-Routine muß programmiert sein.
- gegebenenfalls muß der Interrupt-Verursacher identifiziert werden,
falls mehrere per "wired or" zusammengeschlossen sind.
- das IRQ-FF beim Interrupt-Verursacher muß darin gelöscht werden
- Die Startadresse der ISR muß in den entsprechenden Vektorzellen stehen.
Initialsierung beispielsweise:
ORG $FFFE
DC.W main
- Im Peripheriebaustein-Kontrollregister "interrupt enable" setzen (= Außensperre
öffnen).
- im Prozessor (CC-Register) den entsprechenden Interrupt zulassen (= Innensperre
öffnen).
Im Praktikum geht es vor allem um die Aktionen 3, 4, 5, und 6.
Beispiel 1: Bedingte Unterbrechung am Eingang STRA
Am Eingang STRA ist ein Taster angeschlossen, mit dem eine bedingte Unterbrechung
ausgelöst werden kann. Das Auftreten des Interrupts soll über eine
Variable TFLAG signalisiert werden, die auch über Port C ausgegeben wird.
data equ $2000 Datenbereich
prog equ $8000 Programmbereich
stack equ $7FFF Stackbereich
irqv equ $FFF2 Adresse IRQ-Vektor
resetv equ $FFFE Adresse Reset-Vektor
pioc equ $1002 Adressen Port C
portcl equ $1005
pcdd equ $1007
pcdr equ $1003
org data
tflag ds.b 1
org prog
main lds #stack Init Stack
clr tflag Init Flag
ldab #$FF Port C auf Ausgang
stab pcdd
ldab #$40 Init Interrupt
stab pioc STRA enable
cli Interrupt freigeben
loop ldab tflag Ausgabeschleife
stab pcdr
bra loop
sirq ldaa pioc Interrupt Service Routine
ldaa portcl
com tflag toggle 0 - FF 0 - FF - ...
rti
org irqv Interrupt-Vektor setzen
dc.w sirq
org resetv Reset-Vektor setzen
dc.w main
Beispiel 2: Bedingte Unterbrechung am Eingang PA7
Am Eingang PA7 (Pulse Akku) ist ein Taster angeschlossen, mit dem eine bedingte
Unterbrechung ausgelöst werden kann. Das Auftreten des Interrupts soll über
eine Variable PFLAG signalisiert werden, die auch über Port C ausgegeben wird.
data equ $2000 Datenbereich
prog equ $8000 Programmbereich
stack equ $7FFF Stackbereich
pirqv equ $FFDA Adresse PA-Vektor
resetv equ $FFFE Adresse Reset-Vektor
padr equ $1000 Adresse Port A
pcdd equ $1007 Adressen Port C
pcdr equ $1003
pacr equ $1026 Pulse Akku Control
tflag equ $1025 Timer Flag
tmask equ $1024 Timer Mask
org data
pflag ds.b 1
org prog
main lds #stack Init Stack
clr pflag Init Flag
ldab #$FF Port C auf Ausgang
stab pcdd
ldab #$40 Init Interrupt
stab pacr Pulse Akku enable
ldab #$10
stab tmask PA7 enable
cli Interrupt freigeben
loop ldab pflag Ausgabeschleife
stab pcdr
bra loop
pirq ldaa #$10 Interrupt Service Routine
staa tflg
com pflag toggle 0 - FF 0 - FF - ...
rti
org pirqv Interrupt-Vektor setzen
dc.w pirq
org resetv Reset-Vektor setzen
dc.w main
Beispiel 3: Timer-Unterbrechung
Ein Binärzähler soll mit einer Frequenz von ca. 10 Hz betrieben werden.
Seine Aktuelle Stellung ist an Port C auszugeben. Als Taktquelle ist die bei
Timerüberlauf auftretende Unterbrechung (Timer Overflow Interrupt) des
freilaufenden 16-Bit-Zählers des 68HC11 zu verwenden.
data equ $2000 Datenbereich
prog equ $8000 Programmbereich
stack equ $7FFF Stackbereich
tirqv equ $FFDE Adresse TOF-Vektor
resetv equ $FFFE Adresse Reset-Vektor
padr equ $1000 Adresse Port A
pcdd equ $1007 Adressen Port C
pcdr equ $1003
pacr equ $1026 Pulse Akku Control
tflag equ $1025 Timer Flag
tmask equ $1024 Timer Mask
org data
count ds.b 1 Zaehler
cflag ds.b 1 Clock Flag
org prog
main lds #stack Init Stack
clr count Init Flag
ldab #$FF Port C auf Ausgang
stab pcdd
ldab #$80 Init Interrupt
stab tmask TOF-Interrupt enable
ldab #$40
stab pacr
cli Interrupt freigeben
loop ldab cflag Ausgabeschleife
cmpb #3 Trigger-Zeitpunkt?
bne loop Nein
clr cflag Gotcha!
inc count Zaehler erhoehen
ldab count ...und ausgeben
stab pcdr
bra loop
tirq ldaa #$80 Interrupt Service Routine
staa tflg
inc cflag
rti
org tirqv Interrupt-Vektor setzen
dc.w tirq
org resetv Reset-Vektor setzen
dc.w main
|
|
|