mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 ADC12 Problem


Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein Problem mit dem ADC12 des MSP430FG4618 DevBoard.

Ich habe eine Interruptroutine für den ADC-Conversion Vorgang 
programmiert, die allerdings nicht mehr verlassen wird, d.h. es wird 
nicht mehr in den Main-Loop des Programms zurückgekehrt. Hat jemand eine 
Idee, woran das liegen könnte?

Hier erst mal meine init-routine:
void init_adc() {
P6SEL = 0x0F;
  ADC12CTL0 = ADC12ON + MSC + SHT0_2;   // Turn on ADC12, set sampling time
  ADC12CTL1 = SHP + CONSEQ_1;           // Use sampling timer, single sequ
  ADC12MCTL0 = INCH_0;                  // ref+=AVcc, channel = A0 
  ADC12MCTL1 = INCH_1;                  // ref+=AVcc, channel = A1
  ADC12MCTL2 = INCH_2;                  // ref+=AVcc, channel = A2
  ADC12MCTL3 = INCH_3 + EOS;            // ref+=AVcc, channel = A3, end seq 
  ADC12IE = 0x08;                       // Enable interrupt
  ADC12CTL0 |= ENC;                     // Conversion enabled 
}

Die wird aufgerufen durch:
WDTCTL = WDTPW + WDTHOLD;  // Stop watchdog timer
FLL_CTL0 |= XCAP18PF;  // Set LoadCap 
init_adc();  
_BIS_SR(CPUOFF + GIE);         

und hier jetzt die Routine selbst - die aber eigentlich nicht viel 
macht, außer eine Ausgabe auf die Serielle Schnittstelle zu schreiben:
__interrupt void ADC_ISR (void);
ADC12_ISR(ADC_ISR)
__interrupt void ADC_ISR (void) {
    printUART("ADC-IR\r\n",sizeof("ADC-IR\r\n"));
    _BIC_SR_IRQ(CPUOFF);     
    _NOP();
}

Im Main-Loop steht noch folgendes:
while (true){
  P2OUT ^= 0x02;         
  DC12CTL0 |= ADC12SC;          
  for (i = 0; i < 20000; i++);
}

Hat vielleicht jemand eine Idee? Wie gesagt - wird die 
Interrupt-Routine, des ADCs nicht verlassen, bzw. dauert so lange, dass 
bevor ins Hauptprogramm zurückgesprungen werden kann, wieder die Routine 
aufgerufen wird.

Ich kenn mich leider mit dem TI nicht so gut aus, daher wäre - falls es 
ein Zeitproblem wäre - die Frage, wie ich die Aufrufzeit der ISR 
bestimmen kann. Also wie kann ich einstellen, mit welcher Frequenz der 
Interrupt "gefeuert" wird?

Danke GALDO

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abgesehen vom Programmierstil: Was für eine Datentyp hat den i?

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist denn mit dem Programmierstil?
volatile unsigned int i = 0;

Galdo

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"printUART" in einer Interruptroutine aufrufen? Ist das eine gute Idee?

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir ist schon bewusst, dass "sowas" ewíg dauert, allerdings - macht es 
auch keinen Unterschied, wenn ich das nicht verwende.

Das Problem ist in meinen Augen, dass der Interrupt viel zu hoch 
frequentiert ist und ich nicht weiß, wie ich das vernünftig einstellen 
kann. Ich habe den Code stellenweiße aus den Beispielen von TI - aber 
die Informationen dazu sind sehr gering :(

Er kommt - ob mit oder ohne UART - nicht mehr aus der ISR rauß - somit 
wird nur noch eine Wandlung abgearbeitet, ich habe aber auch noch 
anderen Code, der mal verarbeitet werden müsste - somit brauch ich 
unbedingt noch Ausführungszeit für den Main-Loop.

Hat jemand noch ne Idee?

Danke GALDO

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich antworte mir mal selbst:

Ich habe jetzt eine BruteForce-Lösung programmiert, allerdings wäre eure 
Meinung dazu nicht schlecht.

Ich schalte einfach
ADC12IE = 0x00;
 in der ADC12_ISR, mit einem Timer von etwa 4Hz bis 6Hz (müsste man mal 
mim Oszi plotten), schalte ich jetzt einfach mit dieser Frequenz die
ADC12IE = 0x0F;
 und damit ein.

Das funktioniert soweit ganz gut - allerdings habe ich damit noch keine 
tatsächliche Wandlung versucht - das werde ich demnächst mal testen.

Aber das wäre - sofern es funktioniert - genau das was ich brauche, AD 
auslesen, wandeln, zurückschicken - warten - AD auslesen, wandeln, 
zurückschicken - warte - etc.

Wie würdet ihr obige Anforderung implementieren?

Danke für weitere Anregungen und Hinweise
GALDO

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

Bewertung
0 lesenswert
nicht lesenswert
Andreas del Galdo wrote:

> Aber das wäre - sofern es funktioniert - genau das was ich brauche, AD
> auslesen, wandeln, zurückschicken - warten - AD auslesen, wandeln,
> zurückschicken - warte - etc.
>
> Wie würdet ihr obige Anforderung implementieren?

Nicht so.

Eher so:

  Interrupt kommt

  ADC wird ausgelesen
  Wert wird in einer globalen Variablen bereitgestellt
  zusätzliche globale Variable auf 1 setzen (das sog. Jobflag)
  um der ganzen Welt anzuzeigen, dass ein ADC Wert verfügbar ist
  und etwas damit gemacht werden müsste.

  Interrupt fertig


In der Hauptschleife in main()

  while( 1 ) {

   das Jobflag für den ADC abfragen
   ist es 0  -> kein Wert da, weiter wie bisher
   ist es 1  ->
        Interrupt sperren
        Wert von der globalen Variablen wegholen
        Jobflag wieder auf 0 setzen.
        Interrupt freigeben
        Wert formatieren und über UART ausgeben

  }


Auf die Art ist die Interrupt Routine so kurz wie es nur
irgendwie geht und lässt noch jede Menge Rechenzeit für
anderes übrig.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DC12CTL0 |= ADC12SC;

Ist das ein Schreibfehler? Da fehlt das A. Außerdem: Sobald das SC Bit 
gesetzt wird, startet der Sequenzer und wandelt die 4 Werte und löst den 
Int aus.

Außerdem muss man soweit ich mich erinnere, das ADC12IFG Register selber 
löschen, weiß nich ob das nen Bug ist oder gewollt....

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja - das war ein Copy&Paste Fehler - da wurd das A verschluckt!

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab jetzt mal ein Netzgerät angeschlossen (den Pluspol an einen 
Kanal) und siehe da - es kommt Käse rauß...

Ohne Irgendwas dran hätte doch eigentlich als 0 1,25V raußkommen sollen 
- und was bekomme ich:
Result: 0.318V, 0.923V, 0.001V, 0.732V

Sobald ich dann das Netzgerät - eingestellt auf etwa 3V anschließe 
bekomme ich so abstruße Werte wie 0V, oder 4,2V nur nicht drei - und es 
kommt auch drauf an, wo ich das Netzgerät anschließe - die Werte ändern 
sich an jedem Kanal anders.

Hier nochmal der Init-Code:
void init_adc() {
  P6SEL = 0x0F;
  ADC12CTL0   = ADC12ON + MSC + SHT0_2;
  ADC12CTL1   = SHP + CONSEQ_1;           // Use sampling timer, single sequ
  ADC12MCTL0   = INCH_0;                  // ref+=AVcc, channel = A0 //SREF_1
  ADC12MCTL1   = INCH_1;                  // ref+=AVcc, channel = A1
  ADC12MCTL2   = INCH_2;                  // ref+=AVcc, channel = A2
  ADC12MCTL3   = INCH_3 + EOS;            // ref+=AVcc, channel = A3, end seq 
  ADC12IE     = 0x0F;                       // Enable interrupt
  ADC12CTL0   |= ENC;                     // Conversion enabled 
}

Hat jemand vielleicht nen Tipp, woran das liegen könnte?

Vielen Dank
Galdo

Autor: Andreas DG (galdo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erledigt...

War ein Denkfehler - somit ist alles korrekt!

Vielen Dank für eure Hilfe!

Galdo

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.