Go Down

Topic: Power consumption of ATMEGA32U4 during sleep Power Down higher than expected (Read 2001 times) previous topic - next topic

Mardec

A question to ask is how your measuring the current consumption and is the device/method reporting true values?
I am using a uCurrent Gold by EEV blog. So I am pretty sure those values are reliable.

As a double verification I used my Digitek DT-4000ZC to measure the current also. 
uCurrent gold: 59,1 uA and the Digitek 59.2 uA. 

I don't know if you can write the other registered after you freeze the USB clock. Try to stop the PLL before it.
Will try that right now!
And no difference .. :-( 

Mardec

Lol, found the issue. There is a known bug in the ATMEGA32U4.

Still have to test the workaround, but I am glad I found a good lead:

From P426 of the datasheet:

Code: [Select]
35. Errata
The revision letter in this section refers to the revision of the ATmega16U4/ATmega32U4 device.

35.1 ATmega16U4/ATmega32U4 Rev E
• Spike on TWI pins when TWI is enabled
• High current consumption in sleep mode
• MSB of OCR4A/B/D is write only in 11-bits enhanced PWM mode

1. Spike on TWI pins when TWI is enabled
100 ns negative spike occurs on SDA and SCL pins when TWI is enabled.
Problem Fix/work around
Enable ATmega16U4/ATmega32U4 TWI before the other nodes of the TWI network.

2. High current consumption in sleep mode
If a pending interrupt cannot wake the part up from the selected mode, the current consumption will
increase during sleep when executing the SLEEP instruction directly after a SEI instruction.
Problem Fix/work around
Before entering sleep, interrupts not used to wake up the part from the sleep mode should be disabled.

3. MSB of OCR4A/B/D is write only in 11-bits enhanced PWM mode
In the 11-bits enhanced PWM mode the MSB of OCR4A/B/D is write only. A read of OCR4A/B/D will
always return zero in the MSB position.
Problem Fix/work around
None.

jremington

Glad to hear that the problem is solved! Which particular interrupt was the culprit?

Please post the code that solves the problem, for the benefit of others who have similar issues.

Mardec

Glad to hear that the problem is solved! Which particular interrupt was the culprit?

Please post the code that solves the problem, for the benefit of others who have similar issues.
Thank you JRemington. Yes I will post the code (once I cracked the issue) and possibly make a low power sleep library specifically for the ATMEGA32U4.

But meanwhile I still have not cracked this issue. I have a hard time identifying which revision my chips are.

I found this Document on Atmel/Microchips website. But the notes for a 7 by 7 mm VQFN chip do not seem to correspond to the markings of any of my ATMEGA32U4...

Code: [Select]
One is marked:

ATMEGA32U4
-MU
1704E PH
A8VFMA

Other one is marked:

ATMEGA32U4
-MU
1808E PH   
A9QZPA


I have just spent a few hours going through the datasheet, and adjusting my test script to turn off as many interrupts as I could identify. And still I am stuck at 59 uA. I am really starting to hate the number 59 ... :-)

If I understand correctly Interrupts are OFF by default, so unless I turned them on (like the WDT) they should be off.
The Arduino IDE/Code will turn a bunch of them ON for different component to work. USB for example.
This could be either for your code, or for your bootloader.

Does anybody know how I can see which Interrupts are all being set by the compiler?

Or does anybody know which Interrupts are all being set by the Arduino Code?

I am not far from giving up searching for the solution to this issue. I hate giving up but it is consuming too much time for little to no progress..


theophileb

Hi,

I've just started working with Atmega 32u4 and I got some encouraging results. Maybe it could help you.
The board I'm using is Adafruit Feather 32u4 LoRa. It's far for optimal since it has a LoRa transceiver but I got good results anyway.

First thing I did was removing some useless components from the board :
  • Voltage regulator
  • Battery charger
  • 2 resistors used as a voltage divider to measure battery power


Then, with the following code I got 35µA (there should be at max 1µA coming from the LoRa transceiver in sleep mode) :
Code: [Select]

void goToSleep()
{
    // Disable digital input.
    DIDR0 |= _BV(ADC7D) | _BV(ADC6D) | _BV(ADC5D) | _BV(ADC4D) | _BV(ADC1D) | _BV(ADC0D);
    DIDR1 |= _BV(AIN0D);
    DIDR2 |= _BV(ADC13D) | _BV(ADC12D) | _BV(ADC11D) | _BV(ADC10D) | _BV(ADC9D) | _BV(ADC8D);
    // Disable ADC
    ADCSRA &= ~(_BV(ADEN));
    // Disable analog comparator and it's interrupts
    ACSR = (ACSR & ~_BV(ACIE)) | _BV(ACD);

    Watchdog.sleep(8000);
}


I then changed the BOD fuses to disable it and now I have a power consumption of 28µA.

That's still a lot compared to value announced on datasheet. I will try to look at disabling all interrupts except the watchdog one. But I don't have much faith into this.
If anyone as an idea to further reduce the power consumption, I would be glad to hear it :)

jeffsiddall

Well... not a fix for your issue specifically, but I ended up changing MCUs.

Figuring out how to set all the registers to get best power saving on the 32u4 was well beyond my paygrade, but I did achieve success on a SAMD21, specifically a Seeeduino XIAO.  The standby (aka sleep) power is in the mid 20's of uA with the only hardware change being removing the power LED.  Perhaps even more interesting is CPU scaling which can be dynamically changed on-the-fly when not sleeping with a current of about 12 mA when running at 48 MHz, down to about 1.8 mA at 4 MHz (clock divisor of 12).  Ex:


Code: [Select]
    GCLK->GENDIV.reg = GCLK_GENDIV_DIV(12) |
                       GCLK_GENDIV_ID(0);


The only downside I can see is that there is no compensation for the actual F_CPU in any other code, so things like delay(1) actually delays 12 ms when using a clock divisor of 12.  That breaks timing critical things including USB so you need to disconnect USB before messing with the clock.

That might not be the answer you were looking for but in case it helps someone...

Jiggy-Ninja


jeffsiddall

You can change the clock prescaler on an AVR too.
I thought that changing clock was more invasive on the AVR.  Doesn't it required burning fuses?  If you could do it within code that could be interesting, though the AVR clock is already significantly slower to begin with so the benefits would presumably also be less significant.


theophileb

I thought that changing clock was more invasive on the AVR.  Doesn't it required burning fuses?  If you could do it within code that could be interesting, though the AVR clock is already significantly slower to begin with so the benefits would presumably also be less significant.


You can set the CKDIV8 fuse to divide frequency by 8 directly on boot.
Otherwise, you can also change it on the fly (cf avr-libc documentation for avr/power.h : https://www.nongnu.org/avr-libc/user-manual/group__avr__power.html). It seems to be as easy as with your ARM device

jremington

Clock scaling usually does little or nothing for power saving, because required computations take proportionally longer.

In your example, energy consumption in terms of CPU hours is actually quite a bit worse. 12 x 1.8 mA = 21.6 mAh.

Quote
current of about 12 mA when running at 48 MHz, down to about 1.8 mA at 4 MHz

jeffsiddall

Clock scaling usually does little or nothing for power saving, because required computations take proportionally longer.

In your example, energy consumption in terms of CPU hours is actually quite a bit worse. 12 x 1.8 mA = 21.6 mAh.

Yes, I would have though the same, but my app spends most of the time idle and even 1/6 speed (8 MHz), which is plenty fast enough to do everything I need per loop, the MCU runs at 2.8 mA.  Yet calling idle(IDLE_2), which is the lowest power idle mode, the MCU takes 3.2 mA running no code at all!

jremington

Quote
my app spends most of the time idle
Battery life must be terrible.

jeffsiddall

Battery life must be terrible.
Not really, it depends on how much of the time it is active and how much is in standby.

I probably should have been clearer with my terminology.  When running at full clock speed, my app spends about 1/6 of the time doing useful stuff and 5/6 of the time waiting for something to happen.  That's what I mean by "most of the time idle".  One solution to that is to go into a low power mode for the 5/6 of the time while waiting, and using idle mode got me down to the 3 mA range for the waiting.  But if I run the CPU at 1/6 of full speed then I get a constant 2 mA range and still get the same amount of work done.

In addition, when the app can go to sleep then standby mode gets it to the 20 uA range and it can stay like that for years on battery, waking up on interrupt.

I suppose another alternative would be to run at full clock speed for the 1/6 of the time and then divide the clock way down for the remaining idle time.  I'll have to check how low the Cortex clock can go.  Regardless, it wouldn't save any power.

One other thing I will add about the SAMD21 is that it takes nearly an eternity in clock cycles (about a second) to exit standby mode when running on the typical DFLL48M clock, making it more like a hibernation than a typical MCU sleep.

EDIT: Maximum clock divider is 31, so about 1.5 MHz, not really that slow.

Go Up