Forum: Mikrocontroller und Digitale Elektronik MSP430xG46x TimerB Capture Compare Register Funktion


von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Moin,

ich arbeite mit einem MSP430FG4618 und möchte an 3 Pins jeweils ein 
Rechtecksignal ausgeben. Diese sollen am Ende jeweils um 120° 
Phasenverschoben sein.

Begonnen habe ich mit der Erzeugung eines Rechtecksignals.
Dazu habe ich den TimerB mit dem TimerClock ACLK definiert und ihn im 
Continousmode gestartet.

Das Capture/Compare Register 0 verwende ich, um ein Rechtecksignal zu 
erzeugen, was letztendlich auf Pin 5.1 ausgegeben wird.
Das klappt auch wunderbar.

Nun habe ich in meiner Unerfahrenheit einfach mal ein zweites Register 
... Capture/Compare Register 1 ebenfalls mit einem Wert "32768" 
beschrieben.
Das sorgt nun aber dafür, dass mein gesamtes Programm immer wieder von 
vorne gestartet wird. Und zwar in dem Intervall, wie ich es über das 
CCR1 definiert habe. Bei 32768 ist das 1 sec.

Kann mir nochmal jemand erklären, WARUM man für die Register das CCIE 
setzt?

Ob mit dem Ausdruck TBCCTL0 = CCIE; das CCIE nur für das CCR0 gesetzt 
wird, oder für alle CC-Register?

Und wie sorge ich dafür, dass das Taktsignal mit welches über TBCCR1 
definiert ist, auf einen anderen PIN als P5.1 ausgegeben wird und nicht 
ständig mein Programm neustartet bzw. von vorne abarbeitet?

Hoffe auf hilfreiche Hinweise.
Stefan.

von greg (Gast)


Lesenswert?

CCIE aktiviert den Interrupt-Request für das jeweilige CCR.

Wenn du schon das zweite CCR mit Interrupts benutzt, solltest du dafür 
auch den Interrupt-Handler definieren. Sonst springt die CPU ins 
nirgendwo und das kann dann wie ein Reset wirken.

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

greg schrieb:
> CCIE aktiviert den Interrupt-Request für das jeweilige CCR.
>
> Wenn du schon das zweite CCR mit Interrupts benutzt, solltest du dafür
> auch den Interrupt-Handler definieren.

Was bedeutet das, "Interrupt-Handler"?
Meinst du eine Interrupt-Service-Routine?

Für das CCR1 klappt das dann sogar :)

Nun muss da noch ein 3. ran ... Allerdings gibt es keine Definition mehr 
für
"#pragma vector=TIMERB2_VECTOR"

Und beide Signale laufen nun auch mit einer unterschiedlichen Frequenz. 
Wie kann man beide Frequenzen aneinander anpassen? Nur über das 
jeweilige Register? Oder muss ich noch TB1CTL definieren?

Eine alternative für 3 Rechtecksignale habe ich auch in den Beispielen 
von TI gefunden. Das ist die msp430x46x_tb_10.c. Das sieht schonmal sehr 
gut aus. Die Dutycycle hab ich schon so verändert, dass alle drei 
Signale eine PWM von 50% ausgeben. Nun stellt sich nur noch die Frage, 
ob man jeweils ein Signal um 120° Phasenverschieben kann? Und wenn ja, 
wie man das macht :)

Jedes Register beinhaltet den gleichen Wert und gibt somit zur selben 
Zeit seinen überlauf. Irgendwie müsste man dafür sorgen, dass bei dem 
einen TCCR später angefangen wird mit zählen, als bei dem anderen. Und 
das geht doch eigentlich nur, mit einem anderen Takt, oder?
Oder würde es auch mit einem Delay oder einer Whileschleife klappen?

von greg (Gast)


Lesenswert?

Stefan M. schrieb:
> Was bedeutet das, "Interrupt-Handler"?
> Meinst du eine Interrupt-Service-Routine?
>

Ja. Interrupt-Handler klingt IMO nicht ganz so hölzern. ;)

>
> Nun muss da noch ein 3. ran ... Allerdings gibt es keine Definition mehr
> für
> "#pragma vector=TIMERB2_VECTOR"
>

Die Vektoren für die CCRs sind teilweise multiplexed, siehe Datasheet. 
Du musst innerhalb deines Handlers dann bestimmen, welche Quelle der 
Interrupt hatte.

> Und beide Signale laufen nun auch mit einer unterschiedlichen Frequenz.
> Wie kann man beide Frequenzen aneinander anpassen? Nur über das
> jeweilige Register? Oder muss ich noch TB1CTL definieren?
>

Naja, die Frequenz justierst du doch selber, je nachdem wie du das 
CC-Register verstellst... was meinst du damit?

> Eine alternative für 3 Rechtecksignale habe ich auch in den Beispielen
> von TI gefunden. Das ist die msp430x46x_tb_10.c. Das sieht schonmal sehr
> gut aus. Die Dutycycle hab ich schon so verändert, dass alle drei
> Signale eine PWM von 50% ausgeben. Nun stellt sich nur noch die Frage,
> ob man jeweils ein Signal um 120° Phasenverschieben kann? Und wenn ja,
> wie man das macht :)
>

Da musst du die richtigen Startbedingungen schaffen. Schalte den Timer 
ab, setze das Timerregister und die CC-Register (jeweils um 120° 
verschoben), schalte die IRQs ein und dann lasse den Timer loslaufen.

Gehen wir mal davon aus, du hast eine Periodenlänge von 6000 
Timerzyklen.
6000 / 3 = 2000. Also kannst du bspw. den Timer auf 0xFFFF setzen und 
die CCRs auf 0, 2000, 4000. In den Interrupt-Handlern inkrementierst du 
die CCRs dann immer um 3000, um 50% duty cycle zu erreichen.

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

> Naja, die Frequenz justierst du doch selber, je nachdem wie du das
> CC-Register verstellst... was meinst du damit?

Meine genau das ;)

> Da musst du die richtigen Startbedingungen schaffen. Schalte den Timer
> ab, setze das Timerregister und die CC-Register (jeweils um 120°
> verschoben), schalte die IRQs ein und dann lasse den Timer loslaufen.

Meinst du mit IRQ's einschalten TBCCTL0 = CCIE oder würde es auch mit 
einem general interrupt gehene? Hm, glaube die Frage kann ich mir selbst 
beantworten. mit einem GIE würde ja die Zuordnung zu den einzelnen 
Registern fehlen :D

> Gehen wir mal davon aus, du hast eine Periodenlänge von 6000
> Timerzyklen.
> 6000 / 3 = 2000. Also kannst du bspw. den Timer auf 0xFFFF setzen und
> die CCRs auf 0, 2000, 4000. In den Interrupt-Handlern inkrementierst du
> die CCRs dann immer um 3000, um 50% duty cycle zu erreichen.

Ich benötige dann ja 3 ISR für den TimerB. Wie genau ist so eine Routine 
denn aufgebaut und kann man die in der Headerdatei selber noch weitere 
"nachdefinieren"?

Hier mal als Beispiel zur Erklärung für mich:

>// Timer B0 interrupt service routine
>#pragma vector=TIMERB0_VECTOR
>__interrupt void Timer_B (void)
>{
>  P5OUT ^= 0x02;                     // Toggle P5.1
>  TBCCR0 +=500;
>}

Also, welcher Teil bestimmt die Interruptzugehörigkeit?
ich würde ja jetzt einfach auf die folgende Zeile tippen:
>__interrupt void Timer_B (void)

Timer_B gibt es doch aber nur einmal. Das Interrupt vom RegisterX ist 
doch entscheidend, oder?

Und wenn ich jetzt zum Beispiel TBCCTL0 = CCIE setze und TBCCTL1 = CCIE 
...
woher weiß ich, oder wie bestimme ich in der ISR, das der registrierte 
Interrupt von CCR0 kommt und nicht von CCR1?

Im Anhang mein bisheriger Fortschritt :D
Timer gestoppt, Timerregister0 gesetzt.
Den 120° Versatz habe ich noch nicht in die Register geschrieben, da mir 
ja noch die IRQ's und die ISR's fehlen.

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Also wenn ich das richtig verstanden habe, sollte das ganze so gehen.

Alle TimerB-Interupts gehen in die selbe Interrupt-Routine oder Handler 
wie man will, dort ist es deine Aufgabe festzustellen, welcher Interrupt 
es genau ist.

Es gibt für den Timer das TBIFG und den jeweiligen TBCCRx die jeweilige 
Kombination zeigt genau an um welchen Interrupt es sich handelt, sprich 
um welches C&C-Register. Da wir alle faul sind hat Ti aber das TBIV 
register erfunden hier wird in 3 Bit reingeschreiben welcher Interrupt 
ausgelöst wurde (Im User Manual unter Timer_B Interrupt Vector Register; 
zumindest bei meiner Family).

Damit benötigst du nur einen ISR bzw. es gibt nur einen ISR und in 
diesem stellst du dann wiederum fest, welches C&C ausgelöst hat.

Um einen anderen Ausgang zu belegen musst du ihn einfach Toggeln und ihn 
vorher natürlich als Output definieren.

von Stefan M. (stefan_m)


Lesenswert?

Fabian Hof schrieb:
> Also wenn ich das richtig verstanden habe, sollte das ganze so gehen.
> Alle TimerB-Interupts gehen in die selbe Interrupt-Routine [...]
> dort ist es deine Aufgabe festzustellen, welcher Interrupt es genau ist.

Das zu hören freut mich schon mal, denn alle 3 Pins gleichzeitig togglen 
kann ich ja. Und in eine ISR zu springen, hab ich ja auch schon 
geschafft :D

> Es gibt für den Timer das TBIFG und den jeweiligen TBCCRx [...]TBIV
> register [...]

Von diesem Flag und diesem Register habe ich schon gelesen in der 
Dokumentation. Da ich aber bis eben noch so darauf fixiert war, die 
ganze Problematik in mehreren ISR's zu verwirklichen, bin ich dieser 
Sache noch nicht weiter nachgegangen.

Vielen Dank für deine Hilfe. Manchmal muss man die Dinge eben aus einer 
anderen Sicht betrachten, um voran zu kommen :)

Mal sehen ob ich das morgen dann auf die Reihe bekomme. Für heute bin 
ich erstmal bedient. Mein Compiler stürzt ständig ab -.-

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Soooo,

hier mal ein Update. Allerdings noch nicht vollendet.

Alle PINS wurden Initialisiert und die CCR's ebenfalls gesetzt.
Allerdings glaube ich zu ahnen warum das ganze noch nicht so 
funktioniert wie ich will.

Wie ihr seht, sind in der ISR die PINS P2.3 und P3.4 eigentlich 
deaktiviert. Bzw. werden sie in der Routine nicht zum toggln angeregt.
Jedoch hab ich dennoch ein PWM Signal auf diesen PINS.
Hängt das mit der Pin-Initialisierung zusammen PxSEL ?
Damit wird doch die Funktion des PINs aktiviert, oder? Naja, steht 
jedenfalls so im Datenblatt.

Aber wenn ich das PxSEL nicht setze, dann habe ich kein Signal am 
Ausgang.

Hat da jemand vielleicht noch mal eine nette Umschreibung dieser 
Problematik, wie ich meine PINs initialisieren muss, damit ich in der 
ISR dann auch mittels TBIV des jeweilige CCRx Signal wählen kann.

Am Ende will ich das ja noch verschieben.

von Stefan M. (stefan_m)


Lesenswert?

Und außerdem steht im Datenblatt auch, dass beim setzen des PxSEL = 1, 
das Interrupt für diesen PIN deaktiviert wird. Dann könnte ich doch 
eigentlich gar nicht mit so einer Initialisierung in die ISR hüpfen, 
oder?

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Nicht ganz richtig, in meinem Datenblatt steht.
1
Primary peripheral module function is selected.

Hier mal ein Code für Capture Compare bei TimerA:
1
TACTL = TACLR + MC_2 + ID_0 + TASSEL_2;
2
  TACCTL0 = CM_2 + CCIS_0 + CAP + CCIE;
3
  P1SEL |= BIT1;
4
  P1DIR&=~0x02;

Das reicht um die C&C Funktion zu nutzen. Damit springt er bei jeder 
hi/lo oder hi/lo habs nicht im Kopf in den ISR.

von Stefan M. (stefan_m)


Lesenswert?

>
1
Primary peripheral module function is selected.

Korrekt. Bei mir heißt es:
1
 Each PxSEL bit is used to select the pin function - I/O port or periphal module function

In einer darunterfolgenden Notiz heißt es:
1
 NOTE: P1 and P2 Interrupts Are Disabled When PxSEL = 1
2
When any P1SELx or P2SELx bit is set, the corresponding pin's interrupt function is disabled.

Also kann ich das PxSEL drin lassen :)?
Ich versuch das gleich mal mit dem Codebrocken von Fabian.

Ach und -->
> bei jeder hi/lo oder hi/lo
oder meinst du lo/hi bzw. lo/hi g

von Stefan M. (stefan_m)


Lesenswert?

>
1
TACTL = TACLR + MC_2 + ID_0 + TASSEL_2;
2
>   TACCTL0 = CM_2 + CCIS_0 + CAP + CCIE;
3
>   P1SEL |= BIT1;
4
>   P1DIR&=~0x02;
>
> Damit springt er bei jeder
> hi/lo oder hi/lo habs nicht im Kopf in den ISR.

Hm, also CM_2 ist wie du sagtest,
1
 capture on falling edge
Das heißt, dass er bei jeder fallenden Flanke ein TAIV auslöst?
Oder zwingt ihn das nur in die ISR?

Und was genau bezweckst du mit P1DIR &=~ 0x02; ? Ich weiß das die Tilde 
negiert. Also aus ~01b = 10b macht.

Ich hatte meine Ports ja mit P1DIR |= 0x02; definiert.

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Also er schmeißt den ISR und setzt das TAIV, sollte beides imemr 
zusammen geschehen, anerst würde es zumindest für mich keinen Sinn 
machen.

Richtig ~ negiert, &= ist das logische UND. Damit wir BIT1 mit 0 UND 
verbunden somit wird BIT1 0. Ich will damit nur sicher gehen das der PIN 
als Eingang definiert ist.

Ich würde an deiner Stelle meinen Code eins zu eins für TimerB 
übernehmen und schauen ob du in den ISR kommst, klappt das, kannst du 
dich um den Rest kümmern.

von Stefan M. (stefan_m)


Lesenswert?

Ach so, der PIN muss als Eingang geschaltet sein. Aber wieso?
Bisher habe ich meine Signal doch aus diesen PINS erhalten.

Das erklärt natürlich, warum ich mit deinem Code erstmal kein 
Ausgangssignal mehr an den PIN's sehe ^^

Bis hier hin, hab ich das nun mal alles mit deinem Code definiert.
Aber an welchen PIN's soll ich nun mein TOGGLE abgreifen?

Irgendein anderen. Zum Beispiel P5.1?

Dann hüpft man sozusagen in die ISR und sagt dort
1
 if (TBIV == 0x02)
2
  {
3
         P5DIR |= 0x02;
4
   P5OUT ^= 0x02;  
5
         TBCCR1 +=3000;
6
  }

Das wäre jetzt das logischste für mich :)

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Ich muss noch einmal in Worte fassen was mein Code von oben macht. Ich 
hab das gefühl wir reden aneinander vorbei.

Mein Code macht folgendes:

Sobald an TA0 eine hi/lo Flanke kommt springt er in den ISR.
Dort kannst du machen was du willst.

Wenn ich dich jetzt richtig verstehe, willst du dein ISR auslösen, wenn 
der TIMER B auf einen bestimmten Wert gezhält hat. Das unterscheidet 
sich von meinem Code erheblich. Steht aber ganz genau in den TI 
Beispielen.

Also wenn ich mir den Rest von oben noch einmal durchlese merk ich das 
ich dir total falschen Code gegeben habe.
1
//******************************************************************************
2
//  MSP430F23x0 Demo - Timer_A, Toggle P1.0, TACCR0 Cont. Mode ISR, DCO SMCLK
3
//
4
//  Description: Toggle P1.0 using software and TA_0 ISR. Toggles every
5
//  50000 SMCLK cycles. SMCLK provides clock source for TACLK.
6
//  During the TA_0 ISR, P1.0 is toggled and 50000 clock cycles are added to
7
//  TACCR0. TA_0 ISR is triggered every 50000 cycles. CPU is normally off and
8
//  used only during TA_ISR.
9
//  ACLK = n/a, MCLK = SMCLK = TACLK = default DCO ~1.2MHz
10
//
11
//              MSP430F23x0
12
//            -----------------
13
//        /|\|              XIN|-
14
//         | |                 |
15
//         --|RST          XOUT|-
16
//           |                 |
17
//           |             P1.0|-->LED
18
//
19
//  A. Dannenberg
20
//  Texas Instruments Inc.
21
//  January 2007
22
//  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
23
//******************************************************************************
24
#include "msp430x23x0.h"
25
26
void main(void)
27
{
28
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
29
  P1DIR |= 0x01;                            // P1.0 output
30
  TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
31
  TACCR0 = 50000;
32
  TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode
33
34
  __bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupt
35
}
36
37
// Timer A0 interrupt service routine
38
#pragma vector=TIMERA0_VECTOR
39
__interrupt void Timer_A (void)
40
{
41
  P1OUT ^= 0x01;                            // Toggle P1.0
42
  TACCR0 += 50000;                          // Add Offset to TACCR0
43
}

Das TI Beispiel kann dann alles was du brauchst, du musst dir zusätzlich 
noch überlegen wie du die 120° Phasenverschiebung sauber hinbekommst, 
gerade wann die Interrupts ausegelöst werden müssen und die wie die 
Zählerstände berechnet werden. Bei mir will es gerade nicht in den Kopf 
das Mittagessen liegt mir wohl schwer im Magen.

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Ja, sag ich doch ^^ Irgendwie stimmt das als Eingang nicht.

Aber diese falsch Information hat mich dazu getrieben, mehr in dem 
Userguide zu lesen um auch mehr über das TBIV zu erfahren.

Der Unterschied bei ContinousMode und Upmode ist doch nur der, dass im 
UpMode BIS zu dem Wert im CCR gezählt wird und dann beginnt der Timer 
von 0. Und im ContinousMode, würde er den Interrupt bei erreichen des 
CCRx_Wertes auslösen und dann einfach weiterzählen. Hier muss man also 
in der ISR dann einen Offset einfügen, damit er den Zählabstand von 0 
bis CCR einhält.
Sehe ich das richtig? Eigentlich logisch -g-

Allerdings habe ich noch Probleme, beim Verständnis des Offsets.
Vor der ISR wird TCCR0 = 5000;
1
 TCCR0 = 5000;         // CCR setzen
2
    .
3
    . 
4
    .
5
// ISR TIMERB VECTOR------------
6
   void TIMERB(void)
7
   {
8
    //mach was//
9
    TBCCR0 += 5000;      // Add Offset 
10
   }

Der Timer zählt bis 5000, springt in die ISR, macht was, und wird dann 
um 5000 addiert. Dann stünde er doch bei 10000 und zählt munter eine 
Runde rum, oder nicht? Das kann natürlich nicht sein, dann am Oszi sehe 
ich ja, dass es funktioniert und sich die Frequenz steigt erhöht, je 
kleiner ich den Wert für mein CCR setze.

Und nun noch zu dem eigentlichen Problem:
-----------------------------------------

> ... du musst dir zusätzlich
> noch überlegen wie du die 120° Phasenverschiebung sauber hinbekommst,
> gerade wann die Interrupts ausegelöst werden müssen und die wie die
> Zählerstände berechnet werden. Bei mir will es gerade nicht in den Kopf
> das Mittagessen liegt mir wohl schwer im Magen.

Für die Phasenverschiebung habe ich noch keine Lösung. Aber ich denke, 
ich muss eh erstmal genau herausfinden, wie ich die TBIV's unterscheide.

Wenn ich nur ein TBIV abfrage, klappt das und er toggelt mir den Pin, 
den ich angebe. Wenn ich aber mehrere TBIV's abfrage, klappt es nicht. 
(siehe Code im Anhang msp430xG46x_tb_TBIV.c)
Dann ist je nach dem Wert in dem jeweiligen CCR der zugeordnete PIN 
aktiv.

Daraus würde ich nun schlussfolgern, dass die Zählweise des Timers nicht 
so stattfindet, wie ich mir das vorstelle. Eigentlich erhalte ich ein 
Interrupt, wenn der Timer das CCR0 register erreicht, hüpft in die ISR 
toggelt P5.1 und fügt den Offset zu CCR0. Anschließend prüft er, ob das 
TBIV von CCR1 gesetzt ist --> ist es nicht, dann prüft er ob TBIV von 
CCR2 gesetzt ist --> ist es nicht, also wieder raus.

Nun die Frage, zählt der Timer weiter? Oder beginnt er wieder bei 0. 
Wenn er wieder bei 0 anfängt, erreicht er doch nie den Wert von TBCCR1, 
da dieser ja höher ist, als der vom TBCCR0.

In msp430xG46_tb_TBIV_funzt.c frage ich nur ein TBIV ab und erhalte hier 
auch bei Signal an den entsprechenden PIN's.
P5 toggelt bei jedem Sprung in die ISR und für jeden Interrupt von TCCR1 
erhalte ich einen Toggel an P2.2

Ich freue mich über jegliche Anregungen und Diskussion :)

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Ok, versuchen wir mal Licht in den Offsetjungle zu bringen.

Offset heißt doch einfach das es ist eine Verschiebung der Gerade nach 
oben. D.h. sie fängt nicht bei NULL an zu zählen sondern bei 5000. Mehr 
steckt nicht dahinter.
In deinem Beispiel heißt Offset aber einfach nur Draufsetzen und 
spiegelt somit deine halbe Periodendauer wieder.

Wir nehmen an. Du bist im ContMode bei 0, bei 1Mhz. Startest das 
Programm.
CCR0=5000. Er zählt bis 5000 > Toggle + CCR0=5000+5000. Er zählt bis 
10000 > Toggle + 10000+5000 .... usw. das heißt deine halbe Periodedauer 
sind 5ms, deine ganze 10ms also 100Hz. Das ganze wird an P5.1 
ausgegeben.

Damit ist deine Erklärung auch logisch, je kleiner ich CCR0 mache desto 
schneller toggelt P5.1 und das heißt die Frequenz steigt.

Bei CCR1 und CCR2 das gleiche, nur das hier die Perioden anderst sind 
und die Pins an dennen es ausgegeben wird.

Frage:
Das mit den verschiedenen TBIV klappt so wie es beschrieben ist?
Also die IF-Abfragen?

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Versuch mal das TBIV irgendwie anzuzeigen so das du immer die jeweiligen 
Werte darin siehst.
Als ich dein Code von oben einfach auf TimerA umgemünzt habe, ging alles 
wunderbar, sprich es müssen unterschiedliche TAIV gekommen sein sonst 
würde man nicht in die if´s kommen.
Leider bin ich nur noch 10 min im Geschäft, werd morgen noch einmal 
schauen ob ich dahinter komm.
Gerade nerft mich mal wieder Eclipse.

Have a nice Day

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Hi,

jetzt ist der Groschen gefallen. Das ernüchternde ist, dass ich mir das 
so vor ein / zwei Monaten schonmal selbst erarbeitet habe. Aber 
scheinbar war ich nun so verbissen darauf ein Lösung für meine 
Phasenverschiebung zu finden, dass ich da völlig auf dem Schlauch stand.
Ich sollte wohl auch einfach etwas strukturierter an die Sache heran 
gehen ^^
Kleine Schritte, Step by Step.

> Frage:
> Das mit den verschiedenen TBIV klappt so wie es beschrieben ist?
> Also die IF-Abfragen?

Leider klappt es nicht mit der TBIV Abfrage. Ich habe beim herumspielen 
festgestellt, dass er die Ports in der ISR immer toggelt, egal welchen 
Wert ich im TBIV abfrage.

Ich hab mir nochmal ein Beispielprog. genommen und nochmal mit ganz 
wenig Code von vorne angefangen.

TimerB betrieben mit ACLK gibt mir eine Frequenz von 1/2 Hz aus. Also 1 
Toggle pro Sekunde. In der ISR frage ich dann ab, ob der Interrupt vom 
TBCCR0 ausgelöst wurde, wenn nicht, ob es vom TBCCR1 ausgelöst wurde.
Da das TBCCR1 einen halb so großen Wert beinhaltet wie TBCCR0, müsste 
mein Signal vom TBCCR1 also doppelt so schnell sein. Beide Signal haben 
aber die gleiche Frequenz :( Somit funktioniert es noch nicht.

Zur erläuterung hier ein Ausschnitt aus meinem Userguide:
1
 TBIVx Bits 15-0 Timer_B interrupt vector value
2
TBIV Contents :: Interrupt Source :: Interrupt Flag :: Interrupt Priority
3
----------------------------------------------------------------------  
4
    00h          No interrupt pending     -
5
    02h          Capture/compare 1     TBCCR1 CCIFG        Highest
6
    04h          Capture/compare 2     TBCCR2 CCIFG
7
    06h          Capture/compare 3    TBCCR3 CCIFG
8
    08h          Capture/compare 4    TBCCR4 CCIFG
9
    0Ah          Capture/compare 5    TBCCR5 CCIFG
10
    0Ch          Capture/compare 6    TBCCR6 CCIFG
11
    0Eh          Timer overflow        TBIFG               Lowest
12
13
 MSP430x4xx devices only

Was ich auch nicht so recht verstehe...in der angehängten Datei soll in 
der ISR eigentlich nur der PIN 2.2 getoggelt werden. Jedoch toggelt der 
PIN 5.1 in der gleichen Frequenz, obwohl ich ihn in der ISR überhaupt 
nicht anspreche. Und das TBCCR0 liegt eigentlich am PIN 2.1

Wie kann das sein?

von Stefan M. (stefan_m)


Lesenswert?

Fabian Hof schrieb:
> Versuch mal das TBIV irgendwie anzuzeigen so das du immer die jeweiligen
> Werte darin siehst.

Meinst du über die Schrittweise Ausführung des Compilers ... da kann ich 
mir den Inhalt der Register ja anzeigen lassen. Auch ob das CCIFG des 
jeweiligen Registers (TBCCRx) gesetzt ist.

> Als ich dein Code von oben einfach auf TimerA umgemünzt habe, ging alles
> wunderbar, sprich es müssen unterschiedliche TAIV gekommen sein sonst
> würde man nicht in die if´s kommen.

Hast du dabei auch die ISR Bezeichnung geändert? Ich hab das versucht 
mal nachzumachen, alles auf TimerA geändert und dann hatte ich plötzlich 
die doppelte Frequenz. Bis mir dann aufgefallen ist, dass meine ISR 
immer noch Timer_B0 hieß und mein Signal sozusagen ohne die ISR erzeugt 
wurde.

Das erklärt auch dieses Problem:
> [es] soll in der ISR eigentlich nur der PIN 2.2 getoggelt werden. Jedoch
> toggelt der PIN 5.1 in der gleichen Frequenz, obwohl ich ihn in der ISR
> überhaupt nicht anspreche.
1
 // Wait for xtal to stabilize
2
  do
3
  {
4
  IFG1 &= ~OFIFG;                           // Clear OSCFault flag
5
  for (i = 0x47FF; i > 0; i--);             // Time for flag to set
6
  }
7
  while ((IFG1 & OFIFG));                   // OSCFault flag still set?

Mit diesem Code werden alle PIN's getoggelt, die man als Ausgang 
definiert hat. Hatte nämlich noch mehr PIN's mit LED's als Ausgang 
definiert und festgestellt, dass immer alle in der gleichen Frequenz 
blinken.
Was genau jetzt im Mikrocontroller geschieht, kann ich noch nicht sagen. 
Dazu muss ich erst nochmal den Userguide studieren.

Hm, ich habe gerade mein board wieder initialisiert, mein CCE gestartet 
und das gleiche Progg übertragen, bei dem alle definierten Ports wegen 
der While-Schleife im selben Takt blinken. Und jetzt blinkt nur ein PIN 
... ohne ISR. Wieso blinken die anderen jetzt nicht :( ich krieg noch 
die KRISE -,.-

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Fabian Hof schrieb:
> Versuch mal das TBIV irgendwie anzuzeigen so das du immer die jeweiligen
> Werte darin siehst.

Moin,

im Anhang hab ich nochmal ein Codeschnipsel, mit dem ich gerade versuche 
das TBIV zu unterscheiden. In der rechten Bildhälfte kann ich mir bei 
einer step-by-step Programmausführung den Wert von TBIV jeweils anzeigen 
lassen.

Die farbigen Punkte in der ISR stehen jeweils für die LED an dem PIN.
So wie der Code da steht, blinkt die rote und gelbe LED wechselseitig.
Also rot = an und gelb = aus anschließend rot = aus und gelb = an.
Die Ursache liegt wahrscheinlich darin, dass mit der Richtungsdefinition 
P2OUT |=0x02; für die gelbe LED, diese sofort einschaltet.

Die grüne LED leuchtet niemals. Bei genauerer Betrachtung meines 
ausführenden Codes im Step-by-Step-Mode, wird die ISR nur bei einem 
TBIV(wert) = 0x00 betreten. Das TBIV nimmt zwar auch den Wert 0x02 an, 
doch die ISR wird dabei nicht betreten.

Die Frage ist, weshalb nicht? Liegt das vielleicht an den Prioritäten 
der Registerflags?

Und dann ist da noch eine Verständnisfrage. Was im Grunde an die 
Prioritäten anknüpft.
Mein TBCCR0 CCIFG (TBIV0 sozusagen) hat die höchste Priorität.
Wenn mein TBCCR0 nun einen geringeren Wert als TBCCR1 beinhalten würde, 
würde dann überhaupt jemals das Flag für TBCCR1 gesetzt werden?

Denn mein Timer zählt doch im UpMode jeweils bis zu meinem Registerwert 
TBCCR0 und beginnt dann wieder bei 0. Wenn TBCCR1 dann einen höheren 
Wert besitzt, würde der doch nie erreicht werden?!
Andererseits hab ich das Gefühl dass ich bei dieser Überlegung schon 
wieder irgendwas nicht beachte, denn eigentlich wäre sowas doch 
unpraktisch, oder?

von Fabian H. (Firma: keine) (eimer)


Angehängte Dateien:

Lesenswert?

Moin,

Stefan Marx schrieb:
> Denn mein Timer zählt doch im UpMode jeweils bis zu meinem Registerwert
> TBCCR0 und beginnt dann wieder bei 0. Wenn TBCCR1 dann einen höheren
> Wert besitzt, würde der doch nie erreicht werden?!
> Andererseits hab ich das Gefühl dass ich bei dieser Überlegung schon
> wieder irgendwas nicht beachte, denn eigentlich wäre sowas doch
> unpraktisch, oder?

Wenn man sich das ganze als Rennstrecke vorstellt, sprich du hast einen 
Rundkurs der 32768m lang ist und an jedem CCRx stellst du ein Zeitmesser 
auf.
Im ContMode fährst du Runde für Runde.
Im UpMode baust du aber eine Abkürzung ein(ok, die ist nicht 0m lang, 
aber sagen wir sie ist theoretisch 0m lang) sagen wir bei 20000m, dann 
heißt das doch, du befährst die Strecke von 20000m-32768m nicht. Wie 
soll da die Zeit gemessen werden?

Stefan Marx schrieb:
> Die grüne LED leuchtet niemals. Bei genauerer Betrachtung meines
> ausführenden Codes im Step-by-Step-Mode, wird die ISR nur bei einem
> TBIV(wert) = 0x00 betreten. Das TBIV nimmt zwar auch den Wert 0x02 an,
> doch die ISR wird dabei nicht betreten.

Ich frag mich gerade wieso TBIV=0x02; sein kann. Tu hast TCCR2=x 
auskommentiert, da dürfte kein ISR ausgelöst werden. Beziehungsweise, es 
wird ja keiner ausgelöst, aber TBIV sollte dann wohl auch nicht 
eingetragen sein.

Anmerkung:
TCCR0 kann man nicht abfragen(mein Verständnis) zumindest nicht im TBIV.
Siehe deine Tabelle vom 24.

Also im Anhang habe ich Code der bei mir so funktioniert, gerade eben 
getestet. Er benutzt das CCR0, das auf CCR1 umzustricken sollte keine 
Probleme bereiten. Außerdem muss beachtet werden das CCR0 nicht 
abgefragt werden können. Das heißt also, dass der auszuführende Code im 
Nein-Teil einer if sitzen muss. if (0x02) Esle if(0x04) else (CCR0)

von Stefan M. (stefan_m)


Lesenswert?

Hi Fabian,

also deine Erläuterungen sind echt Klasse :)
Man erreicht den Abschnitt somit nie zwischen 20.000m und 32.768m.

Das erklärt auch, weshalb ich mich also an den ContMode halten muss.

> Ich frag mich gerade wieso TBIV=0x02; sein kann.

Weil dieser Wert für das TBCCR1 CCIFG steht. Also zu dem TBCCR1 gehört 
;)

Das man TBCCR0 eigentlich nicht abfragen kann, da es da ja eigentlich 
keinen Wert im TBIV gibt hab ich auch der Tabelle entnommen.
Den Wert 0 gibt es ja dennoch im TBIV. So das ich diesen dann halt 
abgefragt habe. Logischerweise ohne zugehörigkeit zum TBCCR0. Was mir 
erst jetzt klar geworden ist. Gut das wir darüber geredet haben g

Ich werde mich gegen Mittag nochmal ran setzen. Bis dahin muss ich 
erstmal Labeln :(

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Sooo,

wieder dem Ziel ein Schritt näher :)

Erst hatte ich die Abfrage
1
 if (TBIV == 0x02 bzw 0x04)
 alles in der ISR vom TimerB0. Ein Interrupt durch die entsprechenen 
Register TBCCR1 oder TBCCR2 führte mich nie in die ISR von diesem Timer, 
sondern wurde einfach ignoriert. Dabei ging ich davon aus, dass jeder 
Interrupt vom TimerB oder dessen Register mich in die ISR TimerB0 
bringen wird.

Dem ist aber nicht so. Die ISR TimerBO reagiert nur auf Interrupts vom 
TCCR0. Erst als ich die Abfrage für das TBIV von TBCCR1 und TBCCR2 in 
die ISR TimerB1 verschoben habe, reagierte mein Programm auch auf deren 
Interrupt. So explizit habe ich das allerdings nicht im Userguide 
gefunden, sondern durch einen Freund erfahren. Oder kann mir da jemand 
gegenteiliges berichten?

Nun besteht aber noch ein Problem. Dazu habe ich die PNG-Files 01- bis 
03- TBIV0x04 mit angehängt. Wenn ich einen Interrupt vom TBCCR1 erhalte, 
wird mein TBIV = 0x02 gesetzt. --> Sprung in ISR TimerB1 --> ABFRAGE
1
 if (TBIV == 0x02)
 ... positiv, also betritt er die if Schleife und löscht gleichzeitig 
das TBIV --> toggle PIN und wieder raus.

Wenn ich einen Interrupt vom TBCCR2 erhalte, wird mein TBIV = 0x04 
gesetzt. --> Sprung in ISR TimerB1 --> ABFRAGE
1
 if (TBIV == 0x02)
 ... negativ, also sprung zu
1
 else if (TBIV == 0x04)
 ABER gleichzeitig löscht er das TBIV --> ABFRAGE
1
 else if (TBIV == 0x04)
 --> negativ, da TBIV ja eben auf 0x00 zurückgesetzt wurde.

Laut Userguide wird das Interrupt nach der Bedienung durch die ISR 
gelöscht bzw. zurückgesetzt. Also somit auch das TBIV. Frage: Ab wann 
gilt denn ein Interrupt als bedient?
Nach dieser Erfahrung hier, nachdem es die ISR betritt, also nach der 
ersten geschweiften Klammer.

Denkst du eine Switch Case Anweisung löst das Problem?

von Fabian H. (Firma: keine) (eimer)


Angehängte Dateien:

Lesenswert?

Morgen,
also wenn ich das richtig sehe(siehe Anhang) muss man ein switch 
verwenden. Es scheint mir, das eine Abfrage des TBIV es automatisch 
zurücksetzt, sagen kann ich das aber nicht mit Sicherheit, hab ich noch 
nie gebraucht.

Im Anhang ist ein Code-Beispiel von TI was glaube ich genau deinen 
Ansprüchen gerecht wird. Dabei kannst du dir sogar die unterschiedlichen 
ISR sparen.

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Moin moin,

heute ist ein guter Tag. Denn es ist endlich vollbracht :)

Die If-Abfragen habe ich durch eine Switch-Case-Abfrage ersetzt. Damit 
kann jeder Wert im TBIV bearbeitet werden ;) Also, dass konnte man 
vorher auch, aber bei der zweiten "else"-Abfrage war das Bit ja meist 
schon zurückgesetzt.

Alternativ könnte man sicherlich den Inhalt vom TBIV in eine Variable 
übertragen, die dann in der if-Abfrage überprüft wird.

Die Phasenverschiebung der 3 Signale konnte ich so realisieren, wie Greg 
das im 4. Beitrag beschrieben hat :)

Jetzt muss noch die Periode für alle 3 Signale flexibel gemacht werden, 
so dass man bei Betätigung von Taste 1, diese erhöht und bei Betätigung 
von Taste 2, erniedrigt wird.

Entsprechende Codeschnipsel habe ich dafür schon ;)

Was mich noch interessieren würde ist, wie man kleine Unterprogramme in 
extra c-files packt? Und ab wann man das machen sollte? Momentan ist das 
nur Spielerei, aber es interessiert mich halt ^^

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

Servuz,

na dann sag ich mal gut Ding will weile haben.

Also zum auslagern brauchst du nur ein C-File und ein passendes H-File. 
Wie das geht findet man im Netzt zur genüge.
Es lohnt sich vor allem dann, wenn du Funktionen benutzt, die in vielen 
Files aufgerufen werden. Oder sehr viel Hirnschmalz drin steckt, viele 
LOC oder du mit einem Aufruf viel erschlagen kannst.
Wiem an sich halt so eine Lib vorstellt.

Eine Frage hab ich allerdings noch.
Deine Rechtecke sind immer symmetrisch? Also kein PWM Signal?

von Stefan M. (stefan_m)


Lesenswert?

Fabian Hof schrieb:
> Eine Frage hab ich allerdings noch.
> Deine Rechtecke sind immer symmetrisch? Also kein PWM Signal?

In diesem Fall sind sie symmetrisch. Ich will einen 3 Phasenmotor 
ansteuern. Das hab ich erst auf elektronischen Wege versucht und mir 
diesen dabei zerschossen. Hätte ich mal noch ein paar Dioden mit in die 
Schaltung gehangen ^^
Naja, und um den dort verwendeten Treiberbaustein besser zu verstehen 
wollte ich die Hallsignale des Motors simulieren. Diese sind immer 
symmetrisch und variieren nur in ihrer Frequenz.

In einem späteren Schritt, werde ich versuchen aus diesem Code ein PWM 
zu erzeugen.

von Stefan M. (stefan_m)


Angehängte Dateien:

Lesenswert?

Hier mal noch ein Update mit ein paar extra features :)

Beim starten des Programms wird ein Signal wiedergegeben. Startsound 
sozusagen. Beim betätigen der Tasten wird ebenfalls ein Sound 
wiedergegeben. Taster 1 sorgt für ein Ansinken der Signalfrequenz und 
Taster 2 für ein ansteigen. Wird der jeweilige Minimal- oder Maximalwert 
erreicht, ertönt ein Fehlersignal.

Dummerweise stimmt der Phasenversatz nach Betätigung der Taster nicht 
mehr.

Ich bin mir nicht sicher woran das liegt. Meine TBCCRx Register fülle 
ich durch Variablen, die ich vorher definiert habe.
1
 
2
TB0 = 1219;
3
TB1 = TB0/3;
4
TB2 = TB0/3*2;
5
TB3 = TB0-1;

Die Register fülle ich dann einfach mit
1
 TBCCR1=TB1;

Wird ein Taster gedrückt, verändere ich den Wert im TB0 mit:
1
 TB0 += 122;
Meine obere Grenze für TB0 ist 1214 und die niedrigste 360.
Der Phasenversatz soll zwischen TB1 bis 3 jeweils um ein drittel 
betragen.

Was könnte die Ursache sein, dass dieses Verhältnis nicht eingehalten 
wird?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.