Forum: Mikrocontroller und Digitale Elektronik MSP430F2013 ADC oversampling


von Dirk (Gast)


Lesenswert?

MSP430F2013

Weiß jemand wie das mit dem Digital Filter Output
und dem Oversampling geht?

Die Werte bei einer Gleichspannung springen bei mir sehr.

Ich triggere den ADC von aussen (200x/sec),
und übernehme die Werte in einen anderen µP.

// ....
   SD16CTL = SD16REFON + SD16SSEL_1;         // 1.2V ref, SMCLK
   SD16INCTL0 = SD16INCH_1;                  // A1+/-
   SD16CCTL0 = SD16SNGL + SD16UNI + SD16IE ; // Single conv,
                                             //interrupt,unipolar
   SD16AE = SD16AE2;     // P1.2 A1+; P1.3 A1- = VSS    =>Löt 4 / 5
//..............

Könnte ich pro Aufruf mehrere Messungen machen lassen,
und dann den Mittelwert abfragen/versenden?
Oder muß ich das von Hand programmieren?



Vielen Dank im Vorraus
Dirk

von Dirk (Gast)


Lesenswert?

Hallo,

kann mir einer sagen was hier falsch ist bei der addition?
bzw. wie das richtig in C geschrieben wird.

//.....................
   if (OVS==1)
   {
     Wert4 = SD16MEM0;

     Wert = Wert1 + Wert2 + Wert3 + Wert4;
     Wert=Wert/4;

     Wert_Senden ();

     OVS=0;
   }
//.....................

auch..
   Wert=Wert1
   Wert+=Wert2
   usw.
gibt eine Wahrnung

Vielen Dank
Dirk

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> gibt eine Wahrnung

Welche? (Übrigens ohne 'h')

von Dirk (Gast)


Lesenswert?

Hallo Rufus,

die Meldung(!) lautet:
[Pa082]: undefined behavior: the order of volatile accesses is undefined 
in this statement

Wert = Wert1 + Wert2 + Wert3 + Wert4;

auch bei
Wert+=Wert2;


Also wie addiert mann/frau in 'C' für den MSP430F2013

Dirk


von Christian R. (supachris)


Lesenswert?

Ich nehme an, du willst einen gleitenden Mittelwert realisieren, oder?
Da brauchst du eine Art Ringpuffer, der bei jedem Sample mit einem neuen 
Wert gefüllt wird. Nach dem neuen Wert musst du die letzten x Werte 
aufsummieren und wieder teilen. Für Werte 2^x geht das besonders gut, 
dann hast du schnelle Bitschiebe-Operationen.

Das sieht dann bei mir folgendermaßen in der ADC12 ISR aus:
1
      SamplePointer = SampleCount & ModeMedianSampleMask;    //ganz billiger Ringpuffer ;-)
2
      // -> Index wird mit der Anzahl der Mittelwert-Samples -1 markiert 
3
      // z.B. Anzahl 8 -> unterste 3 Bits werden 1 gesetzt,
4
      // -> Index läuft immer nur von 0 bis 7 durch
5
      
6
      
7
      ADCData0[SamplePointer] = ADC12MEM0;            //Werte in die Puffer
8
      ADCData1[SamplePointer] = ADC12MEM1;
9
      ADCData2[SamplePointer] = ADC12MEM2;
10
      ADCData3[SamplePointer] = ADC12MEM3;
11
      
12
      unsigned char i;
13
      unsigned char j;          
14
15
      
16
      i = ModeMedianSampleCount;
17
      j = (SamplePointer -i) & ModeMedianSampleMask;
18
      
19
      MedianValue0 = ADCData0[j];                  //Neue Startwerte in Mittelwert
20
      MedianValue1 = ADCData1[j];
21
      MedianValue2 = ADCData2[j];
22
      MedianValue3 = ADCData3[j];
23
      
24
      i--;
25
      
26
      while(i)                          //restliche n-1 Werte aufsummieren
27
      {
28
        j = (SamplePointer -i) & ModeMedianSampleMask;      //Position im "Ringpuffer" neu berechnen
29
        MedianValue0 += ADCData0[j];
30
        MedianValue1 += ADCData1[j];
31
        MedianValue2 += ADCData2[j];
32
        MedianValue3 += ADCData3[j];
33
        i--;
34
      }
35
      
36
      
37
MedianValue0 = MedianValue0 >> ModeMedianSampleBitShift;  //Ales nochma rumschieben....
38
MedianValue1 = MedianValue1 >> ModeMedianSampleBitShift;
39
MedianValue2 = MedianValue2 >> ModeMedianSampleBitShift;
40
MedianValue3 = MedianValue3 >> ModeMedianSampleBitShift;
41
      
42
      
43
ADC12IFG = 0x00;  // Flags löschen 
44
ADC12CTL0 |= ADC12SC;  // schon mal Start conversion....kann ja nich schaden, spart zeit am Ende.



Die nötigen Werte werden vor dem Sampling-Start irgendwoanders 
folgendermaßen initialisiert, um zeit zu sparen:
1
if(samples == 2)ModeMedianSampleBitShift = 0;
2
if(samples == 4)ModeMedianSampleBitShift = 1;
3
if(samples == 8)ModeMedianSampleBitShift = 2;
4
if(samples == 16)ModeMedianSampleBitShift = 3;
5
      
6
ModeMedianSampleMask = ModeMedianSampleCount - 1;

Geht natürlich in der einfachen Form nur für 1,2,4,8 oder 16 
Mittelungen, dann ist der 16 Bit Wertebereich für die ADC12 Summen-Werte 
erschöpft.

von Dirk (Gast)


Lesenswert?

Hallo  Christian R.,



ergentlich wollte ich bei jedem triggern 4x hintereinander messen und
aus den 4 Messungen dann den Mittelwert bilden.

Den Code habe ich schon geschrieben, aber die Zeilen mit der Addition 
will er
einfach nicht haben.

Danke für das Beispiel

Dirk

von Dirk (Gast)


Lesenswert?

Hallo,
habe die Vars verändert

 volatile unsigned long ADC_Wert;
=>> long ADC_Wert;

nun kommt keine Meldung mehr.




Danke, einfach zuwenig 'C'

Dirk

von Uhu U. (uhu)


Lesenswert?

Na, jetzt hast Dus durch probieren rausbekommen - aber weißt Du auch, 
was Du gemacht hast und warum volatile diese Warnung erzeugt?

von Dirk (Gast)


Angehängte Dateien:

Lesenswert?

Hallo  Uhu Uhuhu,

nein habe die Sache bisher nicht weiter verfolgt,
bin an den Vorbereitungen für die Digitalen Filtern dran.

Leider habe ich nur ein Multimeter, und muß deshalb alles schichtweise 
aufbauen und auch verbessern(4fach messen je Wert).

Meine Soundkarte(Uralt) gibt was sinusartige ab 7Hz aus, ab ca. 15Hz 
kann ich es gebrauchen.

Das Bild zeigt einen 25Hz Sinus (teilweise, noch schlechte Fototechnik))
- von der Soundkarte
- über den ADC vom MSP430F2013 ( 4fach gemessen Mittelwert )
- zu einem zweiten µP (Propeller) (Quarz, triggern ++)
- über RS232 zum PC
- über VB6 auf den Monitor

Aber wenn Du möchtest, Warum?

Dirk

von Dirk (Gast)


Lesenswert?

Hallo  Uhu Uhuhu,

habe nochmal über Deine 'Frage' nachgedacht.
Die Frage die Du gestellt hast hilft mir nicht weiter!
Es ist keinerlei Tip/Hinweis vorhanden. z.B PDF, Stichworte, usw.


All_so hast DU die Frage für DICH gestellt,
und möchtest mich als Bühne benutzen.

Du liest mindestens einen Teil des Hin und Hers,
verschenkst all_so doch schon eine Menge Zeit.
Aber warum, dann keinen kleinen Tip?

Einen moralischen Zeigefinger,
oder überholte Lernmodele helfen nicht bei mir.
Ich bin alt und auch noch stur.


Mir soll das ganze auch freude machen, und ich erwarte von keinem
das er den Code für mich schreibt.

Leider sind die moderen Themen erstaunlich komplex
und als Anfänger bzw. Hobby-Erfinder ist es schon ein hartes Brot, und
den einen oder andern Tip, auch unverdient(unberechtigt) währe nicht nur 
eine schöne Geste.

Ich bin schon sooooft gegen die Wand gelaufen,
das ich das Lernmodel nicht mehr unterstützen möchte.

Wenn DU eine Frage hast, würde ich Dir gerne weiterhelfen.
Leider bin ich noch nicht Fit, und viele Unklarheiten schränken das
ein, was ich schon gefunden habe.


All_so, warum?
Dirk

von Joe (Gast)


Lesenswert?

>> Die Werte bei einer Gleichspannung springen bei mir sehr.

Sag mal, wie sehr springt denn der Wert ? ich habe arge Zweifel das ne 
4fach Messung das schon beseitigt.

Ich hab mir mal die Zähne dran ausgebissen. Der F2013 hat in der 
Hinsicht ein paar Tücken.

Du solltest die VREF abblocken (siehe Datenblatt), die VREF muß zu 
diesem Zweck auf den Ausgang geschaltet werden.

P1SEL_bit.P1SEL_3 = 1;     // Referenz auf den Ausgang

Dann Errata Sheets lesen (center 1,2V temp. drift 50ppm/K), hier mußt du 
einen Korrektur Wert (0xBF) schreiben.

Der ADC IN- gehört an Masse (du verwendest ja den unipolaren Modus.

Dann kannst du mit den Filtern mal experimentieren (OSR=1024 ergibt bei 
mir die besten Ergebnisse).

Hardware, Layout, 16 BIT bei einer Eingangsspg. von 0 - 0,6 V, rechne 
das mal aus. Wenn du dir große Mühe gibst dann holst du stabile 15 BIT 
heraus (128 Mittelwerte vorraus gesetzt).

Es gibt also noch ein paar Denksportausgaben.

von Dirk (Gast)


Lesenswert?

Hallo Joe, erstmal vielen Dank!

Denksport mit Aussichten finde ich gut.

Also, mit einem selbstgebauten VB6 Ozi (200Messungen/sec.)
hatte ich den optischen Eindruck das sich das Springen ungefähr halbiert 
hat.
Wahrscheinlich gibt es noch irgendwelche Störungsignale im System und
es liegt noch nicht am ADC.

Danke,
mit den meisten Tips werde ich klarkommen,
auch die Art ist fein für mich.

Aber leider geht es erst am Wochenende weiter für mich.

Frage:
- viele Wandlungen/sec. schafft er den.
  Habe keine Angaben für den F2013 gefunden.
  (Ich bin mal auf 3000 in zwei Sec. gewessen,
   aber da gab es noch mehrere Fehler
   bei meinen Frequenzeinstellungen und im gesammten Wechselspiel)




// Zur Zeit habe ich das, kann natürlich erweitert werden 
........................

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
  P1IFG &= ~0x10;            // P1.4 IFG cleared
  P1OUT |= 0x20;             // Data 'H'   => warten auf ADC_Wert
  OVS=3;           // Public  oversampling + 1
  ADC_Wert=0;         // Public

  SD16CCTL0 |= SD16SC;       // Set bit to start conversion ADC
}


#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
  ADC_Wert += SD16MEM0;
  OVS=OVS-1;

  if (OVS==0)
   {
     ADC_Wert=ADC_Wert/4;   // OVS +1
     ADCWert_Senden ();
   }
   else
   {
     SD16CCTL0 |= SD16SC;       // Set bit to start conversion ADC
   }
}

von Uhu U. (uhu)


Lesenswert?

Hallo Dirk,

> All_so hast DU die Frage für DICH gestellt,
> und möchtest mich als Bühne benutzen.

Beileibe nicht.

Ich findes es gut, daß Du das Problem selbst gelöst hast. Nicht gut 
finde ich, daß Du offenbar nur rumprobiert hast, ohne zu wissen, was Du 
tust.

Was macht volatile und warum mault der Compiler

  [Pa082]: undefined behavior: the order of volatile accesses is
           undefined

wenn Du

    Wert = Wert1 + Wert2 + Wert3 + Wert4;

schreibst und die Wert<n> vom Typ volatile unsigned long sind - das ist 
doch die Frage, die Du Dir hier stellen müßtest.

Also, hier ist die Erklärung:

Volatile sagt dem Compiler, daß sich der Inhalt der Variablen zu jeder 
Zeit ändern kann - z.B. durch eine Interrupt-Service-Routine. Der 
Compiler lädt deshalb volatile-Variable vor jedem Gebrauch neu und hält 
sie nicht in einem Register (was den Code meistens aufbläht, deswegen 
sollte man volatile nur benutzen, wenn es wirklich so ist).

Aber warum resultiert aus einer Addition von volatile-Variablen 
undefiniertes Verhalten?

Ganz einfach: Per Definition werden in C Ausdrücke von links nach rechts 
abgearbeitet - natürlich unter Berücksichtigung der 'Vorfahrtregeln'.

Bei volatile Variablen hat der Compiler die Freiheit, die Reihenfolge 
der Ladeoperationen anders als von links nach rechts anzuordnen und da 
er solche Variable nicht in einem Register halten kann - die Urkopie 
kann sich ja jederzeit ändern - ist Abarbeitung von links nach rechts 
nicht mehr garantiert. Deshalb die Warnung.

Angenommen, man schreibt folgende Anweisung:

    Wert = Wert1 + Wert1 + Wert2 + Wert1;

und Wert1 ändert sich zufällig in dem Moment, wo Wert2 dazuaddiert wird, 
dann kommt u.U. ein falsches Ergebnis heraus und die Ursache solcher 
Fehler ist sehr schwer zufinden, weil sie nur sporadisch auftreten ohne 
Kausalzusammenhang mit dem Code, in dem sie auftreten und sehr schnell 
ablaufen. Per Einzelschritt im Debugger kann man sie nicht finden.

von Dirk (Gast)


Lesenswert?

Hallo Uhu Uhuhu,

mit der 'Bühne',
da sind mir die Pferde durchgegangen und noch nicht mal wegen Dir.
Und das Du mir trotzdem antwortest finde ich gut.
Und der Inhalt der Antwort hat es in sich. Ist mir nun klarer geworden.

Die definition Veränderung kamm erst wirklich ganz am Ende und eher aus 
purem frust.
Da hatte ich schon eine Menge Gegoogelt, wegen 'C', alle Beispiele
durchsucht und konnte es nicht fassen wieso eine solche Zeile bei mir 
nicht
laufen sollte.
Die definition 'volatile unsigned' hatte ich aus einem Beispiel copiert,
und hatte sowas im Kopf, das in der Einzelschrittsteuerung auch dieser 
Wert
geprüft werden kann. (irgendwo angelesen und nicht verdaut).

Das sind meine ersten Begegnungen mit 'C'und 'Spin' und µP.

Das die Interrupt-Service-Routine mit dem µP-Clock gesteuert werden und 
somit jede
Code Zeile trennen können ist mir erst jetzt bewuster geworden.

Möglicherweise habe ich noch so ein duzent halbgare geschichten,
die alles irgendwie zäh werden lassen.

Im Simulationsbetrieb geht er nicht in die Interrupts
rein obwohl ich sie von Hand auslöse.
Fehlt eine Einstellung oder habe ich ein Denkfehler.

Ich habe den 2013 aus dem USB-Stick rausgenommen, mit zwei Drähten 
verbunden.
(externe Stromversorgung)
- programmieren kann ich ihn
- das Prog. bleibt auch drin
aber ich muß immer erst den Stick wieder einstecken, damit das Program 
startet.
Dannach kann ich ihn wieder raus ziehen und es läuft
weiter bis zum Abschalten der Stromversorgung

Zu beiden Geschichten habe ich noch nichts in den PDFs gefunden.




Vielen Dank Uhu (Uhuhu)

(muß nun arbeiten)
Dirk

von Joe (Gast)


Lesenswert?

>> aber ich muß immer erst den Stick wieder einstecken, damit das Program
>> startet.

Schau dir mal die Resetbeschaltung an, hängt dein Reset (wenn nicht mit 
dem Stick verbunden) in der Luft ?

Ich werde mir morgen (im Moment keine Zeit) deinen Thread noch mal 
vornehmen und die Tipps ausformulieren.

Viel Erfolg bis dahin.

von Uhu U. (uhu)


Lesenswert?

> Schau dir mal die Resetbeschaltung an, hängt dein Reset (wenn nicht
> mit dem Stick verbunden) in der Luft ?

Darauf würde ich auch tippen - ich hatte das Problem auch schon.

von Dirk (Gast)


Lesenswert?

Hallo Joe,
Hallo Uhu Uhuhu,

mir war heute nicht so gut auf der Arbeit, also bin ich wieder vor der 
Schaltung.
Muß das morgen nacharbeiten.

All_so nun zum guten Teil des Tages:
Lötstift 10 oder der Zweite von rechts von den 4 Stiften des 
USB-Steckers.

Es stimmt kurzer Reset-Impuls. Bei mir muß auch die RS-Schnittstelle
neu geöffnet werden. Beides zusammen wirkt.
Habe zwar die RS entkoppelt, aber irgendwie haut sie noch durch.

Mein anderer µP hat einen Autoreset, wenn Spannung angelegt wird.
Ist schon witzig.

In Endaufbau heißt es dann  + Widerstand nach C nach Masse,
zwischen Wiederstand und Masse, dann den Reset.
(Plus >---###--x--||--> Masse
               |
               | => Reset Lötstift 10



Ich habe den Träger rausgenommen, und mit 2Ltg (Löt 10/11)
zum Programmieren an den kleine Stecker des USB-Stickes gelötet(hatte 
keinen so kleinen Stecker).
Alle andern(12) habe ich auf eine Lötleiste gelegt,
von da gehe ich zum Demoboard des Propellers(- +  I/Os ).
Hierdurch ist mir die dop. Belegung entgangen bzw. habe auch keinen 
Reset erwartet.

Hallo Joe,
ist zwar eine sehr schöne Idee, aber bis morgen wird sich sehr viel im 
Prg verändert haben
oder ich stehe wieder heulend auf der Matte.


Vielen Dank, die Liste wird kürzer,

was kann ich für euch tun?
Dirk

von Uhu U. (uhu)


Lesenswert?

Hallo Dirk,

sei mir nicht böse, aber mit 'Was kann ich für Sie tun?' assoziiere ich
immer Telekom etc. und Dienst nach Vorschrift... kotz, würg.

Ich hab noch einen kleinen Nachtrag zum Thema volatile:

volatile long ist auf dem MSP430 richtiggehend gemeingefährlich:

Der Prozessor ist 16 bit breit, die long-Typen 32.

Wenn auf ein volatile long zugegriffen werden soll, dann sind dafür zwei
Maschinenbefehle notwendig.

Angenommen, Du hast einen Inkremantalgeber, der zwischen -1 und 0
herumdümpelt, dann wechselt der Wert zwischen 0xffffffff und 0x00000000.

Wenn es der Zufall will, daß der Wechsel der Variablen genau nach dem
Zugriff auf ein Teilwort stattfindet, dann rechnet der Prozessor
plötzlich nicht mit 0xffffffff oder 0x00000000, sondern mit 0xffff0000
oder 0x0000ffff - ein Wort stammt vom vorherigen Wert, eins vom
aktuellen.

Auf dem MSP430 muß man deshalb vor dem Zugriff auf ein volatile long die
Interrupts sperren.


Warum verwendest Du eigentlich für ADC_Wert ein long? Der ADC des 2013
liefert 16 Bit, da reicht ein int-Typ aus.

von Dirk (Gast)


Lesenswert?

Hallo Uhu Uhuhu,

Ich habe nach Public gesucht in den Beispielen
und dann copiert.

Dann bei dem 4fach Messen war es einfach, erst addieren dann teilen.
Und eine Gefahr war nicht in Sicht.

Leider hat sich grade die ganze Schaltung verabschiedet.

Muste einiges umlöten.

Habe von SD16INCH_1 nach SD16INCH_4 umgearbeitet damit ich die
Ref auf  P1.3 legen kann (P1SEL=0x08?).
Hatte zwar mit den Fingern gute Anzeige, aber ansonst lief weder 
Rechteck noch Audiokarte gegen Masse.
Bei dem ganzen gelöte, umprogrammieren und
C an Ref legen usw. habe ich wohl einen hochgeladen Kondensator an +/- 
3,3V angeschlossen.
Das hat sich wohl durchgefressen bis in Spannungsstabilisierung.

Der Msp ist Ok, kleiner Test nur über USB (klein, zäh und tapfer).

Die Spannungsstabilisierung ist hin,
den Propeller kann ich noch nicht testen.

Warscheinlich muß ich jetzt am Sonntag mit zum Spaziergang
durch das grüne Zeug.

Wünsche euch ein schönes Wochenende

Dirk

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.