Forum: Mikrocontroller und Digitale Elektronik RMS über 8192 Werte auf MSPF149 sehr langsam


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


Lesenswert?

Hi Leute,

ich hab mir ein kleines Programm geschrieben das mir den RMS über 8192 
Werte in der Sekunde berechnen sollte.

Jetzt dauert die Berechnung insgesamt ca. 5 Sekunden ist das normal?

Also wenn ich die Wurzelfunktion draussen lass verändert sich nichts 
spürbar, bei der Multiplikation gewinne ich ca. 2 Sekunden.
Der msp430 hat doch ein Hard. Multiplier das sollte doch raz faz gehen.
Ich seh jetzt nicht ganz den Zeitfresser?

Der Timer A3 hat ja eine niedrigere Priorität wie der ADC12, deshalb 
arbeitet der auch alles ab was im ADC gemacht werden soll.

Bin etwas ratlos, kann mir vll. jemand ein tip geben woran das liegen 
kann?
1
unsigned int RMS_SIG1;
2
unsigned long long int SUM_SIG1;
3
4
#pragma vector=TIMERA0_VECTOR
5
__interrupt void Timer_A (void)
6
{
7
  i++;
8
  P4OUT ^= 0xFF;                            // Toggle P1.0
9
  P6SEL |= 0x70;                            // Enable A/D channel A0
10
  ADC12CTL0 = ADC12ON+SHT0_0+MSC;           // Turn on ADC12, set sampling time
11
  ADC12CTL1 = SHP+CONSEQ_1;                 // Use sampling timer, set mode
12
  ADC12MCTL0 = INCH_4+SREF_0;               // channel = A4
13
  ADC12MCTL1 = INCH_5+SREF_0;               // channel = A5
14
  ADC12MCTL2 = INCH_6+EOS+SREF_0;           // channel = A6
15
  ADC12IE = 0x01;                           // Enable ADC12IFG.6
16
  //ADC12MCTL0 = EOS+INCH_0+SREF_0;
17
  ADC12CTL0 |= ENC;                         // Enable conversions
18
  ADC12CTL0 |= ADC12SC;                     // Start conversion
19
20
}
21
22
#pragma vector=ADC12_VECTOR
23
__interrupt void ADC12ISR (void)
24
{
25
  unsigned long int MW_SIG1,ADC_SIG1;
26
27
  
28
  if(i<8192){
29
    ADC_SIG1=ADC12MEM0;
30
    ADC_SIG1*=ADC_SIG1;                        //Quadrat
31
    SUM_SIG1=SUM_SIG1+ADC_SIG1;                //Summe
32
    j++;                                    //counter of ADC conversions
33
  }else{
34
    MW_SIG1=SUM_SIG1/j;                     //Mean of RMS
35
    RMS_SIG1=julery_isqrt(MW_SIG1);         //sqrt of RMS
36
    SUM_SIG1=0;
37
38
    i=0;
39
    j=0;
40
  }
41
   ADC12CTL0 &= ~ENC;                         // Enable conversions
42
}

von Christian R. (supachris)


Lesenswert?

Naja, die Frage ist, ob der Kompiler automatisch den HW-Mult 
benutzt....das solltest du anhand des Assembler-Listings oder der 
Kompiler-Optionen erst mal prüfen.

Das Teilen durch j ist natürlich auch ein Zeitfresser....

von Karl H. (kbuchegg)


Lesenswert?

Fabian Hof schrieb:

> Also wenn ich die Wurzelfunktion draussen lass verändert sich nichts
> spürbar, bei der Multiplikation gewinne ich ca. 2 Sekunden.

?
Hast du den Optimizer eingeschaltet.
Das kann ich mir nur schwer vorstellen, dass tatsächlich das bischen 
Rechnerei bei einem ADC Ergebnis so dermassen zeitbestimmend sein soll.

Hast du vielleicht noch andere, höher priorisierte Interrupts am laufen, 
die dem ADC Interrupt keine oder kaum Rechenzeit übrig lassen?

von Martin (Gast)


Lesenswert?

Hier 'MW_SIG1=SUM_SIG1/j;' besser eine Shiftanweisung verwenden.

MW_SIG1 = SUM_SIG1 >> 13 ;

Controller zu langsam getaktet?

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


Lesenswert?

Hi,

so hab mal bitshift reingemacht, hätte ich auch selber drauf kommen 
können. Geht soweit auch ohne Probleme.

Zum Thema Hardware Multiplier, wenn mir einer genau sagt wie ich das 
einstell bei der IAR Workbench mach ich das rein. Ich hab halt gelesen 
das er den automatischbenutz sofern es möglich ist.
Hier mal der Assembler-COde für die Multiplikation
1
ADC_SIG1*=ADC_SIG1 //Quadrat
2
3
mov.w R6,R12
4
mov.w R7,R13
5
mov.w R6,R14
6
mov.w R7,R15
7
call #?Mul32HW
8
mov.w R12,R6
9
mov.w R13,R7

Kommt mir komisch vor im Usergiude von TI zum F149 steht was von
1
16x16 Unsigned Multiply Accumulate
2
MOV #01234h,&MAC ; Load first operand
3
MOV #05678h,&OP2 ; Load 2nd operand
davon ist nichts zu finden.

Zum Thema Interrupts:
Ich hab nur die beiden Interrupts die ihr oben in meinem ersten Poste 
seht laufen. Also sollte mir da nicht reinhageln.

Thema Takt:
Also ich muss sagen da hab ich garnichts eingestellt, ich bin davon 
ausgegangen, das er automatisch auf 5 Mhz läuft bzw.
Wie kann ich mir nochmal MCLK auf PIN5.4 anschauen?
Stimmt das so?
1
P5SEL |= 0xFF;

Jetzt hab ich auf MCLK und SMCLK 1,5MHZ.

von Martin (Gast)


Lesenswert?

... call #?Mul32HW ...

Diese Routine könnte der Knackpunkt sein, dahinter ist u. U. eine 
längeres Programm verborgen. Poste doch mal die Routine.

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


Lesenswert?

1
?Mul32Hw
2
3
push.w SR
4
dint
5
nop
6
mov.w R12,&MPY
7
mov.w R14,&OP2
8
mov.w  R12,&MAC
9
mov.w &RESLO,R12
10
mov.w &RESHI, &RESLO
11
mov.w R15,&OP2
12
mov.w R13,&MAC
13
mov.w R14,&OP2
14
mov.w &RESLO,R13
15
reti

Sieht nach HW multiplizierer aus also, da hab ich kein Zweifel.

Kann ich mir in der IAR genau anzeigen lassen wieviel Zeit eine 
Operation verschlingt? Dann könnte man das mal eingrenzen.

Beibt wohl nur noch den Takt Hochzusetzen auf 5 MHZ dann sollte ich 
Faktor 3 gewinnen.

von Ferkel (Gast)


Lesenswert?

>  unsigned long int MW_SIG1,ADC_SIG1;

eine 16-Bit MUL kann nur dann verwendet werden, wenn die Variable auch 
16-Bit breit ist. Du definierst aber ADC_SIG1 als unsinged long.

>#?Mul32HW

Diese Routine steht in einer .lib. Die Quelle dürfte verborgen sein :-(

von Christian R. (supachris)


Lesenswert?

Wenn du am DCO nix änderst, läuft der mit irgendeiner Standard-Frequenz, 
die im Datenblatt steht. Aber ADC Messungen mit dem DCO...naja, würd ich 
nicht machen, das ist ein relativ instabilder RC-Oszillator. Wenn du die 
Betriebsspannung auf 3,6V anhebst, kannst du einen 8MHz Quarz 
anschließen. Bei 3,3V gehts bis 7,4MHz stabil.
Ansonsten scheint er ja den HW Mult zu benutzen.

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


Lesenswert?

Der ADC wir von einem externen 32kHz Quarz getacktet also DCO kann ich 
beliebig wählen.
Hat wer vll. die einstellungen für maximalen Takt vom F149 ?

von Christian R. (supachris)


Lesenswert?

Aus den Code-Beispielen von TI:
1
DCOCTL = DCO0 + DCO1 + DCO2;              // Max DCO

von Stefan (Gast)


Lesenswert?

Christian R. schrieb:
> Aus den Code-Beispielen von TI:
> DCOCTL = DCO0 + DCO1 + DCO2;              // Max DCO

Naja...
ein zusätzliches
1
BCSCTL1 |= RSEL0 + RSEL1 + RSEL2;
wär vielleicht auch nicht schlecht ;-)

von Guest (Gast)


Lesenswert?

Kann es sein, dass deine RMS deshalb so lange braucht, weil du den ADC 
mit 32KHz taktest, der ist normalerweise mit 5MHz spezifiziert.

von Christian R. (supachris)


Lesenswert?

Hehe, wieder mal nur eine Zeile erwischt beim Copy-Paste ;)
Das sorgt doch immer noch für die schönsten Effekte beim 
"Programmieren".

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


Angehängte Dateien:

Lesenswert?

Top! Hab jetzt mal sichergestellt das der CLock auf  ~4.6Mhz und den ADC 
betreib ich jetzt mit ADC12OSC, das sollte ja der maximale sein.

Aber mal eine Frage:
Wenn ich die MIttelwertbildung und das Wurzelziehen im Main mache sollte 
ich doch keine Probleme bekommen, ausser natürlich das dauert länger als 
das meine 8192 Abtastwerte voll sind oder?
Das hab ich jetzt mal so versucht, siehe Anhang.

Leider springt er mir die while nie wieder an ausser beim ersten Aufruf, 
hat einer eine Idee warum?

Langsam krieg ich totes Hirn, für heute.

von Stefan (Gast)


Lesenswert?

Du musst bei Measure==1 in der ISR ja auch LPM0 deaktivieren, damit er 
überhaupt in main hupfen kann

von Peter D. (peda)


Lesenswert?

Wenn das long long genauso implementiert ist, wie beim AVR-GCC, dann ist 
es schneckenlahm. Da ist sogar float noch besser.

Am besten, Du bastelst Dir das long long aus 2 uint32_t selber.



Peter

von Ferkel (Gast)


Lesenswert?

>Wenn das long long genauso implementiert ist, wie beim AVR-GCC, dann ist
>es schneckenlahm. Da ist sogar float noch besser.

Darum geht es doch garnicht. Offensichtlich muß nur der ADC schneller 
laufen, damit die CPU schneller rechnet :-)

von Falk B. (falk)


Lesenswert?

Kann man leicht messen. Am Anfang der ISR ein Pin auf High setzen, am am 
Ende auf LOW. Oszi dran, messen. Dann sieht man,

den Abstand der Pulse = ADC Wandlertakt.
Die Breite der Pulse. Rechenzeit in der ISR
Das Tastverhältnis = CPU -Auslastung

MfG
Falk

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Der Hardwaremultiplizierer kann nur maximal 16 bit x 16 bit berechnen.
ADC_SIG1 ist unsigned long int und daher 32 bit breit (oder ist das beim 
IAR Compiler anders?).

ADC_SIG1=ADC12MEM0;
ADC_SIG1*=ADC_SIG1;                        //Quadrat
SUM_SIG1=SUM_SIG1+ADC_SIG1;                //Summe

Das würde ich so schreiben:

SUM_SIG1 += ADC12MEM0 * ADC12MEM0;

Was ist das eigentlich für eine umständliche Vorgehensweise mit dem i 
und j? Letztenendes will man doch samples zählen, das macht man am 
einfachsten direkt im ADC-Interrupt.

Wofür zählt j mit, der Wert, den es bei der Auswertung haben wird, ist 
doch zur Compilezeit bekannt (8192)?


Grüße,

Peter

von Fabian Hof (Gast)


Lesenswert?

Hi tip von Stefan mit LPM0 deaktivieren hat gepasst.
Klar kann er auch 32 bit mit dem HW Multiplier machen nur nicht auf 
einmal. Aber die ganze Sache läuft jetzt auch soweit so gut.

Peter das j war noch aus einer früheren Version, ist natürlich bekannt 
und mitlerweile auch verschwunden.
Ausserdem sollte man ADC_SIG1=ADC12MEM0; und dann SUM_SIG1 += ADC_SIG1 * 
ADC_SIG1; machen sonst kommt ein volatile warning.

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.