AVR-GCC ADC "Noise Reduction"-Konfiguration unklar mit sleep()

OP #1985166
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
OP #1985232
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
#1985290
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
#1985506
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
(Firma: TU Chemnitz) #7603265
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren