Forum: Mikrocontroller und Digitale Elektronik ADC Auslesen STM32F04


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Patrick E. (perdmann)



Lesenswert?

Hallo,

ich kämpfe seit Tagen damit,Temperaturwerte aus einem ADC vom STM32 
auszulesen. Ich habe DMA und polling versucht und jedes mal sind die 
Werte total unplausibel. Wenn ich mit einem multimeter Messe sehen die 
Werte aber plausibel aus.

Hat jemand das schonmal gemacht und den Beispielcode für mich?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Patrick E. schrieb:
> Hat jemand das schonmal gemacht und den Beispielcode für mich?

https://github.com/STMicroelectronics/STM32CubeF0/tree/master/Projects/STM32F042K6-Nucleo/Examples/ADC/ADC_DMA_Transfer

Dürfte sich bereits auf deinem PC befinden als Teil des STM32CubeF0.

von N. M. (mani)


Lesenswert?

Patrick E. schrieb:
> Ich habe DMA und polling versucht

Dann zeig Mal den Code dazu. Ohne kann hier niemand weiter helfen.

Patrick E. schrieb:
> und jedes mal sind die Werte total unplausibel.

Wie äußert sich das? Wie sehen die Werte aus und was erwartest du?

Patrick E. schrieb:
> Wenn ich mit einem multimeter Messe sehen die Werte aber plausibel aus.

Wieso, was misst du damit?

Patrick E. schrieb:
> Hat jemand das schonmal gemacht und den Beispielcode für mich?

Etwas unspezifisch. Zum einen gibt es von ST selbst einige Beispiele. 
Zum anderen ist das mit Arduino eine Zeile. Also was genau willst du?

von Wastl (hartundweichware)


Lesenswert?

Patrick E. schrieb:
> ich kämpfe seit Tagen damit,Temperaturwerte aus einem ADC vom STM32
> auszulesen.

Ich würde eher sagen du kämpfst damit hier klar darzustellen
was du überhaupt machst bzw. machen willst.

Also zuerst mal:
Aus einem ADC kann man keine Temperaturwerte auslesen.

von Norbert (der_norbert)


Lesenswert?

Patrick E. schrieb:
> Hat jemand das schonmal gemacht und den Beispielcode für mich?
1
#!/python
2
# -*- coding: UTF-8 -*-
3
# vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
4
from machine import Pin,ADC
5
6
ADC_PIN_NUM = xxx
7
8
adc_pin = Pin(ADC_PIN_NUM, Pin.IN, None)
9
adc_channel = ADC(adc_pin)
10
value = adc_channel.read_u16() >> 4

von Patrick E. (perdmann)


Angehängte Dateien:

Lesenswert?

Ich habe alles soweit schon ausprobiert, im Moment sieht es so aus:

https://dpaste.org/7m6zr
https://dpaste.org/DymS9

Wenn ich das richtig verstehe, kann man bei den kleinen STM32 die "Scan 
conversation mode" nicht ausschalten und muss daher immer alle 
konfigurierten ADC Sensoren in einem rutsch pollen. Deshalb sollte man 
lieber DMA benutzen, man sieht auch noch schnippsel von dem DMA code in 
dem source code, diese werden zur Zeit nicht benutzt.

Die Beispiele kenne ich auch, die rufen da aber nur einen ADC ab, wenn 
ich micht nicht täusche.

Ich habe auch meine clock config mal angehängt.

: Bearbeitet durch User
von Roland E. (roland0815)


Lesenswert?

Die Eingangsimpedanz der ADC schwankt stark mit der 
Einlesegeschwindigkeit. So hochohmig wie deine Messchaltung ist, 
solltest du so langsam wie sinnvoll messen...

von Patrick E. (perdmann)


Lesenswert?

Roland E. schrieb:
> Die Eingangsimpedanz der ADC schwankt stark mit der
> Einlesegeschwindigkeit. So hochohmig wie deine Messchaltung ist,
> solltest du so langsam wie sinnvoll messen...

Also du meinst ich sollte den Spannungsteiler lieber auf 1k / 100R 
reduzieren? Kann ich mit meinen 10k NTCs kann überhaupt was anfangen?...

von Monk (roehrmond)


Lesenswert?

Patrick E. schrieb:
> Also du meinst ich sollte den Spannungsteiler lieber auf 1k / 100R
> reduzieren? Kann ich mit meinen 10k NTCs kann überhaupt was anfangen?...

Die Impedanz des Spannungsteilers entspricht der Parallelschaltung 
beider Widerstände.

1k / 100R ergäben 91 Ohm

10k / 10k ergeben 5k  Ohm

Bis 10k bin ich sicher, dass das ohne Probleme funktionieren kann. Denn 
niemand zwingt dich dazu, eine besonders kurze Sampling-Zeit 
einzustellen.

Siehe 
file:///home/stefan/Downloads/an2834-how-to-optimize-the-adc-accuracy-in 
-the-stm32-mcus-stmicroelectronics.pdf  Kapitel 3.2.7 und 4.2.6

von Oliver R. (orb)


Lesenswert?

Monk schrieb:
> file:///home/stefan/Downloads/an2834-how-to-optimize-the-adc-accuracy-in
> -the-stm32-mcus-stmicroelectronics.pdf

Schon wieder jemand, der lokale Files verlinkt.
Da kann keiner von uns drauf zugreifen.

von Monk (roehrmond)


Lesenswert?

Oliver R. schrieb:
> Schon wieder jemand, der lokale Files verlinkt.

Oh, das hatte ich per Google gefunden und aus der URL Zeile kopiert, 
ohne genau hin zu schauen.

https://www.st.com/resource/en/application_note/an2834-how-to-optimize-the-adc-accuracy-in-the-stm32-mcus-stmicroelectronics.pdf

Noch eine Ergänzung:

Man kann mit einem Oszilloskop am Eingang des ADC messen, wie stark er 
den Spannungsteiler belastet.

Man kann ggf. diese Spannung mit externen Kondensatoren (zwischen Signal 
und GND) stabilisieren. Wenn der externe Kondensator relativ groß ist 
(z.B. 100nF) und zwischen den Messungen reichlich Zeit zum Aufladen 
bekommt, dann ergibt sich eine schön stabile Spannung. Ganz egal wie 
hochohmig der Spannungsteiler ist.

von Roland E. (roland0815)


Lesenswert?

Monk schrieb:
> ...
>
> Man kann ggf. diese Spannung mit externen Kondensatoren (zwischen Signal
> und GND) stabilisieren. Wenn der externe Kondensator relativ groß ist
> (z.B. 100nF) und zwischen den Messungen reichlich Zeit zum Aufladen
> bekommt, dann ergibt sich eine schön stabile Spannung. Ganz egal wie
> hochohmig der Spannungsteiler ist.

Jepp. 100n vor den Pin auf dem geteilten Signal sollte auch gehen. Eine 
Akkuspannung muss man ja nicht 1000x pro Sekunde einlesen. Da kann man 
auch 1x in der Sekunden den ADC einmal messen lassen.

Auf der Seite 107 in 
https://www.st.com/resource/en/datasheet/stm32f401re.pdf ist die 
berechnung für die Eingangsimpedanz der ADC.

Ich habe mir aus den Erfahrungen gemerkt, dass alles über 5k 
Quellimpedanz extrem ungenau wird. Die in den electrical Spec angegbenen 
50k (max) sind reines Wunschdenken am theoretischen Rand des ADC...

: Bearbeitet durch User
von Patrick E. (perdmann)


Lesenswert?

Ich habe jetzt mal 100 nF vom signal zu Masse gelötet. Sampling rate ist 
auf Maximum trotzdem springen die Werte zwischen 0 und 4095. Gemessen 
habe ich am spannungsteiler 0,2xxx Volt also sollte ich doch ca 248 am 
ADC auslesen... Ungefähr .

von Monk (roehrmond)


Lesenswert?

Patrick E. schrieb:
> Sampling rate ist auf Maximum trotzdem springen die Werte zwischen 0 und
> 4095. Gemessen habe ich am spannungsteiler 0,2xxx Volt also sollte ich
> doch ca 248 am ADC auslesen.

Also wahrscheinlich ein Softwareproblem.

von Patrick E. (perdmann)


Lesenswert?

Monk schrieb:
> Patrick E. schrieb:
>> Sampling rate ist auf Maximum trotzdem springen die Werte zwischen 0 und
>> 4095. Gemessen habe ich am spannungsteiler 0,2xxx Volt also sollte ich
>> doch ca 248 am ADC auslesen.
>
> Also wahrscheinlich ein Softwareproblem.

Mit dma kommt auch nur 0 zurück. Sollte ich mal von HAL auf LL 
umschalten in cubemx? Ich habe jetzt so ziemlich alle Kombinationen 
durch und weiß auch nicht mehr weiter wie ich da sinnvolle werte raus 
bekommen soll.

von Monk (roehrmond)


Lesenswert?

Patrick E. schrieb:
> Sollte ich mal von HAL auf LL umschalten in cubemx?

Ich bin kein Fan von der HAL, aber ich bin sicher, dass die 
Problemursache woanders liegt. Lerne lieber, sie richtig zu benutzen. 
Dazu reicht die Doku der HAL alleine nicht aus. Man muss auch das 
Reference Manual und das Datasheet dazu lesen.

Vielleicht erst mal mit einem STM32F0 oder L0 anfangen, denn die sind 
weniger komplex.

: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

Patrick E. schrieb:
> Wenn ich das richtig verstehe, kann man bei den kleinen STM32 die "Scan
> conversation mode" nicht ausschalten und muss daher immer alle
> konfigurierten ADC Sensoren in einem rutsch pollen.

Nein, hast du nicht.

STM32F0x Reference Manual:

Analog input channels:
– 16 external analog inputs
– 1 channel for internal temperature sensor (V SENSE )
– 1 channel for internal reference voltage (V REFINT )
– 1 channel for monitoring external V BAT power supply pin

Start-of-conversion can be initiated:
– By software
– By hardware triggers with configurable polarity (timer events)

Conversion modes:
– Can convert a single channel or can scan a sequence of channels.
– Single mode converts selected inputs once per trigger
– Continuous mode converts selected inputs continuously
– Discontinuous mode

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Patrick E. schrieb:
> Die Beispiele kenne ich auch, die rufen da aber nur einen ADC ab, wenn
> ich micht nicht täusche.

Dann fang doch erstmal damit an. Wenn das Beispiel einen Kanal korrekt 
abfragt kannst du es erweitern. Man kann bei solchen Themen so viel 
falsch machen, da ist es absolut sinnvoll mit einem funktionierenden(!) 
Beispiel anzufangen anstatt Ewigkeiten an einem vermurksten Code 
herumzudoktorn. Und wenn es doch ein Hardware-Problem ist, kannst du 
lange an der Software herumpfuschen.

von Rahul D. (rahul)


Lesenswert?

Patrick E. schrieb:
> Die Beispiele kenne ich auch, die rufen da aber nur einen ADC ab, wenn
> ich micht nicht täusche.

Der STM32F04xx hat nur einen einzigen ADC.
Der jeweilige Messkanal wird durch einen Multiplexer auf dessen Eingang 
gelegt (Neudeutsch "geroutet").

Per DMA kann man eine vorher festgelegte Reihenfolge der Messkabnäle 
festlegen, die ziemlich wahlfrei ist (ich kene das Reference Manual des 
F04 nicht [auswendig]).

Mit STCubeMX kann man das alles fertig konfigurieren,

von Rolf (rolf22)


Lesenswert?

Patrick E. schrieb:
> Sampling rate ist auf Maximum trotzdem springen die Werte zwischen 0 und
> 4095.

Das weckt den Verdacht, dass du das ADC-Register zum falschen Zeitpunkt 
ausliest. Wo in deinem hier gezeigten Quellcode wird denn 
sichergestellt, dass in dem Register im Moment des Auslesens ein 
gültiger Wert steht?

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

> uint32_t AD_RES_BUF[ADC_BUF_SIZE];

Liefert der ADC nicht 16bit-Werte?!

von Roland E. (roland0815)


Lesenswert?

Niklas G. schrieb:
>> uint32_t AD_RES_BUF[ADC_BUF_SIZE];
>
> Liefert der ADC nicht 16bit-Werte?!

12Bit. Ist aber unkritisch, das 16Bit-Register in einen 32Bit uint zu 
packen. RAM ist bei den Cortex billig, da muss man nicht wegen drei oder 
vier Byte rumgeizen. Rechnen tut der schließlich auch mit 32Bit...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Roland E. schrieb:
> Rechnen tut der schließlich auch mit 32Bit...

Das DMA speichert aber wahrscheinlich einzelne 16bit-Werte in diesen 
Puffer. Wenn man diese in C als 32bit ausliest passiert Murks.

von Monk (roehrmond)


Lesenswert?

Niklas G. schrieb:
> Das DMA speichert aber wahrscheinlich einzelne 16bit-Werte in diesen
> Puffer. Wenn man diese in C als 32bit ausliest passiert Murks.

Guter Punkt. Ob das wohl die Problemursache ist?

von Rahul D. (rahul)


Lesenswert?

Niklas G. schrieb:
> Das DMA speichert aber wahrscheinlich einzelne 16bit-Werte in diesen
> Puffer. Wenn man diese in C als 32bit ausliest passiert Murks.

Kann sein. Ich habe das nicht mehr so im Gedächtnis.
Wegen solcher Hinweise sollte man sich das Kapitel "ADC" und/oder "DMA" 
im Reference Manual angucken.

von Norbert (der_norbert)


Lesenswert?

Niklas G. schrieb:
> Das DMA speichert aber wahrscheinlich einzelne 16bit-Werte in diesen
> Puffer. Wenn man diese in C als 32bit ausliest passiert Murks.

Patrick E. schrieb:
> trotzdem springen die Werte zwischen 0 und 4095.

Lässt sich jedoch nicht mit falscher DMA Übertragungsgröße 
(WORD/HALFWORD) erklären.

von Andreas B. (abm)


Lesenswert?

Patrick E. schrieb:
> Mit dma kommt auch nur 0 zurück. Sollte ich mal von HAL auf LL
> umschalten in cubemx? Ich habe jetzt so ziemlich alle Kombinationen
> durch und weiß auch nicht mehr weiter wie ich da sinnvolle werte raus
> bekommen soll.

Da würd' ich doch glatt mal alle ADC- und DMA-Register "zu Fuß" auslesen 
und kontrollieren, ob da wirklich das Gewünschte drin steht ...

von Patrick E. (perdmann)


Lesenswert?

Norbert schrieb:
> Niklas G. schrieb:
>> Das DMA speichert aber wahrscheinlich einzelne 16bit-Werte in diesen
>> Puffer. Wenn man diese in C als 32bit ausliest passiert Murks.
>
> Patrick E. schrieb:
>> trotzdem springen die Werte zwischen 0 und 4095.
>
> Lässt sich jedoch nicht mit falscher DMA Übertragungsgröße
> (WORD/HALFWORD) erklären.


Ich hatte HALFWORD/HALFWORD konfiguriert... Was aber natürlich Murks 
ist. Ich habe jetzt, weil RAM hab ich ja, auf WORD/WORD umgestellt und 
siehe da. Es klappt... plausible Werte..

Wirklich vielen vielen Dank! Und ich werde mir für die nächste Schaltung 
merken, dass ich die ADC Eingangswiderstände überprüfe und die Eingänge 
puffer.

von Norbert (der_norbert)


Lesenswert?

Patrick E. schrieb:
> Ich hatte HALFWORD/HALFWORD konfiguriert... Was aber natürlich Murks
> ist. Ich habe jetzt, weil RAM hab ich ja, auf WORD/WORD umgestellt und
> siehe da. Es klappt... plausible Werte..

WORD sind in dieser Architektur 32bit und somit gänzlich unnötig bei 
ADC.
HALFWORD sind 16 bit und das ist korrekt, wenn man damit ein uint16 
array füllt.
Oftmals kann man sogar (bei verminderter Auflösung) den ADC auf 8bit 
setzen (autoshift >> 4) und mit DMA BYTE Transfers ein uint8 array 
füllen.

von Patrick E. (perdmann)


Lesenswert?

Norbert schrieb:
> Patrick E. schrieb:
>> Ich hatte HALFWORD/HALFWORD konfiguriert... Was aber natürlich Murks
>> ist. Ich habe jetzt, weil RAM hab ich ja, auf WORD/WORD umgestellt und
>> siehe da. Es klappt... plausible Werte..
>
> WORD sind in dieser Architektur 32bit und somit gänzlich unnötig bei
> ADC.
> HALFWORD sind 16 bit und das ist korrekt, wenn man damit ein uint16
> array füllt.
> Oftmals kann man sogar (bei verminderter Auflösung) den ADC auf 8bit
> setzen (autoshift >> 4) und mit DMA BYTE Transfers ein uint8 array
> füllen.

Richtig wäre dann ja trotzdem WORD -> HALFWORD ... Ich hatte nicht 
verstanden das es hier um peripherie Breite --> Memory Breite ging.

von N. M. (mani)


Lesenswert?

Patrick E. schrieb:
> Richtig wäre dann ja trotzdem WORD -> HALFWORD

Ne, HALFWORD Peripherie (ADC, 12Bit) zu HALFWORD Memory (uint16_t).

Dein eigentlicher Fehler war also deinen Buffer uint32_t zu deklarieren.

von Norbert (der_norbert)


Lesenswert?

Patrick E. schrieb:
> Richtig wäre dann ja trotzdem WORD -> HALFWORD ... Ich hatte nicht
> verstanden das es hier um peripherie Breite --> Memory Breite ging.

Ähm, nein.

Datenblatt STM32F0: 13.11.9 ADC data register (ADC_DR)
Address offset: 0x40
Reset value: 0x0000 0000
Bits 15:0 DATA[15:0]: Converted data

Also DMA read: HALFWORD (nimmt automagisch den unteren 16bit Teil)
DMA write: HALFWORD

Edit: N.M. war schneller

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

Außer dass es unnötig Speicher frisst nützt dir das Array als uint32 ja 
nichts.

P.S. Das Log() in deiner Konvertierung würde ich auch lieber durch eine 
Tabelle ersetzen.

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.