Go Down

Topic: Mega 2560 - Power Saving - Strom sparen (Read 17133 times) previous topic - next topic

jim_beam

Hallo Doc-Arduino,

habe bei einem meiner Mega auch mal alle hier beschriebenen Hardwareänderungen vorgenommen (Spannungsregler, Mosfet, 16U2 und Power-LED runter) und kann den Stromverbrauch im SleepMode (fast) bestätigen, mein Wald-und-Wiesen-Multimeter zeigt im mA Messbereich <1mA und im uA Bereich ca. 500uA (BOD war aktiv). Ich bin zufrieden, was das angeht,

NUR leider bekomme ich ihn jetzt nicht mehr Programmiert!  :smiley-fat:

Einen Bootloader bekomme ich noch drauf gebrannt mit einem anderen UNO oder Mega (sowhol mit der Methode von Nick Gammon als auch mit der IDE und einem "Arduino as ISP") , aber keine Sketch! Beim "Arduino as ISP" geht sofort die Rot Fehler LED an beim versuch einen Sketch zu rbennen und in der IDE kommt Timeout Fehlermeldung.

Wobei ich es irgendwie schon (versehentlich) geschafft habe meinen Stromsparsketch zu überschreiben, so dass jetzt die LED13 munter blinkt (ca. 1000ms on, 100ms off, das habe ich so nicht versucht zu proggen).

Und nu steh ich bisschen im Regen...habe das Problem auch hier im Forum schon mal beschreiben, bisher ohne zündende Idee.

Hast Du noch einen Tip für mich? Gibt es vielleicht einen alternativen Code für Arduino as ISP als den aus der IDE (1.6.5 unter Ubuntu 14.04)?

Vielen Dank und schöne Grüße!

Doc_Arduino

#46
Sep 03, 2015, 12:51 pm Last Edit: Sep 03, 2015, 12:53 pm by Doc_Arduino
Hallo,

das ist natürlich total doof. Ich programmiere den kastrierten Mega mittels AVR mkII Programmer. Meiner sieht so aus siehe Anhang. Optisch nicht schön, funktioniert jedoch.



Wie versorgst Du den Mega jetzt mit Spannung?
Vin ist tot gelegt, weil der Spannungsregler fehlt.
USB ist tot, weil T1 fehlt.
Hier hatte ich damals noch eine Brücke bei T1 eingelötet, dass ich die Platine wenigstens über USB noch eine Weile mit Spannung versorgen kann. Mittlerweile ist die USB Buchse auch weg. Die Platine wird jetzt und für immer direkt mit 5V an der Power-Buchsenleiste versorgt. 5V / GND. Dafür bräuchte man die Brücke eigentlich nicht mehr.

Zum programmieren muß aber 5V als Ub anliegen. Messe mal am ICSP nach ob da wirklich 5V vorhanden sind, wenn Du alles verkabelt hast. Pin 2 und 6 und Pin 2 gegen andere Masse.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

jim_beam

Hallo,

vielen dank für die schnelle Rückmeldung.

Ich konnte das Problem lösen/Umgehen dank eines Tipps von combie doch einen UNO-Board zu nehmen, den 328 raus und Serial, Reset und Vcc/GND Verbinden. Klappt erst mal sehr gut!

Über das leere UNO Board habe ich auch Serial Verbindung zum PC zum Debuggen. Ist eine feine Sache den Mega etwas zu modifizieren und damit Batteriebetrieb zu ermöglichen. Danke auch noch mal an alle für diesen Thread hier.

So siehts bei mir aus:



Und mit diesem Test Code ( original von Nick Gammon, leicht Modifiziert für Mega) bekomme ich jetzt 359,2uA (laut meinem Multimeter). Damit bin ich einverstanden.  :)

Test Code für Mega mit waikup by Serial Input:
Code: [Select]
/*
 * Sorce: Nick Gammon http://www.gammon.com.au/forum/?id=11497&reply=8#reply8
 * 03.09.2015:  Edit for Mega250 support and added some Serial Output 4 Debugging
 */

#include <avr/sleep.h>
#include <avr/power.h>

const byte AWAKE_LED = 13;
const byte GREEN_LED = 12;
const unsigned long WAIT_TIME = 3000;

ISR (PCINT2_vect)
{
  // handle pin change interrupt for D0 to D7 here
}  // end of PCINT2_vect

void setup()
{
  pinMode (GREEN_LED, OUTPUT);
  pinMode (AWAKE_LED, OUTPUT);
  digitalWrite (AWAKE_LED, HIGH);
  Serial.begin(230400);
  Serial.print(F("\n\nStarting...\n File: " __FILE__ "\n Date: " __DATE__ "\n Time: " __TIME__ "\n IDE : "));
  Serial.println(ARDUINO);
  Serial.println();
} // end of setup

unsigned long lastSleep;

void loop()
{
  
  if (millis () - lastSleep >= WAIT_TIME)
  {
    lastSleep = millis ();

    Serial.print(F("\n go sleeping"));
    Serial.flush();
    
    noInterrupts ();

    byte old_ADCSRA = ADCSRA;
    // disable ADC
    ADCSRA = 0;  
    /*    // pin change interrupt (example for D0) Uno/328P!
    PCMSK2 |= bit (PCINT16); // want pin 0
    PCIFR  |= bit (PCIF2);   // clear any outstanding interrupts
    PCICR  |= bit (PCIE2);   // enable pin change interrupts for D0 to D7
*/
    // pin change interrupt (example for D0) Mega 2560!
    PCMSK1 |= bit (PCINT8); // want pin 0
    PCIFR  |= bit (PCIF1);   // clear any outstanding interrupts
    PCICR  |= bit (PCIE1);   // enable pin change interrupts for D0 to D7

    set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
    power_adc_disable();
    power_spi_disable();
    power_timer0_disable();
    power_timer1_disable();
    power_timer2_disable();
    power_twi_disable();

    UCSR0B &= ~bit (RXEN0);  // disable receiver
    UCSR0B &= ~bit (TXEN0);  // disable transmitter

    sleep_enable();
    digitalWrite (AWAKE_LED, LOW);
    interrupts ();
    sleep_cpu ();      
    
    digitalWrite (AWAKE_LED, HIGH);
    sleep_disable();
    power_all_enable();

    ADCSRA = old_ADCSRA;
    //PCICR  &= ~bit (PCIE2);   // disable pin change interrupts for D0 to D7
    PCICR  &= ~bit (PCIE1);   // disable pin change interrupts for D0 to D7
    
    UCSR0B |= bit (RXEN0);  // enable receiver
    UCSR0B |= bit (TXEN0);  // enable transmitter
     Serial.print(F("\n Woke. "));
  }  // end of time to sleep

  if (Serial.available () > 0)
  {
    byte flashes = Serial.read () - '0';
    if (flashes > 0 && flashes < 10)
      {
      // flash LED x times
      for (byte i = 0; i < flashes; i++)
        {
        digitalWrite (GREEN_LED, HIGH);
        Serial.print(F("\n Flasch: "));
        Serial.print(i);
        delay (200);  
        digitalWrite (GREEN_LED, LOW);
        delay (200);  
        }
      }        
  }  // end of if

}  // end of loop

 

jim_beam

PS: Welche Funktion hat/hatte der winzige 8-beinige IC der neben/unter dem Quarz liegt/lag? Ist das ein Komparator? (Wofür?) Und wie viel ließ sich dadurch einsparen?

combie

#49
Sep 03, 2015, 03:38 pm Last Edit: Sep 03, 2015, 04:18 pm by combie
Quote
Welche Funktion hat/hatte der winzige 8-beinige IC der neben/unter dem Quarz liegt/lag?
2 fach OP
Treiber für die Pin 13 LED und Stromversorgungsumschaltung.
Wenn du den abbaust, kann auch der zugehörige Spannungsteiler weg.

https://www.arduino.cc/en/uploads/Main/arduino-mega2560_R3-sch.pdf


Nachtrag:
Es gibt noch weiteres Stomsparpotential.
Mit 1,8V versorgen, dann muss aber der Quarz deaktiviert werden.
Also intern takten.
So ist dann per Fuses 1 und 8MHz möglich.
Per Teiler auch noch weitere Einstellungen.
Als noch langsamere Taktquelle: Internen Takt abschalten und den Watchdog Takt nutzen,

So solltest du auf wenige µA runter kommen können, ohne sleep.





Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

#50
Sep 03, 2015, 05:00 pm Last Edit: Sep 03, 2015, 05:05 pm by Doc_Arduino
Hallo,

was der OPV spart habe ich jetzt nicht extra notiert. Einige Einzelmessungen sind im Thread enthalten.
Edit:
der OPV und T1 spart nicht sehr viel, nur 0,x mA. Posting # 30, 31
Erst das entfernen des 16U2 hat wieder paar mA Einsparung gebracht.

Nur solltest Du Dich für eins von beiden entscheiden. sleep.h oder power.h
Wenn Du den tiefsten Schlafzustand sowieso wählst, mußte danach nicht noch extra die einzelnen Funktion lahm legen. Lege vorher den Interrupt fest worauf er reagieren/aufwachen soll und lege das Teil schlafen. Mehr mußte nicht machen. Bzw. nur die UART am leben halten und den Rest schlafen legen.

Ohne sleep packste keine µA. Ohne sleep Mode bleibt man im einstelligen mA Bereich.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
Ohne sleep packste keine µA. Ohne sleep Mode bleibt man im einstelligen mA Bereich.
;) Wetten? ;)
Ich biete 80µA im aktiven Zustand, mit dem WDT Takt.


Am liebste würde ich jetzt meinen Mega rupfen, um das zu beweisen....
Aber nein, den Beweis bleibe ich schuldig ....
Der bleibt, solange es geht, heile.
Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

Hallo,

wenn ich mir die Messwerte von Nick anschaue, hatte ich angeschaut, dann sehe ich nur µA Werte im Sleepmode. Deswegen mein Einspruch. Was ich nicht verstehe "80µA im aktiven Zustand mit WDT". WDT ist doch Sleepmode!!!
Also wenn er regelmäßig laut WDT aufweckt.

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#53
Sep 03, 2015, 05:49 pm Last Edit: Sep 03, 2015, 06:17 pm by combie
Quote
Was ich nicht verstehe "80µA im aktiven Zustand mit WDT". WDT ist doch Sleepmode!!!
Also wenn er regelmäßig laut WDT aufweckt.
Nee, man kann auch den Takt des Watchdog Timers als Taktquelle für den Rest nutzen.
Dann bleiben Quarz und interne RC Taktquelle aus.

Der Prozessor arbeitet dann mit ca 128kHz.
Durch die Vorteiler kann man noch weiter runter teilen.
bis 32kHz? runter (ohne Gewähr)
16kHz mit CKDIV8 Fuse

Dann ist man voll auf Schleichfahrt ;-)

Viel sparsamer kann ein durch WDT unterbrochener Sleepmode dann auch nicht mehr sein.
Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

Hallo,

naja okay, wenn das so funktioniert wäre das ein verkappter dauerhafter Sleepmode, theoretisch möglich, meinetwegen auch praktisch, aber ohne echten Sinn. Wenn er was machen soll, dauert das ewig und die Einsparung wäre dahin. Wenn man mal ehrlich ist.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

jim_beam

Ok der OPV  ist auch runter, jetzt sind aus den 359uA nette 77uA geworden (mit WDT aktiv)
Ohne WDT und nur PCI wake up durch Serial sind es 70uA. Bin sehr begeistert.  :)

Alles bei 5,08V. Jetzt könnte ich noch die Spannung reduzieren. Auch das senken des Taktes ist sicherlich für mein Projekt ohne Probleme möglich auf 8/4 vielleicht auch auf 1Mhz. Aber das kommt dann noch.
Dann wird es interessant, denn um so länger der uC braucht für z.B. Datenerfassen und Speicher bzw. Versenden um so länger ist auch die (ext.) Hardware an (z.B. Funkmodul, SD Karte, ADC,..) und Energie ist ja Leistung * Zeit. Bin gespannt. Hmm aber vielleicht lande ich ja bei 128kHz  :)



jim_beam

Nur solltest Du Dich für eins von beiden entscheiden. sleep.h oder power.h
Wenn Du den tiefsten Schlafzustand sowieso wählst, mußte danach nicht noch extra die einzelnen Funktion lahm legen. Lege vorher den Interrupt fest worauf er reagieren/aufwachen soll und lege das Teil schlafen. Mehr mußte nicht machen. Bzw. nur die UART am leben halten und den Rest schlafen legen.

Das habe ich jetzt nicht ganz verstanden.
 
Die ganzen internen Hardware Sachen sind scheinbar automatisch im low Power sleep aus. Ich konnte da keinen unterschied Messen. ABER das ausschalten des ADC (mit  ADCSRA = 0;                            // disable ADC) hat noch einen Unterschied gemacht.

Später möchte ich auch die anderen SleepModes nutzen z.B. ADC und während dessen unbenutzte Komponenten ausschalten. Auch während des aktiven Betriebs des uC würde ich nicht benutzte Funtionen abschalten. Dafür brauche ich doch dann beide sleep.h und power.h. Oder bringe ich da was durcheeinader?

Ich würde gerne den uC periodisch durch den WDT aufwecken und zusätzlich bei Serial Rx. Einzeln klappt beiden, aber zusammen habe ich da gerade ein Bug drin, er wacht nicht richtig auf bei Serial event, bzw. die PCI-ISR für Pin 0 (Rx) wird nicht erreicht...
Scheinbar ist er beim ersten erreichen der PCI ISR ja noch im sleep-Mode und schaltet deswegen keine Kontroll-LED ein?? Hm naja werde da morgen mal weiter dran forschen.

 

Aber was genau macht eigentlich:
Code: [Select]
UCSR0B &= ~bit (RXEN0);  // disable receiver (Serial? I2C?)
      UCSR0B &= ~bit (TXEN0);  // disable transmitter

Habe ich auch von Nick, aber mir nicht ganz klar. Seriel sollte doch schon mit disable_all() aus sein oder?

Was kann mann denn noch ausschalten?  Wie ist das mit dem BOD (Brown-out) beim Mega? Habe da was im Datenblatt gefunden. Geht wohl über die Fuses, aber geht es auch via Software?

Schöne Grüße


jim_beam

2 fach OP
Treiber für die Pin 13 LED und Stromversorgungsumschaltung.
Wenn du den abbaust, kann auch der zugehörige Spannungsteiler weg.
Wo finde ich denn denn der Spannungsteiler auf dem Board? Ist das das Teil mit der "103" zwischen dem OPV und den 2 großen C?

Danke!

jim_beam

Ich würde gerne eine Slaf Funktion mit folgender Funktionalität benutzen (PsydoCode):

Code: [Select]

volatile sleep_enabel = 1;        // global Flag is set to 0 in any waking ISR to stop sleeping


PowerDownExternalHardware( byte settings){
  if(bitset(settings,0)){
    //swirch off Hardware A by switching off Pin x
    digitalWrite(Pin0, LOW);
  }
  if(bitset(settings,1)){
    //swirch off Hardware A by switching off Pin x
    digitalWrite(Pin1, LOW);
  }
  //...

}//PowerDownExternalHardware


PowerDownInternalHardware( byte settings){
  if(bitset(settings,0)){
    disable_TWI();
  }
  if(bitset(settings,1)){
    disable_ADC();
  }
  //...

}//PowerDownInternalHardware

// Sleep Function, set: SleepMode, WDT Sleep Periode, if Serial waiks up, PCI Pins to wake up uC,
//                      Settings for external and internal Hardware shutdown
mySleep(byte Mode, unsigned int wdtPeriode, bool wakeBySerialRx, byte pciWakePins[],\
        byte pinCount, byte extHwSet, byte intHwSet)
{
  PowerDownExternalHardware( extHwSet);     // shut down associated ext. Harware
  PowerDownInternalHardware( intHwSet);     // shut down associated int. Harware

  if(wakeBySerialRx){
    //set PCI for Pin 0, Provide PCI ISR!!
  }

  for(byte i = 0;i< pinCount;i++){
    //enable Pci for Pins and ports, provide PCI ISRs !!
    //enable PCI for acording pciWakePins[i],
  }

  if(wdtPeriode){       // enable wake by WDT only if WDT Periode is set
  // setup wdt to periode and sleep x times till prriode is over
    
    if(WDT Periode >= 8000){                   // Sleep 8 sec
    
      noInterrupts();
      bool sleep_enabel_copy = sleep_enabel;  // check if sleep is still enabled
      interrupts();

      While(sleep_enabel_copy && wdtPeriode >= 8000){   // sleep for x * 8sec
        Periode -= 8000;
        //set WDT
        // start sleeping...
        // disable sleeping
        noInterrupts();
        sleep_enabel_copy = sleep_enabel;   // check if sleep is still enabled
        interrupts();
      }//while
    }//if(WDT Periode > 8sec)

    // skip 4 and 2 Sec    

    if(WDT Periode >= 1000){                   // Sleep 1 sec
    
      noInterrupts();
      bool sleep_enabel_copy = sleep_enabel;  // check if sleep is still enabled
      interrupts();

      While(sleep_enabel_copy && wdtPeriode >= 1000){   // sleep for x * 8sec
        Periode -= 1000;
        //set WDT
        // start sleeping...
        // disable sleeping
        noInterrupts();
        sleep_enabel_copy = sleep_enabel;   // check if sleep is still enabled
        interrupts();
      }//while
    }//if(WDT Periode > 1sec)

    // same for 128ms
    // same for 16ms  

  }// if(wdtPeriode){
 
  else{                             // no WDT Periode was given =>don't wake periodicly
                                    // wake only by Interrtupt from PCI, ADC, Serial RX ...
    // start sleeping...
    // disable sleeping after Interrupt (or better disable sleep in ISRs?)
  }
 
  PowerUpInternalHardware();
  PowerUpExternalHardware();
  
}

/* in all ISRs:
  Disable sleep in wakeISRs !?
  Set sleep enable == 0;          // needed?
  Set (global and local) ISR_has_happend_Flags
  Disable own ISRs? (PCI: not if used for someting else, Serial: yes, not needed in
                      active state, WDT: disable and reste does extra overhed, keep
                      running and just reset intervall,  ok/ possible??????)
*/


Kann mir jamdn dazu Tipps geben oder ob es überhaupt so möglich ist bzw was dagegen spricht? z.B. Welche Sequenzen mü+ssen dringen aufeinander folgen?

Vielen Dank.

PS: Das ganze funktioniert in Teilen schon, nur in der Kombination von mereren Wake-Quellen bekomme ich gerade Probleme.


Doc_Arduino

#59
Sep 04, 2015, 12:37 pm Last Edit: Sep 04, 2015, 12:40 pm by Doc_Arduino
Hallo,

hast du den gesamten Text von Nick gelesen? Posting #30 kannste auch wie schon erwähnt lesen?
SLEEP_MODE_PWR_DOWN legt alles lahm, hat den tiefst möglichen Schlafzustand.

Wegen dem BOD (Brown Out Detection). Das ist eine Schutzfunktion in Hardware. Das hat nichts mit Strom sparen zu tun. Das Spannungslevel wird über die Fuses eingestellt. Wenn die µC Ub drunter liegt, schaltet der µC ab bevor der Mist macht. Standardmäßig ist bei Arduino auf 2,7V gesetzt.

Spannungsteiler am OPV finde ich nur den links vom IC7B im Schaltplan. Da Vin tot ist, ist der Spannungsteiler auch tot. Damit erübrigt sich das auslöten meinerseits.

Für mehrere WakeUp Quellen kann ich dir folgenden Code geben als Basis. Der ist damals hier im Forum entstanden. Finde den Link nicht mehr zum Thread.

Der Text im Code ganz am Anfang ist für mich, muß nicht unbedingt für jeden Sinn ergeben. Weil ich immer wieder erweitert hatte. Auf jeden Fall ist das ein Bsp. für 6 externe Interrupt Eingänge. Pin 2, 3, 18, 19, 20, 21.
Die schalten für mich in dem Bsp. LEDs an Pin 30-35.
Du mußt die Interrupts auf jeden Fall vorher definieren und weil die im µC fest verdrahtet sind, gehen die an unterschiedliche Pins raus. Steht aber alles im Code kommentiert drin.

Viel Spass beim probieren, testen und coden.



Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up