Forum: Mikrocontroller und Digitale Elektronik AVR ADC und differentielle Messung


von Malte _. (malte) Benutzerseite


Lesenswert?

Hallo,
ich finde gerade den Fehler nicht und eine Google Suchen brachte auch 
keine Hinweise.
Die ADC Funktionen sind:
1
static inline void AdStartExtRef(uint8_t prescal, uint8_t channel) {
2
  ADMUX = (1<<REFS0) | (channel & 0x1F); //Select AD channel, use external Aref pin
3
  ADCSRB = (channel >> 2) & 0x08;
4
  ADCSRA = (1 << ADEN) | (1 << ADSC) | (prescal & 0x07); //start conversion
5
}
6
7
static inline uint16_t AdGet(void) {
8
  while (ADCSRA & (1<<ADSC));
9
  return ADC;
10
}

Das ganze liefert wunderbar die gewünschten Werte, wenn ich die ADC 
Werte vor und hinter einem Shunt Widerstand einzeln abfrage
1
uint16_t VccRaw(void) {
2
  AdStartAvccRef(ADPRESCALER, 4); //+5V Vcc
3
  uint32_t ad = AdGet();
4
  return ad;
5
}
6
7
//directly the AD converter value
8
uint16_t DropRaw(void) {
9
  AdStartAvccRef(ADPRESCALER, 5); //+5V - charger drop voltage
10
  uint32_t ad = AdGet();
11
  return ad;
12
}
Ergibt 318 im 1. Fall und 283 für DropRaw.

Aber
1
uint16_t SensorsBatterycurrentGet(void) {
2
  AdStartExtRef(ADPRESCALER, 0x15); //pos: PA5, neg: PA6, gain: 1x (0x2D has the same settings)
3
  uint16_t ad = AdGet();
4
  return ad;
5
}
ist beharrlich 0.
Wieso?
Das ganze läuft auf einem ATtiny861A (der ADC4 ist hier PA5 und ADC5 ist 
hier PA6). Laut Datenblatt müsste mit channel = 0x15 oder 0x2D beides 
mal  ADC4 als positiven und ADC5 als negativer Eingang ausgewählt 
werden.

: Bearbeitet durch User
von Ja (Gast)


Lesenswert?

uint32_t macht keinen Sinn.
Bei älteren AVR muss man 1 ms warten, wenn die interne Referenz 
eingeschaltet wird. Normalerweise verwirft man auch das erste Ergebnis 
nach Mux-Umschaltung. Für beides gibt es Hinweise, die gut versteckt 
sind.

von Malte _. (malte) Benutzerseite


Lesenswert?

Ja schrieb:
> Bei älteren AVR muss man 1 ms warten, wenn die interne Referenz
> eingeschaltet wird. Normalerweise verwirft man auch das erste Ergebnis
> nach Mux-Umschaltung. Für beides gibt es Hinweise, die gut versteckt
> sind.
Ich nutze für die Messung eine externe Referenz mit 2V. Und direkt davor 
nutze ich die selbe Referenz erfolgreich für eine andere Messung, das 
kann es also nicht sein.

Die interne Referenz nutze ich übrigens für die Chiptemperatur und 
funktioniert ebenfalls einwandfrei.
1
static inline void AdStart11Ref(uint8_t prescal, uint8_t channel) {
2
  ADMUX = (1<<REFS1) | (channel & 0x1F); //Select AD channel, use internal 1.1V ref
3
  ADCSRB = (channel >> 2) & 0x08;
4
  ADCSRA = (1 << ADEN) | (1 << ADSC) | (prescal & 0x07); //start conversion
5
}
6
7
//in 0.1°C units
8
int16_t SensorsChiptemperatureGet(void) {
9
  uint32_t ad;
10
  AdStart11Ref(ADPRESCALER, 0x3F);
11
  waitms(1); //setting time of the internal reference
12
  AdGet();
13
  AdStart11Ref(ADPRESCALER, 0x3F);
14
  ad = AdGet();
15
  /* Uncalibrated values (+-10°C) according to the datasheet
16
    230 @ -40°C
17
    300 @ 25°C
18
    370 @ 85°C
19
    Ignoring the middle value, this results in the formula:
20
    Temperature[°C] = (ADC - 230) / 1.12 - 40
21
    Temperature[0.1°C] = ((ADC - 230)*10) / 1.12 - 400
22
    Temperature[0.1°C] = ((ADC - 230)*1000) / 112 - 400
23
    Temperature[0.1°C] = ((ADC - 230)*125) / 14 - 400
24
  */
25
  int32_t temperature = ((ad - 230) * 125UL / 14UL) - 400;
26
  return temperature;
27
}

von c-hater (Gast)


Lesenswert?

Malte _. schrieb:

> Ich nutze für die Messung eine externe Referenz mit 2V. Und direkt davor
> nutze ich die selbe Referenz erfolgreich für eine andere Messung, das
> kann es also nicht sein.
>
> Die interne Referenz nutze ich übrigens für die Chiptemperatur und
> funktioniert ebenfalls einwandfrei.

Mal 'ne Frage nebenbei: um welchen AVR geht es denn eigentlich konkret? 
Gerade im Bereich ADC gibt es da im Detail doch deutliche Unterschiede, 
auch wenn das Grundkonzept immer dasselbe ist.

Meiner Meinung nach hast du das in diesem Thread bisher nirgendwo 
mitgeteilt...

von Malte _. (malte) Benutzerseite


Lesenswert?

c-hater schrieb:
> Mal 'ne Frage nebenbei: um welchen AVR geht es denn eigentlich konkret?

Malte _. schrieb:
> Das ganze läuft auf einem ATtiny861A

:)

von Axel R. (axlr)


Lesenswert?

1
Special care should be taken when changing differential channels. Once a differential channel
2
has been selected the input stage may take a while to stabilize. It is therefore recommended to
3
force the ADC to perform a long conversion when changing multiplexer or voltage reference settings. This can be done by first turning off the ADC, then changing reference settings and then
4
turn on the ADC. Alternatively, the first conversion results after changing reference settings
5
should be discarded.
1
ADCSRA = 0;
2
waitms(1);
3
AdStartExtRef(ADPRESCALER, 0x15);
4
AdStartExtRef(ADPRESCALER, 0x15);
5
uint16_t ad = AdGet();
Was mit dem Bit "BIN" im ADCSRB-Register? (Umschaltung 
bipolar/unipolarer Messmode.) Wenn Du negativ bist, zeigts "0" an? keann 
ich jetzt nicht ausprobieren. Kannst ja einfach 128 zum ADCSRB 
dazuaddieren, so zum Test. Also; Bit7 setzen

von c-hater (Gast)


Lesenswert?

Malte _. schrieb:

>> Das ganze läuft auf einem ATtiny861A

OK, jetz habe ich es auch gefunden. Ist ganz einfach mit dem Suchen, 
wenn man den Suchbegriff schon kennt ;o)

Also ich denke, Axel R. stochert hier in die richtige Richtung mit 
seinem Hinweis. Ansonsten sieht meiner Meinung nach alles korrekt aus.

von Malte _. (malte) Benutzerseite


Lesenswert?

Axel R. schrieb:
> Once a differential channel
> has been selected the input stage may take a while to stabilize. It is
> therefore recommended to
> force the ADC to perform a long conversion when changing multiplexer or
> voltage reference settings. This can be done by first turning off the
> ADC, then changing reference settings and then
> turn on the ADC. Alternatively, the first conversion results after
> changing reference settings
> should be discarded.

Danke, genau das war es. Entweder den ADC vorher ausschalten, oder die 
erste Messung nach dem Umschalten verwerfen. Beides funktioniert :)

von Oliver S. (oliverso)


Lesenswert?

Ja schrieb:
> Für beides gibt es Hinweise, die gut versteckt
> sind.

Na ja, wenn man diesen deutlichen und einfach zu findenden Text im sehr 
übersichtlichen und kurzen AVR Datenblatt schon als „gut versteckt“ 
bezeichnet, was machst du dann erst bei „richtigen“ Mikrocontrollern mit 
mehreren hundert Seite Doku, verteilt auf zig Dokumente?

Oliver

von Malte _. (malte) Benutzerseite


Lesenswert?

Oliver S. schrieb:

> Na ja, wenn man diesen deutlichen und einfach zu findenden Text im sehr
> übersichtlichen und kurzen AVR Datenblatt schon als „gut versteckt“
> bezeichnet, was machst du dann erst bei „richtigen“ Mikrocontrollern mit
> mehreren hundert Seite Doku, verteilt auf zig Dokumente?
Ich muss zugeben, die AVR Doku eher Quergelesen zu haben.

Übersehen und ein Whitepaper draus machen ;)
https://community.nxp.com/pwmxy87654/attachments/pwmxy87654/imx-processors%40tkb/1722/1/Adeneo%20Embedded%20-%20Technical%20Note%20for%20WEC%20i.MX6%20BSP%20Hang%20Issue.pdf

Um daraus zu zitieren:
> This investigation was done over a period of about 8 months, and Adeneo
> Embedded put a committed effort into it to solve the problems. A core team
> of engineers worked fulltime on it while an extended group of engineers was
> available to support where needed (test, build, debugging, applications,..).
> The problems we had to solve here were not trivial;

Das Verhalten des Prozessors stand so übrigens auch in den ~20000 Seiten 
Doku. War dort ein Zweizeiler.

von Oliver S. (oliverso)


Lesenswert?

Malte _. schrieb:
> Das Verhalten des Prozessors stand so übrigens auch in den ~20000 Seiten
> Doku. War dort ein Zweizeiler.

Eben. DAS nenne ich versteckt ;)

Oliver

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.