ATMega328P low power funktioniert nicht

Gast #4866200
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!
(Firma: matzetronics) #4866225
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.
#4866233
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.
#4866258
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.
#4866264
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.
Gast #4866320
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...
Gast #4866334
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?
Gast #4866350
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.
Gast #4866365
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'
#4866382
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.
Gast #4866387
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.
Gast #4866394
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...
Gast #4866395
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).
Gast #4866398
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.
Gast #4866437
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 :/
Gast #4866504
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.
Angehängte Dateien:
Gast #4866677
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...
Gast #4866934
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 ?
#4866967
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.

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