Mit dem Timer A und dem Timer B steht uns ein sehr vielseitiger Funktionsblock zur Verfügung, mit dem viele Funktionen rund um das Zählen und das Messen von Zeit realisiert werden können. Beide Funktionsblöcke sind relativ ähnlich aufgebaut, weshalb sie in einem Kapitel beschrieben sind. Timer B besitzt noch einige Zusatzfunktionen, die im Anschluss daran erläutert werden. Die wesentlichen Eigenschaften des Timerbausteins können wie folgt zusammengefasst werden.
Je nach Variante des Prozessors steht uns eventuell nur der Timer A oder, bei besserer Ausstattung, auch der Timer B zur Verfügung. Auch die Anzahl der Capture/Compare-Register ist unterschiedlich. So hat beispielsweise ein MSP430F1232 nur einen Timer A mit drei Capture/Compare-Registern, ein MSP430F1612 hat einen Timer A mit drei und einen Timer B mit sieben Capture/Compare-Registern. Der grundsätzliche Aufbau ist in beiden Fällen jedoch sehr ähnlich. Der Einfachheit halber wird im Folgenden nur der Timer A beschrieben. Für den Timer B gilt alles analog, lediglich die Registernamen sind entsprechend anzupassen. Das Funktionsdiagramm des Timers A ist in folgendem Bild dargestellt.
Wie man erkennt, kann die Funktionalität des Timers prinzipiell in zwei Funktionsblöcke unterteilt werden. Im oberen Teil ist das eigentliche Zählmodul (”Timer Block”) untergebracht. Zentrales Element ist das Zählregister, das den aktuellen Zählerstand enthält. Umgeben ist es mit etwas Logik, die Zählquelle und Zählmodalität festlegt. Im unteren Teil sieht man die komplexe Funktionalität des Capture/Compare-Funktionsblocks, mit der das Ausgangsverhalten des Timers definiert werden kann.
Bevor man einen Timer benutzen kann, muss er den eigenen Funktionsanforderungen entsprechend konfiguriert werden. Dazu steht ein 16 Bit breites Register, das Timer-A-Control- Register, kurz TACTL zur Verfügung. Die Aufteilung der zugehörigen Steuerbits des TACTL-Registers ist in Bild 4.2 dargestellt.
Wie man erkennen kann, sind die oberen sechs Bits reserviert und haben keine Auswirkung auf die Konfiguration des Timers.
In einem ersten Schritt ist die Taktquelle des Timers festzulegen. Er kann wahlweise aus der Auxiliary-Clock ACLK oder der Sub-Main-Clock SMCLK des Basic-Clock-Moduls (siehe Kap. 3) betrieben werden. Alternativ lässt sich der Timer A auch mit einer externen Taktquelle TACLK, angeschlossen an Port P1.0 oder der Taktquelle INCLK, die an Port P2.1 angeschlossen wird, verknüpfen. Mit den TASELx-Flags legt man die Taktquelle des Timers A fest. Die Zuordnung für die Auswahl der Taktquellen ist in Tabelle 4.1 gelistet.
TASSEL1 | TASSEL0 | Taktquelle |
0 | 0 | TACLK (Port P1.0) |
0 | 1 | ACLK |
1 | 0 | SMCLK |
1 | 1 | INCLK (Port P2.1) |
Tabelle 4.1.: | Auswahl der Taktquelle für den Timer A |
Das Taktsignal kann nach Auswahl der Taktquelle noch zusätzlich um einen Faktor geteilt werden. Dazu dienen die IDx-Flags (Tabelle 4.2).
ID1 | ID0 | Teiler |
0 | 0 | 1 |
0 | 1 | 2 |
1 | 0 | 4 |
1 | 1 | 8 |
Tabelle 4.2.: | IDx-Flags: Software-Teiler für den Timer A |
Auf die Bits und Flags MCx, TAIE und TAIFG kommen wir später noch zu sprechen.
Der Timer A verfügt über ein 16 Bit breites Zählregister TAR, das den derzeitig aktuellen Zählerstand enthält. Auf das Register kann sowohl lesend als auch schreibend zugegriffen werden.
Mit Hilfe des TACLR-Flags im TACTL-Steuerregister wird das Zählregister des Timers (TAR) sowie der Teiler und damit die IDx-Bits gelöscht. Auf dieses Flag kann nur schreibend zugegriffen werden. Liest man den Inhalt von TACLR, erhält man immer den Wert 0. Das TACLR-Flag ist damit eine Art Taster, mit dem man einen Reset für den Timer A ausführen kann. Es wird nach Setzen durch den Anwender automatisch vom Controller wieder gelöscht.
Der Timer A kann in seiner Arbeitsweise flexibel eingestellt werden. Er besitzt insgesamt vier Betriebsarten:
Die gewünschten Betriebsarten Continuous-Mode, Up-Mode, Up/Down-Mode oder Stop-Mode werden durch eine entsprechende Bit-Auswahl der MCx-Flags im TACTL-Register gemäß Tabelle 4.3 ausgewählt.
MC1 | MC0 | Modus |
0 | 0 | Stop-Mode |
0 | 1 | Up-Mode |
1 | 0 | Continuous-Mode |
1 | 1 | Up/Down-Mode |
Tabelle 4.3.: | Auswahl der Betriebsart im TACTL-Register |
Der Timer startet mit dem Zählvorgang, sobald eine andere Betriebsart als der Stop-Mode ausgewählt wurde. Dabei wird der Wert des Registers TAR inkrementiert oder dekrementiert. Beim Up- (Seite §) sowie Up/Down-Mode (Seite §) muss darüber hinaus das Register TACCRO einen von 0 verschiedenen Wert haben. Es wird dringend empfohlen, sämtliche Konfigurationen des Timers nur bei gestopptem Timer durchzuführen. Andernfalls läuft man Gefahr, dass ein sehr merkwürdiges Verhalten des Timers während dieser Zeit entstehen kann.
Beim Continuous-Mode inkrementiert der MSP430 das Register TAR bis zum Wert 65535 (entspricht 0xFFFF in hexadezimaler Schreibweise). Bei eben diesem Maximalwert führt die nächste Taktflanke zum Überlauf und so zu einem Zählerstand 0 des TAR-Zählregisters. Darüber hinaus wird das Timer-A-Interrupt-Flag TAIFG gesetzt.
Nachdem der Zählerstand wieder 0 ist, beginnt der Timer wieder mit der Inkrementierung des Zählregisters. Der gesamte Prozess wiederholt sich also fortlaufend, was in Bild 4.3 beispielhaft für vier Zyklen skizziert ist.
Das Register TAR kann mit Hilfe des TACLR-Flags manuell auf 0 gesetzt werden. Dabei gehen
allerdings auch die Einstellungen des Vorteilers (IDx-Flags) verloren. Beim Auslesen des
Timer-Wertes aus dem TAR-Register müssen wir zusätzlich berücksichtigen, dass der Timer
während der Abarbeitung des Befehls weiterläuft. Für eine sehr genaue Zeitmessung müssten wir
die Ausführungszeit des Lesebefehls bei der Interpretation des Ergebnisses berücksichtigen. Wird
der Timer mit der gleichen Taktgeschwindigkeit wie der Prozessortakt MCLK betrieben, sollte vor
dem Auslesen des TAR-Registers der Timer gestoppt werden. Andernfalls können Zahlüberläufe zu
fehlerhaften Leseergebnissen führen.
Das Beispiel in Listing 4.1 zeigt, wie man mit dem Timer A die Laufzeit einer Funktion messen kann. Die Ausführung muss allerdings weniger als 65535 Schritte betragen, da ja sonst ein Überlauf des Timers eintreten würde. Bei der exakten Berechnung der Laufzeit muss ein OFFSET durch die Dauer der Abarbeitung des Befehls zum Starten und Stoppen des Timers abgezogen werden. Bei diesem Beispiel wurde dieser Offset experimentell ermittelt, indem in einem Vorexperiment der Funktionsaufruf von meine_Funktion() einfach ausgeklammert wurde.
Listing 4.1: | Verwendung des Timers A zur Laufzeitmessung |
Der Up-Mode ist vergleichbar mit dem Continuous-Mode, nur dass der Programmierer hier den Maximalwert des Zählers mit dem Register TACCR0 einstellen kann. Bild 4.4 skizziert den zeitlichen Verlauf des Timers im Up-Mode über vier Zyklen.
Erreicht der Zähler den Wert TACCR0, so wird das Capture/Compare-Interrupt-Flag CCIFG0-Flag im TACCTL0-Register gesetzt (dazu später mehr im Kapitel zu den Capture/Compare-Registern). Ein erneuter Taktimpuls setzt das Zählregister wieder auf 0 und das Timer-A- Interrupt-Flag (TAIFG) wird gesetzt.
In Abhängigkeit von der gewählten Taktquelle ergibt sich für jeden Zählerstand ein zugehöriges Zeitintervall. Analog dazu kann man für einen gesamten Zyklus, also für den Zählerstand 65535 ebenfalls einen Zeitintervall berechnen. Bei Verwendung der Auxiliary-Clock mit einer Frequenz von 32.768kHz und einem Software-Teiler von 1 (ID0 = 0 und ID1 = 0) entspricht das Zählinkrement eins einem Zeitintervall von rund 31μs. Der Zählerstand 200 entspricht analog dazu einem Zeitinvertvall von etwa 6.12ms. Gleichung 4.1 beschreibt, wie das Zeitintervall T in Abhängigkeit von der Taktquellen-Frequenz fCLK, dem Software-Teiler ID0 und ID1 und dem Zählerstand TAR berechnet werden kann.
Im folgenden Programm soll der Timer A jetzt so initialisiert werden, dass mit einem extern angeschlossenen Uhrenquarz mit einer Frequenz von 32.768kHz der Timer-Interrupt einmal pro Sekunde auftritt. In der Interrupt-Service-Routine implementieren wir eine kleine Echtzeituhr.
Listing 4.2: | Eine Echtzeituhr auf Basis des Timers A |
Bisher haben wir mit dem Continuous- und Up-Mode zwei Betriebsarten kennengelernt, bei denen der Mikroprozessor von 0 bis zu einem bestimmten Maximalwert vorwärts zählt. Der Up/Down-Mode kombiniert einen Vorwärts- und Rückwärtszähler. In einem Zyklus inkrementiert der Prozessor das Zählerregister zunächst bis zum Maximalwert TACCR0. Unmittelbar beim Erreichen des Maximalwerts wird das CCIFG0-Flag gesetzt.
Anders als beim Up-Mode ändert sich bei Erreichen von TACCR0 nun die Zählrichtung. Der Prozessor zählt vom Maximalwert rückwärts bis zum Wert 0 und setzt dann das TAIFG-Flag. Bild 4.5 skizziert den zeitlichen Verlauf des Zählregisters über drei Zyklen. Die gesamte Periodendauer T eines Zyklus’ lässt sich mit Gleichung 4.2 berechnen. Sie entspricht gerade dem Doppelten der Periodendauer, wenn der Timer A im Up-Mode betrieben wird, bei gleichem TACCR0.
Dabei ist fCLK die Frequenz der Taktquelle, die durch den Software-Teiler ID0 und ID1 für den Timer A konfiguriert werden kann.Der Zählvorgang kann während des Up/Down-Modus unterbrochen werden. Dabei merkt sich der Mikroprozessor den Wert des Zählregisters und die Zählrichtung (vorwärts oder rückwärts). Setzt man das TACLR-Flag, so wird der Timer neu initialisiert. Damit wird das Zählregister auf 0 gesetzt und die Zählrichtung auf vorwärts festgelegt.
Der Up/Down-Modus eignet sich für die Erzeugung von symmetrischen pulsweitenmodulierten Signalen, die wir im Kapitel 7.4.1 noch näher kennenlernen werden.
Um den Timer A in den Stop-Mode zu schalten, müssen die Bits MC0 und MC1 gelöscht werden. Dabei wird der Zählvorgang angehalten, ohne den Zählstand oder die Zählrichtung zu ändern. Will man den Wert des Zählregisters TAR auslesen, so sollte vorher der Timer gestoppt werden. Ansonsten geht in den Zählstand auch die für das Lesen des Registers TAR benötigte Zeit ein.
Listing 4.3: | Anhalten des Timers A |
Bisher haben wir uns auf das Zählregister sowie dessen Konfiguration konzentriert. Im jetzt folgenden Abschnitt soll es um die erweiterten Auswertemöglichkeiten mit Hilfe der so genannten Capture/Compare-Kanäle (CCRx) gehen. Je nach Ausstattung des Prozessors gibt es von diesen Kanälen pro Timer drei, fünf oder sieben Stück. Alle Kanäle eines Timers teilen sich das gleiche Zählregister (TAR). Jeder Capture/Compare-Kanal hat als zentrale Komponente ein Register sowie eine zugehörige Steuerlogik, die das Ein- und Ausgangsverhalten des Funktionsblocks definiert. Ein Blockschaltbild der Capture/Compare-Funktionseinheit, diesmal des Timers B, zeigt Bild 4.6 (vergleiche dazu auch den Timer A, Bild 4.1).
Der Kanal 0 (CCR0) ist den anderen Kanälen übergeordnet. Diesen Kanal haben wir im vorigen Kapitel benutzt, um das Zählverhalten des Timers zu beeinflussen (z.B. zum Einstellen der Zählgrenze im Up/Down-Mode).
Im Capture-Modus lassen sich Zeitmessungen bestimmten Ereignissen zuordnen. Das heißt, dass man sich z.B. den Zählerstand automatisch merken kann, wenn der Status eines externen Pins wechselt. Im Compare-Modus wird der Wert des Timer-Registers ständig mit dem Compare-Register verglichen und abhängig davon wird z.B. ein Interrupt ausgelöst. Mit Hilfe der Timer-Kanäle lassen sich also Zeitpunkte und Zeitstempel zuordnen sowie Ereignisse auslösen, ohne dass dazu Ressourcen der CPU benötigt werden.
Die Konfiguration der Capture- und Compare-Funktion wird mit Hilfe des Capture/Compare-Control-Registers TACCTLx durchgeführt. Jeder Timer-Kanal verfügt dabei über ein eigenes TACCTLx-Register. Auf dem MSP430F1612 sind beispielsweise drei Timer-Kanäle für Timer A implementiert. Als Konfigurationsregister stehen damit TACCTL0, TACCTL1 und TACCTL2 zur Verfügung.
Die Bitbelegung des 16 Bit breiten Capture/Compare-Control-Registers ist in Bild 4.2 dargestellt und bei allen Timer-Kanälen identisch aufgebaut.
Zu Beginn des Kapitels 4.1.3 wurde darauf verwiesen, dass der MSP430 mit Hilfe der Capture/Compare-Funktionalität Ereignissen Zeitmarken und Zeitstempel zuweisen kann. Ereignisse sind Flanken- bzw. Pegelwechsel an bestimmten Portpins oder Taktquellen. Prinzipiell kann man unterscheiden, ob man auf eine steigende, eine fallende oder sowohl auf eine steigende als auch eine fallende Flanke reagiert.
CMx | Funktion |
00 | Keine Funktion |
01 | Reaktion auf steigende Flanke |
10 | Reaktion auf fallende Flanke |
11 | Reaktion auf steigende und fallende Flanke |
Tabelle 4.4.: | Flankengetriggerte Reaktion für die Capture/Compare-Funktion |
Diese Einstellung kann mit den CMx-Flags (Tabelle 4.4) konfiguriert werden. Jedem Timer-Kanal kann eine eigene Flankentriggerung zugewiesen werden.
Die Auswahl der Eingangsgröße des Ereignisses kann gleichermaßen für jeden Kanal individuell vorgenommen werden. Dazu dienen die Capture/Compare-Input-Select-Bits (CCISx). Wie wir in Tabelle 4.5 sehen, können insgesamt vier Eingangsereignisse ausgewählt werden.
CCISx | Funktion |
00 | CCIxA |
01 | CCIxB |
10 | GND |
11 | VCC |
Tabelle 4.5.: | Auswahl der Eingänge für die Capture/Compare-Funktion |
Die Signale CCIxA und CCIxB sind symbolische Platzhalter. Deren Zuordnung bzw. Anschluss ist
unterschiedlich für jeden Timer-Kanal und variiert für die verschiedenen MSP430-Typen. Die
genaue Zuordnung ist dem jeweiligen Datenblatt zu entnehmen. Als weitere Signal-Anschlüsse
können auch die konstanten Signale GND und VCC verwendet werden. Sinn ergeben diese
Zuweisungen erst, wenn man durch Software zwischen beiden Zuständen wechselt. So kann man
dann per Software die Capture/Compare-Funktionalität bedienen und zum Beispiel die Laufzeiten
von Programmteilen messen.
Beispielhaft für die MSP430F16xx-Baureihe ist in Tabelle 4.6 die Zuordnung der Eingangsereignisse zu CCIxA und CCIxB für den Timer A (oben) und Timer B (unten) zu sehen. Die Eingänge können zum Beispiel ein externer Portpin (z.B. P1.1) sein, aber auch interne Signale, wie die ACLK oder der Ausgang des Comparator-A-Moduls (Kapitel 6).
Signal | Signal-Anschluss | Timer-Kanal | |
CCI0A | P1.1 | TACCR0 | |
CCI0B | P2.2 | TACCR0 | |
CCI1A | P1.2 | TACCR1 | |
CCI1B | CAOUT (intern) | TACCR1 | |
CCI2A | P1.3 | TACCR2 | |
CCI2B | ACLK (intern) | TACCR2 | |
Signal | Signal-Anschluss | Timer-Kanal | |
CCI0A+B | P4.0 | TBCCR0 | |
CCI1A+B | P4.1 | TBCCR1 | |
CCI2A+B | P4.2 | TBCCR2 | |
CCI3A+B | P4.3 | TBCCR3 | |
CCI4A+B | P4.4 | TBCCR4 | |
CCI5A+B | P4.5 | TBCCR5 | |
CCI6A | P4.6 | TBCCR6 | |
CCI6B | ACLK (intern) | TBCCR6 | |
Tabelle 4.6.: | Signale und deren Signal-Anschlüsse für die Capture/Compare-Funktion |
Wenn das CIE-Flag gesetzt ist, triggert der MSP430 im Capture- bzw. Compare-Fall einen
Interrupt. Ist das Flag gelöscht, so wird kein Interrupt generiert. Der Interrupt kann
mit Hilfe des CCIFG-Flags ausgewertet werden. Zur Dekodierung der Interrupts der
Timer-Kanäle gibt es ein weiteres Register, das Timer-A- Interrupt-Vector (TAIV)-Register, Bild
4.8.
Mit den TAIV-Bits erfolgt eine Codierung der verschiedenen Interrupts der Capture/Compare-Kanäle gemäß Tabelle 4.7. Auf den ersten Blick mag die Position der TAIV-Bits komisch erscheinen, aber auf diese Art und Weise kann der Vektor einfach als Eingang einer Sprungtabelle genutzt werden. Eine entsprechende Beispielimplementierung für den Timer A ist in Listing 4.4 zu finden.
TAIV | Quelle | Interrupt Flag | |
00h | kein Interrupt | ||
02h | Cap/Comp. 1 | TACCR1 CCIFG | |
04h | Cap/Comp. 2 | TACCR2 CCIFG | |
06h | reserviert | ||
08h | reserviert | ||
0Ah | Timer overflow | TAIFG | |
0Ch | reserviert | ||
0Eh | reserviert | ||
TBIV | Quelle | Interrupt Flag | |
00h | kein Interrupt | ||
02h | Cap/Comp. 1 | TBCCR1 CCIFG | |
04h | Cap/Comp. 2 | TBCCR2 CCIFG | |
06h | Cap/Comp. 3 | TBCCR3 CCIFG | |
08h | Cap/Comp. 4 | TBCCR4 CCIFG | |
0Ah | Cap/Comp. 5 | TBCCR5 CCIFG | |
0Ch | Cap/Comp. 6 | TBCCR6 CCIFG | |
0Eh | Timer overflow | TBIFG | |
Tabelle 4.7.: | Dekodierung der Interrupts der Capture/Compare-Kanäle für Timer A und Timer B |
Listing 4.4: | Sprungtabelle zur Dekodierung des Timer A Interrupts, nach [Tex06b] |
Am Anfang dieses Kapitels (siehe z.B. Listing 4.2) haben wir auch schon eine Interrupt-Funktion
des Timers verwendet. Dort war es allerdings die Interrupt-Funktion des Capture/Compare-Kanals
0, die einen eigenen Interrupt-Vektor (TIMERA0_ISR respektive TMERB0_ISR) besitzt. Dem
Interrupt-Vektor TIMERA1_ISR sind alle anderen Interrupt-Ereignisse des Timers zugeordnet.
Durch die Struktur der Switch-Case-Anweisung in Listing 4.4 gelingt es dem Compiler, diese in
einer einfachen Sprungtabelle abzubilden. Vor dem jeweiligen Break können entweder direkt die
zum Interrupt gehörigen Befehle eingefügt oder, alternativ, eine eigene Funktion aufgerufen werden.
Die Verwendung der compilereigenen _never_executed()-Funktion führt dazu, dass die
Switch-Anweisung ohne Bereichsüberprüfung und nur für die genannten Werte implementiert
wird.
Mit dem Timer A/B können an den Digitalports Signale, beispielsweise ein pulsweitenmoduliertes Signal, ausgegeben werden. Für diese Funktionalität stehen die Bits OUTMODx zur Verfügung. Die logischen Pegel an den Digitalports hängen dann je nach Einstellung der OUTMODx-Bits vom Zählregister TACCR0 und/oder TACCRx vom jeweiligen Timer-Kanal ab und sind dem Datenblatt zu entnehmen. Am Beispiel des pulsweitenmodulierten Signals wird diese Funktionalität noch einmal in Kapitel 7.4 verdeutlicht.
Mit der Capture-Funktion kann man Ereignissen eine Zeitmarke zuordnen. Aus zwei Zeitmarken lassen sich Zeitdifferenzen bestimmen, ohne auf Software und damit auf Rechenleistung der CPU zurückgreifen zu müssen. Erkennt der MSP430 ein Ereignis über ein Signal (vgl. vorherige Abschnitte), so speichert er den Wert des Timers TAR im Register TACCRx des jeweiligen Timer-Kanals (zum Beispiel TACCR2 für Timer-Kanal 2).
Um die Capture-Funktion auszuwählen, muss das CAP-Flag im TACCTLx-Register gesetzt werden. Wenn das Flag gelöscht ist, arbeitet der Kanal mit der Compare-Funktion.
Das SCS-Flag im TACCTLx-Register sollte insbesondere bei schnellen Anwendungen gesetzt werden. Wird beispielsweise ein Ereignis erkannt, während der Timer TAR sich gerade im Inkrementierungsvorgang befindet, so kann es zu fehlerhaften Zeitstempeln im TACCRx-Register kommen. Das SCS-Flag synchronisiert den Timer mit der Capture-Funktion, um solche Probleme zu vermeiden.
Wenn zwei Ereignisse in einer kurzen Zeitabfolge hintereinander erkannt werden, kann es zu einem
Überschreiben des TACCRx-Registers kommen, ohne dass dieses vorher gelesen werden
konnte. Die Berechnung einer Zeitdifferenz würde damit unmöglich werden. Der MSP430
ist zwar nicht in der Lage dieses Problem zu beheben, allerdings bietet der Timer A
mit Hilfe des COV-Flags im TACCTLx-Register die Möglichkeit einen Überlauf, also
das Überschreiben des Wertes im TACCRx-Registers, zu erkennen. Das Flag kann im
Programm ausgelesen und ausgewertet werden. Es muss aber manuell zurückgesetzt
werden.
Im folgenden Beispiel schließen wir an den Pin P1.2, dem Eingangspin des Timer-A-Capture/Compare-Kanals 1, ein Rechtecksignal an. Wir wollen nun dessen Periodendauer mit Hilfe des Timers A bestimmen. Der Einfachheit halber gehen wir davon aus, dass eine Periode maximal 65535 Taktzyklen der SMCLK und minimal die Laufzeit der Interruptfunktion dauert.
Listing 4.5: | Bestimmung der Periodendauer eines Rechtecksignals an P1.2 mit Hilfe des Timers A im Capture-Mode |
Die Compare-Funktionalität wird dafür verwendet, den Status des Timerausgangs abhängig von einem Vergleich mit einem Referenzregister (TACCRx-Register) zu schalten. Dies kann man dazu verwenden z.B. zeitgesteuerte Ausgangssignale (PWM, siehe Kapitel 7.4) oder verschieden schnelle Zeitscheiben eines Echtzeitbetriebssystems zu erzeugen.
Um die Compare-Funktion auszuwählen, muss im TACCTLx-Register (vgl. Bild 4.7) das
CAP-Flag gelöscht werden. Nun wird das Timer-Zählregister TAR kontinuierlich, ohne
weiteres Zutun des Prozessors, über eine Komparatorlogik mit dem TACCRx-Register
verglichen. Entspricht der Wert im TACCRx-Register dem Zählerstand, so wird das interne
EQUx-Signal gesetzt. Mit ihm werden verschiedene Output-Modi des Timers ausgelöst.
Gleichzeitig wird auch das entsprechende CCIFG-Flag gesetzt und, bei gesetztem CIE-Flag, ein
Interrupt generiert. Als weitere Reaktion (dies gilt nur für Timer A) übernimmt das
SCCI-Flag den Status des Capture/Compare-Input-Blocks (CCI, siehe Seite §). Timer B hat
stattdessen eine zusätzliche Auswertlogik, auf die wir aber erst in Kapitel 4.1.4 eingehen
werden.
Jeder Capture/Compare-Kanal hat einen eigenen Ausgangspin. Dieser kann natürlich erst als Hardware-Ausgang genutzt werden, wenn die entsprechenden Port-Register (siehe Kapitel 2, PxSEL und PxDIR) richtig gesetzt sind. Eine komplexe Schaltlogik (”Output-Unit”) definiert das Ausgangsverhalten. Insgesamt sind acht verschiedene Modi verfügbar, die durch die OUTMODx-Bytes im TACCTLx-Register definiert werden. Tabelle 4.8 zeigt eine Übersicht.
Das folgende Listing zeigt beispielhaft, wie der Timer A zur Erzeugung eines periodischen Rechtecksignals mit einstellbarer Frequenz, das an P1.1 abzugreifen ist, verwendet werden kann.
Listing 4.6: | Erzeugen eines Rechtecksignals mit dem Timer A |
OUTMODx | Mode | Beschreibung |
000 | Output | Der Ausgang entspricht direkt dem Wert des OUT-Bits im TACCTLx-Register |
001 | Set | Der Ausgang wird gesetzt, wenn der Timer bis zum Wert des TACCRx-Registers gezählt hat. Er behält seinen Zustand bis zu einem Reset des Timers. |
010 | Toggle/Reset | Der Ausgang wechselt seinen Zustand, wenn der TACCRx-Wert erreicht wird. Erreicht der Timer den TACCR0-Wert, erfolgt ein Reset. |
011 | Set/Reset | Der Ausgang wird gesetzt, wenn der TACCRx-Wert erreicht wird. Erreicht der Timer den TACCR0-Wert, erfolgt ein Reset. |
100 | Toggle | Der Ausgang wechselt seinen Zustand, wenn der TACCRx-Wert erreicht wird. |
101 | Reset | Der Ausgang wird gelöscht, wenn der Timer bis zum Wert des TACCRx-Registers gezählt hat. Er behält seinen Zustand bis zu einem Reset des Timers. |
110 | Toggle/Set | Der Ausgang wechselt seinen Zustand, wenn der TACCRx-Wert erreicht wird. Erreicht der Timer den TACCR0-Wert, wird der Ausgang gesetzt. |
111 | Reset/Set | Der Ausgang wird gelöscht, wenn der TACCRx-Wert erreicht wird. Erreicht der Timer den TACCR0-Wert, wird er gesetzt. |
Tabelle 4.8.: | Konfiguration des Timer-Ausgangsverhaltens |
Besseres Verständnis für das Ausgangsverhalten des Timers bekommt man, wenn man sich das Verhalten der verschiedenen Modi bei den unterschiedlichen Timer-Betriebsarten (siehe Kapitel 4.1.2) betrachtet. Bild 4.9 zeigt das Ausgangsverhalten für den Continuous-Mode (links) und den Up-Mode (rechts) für jeweils zwei Perioden.
Das Ausgangsverhalten des Up/Down-Modes über zwei Perioden ist in Bild 4.10 exemplarisch skizziert.
Eine weitere Anwendung des Timers, bei der die Mehrkanaligkeit voll ausgenutzt werden kann, ist die Ableitung verschiedener Systemtakte eines Echtzeitbetriebssystems aus einem Timerbaustein. Wenn man sich näher mit dem Thema Echtzeitbetriebssysteme und Datenkonsistenz beschäftigen möchte, sei z.B. das Buch von David E. Simon [Sim99] empfohlen. Im Folgenden sei hier nur ein kleines Beispiel dafür erklärt. In einem Echtzeitbetriebssystem sollen drei Tasks implementiert werden:
Die Tasks FAST und SLOW werden in Interrupt-Routinen implementiert. Da der Task FAST höchste Priorität hat, muss er alle weniger prioren Tasks unterbrechen können. Dies wirft für den Fall des SLOW-Tasks ein gewisses Problem auf. In allen bisherigen Interrupt-Beispielen wurden Interrupts exklusiv verarbeitet und konnten nicht unterbrochen werden. Soll aber nun ein Interrupt durch einen weiteren Interrupt unterbrochen werden, muss man in der entsprechenden Interrupt-Routine einfach nochmals das Global-Interrupt-Enable-Bit setzen. Eine Grundvoraussetzung für das korrekte Funktionieren ist natürlich, dass die Interrupt-Funktionen auch in der Summe der Zeit abgearbeitet werden können.
Listing 4.7: | Ein kleines Echtzeit-Tasksystem mit dem Timer A |
In allen wesentlichen Funktionen gleichen sich Timer A und Timer B, einige wenige Unterschiede gibt es jedoch, auf die in diesem Kapitel eingegangen werden soll: Das Bild 4.11 zeigt das Timer-B-Kontrollregister. Die Bits 11-14, die beim Timer A noch unbenutzt waren, haben jetzt eine Funktion.
Die Länge des Timers B ist auf 8, 10, 12 oder 16 Bit einstellbar. Dies erfolgt mit den CNTLx-Bits im Steuerregister. Tabelle 4.9 zeigt die entsprechende Zuordnung.
CNTL1 | CNTL0 | Länge Register | maximaler Wert |
0 | 0 | 16-bit | TBR(max) = 0FFFFh |
0 | 1 | 12-bit | TBR(max) = 0FFFh |
1 | 0 | 10-bit | TBR(max) = 03FFh |
1 | 1 | 8-bit | TBR(max) = 0FFh |
Tabelle 4.9.: | Einstellbare Registerlänge für Timer B |
Die Timer-B-Capture/Compare-Register sind alle doppelt gepuffert. Somit können Schreib- und Lesekonflikte vermieden werden.
Mit den TBCLGRP-Bits kann man mehrere Capture/Compare-Register des Timers zu gleicher Funktion zusammenfassen. Damit lassen sich z.B. PWM-Ausgaben mehrerer Kanäle exakt synchronisieren, siehe Tabelle 4.10.
TBCL1 | TBCL0 | Beschreibung |
0 | 0 | Jedes TBCLx schaltet unabhängig |
0 | 1 | TBCL1+TBCL2 (TBCCR1 CLLDx Bits ) |
TBCL3+TBCL4 (TBCCR3 CLLDx Bits ) |
||
TBCL5+TBCL6 (TBCCR5 CLLDx Bits ) |
||
TBCL0 unabhängig |
||
1 | 0 | TBCL1+TBCL2+TBCL3 (TBCCR1 CLLDx Bits ) |
TBCL4+TBCL5+TBCL6 (TBCCR4 CLLDx Bits ) |
||
TBCL0 unabhängig |
||
1 | 1 | TBCL0+TBCL1+TBCL2+TBCL3+TBCL4+TBCL5+TBCL6 |
(TBCCR1 CLLDx Bits bestimmen Verhalten) |
||
Tabelle 4.10.: | Gruppierung der Timer-B-Capture/Compare-Kanäle |
Mit dem TBOUTH-Pin, der z.B. beim MSP430F1612 dem Pin 5.7 entspricht, können die Ausgangspins des Timers B in einen hochohmigen Zustand gesteuert werden. Hierzu muss ein HIGH-Signal an den Pin angelegt werden. Natürlich muss vorher in der Konfiguration des Pins 5.7 die entsprechende Funktion ausgewählt sein.
Die SCCI-Bit-Funktion existiert nicht. Somit kann das CCI-Capture/Compare-Input-Signal nicht mehr intern synchronisiert ausgelesen werden. Dies ist aber Dank der schon erwähnten doppelt-gepufferten Register auch nicht mehr nötig