2

I know this sounds like a stupid question, but I'm wondering if the datasheet has an error or something.

I have an ATtiny84 connected to my bench power supply set for 3 volts. It's fused for the internal 8 MHz RC oscillator and a divide-by-8 clock. No watchdog, no brown-out detector.

8 of the I/O pins are hooked to LED anodes, with the cathodes grounded through 0 ohm resistors (yes, the duty cycle is low. Fear not). One of them is connected to a button with the other side grounded. Two of them (shared with MOSI and SCK of the ISP) are not connected (other than to the ISP which is itself disconnected for this test).

setup:

void setup() {

  power_adc_disable();
  power_usi_disable();
  power_timer1_disable();
  ACSR = _BV(ACD);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(UNUSED_1, OUTPUT);
  digitalWrite(UNUSED_1, LOW);
  pinMode(UNUSED_2, OUTPUT);
  digitalWrite(UNUSED_2, LOW);
  for(int i = 0; i < 8; i++) {
    pinMode(LED_PINS[i], OUTPUT);
    digitalWrite(LED_PINS[i], LOW);
  }
  while(1) sleep_mode();
}

The result is 240 µA of current draw. This is measured with a µCurrent Gold, so I have some confidence in the accuracy.

The datasheet (figure 21-1) says that powered down at 25°C the chip should take more like 100 nA.

WTF?

For reference, here's the actual sleep function used by the code (but not part of this test):

void sleepNow() {
  // All LEDs off
  for(int i = 0; i < 8; i++) {
    digitalWrite(LED_PINS[i], LOW);
  }
  cli();
  power_timer0_disable();
  PCMSK0 |= _BV(PCINT5);
  GIMSK |= _BV(PCIE0);
  sleep_enable();
  sei();
  sleep_cpu();
  sleep_disable();
  PCMSK0 &= 0xff ^ _BV(PCINT5);
  GIMSK &= 0xff ^ _BV(PCIE0);
  power_timer0_enable();
  button_debounce_time = millis();
  ignoring_button = 1;
  place_in_pattern = -1;
  milli_of_next_act = 0;
}

It yields the same current consumption, which is why I reduced this test down to just putting the chip to sleep in as little code as possible.

The schematic:

enter image description here

For this test, the battery is absent and 3.00 volts is being fed in to the Vcc and GND pins of the ISP header. No other ISP pins are connected.

I've repeated this experiment with an ATTiny85 on a breadboard. I programmed it with this:

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

void setup() {
  PRR = 0xff;
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  pinMode(0, OUTPUT);
  digitalWrite(0, LOW);
  pinMode(1, OUTPUT);
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
  while(1) { sleep_mode(); digitalWrite(2, HIGH); }
}

void loop() {}

I then fused it for a 1 MHz internal clock, and then disconnected everything but power and ground. The result: 240 µA.

Now, all of this would be explained if the graph in figure 22-11 (this is the ATTiny85 datasheet now) had the axis mislabeled and was actually in mA rather than µA. The power down current vs Vcc and temperature that I'm using lines right up with the graph 3 orders of magnitude higher.

Has anyone gotten an ATTiny to draw less than a micro-amp (other than just disconnecting power)? Can someone write a sketch that will make an ATTiny do nothing but just go permanently to sleep consuming as little power as possible with nothing connected except power and ground? That's what I've been trying to do, and there clearly is something that I'm missing and I'll be damned if I can figure out what it is.

nsayer
  • 1,543
  • 1
  • 18
  • 35
  • For completeness, do you have a voltage regulator in the circuit? It's quiescent current might be that big. I assume the datasheet has not got an error that big. It is quite an old chip, so I would expect an errata to have fixed the datasheet by now. – gbulmer Aug 23 '14 at 18:04
  • No. I am using a bench supply set to 3.00 volts going directly to Vcc. – nsayer Aug 23 '14 at 18:42
  • Oh, and the µCurrent is on the low side, so that there's a common ground with the scope being used to measure the voltage (which is what the µCurrent outputs). – nsayer Aug 23 '14 at 19:23
  • Okay - so the *only* parts current can flow through are the ATTiny and the closed switch? 240uA looks so big, that it might be more than one cause. To reduce the number of possibilities, is it practical to disconnect all I/O pins except the switch? – gbulmer Aug 23 '14 at 19:25
  • The only thing hooked up to the pins are LEDs, and the pins are all set LOW - there should be no current flowing at all through them. The only part that has both +3 and ground hooked up is the ATTiny (assuming the button is not being pushed - which it isn't). – nsayer Aug 23 '14 at 21:42
  • What changes if you ground mosi and sck as well? – Passerby Aug 23 '14 at 22:12
  • I haven't tried that, but I am setting the pin to OUTPUT and LOW, so that would be moot. – nsayer Aug 24 '14 at 03:01

3 Answers3

3

This comment on reddit pointed me to this page, which says that clearing the ADEN bit in ADCSRA shed as many µA as are currently in excess in my test rigs. I am away from the lab right now, but when I get home tonight, that's the first thing I'll try. I'm optimistic. I do know that the ADEN bit gets set in init() in wiring.c...

If it's confirmed, then the lesson is that PRR is not enough to turn the ADC all the way off.

EDIT: It is confirmed. The one added caveat is that order matters. ADCSRA must be written before PRR.

My sleep_tiny_sleep sketch (last above) now takes < 100 nA.

nsayer
  • 1,543
  • 1
  • 18
  • 35
1

Are you certain sleep_mode() is able to put everything into that 100nA power down mode?

A simple explanation is it does not go that deep.

says

As the sleep_mode() macro might cause race conditions in some situations, the individual steps of manipulating the sleep enable (SE) bit, and actually issuing the SLEEP instruction, are provided in the macros sleep_enable(), sleep_disable(), and sleep_cpu()much .

So they advise against using sleep_mode()

Even if sleep_mode() returns with an error, it is in a while(1) so it might just be going round and round.

Maybe change while(1) sleep_mode(); into something like

while(1) {
    sleep_mode();
    blink LED
}

and see if the LED is on. If you have an oscilloscope, have a look at the pin, and see what is happening.

Edit:
One approach would be to look at the ATTiny84 datasheet, and see which peripheral might be consuming that much current.

240µA is so big, it may be more than one cause; no single peripheral on the data sheet looks big enough to consume that much.

The internal I/O pin pull-up resitors could leak enough to reach that order of magnitude, so try to ensure they are all off.

gbulmer
  • 10,040
  • 20
  • 29
  • I'll try it. sleep_mode() is part of the AVR power.h api: http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html I'd be a little surprised if it didn't do what it says it's supposed to. – nsayer Aug 23 '14 at 17:50
  • I agree. However it clearly isn't working!-) Actually I don't hold out much hope that it checks enough to find out what is wrong. But you might find a clue. – gbulmer Aug 23 '14 at 17:53
  • The light never lights up. – nsayer Aug 23 '14 at 17:57
  • Oh! The nongnu.org/avr-libc/user-manual/group__avr__sleep.html page does recommend a different way to sleep, and identifies problems with using other ways. user34920 diagnosis is likely correct. – gbulmer Aug 23 '14 at 17:58
  • Interestingly, I see the current draw increase 60 µA when I push the button, but the light still doesn't do anything - not surprising, because I didn't set up any of the pin change interrupts yet. – nsayer Aug 23 '14 at 17:59
  • Sure, for the *actual* code, those suggestions have merit. But right now, I'm still puzzling out why sleeping is drawing 2.5 orders of magnitude too much power. – nsayer Aug 23 '14 at 18:00
  • 2
    The pull-up or pull-down resistor on the button will add some extra current flow. – gbulmer Aug 23 '14 at 18:00
  • Yeah, I didn't see anything else in the datasheet that I could power down. And SLEEP_MODE_POWER_DOWN is supposed to stop all of the clocks - even mooting the PRR register settings I'm already making. Thus the question. :) – nsayer Aug 23 '14 at 18:08
  • All of the pins are set to OUTPUT and LOW except for the switch pin, which is INPUT_PULLUP (and has to be). Figure 21-15 shows an absolute maximum pull-up current of 70 µA - still more than 3 times too little to explain the symptoms - and that's only with the pin grounded (and it's floating when the switch isn't pushed). – nsayer Aug 23 '14 at 21:45
  • @nsayer - how about setting all the connected pins to input? Clearly something is wrong. Current looks too big to be one cause. As Sherlock Holmes said "when you have eliminated the impossible, whatever remains, however improbable, must be the truth". The next step will be to explicitly switch off peripherals, one by one. Something has got to change. – gbulmer Aug 23 '14 at 23:57
  • Starting with a lone ATTiny85 PDIP in a breadboard, with no pins connected except Vcc and ground, yields identical current draw. It has to be something in the software. – nsayer Aug 24 '14 at 19:43
  • @nsayer - Yes, that halves the problem! I assume something is being switched on that isn't being switched off. I also assume you have the source code to the startup. Maybe try disabling code (#if 0 ... endif) to prevent initialisation? – gbulmer Aug 24 '14 at 19:48
  • The code is at the tail end of the revised question. – nsayer Aug 25 '14 at 00:31
0

This does not look like the proper sleep sequence to me...

  1. Set the sleep mode
  2. disable global interrupts
  3. condition to sleep (if...)
  4. enable sleep
  5. enable global interrupts
  6. sleep cpu
  7. disable sleep (this executed after external interrupt)

Try this and report back.

user34920
  • 1,872
  • 2
  • 22
  • 44
  • That's the sequence used for the actual code - which uses the button to wake up. But this is just a test. I am trying to put the chip into *permanent* sleep just for now, and that doesn't seem to be working as expected. – nsayer Aug 23 '14 at 17:53
  • Try using this sequence without other code in the middle, make sure you follow all the steps in the right order. give it a go it will take you 2 minutes. – user34920 Aug 23 '14 at 17:54
  • The original sleep code - which I pasted above - yields the same current consumption. I reduced the code down to the minimal case for this question to try and reduce the scope. – nsayer Aug 23 '14 at 19:02