Forum: Mikrocontroller und Digitale Elektronik ATMega328P low power funktioniert nicht


von tobiasm (Gast)


Lesenswert?

Hallo Forum,

ich bin am Verzweifeln mit meinem ATMega328P. Eigentlich möchte ich ihn 
als batteriebetriebenen Sensor arbeiten lassen, schlafen lassen um 
Batterie zu sparen und ab und zu kurz Aufwecken.

Um das Ganze vorzubereiten habe ich einen 328P auf einem Breadboard mit 
16MHz Quartz und 2 Kondensatoren, versorgt über ein 5V Netzteil 
(Minimalkonfiguration).

Ich habe mich mit ordentlich mit den verschiedenen PowerSave Features 
des Mega beschäftigt und wollte jetzt ein kleines Programm schreiben, um 
den uC schlafen zu legen.

Mein Problem ist, es funktioniert einfach nicht. Die Stromaufnahme 
sollte nach ausführen des Codes auf einige uA zurückgehen, tatsächlich 
springt der Stromverbrauch aber nur von 40mA (Test LED an) zu 20mA (Test 
LED aus, CPU off).

Da die Konfiguration auch Arduino kompatibel ist und es da zwei 
interessante Powersave Libraries (jeelib, rocketscream lowPower) gib, 
habe ich es mal damit versucht -> gleiches Verhalten! Zudem habe ich mal 
auf den internen Oszillator umgeschaltet -> ändert auch nichts.

Es muss eigentlich am Mega liegen, aber wie erklärt man sich das? Ich 
habe die Dinger in China bestellt ... eventuell doch kein echter ATMega?

Kann mir bitte jemand helfen und sagen ob ich irgendwas übersehe?

Code:

normaler avr code
1
#include <avr/io.h>
2
#include <avr/power.h>
3
#include <avr/sleep.h>
4
#include <avr/interrupt.h>
5
6
#include <stdio.h>
7
#include <stdlib.h>
8
9
int main()
10
{
11
    PRR = 0xff;
12
    
13
    // Set up a pin for an LED.
14
    DDRB = 0x01;
15
    
16
    // Enable the interrupt as a falling edge.
17
    EICRA = (1<<ISC01);
18
    EIMSK = (1<<INT0);
19
    
20
    while (1)
21
    {
22
        // Go to sleep until interrupted.
23
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
24
        sleep_enable();
25
    
26
        // Must enable or can't wake!
27
        sei();
28
        sleep_cpu();
29
    
30
        // Zzz...
31
    
32
        sleep_disable();
33
        
34
        // Do stuff like toggle a bit.
35
        PINB |= 0x01;
36
    }
37
}
38
39
ISR(INT0_vect)
40
{
41
    // Empty. We don't care - we just want it to wake the CPU!
42
}

arduino code
1
#include "test.h"
2
#include "LowPower.h" //rocketscream library
3
4
5
void setup() {
6
  // initialize digital pin LED_BUILTIN as an output.
7
  pinMode(3, OUTPUT);
8
}
9
10
// the loop function runs over and over again forever
11
void loop() {
12
  digitalWrite(3, HIGH);   // turn the LED on (HIGH is the voltage level)
13
  delay(5000);                       // wait for a second
14
  digitalWrite(3, LOW);    // turn the LED off by making the voltage LOW
15
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
16
}

Danke!

von Thomas E. (thomase)


Lesenswert?

tobiasm schrieb:
> eventuell doch kein echter ATMega?

Nun mal keine Verschwörungstheorien.

Hast du bei deinen Tests auch deinen Programmer abgezogen?

von S. Landolt (Gast)


Lesenswert?

Sind da nicht sämtliche Eingänge freischwebend? Also auf jeden Fall 
Pullups ein- oder auf Ausgänge umschalten.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Und das Datenblatt lesen - hier mal aus dem Mega328 DB:
" Unconnected pins
If some pins are unused, it is recommended to ensure that these pins 
have a defined level. Even though most of the digital inputs are 
disabled in the deep sleep modes as described above, floating inputs 
should be avoided to reduce current consumption in all other modes where 
the digital inputs are enabled (Reset, Active mode and Idle mode). The 
simplest method to ensure a defined level of an unused pin, is to enable 
the internal pull-up. In this case, the pull-up will be disabled during 
reset. If low power consumption during reset is important, it is 
recommended to use an external pull-up or pull-down. Connecting unused 
pins directly to VCC or GND is not recommended, since this may cause 
excessive currents if the pin is accidentally configured as an output."

Also alle Pins mit Pegel vorbelegen und nicht nur die benötigten. Edit:
Herr Landolt war schneller.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Das hier:

tobiasm schrieb:
> // Do stuff like toggle a bit.
>         PINB |= 0x01;


Toggle'd nicht nur ein Bit, sondern je nach aktuellem Spannungslevel am 
PortB auch mehrere. (und schaltet damit ggfs. die Pull-Ups aus)

Zum Togglen wäre

PINB = 0x01;

ausreichend.


und zum Aufwachen aus dem PWR_DOWN brauchst du einen LEVEL-Interrupt, 
keinen Edge-Triggered.
Aber das würde nur zuwenig Stromverbrauch erklären, nicht zuviel.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Εrnst B. schrieb:
> Toggle'd nicht nur ein Bit, sondern je nach aktuellem Spannungslevel am
> PortB auch mehrere. (und schaltet damit ggfs. die Pull-Ups aus)

Doch. Nur eins.
1
   PINB |= (1 << 0);
2
 49c:  b0 9a         sbi  0x16, 0  ; 22

Während der am Ziel vorbeigeht:

Εrnst B. schrieb:
> Zum Togglen wäre
>
> PINB = 0x01;
>
> ausreichend.
1
   PINB = (1 << 0);
2
 49c:  81 e0         ldi  r24, 0x01  ; 1
3
 49e:  86 bb         out  0x16, r24  ; 22

Εrnst B. schrieb:
> und zum Aufwachen aus dem PWR_DOWN brauchst du einen LEVEL-Interrupt,
> keinen Edge-Triggered.

Mit Pinchange geht es auch. Aber mit INTx nur mit Level.

von Εrnst B. (ernst)


Lesenswert?

Thomas E. schrieb:
> Doch. Nur eins.

Haarspalterei:
Nur wegen eingeschalteter Optimierung, die hier etwas über's Ziel 
hinausschießt.
Bei vollem Read-Modify-Write würden (zusätzlich zu Bit 0) alle 
PORTB-Outputs getoggle'd, die gerade im PINB als HIGH gelesen werden.

Code, der abhängig von der Compiler-Optimierungsstufe mal geht, und mal 
komplett falsch ist, ist mir suspekt.



Thomas E. schrieb:
> PINB = (1 << 0);
>  49c:  81 e0         ldi  r24, 0x01  ; 1
>  49e:  86 bb         out  0x16, r24  ; 22

Ist exakt richtig. BIT0 im PORTB wird getoggled. Unabhängig von 
Compilersettings.


Thomas E. schrieb:
> Mit Pinchange geht es auch. Aber mit INTx nur mit Level.

-> Siehe:
tobiasm schrieb:
>  EICRA = (1<<ISC01);

Er versucht es mit Falling Edge am INT0.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Εrnst B. schrieb:
> Nur wegen eingeschalteter Optimierung, die hier etwas über's Ziel
> hinausschießt.

Die schießt nicht übers Ziel hinaus, sondern ist die einzige 
Möglichkeit, dieses Feature in C einzusetzen. Einmal abgesehen von 
Inline-Asm.

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Thomas E. schrieb:
> Die schießt nicht übers Ziel hinaus, sondern ist die einzige
> Möglichkeit, dieses Feature in C einzusetzen.

Quatsch. Das "PINB = (1 << 0);" funktioniert auch. Es muss nur eine 1 in 
das jeweilige Bit geschrieben werden. Das muss nicht zwangsläufig mit 
sbi geschehen, ein out tut's auch.

von Thomas E. (thomase)


Lesenswert?

Stefan E. schrieb:
> Quatsch.

Quatsch ist das, was du schreibst.

Es geht nicht darum, was auch funktioniert, sondern was am effektivsten 
ist. Und das ist das Toggeln eines Portbits mit einem sbi aufs PIN-Reg.. 
Den erhält man aber nur mit OR bei eingeschalteter Optimierung. Da dann 
nämlich kein RMW ausgeführt wird.

von Stefan E. (sternst)


Lesenswert?

Thomas E. schrieb:
> Es geht nicht darum, was auch funktioniert, sondern was am effektivsten
> ist.

Nö, denn du schriebst "einzige Möglichkeit", und nicht etwa "effektivste 
Möglichkeit"

von tobiasm (Gast)


Lesenswert?

Vielen Dank für eure rege Beteiligung, finde ich super.

Habe jetzt alle nicht belegten Pins auf Eingang gestellt und die 
internen Pullups aktiviert -> ändert nicht viel, jetzt habe ich 18,8mA 
im "Tiefschlaf".

Irgendwas stimmt da doch gewaltig nicht...

von S. Landolt (Gast)


Lesenswert?

> Irgendwas stimmt da doch gewaltig nicht...
In der Tat.

Mir ist unklar, was auch schon Ernst B. anmerkte, wie überhaupt der 
Interrupt ausgelöst und damit in der Folge die LED umgeschaltet werden 
kann, denn auf INT0 kommt man nur mit einem Level-Interrupt aus dem 
Power-Down-Mode heraus, eingestellt wurde aber fallende Flanke.
Rund 20 mA lassen sich tatsächlich nicht mit freischwebenden Eingängen 
erklären, also wie steht es mit dem Hinweis von Thomas Eckmann bezüglich 
des abgehängten Programmiergeräts?

von S. Landolt (Gast)


Lesenswert?

Pardon - das mit der Flanke auf INT0 und Power-Down-Mode scheint doch zu 
funktionieren, ich habe es eben ausprobiert; sehe ich so zum ersten Mal.
  Wie auch immer - ich komme hier auf unter 0.2 uA.

von Ingolf (Gast)


Lesenswert?

Hast du eventuell den Watchdog per Fuse aktiviert? Was passiert ohne den 
Wake-Interrupt? Also INT0 mal nicht "scharf schalten".

von tobiasm (Gast)


Lesenswert?

Der ISP Programmer ist natürlich abgesteckt ;)

Fuses lauten: H:D9, L:42, E:FF

von S. Landolt (Gast)


Lesenswert?

Und nochmals pardon - freischwebende Eingänge gibt es im Power-Down-Mode 
gar nicht, das hatte mir hier mal jemand erklärt, aber mein 
Gedächtnis...

siehe Datenblatt '18.2.5. Digital Input Enable and Sleep Modes'

von tobiasm (Gast)


Lesenswert?

Kann es sein, dass der externe Resonator die 18mA zieht?

von Thomas E. (thomase)


Lesenswert?

Stefan E. schrieb:
> Nö, denn du schriebst "einzige Möglichkeit"

Vielleicht solltest du auch mal über den Zusammenhang, in dem ich das 
geschrieben habe, nachdenken und nicht einfach blöd drauflosschreiben.

Thomas E. schrieb:
> Die schießt nicht übers Ziel hinaus, sondern ist die einzige
> Möglichkeit, dieses Feature in C einzusetzen. Einmal abgesehen von
> Inline-Asm.

Extra für dich:

Dabei geht es darum, daß mit dem sbi ein Pin getoggelt wird. Das ist die 
einzige Möglichkeit, diesen effektiven Befehl einzusetzen. Außer mit 
Inline-Asm. Damit geht es auch.

von Ingolf (Gast)


Lesenswert?

Der Quarz wird mit den Einstellungen gar nicht benutzt. Ob der dann 
allerdings Strom zieht, wage ich zu bezweifeln (die Pins sind ja nicht 
high).

Ich kann mir gerade nur vorstellen, dass dein INT0 ständig getriggert 
wird oder so.

von Ingolf (Gast)


Lesenswert?

PS: Achso, aufwachen aus Power-down geht nur mit INT0 level interrupt, 
nicht edge. Eventuell ist das ein Nebeneffekt, wenn man das nicht 
beachtet. Dann müsstest du natürlich noch den Pullup am entsprechenden 
Pin einschalten, sonst ist er ja dauernd low...

von S. Landolt (Gast)


Lesenswert?

> ... L:42 ...
Also: auf dem Steckbrett sitzt der ATmega328P mit 2 GND- und 2 
Vcc-Verbindungen, zusätzlich die LED mit Widerstand sowie vermutlich ein 
Widerstand an INT0, an welchem auch der Taster angeschlossen ist - sonst 
nichts. In der Vcc-Leitung hängt das Amperemeter - zeigt bei mir 0.1 uA 
(genauer geht's nicht).

von tobiasm (Gast)


Lesenswert?

ok, neues Beispiel - bisschen leichter zu handhaben, da per LED 
kontrolliert wird was los ist:
1
void setup(void)
2
{
3
    DDRD &= B00000011;       // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is
4
    DDRB = B00000000;        // set pins 8 to 13 as inputs
5
    PORTD |= B11111100;      // enable pullups on pins 2 to 7
6
    PORTB |= B11111111;      // enable pullups on pins 8 to 13
7
    pinMode(13,OUTPUT);      // set pin 13 as an output so we can use LED to monitor
8
    digitalWrite(13,HIGH);   // turn pin 13 LED on
9
}
10
                //
11
12
13
void pinInterrupt(void)
14
{
15
    detachInterrupt(0);
16
}
17
18
void sleepNow(void)
19
{
20
    // Set pin 2 as interrupt and attach handler:
21
    attachInterrupt(0, pinInterrupt, LOW);
22
    delay(100);
23
    //
24
    // Choose our preferred sleep mode:
25
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
26
    //
27
    // Set sleep enable (SE) bit:
28
    sleep_enable();
29
    //
30
    // Put the device to sleep:
31
    digitalWrite(13,LOW);   // turn LED off to indicate sleep
32
    sleep_mode();
33
    //
34
    // Upon waking up, sketch continues from this point.
35
    sleep_disable();
36
    digitalWrite(13,HIGH);   // turn LED on to indicate awake
37
}
38
void loop(void)
39
{
40
    // Stay awake for 1 second, then sleep.
41
    // LED turns off when sleeping, then back on upon wake.
42
    delay(1000);
43
    sleepNow();
44
}

gleiches Verhalten, LED an: 36mA, LED aus (power down): 18,8mA. Danach 
PIN2 auf low, LED geht an und zieht wieder 36mA.

von S. Landolt (Gast)


Lesenswert?

Mit Low-Fuse-Byte=$42 beträgt der Strom bei 5.0 V ohne sleep ca. 1 mA 
- mir ist völlig unklar, woher die knapp 20 kommen.

von Ingolf (Gast)


Lesenswert?

Zieh mal deinen Quarz und die entsprechenden Kerkos ab. Die werden eh 
nicht benutzt.

von S. Landolt (Gast)


Lesenswert?

> Zieh mal deinen Quarz
Wenn er den noch drauf hat trotz meines Beitrags von 20:01, dann ... 
möchte ich mich verabschieden.

von tobiasm (Gast)


Lesenswert?

S. Landolt schrieb:
> Mit Low-Fuse-Byte=$42 beträgt der Strom bei 5.0 V ohne sleep ca. 1
> mA
> - mir ist völlig unklar, woher die knapp 20 kommen.

Dann ist meine Verschwörungstheorie doch richtig und der China ATMega 
ist halt doch nur ein Nachbau mit einem wesentlich höheren 
Stromverbrauch.
Ich kanns nicht ändern, der Chip hängt nackt ohne Resonator auf dem 
Breadboard. Jetzt kann höchstens noch mein Messgerät im Eimer sein :/

von S. Landolt (Gast)


Lesenswert?

Wie hoch ist die Stromaufnahme des Steckbretts ohne Controller?

von S. Landolt (Gast)


Lesenswert?

Nanu, das Heraushebeln eines ATmega328P-PU aus einem Steckbrett dauert 
doch nur ein paar Sekunden; die Frage war durchaus ernst gemeint.

von Manfred (Gast)


Angehängte Dateien:

Lesenswert?

tobiasm schrieb:
> Die Stromaufnahme
> sollte nach ausführen des Codes auf einige uA zurückgehen, tatsächlich
> springt der Stromverbrauch aber nur von 40mA (Test LED an) zu 20mA (Test
> LED aus, CPU off).
Ich hoffe, da hängt nicht noch weitere Peripherie dran.

Mit der lowpower.h (Anhang) bekomme ich auf einem China ProMini um 7µA, 
AT328 bei 5V Versorgung und 16MHz. Der wacht alle x-Sekunden auf, zählt 
einen hoch und geht wieder schlafen. Natürlich habe ich den 
Spannungsregler und die LED auf der Versorgungsleitung abgelötet.

Mit den angehängten .ino macht er alle 8s die LED13 an, dabei fließen um 
17mA.

Zu lesen gibt es das dort: 
http://www.home-automation-community.com/arduino-low-power-how-to-run-atmega328p-for-a-year-on-coin-cell-battery/

Wie Dir schon geschrieben wurde, geht natürlich noch weniger - mir ist 
es erstmal egal, weil meine Versorgung um 10Ah hat und weitere Last dran 
hängt.

von Ingolf (Gast)


Lesenswert?

Naja, ist vielleicht ein ganz einfacher, blöder Fehler und dem OP 
peinlich... aber es wäre bestimmt für andere auch hilfreich, zu 
erfahren, wie es weitergegangen ist. Letztlich sind es ja ziemlich oft 
solche Sachen...

von Karl M. (Gast)


Lesenswert?

Guten Morgen,

das beste ist, wenn zwei Ausgänge, USB-TX <--> AVR RX gegeneinander auf 
einem Arduinoboard arbeiten !
1
DDRD &= B00000011;       // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is
Wie kommt man auf diese Idee ?

von Εrnst B. (ernst)


Lesenswert?

Thomas E. schrieb:
> Die schießt nicht übers Ziel hinaus, sondern ist die einzige
> Möglichkeit, dieses Feature in C einzusetzen.

Ist jetzt zwar Off-Topic, aber nochmal zur Klarstellung, was ich meine:
1
  PINB=0x00; // Toggle nothing
2
  PINB=0x01; // Toggle PB0
3
  PINB=0x03; // Toggle PB0 and PB1
verhalten sich, unabhängig von Compilerversion und Optimierungsstufe, 
immer so wie im Datenblatt angegeben.

Hingegen
1
  PINB|=0x00; // Toggle "random" Pins
2
  PINB=PINB;  // Same.
3
  PINB|=0x01; // Toggle only PB0 with -Ox, Toggle PB0+random with -O0
4
  PINB|=0x03; // Toggle PB0, PB1 and random other bits.

Verhält sich nur in einer Version so wie sich der Programmierer das 
vermutlich gedacht hat, und das auch erst seit GCC Version 2.X?, als die 
SBI-Optimierungen dazugekommen sind.

Welches nun das "Richtige" oder "Falsche" Verhalten ist, mag jemand mit 
tiefem Verständnis des C-Standards entscheiden, mir jedenfalls ist Code, 
der abhängig vom Optimierungslevel unterschiedliche Bedeutungen hat, 
suspekt.

von Einer K. (Gast)


Lesenswert?

Karl M. schrieb:
> das beste ist, wenn zwei Ausgänge, USB-TX <--> AVR RX gegeneinander auf
> einem Arduinoboard arbeiten !
Wo siehst du 2 Pins gegeneinander arbeiten?

Ich glaube, das hast du dir nur mal ebenso zwischendurch ausgedacht....

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.