getadc() bringt manchmal falsches Ergebnis

  • 1
  • 2
  • 3
  • 4
  • Page 1 of 4
bovist
Benutzer
Avatar
Gender:
Age: 64
Homepage: shop.keyboardpartn…
Posts: 34
Registered: 03 / 2006
Subject:

getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 14:31  ·  #1
Hallo,

habe ein mysteriöses, sporadisches, aber reproduzierbares Problem:

Meine ATmega32-Anwendung verwendet ADC-Ports PA2 und PA3, die über RS232 abgefragt werden können. Wenn die Spannungen an beiden Ports stark unterschiedlich sind, liefern die getadc(3) und getadc(4)-Abfragen so etwa alle 100..200 Messungen (Zeit zwischen den Abfragen über die Serielle 20..50 ms) ein falsches Ergebnis: Beim kleineren Wert in positiver Richtung, beim größeren Wert in negativer Richtung. Sind beide Eingangsspannungen gleich, treten keine (oder nur vernachlässigbare) Störungen auf.

Mit importierter Integrate-Funktion (,int2) wirds massiv schlimmer. Systick auf 1 oder 10 ms -- kein Unterschied. Mittlere ADC-Vorteiler bringen leichte Besserung, in den Extremen (8, 128) wird es wieder schlimmer.

Das Problem tritt in verschiedenen Schaltungs-Designs (c't-Lab :oops: ), sowohl in QFP- als auch DIL-Version, auf; mangelnde Abblockung der Vcc- und AVcc-Spannungen kann ich ausschließen -- hat alles nichts gebracht. Ich sperre keine Interrupts, als einzige Besonderheit werden PA0 und PA1 als Inkrementalgeber-Ports benutzt.

Offensichtlich ein Problem des ATmega-internen Multiplexers (Settling Time?) oder des Treibers -- den möchte ich aber nicht vorschnell beschuldigen. Deshalb meine Frage: Hat jemand schon einmal diese Phänomen beobachtet und womöglich sogar eine Lösung parat?

cm

(hier noch die Defines)

Quote

Import SysTick, TWImaster, ADCport, SerPort, IncrPort4, LCDmultiPort;

from System import float;

Define
ProcClock = 16000000; {Hertz}

TWIpresc = TWI_BR400;

LCDmultiPort = I2C_TWI;
LCDTYPE_M = 44780; // 44780 oder 66712;
LCDrows_M = 2; //rows
LCDcolumns_M = 8; //chars per line
IncrPort4 = PinA, 1, 32; // pin-reg used, channels, 16 or 32bit integer
IncrScan4 = Timer1, 4; // timer used, scan rate 1kHz (1..100)

SysTick = 1; //msec
SerPort = 38400, Stop1, timeout; {Baud, StopBits|Parity}
RxBuffer = 255, iData;
TxBuffer = 255, iData;

StackSize = $0080, iData;
FrameSize = $0100, iData;

ADCchans = [3..5], iData, int2;
ADCpresc = 64;
bovist
Benutzer
Avatar
Gender:
Age: 64
Homepage: shop.keyboardpartn…
Posts: 34
Registered: 03 / 2006
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 15:17  ·  #2
Nach etwas Forschen jetzt ein Anhaltspunkt: Die Werte sind im Fehlerfall VERTAUSCHT, d.h. getADC(2) liefert Eingang PA4 statt PA3 und getADC(3) liefert Eingang PA3 statt PA4. Wie das? Multiplexer ab und zu nicht umgeschaltet?

Besonders erstaunlich ist, dass die ",int2"-Option im Fehlerfall einen Mittelwert des richtigen und des falschen Kanals liefert; das war mir oben noch nicht aufgefallen.

cm
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 16:15  ·  #3
Hallo Carsten,

könnte ein Compiler Bug sein, bekannt ist darüber aber noch nichts. Bitte mal
eine kleine App erstellen und gezippt schicken.

rolf
bovist
Benutzer
Avatar
Gender:
Age: 64
Homepage: shop.keyboardpartn…
Posts: 34
Registered: 03 / 2006
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 17:31  ·  #4
Ich mach mal ein Demo-Zip.

Auf jeden Fall funktioniert die Zu-Fuß-und-ohne-Interrupt-Lösung

Code

var
  ADSC10[@ADCSRA, 6]:bit;
...
function GetADC10(myChannel:byte):word;
var
  CurrentADC10:word;
  CurrentADC10lo[@CurrentADC10]:byte;
  CurrentADC10hi[@CurrentADC10+1]:byte;
begin
  ADMUX:=((myChannel-1) and $07);
    asm; // 3 µs warten
      ldi  _ACCB, 10
      ADC10settleLoop1:
      dec _ACCB
      BRNE ADC10settleLoop1
    endasm;
  ADCSRA:=$C7; // enable, start, single shot, no interrupt, div 128
  repeat
  until not ADSC10;
  CurrentADC10lo:=ADCL;
  CurrentADC10Hi:=ADCH;
  return(CurrentADC10);
end;


als Ersatz für getadc() absolut einwandfrei (kostet aber natürlich Rechenzeit für das Warten auf das Wandlungsergebnis, die ich eigentlich nicht übrig habe -- wer hat das schon...).

Ohne die kleine 3us-Zeitschleife für die Settle Time des Mux geht es auch, aber das Messergebnis ist dann etwas nervöser.
bovist
Benutzer
Avatar
Gender:
Age: 64
Homepage: shop.keyboardpartn…
Posts: 34
Registered: 03 / 2006
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 18:06  ·  #5
Vielleicht eine Idee: Kann es sein, dass die ADC-Wandlung im Systick das Wandlungsende-Flag NICHT abfragt, sondern sich blind darauf verlässt, dass die Wandlung seit dem letzten SysTick abgeschlossen sein MÜSSTE? Wenn die Wandlung aber tatsächlich noch gar nicht fertig ist, weil der SysTick zweimal schnell hintereinander kam (z.B. wegen eines längeren Empfangs-Interrupts), kommt das alte Ergebnis, also das des falschen Kanals.

Das wär nicht unbedingt ein Compilerfehler -- man kann ja nicht verlangen, dass der Systick auf die ADC-Wandlung warten muss. Aber es könnte zu dem beschriebenen Fehlverhalten kommen. In meiner Applikation gibt es eine Menge seriell zu senden und zu empfangen, und offensichtlich hängt der Fehler damit zusammen.

cm
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 18:28  ·  #6
Hallo Carsten,

das klingt extrem pausibel. Der SysTick liest immer als erstes den alten Wert
und setzt dann den MUX. Der ADC-Start kommt dann am Ende. Damit hat
der MUX zeit zum stabil werden. Wenn jetzt nach dem ADC-Start der SysTick
sofort wieder zuschlägt, läuft die aktuelle Wandlung noch. Damit wird der alte
Wert wieder gelesen. Möglicherweise hilft hier nur noch den SysTick auf 2msec
verlängern.

rolf
Gunter
Administrator
Avatar
Gender:
Location: Frankfurt Main / Germany
Posts: 1697
Registered: 02 / 2003
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 18:58  ·  #7
Hallo Rolf,

eine Erweiterung derart, dass der ADC im Systick nur dann bearbeitet wird, wenn
das Complete-Flag gesetzt ist wäre keine Alternative?
Ich vermute, dass diese Erweiterung doch relativ ungefährlich (ohne mit
Seiteneffekten rechnen zu müssen) zu implementieren wäre?

Gruss
Gunter
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: getadc() bringt manchmal falsches Ergebnis

 · 
Posted: 11.09.2007 - 19:07  ·  #8
Hallo Gunter,

ungefährlich? Möglicherweise. Da aber im dem Heavy Duty Job "SysTick" dann
bis zu 3mal das Busy gelesen und ausgewertet werden müsste, eine ziemlich
Zeit und Code aufwendige Angelegenheit. Wenn das System so mit Interrupts
dicht ist wie hier, dann macht es auf jeden Fall mehr Sinn den SysTick etwas
zu entspannen, was wiederum zur Entlastung des gesamten Systems beiträgt.

Oder 20MHz AVR oder XMEGA 32MHz....

rolf
  • 1
  • 2
  • 3
  • 4
  • Page 1 of 4
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 14 · Cache Hits: 14   123   137 · Page-Gen-Time: 0.035699s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI