Hallo,
ich habe (wieder Mal) ein kleines Problemchen mit dem MSP430F612, bzw.
mit dessen Programmierung:
Software ist wie immer die IAR 3.21A
Sprache: C
Ich möchte eine LookUpTable erstellen, die meine Messwerte enthält.
Das Programm ist jetzt erstmal nur zum Testen.
Ich habe an zwei ADC12-Kanälen 2 verschiedene Spannungen dran.
Die Referenz ist 2,5V (interne Ref) und Vdd.
Jetzt möchte ich nur mal testweise eine LUT erstellen, die 4096 Werte
enthält, die die Millivolt darstellen sollen.
Ich möchte dann je nach Wandlerwert in die LUT reingehen, und die
Spannung raussuchen lassen...
Wenn ich die LUT 2000 Elemente lang mache, dann geht es.
Wir die LUT allerdings länger als 2045, dann bleibt der Debugger an der
Stelle hängen, die auf dem Bild zu sehen ist.
Die LUT wird dann NICHT gefüllt.
Das ist natürlich etwas ungünstig, weil ich ja 4096 Werte in der LUT
haben muss.
Hier mal der Code:
1
#include<msp430x16x.h>
2
voidfill_LUT(void);
3
WORDLUT[2055];
4
5
voidmain()
6
{
7
WDTCTL=WDTPW+WDTHOLD;// Stop watchdog timer
8
9
fill_LUT();// füllen der LookUpTable
10
11
for(;;)
12
{
13
_NOP();
14
}
15
}// ende main
16
17
voidfill_LUT(void)
18
{
19
for(shortj=0;j<2055;j++)
20
{
21
// WORD ist unsigned short, also 2 bytes
22
LUT[j]=(WORD)(j*2500.0/4096.0);
23
}
24
}
Ich habe den Kram mit der Wandlung und so mal alles rausgenommen.
Das komische ist aber auch, dass, wenn ich mein "richtiges" Programm
nehme,
und dann die LUT 4096 lang machen möchte, zeigt er mir folgenden Fehler:
Was ist das für ein Fehler? Was kann ich da machen?
Hat einer Rat?
Bzw. wie erstelle ich auf dem MSP430F1612 eine LUT mit 4096 Elementen?
Dankeschön!
mathias
@ Mathias U. (munter)
>Ich möchte eine LookUpTable erstellen, die meine Messwerte enthält.
Das ist aber keine LUT, denn die ist eigentlich konstant. Du willst
einen Puffer für deine Messwerte.
>Ich möchte dann je nach Wandlerwert in die LUT reingehen, und die>Spannung raussuchen lassen...
Warum das? Musst du soooo schnell wandeln? Eine Umrechnung per Funktion
ist WSENTLICH sparsamer im RAMverbrauch.
>Wenn ich die LUT 2000 Elemente lang mache, dann geht es.
Das sind bei 2 Byte/Element bereit 4000 Byte.
>Das komische ist aber auch, dass, wenn ich mein "richtiges" Programm>nehme,und dann die LUT 4096 lang machen möchte, zeigt er mir folgenden Fehler:
Wer des Englischen halbwegs mächtig ist erkennt, dass da irgendwas zu
gross ist. Dein Array?
MfG
Falk
Gut, dass ist mir zwar klar, bringt mich aber zu der Erkenntnis, dass
ich die LUT sicher nicht im RAM, sondern doch eher im Flash abspeichern
sollte... ;-)
Davon hat er jetzt 55kB.
Wie ich da rangehe, weiss ich zwar *noch nicht, aber evtl. hat ja einer
noch solch einen genialen Einfall! (Das mit dem Ram war wirklich ein
Wink mit dem Pfahl, der gewirkt hat!)
*edit @falk: arrg, falsch ausgedrückt! Die LUT soll nicht die Messwerte
enthalten!
Es soll wirklich schon eine richtige LUT sein.
Also quasi: Ich bekomme einen Wandlerwert. Dieser Wandlerwert
repräsentiert eine Spannung. Diese Spannung steht in der LUT. Mit dem
Wandlerwert gehe ich in die LUT und hole mir die Spannung raus...
Die Spannungen in der LUT sind jetzt erstmal nur zum testen! In meiner
richtigen LUT stehen dann dB-Werte drin...
Und ich denke, dann spare ich schon Rechenzeit, weil ich die ja dann
nicht jedesmal neu berechnen muss
mathias
@ Mathias U. (munter)
>Die Spannungen in der LUT sind jetzt erstmal nur zum testen! In meiner>richtigen LUT stehen dann dB-Werte drin...
Das kann man auch berechnen.
>Und ich denke, dann spare ich schon Rechenzeit, weil ich die ja dann>nicht jedesmal neu berechnen muss
Sicher, aber wieviele Wandlungen pro Sekunde willst du denn machen?
MFG
Falk
P.S. Wie man ein Array beim MSP430 in den Flash verlegt weiss ich jetzt
auch nicht.
Legst du dir die LUT in den FLASH-Speicher.
Dann hast du bei deiner Füllerei allerdings ganz schönen Blödsinn
drinne:
1
LUT[j]=(WORD)(j*2500.0/4096.0);
Was soll denn das bedeuten? Das sind ja dann irgendwie Float-Zahlen, die
der Compiler erst ma umrechnet....
Da du aber die LUT im Flash haben willst, geht das so schon mal sowieso
nicht.
du musst die LUT gleich bei der Deklaration füllen:
1
constWORDLUT[5]={100,256,2035,0,4};
Mal als Beispiel für eine 5 Worte große LUT.
Bist du sicher, dass eine Berechnung viel länger dauern würde? Wie
schnell tastest du denn ab? Mit einer 2 oder 3 stufigen Näherung kannst
du ziemlich schnell und relativ genau auch solche Potenzen ausrechnen.
Mathematik II: Reihenentwicklung.
Dann noch den Hardware-Multiplizierer benutzt, am besten in der MACS
Betriebsart, und du kommst rasend schnell zu deinem Ergebnis ohne massig
Speicherplatz-bedarf.
Allerdings ist da der Einsatz des Gehirnes mehr gefordert.....
Falk Brunner wrote:
> Das kann man auch berechnen.> ...> Sicher, aber wieviele Wandlungen pro Sekunde willst du denn machen?
Sicher kann man das auch berechnen, aber ich möchte jetzt mal eine LUT
erstellen. (auch zum Lernen!)
Ob das an dieser Stelle nötig oder sinnvoll ist, sei mal dahigestellt.
Aber ich finde es schon sinnvoll, lieber ein Array EINMAL zu füllen, als
bei jedem neuen Wandlerwert meine Werte zu berechnen ( log10,
Potenzieren...).
Da glaube ich, ist es einfacher den MSP mal schnell in einer Tabelle
nachschauen zu lassen...
Wandeln möchte ich dann alle 125ms also 8* pro sek..
Wie man ein solches Array jetzt in den Flash reinkriegt wäre die Lösung.
Aber ich weiss halt auch noch nicht genau wie...bin halt Anfänger.
Hat einer ne Idee?
danke
@ Mathias U. (munter)
>Sicher kann man das auch berechnen, aber ich möchte jetzt mal eine LUT>erstellen. (auch zum Lernen!)
OK.
>Wie man ein solches Array jetzt in den Flash reinkriegt wäre die Lösung.>Aber ich weiss halt auch noch nicht genau wie...bin halt Anfänger.
Siehe das letzte Posting von Christian R.
Die Werte brechnet man sinnvollerweise mit Excel und lässt sich am
besten per Makro den Quelltext erzeugen.
MFG
Falk
Lies doch mal mein Posting. Da steht doch alles drin.
Außerdem musst DU das Array füllen, wenn´s im Flash ist. Nicht der
Compiler und nicht der MSP430. Die Werte müssen alle zur Kompilierzeit
bekannt und konstant sein.
Warum soll ein Compiler nicht die Konstanten ausrechnen können?
Das kann ja schon jeder doofe^H^H^H^H^Hbessere Assembler.
timfrq set 80000000.0/2.0/@cvf(timcnt)
Fs set 1000.0*@cvf(smplrt)/@cvf(lfos)/@cvf(skipcnt)
msg 'timfrq:',timfrq,' Fs:',Fs
;Specify sampling frequency.
PI set 2.0*@asn(1.0) ;Compute PI as 2.0*arcsin(1.0)
factor set PI/180.0 ;Multiplier for degrees to radians
s_coef macro f
_freq set
@pow(lfomax/lfomin,@cvf((f/phases)*phases)/@cvf(lfos-1))*lfomin
@ Klugscheisser (Gast)
>Warum soll ein Compiler nicht die Konstanten ausrechnen können?>Das kann ja schon jeder doofe^H^H^H^H^Hbessere Assembler.
Na dann scheib mal ein paar Makros für den C-Compiler zu DIESEM Problem.
MfG
Falk
Danke Christian & Falk.
Hab da smit der LUT jetzt mal so gemacht.
Hab sie selber initialisiert...war etwas tricky, da ich mich mit Makros
in Excel nicht auskenne, aber es geht jetzt!
Danke
Hallo,
zunächst ist mal zu überlegen, was Dir eine LUT bringen soll. Wenn
tatsächlich keine Berechnung (sondern nur noch ein Vergleichen)
stattfinden soll, dann benötigst Du sehr viele Werte in der LUT. Wenn Du
damit nur eine Nichtlinearität ausgleichen willst, kommt man ggf. mit
weniger Werten aus, das erfordert dann aber nach dem Auslesen der
benachbarten LUT-Werte noch eine Interpolationsrechnung.
LUT hat gegenüber Berechnung schon Vorteile, vor allem, wenn man per
Abgleichdaten Werte in der LUT beeinflussen möchte. Aber gerade wenn die
o. g. Interpolation nötig ist, muss man sich überlegen, ob eine laufende
Berechnung nicht genauso den Zweck erfüllt. Nur um einen Prop.-Faktor zu
ersetzen, dafür setzt kein Mensch eine LUT ein.
Gruß
Dieter
Also generel ist es möglich werte während des Betreibs in den Flash zu
schreiben. es ist zwar etwas hakelig da dazu der Prozessor aus sein
muss, du due richtige Schreibfrequenz brauchst, du aufpassenmaust das du
nicht grad den bereich beschreibst wo dein Programm drin ist ... .
aber generell ist es möglich. Für welchen zwek auch immer
Hallo, ich muss nochmal was zur Effektivität von LUT's fragen.
Hier mal ein einfaches Beispiel. Ich möchte einfach nur einen Wert auf
der als linear angenommenen Wandlerkennlinie des MSP ermitteln.
Das kann ich ja einmal über die lineare Formel machen, oder halt die
Werte in einer LUT ablegen.
Ich denke, hier bringt die Anwendung einer LUT nicht so wahnsinnig viel,
richtig?
Mal abgesehen davon, dass ich ja die ganzen Multiplikationen auf dem
MSPF1612 hardware-mäßig machen könnte.
wert = lut_1[adcwert];
oder
wert = 100*(anstieg*adcwert + y_schnitt);
Aber wie sieht die Sache beim Potenzieren aus?
Die beiden Varianten machen unten das gleiche. Aber welche Version wird
effektiver sein?
In der LUT stehen die Werte drin, die halt mit pow(...) berechnet
werden.
summe_wert = summe_wert + lut_pow[(wert-6640)/10];
oder
summe_wert = summe_wert + pow(10, (0.001*wert));
Bringt an dieser Stelle eine LUT was, oder ist die Berechnung
unwesentlich langsamer?
Also der Quellcode soll jetzt nur die grundsätzliche Funktion
darstellen...
Hiho,
also bei float-Operationen ohne HW-Multiplizierer bringen die LUT's
schon etwas, denke ich. Kommt halt auf die Funktion an.
Miss doch einfach mal die Laufzeiten mit LUT und Bibliotheksfunktion und
vergleiche. Bei pow wird sich da ein signifikanter Unterschied ergeben.
Wenn ich mich dunkel entsinne, dauert eine float-Division über die
Bibliothek bei einem MSP430F1232 (hat keine HW-Multiplizierer) mit 5MHz
CPU-Clock (MCLK) einige 100µs.
Für eine Gerade brauchst du keine LUT - das geht mit der
Geradengleichung genausogut - die lineare Interpolation, die du zwischen
den Punkten machen mußt, ist letztlich nichts anderes, als die
Berechnung einer Geraden.
Wenn du allerdings potenzieren mußt, sieht es anders aus. Da lohnt sie
sich mit Sicherheit. Du mußt nur den Abstand der Stützpunkte so wählen,
daß der maximal tolerierbare Fehler nicht überschritten wird. Die
Zwischenwerte zwischen den Stützpunkten berechnest du dann mit linearer
Interpolation.
Auch solltest du dir überlegen, ob sich das Problem mit vertretbarem
Aufwand mit skalierter Integerarithmetik lösen läßt.
Ein schönes Werkzeug, um solche Probleme zu untersuchen, ist Maxima.
Hallo, ich habe jetzt mal die Laufzeiten gemessen, die die Funktionen
und das "Nachschauen" in der Lut brauchen...
Es kommt mir etwas komisch vor, oder ich versteh die Angaben einfach nur
nicht...
hier mal mein Programm:
Folgendes passiert:
Ich rufe die jeweiligen Funktionen auf, die entweder in der LUT
nachsehen, oder den gewünschten Wert berechnen.
Bei den auskommentierten Sachen handelt es sich um die Realisierung OHNE
explititen Aufruf einer Funktion.
Aber für das Profiling brauche Ich ja Funktionen.
Hier mal die Angaben, die mir das Profiling ausgeben, einiges wurde
entfernt:
1
Profilinginformation
2
3
Flat%Acc.%CallsFunction
4
TimeTime
5
6
00.0000.000Outsidemain
7
8
130.03130.031linear_lut
9
60.024211.061linear_normal
10
11
2010.512010.511pow_lut
12
60.021182329.711pow_normal
13
14
00.0000.000wait
Was ist denn die "Flat-Time" genau?
Die "Accumulated-Time" stellt ja die Zeit dar, die die Funktion inkl.
aller evtl. Unterfunktionsaufrufe, benötigt, oder?
Das scheint mir aber etwas komisch zu sein, DENN bei der normalen
Berechnung eines Punktes auf einer linearen Kennlinie (linear_lut und
linear_normal) ist da schon ein Faktor von knapp 32 drinn (421/13).
Da hiesse, hier ist eine LUT 32* schneller. Das kann ich mir gaaanz
schlecht vorstellen.
Bei der Berechnung von pow liegt der Faktor bei knapp 59 (11823/201).
Ich meine, dass hier ein Vorteil einer LUT ggü. der Berechnung vorliegen
muss ist klar, aber das der wirklich sooo groß sein soll, kann ich mir
auch nicht vorstellen...
Wo liegt mein Denkfehler?
danke
edit: Ich habe mal einen Teil aus dem Disassambly angehangen.
Dabei hab ich die Berechnungen nicht mit einzelnen Funktionen, sondern
gleich direkt in der for(;;) gemacht. (Das sind die auskommentierten
Sachen)
Man kann deutlich erkennen, das das "Raussuchen" aus einer LUT weiniger
Schritte benötigt, als das Berechnen der Werte...
Hiho,
kurze Zwischenfrage, sind EFF_ANSTIEG bzw. EFF_Y_SCHNITT
Float-Konstanten?
Flat ist denke ich die Zeit ohne Unterfunktionen, Acc die Zeit mit
Unterfunktionen.
Ah, die Frage hat sich geklärt. Habe mal Dein Assembler-File ein
bisschen bearbeitet:
// eff-pegel berechnen
aus kennlinie
0025A4 1C420411 mov.w &adcwert,R12
0025A8 0D43 clr.w R13
0025AA B0128A2C call #?UL_TO_FLT
0025AE 3E40508D mov.w #0x8D50,R14
0025B2 3F40973C mov.w #0x3C97,R15
0025B6 B012262F call #?FLT_MUL
0025BA 3E400080 mov.w #0x8000,R14
0025BE 3F408542 mov.w #0x4285,R15
0025C2 B0127231 call #?FLT_ADD
0025C6 0E43 clr.w R14
0025C8 3F40C842 mov.w #0x42C8,R15
0025CC B012262F call #?FLT_MUL
0025D0 B012082D call #?FLT_TO_UL
0025D4 824C0811 mov.w R12,&Lequ_1
Hier siehst Du was die Laufzeit für die linear_normal verursacht.
Er ruft folgende Subroutinen aus der Bibliothek auf:
1. Cast von Unsigned nach Float (adc--> float)
2. erste float-Multiplikation (adc * EFF_ANSTIEG)
3. float- addition (+ EFF_Y_SCHNITT)
4. zweite float-Multiplikation (*100)
5. Cast von float nach unsigned
So gesehen sind die 421 als acc. time noch "gnädig". Zeitkritische
Sachen im float mit nem Prozessor ohne Gleitkommaeinheit waren schon
immer spannend :-)
Miss doch die Zeiten mal direkt auf dem Chip. Oszi an ein Pin und dann
los. Ich wette, es kommt in etwa das gleich Verhältnis raus.
Wie schon gesagt, dauern Float-Operationen ewig auf dem kleinen Teil.
Ist ja klar, ohne FPU. Da ist die LUT deutlich im Vorteil.
Gut, ich danke Euch! Das mit der fehlenden FPU und der
floating-point-rechnung leuchtet jetzt auch ein. Mir kamen die Werte nur
etwas zu hoch vor, aber ich denke, es passt schon so.