Pages: 1 2 [3]   Go Down
Author Topic: Breaking the .7 mA barrier?  (Read 2759 times)
0 Members and 1 Guest are viewing this topic.
Switzerland
Offline Offline
Sr. Member
****
Karma: 6
Posts: 375
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, here's another power-saving solution I've been using which doesn't use the Narcoleptic library.  I hadn't actually checked the current draw until now.

My meter reads 3uA (at 5.1V), but the real current is probably lower than this.
To do timed sleeps you need to enable the WatchDog, which uses roughly another 8uA.

Here's the code.  See the comments for more details
Code:
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

// ====== Utility macros ======
#define adc_disable()  (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)
#define adc_enable()   (ADCSRA |=  (1<<ADEN)) // re-enable ADC
#define ac_disable()   (ACSR   |=  (1<<ACD )) // disable analogue comparator
#define ac_enable()    (ACSR   &= ~(1<<ACD )) // enable analogue comparator
#ifndef sleep_bod_disable() // not included in Arduino AVR toolset
#define sleep_bod_disable() \
do { \
  uint8_t tempreg; \
  __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
                       "ori %[tempreg], %[bods_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" "\n\t" \
                       "andi %[tempreg], %[not_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" \
                       : [tempreg] "=&d" (tempreg) \
                       : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
                         [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
                         [not_bodse] "i" (~_BV(BODSE))); \
} while (0)
#endif

// wake-up pins on port-C
#define INPUT_MASK  0x3F


void setup() {
  // low outputs on ports B & D
  PORTB=0x00;
  DDRB=0xFF;
  PORTD=0x00;
  DDRD=0xFF;

  // pull-ups on port-C
  PCICR  = 0;           // disable pin-change interrupts
  DDRC &= ~INPUT_MASK;  // inputs on DIs
  PORTC  = INPUT_MASK;  // pull-ups on DIs
  PCMSK1 = INPUT_MASK;  // interrupt on DIs
  PCICR  = (1<<PCIE1);  // enable port-C interrupts
 
  // current-consumption of pull-ups is too small to measure (<1uA for 6 pins)
}

void loop() {
  // all currrents measured with ATmega328p at 8MHz and 5V
  // minimum current draw is less than the multimeter error (~3uA)
 
  digitalWrite(13,HIGH);
  delay(100);
  digitalWrite(13,LOW);
  delay(5000);
  digitalWrite(13,HIGH);
  delay(100);
  digitalWrite(13,LOW);
 
  // power off peripherals
  ac_disable();
  adc_disable(); // ADC uses ~125uA
  power_all_disable();
  wdt_disable(); // WDT uses ~8uA

  //wdt_enable(WDTO_4S);

  // enter sleep
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_bod_disable(); // BOD uses ~18uA
  sleep_cpu();
  sleep_disable();

  // to wake CPU pull pin A0-A5 low (or wait for WDT timeout if enabled)

  wdt_disable();
  power_all_enable();
}

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You should be able to get a lot less than 700 uA.

http://www.gammon.com.au/forum/?id=11497

I got consumption down to 355 nA on that page. That's about 2000 times less. (That's with no watchdog).

I think I reckoned the watchdog at 6.2 uA which roughly agrees with tim7.

As I point out on that page, most batteries have a somewhat larger self-discharge rate than that, so you aren't really achieving much by going much lower.
Logged

Pages: 1 2 [3]   Go Up
Jump to: