Hi Leute!
Ich stehe gerade vor einem Rätsel. Ich möchte zwei int32-Werte
miteinander verrechnen. Ich arbeite mit dem MSP430G2955 und CCS V5
Ich habe eine Funktion, welche mir einen Wert berechnen soll. Als
Argument bekommt sie einen int32_t.
Wenn ich jetzt mit diesem Wert weiterrechnen will, dann kommt nurnoch
Müll raus...
device_param.adc_cal_values[0] und device_param.adc_cal_span sind auch
vom Typ int32_t und device_param.percent_cal_values[0] ist ein float -
aber diese Werte sind ja sogar uninteressant, da der Fehler vorher
auftritt.
adc_val hat jetzt beispielsweise einen Wert von 16000000, was ja locker
in den int32 reinpasst.
device_param.adc_cal_values[0] hat den Wert 1764944.
Also:
1
x_minus_x1 = 16000000 - 1764944 = 14235056
x_minus_x1 wird nicht richtig berechnet. Da steht als Ergebnis -51792
!!!
Ich habe jetzt alles doppelt und dreifach wegen den Datentypen
kontrolliert. Und testweise habe ich mal einfach
1
x_minus_x1 = (adc_val - 5)
reingeschrieben - auch falsches Ergebnis!
Was funktioniert:
1
x_minus_x1 = adc_val;
und
1
x_minus_x1 = (adc_val - 0)
Kann mir jemand erklären, was da los sein kann? Ich habe auch schon den
gesamten Workspace "gecleant"...Fehler bleibt!
Jemand 'ne Idee?
>> x_minus_x1 wird nicht richtig berechnet. Da steht als Ergebnis -51792> !!!
Wo steht dieses Ergebnis?
Schon mal in Betracht gezogen, dass auch die Ausgabefunktion fehlerhaft
sein kann, bzw. die falsche Ausgabefunktion benutzt wird?
>> x_minus_x1 wird nicht richtig berechnet. Da steht als Ergebnis -51792> !!!
Mal eine Beobachtung:
16Mio - 1764944 ergibt die von dir angegebene Zahl.
Als Hexzahl lautet das Ergebnis
1
00 D9 35 B0
Du siehst an der Ausgabe das Ergebnis -51792. Dieses Ergebnis wiederrum
als Hex-Zahl ausgedrückt, lautet
1
FF FF 35 B0
Was sofort auffällt: die unteren 16 Bit stimmen. lediglich die oberen
sind falsch. Das scheint so zu sein, dass da irgendwo 16 Bit verloren
gehen.
Wenn wir mal davon ausgehen, dass der Compiler keinen Fehler gemacht
hat, dann muss irgendwo das High-Word verloren gegangen sein. Unklar ist
dann allerdings, wo die 0xFFFF im High-Word herkommen.
Karl Heinz schrieb:> Wo steht dieses Ergebnis?> Schon mal in Betracht gezogen, dass auch die Ausgabefunktion fehlerhaft> sein kann, bzw. die falsche Ausgabefunktion benutzt wird?
Wenn man sich die beiden Zahlen binär anschaut, ist das sogar ziemlich
sicher so.
Grüsse,
René
> adc_val hat jetzt beispielsweise einen Wert von 16000000, was ja locker in den
int32 reinpasst.
Wo hast du diese 16000000 verifiziert?
Innerhalb der Funktion oder gehst du davon aus, dass der Wert stimmt,
weil du weißt dass da 16000000 drinnen stehen müsste.
> Was funktioniert:> x_minus_x1 = adc_val;> und> x_minus_x1 = (adc_val - 0)
Das allerdings ist schon ein Fingerzeig, dass der Weg in Richtung
Compiler-Fehler gehen könnte. Denn wenn adc_val schon falsch ist, dann
müsste auch hier ein Word-Verlust feststellbar sein.
Nichts desto trotz, lass uns mal den Suchkreis auf den Aufruf der
Funktion ausdehen. Wo kommt adc_val her, was passiert im Vorfeld mit
diesem Wert?
(allerdings ist die erste Frage immer noch: wie ist 'da steht' zu
verstehen? Eigene Funktion oder Debugger-Ausgabe. Das wär momentan mal
die wichtigere Frage aus meiner Sicht)
Hi Leute!
Vielen Dank für eure zahlreichen Beiträge.
Ich habe das Problem gerade entdeckt - die Rechnung funktioniert an
sich, das Problem liegt hier:
Der Wert adc_val kommt von außen, klar. Um die Funktion nun mit
verschiedenen Werten zu testen, also wenn z.B. der ADC-Wert niedriger
als der minimal kalibrierte Wert, bzw. höher als der maximal kalibrierte
Wert liegt, habe ich die Funktion aufgerufen und vor der ersten Aktion
den Debugger angehalten und den adc_val, welcher ja von außen kommt und
irgendeinen Wert aus der Messung enthält, selbst auf den Wert 16000000
gesetzt. adc_val habe ich in meinem "Watch"-Fenster drin, da kann ich ja
alle Werte jederzeit ändern, solange der Debugger auf Pause steht.
Der Wert wird auch übernommen, die 16000000 stehen dann im Watch-Fenster
für die Variable adc_val. Mache ich mit dem Programm jetzt weiter, wird
falsch gerechnet. Irgendwie wird die neu eingebene Zahl nicht für die
Rechnung benutzt.
Manipuliere ich den Wert vor Aufruf der Funktion, dann funktioniert es
wie erwartet. Also natürlich nicht adc_val selbst, sondern die Variable,
welche dann an adc_val übergeben wird.
Kann mir jemand sagen, warum das so ist?
Was mir halt garnicht einleuchtet ist die Tatsache, dass ich den in der
Funktion manipulierten Wert mit 0 verrechnen kann und es dann stimmt.
Und ebenso funktionierte die Zuweisung des manipulierten Wertes an eine
andere Variable.
Nur eben das verrechnen mit einem Wert != 0 geht nicht.
welchen Datentypen verwendest Du für device_param.adc_cal_values[0]?
Möglicherweise einen 16-bit Typ?
Funktioniert es eventuell wenn du einen expliziten type-cast schreibst:
x_minus_x1 = (adc_val - (int32_t) device_param.adc_cal_values[0]);
???
andi6510 schrieb:> welchen Datentypen verwendest Du für device_param.adc_cal_values[0]?Dennis schrieb:> device_param.adc_cal_values[0] und device_param.adc_cal_span sind auch> vom Typ int32_t
Die Datentypen sind "leider" alle gleich
Karl Heinz schrieb:> Was sofort auffällt: die unteren 16 Bit stimmen. lediglich die oberen> sind falsch. Das scheint so zu sein, dass da irgendwo 16 Bit verloren> gehen.>> Wenn wir mal davon ausgehen, dass der Compiler keinen Fehler gemacht> hat, dann muss irgendwo das High-Word verloren gegangen sein. Unklar ist> dann allerdings, wo die 0xFFFF im High-Word herkommen.
Signed extend. Das riecht doch ziemlich stark nach Compilerfehler.
Aber ich verstehe das Problem nicht. Ein Blick in den Assemblercode
klärt das doch umgehend. Keine Ahnung, warum das der TO nicht schon
längst selbst gemacht hat, bevor er den Thread überhaupt erst eröffnet
hat.
Ohne harte Fakten ist das doch alles bloß sinnloses Rumgerate.
Dennis schrieb:> Was mir halt garnicht einleuchtet ist die Tatsache, dass ich den in der> Funktion manipulierten Wert mit 0 verrechnen kann und es dann stimmt.> Und ebenso funktionierte die Zuweisung des manipulierten Wertes an eine> andere Variable.>> Nur eben das verrechnen mit einem Wert != 0 geht nicht.
Kommt immer auf den Compiler bzw. Debugger an. Zum einen müßtest Du im
Disassembler genau sehen, was gemacht wird. Im einfachsten Fall änderst
Du den Wert auf der RAM Zelle. An der Stelle, an der Du anhälst, rechnet
dein Programm dann bereits mit den Registerinhalten.
Für solche Spielereinen ohne genaues nachsehen würde ich Optimierung 0
und wenn das nicht reicht - volatile für alle relevanten Variablen -
empfehlen. Nur nicht vergessen, das hinterher wieder wegzumachen.
Allerdings frage ich mich, ob es nicht einfacher ist, die Testwerte
direkt im Sourcecode zu setzen.
Ich glaube nicht an einen Compilerfehler, solange hier nicht der
lauffähige Code gezeigt wird. Da steckt bestimmt ein Programmierfehler
drin und die Warnings werden missachtet oder sind ausgeblendet.
Dennis schrieb:> Was funktioniert:> x_minus_x1 = adc_val;> und> x_minus_x1 = (adc_val - 0)
na das bedeutet doch nur, das keine veränderung vorgenommen wird --> der
Compiler erkennt das und optimiert die Subtraktion gleich ganz weg...
Dennis schrieb:> Manipuliere ich den Wert vor Aufruf der Funktion, dann funktioniert es> wie erwartet. Also natürlich nicht adc_val selbst, sondern die Variable,> welche dann an adc_val übergeben wird.>> Kann mir jemand sagen, warum das so ist?
Weil der Compiler die Variable irgenwann in ein (oder zwei bei int32_t)
Register packt um damit zu rechnen. Dann kannst Du die Variable im RAM
zwar ändern - der Prozessor rechnet aber weiter mit dem Inhalt der
Register.
Darum zeigt ein guter Debugger auch immer den disassemblierten Code an,
dort sieht man ob gleich mit Registern gerechnet oder eine Variable aus
dem RAM geladen wird.
Ein optimierender C-Compiler wird so oft wie möglich mit Registern
arbeiten.