Forum: Mikrocontroller und Digitale Elektronik AVR-GCC ADC "Noise Reduction"-Konfiguration unklar mit sleep()


von Björn G. (tueftler)


Lesenswert?

Hi da.

Ich würde gerne das "noise Reduction" Feature des ATMega16 nutzen um die 
störenden PWM Signale bei einem Sample zu unterbinden.

Das Datenblatt ist in dem Punkt leider sehr undurchsichtig und 
Forenbeiträge helfen bisher auch nicht weiter.

Bisher programmiert wurde es so:
1
#include <avr/sleep.h>
2
3
set_sleep_mode(SLEEP_MODE_ADC);
4
5
main()
6
{
7
   sleep_mode();
8
}
9
10
ISR ADC im one shot mode
11
{
12
   ...
13
   ADC wieder anstubsen mit ADCSRA |= (1<<ADSC);
14
}

Muß man den ADCSRA nun direkt vor dem sleep(); Aufruf ausführen oder ist 
es in der ADC-ISR am Ende in Ordnung?
Oder muß man das ganze komplett anders machen?

Noch eine Frage dazu:
1
...stopping the CPU but allowing the ADC, the external...,Timer/Counter2...to continue operating

Wir nutzen derzeit Timer0 und Timer2 für die PWM.
Heißt das nun, das die Timer2 PWM beim Sleep ohnehin gar nicht 
deaktiviert würde?

Irgendwie blicke ich hier nicht durch :)

Könnte mir jemand mal von der Leitung runter helfen?

Gruß
Björn

von Jörg H. (idc-dragon)


Lesenswert?

Wenn ich mich recht erinnere legt der ADC (im Noise-Reduction Modus) 
automagisch erst dann los, wenn die CPU schlafen geht.

Wenn kurz danach ein Interrupt reinbritzelt hat man für diese Messung 
dann wohl Pech gehabt?

Jörg

von Björn G. (tueftler)


Lesenswert?

Man kann dem ADC ja nicht selber sagen das er nun im Noise-Reduction 
Modus läuft.
Das einzige das man machen muß ist den Freerun mode raus machen und das 
ganze als one shot laufen lassen (zumindest so wie ich es verstanden 
habe).
Sehr schade das das Atmel Datenblatt hier große Fragen offen lässt.

Was ich noch machen könnte ist natürlich einen Timer oder einen Zähler 
in der Main loop nutzen mit dem ich geziehlt die PWMs aus schalte, dann 
die ADC anstubse und danach die PWMs wieder aktiviere...

Hoffe es hat noch jemand Erfahrungswerte in dem Mode.

Björn

von Jörg H. (idc-dragon)


Lesenswert?

Ach so, ich dachte da gäbe es ein Konfigurationsbit für diesen Modus.
Davon unabhängig, ich habe das mal so gebaut, daß ich den ADC als letzte 
Aktion in meinem Heartbeat-Interrupt starte. (Danach macht die 
Hauptschleife üblicherweise wieder einen sleep.)

Speziell wenn der ADC vorher aus war braucht er noch etliche Takte, bis 
er tatsächlich loslegt.

Zu deinen Timern, und freihändig ohne Datenblatt: die laufen im 
Idle-Mode weiter, im Deep Sleep nicht. Die neueren Prozessoren haben 
noch ein Power-Reduction-Register, mit dem man nicht benutzte Peripherie 
abschalten kann. Sehr nützliche Sache, so schalte ich die Timer bei 
Bedarf ein und nach Ablauf wieder aus.

Jörg

von Ingo S. (ingo-s)


Lesenswert?

Hi,

ich mache das in einer ADC-Funktion mit Überwachung, ob nicht ein 
Interrupt den "sleep" gestört hat (diese setzen Flag "bIntset" in GPIO 
Register).
Hier für den ATtin44/45, muss für ATMega16 evtl. angepasst werden.

---
int getAdcval (uint8_t nAdc)
{
  ADMUX  = nAdc;            // first set input channel
  do{
    // AD-Wandlung starten - Achtung bei Noise Reduction Mode kein ADSC 
setzen!
    ADCSRA = (1<<ADIE)+(1<<ADEN)+(1<<ADPS2)+(1<<ADPS1);
    intevent &= ~(1<<bIntset);
    MCUCR  |= (1<<SE);        // das startet die AD-Wandlung
    asm volatile ("sleep");      // in Verbindung mit "sleep"
    do{                // noch aktiv wegen fremden Interrupt?
    }while(ADCSRA & (1<<ADSC));
  }while(intevent & (1<<bIntset));  // anderer interrupt - > try again
  return ADC;
}

Gruß Ingo

von Henrik H. (Firma: TU Chemnitz) (heha)


Lesenswert?

Ja das mit dem A/D-Wandler, dem One-Shot-Modus und dem Noise-Reduction 
wird aus dem Datenblatt nicht klar.

Ich habe beim ATtiny13 die Dauer des Noise-Reduction-Mode gemessen und 
dabei Zeiten von unglaublichen 10 ADC-Takten ermittelt, obwohl ich 
ADCSRA.ADATE schön auf 0 gelassen habe und die Wandlung nur mit sleep 
einleite.
Das Testprogramm hatte ein festes Zeitschema, deshalb schwankte diese 
Zeit nicht; Erklärung folgt.

Des Rätsels Lösung: Der A/D-Wandler wird durch das Setzen von 
ADCSRA.ADSC immer in den kontinuierlichen Modus versetzt! Die erste 
Wandlung dauert 25 Takte, jede weitere 13* Takte. Dann kommen immer 
weiter Interrupts vom A/D-Wandler — und damit auch Messergebnisse. Bei 
gesperrten Interrupts, fest eingestelltem ADMUX und konstanter Spannung 
am Portpin fällt das gar nicht weiter auf.

Der Satz "The software may then set ADSC again, and a new
conversion will be initiated on the first rising ADC clock edge." stimmt 
also nicht. Allenfalls wird das Bit bei Interrupt wieder gelöscht.

ADCSRA.ADATE bewirkt demnach nur, dass man mit ADCSRB diesen 
Auto-Trigger auf einige Hardware-Ereignisse legen kann. Leider nicht auf 
Software. Habe ich nicht untersucht.

Richtig ist: sleep im Noise-Reduction-Mode legt alle synchrone Hardware 
lahm, insbesondere Timer, und damit bleiben PWM-Ausgänge stehen.
Und es setzt tatsächlich ADCSRA.ADSC. Was aber, wie oben angegeben, 
wirkungslos im kontinuierlichen Modus ist; genauer: Der 
Sampling-Zeitpunkt ist dann irgendwann davor, und das Umschalten von 
ADMUX oder einem externen Multiplexer ist wirkungslos weil zu spät.

Die beste Lösung, so scheint es mir, ist es, den A/D-Wandler nach einer 
Einzel-Wandlung explizit auszuschalten (ADCSRA.ADEN = 0).
Das bedeutet leider auch, dass der Zeitpunkt der Abtastung stets recht 
spät nach dem Start ist.

* Gemessen habe ich ziemlich exakte 13,5 Takte. Auch im Widerspruch zum 
Datenblatt. Aber wenigstens konstant. Beim ATmega328 waren es jedoch 
genau 13 Takte.

: Bearbeitet durch User
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.