Forum: Mikrocontroller und Digitale Elektronik Falsche Timer Werte MSP430


von Marco K. (morpheus133)


Lesenswert?

Moinsen,

ich betreibe hier ein MSP in Kombination mit einem Propeller.
Der Propeller spricht den MSP per SPI an und schickt ihm Befehle.
Aktuell soll er bei dem Eingang von 0x20 die Dauer von einer Periode 
messen.
Dazu wird ein irq bei steigender Flanke ausgelöst und der Timerwert 
gespeichert.
Dieses wird 6mal gemacht und dann als Mittelwert verschickt.
Frequenz wird per NE555 erzeugt und liegt bei 1200 Hz.
Das Signal sieht am Oszi auch gut aus.

Der Timer-Wert liegt bei ca. 98 und das stimmt nicht, er müsste bei 
ca.900 liegen.

anbei mal der Code - ich schätze ich habe mir irgendwo mit den IRQ 
verhaspelt ich finde es nur nicht.
1
/*
2
* Clockfrequenz:    
3
* Timer mit SMCLK im Contmodus
4
* Spi sende 16 bit als 2x8bit; LSB_First und aktiviere dann erneut rx-IRQ
5
* ADC GND - Vreff = VCC
6
Warte auf SPI Input 
7
- je nach rx-Bit
8
0x01:  Starte ADC mit A0  
9
0x20:  Starte IRQ auf P2.0 bei low2high, bei auslösen der irq speicher TAR, messer 6 IRQ und bilde dann Durchschnitt der Differenzen und schicke per SPI
10
0x40:  Starte IRQ auf P2.1 bei low2high, bei auslösen der irq speicher TAR, messer 6 IRQ und bilde dann Durchschnitt der Differenzen und schicke per SPI
11
 
12
P1.0  - ADC A0
13
P1.1  - ADC A1
14
P1.2  - ADC A2
15
P1.3  - ADC A3
16
P1.4  - ADC A4
17
P1.5  -SPI CLK
18
P1.6  -SPI MISO
19
P1.7  -SPI MOSI
20
P2.0  -Frequenz 1
21
P2.1  -Frequenz 2
22
P2.2
23
P2.3
24
P2.4
25
P2.5
26
P2.6
27
P2.7
28
*/
29
#include  "msp430g2553.h"
30
#include "Utilities.h"
31
#include "SPI.h"
32
int cnt_0, Value_0_Mean, Value_0[6];
33
int cnt_1, Value_1_Mean, Value_1[6];
34
void main(void)
35
{
36
    WDTCTL  = WDTPW + WDTHOLD;                             // Stop WDT
37
    BCSCTL1 = CALBC1_1MHZ;
38
  DCOCTL   =  CALDCO_1MHZ;
39
//SPI
40
   SPI_init();
41
//TimerA
42
  TACTL   = TASSEL_2 + ID_0 + MC_2;                  // SMCLK, /1 ,contmode, 
43
//ADC
44
ADC10CTL0 = SREF_0 + ADC10SHT_0 + REFON + + ADC10IE + ADC10ON;        //Intern Ref = 3V + SampleHold 4 + IRQ ON + CORE ON
45
//Start Bedingunge
46
cnt_0=0;
47
cnt_1=0;
48
P2IFG = 0x00;
49
_BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/interrupt
50
}
51
52
// Port 2 interrupt service routine
53
#pragma vector=PORT2_VECTOR
54
__interrupt void Port_2(void)
55
{
56
//P2.0
57
if(P2IFG & BIT0)
58
     {
59
    Value_0[cnt_0] = TA0R;
60
    cnt_0++;
61
    if (cnt_0 == 6 )                //5 Differenzen
62
      {
63
      cnt_0  =0x00;                //Reset Counter
64
      Value_0_Mean = (Value_0[5] - Value_0[0])/5;  //Mean
65
      SPI_send_16bit(Value_0_Mean);
66
      P2IE    &= ~BIT0;                           //P2.0 interrupt disable      
67
      }       
68
      P1IFG   &= ~BIT0;                             // P2.0 IFG cleared
69
     }
70
//P2.0
71
if(P2IFG & BIT1)
72
     {
73
    Value_1[cnt_1] = TA0R;
74
    cnt_1++;
75
    if (cnt_1 == 6 )                //5 Differenzen
76
      {
77
      cnt_1  =0x00;                //Reset Counter
78
      Value_1_Mean = (Value_1[5] - Value_1[0])/5;  //Mean
79
      SPI_send_16bit(Value_1_Mean);
80
      P2IE    &= ~BIT1;                           //P2.1 interrupt disable      
81
      }       
82
      P1IFG   &= ~BIT1;                             // P2.1 IFG cleared
83
     }                         
84
}
85
86
87
#pragma vector=USCIAB0RX_VECTOR
88
__interrupt void USCI0RX_ISR (void)
89
{
90
  
91
  
92
switch (UCB0RXBUF)
93
  {
94
  case 1:                                //P1.0  A0 ADC
95
    IE2 &= ~UCB0RXIE;                        //disable IRQ
96
    ADC10CTL1 = INCH_0 + ADC10SSEL_3;                            // A0 auf P1.0 + SMCLK
97
     break;
98
   case 2:                                //P1.1 A1 ADC
99
     IE2 &= ~UCB0RXIE;                        //disable IRQ
100
     break;
101
   case 4:                                //P1.2 A1 ADC
102
     IE2 &= ~UCB0RXIE;                        //disable IRQ
103
     break;
104
   case 8:                                //P1.3 A1 ADC
105
     IE2 &= ~UCB0RXIE;                        //disable IRQ
106
     break;
107
   case 16:                              //P1.4 A1 ADC
108
     IE2 &= ~UCB0RXIE;                        //disable IRQ
109
     break;
110
   case 32:                              //P2.0 Frequenz
111
     IE2 &= ~UCB0RXIE;                        //disable IRQ
112
    P2IE |= BIT0;                                         //P2.0 interrupt enable
113
    P2IFG &= ~BIT0;                                        //P2.0 IFG cleare
114
     break;
115
   case 64:                              //P2.1 Frequenz
116
     IE2 &= ~UCB0RXIE;                        //disable IRQ
117
    P2IE |= BIT1;                                         //P2.1 interrupt enable
118
    P2IFG &= ~BIT1;                                        //P2.1 IFG cleare
119
     break;
120
   }
121
122
}

von Stefan Z. (Gast)


Lesenswert?

Zeus Mclane schrieb:
>
1
Value_0_Mean = (Value_0[5] - Value_0[0])/5;  //Mean

Wird der Mittelwert nicht so berechnet?
1
Value_0_Mean = (Value_0[0] + Value_0[1] + Value_0[2] + Value_0[3] + Value_0[4] + Value_0[5])/6;  //Mean

von Stefan Z. (Gast)


Lesenswert?

P.S.:

Überlauf muss noch beachtet werden!

von Stefan Z. (Gast)


Lesenswert?

Achso, jetzt habe ich es verstanden.
Vergiss die zwei letzten Posts mit den Mittelwerten.

Zum Überprüfen der Timereinstellungen kannst du SMCLK auf einen Pin 
ausgeben. SMCLK müsste ja eine Frequenz von 1 MHz haben.
Außerdem kannst du einen Pin auf High setzen, sobald die ISR gestartet 
wird. Am Oszi kannst du dann sehen, wann bzw ob die ISR aufgerufen wird.

Ich konnte jetzt keinen Fehler sehen.

von Stefan Z. (Gast)


Lesenswert?

Noch was :-)

Zum testen würde ich den LowPowerMode nicht verwenden. Besser
1
   while(1);

statt
1
_BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/interrupt

von SB (Gast)


Lesenswert?

1. Ein Überlauf von TA0R könnte auftreten, während du deine Werte 
speicherst (und das ist garnicht mal so unwahrscheinlich, ist doch die 
Differenz von Messwert 1 bis Messwert 6 = 5000 TA0R

2. Ein Signal von 1200Hz würde bei 1MHz: 833 Cycles bedeuten, die der 
Timer zwischendrin den Counter erhöht.

3. Auch könnte ich mir vorstellen, dass du mit deinem IRQ zu langsam 
bist, schau mal ins Disassembly wie viel Zyklen deine Port-ISR braucht.
Ich würde dort ausschließlich TAR samplen, den Rest in der main 
erledigen. Auf volatile Variablen achten.
4. Auch ist int ein dehnbarer Begriff, ich weiß nicht wie breit er auf 
dem MSP ist, inkludiere inttypes.h und nutze uint16_t für deine 
Variablen, dann entspricht das der Bitbreite von TA0R.

An der reinen Initialisierung der Interrupts sehe ich keine Probleme 
gerade.

von Karl H. (kbuchegg)


Lesenswert?

SB schrieb:
> 1. Ein Überlauf von TA0R könnte auftreten, während du deine Werte
> speicherst (und das ist garnicht mal so unwahrscheinlich, ist doch die
> Differenz von Messwert 1 bis Messwert 6 = 5000 TA0R

1 Überlauf würde durch unsigned Rechnereei automatisch berücksichtigt, 
da braucht man dann nichts tun. Es kommt automatisch das Richtig raus. 
Solange es sich also nur um 1 Überlauf handelt würde es reichen die 
entsprechenden Variablen unsigned zu machen um diesen Punkt abzuhaken.
(Das ist doch ein 16 Bit Timer, oder nicht?)

von Marco K. (morpheus133)


Lesenswert?

Danke für die Verschiedenen Antworten, hier erstmal die Lösung:

In dem Port IRQ, wird leider nicht der Richtige IRQ wieder zurück 
gesetzt:
Statt
1
           }       
2
      *P1IFG*   &= ~BIT0;                             // P2.0 IFG cleared
3
     }
4
//P2.0

muss es natürlich
1
           }       
2
      *P2IFG*   &= ~BIT0;                             // P2.0 IFG cleared
3
     }
4
//P2.0

sein.

Zu dem Rest:

Die Mittelwertbildung ist so natürlich Blödsinn, da ich mir aber die 
einzelnen Cases angeschaut habe und die immer gleichmässig ware, habe 
ich das als nächstes Problem verschoben :)

Überlauf wurde ja schon geklärt, werde die Variablen unsigned machen.
Hat das eigentlich irgendwelche Nachteile - ausser wenn ich wirklich 
negative Zahlen bräuchte?

Das mit den SMCLK und IRQ nach aussen zu legen ist echt ne super Idee, 
war zwar jetzt nicht nötig, aber danke! Werde ich das nächste Mal sicher 
gebrauchen können.

Ich werde versuchen die IRQ auszudünnen, um speicher und Rechenzeit zu 
sparen.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Zeus Mclane schrieb:

> Die Mittelwertbildung ist so natürlich Blödsinn,

Würde ich so nicht sagen.
Dadurch, dass du die Zählerstände speicherst, hast du damit automatisch 
eine Aufsummierung. Wenn du die Differenzen aufsummieren würdest, würde 
auch nichts anderes rauskommen. Natürlich nur, solange es keinen 
arithmetischen Ovberflow gibt.

> Überlauf wurde ja schon geklärt, werde die Variablen unsigned machen.
> Hat das eigentlich irgendwelche Nachteile - ausser wenn ich wirklich
> negative Zahlen bräuchte?

Nein. Ganz im Gegenteil: Wenn du von vorne herein weißt, dass etwas nur 
positiv sein kann, dann SOLLST du unsigned nehmen. Zum einen gewinnst du 
dadurch ein 'Zähl'bit mehr, zum anderen eröffnest du dem Compiler 
Optimierungsmöglichkeiten.

Bei einem unsigned Wert kann man Divisionen durch 2-er Potenzen (bzw. 
die Umkehrung: Multiplikationen) durch Schiebeoperationen ersetzen. Bei 
signed Werten funktioniert das aber nicht: negative Werte werden dann in 
die falsche Richtung abgeschnitten. -3 / 2 ergibt nun mal den C-Regeln 
nach -1 (echte Division) und nicht -2 (1 mal rechts Schieben).

von SB (Gast)


Lesenswert?

Korrekt, unsigned macht hier keine Probleme, stimmt.

von Marco K. (morpheus133)


Lesenswert?

@Karl Heinz Buchegger

ok, du hast Recht, durch die Aufsummierung erhalte ich natürlich nichts 
Anderes. Aber ich kann Speicher Sparen, in dem ich nur den ersten und 
letzten Wert speicher und diesen dann teile.

Macht also auch sinn Mittelwert aus n werten zu bilden um mittels 
bit-shift schneller zu teilen. Also zum Beispiel 5 Werte damit man 4 
Differenzen hat ?!

von Karl H. (kbuchegg)


Lesenswert?

Zeus Mclane schrieb:

> Macht also auch sinn Mittelwert aus n werten zu bilden um mittels
> bit-shift schneller zu teilen.

Nur der Vollständigkeit halber: Da fehlt was. Nämlich der Satzteil: 
wobei n-1 eine 2-er Potenz ( 1, 2, 4, 8, 16, 32, ...) sein soll.
Ist das nicht der Fall, kannst du (besser gesagt der Compiler) auch 
keinen Bitshift einsetzen.


Das soll jetzt bedeuten:
Wenn du Zahlen willkürlich benutzen darfst, dann sind 2-er Potenzen 
meistens eine gute Wahl.
Kümmere DU (als Programmierer) dich darum, die richtigen Datentypen zu 
benutzen. Und wenn du dividieren willst oder musst, dann schreib auch 
Division. Wenn es da einen Trick gibt, dann kennt ihn dein Compiler (der 
kennt mit Sicherheit mehr derartige Tricks als du). Das ist nichts was 
dir groß Kopfzerbrechen machen muss.

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.