www.mikrocontroller.net

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


Autor: devzero (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
    // if it is time to measure our own temperature...
    if(sSelfMeasureSem)
    {
      char msg [6];
      char addr[] = {"HUB0"};
      char rssi[] = {"000"};
      int degC, volt;
      volatile long temp;
      int results[2];
      
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;
      for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
      ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
      __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
      results[0] = ADC10MEM;
    
      ADC10CTL0 &= ~ENC;
...
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)
    // if it is time to measure our own temperature...
    if(sSelfMeasureSem)
    {
      char msg [6];
      char addr[] = {"HUB0"};
      char rssi[] = {"000"};
      int degC, volt;
      volatile long temp;
      int results[2];
      uint16_t adcsum = 0;
      uint8_t i;
      
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;

      for( i = 64; i > 0; i-- )
      {
        for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
        ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
        __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
//        results[0] = ADC10MEM;
        adcsum += ADC10MEM;
    
        ADC10CTL0 &= ~ENC;
      }
      adcsum = adcsum>>6;
      results[0] = (int) adcsum;
...

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Watchdog  ein/aus geschaltet ?
Durch die laengere Laufzeit koennte eventuelle der Watchdog zuschlagen.

Autor: devzero (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: avion23 (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: devzero (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In dem ZIP ist es die main_AP.c im Ordner Applications.
    // if it is time to measure our own temperature...
    if(sSelfMeasureSem)
    {
      char msg [6];
      char addr[] = {"HUB0"};
      char rssi[] = {"000"};
      int degC, volt;
      volatile long temp;
      int results[2];
      uint16_t adcsum = 0;
      uint8_t i;
      
      ADC10CTL1 = INCH_10 + ADC10DIV_4;     // Temp Sensor ADC10CLK/5
      ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;


      for( i = 64; i > 0; i-- )
      {
        for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
        ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
        __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
//        results[0] = ADC10MEM;
        adcsum += ADC10MEM;
    
        ADC10CTL0 &= ~ENC;
      }
      adcsum = adcsum>>6;
      results[0] = (int) adcsum;

      ADC10CTL1 = INCH_11;                  // AVcc/2
      ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE + REF2_5V;
      for( degC = 240; degC > 0; degC-- );  // delay to allow reference to settle
      ADC10CTL0 |= ENC + ADC10SC;           // Sampling and conversion start
      __bis_SR_register(CPUOFF + GIE);      // LPM0 with interrupts enabled
      results[1] = ADC10MEM;
      ADC10CTL0 &= ~ENC;
      ADC10CTL0 &= ~(REFON + ADC10ON);      // turn off A/D to save power
      
      // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278
      // the temperature is transmitted as an integer where 32.1 = 321
      // hence 4230 instead of 423

      temp = results[0];
      degC = (((temp - 673) * 4230) / 1024);
      if( (*tempOffset) != 0xFFFF )
      {
        degC += (*tempOffset); 
      }
      degC -= 40;   // temperature is too high - minus 4°C

      temp = results[1];
      volt = (temp*25)/512;
      
      msg[0] = degC&0xFF;
      msg[1] = (degC>>8)&0xFF;
      msg[2] = volt;
      transmitDataString(1, addr, rssi, msg );
      BSP_TOGGLE_LED1();
      sSelfMeasureSem = 0;
    }  

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.