Forum: Mikrocontroller und Digitale Elektronik RFM12B sleep mode


von Jens K. (mister232)


Lesenswert?

Hallo Leute,
ich würde gerne einen an meinem ATmega32 angeschlossenen RFM12B in den 
sleep mode bringen und anschließend auch den ATmega32 schlafen lassen. 
Wenn dann der wakeup Timer des RFM12B anschlägt, sollen beide wieder 
aufwachen, kurz etwas machen und wieder schlafen.
Ich habe nun schon etliche Beispiele gefunden, aber irgendwie will da 
nichts so richtig laufen.
Meine Funktion um schlafen zu gehen:
1
 
2
3
// Function to set the microcontroller to sleep to save energy and wait for request for temperature
4
void goToSleep(void)
5
{
6
  // Disable AC
7
  ACSR = (1<<ADC);
8
  // Set RFM12B to sleep with wake-up timer
9
  RFM12_sleep();
10
  // Select power down sleep mode
11
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  
12
  // Go to sleep
13
  sleep_mode();
14
}

Die Funktion um den wakeup Timer zu aktivieren (aus einem 
Forumsbeitrag):
1
void RFM12_sleep(void)
2
{
3
    RF12_WRT_CMD(0xE000 | 0x0A00 | 2);
4
    RF12_WRT_CMD(0x8201);
5
    RF12_WRT_CMD(0x8203);
6
}

Und die Initialisierung des INT0-Interrupts:
1
        // Enable INT0
2
  GICR|=(1<<INT0);
3
  MCUCR|=(1<<ISC01);
4
        MCUCR &= ~(1<<ISC00);

Danach dann noch sei().

Könnte mir das mal einer von euch vernünftig erklären. Also wie ich was 
setzen muss und was was bewirkt. Aus dem Datenblatt werde ich da auch 
nicht so richtig schlau.

von Christian K. (the_kirsch)


Lesenswert?

"Only an External Reset, a Watchdog Reset, a Brown-out Reset, a Two-wire 
Serial Interface address match interrupt, an External level interrupt on 
INT0 or INT1, or an External interrupt on INT2 can wake up the MCU."


Flankenerkennung an INT0 und INT1 geht wohl nicht.

ISC01 und ISC00 müssen 0 sein, damit der AVR über INT0 aufwachen kann.

von Jens K. (mister232)


Lesenswert?

Okay, leider bringt das trotzdem nichts. Der RFM12B geht in den sleep 
mode und wacht nicht wieder auf

von Christian K. (the_kirsch)


Lesenswert?

Hast du einen Externen Pullup an der INT0 Leitung?

von Stefan (Gast)


Lesenswert?

Du mußt das TX Register deaktivieren,
sonst blockiert der Interrupt.
Ausserdem sehe ich nicht wo der Wake up
eingestellt wird.

von Jens K. (mister232)


Lesenswert?

Kannst du mir den erklären, wie man das vernünftig einstellt?

Und nein, ein Pullup ist nicht an INT0, nur der intern im µC

: Bearbeitet durch User
von Felix P. (fixxl)


Lesenswert?

Sind die Interrupts korrekt aktiviert und vor allem auch per sei() 
eingeschaltet?

Bei mir läuft folgende Sequenz erfolgreich, um einen ATtiny85 mit RFM12 
schlafen zu legen:
1
// Pin change interrupt einschalten
2
PCMSK |= 1 << PCINT4;
3
GIMSK |= 1 << PCIE;
4
5
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
6
7
// Alles am RFM ausschalten
8
rfm_cmd(0x8201);
9
10
// Mode einstellen (868 MHz)
11
rfm_cmd(0x8067);
12
13
// nIRQ auf 'high' zwingen
14
while (!(NIRQ_PIN & (1 << NIRQ))) {
15
  if (rfm_cmd(0x0000); & (1 << 15)) {
16
    rfm_cmd(0xB8AA);
17
    rfm_cmd(0xB000);
18
  }
19
}
20
21
rfm_cmd(0xEB01);  // Wake-up in 2,048 Sekunden
22
rfm_cmd(0x8201);  // Alles aus
23
rfm_cmd(0x8203);  // Wake-up ein
24
25
// Interrupt-Flag löschen
26
while (GIFR & (1 << PCIF)) {
27
    GIFR = 1 << PCIF;
28
}
29
30
sleep_enable();
31
sleep_bod_disable();
32
sei();
33
sleep_cpu();
34
35
// Jetzt sind wir im Sleep mode und warten auf den Interrupt
36
    
37
sleep_disable();

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Danke für die ausführliche Antwort. Werde ich nachher mal ausprobieren. 
Noch eine Frage : Was bewirkt der Befehl " Mode einstellen ( 868MHz )"?

von Felix P. (fixxl)


Lesenswert?

Jens K. schrieb:
> Was bewirkt der Befehl " Mode einstellen ( 868MHz )"?

Man deaktiviert das Tx-Register (Bit 7), indem man Bit 7 auf 0 setzt - 
das ist genau das, was Stefan gemeint hat.

von Jens K. (mister232)


Lesenswert?

Es funktioniert mit deinem Code. Vielen dank!

von Jens K. (mister232)


Lesenswert?

Jetzt aber noch eine andere Frage: Wenn ich den ATMEGA32 und den RFM12B 
schlafen schicke (30s), dann werden immernoch 5,5mA gezogen. Ich habe 
mal nur den ATMEGA32 laufen lassen (mit dem kompletten Programm) und 
musste feststellen, dass dieser im Sleep Mode nicht unter 5mA geht. Kann 
ich da noch was einsparen? AC ist aus, SPI auch, interne pullups 
deaktiviert.

von Felix P. (fixxl)


Lesenswert?

Wie versorgst du die Schaltung? Direkt über Batterien oder per Regler? 
Viele Spannungsregler benötigen eine Mindestlast, welche einen Strom im 
Bereich dieser 5 mA zieht.

In meinem Fall verwende ich den LP2951, dessen Ruhestrom ist deutlich 
niedriger und ich messe etwa 120 µA im Deep-Sleep-Modus bei meinen 
Messstationen mit ATtiny85, RFM12 und DHT22.

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Ich verwende einen LM317. Aber wie gesagt, wenn ich nur den ATMEGA32 aus 
der Schaltung nehme, das Programm drauf spiele und ihn aus einem 
Netzteil direkt mit 3,3V versorge, dann zeigt mir das Messgerät zwischen 
Netzteil und VCC des uC trotzdem 5mA an.

von c-hater (Gast)


Lesenswert?

Jens K. schrieb:

> Jetzt aber noch eine andere Frage: Wenn ich den ATMEGA32 und den RFM12B
> schlafen schicke (30s), dann werden immernoch 5,5mA gezogen. Ich habe
> mal nur den ATMEGA32 laufen lassen (mit dem kompletten Programm) und
> musste feststellen, dass dieser im Sleep Mode nicht unter 5mA geht. Kann
> ich da noch was einsparen?

Ganz sicher, aber schon die Analyse erfordert zwingend das vollständige 
Verständnis der kompletten Außenbeschaltung des Controllers, 
einschließlich der Stromversorgung.

D.h.: Für reine Nachbauer von Schaltungen ist hier schon Ende der 
Fahnenstange...

Bei der Behebung der Mißstände ist dann zusätzlich zu den 
Elektronikkenntnissen meist auch noch umfassende Kenntnis des 
Datenblatts des Controllers und der genauen Funktion der verwendeten 
Softwaremodule erforderlich, um entscheiden zu können, ob ein Problem 
per Softwareänderung gelöst werden kann, oder ob die Hardware geändert 
werden muß.

D.h.: für die meisten C-ler (die C nur benutzen, weil es dafür so viele 
Vorlagen für's Copy&Paste gibt) ist dann spätestens hier Ende der 
Fahnenstange...

Naja, und für den kleine Rest, der die Fahenstange überfliegt, ist so 
eine Optimierung immerhin noch viel Arbeit. Insbesondere eine, die eine 
vollständige Dokumentation von Hard- und Software als unbedingte 
Voraussetzung erfordert. Mindestens vollständiger Schaltplan und 
vollständiger Quelltext sind das absolute Minimum, was hier nötig ist, 
ansonsten braucht man erst garnicht anfangen...

von Felix P. (fixxl)


Lesenswert?

Jens K. schrieb:
> Ich verwende einen LM317.
Der gehört zur zitierten Gattung, welche eine Mindestlast (Minimum Load 
Current) im Bereich von 5mA ausweisen.

Jens K. schrieb:
> Aber wie gesagt, wenn ich nur den ATMEGA32 aus
> der Schaltung nehme, das Programm drauf spiele und ihn aus einem
> Netzteil direkt mit 3,3V versorge, dann zeigt mir das Messgerät zwischen
> Netzteil und VCC des uC trotzdem 5mA an.
Wie ist der ATMEGA32 in diesem Szenario genau beschaltet? Sind sowohl 
VCC als auch AVCC verbunden, ebenso alle GNDs und was ist mit dem 
Reset-Pin?

von N.G. (Gast)


Lesenswert?

ACSR = (1<<ADC);
müsste das Bit nicht ACD heißen? Ich hab jetzt nicht nachgeschaut, wäre 
aber mMn logischer

von Jens K. (mister232)


Lesenswert?

Zur Beschaltung: VCC und beide GND sind verbunden AVCC nicht. AVCC muss 
doch auch nur für den ADC beschaltet werden.

Ich dachte eher daran, ob es interne Module gibt, die noch weiter laufen 
und welche man zum Stromsparen abschalten könnte. Es ist mein erstes, 
bei dem ich mit Sleep arbeite um Strom zu sparen, daher kenne ich mich 
da noch nicht so aus und wäre dankbar für ein paar Tipps ;-)

von Felix P. (fixxl)


Lesenswert?

Dazu steht einiges ab Seite 34 im Datenblatt. Unter anderem: Der 
Analog-Digital-Converter sollte vor dem Aktivieren des Sleep-Modes 
ausgeschaltet werden (ADEN-Bit in ACSRA auf 0).

Auch der Hinweis von N.G. ist richtig. Du meinst bestimmt das ACD-Bit 
(Analog Comparator Disable), welches du auf 1 setzen willst, ADC ist das 
16-bit-Pseudo-Register mit den ADC-Ergebnissen.

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Okay, danke für den Tipp. Ich habe jetzt folgenden Code zum abschalten 
der Peripherie geschrieben:
1
void disable_Peripherals(void)
2
{
3
  // Disable pull-up on INT0
4
  PORTD &= ~(1<<PD2);
5
  
6
  // SPI-Ports as inputs
7
  DDRB &= ~((1<<PB4) | (1<<PB5) | (1<<PB7));
8
  
9
  // Disable SPI
10
  SPCR &= ~(1<<SPE);
11
  
12
  // Disable ADC
13
  ACSR &= ~(1<<ADEN);
14
}

Die Fuses für Brown-Out Detector und JTAG sind ebenfalls deaktiviert. 
Leider gibt es keine Änderung.

Nochmal genauer zur aktuellen Beschaltung:
- VCC mit 100nF an VCC
- GNDs mit GND verbunden
- 8MHz Quarz mit 22pF Kondensatoren am entsprechenden Eingang
- 10k nach VCC und 100nF nach GND an Reset

Ansonsten ist nichts mit dem Mikrocontroller verbunden. Versorgt wird 
er, wie bereits erwähnt, aus einem Netzteil mit 3,3V und ich messe den 
Strom zwischen  dem Netzteil und dem Spannungseingang des Steckboards, 
auf welchem der Mikrocontroller aktuell steckt.

von Jens K. (mister232)


Lesenswert?

Also er zieht immernoch 5mA :-(

von Felix P. (fixxl)


Lesenswert?

Jens K. schrieb:
> Okay, danke für den Tipp. Ich habe jetzt folgenden Code zum abschalten
> der Peripherie geschrieben:
>
>
1
> void disable_Peripherals(void)
2
> {
3
>   // Disable pull-up on INT0
4
>   PORTD &= ~(1<<PD2);
5
> 
6
>   // SPI-Ports as inputs
7
>   DDRB &= ~((1<<PB4) | (1<<PB5) | (1<<PB7));
8
> 
9
>   // Disable SPI
10
>   SPCR &= ~(1<<SPE);
11
> 
12
>   // Disable ADC
13
>   ACSR &= ~(1<<ADEN);
14
> }
15
>
>
> Die Fuses für Brown-Out Detector und JTAG sind ebenfalls deaktiviert.
> Leider gibt es keine Änderung.
>
> Nochmal genauer zur aktuellen Beschaltung:
> - VCC mit 100nF an VCC
> - GNDs mit GND verbunden
> - 8MHz Quarz mit 22pF Kondensatoren am entsprechenden Eingang
> - 10k nach VCC und 100nF nach GND an Reset
>
> Ansonsten ist nichts mit dem Mikrocontroller verbunden. Versorgt wird
> er, wie bereits erwähnt, aus einem Netzteil mit 3,3V und ich messe den
> Strom zwischen  dem Netzteil und dem Spannungseingang des Steckboards,
> auf welchem der Mikrocontroller aktuell steckt.

In ACSR gibt es kein Bit ADEN. ACSR enthält Einstellungen für den 
Komparator. Den schaltet man ab mit:
1
 ACSR |= (1 << ACD);

ADEN schaltet den ADC ein und aus und befindet sich im Register ADCSRA 
(das D hatte ich oben vergessen, daher wohl die Verwirrung!). Hier ist 
die Ausschalt-Einstellung:
1
ADCSRA &= ~(1 << ADEN);

Da ACD und ADEN beide nur Makros sind, die gleichbedeutend für die Zahl 
7 stehen, und man den Komparator durch das Setzen eines Bits, den ADC 
aber durch das Löschen eines Bits ausschaltet, bewirkt deine bisherige 
Einstellung genau das Gegenteil des gewünschten Effekts, nämlich dass 
der Komparator eingeschaltet wird/bleibt, während für den ADC keine 
Änderung vorgenommen wird.

AVCC sollte man immer anschließen, damit wird nicht nur der ADC 
gespeist, sondern grundsätzlich PORTA (Datenblatt S. 5 unten). Hier 
ebenfalls einen 100nF-Kondensator nahe am Pin vorsehen, genauso von AREF 
(bleibt ansonsten unbeschaltet) nach GND.

Den Pullup am Interrupt-Pin solltest du in deiner Testschaltung nicht 
deaktivieren - oder hast du irgendeine Quelle bzw. einen externen Pullup 
dran hängen, um den Pin fest auf einem bestimmten Pegel zu halten? Der 
Zustand eines offenen Eingangs ist nicht definiert und irgendwelche im 
Raum befindlichen Felder können ihn dann nach Herzenslust zwischen den 
verschiedenen Potentialen her und her wackeln lassen, was zum Aufwachen 
führen kann.

Figure 150 im Datenblatt zeigt, dass der Controller bei 8 MHz und 3,3 V 
im aktiven Zustand in etwa die von dir gemessenen 5 mA ziehen sollte. Es 
sieht für mich also ganz so aus, als ob er nicht wirklich schlafen geht. 
Im Power Down Mode liegt die Stromaufnahme typischerweise unter 1 µA 
(Figure 160) also Faktor 5000 darunter.

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Okay, ich habe nun mal ein Programm geschrieben, welches eine LED 
blinken lässt und den ATmega32 dann in den Sleep Mode schickt und siehe 
da... 15µA. Es scheint also irgendein Fehler im Programm zu sein, denn 
den Aufbau habe ich beibehalten.

von Felix P. (fixxl)


Lesenswert?

Jens K. schrieb:
> Okay, ich habe nun mal ein Programm geschrieben, welches eine LED
> blinken lässt und den ATmega32 dann in den Sleep Mode schickt und siehe
> da... 15µA. Es scheint also irgendein Fehler im Programm zu sein, denn
> den Aufbau habe ich beibehalten.

Das ist doch mal ein schönes Zwischenresultat. Dann lade doch mal deinen 
aktuellen Programmcode hoch, irgendwo in der Konfiguration wird sich der 
Bug schon versteckt haben.

von Jens K. (mister232)


Lesenswert?

Ja, und ich habe ihn gefunden. Hatte den Sleep Mode vom RFM12B falsch 
eingestellt. Als zweite Fehlerursache bin ich nun tatsächlich auf den 
Spannungsregler gestoßen (also bei der richtigen Schaltung, nicht auf 
dem Steckbrett). Auf dem Steckbrett, ohne Spannungsregler, komme ich 
nämlich auch auf 15µA und bei meinem Aufbau immer noch nur auf 5mA. Gehe 
ich mit der Spannung runter, also statt 9V mal auf 4V, so sinkt der 
Strom auf 3mA. Ich denke ich werde das mal mit dem Spannungsregler 
versuchen, den du vorgeschlagen hattest

von Jens K. (mister232)


Lesenswert?

Ja, es klappt. Ich habe mal den Spannungsregler ausgelötet und direkt 
3,3V eingespeist. Tada... 3µA :-)

Vielen Dank für deine Hilfe Felix!!!!!

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.