Lowest consumption issue

Reading the code of the low power library, I can see that the option BOARD_HAS_COMPANION_CHIP is not setup. Unfortunately this doesn't give us the capability to use the instruction LowPower.companionSleep(); and to ensure that the sigfox module by itself is set in deep sleep mode as well as the SAMD CPU.

In my test bench I did'nt initialised the sigfox module. I was expecting the sigfox module to be its lowest consumption mode after reset. Furthermore I didn't call a SigFox.end() instruction. Maybe the mistake is there, I don't know ...

I definitively would appreciate to get support on this topic.

Please tell me anyway how you've got happy with the lifetime of your "AA" battery back !

Philippe.

I've updated the Arduino Low Power library to 1.2.0, I've called sigfox.end(); : I get 500 uA (+/- 100 uA) during the sleep mode. Progress, yes, but not as much as expected reading the components data sheet + MKRFOX1200 schematics.

End of my posts on that subject.

mkrfox1200-testsleep.ino.ino (2.03 KB)

Sorry, but I'm coming again a last time in order to provide a fruitful issue .

I've tried "to remove the pin initialization in wiring.c", as suggested in other forums :

And now my consumtion in standby is about 50uA, difficult to be more precise with my multimeter ...

I've not seen negative side effects, anyway.

I can close the topic as SOLVED, and maybe my trials will help others ...

2 Likes

@philgeek, Wiring.C file in Arduino installation folder on my computer is completely different than this one and there is no pin initialization in it. Do I have to substitute it with the one on Github?

Here is the updated file with comments & installation path added in the header. I hope this will help to get the low consumption figure on mkrfox1200.

Please take also into account the great benefits of a setup boost 3.3V circuit, which makes batttery life about 10 times longer. My reference is the NCP1402, and its implementation by Sparkfun.

/*
Copyright (c) 2015 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Philgeek on www.philoc.fr
// Edited on 2018/03/17 thanks to question / my post on Arduino forum mkrfox1200/lowest consumption issue
// I just hope it can help but I cannot commit :wink:

// This file has been updated as I looked for the lowest consumption on mkrfox1200
// The modification below is tagged with "phg" embedded in the comment
// Only one line had to be placed as comment ...
// Notes :
// The path on my configuration is .arduino15/packages/arduino/hardware/samd/1..6.16/cores/arduino/wiring.c
// Notes / Prerequisites
// All unused components, and especially sigfox and usb must have been reset by your application before entering deep sleep
// And Arduino Low Power library must be in its 1.2.0 version, at least in my configuration
// Lastly check any pin configuration, be careful with pullups and leds ... but you did that already
// And at he end of the day, you should get around 50 mA, as I've got by myself ... because the data sheet figures & the mkrfox1200 schematics are done that way.
*/--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
#include "Arduino.h"

#ifdef __cplusplus
extern "C" {
#endif

/*

  • System Core Clock is at 1MHz (8MHz/8) at Reset.
  • It is switched to 48MHz in the Reset Handler (startup.c)
    */
    uint32_t SystemCoreClock=1000000ul ;

/*
void calibrateADC()
{
volatile uint32_t valeur = 0;

for(int i = 0; i < 5; ++i)
{
ADC->SWTRIG.bit.START = 1;
while( ADC->INTFLAG.bit.RESRDY == 0 || ADC->STATUS.bit.SYNCBUSY == 1 )
{
// Waiting for a complete conversion and complete synchronization
}

valeur += ADC->RESULT.bit.RESULT;
}

valeur = valeur/5;
}*/

/*

  • Arduino Zero board initialization
  • Good to know:
    • At reset, ResetHandler did the system clock configuration. Core is running at 48MHz.
    • Watchdog is disabled by default, unless someone plays with NVM User page
    • During reset, all PORT lines are configured as inputs with input buffers, output buffers and pull disabled.
      /
      void init( void )
      {
      // Set Systick to 1ms interval, common to all Cortex-M variants
      if ( SysTick_Config( SystemCoreClock / 1000 ) )
      {
      // Capture error
      while ( 1 ) ;
      }
      NVIC_SetPriority (SysTick_IRQn, (1 << __NVIC_PRIO_BITS) - 2); /
      set Priority for Systick Interrupt (2nd lowest) */

// Clock PORT for Digital I/O
// PM->APBBMASK.reg |= PM_APBBMASK_PORT ;
//
// // Clock EIC for I/O interrupts
// PM->APBAMASK.reg |= PM_APBAMASK_EIC ;

// Clock SERCOM for Serial
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ;

// Clock TC/TCC for Pulse and Analog
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ;

// Clock ADC/DAC for Analog
PM->APBCMASK.reg |= PM_APBCMASK_ADC | PM_APBCMASK_DAC ;

// Setup all pins (digital and analog) in INPUT mode (default is nothing)
for (uint32_t ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ )
{
// modification - PHG - 2017-09-13 : line below suppressed in order to get lower consumption in standby /deep sleep mode '<50uA)
// pinMode( ul, INPUT ) ;
}

// Initialize Analog Controller
// Setting clock
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
GCLK_CLKCTRL_CLKEN ;

while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains

ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock by 512.
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default

ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length

while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains

ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)

// Averaging (see datasheet table in AVGCTRL register description)
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0

analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)

// Initialize DAC
// Setting clock
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY );
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_DAC ) | // Generic Clock ADC
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
GCLK_CLKCTRL_CLKEN ;

while ( DAC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
DAC->CTRLB.reg = DAC_CTRLB_REFSEL_AVCC | // Using the 3.3V reference
DAC_CTRLB_EOEN ; // External Output Enable (Vout)
}

#ifdef __cplusplus
}
#endif

Hi there philgeek

I have also tried the Mkrfox1200 in Lowpower deepspleep. (The board has its own way of behaving).

I need a board for long life. As a test I have put the board in deep sleep for intervals with a tmp36 temp measure sensor. I have measured the voltage between vcc / ground and the current used by the sensor. When the board changed to sleeping mode the values did not change.

I think thats not good for a long battery life – did you find a way to make the board “total sleep” .

Hi philgeek and Gormd,

I'm in a similar project and need a low power board.

Just beginning tests, so I will take advantage of your work and keep you also updated about my progresses.

I cant't find wiring.c in my installation. Where should I find it in a MAC OS X installation?

And, what do you mean philgeek with setup boost 3.3V circuit? It's an additional circuit I should put in front of the board? Could you give more information?

By the moment I'm feeding the board using 2xAA cells.

Best regards.

Hi,

I finally found wiring.c and it looks like the one indicated by philgeek.

Regarding the functions to get the board into sleep mode, I have seen that using LowPower.sleep() function the board awakes without problem, but using LowPower.deepsleep() freezes the board and doesn'n wake up. Have you experienced the same problem?

I've seen one post talking about the same problem, but there is no answers.

I have still not made any mesure about the power consumption.

I'll try tomorrow, maybe.

Keep you updated.

Update.

Neither the sleep() nor the deepSleep() functions work. And I'm pretty sure they were working in the first tests. I have never changed any core library. Any suggestion?

It's really weird...

Maybe a kind of hard reset? ...

Hi jmsalomr

A lot of time can be "spild" on this - sometimes its working - sometimes not.

When you use sleep(yourtime to wakeup) you have to add the:
LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, alarmEvent0, CHANGE); -in your void setup().. that worked for me.

Have not tried to use the deepsleep - I will try it now....

What will you use your Mkrfox1200 for?

(be aware, that if you have your deve going in sleep mode you have a hard time to connect it to your usb!!)

Hi there

Deepsleep is also ok with attachInterruptWakeup as mentioned.

Hi Gormd,

It was a little bit weird, but it works for me now. I have just to disconnect the board and connect it again. If I left it connected through the USB, even if I push the reset button, it doesn't work - no wake up. But if I disconnect the board and I connect it again, it works. Both with sleep() and deepSleep(). It seems I need just a switch off.

I've been measuring with both sleep() and deepSleep(), without SigFox initialization, and I measure 350 uA in sleep() and deepSleep() modes. No differences between them.

I'm using MKRFOX1200 for an agriculture application. I've been testing Pycom SiPy + PySense with quite good results, but I would like also to test this board.

I'm going to test removing the pin initialization from wiring.c.

Hi,

Removing the pin initialization, in my case gives me just 17 uA in both sleep() and deepSleep() modes. No differences between them. Good numbers!

Best regards.

Hej jmsalomr

Sounds like you are having some funn with Sigfox - my I ask what you are going to do in the agriculture area?

I have actually had some practice with the MKRFOX1200 now - in the field it works nicely, but connected to the computer for compiling from the Arduiono IDE - it really has its own life :slight_smile:

Would be nice to hear your experience with the SiPy and Sigfox comparing to MKRFOX1200:-)

Best regards

Hi Gormd, I read with interest your suggestions regarding attaching the interrupt. Indeed, when I do this the board reset and sleep function are reliable. I was also able to achieve a reliable sleep() and reset if I instantiated an RTCZero object and invoked the begin() method. I am wondering if you have any thoughts on this?

RTCZero rtc;

setup() {
  rtc.begin(false);
}

I took a dive into the ArduinoLowPower code and (the RTCZero library on which it depends) and it appears to me that the attachment of the interrupt is handled by the sleep() method? See the attached code snippets from ArduinoLowPower.cpp. It is odd to me that this doesn't appear to be working. The ArduinoLowPower class instantiates an RTCZero object in the private section. So, it is my understanding, attaching an interrupt as you described would require instantiating another RTC object? Shouldn't there be a compiler error if you attempt to use attachInterrupt on a private object?

class ArduinoLowPowerClass {
	public:
		void idle(void);
		void idle(uint32_t millis);
		void idle(int millis) {
			idle((uint32_t)millis);
		}

		void sleep(void);
		void sleep(uint32_t millis);
		void sleep(int millis) {
			sleep((uint32_t)millis);
		}

		void deepSleep(void);
		void deepSleep(uint32_t millis);
		void deepSleep(int millis) {
			deepSleep((uint32_t)millis);
		}

		void attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode);

		#ifdef BOARD_HAS_COMPANION_CHIP
		void companionLowPowerCallback(onOffFuncPtr callback) {
			companionSleepCB = callback;
		}
		void companionSleep() {
			companionSleepCB(true);
		}
		void companionWakeup() {
			companionSleepCB(false);
		}
		#endif

		#ifdef ARDUINO_ARCH_NRF52
		void enableWakeupFrom(wakeup_reason peripheral, uint32_t pin = 0xFF, uint32_t event = 0xFF, uint32_t option = 0xFF);
		wakeup_reason wakeupReason();
		#endif

	private:
		void setAlarmIn(uint32_t millis);
		#ifdef ARDUINO_ARCH_SAMD
		RTCZero rtc;
		#endif
		#ifdef BOARD_HAS_COMPANION_CHIP
		void (*companionSleepCB)(bool);
		#endif
};
void ArduinoLowPowerClass::idle(uint32_t millis) {
	setAlarmIn(millis);
	idle();
}

void ArduinoLowPowerClass::setAlarmIn(uint32_t millis) {

	if (!rtc.isConfigured()) {
		attachInterruptWakeup(RTC_ALARM_WAKEUP, NULL, 0);
	}

	uint32_t now = rtc.getEpoch();
	rtc.setAlarmEpoch(now + millis/1000);
	rtc.enableAlarm(rtc.MATCH_HHMMSS);
}

void ArduinoLowPowerClass::attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode) {

	if (pin > PINS_COUNT) {
		// check for external wakeup sources
		// RTC library should call this API to enable the alarm subsystem
		switch (pin) {
			case RTC_ALARM_WAKEUP:
				rtc.begin(false);
				rtc.attachInterrupt(callback);
			/*case UART_WAKEUP:*/
		}
		return;
	}

	EExt_Interrupts in = g_APinDescription[pin].ulExtInt;
	if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI)
    		return;

	//pinMode(pin, INPUT_PULLUP);
	attachInterrupt(pin, callback, mode);

	// enable EIC clock
	GCLK->CLKCTRL.bit.CLKEN = 0; //disable GCLK module
	while (GCLK->STATUS.bit.SYNCBUSY);

	GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK6 | GCLK_CLKCTRL_ID( GCM_EIC )) ;  //EIC clock switched on GCLK6
	while (GCLK->STATUS.bit.SYNCBUSY);

	GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(6));  //source for GCLK6 is OSCULP32K
	while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

	GCLK->GENCTRL.bit.RUNSTDBY = 1;  //GCLK6 run standby
	while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

	// Enable wakeup capability on pin in case being used during sleep
	EIC->WAKEUP.reg |= (1 << in);

	/* Errata: Make sure that the Flash does not power all the way down
     	* when in sleep mode. */

	NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
}

Finally, have you by chance tried the same on a MKRWAN1300? I cannot seem to get the MKRWAN1300 below 1.16mA. I have removed the pin initialization from wiring.c and used the method suggested here to attach the interrupt. Still 1.16mA. I am trying to ascertain if the current is being used by the SAMD or the Murata LoRa module but its difficult to tell.

Thank you and kind regards,

Hi jmsalomr,

Would it be possible for you to post your sketch that achieved the 17uA ?

Thank you,

For anyone following this thread, there is a hardware problem with the MKRWAN1300 that prevents it from achieving a sleep current below 1.15mA. There will be a board revision to 2.0 that will correct the problem.

Dear all
Thank for this convrsation. I have a similar problem but I am still testing Arduino Low Power, but apparently this

sw.digitalWrite(wakeup_led,LOW);
LowPower.sleep(5000);
sw.digitalWrite(wakeup_led,HIGH);

goes to sleep because the led turn for 5 second.

But after free day, I see no difference. The battery goes from 4.2V to 3.7V in less than 3 days.
Without the lowpower, it goes down in 3 days as well . Not good.

I was expected to see a better difference.

My circuit is a bt different than yours. I am using Adafruit Feather MO adalogger with a AMD21 (ARM). I am not ueing sigfox but LoRa

Does some one has an experience with Adafruit Feather MO adalaoger and a RFM95 LoRa module radio in sleep mode, eight with AdruinoLowPower, or may be Sleepdog library from Adafruit?

I am going to investigate a bit more about wiring.c, but someone can tell exactely what does it and for what it's usefull? What impact if I remove it as well?

Many thanks for any support and help.

Hello @philgeek et al.,

this thread was really useful to get as low consumption as possible! I have a simple alarm created with the mkrfox1200, battery powered and using a reed switch.

Following the tips here now I'm able to get 128.7uA while on deepSleep mode. While transmitting, it's around 380-400uA for 5 seconds. For some reason it's a bit higher than what you got, but I think it's more than enough. The only modification I made to the vanilla Arduino framework has been, as said above, the changes on wiring.c

I'll monitor how long the battery lasts. For anyone interested, code of my app is here: