www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 ADC hängt bei Polling auf Interrupt


Autor: Christoph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
mein Problem ist, dass der AD-Wandler meines µC (MSP430F1610) in 
halbwegs unregelmäßigen Abständen stehen bleibt.

Das die Stelle, an der er passiert:
float pt_get()
{ 
        float temp;

        ADC12CTL0 &= 0xfffd; // ENC aus um Konfig zu ändern (stoppt am Ende der Sequenz)
        ADC12IFG &= 0xfffe;  // Interrupt flag löschen
        ADC12CTL0 |= ENC + ADC12SC;  //ADC12 wieder starten
        pt_data.count++;
        while( !(ADC12IFG & 0x0001));
        pt_data.adc = ad_get_int(0);
  temp = pt_data.adc * ADC_REF_EXT / (1<<12);  // AD-Wert --> Spannung

Der ADC läuft im "Repeat sequence of channels"-Mode frei durch.
Deshalb soll das Programm in der while-Schleife auf den nächsten 
Wandlerwert warten, da zuvor Messkanal erst durchgeschaltet wurde.
Nur bleibt er eben in der while-Schleife immer wieder hängen.
Dabei steht dann im ADC12IFG: 0x000E. Die ADC12 Kontrollregister sehen 
im Debugger eigentlich richtig aus (ENC, ADC12ON und ADC12SC sind 
gesetzt), aber der Wandler liefert keine neuen Werte, ergo kein neues 
Interrupt-flag und ich kommen nicht mehr aus der Schleife raus. Bleibt 
er hängen, ist das BUSY-Bit durchgehend 1.
Wenn ich via Debugger ADC12ON erst Null und dann wieder Eins setzte, 
läuft er weiter.
Was mich jedoch am meiste wundert ist, dass das Programm immer wieder 
nach der gleichen Anzhal Zyklen stehenbleibt. (pt_get() wird in 
2ms-Intervallen aufgerufen)
Ich habe das Programm bis jetzt 14 mal durchlaufen lassen, dabei sind 
Hänger im Bereich des 55. bis 394. Zykluses aufgetreten. Dabei waren:
55: 3mal
89: 3mal
123: 2mal
191: 2mal

Nehme ich die while-Schleife raus, treten keine Hänger auf...

Hat jemand ne Idee, wo der Fehler liegen könnte und vor allem in welche 
Richtung ich suche sollte?
Wieso beeinflusst das Polling überhaut den ADC?

Danke schonmal im Vorraus.

Gruß Christoph

und noch was: alle Interrupts sind in dem Programmbereich aus. (GIE = 0)

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso wurstet das pt_get() Programm in den ADC Registern rum wenn du 
doch sagst: "Der ADC läuft im "Repeat sequence of channels"-Mode frei 
durch."? Du musst doch die Wandlung nur einmal anstossen und er wandelt 
dann ewig weiter bist du ihn stoppst. Wenn du jedesmal von Hand neu 
startest, ist das der "sequence of channels" Mode.

Autor: Christoph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jau, komplett frei läuft er nicht durch :)
Ich hab mehrere Eingänge, die ich abtaste. Dauert insgesamt irgendwas im 
zweistelligen µs-Bereich. Alle 2ms brauche ich dann die Spannung am 
PT-Element und das relativ schnell. (Den ersten richtigen Wert nach dem 
Aufschalten der Referenzspannung). Deswegen das Löschen des 
Interrupt-Flags mit anschließendem Polling. Dann läuft er wieder frei 
weiter.
Kann gut sein, dass das noch nicht die optimale Lösung ist, so konnte 
ich aber bestehenden Code weiterverwenden. Und bevor ich da 
weiterbastel, würde ich doch ganz gerne wissen, wieso da diese Hänger 
auftreten...

Autor: Jörg S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also noch mal zum mitschreiben :)

Du machst "Repeat sequence of channels", dann willst du irgendwann einen 
speziellen AD Eingang wandeln, dazu stoppst du die "Repeat sequence of 
channels" und wandelst einmal einen Eingang und startest danach  wieder 
"Repeat sequence of channels"? Richtig?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du während "Repeat sequence of channels" eine "single-channel, 
single conversion" einschieben willst, dann solltest Du das dem ADC12 
auch sagen:
ADC12CTL1 &= ~CONSEQ_3;
Danach natürlich wieder aktivieren!

Autor: Christoph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also noch mal zum mitschreiben :)

Du machst "Repeat sequence of channels", dann willst du irgendwann einen
speziellen AD Eingang wandeln, dazu stoppst du die "Repeat sequence of
channels" und wandelst einmal einen Eingang und startest danach  wieder
"Repeat sequence of channels"? Richtig?

Nicht ganz :)
Ich bleibe im "Repeat sequence of channels"-Mode.
Also anfangs läuft er frei durch. Dann halte ich ihn durch das 
Rausnehmen von ENC am Ende der Sequenz (Kanal 3) an und lösche das 
Interrupt-Flag für Kanal 0. Dann wird er wieder gestartet und läuft 
weiter im "Repeat sequence of channels"-Mode. Da der ADC nach der 
Unterbrechung bei Kanal 0 anfängt zu sampeln, welchen ich zu diesem 
Zeitpunkt ja haben will, dürfte es schnell genug sein. Durch das Polling 
erkenne ich schlussendlich, wann mein Wert anliegt.

Ich hoffe mal das ich mich jetzt klar ausgedrückt habe. :)

Die Lösung ist aber sicherlich, wie oben auch geschrieben, noch nicht 
optimal.
Und bevor ich da
weiterbastel, würde ich doch ganz gerne wissen, wieso da diese Hänger
auftreten...

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dann halte ich ihn durch das
>Rausnehmen von ENC am Ende der Sequenz (Kanal 3) an
Du wartest aber nicht auf die letzte Conversion von Kanal 3 sondern 
startest sofort eine neue Sequenz. Da kommen sich wahrscheinlich zwei 
Sequenzen in die Quere.

Siehe User-Guide Kap ADC12:

"...Resetting ENC during a sequence or repeat-sequence mode stops the
converter at the end of the sequence...
...Any conversion mode may be stopped immediately by setting the
CONSEQx = 0 and resetting ENC bit. Conversion data are unreliable."

"If no EOS bit is set and a sequence mode is selected, resetting the ENC 
bit does not stop the sequence. To stop the sequence, first select a
single-channel mode and then reset ENC."

Autor: Christoph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du wartest aber nicht auf die letzte Conversion von Kanal 3 sondern
>startest sofort eine neue Sequenz. Da kommen sich wahrscheinlich zwei
>Sequenzen in die Quere.

Volltreffer. Oh man und ich saß da stundenlang davor und hab den Fehler 
nicht gesehen. -.-
ADC12CTL0 &= 0xfffd; // ENC aus um Konfig zu ändern (stoppt am Ende der Sequenz)
ADC12IFG &= 0xfffe;  // Interrupt flag löschen
while(ADC12CTL1 & ADC12BUSY);
ADC12CTL0 |= ENC + ADC12SC;  //ADC12 wieder starten
while( !(ADC12IFG & 0x0001));
pt_data.adc = ad_get_int(0);

Jetzt läuft alles wie es soll.

Ist zwar ein bißchen viel Gepolle, aber das stört erstmal nicht. :)

Danke für die Hilfe!

Gruß, Christoph

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.