Due to high demand expect some shipping delays at this time, orders may not ship for 3-4 business days. On MLK Day no orders will be shipped.
0

M0: Power high in STANDBY
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

M0: Power high in STANDBY

by nand on Fri Oct 05, 2018 11:45 am

I have a Trinket M0 that I'm trying to reduce the power consumption on. Using rtc.standbyMode() I'm able to put it into STANDBY. According to the datasheet the CPU itself should only consume ~4uA when in this mode. After destroying the green power LED (~0.1mA) and the dotStar LED (~1mA) I still measure ~400uA for the whole board. The LDO's datasheet says ~50uA of quiescent. There's nothing else on the board. So 400uA seems quite high, given that it's 7x what it should theoretically be.

The test setup I'm using was used to correctly measure the current consumption of an ATtiny85 based Trinket down to 40uA, so I don't think the setup is an issue.

(Test setup is a bench power supply, 4.5V, multimeter used to measure current from supply to BAT pin.)

Any ideas on where the extra current is going?

Perhaps I did not completely destroy the dotStar? I couldn't find any information in its datasheet for current draw when it's off, so I'm not sure if the 1mA drop I saw was everything.

According to the SAMD21 datasheet STANDBY should turn off all the peripheral clocks (unless otherwise specified, which I haven't). So I'm not sure what else I need to do.

Also of note: the board pulls ~11mA when active in a while loop. That's also really high relative to the datasheet. The CPU itself should only be ~3.5mA. I've tried playing with the Power Manager's registers to turn off all the peripherals, but so far I've only gotten down to ~9mA. Underclocking the CPU to 3MHz only gets me to ~6mA.

Thank you!
nand
 
Posts: 15
Joined: Sat Nov 09, 2013 5:42 am

Re: M0: Power high in STANDBY

by adafruit_support_mike on Sat Oct 06, 2018 5:23 am

There are also sources of parasitic current leakage throughout the board.. the Schottky diode between BAT and USB has about 250uA of reverse leakage, for instance.

In the measurements I've done, the quiescent current is about 80uA when you pull the EN pin low and shut off the voltage regulator. Any state that keeps the microcontroller active will use more current.

Low-power design is a specialized design field, and component selection is a big part of the process. That wasn't a design goal for the Feather line, so you won't be able to trim the quiescent current too far.

As an aside, you always want to take banner specs from a datasheet with a healthy dose of salt. Datasheets are a negotiated compromise among a company's engineering, marketing, and legal divisions. The engineers generally want to provide accurate information because they have to handle the support calls, the marketers want to emphasize all the good points and downplay all the bad ones to boost sales, and the lawyers demand that every statement in the document be provable in court if necessary. The result is a practice called 'specsmanship' that pushes the limits of truth about as far as they can go.

To illustrate, the datasheet for a human being would list the Olympic records for weight lifting, sprinting, and high jumping in a way that lets the reader assume a typical human can do all three at the same time.

Low-power specs are especially ripe for values taken under specific-but-undocumented conditions.. the SAMD21 operates down to 1.62V for instance, and I'd bet a nickel that the banner values (the ones mentioned most prominently) were measured at about 1.65V.


If you're looking for strobed power, take a look at the TPL5110 breakout:

https://www.adafruit.com/product/3435

It's a low-power timer that controls power to a load. By default, its quiescent current is about 20uA, almost all of which is reverse leakage through the power-on LED. If you cut the trace to the LED, quiescent current is less than 100nA for supply voltages up to 4V. That's at least two orders of magnitude better than you can do with any microcontroller sleep mode on a Feather.

The TPL5110 is another case of specsmanship, as the datasheet says quiescent current is 35nA @ 2.5V. From the measurements I've taken, it rises to at least 50uA at 2.6V.

adafruit_support_mike
 
Posts: 63921
Joined: Thu Feb 11, 2010 2:51 pm

Re: M0: Power high in STANDBY

by nand on Sat Oct 06, 2018 10:40 am

Hey mike, thank you so much for taking the time to reply! I appreciate it. Also that's a neat little device, the TPL5110.

The reason for my puzzlement is that I'm aware of the fudge factor involved with datasheets, etc, but being 7x off from theoretical indicated to me that most likely something was wrong with the MCU's configuration. Also I had no difficulty getting the ATtiny85 based Trinket down to its theoretical minimum (40uA).

So I very much suspect that there's a configuration I'm missing that's leaving some peripherals still running in standby. Unfortunately the datasheets for these more modern 32-bit MCUs are ... vast, to say the least.

I'll keep digging, but if anyone happens to have had previous success getting the Trinket M0's power lower...
nand
 
Posts: 15
Joined: Sat Nov 09, 2013 5:42 am

Re: M0: Power high in STANDBY

by adafruit_support_mike on Sun Oct 07, 2018 12:13 am

The values you get from the microcontroller datasheet only apply to the microcontroller, not to anything else on the board. You also have to consider the current necessary to keep things like the external crystal oscillator running.

adafruit_support_mike
 
Posts: 63921
Joined: Thu Feb 11, 2010 2:51 pm

Re: M0: Power high in STANDBY

by nand on Sun Oct 07, 2018 12:50 am

According to the schematic there is nothing else on a Trinket M0. Just MCU, LDO, and LEDs.
nand
 
Posts: 15
Joined: Sat Nov 09, 2013 5:42 am

Re: M0: Power high in STANDBY

by nand on Sun Oct 07, 2018 8:42 pm

SOLVED

TL;DR:
The fix is to reset all the Port A pins:

Code: Select all | TOGGLE FULL SIZE
  PORT->Group[0].DIRCLR.reg = 0xFFFFFFFF;
  PORT->Group[0].WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG | 0xFFFF;
  PORT->Group[0].WRCONFIG.reg = PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | 0xFFFF;


NOTE: This also resets the USB pins, which means the USB port will go offline. If you don't want that you'll want to modify the above to not reset the USB pins.



The Journey

I threw everything and the sink at this. Further reading of the datasheets revealed that the Power Manager module is a big misnomer. It can only turn off the clocks going to the peripheral's interfaces; not to the peripherals themselves. So it isn't helpful for disabling peripherals to save power...

Rather, the GCLK module is how you disable the clocks to the various peripherals. The GCLK module is where all the generated clocks are configured, and thus where you choose which (if any) clocks drive which peripherals.

And SYSCTRL is where you control the source clocks (internal and external oscillators).

Well, that was all good for me to learn, but it was ultimately fruitless. I used the ZeroReg library to dump all the registers and take a look at the GCLK, SYSCTRL, and other configurations. Everything was as it should be. The only clock that was set up to run during STANDBY (had the RUNSTDBY flag) was the 32kHz oscillator driving the RTC peripheral. Everything else was off.

Persisting, I tried disabling everything I could, even though it shouldn't be running during standby. I turned off OSC8M, USB, USB's clocks, I used the PM to turn off the interfaces for everything. Nothing helped.

Eventually I checked the I/O configuration. A handful of pins were enabled, which was a bit odd. Most pins are floating on the Trinket M0 board. I guess it was just a leftover from the bootloader supporting other PCBs. So I went through and turned off all the pins (AFAIK there's no nice Arduino API for this. I had to interact with the PORT registers manually to make sure the INEN bits were 0 to truly disconnect the pins.).

That helped a little, but not much. It went from 400uA down to 299uA. The goal, based on the datasheets, is something on the order of 54uA.

The Solution
Fortuitously I was reading through google results and noticed someone mention their SAMD21 based board would change power consumption based on whether they had their hand near the board or not. Odd...

I tried putting my hand near the board, but nothing changed. Then I touched the board. The power dropped!

Dry skin has a high resistance, it won't short anything out, so I began poking and prodding the board. (Obviously don't go poking anything high voltage or AC!!!!) Best guess was my fingers were grounding a floating pin or something.

My prodding revealed some interaction with the Test Points on the Trinket M0. The test points expose the SWD and SWC signals from the MCU. Hmm...

Turns out, the ZeroReg library doesn't print anything about the SWD and SWC pins. All pins on these SAMD MCUs are configurable, so even the debug pins can be configured. I printed their configuration manually. Lo and behold, INEN was set to 1 for both.

I added code to clear the INEN bits on those pins and voila!. Current draw in STANDBY was measured at 63uA! Just slightly above theoretical!

Problem solved.

So the trick for my application, at least, was to simply reset all the Port A pins at the beginning of the sketch.

Full code:

This blinks the on board red LED a few times, then goes into a sleep loop where it toggles the LED on and off every 10 seconds. You'll see the current drop to ~60uA when it's asleep and the LED is off. Also note that I destroyed the green power LED and onboard dotStar.

Code: Select all | TOGGLE FULL SIZE
#include <RTCZero.h>

RTCZero rtc;

byte timesec = 10;
bool state = false;

void setup() {
  // Reset all pins on Port A to help conserve power (not doing this, given the defaults left by the bootloader, results in ~340uA of extra current draw)
  PORT->Group[0].DIRCLR.reg = 0xFFFFFFFF;
  PORT->Group[0].WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG | 0xFFFF;
  PORT->Group[0].WRCONFIG.reg = PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | 0xFFFF;
 
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  delay(1000);
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
  digitalWrite(13, HIGH);

  rtc.begin();
  rtc.setTime(17, 00, 0);
  rtc.setDate(17, 11, 15);

  rtc.setAlarmTime(17, 00, 10);
  rtc.enableAlarm(rtc.MATCH_HHMMSS);

  rtc.attachInterrupt(alarmMatch);
 
  rtc.standbyMode();
}

void loop() {
  timesec += 10;

  rtc.setAlarmTime(17, 00, timesec);
  rtc.enableAlarm(rtc.MATCH_HHMMSS);
 
  rtc.standbyMode();
}

void alarmMatch()
{
  if (state == false) {
    digitalWrite(13, LOW);
    state = true;
  }
  else {
    digitalWrite(13, HIGH);
    state = false;
  }
}
nand
 
Posts: 15
Joined: Sat Nov 09, 2013 5:42 am

Re: M0: Power high in STANDBY

by languer on Sun Oct 07, 2018 11:18 pm

These results are great. The lowest I was able to go was 385uA, and I could only achieve this using the SleepyDog lib. I think part of my issues was trying to use the USB serial as part of my testing. But I look forward to trying the RTC lib with your changes.

languer
 
Posts: 46
Joined: Fri May 17, 2013 2:02 pm

Re: M0: Power high in STANDBY

by nand on Tue Oct 30, 2018 3:34 pm

Following up on this with a different, but related issue. I didn't think this warranted a new thread, since I'm not looking for solutions to the new problem.

The short version:

With even very simple software it appears that my Trinket M0 is sometimes getting stuck in STANDBY. This appears to be a common (hardware) bug on SAMD21 devices.


Details:

My fairly simple software sets an RTC alarm and enters STANDBY. Once woken up it fades an LED on, then off, sets an alarm, STANDBY, repeat. Yet after a day or so of doing this the device would be "dead"; no longer pulsing the LED.

If you search around the web, and check the SAMD21 errata sheets, you'll notice a lot of hardware bugs relating to the device getting stuck in STANDBY. I highly suspect that this is the case for my project. It's impossible to debug though, since AFAIK you can't put the device into STANDBY while the debugging. So I can't know for sure where my software gets stuck. It's also not worth my time to debug.

There are some listed remedies (set certain register bits), but none of them should apply to my device according to the errata sheet (my device is the latest revision). Nor did I see any new erratas relating to standby listed.

So either the hardware bug still exists and isn't listed, or there's something wrong with my software. Given the simplicity of the code, and the prevalence of hardware bugs relating to STANDBY on this device ... I'm going to assume the former.

A workaround would, presumably, be to use the watchdog timer to reset the device when it gets stuck, but in normal usage the watchdog timer will only count up to 16s (I need to sleep for longer than that).

So I've basically given up on the Trinket M0 for my project. Oh well. At least I figured I'd share my story here, as a warning mark for future explorers. Good luck!

(For reference I've fallen back to the Trinket 3V for my project. Its power usage is about the same, doesn't require fiddling to achieve low standby power, [40uA in sleep, ~8mA active] and doesn't have these silly bugs. So far so good!)
nand
 
Posts: 15
Joined: Sat Nov 09, 2013 5:42 am

Please be positive and constructive with your questions and comments.