Hallo zusammen,
ich versuche mich gerade an einem STM32F0 Discovery_Board und habe den
ADC in Verwendung.
Diesen calibriere ich zu Beginn und erhalte einen Wert von 66.
Anschließend gibt mir mein ADC in der Main zyklisch Werte von Pa0 und
Vref-Int aus.
Danach möchte ich die Spannung an PA0 berechnen mit der Formel aus dem
Reference Manual V=(3300V*V_ref_cal*ADC-Data)/(4095*V_ref_data)
Die Spannung die ich messen möchte, liegt ca. bei 2.8V. Ich bekomme als
Werte ungefähr ADC_Data=3949 und V_ref_data=2569.
Mein Ergebnis liegt immer bei 74. Müsste allerdings bei 2800 liegen.
Benutze ich eine falsche Formel? Stimmt der Calibration-Wert oder müsste
dieser größer sein?
Vielleicht sieht jemand meinen Fehler..
Danke für eure Hilfe
Setzt Du für v_ref_cal den richtigen Wert ein? Der steht im Flash:
Aus STM32F071 datasheet:
3.10.2 Internal voltage reference (VREFINT)
The internal voltage reference (VREFINT) provides a stable (bandgap)
voltage output for the ADC. VREFINT is internally connected to the
ADC_IN17 input channel. The precise voltage of VREFINT is individually
measured for each part by ST during production test and stored in the
system memory area. It is accessible in read-only mode.
Calibration value name Memory address
-----------------------------------------------------------
VREFINT_CAL 0x1FFF F7BA - 0x1FFF F7BB
Ich habe den Eindruck, dass im Reference manual Offset-calibration und
VREF-calibration-factor etwas unglücklich zusammengemischt werden.
Gruß, Stefan
Stefan K. schrieb:> Setzt Du für v_ref_cal den richtigen Wert ein? Der steht im Flash:
Laut dir nicht. Ich dachte immer, ich setze den Wert meiner Kalibrierung
zu Beginn der ADC-Konfigurierung ein. So ist das aus dem Datenblatt für
mich ersichtlich.
Ich benutze allerdings einen STM32F051. In dem Reference Manual steht
das nicht so deutlich.
Das das so ist, dachte ich mir eigentlich auch schon. Habe allerdings
noch keinen Wert für Vref_CAL gefunden, ausser eben den Wert, den ich
nach der Kalibrierung erhalte. Danke schonmal für deinen Einwand, dann
muss ich wohl noch weiter suchen...
Matthias H. schrieb:> Laut dir nicht. Ich dachte immer, ich setze den Wert meiner Kalibrierung> zu Beginn der ADC-Konfigurierung ein. So ist das aus dem Datenblatt für> mich ersichtlich.
Ja, das dachte ich auch zuerst.
Allerdings ist der Wert, der nach der ADC-Kalibration gelesen soll, ja
anscheinend ein DC-Offset, erstens wegen seiner Größe (Bit 0..6, also 0
.. 127) und zweitens wegen dem Satz in 13.4.1:
"The internal analog calibration is kept if the ADC is disabled
(ADEN=0). When the ADC operating conditions change (VDDA changes are the
main contributor to ADC offset variations and temperature change to a
lesser extend), it is recommended to re-run a calibration cycle."
Die Werte V_ref_cal und V_ref_data werden in der von Dir benutzten
Formel aber als Gain-Korrektur verwendet.
Meiner Meinung nach musst Du den Vref Channel messen und diesen Wert als
V_ref_data in Deine Formel einsetzen. Für V_ref_cal wird der Wert aus
dem Flash genommen. Dieser Wert wurde von ST für diesen speziellen Chip
berechnet und stellt den individuellen Korrekturfaktor für die interne
Referenzspannungsquelle dar.
Viele Grüße, Sefan
Matthias H. schrieb:> In dem Reference Manual steht> das nicht so deutlich.
Wer lessen kann ist klar im Vorteil. Im reference manual steht nichts,
allerdings im Datenblatt:
VREFINT_CAL 0x1FFFF7BA-0x1FFFF7BB
Allerdings ist diese Variable nicht in der CooCox-Umgebung vorhanden.
Matthias H. schrieb:> Ich bekomme als> Werte ungefähr ADC_Data=3949 und V_ref_data=2569.
2569/4095 * 3.3V sind etwa 2V. Da kann also schon mal etwas nicht
stimmen, denn das Bandgap Element liegt bei etwa 1.2V
Welchen Wert kriegst du für calib?
Edit:
Du rufst ja auch schon ADC_GetCalibrationFactor auf. Je nach
Interpretation des Reference Manuals könnte man zum Schluss gelangen,
dass danach die Korrektur schon intern angewendet wird. (siehe ADCAL
Abschnitt)
Felix U. schrieb:> Matthias H. schrieb:>> Ich bekomme als>> Werte ungefähr ADC_Data=3949 und V_ref_data=2569.>> 2569/4095 * 3.3V sind etwa 2V. Da kann also schon mal etwas nicht> stimmen, denn das Bandgap Element liegt bei etwa 1.2V> Welchen Wert kriegst du für calib?
Habe die SR erhöht und erhalte 1692 für Vref_Data. Bei 2,978 VDDA ergibt
das 1,23 was relative genau ist. Daran liegt es nicht. Mir fehlt der
Wert von V_REF_CAL
Felix U. schrieb:> Du rufst ja auch schon ADC_GetCalibrationFactor auf. Je nach> Interpretation des Reference Manuals könnte man zum Schluss gelangen,> dass danach die Korrektur schon intern angewendet wird. (siehe ADCAL> Abschnitt).
Das denke ich auch. Der hier ermittelte Wert wird ja auch an keiner
weiteren Stelle von Reference oder datasheet mehr erwähnt.
Matthias H. schrieb:> Mir fehlt der Wert von V_REF_CAL
Dessen Adresse sollte in einer der CMSIS Dateien definiert sein.
Viele Grüße, Stefan
Felix U. schrieb:> Edit:> Du rufst ja auch schon ADC_GetCalibrationFactor auf. Je nach> Interpretation des Reference Manuals könnte man zum Schluss gelangen,> dass danach die Korrektur schon intern angewendet wird. (siehe ADCAL> Abschnitt)
Nein. Mache ich es ohne Rechnung mit VrefInt komme ich auf Werte wie
3.1V anstatt 2.8V. Ist ja auch klar, da ich mit VDDA=3.3V rechne und
nicht mit 2.978V
Stefan K. schrieb:> Dessen Adresse sollte in einer der CMSIS Dateien definiert sein.
Nein habe alles durchsucht.
Ich habe es probiert mit:
#define VREFINT_ADDR 0x1FFFF7BA
uint16_t Vrefcal
Vrefcal=*((uint16_t*)VREFINT_ADDR
funktioniert immer noch nicht...
Matthias H. schrieb:> Nein. Mache ich es ohne Rechnung mit VrefInt komme ich auf Werte wie> 3.1V anstatt 2.8V. Ist ja auch klar, da ich mit VDDA=3.3V rechne und> nicht mit 2.978V
Lösung: Rechne mit 2.978 * ADC_DATA/Fullscale, statt mit 3.3. Die
Kalibrierung macht höchstens 0.1 V aus, das ist ja eine Ein-Punkt
Korrektur, kann also gar nicht Offset und Linearitätsfehler
berücksichtigen.
Welchen Wert liest du denn an der Speicheradresse aus? Dann kann man da
mal einen Plausibilitätscheck machen.
Felix U. schrieb:> Lösung: Rechne mit 2.978 * ADC_DATA/Fullscale, statt mit 3.3. Die> Kalibrierung macht höchstens 0.1 V aus, das ist ja eine Ein-Punkt> Korrektur, kann also gar nicht Offset und Linearitätsfehler> berücksichtigen.
Nein, in der späteren Anwendung kenne ich mein VDD nämlich nicht mehr.
Ich habe es jetzt!
Der Fehler war im Wert von VREF_CAL. Nachdem ich den Zugriff auf die
Adresse hinbekommen habe, funktioniert alles einwandfrei.
Danke für eure Hilfe!
Hallo Gemeinde,
vielen Dank auch nochmal von mir für den wirklich nutzbringenden
Hinweis, dass das in der ST-Doku erwähnte "VREFINT_CAL" nicht der Wert
ist, welcher in der Standard Peripheral Library von
ADC_GetCalibrationFactor() zurückgegeben wird - was mein Vorgänger ja
ebenfalls glaubte.
Stundenlang hab ich auch damit zugebracht herauszufinden, warum einfach
keine meiner Berechnungen mit den zur Verfügung stehenden Werten zur
richtigen Referenzspannung führen wollte. Mathe 3 hab ich zwar noch vor
mir, aber so sehr bin ich nun doch nicht auf den Kopf gefallen XD
Ziemlich schade von ST, nicht genau an der Stelle im Reference Manual,
wo die Berechnungen der Referenzspannung aufgeführt ist, einfach nochmal
darauf hinzuweisen, an welcher Adresse das "richtige" VREFINT_CAL zu
finden ist.
Ich benutze im übrigen einen STM32F030CC und mein Test-Code sieht (für
die Nachwelt) wie folgt aus:
Falls sich jemand darüber wundert, warum ich gleich 5000 Mal den ADC
auslese:
Es ist wie gesagt nur Test-Code und ich gebe den Spannungswert über ein
UART aus. Dabei waren mir die teils sehr unschönen Schwankungen von
einigen 10 mV bei einer einzelnen Konvertierung zu nervig anzusehen.
Daher habe ich einfach ein bisschen rumexperimentiert und bin bei 5000
geblieben. Macht bei 48 MHz ja sowieso nur 2 ms aus und ist auch in
meinem Fall absolut unkritisch :D
Und noch ein Hinweis für all diejenigen, die es nicht schon bereits
wussten:
In der Standard Library setzte die Methode ADC_ChannelConfig() nicht
vorher alle Channel zurück, sondern Oder-verknüpft das CHSELR-Register
mit den übergebenen Channels.
Dies kann dann zum Problem werden, wenn man so wie ich die ADC-Werte
durch ein manuelles Auslösen in 5000 Konvertierungen mittelt und dabei
versehentlich mehrere Channels aktiv waren. So werden dann nämlich
reihum alle Kanäle einmal ausgelesen (entsprechend der Einstellung
ADC_ScanDirection) und von all diesen Werten dann das Mittel genommen.
Das könnte dann u.U. zu einer nervigen Fehlersuche führen.
Gruß
Arno