Forum: Mikrocontroller und Digitale Elektronik Probleme mit ADC Mittelwert auf MSP430 2274


von devzero (Gast)


Lesenswert?

Hallo zusammen,

ich habe hier das ez430-RF2500 Set von TI. Es handelt sich dabei um 2 
Platinen mit jeweils einem MSP430-2274 drauf, welche über das SimpliciTI 
Protokoll miteinander kommunzieren. Es gibt von TI eine Demo, wo auf 
beiden Seiten die Temperaturen gemessen und über den USB Debugger 
(virtueller Comport) als String ausgegeben wird.
Der vollständige Sourcecode findet sich hier:
http://www.ti.com/litv/zip/slac139c

Problem besteht nun am AP/HUB mit der Temperaturerfassung. Die 
Temperatur schwankt sehr stark, daher habe ich versucht einen Mittelwert 
zu bilden über 64 Werte. Grundlegend funktioniert es auch, die 
Temperatur ist recht "stabil". Allerdings stürzt das Programm meist so 
nach ca. 3h ab. Es bleibt einfach stehen. Im Programm werden an mehreren 
Stellen noch die LEDs geschaltet; beim Absturz ist der Zustand immer 
unterschiedlich, was mich vermuten lässt, dass das Problem nicht immer 
an der selben Stelle auftritt.
Das original Programm von TI läuft fehlerfrei durch.

Zunächst poste ich erstmal den relevanten Code aus der main_AP.c
1
    // if it is time to measure our own temperature...
2
    if(sSelfMeasureSem)
3
    {
4
      char msg [6];
5
      char addr[] = {"HUB0"};
6
      char rssi[] = {"000"};
7
      int degC, volt;
8
      volatile long temp;
9
      int results[2];
10
      
11
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
12
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;
13
      for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
14
      ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
15
      __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
16
      results[0] = ADC10MEM;
17
    
18
      ADC10CTL0 &= ~ENC;
19
...
Ich habe nun ganz pragmatisch einfach eine for-Schleife um den ADC Teil 
gesetzt, aufsummiert und am Ende durch 64 geteilt (bzw 6 Bit nach rechts 
geschoben)
1
    // if it is time to measure our own temperature...
2
    if(sSelfMeasureSem)
3
    {
4
      char msg [6];
5
      char addr[] = {"HUB0"};
6
      char rssi[] = {"000"};
7
      int degC, volt;
8
      volatile long temp;
9
      int results[2];
10
      uint16_t adcsum = 0;
11
      uint8_t i;
12
      
13
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
14
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;
15
16
      for( i = 64; i > 0; i-- )
17
      {
18
        for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
19
        ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
20
        __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
21
//        results[0] = ADC10MEM;
22
        adcsum += ADC10MEM;
23
    
24
        ADC10CTL0 &= ~ENC;
25
      }
26
      adcsum = adcsum>>6;
27
      results[0] = (int) adcsum;
28
...

Das sind die einzigen Änderungen.. was ist daran falsch, so dass der 
Controller/das Programm nach ca. 3h (manchmal früher, manchmal später) 
einfach stoppt?

Grüße,
devzero

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ich habe nun ganz pragmatisch einfach eine for-Schleife
Wenn das die einzige Änderung ist, dann hast du evtl. die Laufzeit so 
ungünstig verändert, dass du jetzt irgendwo festhängst...

> Die Temperatur schwankt sehr stark,
Tut sie das? Oder schwankt dein Messwert?
Falls ja: was ist die Ursache?

von Helmut L. (helmi1)


Lesenswert?

Watchdog  ein/aus geschaltet ?
Durch die laengere Laufzeit koennte eventuelle der Watchdog zuschlagen.

von devzero (Gast)


Lesenswert?

Ja, die Messung schwankt massiv. Woher es kommt weiss ich leider nicht. 
Der Code ist ansich genau so wie an der Node, wo es stabil läuft. Die 
Versorgungsspannung kommt vom USB Debugger, wird aber da irgendwie auf 
3,6V runtergeregelt. Als Referenz für den ADC werden die internen 1,5V 
benutzt.

Watchdog wird nirgends verwendet, ausserdem müsste er ja dann neustarten 
und sollte somit nur Probleme mit seinen dann nicht mehr connecteten 
Nodes haben. Die Nodes scheinen auch noch weiter zu senden; sie blinken 
noch grün. Sobald man das Modul vom Strom entfernt blinken diese rot.
Damit fällt meine mögliche Theorie, dass er nicht ausm Schlaf aufwacht 
aber auch hin. Im ADC Code wird der Controller schlafen geschickt, bis 
die Wandlung fertig ist und dann per Interrupt wieder aufgeweckt wird.

Ich stehe gerade etwas verloren mit dem Problem da, da ich einfach nicht 
weiss, was da schief läuft. Wenn es gar nicht gehen würde, würde ich mir 
ja denken "ok, ich bin da zu lange.. der ganze SimpliciTI kram wird 
nicht mehr oft genug angesprochen" - aber dann gäbe es auch bzw viel 
mehr Probleme mit der Funkverbindung. Das läuft alles einwandfrei, nur 
stürzt der AP halt meist so nach 3h ab.

PS: Wollte das Problem mal bei http://e2e.ti.com schildern, allerdings 
finde ich da keinen New Post Button oder sowas in der Richtung.. muss 
man dafür erstmal auf mehrere Posts geantwortet haben? Registriert habe 
ich mich natürlich.

von avion23 (Gast)


Lesenswert?

So ein Problem hatte ich mal, als ich die maximale Ramgröße 
überschritten habe.

von Karl H. (kbuchegg)


Lesenswert?

Zeig mal die ganze Funktion

Nicht böse sein, aber ich hab ins Zip reingeschaut und ich such mir da 
jetzt nicht das richtige Source File raus.

von devzero (Gast)


Lesenswert?

In dem ZIP ist es die main_AP.c im Ordner Applications.
1
    // if it is time to measure our own temperature...
2
    if(sSelfMeasureSem)
3
    {
4
      char msg [6];
5
      char addr[] = {"HUB0"};
6
      char rssi[] = {"000"};
7
      int degC, volt;
8
      volatile long temp;
9
      int results[2];
10
      uint16_t adcsum = 0;
11
      uint8_t i;
12
      
13
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
14
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;
15
16
17
      for( i = 64; i > 0; i-- )
18
      {
19
        for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
20
        ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
21
        __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
22
//        results[0] = ADC10MEM;
23
        adcsum += ADC10MEM;
24
    
25
        ADC10CTL0 &= ~ENC;
26
      }
27
      adcsum = adcsum>>6;
28
      results[0] = (int) adcsum;
29
30
      ADC10CTL1 = INCH_11;                  // AVcc/2
31
      ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE + REF2_5V;
32
      for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
33
      ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
34
      __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
35
      results[1] = ADC10MEM;
36
      ADC10CTL0 &= ~ENC;
37
      ADC10CTL0 &= ~(REFON + ADC10ON);      // turn off A/D to save power
38
      
39
      // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278
40
      // the temperature is transmitted as an integer where 32.1 = 321
41
      // hence 4230 instead of 423
42
43
      temp = results[0];
44
      degC = (((temp - 673) * 4230) / 1024);
45
      if( (*tempOffset) != 0xFFFF )
46
      {
47
        degC += (*tempOffset); 
48
      }
49
      degC -= 40;   // temperature is too high - minus 4°C
50
51
      temp = results[1];
52
      volt = (temp*25)/512;
53
      
54
      msg[0] = degC&0xFF;
55
      msg[1] = (degC>>8)&0xFF;
56
      msg[2] = volt;
57
      transmitDataString(1, addr, rssi, msg );
58
      BSP_TOGGLE_LED1();
59
      sSelfMeasureSem = 0;
60
    }

Das läuft in der main(). Der Interrupt der durch den ADC ausgelöst wird, 
schaltet die CPU wieder ein. Das sSelfMeasureSem wird durch einen 
Timerinterrupt gesetzt, ca. jede Sekunde.
Der original Source ist im Prinzip wie dieser, nur ohne die for und ohne 
i und adcsum. Zusätzlich ziehe ich noch 4°C ab, aber das betrifft ja 
nicht das Problem.
Dies hatte ich testweise auch schon ausserhalb der for
        for( degC = 240; degC > 0; degC-- );  // delay to allow 
reference to settle
Ich bin mir da nicht sicher, an welche Stelle das kommt. Am Anfang ist 
klar, danach wird die Referenz ja nicht mehr verändert, allerdings 
dachte ich mir, dass eine kleine Pause zwischen den Messungen auch nicht 
schadet.

@avion23: Der Stack? Die Stackgröße kann man in IAR Embedded Workbench 
einstellen. Im Projekt ist das seitens TI auf 200 gesetzt. Wenn man das 
Beispiel (von TI ohne Änderungen) mitm Debugger laufen lässt und anhält, 
warnt er, dass der Stack mit 100% voll ist. Ich habe das testweise und 
aktuell mal auf 360 gesetzt, damit hab ich die Meldung nicht mehr 
erhalten. Was ich davon halten soll weiss ich nicht so recht, da das 
original wie gesagt stabil läuft.

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.