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


von Fabian H. (Firma: keine) (eimer)


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;
}

von hagbard celine (Gast)


Lesenswert?

zeile 23 anschauen.

von Fabian H. (Firma: keine) (eimer)


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;
}

von Helmut L. (helmi1)


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.

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

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

von Helmut L. (helmi1)


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.

von Stefan (Gast)


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

von Fabian H. (Firma: keine) (eimer)


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;
}

von Helmut L. (helmi1)


Lesenswert?

Wie schnell ist denn deine MCLK fuer dein Prozessor getaktet ?

von Helmut L. (helmi1)


Lesenswert?

>Nicht ganz. 4 Takte für S/H kommen noch dazu.

Ok habe ich geschlabbert.

von Fabian H. (Firma: keine) (eimer)


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.

von Helmut L. (helmi1)


Lesenswert?

>  ADC12IE = 0xFF;                           // Enable ADC12IFG.0


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

von Helmut L. (helmi1)


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.

von Fabian H. (Firma: keine) (eimer)


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;
 }

von Christian R. (supachris)


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?

von Stefan (Gast)


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 :-)

von Fabian H. (Firma: keine) (eimer)


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?

von Stefan (Gast)


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!

von Christian R. (supachris)


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.

von Fabian H. (Firma: keine) (eimer)


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.

von Christian R. (supachris)


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:
1
//*****************************************************************************
2
//  MSP-FET430P140 Demo - ADC12, Single Channel Rpt Mode, TA1 as Sample Trigger
3
//
4
//  Description: Sample and convert A0 using Timer_A as sample trigger in
5
//  Pulse Sample mode. Put "Num_of_Results" ADC12MEM0 values in results[]
6
//  and illuminate LED (P1.0) when done.
7
//
8
//               MSP430F149
9
//             ---------------
10
//            |               |
11
//     Vin -->|P6.0/A0    P1.0|--> LED
12
//            |               |
13
//
14
//  H. Grewal / G. Morton
15
//  Texas Instruments Inc.
16
//  May 2005
17
//  Built with Code Composer Essentials Version: 1.0
18
//*****************************************************************************
19
#include  <msp430x14x.h>
20
21
#define   Num_of_Results   512
22
int results[Num_of_Results] = {0};
23
24
void ADC_Init(void);
25
26
void main(void)
27
{
28
  WDTCTL = WDTPW | WDTHOLD;                 // Disable the Watchdog.
29
  ADC_Init();                               // Initialize ADC12
30
  ADC12CTL0 |= ENC;                         // Start conversion
31
  _BIS_SR(LPM0_bits);                       // Enter LPM0
32
}
33
34
35
void ADC_Init(void)
36
{
37
  P1DIR = 0xff;                             // set port to outputs
38
  P1OUT = 0;                                // reset port outputs
39
  P6SEL |= 0x01;                            // select A0 input
40
  ADC12CTL0 = ADC12ON+SHT0_1+REF2_5V+REFON; // Setup ADC12
41
  ADC12CTL1 = SHP+CONSEQ_2+SHS_1;           // Timer triggers sampling
42
  ADC12MCTL0 = INCH_0 + SREF_1;
43
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
44
45
46
  TACCR0 = 1500;                            // Delay to allow Ref to settle
47
  TACCTL0 |= CCIE;                          // Compare-mode interrupt.
48
  TACTL = TASSEL_1 | MC_1;                  // TACLK = ACLK, Up mode.
49
  _BIS_SR(LPM3_bits + GIE);                 // Wait for delay, Enable interrupts
50
  TACCTL0 &= ~CCIE;                         // Disable timer
51
52
  P2SEL |= BIT3;                            // Set for Timer A1
53
  P2DIR |= 0x08;
54
  TACCR0 = 7;                               // Init TACCR0 w/ sample prd=CCR0+1
55
  TACCR1 = 4;                               // Trig for ADC12 sample & convert
56
  TACCTL1 = OUTMOD_3;                       // Set/reset
57
  TACTL = TACLR | MC_1 | TASSEL_1;          // ACLK, clear TAR, up mode
58
}
59
60
// Timer_A0 Interrupt Service Routine
61
__interrupt void ta0_isr(void);
62
TIMERA0_ISR(ta0_isr)
63
__interrupt void ta0_isr(void)
64
{
65
  TACTL = 0;
66
  LPM3_EXIT;                                // Exit LPM3 on return
67
}
68
69
70
// ADC12 Interrupt Service Routine
71
__interrupt void ADC_ISR (void);
72
ADC12_ISR(ADC_ISR)
73
__interrupt void ADC_ISR (void)
74
{
75
  static unsigned int index = 0;
76
77
  results[index++] = ADC12MEM0;             // Move results
78
79
  if (index == 512)
80
  {
81
    ADC12CTL0 &= ~ENC;                      // Stop conversion
82
    index = 0;
83
    P1OUT |= 0x01;
84
    _BIS_SR(LPM3_bits);                     // Enter LPM3, SET BREAKPOINT HERE
85
  }
86
}

von Johnny B. (johnnyb)


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.

von Fabian H. (Firma: keine) (eimer)


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?

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.