mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP 430 ADC Abtastfrequenz, kriegs nicht hin


Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

darf mich mal als neu outen in der Welt der uC.
Jetzt möchte ich gerne auf dem MSP430F149 ein Signal AD wandeln.
Das Signal soll überabgetastet werden, also mit 8KHz abgestastet werden.

Da kommt schon mein Problem ich habe an ACLK ein 32kHz Quarz.
Jetzt geb ich ACLK als ADC12CLK vor und teile den durch 4 super ich habe 
8kHz. Jetzt will ich das testen, ich springe also jedesmal wenn ich ein 
AD-Wandlung abgeschlossen habe in einen Interrupt und XOR den Pin, spric 
er toggelt, jetzt sollte ich doch die Abtastrate sehen oder?

Nur ich seh jetzt runde 1kHz, was läuft da schief?

Hoff da kann mir jemand weiterhelfen, dreh heute noch durch.



CODE:

#include  <msp430x14x.h>

#define   Num_of_Results   8

static unsigned int results[Num_of_Results];  // Needs to be global in 
this
                                              // example. Otherwise, the
                                              // compiler removes it 
because it
                                              // is not used for 
anything.

void main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
  P6SEL |= 0x01;                            // Enable A/D channel A0
  BCSCTL1 = DIVA_0 + RSEL0 + RSEL1 + RSEL2;
  P5DIR |= 0x70;                            // P5.6,5,4 outputs
  P5SEL |= 0x70;                            // P5.6,5,5 options
  ADC12CTL0 = ADC12ON+SHT1_0+SHT0_0+MSC;           // Turn on ADC12, set 
sampling time
  ADC12CTL1 = ADC12SSEL_1+SHP+CONSEQ_2;                 // Use sampling 
timer, set mode
  ADC12IE = 0x01;                           // Enable ADC12IFG.0
  ADC12CTL0 |= ENC;                         // Enable conversions
  ADC12CTL0 |= ADC12SC;                     // Start conversion
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0,Enable 
interrupts
}


#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
{
  static unsigned int index = 0;

  results[index] = ADC12MEM0;               // Move results
  index = (index+1)%Num_of_Results;         // Increment results index, 
modulo
  P4DIR |=0xFF;
  P4OUT ^=0xFF;
}

Autor: hagbard celine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zeile 23 anschauen.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super Sache.

Jetzt hab ich mal die Zeilen rausgemacht jetzt hab ich 56kHz anliegen 
super!!!!!!

Mensch ich brauch ne Aussage was ich machen muss nicht was ich mir 
anschauen soll sonst hätt ich es schon richtig.

Um das nochmal zu klären ich würde einfach gerne im P4 meine Smplerate 
am Oszi sehen mehr nicht.


hier der erneuerte Code:

#include  <msp430x14x.h>

#define   Num_of_Results   8

static unsigned int results[Num_of_Results];  // Needs to be global in 
this
                                              // example. Otherwise, the
                                              // compiler removes it 
because it
                                              // is not used for 
anything.

void main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
  P6SEL |= 0x01;                            // Enable A/D channel A0
  BCSCTL1 = DIVA_0 + RSEL0 + RSEL1 + RSEL2;
  P5DIR |= 0x70;                            // P5.6,5,4 outputs
  P5SEL |= 0x70;                            // P5.6,5,5 options
  ADC12CTL0 = ADC12ON+SHT1_0+SHT0_0+MSC;           // Turn on ADC12, set 
sampling time
  ADC12CTL1 = ADC12SSEL_1+SHP+CONSEQ_2;                 // Use sampling 
timer, set mode
  ADC12IE = 0x01;                           // Enable ADC12IFG.0
  ADC12CTL0 |= ENC;                         // Enable conversions
  ADC12CTL0 |= ADC12SC;                     // Start conversion
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0,Enable 
interrupts
}


#pragma vector=ADC12_VECTOR
__interrupt void ADC12OV (void)
{
  P4DIR |=0xFF;
  P4OUT ^=0xFF;
}

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo laeuft den dein Prozessor am Schluss des Programmes hin ?
Mach da mal ein while(1); am Schluss rein sonst laeuft der ins Leere.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok hab ich gemacht, geändert hat sich trotzdem nichts? Steh hier auf 
einem Feuerwehrschlauch ich sags euch.

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da kommt schon mein Problem ich habe an ACLK ein 32kHz Quarz.
>Jetzt geb ich ACLK als ADC12CLK vor und teile den durch 4 super ich habe
>8kHz. Jetzt will ich das testen, ich springe also jedesmal wenn ich ein
>AD-Wandlung abgeschlossen habe in einen Interrupt und XOR den Pin, spric
>er toggelt, jetzt sollte ich doch die Abtastrate sehen oder?

>Nur ich seh jetzt runde 1kHz, was läuft da schief?

Deine ADC12CLK ist nicht die Sampleclock , sondern der Arbeitstakt 
deines ADCs.

Deine Wandlung ist erst nach 13 Takten fertig. Also 8KHz / 13 = 
Wandlungsrate. Und da kommen deine 1 KHz schon in etwa hin.
Nimm mal den ADC12OSC als Arbeitstakt oder sorgt dafuer das die ACLK 
schneller wird.

>Steh hier auf einem Feuerwehrschlauch ich sags euch.

Nicht so aufregen sonst gibt noch einen Herzinfarkt.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Helmut Lenzen schrieb:

> Deine Wandlung ist erst nach 13 Takten fertig. Also 8KHz / 13 =
> Wandlungsrate. Und da kommen deine 1 KHz schon in etwa hin.
Nicht ganz. 4 Takte für S/H kommen noch dazu.
Ausserdem sehe ich nirgends, dass ADC12CLK = ACLK / 4 eingestellt wird!
ADC12CLK = ACLK!

> Nimm mal den ADC12OSC als Arbeitstakt oder sorgt dafuer das die ACLK
> schneller wird.
Dann braucht man ACLK nicht mehr. CPU läuft über'n DCO

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist doch mal ne Aussage.
Ok Hab jetzt mal den ADC12OSC als Arbeitstakt genommen.
sollte ja um die 5MHz sein teil ich das durch 13 kommen knappe 390kHz 
raus am Oszi werden mir aber 80kHz angezeigt, stell ich ein Teiler von 8 
ein DIVA_3 kommen immernoch 80kHz raus, was stimmt da nicht?

CODE:
#include  <msp430x14x.h>

void main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
  P6SEL |= 0x01;                            // Enable A/D channel A0
  BCSCTL1 = DIVA_0 + RSEL0 + RSEL1 + RSEL2;
  P5DIR |= 0x70;                            // P5.6,5,4 outputs
  P5SEL |= 0x70;                            // P5.6,5,5 options
  ADC12CTL0 = ADC12ON+SHT1_0+SHT0_0+MSC;    // Turn on ADC12, set 
sampling time
  ADC12CTL1 = ADC12SSEL_0+SHP+CONSEQ_2;     // Use sampling timer, set 
mode
  ADC12IE = 0xFF;                           // Enable ADC12IFG.0
  ADC12CTL0 |= ENC;                         // Enable conversions
  ADC12CTL0 |= ADC12SC;                     // Start conversion
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0,Enable 
interrupts
  while(1);
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12OV (void)
{
  P4DIR |=0x01;
  P4OUT ^=0xFF;
}

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie schnell ist denn deine MCLK fuer dein Prozessor getaktet ?

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nicht ganz. 4 Takte für S/H kommen noch dazu.

Ok habe ich geschlabbert.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, kommt trotzdem nicht hin.

SMCLK/MCLK führ ich ja raus kommen knapp 3.1Mhz raus.

Aber das Problem ist, wenn ich DIVA ändere sollte sich doch auch das 
Signal am Ausgang ändern macht es aber gerade mal garnicht, das versteh 
ich nicht.

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  ADC12IE = 0xFF;                           // Enable ADC12IFG.0


Du willst nur den Interrupt von Kanal 0 schaltest aber alle ein.

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Irgendwie sehe ich auch nicht wo CSTARTADD in ADC12CTL1 gesetzt wird.
Auch must du in den Registern ADC12MCTLx das EOS bit setzen.
Dein Interrupt kommt nur wenn er die Messsequenz abgearbeitet hat und 
das ist bei dir Zufall was da drin steht.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So jetzt nochmal zum Verständnis.

Ich lege ACLK mit DIVA_0 an heisst mein ADC12CLK ist 32Khz.
Passt soweit auch kann ich ja am P2.6 abnehmen.
So nun ist SHT0_0 SHT1_= und MSC_1 damit sollte eine Sample Time 32kHz/4 
also 8kHz herauskommen.
Ok. Nun ist A0 als ADC eingang geschaltet.
 ADC12MCTL0 = EOS+INCH_0+SREF_0; Hier setze ich End of Sample (weiß ich 
nicht wirklich für was das gut ist) SREF auf AVCC und AVSS, INput 
Channel auf A0.

Soweit so gut.
Jetzt sollte er ja nach jedem schreiben in den Memory in mein INterrupt 
springen, also ist das meine Abtastfrequenz? Oder bin ich da falsch?

Oder gibt es eine Fausformel wie ich auf meine Abtastfrequenz komme ohne 
groß zu überlegen.

Ich muss halt eine bestimmte Abtastfrequenz haben weil ich Mittelwert 
über ~1s bilden will.


CODE:
#include  <msp430x14x.h>

void main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
  P6SEL |= 0x01;                            // Enable A/D channel A0
  BCSCTL1 = DIVA_0 + RSEL0 + RSEL1 + RSEL2;
  P5DIR |= 0x70;                            // P5.6,5,4 outputs
  P5SEL |= 0x70;                            // P5.6,5,5 options
  P2DIR |= 0x40;
  P2SEL |= 0x40;
  ADC12CTL0 = ADC12ON+SHT1_0+SHT0_0+MSC;    // Turn on ADC12, set 
sampling time
  ADC12CTL1 = CSTARTADD_0+ADC12SSEL_1+SHP+CONSEQ_2;     // Use sampling 
timer, set mode
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //End of Sequence; Reference 
AVCC AVSS; Input Channel A0
  ADC12IE = 0x01;                           // Enable ADC12IFG.0
  ADC12CTL0 |= ENC;                         // Enable conversions
  ADC12CTL0 |= ADC12SC;                     // Start conversion
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0,Enable 
interrupts
  while(1);
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12OV (void)
{
  P4DIR |=0x01;
  P4OUT ^=0xFF;
 }

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
EOS ist end of sequence, brauchst du, wenn du mehrere Kanäle 
hintereinander wandeln willst. Durch das XOR in deiner ISR bekommst du 
eh nur die halbe Abtastfrequenz am P4 raus, weil ja zu einer Periode 2 
Flankenwechsel gehören.
Was kommt denn raus an P4?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Hof schrieb:
> So nun ist SHT0_0 SHT1_= und MSC_1 damit sollte eine Sample Time 32kHz/4
> also 8kHz herauskommen.

Nö! SHTx stellt die Samplingzeit ein und die beträgt bei Dir nun 4 
Taktzyklen. Dazu kommen noch 13 Takzyklen Wandlungsdauer... macht 
zusammen 17 Taktzyklen bei einem Clock von 32kHz!

Werf mal einen (erneuten) Blick in den User Guide :-)

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also an P4 liegt ~80kHz, d.h. ich hab eine Effektive Abtastrate von 
40kHz.

Ok 17 Zyklen von 32kHz = 531,25us solange dauert es einmal ein Wert 
einzulesen, das wäre dann eine Abtastrate von 1,882kHz.

Was macht denn der gute uC bei tsample ? Was heißt 4 Taktcyklen 
Smaplingtime?
Heißt das er braucht 4*1/32kHz um einen Wert am ADC anliegen zu haben 
und nochmal 13 Zyklen um ihn in einen Digitalen Wert zu Wandeln?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Hof schrieb:
> Was macht denn der gute uC bei tsample ? Was heißt 4 Taktcyklen
> Smaplingtime?
Die Eingangskapazität des ADC muss aufgeladen werden (RC-Glied).
D.h. man muss eine gewisse "Wartezeit" einhalten und die stellt man mit 
SHTx ein.

> Heißt das er braucht 4*1/32kHz um einen Wert am ADC anliegen zu haben
> und nochmal 13 Zyklen um ihn in einen Digitalen Wert zu Wandeln?
So sieht's aus!

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau mal in den User Guide, da sind alle deine Fragen erklärt. Bei 
80kHz am P4 wird deine ISR mit 160khz aufgerufen. Durch das XOR machst 
du dann 80kHz draus. Ich schätze, da läuft mit dem Takt was falsch, 
sicherlich liegt der SMCLK als ADC-Takt an, oder der ADC Oszillator.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der User Guide, da schau ich seit 3 Tagen rein.
Am ADC12CLK liegt definitiv 32kHz an also kann ich mir die 160kHz 
überhaupt nicht erklären.

Also wenn ich 8kHz Abtastfrequenz haben will brauch ich 125us als 
tsample = 17*1/fs also ~136kHz.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach das ganze mal grundlegend anders. Lass den ADC mit seinem internen 
Takt laufen, berechne die Setup und Hold Zeiten entsprechend den Angaben 
im user Guide betreffs Ausgangswiderstand der zu messenden Quelle usw. 
und mach die feste Abtastrate über den Timer. Du kannst beim ADC 
einstellen, dass er durch den Timer gestartet wird. Dann musst du nur 
den Timer so einstellen, dass er aus dem SMCLK die 8kHz generiert und 
der Rest läuft dann alleine ab. In den Codebespielen, genauer in 
"fet140_adc12_11.c" ist diese Vorgehensweise genauestens beschrieben:
//*****************************************************************************
//  MSP-FET430P140 Demo - ADC12, Single Channel Rpt Mode, TA1 as Sample Trigger
//
//  Description: Sample and convert A0 using Timer_A as sample trigger in
//  Pulse Sample mode. Put "Num_of_Results" ADC12MEM0 values in results[]
//  and illuminate LED (P1.0) when done.
//
//               MSP430F149
//             ---------------
//            |               |
//     Vin -->|P6.0/A0    P1.0|--> LED
//            |               |
//
//  H. Grewal / G. Morton
//  Texas Instruments Inc.
//  May 2005
//  Built with Code Composer Essentials Version: 1.0
//*****************************************************************************
#include  <msp430x14x.h>

#define   Num_of_Results   512
int results[Num_of_Results] = {0};

void ADC_Init(void);

void main(void)
{
  WDTCTL = WDTPW | WDTHOLD;                 // Disable the Watchdog.
  ADC_Init();                               // Initialize ADC12
  ADC12CTL0 |= ENC;                         // Start conversion
  _BIS_SR(LPM0_bits);                       // Enter LPM0
}


void ADC_Init(void)
{
  P1DIR = 0xff;                             // set port to outputs
  P1OUT = 0;                                // reset port outputs
  P6SEL |= 0x01;                            // select A0 input
  ADC12CTL0 = ADC12ON+SHT0_1+REF2_5V+REFON; // Setup ADC12
  ADC12CTL1 = SHP+CONSEQ_2+SHS_1;           // Timer triggers sampling
  ADC12MCTL0 = INCH_0 + SREF_1;
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0


  TACCR0 = 1500;                            // Delay to allow Ref to settle
  TACCTL0 |= CCIE;                          // Compare-mode interrupt.
  TACTL = TASSEL_1 | MC_1;                  // TACLK = ACLK, Up mode.
  _BIS_SR(LPM3_bits + GIE);                 // Wait for delay, Enable interrupts
  TACCTL0 &= ~CCIE;                         // Disable timer

  P2SEL |= BIT3;                            // Set for Timer A1
  P2DIR |= 0x08;
  TACCR0 = 7;                               // Init TACCR0 w/ sample prd=CCR0+1
  TACCR1 = 4;                               // Trig for ADC12 sample & convert
  TACCTL1 = OUTMOD_3;                       // Set/reset
  TACTL = TACLR | MC_1 | TASSEL_1;          // ACLK, clear TAR, up mode
}

// Timer_A0 Interrupt Service Routine
__interrupt void ta0_isr(void);
TIMERA0_ISR(ta0_isr)
__interrupt void ta0_isr(void)
{
  TACTL = 0;
  LPM3_EXIT;                                // Exit LPM3 on return
}


// ADC12 Interrupt Service Routine
__interrupt void ADC_ISR (void);
ADC12_ISR(ADC_ISR)
__interrupt void ADC_ISR (void)
{
  static unsigned int index = 0;

  results[index++] = ADC12MEM0;             // Move results

  if (index == 512)
  {
    ADC12CTL0 &= ~ENC;                      // Stop conversion
    index = 0;
    P1OUT |= 0x01;
    _BIS_SR(LPM3_bits);                     // Enter LPM3, SET BREAKPOINT HERE
  }
}

Autor: Johnny B. (johnnyb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde die 8kHz Samplerate nicht mit dem Versorgungstakt des ADC's 
bestimmen, sondern z.B. mit einem Timer die Messung anstossen und den 
ADC dann selber machen lassen, mit einem vernünftigen Takt. Die Timings 
hast Du dann wahrscheinlich besser im Griff und kannst auch den Takt und 
die Einstellungen am ADC optimieren, ohne dass sich ständig Deine 
Samplerate ändert.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Christian R.
Kannst du mir mal bitte sagen wo ich da mein Timer Intervall einstell?
Wenn TACCR0 ändere, bekomm ich an P2.3 immer 4kHz, aber wie kann ich die 
Frequenz nun ändern?

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.