Forum: Mikrocontroller und Digitale Elektronik ADC STM32 Kallibrationfehler ?


von Tomi (Gast)


Lesenswert?

Hallo,

ich habe einen SM3210e-Eval board mit einem STM32F103Z Prozessor von ARM
drauf und habe das Problem das die ADC eine große Abweichung zu dem 
eigentlichen Wert produzieren.

Bis 0.3 V ist der abgetastete Wert gleich dem vom Spannungsgenerator 
erzeugten Spannungswert.

Ab 0.3V wird die Abweichung höher je höher mein Spannungswert wird.

Beispiel:
Spannungsgenarator -> ADC
0.2 V -> 244
0.3 V -> 349
0.5 V -> 667
1 V -> 1233
1.7 V -> 2110


Mache ich etwas falsch bei der Konfiguration oder Kallibration ?

Ich habe hier die Konfiguration vom ADC1 eingefügt da für die ADC2 und 
ADC3 alles Identisch ist außer die Channels.
1
void Config_ADC(void)
2
{
3
  RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                            //clock for ADC  ADCCLK = PCLK2/6 = 72/6 = 12MHz*/
4
5
  // enable ADC system clock
6
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
7
 
8
  
9
   /* Configure PC.01, PC.02 and PC.03 (ADC Channel 11, ADC Channel 12, ADC Channel 13) as analog input */
10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;           // PC.01, PC.02 and PC.03
11
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                                 // Input-Mode
12
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                            // Speed of port
13
  GPIO_Init(GPIOC, &GPIO_InitStructure);                                       // PortC
14
 
15
  
16
  ADC1_Configuration(); // ADC1 configuration
17
18
  ADC1_Calibration();  // ADC1 calibration
19
20
}
21
22
void ADC1_Configuration(void)
23
{
24
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                             //Nächste Wandlung automatisch starten
25
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                         //Links/Rechtsbündig ins Register legen
26
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;           //Welcher externe Signal Wandlung starten soll
27
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
28
  ADC_InitStructure.ADC_NbrOfChannel = 1;
29
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
30
  
31
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_28Cycles5);  //ADC_SampleTime_1Cycles5
32
  ADC_Init(ADC1, &ADC_InitStructure);                                           //set config of ADC1
33
  
34
  ADC_Cmd(ADC1, ENABLE);                                                         //enable ADC1
35
36
}
37
38
void ADC1_Calibration(void)
39
{
40
  //Start-Kallibration 
41
  ADC_ResetCalibration(ADC1);                           /* Enable ADC1 reset calibration register */ 
42
  while(ADC_GetResetCalibrationStatus(ADC1));           /* Check the end of ADC1 reset calibration register (Reset previous calibration)*/
43
  ADC_StartCalibration(ADC1);                           /* Start ADC1 calibration */
44
  while(ADC_GetCalibrationStatus(ADC1));               /* Check the end of ADC1 calibration */
45
  //Ende-Kallibration
46
  
47
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);             // start conversion (will be endless because of continuous mode)
48
}
49
50
in der Main dann 
51
52
int main(void)
53
{
54
 ...
55
 adc1_value = ADC_GetConversionValue(ADC1);
56
57
58
}

von nosilent (Gast)


Lesenswert?

Bei den 12Bit ADCs entspricht 1 Bit 0.8mV, also das gemessene Ergebnis 
mit 0.8 multiplizieren.

von nosilent (Gast)


Lesenswert?

nosilent schrieb:
> Bei den 12Bit ADCs entspricht 1 Bit 0.8mV, also das gemessene Ergebnis
> mit 0.8 multiplizieren.

Nachtrag: bei 3.3V Referenz

von Tomi (Gast)


Lesenswert?

nosilent schrieb:
> nosilent schrieb:
>> Bei den 12Bit ADCs entspricht 1 Bit 0.8mV, also das gemessene Ergebnis
>> mit 0.8 multiplizieren.
>
> Nachtrag: bei 3.3V Referenz

Super ! Ich weiss das die ADC von 0...3.3V arbeiten, aber woher weiss 
ich wie viel Spannung das board als Referenz nimmt wenn ich die 
ADC1_Callibration aufrufe ?

1
 
2
3
void ADC1_Calibration(void)
4
{
5
  //Start-Kallibration 
6
  ADC_ResetCalibration(ADC1);                           /* Enable ADC1 reset calibration register */ 
7
  while(ADC_GetResetCalibrationStatus(ADC1));           /* Check the end of ADC1 reset calibration register (Reset previous calibration)*/
8
  ADC_StartCalibration(ADC1);                           /* Start ADC1 calibration */
9
  while(ADC_GetCalibrationStatus(ADC1));               /* Check the end of ADC1 calibration */
10
  //Ende-Kallibration
11
  
12
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);             // start conversion (will be endless because of continuous mode)
13
}

von Nils P. (ert)


Lesenswert?

was misst du den an der internen Referenz? Sollte ja sehr genau bei 1,2V 
liegen.

Keine Ahnung was für ein Board du nutzt, aber liegen am Ref_pin wirklich 
3,3V an? Beim f4discovery passt das zb hinten und vorne nicht...

G Ert

von nosilent (Gast)


Lesenswert?

Tomi schrieb:
> aber woher weiss
> ich wie viel Spannung das board als Referenz nimmt wenn ich die
> ADC1_Callibration aufrufe ?

Es kommt drauf an, was deine Referenz ist (Extern: dann am einfachsten 
Aref Pin mit einem Voltmeter messen, Intern: Die ist meist um die 1.2V, 
bei den meisten STM32 kann man die auf einem ADC Kanal messen)

von nosilent (Gast)


Lesenswert?

Nils P. schrieb:
> Keine Ahnung was für ein Board du nutzt, aber liegen am Ref_pin wirklich
> 3,3V an? Beim f4discovery passt das zb hinten und vorne nicht...

Full ack, da ist im Aref-Zweig noch eine Diode drinen, daher sind es ca. 
2.95V (leider abhängig von der Diode)

von Tomi (Gast)


Lesenswert?

nosilent schrieb:
> Nils P. schrieb:
>> Keine Ahnung was für ein Board du nutzt, aber liegen am Ref_pin wirklich
>> 3,3V an? Beim f4discovery passt das zb hinten und vorne nicht...
>
> Full ack, da ist im Aref-Zweig noch eine Diode drinen, daher sind es ca.
> 2.95V (leider abhängig von der Diode)

nosilent schrieb:
> Tomi schrieb:
>> aber woher weiss
>> ich wie viel Spannung das board als Referenz nimmt wenn ich die
>> ADC1_Callibration aufrufe ?
>
> Es kommt drauf an, was deine Referenz ist (Extern: dann am einfachsten
> Aref Pin mit einem Voltmeter messen, Intern: Die ist meist um die 1.2V,
> bei den meisten STM32 kann man die auf einem ADC Kanal messen)

Ich finde diesen Aref Pin nicht , habe nur eine Vref = 3.3V in der Doku 
gesehen. Als ich mit dem Voltmeter an den ADC Kanal gemessen habe , habe 
ich 0,7V gemessen.

Allerdings habe ich in der Doku auch 2.4 V < Vref <3,3 V gelesen ...

von Tomi (Gast)


Lesenswert?

Was mich verwirrt, liefert ADC_GetConversionValue nicht den errechneten 
Wert vom Analog ins Digital ? Oder liefert es nurt die Bits zurück in 
der es aufgelöst wurde ... ?

von nosilent (Gast)


Lesenswert?

Tomi schrieb:
> Ich finde diesen Aref Pin nicht , habe nur eine Vref = 3.3V in der Doku

Mein Fehler, du hast recht, heißt bei STM32 Vref.
Hast du die 0.7V auf dem Vref oder auf einem GPIO, der als ADC Eingang 
verwendet wird gemessen?

ADC_GetConversionValue liefert dir nicht den absoluten Spannungswert, 
sondern einen relativen Wert zur Referenz.

von Tomi (Gast)


Lesenswert?

nosilent schrieb:
> Tomi schrieb:
>> Ich finde diesen Aref Pin nicht , habe nur eine Vref = 3.3V in der Doku
>
> Mein Fehler, du hast recht, heißt bei STM32 Vref.
> Hast du die 0.7V auf dem Vref oder auf einem GPIO, der als ADC Eingang
> verwendet wird gemessen?
>
> ADC_GetConversionValue liefert dir nicht den absoluten Spannungswert,
> sondern einen relativen Wert zur Referenz.

Ich habe diesen Wert am ADC am GPIO gemessen also an den BNC eingängen 
am Board.


Wie wird dieser berechnet ? Relativ_V = Absolut/Bit_Spannung ?

von devnull (Gast)


Lesenswert?

Also der ADC auf dem STM32 misst wie der ADC bei AVRs einen relativen 
Wert zu einer Referenz.
Welche Referenz du verwenden solltest hängt von der Spannung die du 
messen willst und von der Genauigkeit ab.
Die absolute Spannung musst du selber berechnen. Der ADC weiß ja selber 
den Spannungswert nie, er vergleicht nur die Referenz mit deinem ADC 
Input.
Du brauchst also eine möglichst genaue Referenzspannung (die deinem 
Eingangsspannungsbereich entspricht).
Die Referenz kann bei STM32 definiert werden (intern, extern-bei manchen 
STM32 sogar differentiell,..). Daher ist es auch möglich über den Vref 
Pin eine andere Referenzspannung, als die 1.2V (welche die interne 
Referenz bietet) anzulegen. Wenn deine zu messende Spannung von 0-1.2V 
geht hast du eben bei 1.2V Referenz die best möglichste Genauigkeit mit 
dem eingebauten ADC (es sind nicht ganz exakt diese Werte, näheres im 
Datenblatt bzw. Referencesheet). Wenn deine Eingangsspannung bis zu 3V 
sind, solltest du am Vref für eine Referenz von 3V sorgen und nimmst die 
externe Referenz als Vergleich.
Somit gilt 
AbsoluteSpannung=(Referenzsspannung/(2^ADCAuflösung))*ADC_GetConversionV 
alue()
Bei den meisten STM32 Discovery-Boards ist der Vref Pin in etwa auf Vcc 
(3V).

von devnull (Gast)


Lesenswert?

Tomi schrieb:
> Beispiel:
> Spannungsgenarator -> ADC
> 0.2 V -> 244
> 0.3 V -> 349
> 0.5 V -> 667
> 1 V -> 1233
> 1.7 V -> 2110

Deine gemessenen Werte deuten auf eine 3.3V Referenz hin, da:
(3,3V÷2^12)×244=0,196582031V
(3,3V÷2^12)×349=0,281176758V
(3,3V÷2^12)×667=0,53737793V
(3,3V÷2^12)×1233=0,993383789V
(3,3V÷2^12)×2110=1,699951172V

von Tomi (Gast)


Lesenswert?

Super , danke euch hat mir echt geholfen :)

von Gregor B. (Gast)


Lesenswert?

devnull schrieb:
> Deine gemessenen Werte deuten auf eine 3.3V Referenz hin, da:
> (3,3V÷2^12)×244=0,196582031V
> (3,3V÷2^12)×349=0,281176758V
> (3,3V÷2^12)×667=0,53737793V
> (3,3V÷2^12)×1233=0,993383789V
> (3,3V÷2^12)×2110=1,699951172V

Dir ist schon klar, dass Du die Werte bis auf 1nV angibst bei einer 
Auflösung von 800µV?
Die dritte Stelle hinterm Komma ist schon nicht mehr sicher...

von devnull (Gast)


Lesenswert?

Ja, das sind ja rein rechnerische Werte, aus den gemessenen.
Alleine die Referenz wird nicht sehr genau sein, außerdem dürfte der ADC 
ja auch nur um 1/2 LSB genau sein (falls es ein SAR ist).

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.