Giter VIP home page Giter VIP logo

arduinolowpower's Introduction

Arduino Low Power library

Check Arduino status Compile Examples status Spell Check status

This library allows the use of the low power features of the SAMD21 MCU. This means your battery powered projects will have a longer battery life on boards like MKRZero, MKR1000 and MKRFox1200.

For more information about this library please visit us at

https://www.arduino.cc/en/Reference/ArduinoLowPower

License

Copyright (c) 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

arduinolowpower's People

Contributors

aentinger avatar cmaglie avatar dependabot[bot] avatar engineer1999 avatar facchinm avatar karlsoderby avatar per1234 avatar sijk avatar sslupsky avatar stlehmann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduinolowpower's Issues

LowPower.idle() doesn't work as expected, and the argument to LowPower.idle(millis) has absolutely no effect.

This simple sketch (on a SAMD21, for ex. MKR WiFi 1010):

#include <ArduinoLowPower.h>

void setup()
{
  pinMode(0, OUTPUT);
  digitalWrite(0, LOW);
}

void loop()
{
  LowPower.idle();
  digitalWrite(0, !digitalRead(0));
}

produces a nice ~500 Hz square wave on pin D0, because the IDLE state is ended by the SysTick interrupt every ms.
This is fine and useful, but should be properly documented.

Adding any value as argument to LowPower.idle(): (I use random() here to emphasize any)

  LowPower.idle((int)random(1000));

lowers the frequency to ~10.6 Hz.

Setting the RTC alarm takes ~46 ms, and then the IDLE state is ended on the next SysTick interrupt.

Most of the time needed to set the RTC alarm comes from synchronisation calls in RTCZero.cpp like

    while (RTCisSyncing())
      ;

I guess looping around the wfi instruction waiting for the right time to pass would be a better solution than using the RTC...

Is there a limitation for the sleeping mode?

Hello
I am wondering if AdruinoLowPower can put in sleep mode my board during 1 hour?
If not what's the limitation?

Actually, I make a loop which make sleep my board 5sec, wake up to quickly flash a led, sleep for 5 sec alternatively during one hour.

I would like to increase to 10 sec-

Does the ArduinoLowPower library work with Adafruit MO AMD21 with the LoRa module as well?

Thank

Absence of README.md file

Hello, I am Bhargav Patel (Engineer1999) a GSoC2020 aspirant.
I have made a pull request #26 in ArduinoLowPower to add the README.md file in the ArduinoLowPower repository.

detachInterruptWakeup function

Hello,

I'm working on a project that will wait for bursts of ticks on a pin, and I'd like to make my arduino sleeping while nothing happens.
Therefore, I'd like to:

  1. be awaken on 1st tick
  2. use interrupts to count other ticks
  3. go to sleep after the burst

As this happens to be on the same pin, I need to "detach" the wake up (and reattach after burst completion).
I looked at the code, and I'm not sure of what to do (like unsetting the configuration)

Or is it not necessary, since there is no impact in being asked to be awaken while already awake, and use the existing callback?

Actually, I already have the code the normal behavior, wondering how to achieve low-power.

LowPower.sleep() on Arduino MKR WiFi 1010

Hi,

Trying to use this library on the Arduino MKR WiFi 1010 seems to ignore the sleep and/or just goes into a frozen state and never wakes up

#include <ArduinoLowPower.h> // https://www.arduino.cc/en/Reference/ArduinoLowPower

void setup() {

}

void loop() {
  Serial.begin(9600);
  while (!Serial);
  
  Serial.println("Waiting 10 seconds");
  
  delay(10000);

  Serial.println("Sleeping");
  Serial.flush();

  LowPower.sleep(5000); // sleep for 5 seconds
}

Screenshot 2021-01-14 at 11 38 53

Allow access to RTC

This is a great library. Not really an issue, more of a feature request.

Is it possible to add time-keeping via the RTC?

For example:

void setRtcTime(uint32_t time){
	// not sure if this is the best way to make sure the RTC is up and running
	if (!rtc.isConfigured()) {
		attachInterruptWakeup(RTC_ALARM_WAKEUP, NULL, 0);
	}

	rtc.setEpoch(time);
}

uint32_t getRtcTime(void){
	return rtc.getEpoch();
}

attaching an InterruptWakeup before and after deepSleep breaks RTCZero::getEpoch

I tested the following code on an MKR 1310:

#include <RTCZero.h>
#include <ArduinoLowPower.h>

void noop() {}

void setup() {
    Serial1.begin(115200);
    RTCZero rtc;
    rtc.begin();
    LowPower.attachInterruptWakeup(LORA_IRQ, noop, RISING);
    LowPower.deepSleep(1000);
    LowPower.attachInterruptWakeup(LORA_IRQ, noop, RISING);
    Serial1.println("This gets printed!");
    Serial1.println(rtc.getEpoch());
    Serial1.println("This never gets printed!");
}

void loop() {}

The first Serial1.println works and I get the message. But then reading the Epoch just results in an Endless Loop right here: https://github.com/arduino-libraries/RTCZero/blob/master/src/RTCZero.cpp#L488

So neither the Epoch nor the last Serial1.println get transmitted over Serial.

The code is just a minimal example of something that works around another problem where another library is overwriting the wakeup interrupt handler with a wrong one.

Wake on PA13 SAMD21 Arduino M0 Pro

Hi, can I use physical pin 22 on the chip (PA13) SAMD21 (Arduino M0 Pro) to wake up from sleep?

Somehow I can't get it to work with this pin.

LowPower.attachInterruptWakeup(43, encoder_int_func, RISING);

Serial not working after wakeup

Hi,

I am using a button to put Arduino in sleep mode and wake it up, but the Serial is not working anymore after it is waking up. What should I do?

#include "ArduinoLowPower.h"

volatile bool just_wakeup = true;

// Pin used to trigger a wakeup
const int pin = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pin, INPUT_PULLUP);
}

void loop() {
  if (just_wakeup) {
    just_wakeup = false;
    delay(3000);
    Serial.begin(115200);
  }
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  Serial.println("test");

  if (digitalRead(pin) == LOW) {
    Serial.end();
    delay(500);
    LowPower.attachInterruptWakeup(pin, wakeup_handler, FALLING );
    LowPower.deepSleep();
  }
}

void wakeup_handler() {
  just_wakeup = true;
  detachInterrupt(pin);
}

Calling LowPower.attachInterruptWakeup with irq_mode CHANGE causes ISR to be fired

Platform: Seeeduino XIAO SAMD21

Device supports Interrupts on any and all pins (just not 5 & 7 at the same time)

The input IO lines are all strapped low for test.

Setting up 6 interrupts:

const uint8_t switchPins[] = { 0, 1, 2, 3, 8, 10 };
const uint8_t numSwitches = sizeof(switchPins) / sizeof(switchPins[0]);

void (*ISRFunctions[numSwitches])() = {
  [] {
    switchChanged(0);
  },
  [] {
    switchChanged(1);
  },
  [] {
    switchChanged(2);
  },
  [] {
    switchChanged(3);
  },
  [] {
    switchChanged(4);
  },
  [] {
    switchChanged(5);
  }
};

void setup(){

...

for (uint8_t i = 0; i < numSwitches; i++) {
    pinMode(switchPins[i], INPUT_PULLUP);
  }
  delay(500);

   for (uint8_t i = 0; i < numSwitches; i++) {
    LowPower.attachInterruptWakeup((digitalPinToInterrupt(switchPins[i])), ISRFunctions[i], CHANGE);
  }
delay(1000);
}

//This will trigger 5 (not 6) calls to the ISR

The current workaround:

for (uint8_t i = 0; i < numSwitches; i++) {
    LowPower.attachInterruptWakeup((digitalPinToInterrupt(switchPins[i])), ISRFunctions[i], RISING);
  }
  delay(1000);
   for (uint8_t i = 0; i < numSwitches; i++) {
    LowPower.attachInterruptWakeup((digitalPinToInterrupt(switchPins[i])), ISRFunctions[i], CHANGE);
  }
  delay(1000);

WakeUp with SERIAL1

I would like to put the MKR on sleep mode until a character arrives on SERIAL1 (pin 13-14). Do you think it's possible with ArduinoLowPower Library ?

Can't get it to low power during sleep - Samd21

Hi,
I'm using a ATSAMD21G18A with this library and while sleeping the power consumption doesn't go 2mA. Unfortunatly that's to much for my application. Is there any chance to get it lower with this lib?

Boards without SERIAL_PORT_USBVIRTUAL

When using a SAMD21 on a custom pcb without a USB connector and commented out (//#define SERIAL_PORT_USBVIRTUAL SerialUSB) in variant.h there appears an error.

Would it be possible to add a check whether it's defined in variant.h or not?

Error message:
ArduinoLowPower-master/src/samd/ArduinoLowPower.cpp:41:6: error: 'SERIAL_PORT_USBVIRTUAL' was not declared in this scope if (SERIAL_PORT_USBVIRTUAL) {

nRF52 Arduino core

I am using Mistry's Arduino core and a custom nRF52 dev board and I tried to compile one of the simple timed low power examples and I am getting a couple of compile errors:

C:\Users\kris\AppData\Local\Temp\arduino_build_473580\sketch\serial_example.ino.cpp.o: In function `ArduinoLowPowerClass::sleep(int)':

C:\Users\kris\AppData\Local\Temp\arduino_build_473580\sketch/ArduinoLowPower.h:43: undefined reference to `LowPower'

C:\Users\kris\AppData\Local\Temp\arduino_build_473580\sketch/ArduinoLowPower.h:43: undefined reference to `ArduinoLowPowerClass::sleep(unsigned long)'

looks like I am missing the LowPower C module; where am I supposed to get this?

Edit:

Got it to compile by commenting out one line in the .h file:

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

not sure why this should matter.

Ran the timed wakeup example, but the device never wakes from sleep mode. The led remains on. If I comment out the lowPower.sleep(2000); call the led blinks, of course.

Good news is the power drops by 5 mA, which is great, but I need the device to wake up. Is it possible the RTC is not functioning on my nRF52, or that I need to attach an interrupt? Somewhat confused at this point why the simplest example doesn't just work...

And tried the wake from external example and it won't compile again with these kinds of errors:

C:\Users\kris\AppData\Local\Temp\arduino_build_385961\sketch\LowPower_externalGPIO_example.ino.cpp.o: In function `setup':

C:\Users\kris\Documents\Arduino\LowPower_externalGPIO_example/LowPower_externalGPIO_example.ino:28: undefined reference to `ArduinoLowPowerClass::attachInterruptWakeup(unsigned long, void (*)(), unsigned long)'

C:\Users\kris\AppData\Local\Temp\arduino_build_385961\sketch\LowPower_externalGPIO_example.ino.cpp.o: In function `loop':

C:\Users\kris\Documents\Arduino\LowPower_externalGPIO_example/LowPower_externalGPIO_example.ino:40: undefined reference to `ArduinoLowPowerClass::sleep()'

Add RTC time setting and getting functionality

Not really an issues, more of a request. I think it would be handy if we could access the underlying RTC to keep track of the time that has elapsed between e.g. two pin-interrupt wake's.

I propose two methods to achieve this:

void ArduinoLowPowerClass::setRtcTime(uint32_t time){
	// not sure if this is the best way to make sure the RTC is up and running
	if (!rtc.isConfigured()) {
		attachInterruptWakeup(RTC_ALARM_WAKEUP, NULL, 0);
	}

	rtc.setEpoch(time);
}

uint32_t ArduinoLowPowerClass::getRtcTime(void){
	return rtc.getEpoch();
}

I have tested this on SAMD and it seems to be working.

Arduino Nano RP2040 Connect not working with this library

Hi, just wondering if The Low Power Library will soon also work for the Arduino Nano RP2040 Connect ?

If yes, when will this be the case?
If no, what alternative library can I use for the Arduino Nano RP2040 Connect ?

Thank you for any hint on this.

Not working on SAMD

The following code never wakeup after the first sleep call (led always on)
#include <ArduinoLowPower.h>
void setup() {
// put your setup code here, to run once:
pinMode(6,OUTPUT);
}

void loop() {
// put your main code here, to run repeatedly:
digitalWrite(6,HIGH);
LowPower.sleep(500);
digitalWrite(6,LOW);
LowPower.sleep(500);
}

ArduinoLowPower and RTCZERO.h

Hi,

I need to use RTCZero to create a daily alarm based on RTC time, but I need to user ArduinoLowPower lib to create a short sleep of 10 seconds in loop.

Why do not work ?

(Arduino MRK 1400 GSM)

#include <RTCZero.h>
#include "ArduinoLowPower.h"

RTCZero rtcZero;

const byte rtcZero_seconds = 0;
const byte rtcZero_minutes = 22;
const byte rtcZero_hours = 14;
const byte rtcZero_day = 15;
const byte rtcZero_month = 3;
const byte rtcZero_year = 21;

void setup() {
  
  Serial.begin(9600);

  rtcZero.begin(); // initialize RTC 24H format
  rtcZero.setTime(rtcZero_hours, rtcZero_minutes, rtcZero_seconds);
  rtcZero.setDate(rtcZero_day, rtcZero_month, rtcZero_year);
  rtcZero.setAlarmTime(14, 22, 30);
  rtcZero.enableAlarm(rtcZero.MATCH_HHMMSS);
  
  rtcZero.attachInterrupt(alarmMatch);

}

void alarmMatch()
{
  Serial.println("Alarm Match!");
  
}


void loop() {
  
 //Serial.println("TESTE");
 LowPower.sleep(10000);

}

Thanks.

SAMD21 wrong sleep time with Seeedstudio XIAO

Hello.

I am seeing issues with wrong sleep time length on Seeedstudio SAMD21 board.

This code sleeps for 1.7 seconds, but should sleep for 1s:

#include "ArduinoLowPower.h"

#define DONE_PIN 1
#define LED_PIN LED_BUILTIN

void setup() {}

void loop() {
    digitalWrite(LED_PIN, HIGH);
    LowPower.deepSleep(1000);
    digitalWrite(LED_PIN, LOW);
 
    signalDONE(100);
    delay(10);
    signalDONE(200);
}

void signalDONE(uint8_t timeout) {
  pinMode(DONE_PIN, OUTPUT);
  digitalWrite(DONE_PIN, HIGH);
  delay(timeout);
  digitalWrite(DONE_PIN, LOW);
}

image

Compile problem in Arduino2.0 [nrf_lpcomp_input_t does not name a type] and more

The compiler shows me the problem below while I compile the ExternalWakeup.ino example, I used Arduino 2.0, and I have no idea what's happening, please help.

c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:31:1: error: 'nrf_lpcomp_input_t' does not name a type; did you mean 'nrf_gpio_pin_input_t'?
   31 | nrf_lpcomp_input_t aPin[]={NRF_LPCOMP_INPUT_1, NRF_LPCOMP_INPUT_2, NRF_LPCOMP_INPUT_4, NRF_LPCOMP_INPUT_5, NRF_LPCOMP_INPUT_6, NRF_LPCOMP_INPUT_7};
      | ^~~~~~~~~~~~~~~~~~
      | nrf_gpio_pin_input_t
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp: In member function 'void ArduinoLowPowerClass::enableWakeupFrom(wakeup_reason, uint32_t, uint32_t, uint32_t)':
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:111:3: error: 'detect_mode' was not declared in this scope
  111 |   detect_mode mode;
      |   ^~~~~~~~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:112:16: error: 'DOWN' was not declared in this scope
  112 |   if(option == DOWN)
      |                ^~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:113:4: error: 'mode' was not declared in this scope; did you mean 'modf'?
  113 |    mode = DOWN;
      |    ^~~~
      |    modf
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:114:21: error: 'UP' was not declared in this scope
  114 |   else if(option == UP)
      |                     ^~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:115:4: error: 'mode' was not declared in this scope; did you mean 'modf'?
  115 |    mode = UP;
      |    ^~~~
      |    modf
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:117:4: error: 'mode' was not declared in this scope; did you mean 'modf'?
  117 |    mode = CROSS;
      |    ^~~~
      |    modf
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:117:11: error: 'CROSS' was not declared in this scope
  117 |    mode = CROSS;
      |           ^~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:118:3: error: 'nrf_lpcomp_config_t' was not declared in this scope; did you mean 'nrf_pwm_configure'?
  118 |   nrf_lpcomp_config_t config={(nrf_lpcomp_ref_t)event, (nrf_lpcomp_detect_t)mode};
      |   ^~~~~~~~~~~~~~~~~~~
      |   nrf_pwm_configure
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:119:25: error: 'config' was not declared in this scope
  119 |   nrf_lpcomp_configure(&config);
      |                         ^~~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:119:3: error: 'nrf_lpcomp_configure' was not declared in this scope; did you mean 'nrf_pwm_configure'?
  119 |   nrf_lpcomp_configure(&config);
      |   ^~~~~~~~~~~~~~~~~~~~
      |   nrf_pwm_configure
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:122:27: error: 'aPin' was not declared in this scope; did you mean 'asin'?
  122 |   nrf_lpcomp_input_select(aPin[pin-14]);
      |                           ^~~~
      |                           asin
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:122:3: error: 'nrf_lpcomp_input_select' was not declared in this scope
  122 |   nrf_lpcomp_input_select(aPin[pin-14]);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:123:3: error: 'nrf_lpcomp_enable' was not declared in this scope; did you mean 'nrf_pwm_enable'?
  123 |   nrf_lpcomp_enable();
      |   ^~~~~~~~~~~~~~~~~
      |   nrf_pwm_enable
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:124:27: error: 'NRF_LPCOMP_TASK_START' was not declared in this scope; did you mean 'NRF_RTC_TASK_START'?
  124 |   nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_START);
      |                           ^~~~~~~~~~~~~~~~~~~~~
      |                           NRF_RTC_TASK_START
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:124:3: error: 'nrf_lpcomp_task_trigger' was not declared in this scope; did you mean 'nrf_pwm_task_trigger'?
  124 |   nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_START);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
      |   nrf_pwm_task_trigger
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:125:33: error: 'NRF_LPCOMP_EVENT_READY' was not declared in this scope
  125 |   while(!nrf_lpcomp_event_check(NRF_LPCOMP_EVENT_READY));
      |                                 ^~~~~~~~~~~~~~~~~~~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:125:10: error: 'nrf_lpcomp_event_check' was not declared in this scope; did you mean 'nrf_pwm_event_check'?
  125 |   while(!nrf_lpcomp_event_check(NRF_LPCOMP_EVENT_READY));
      |          ^~~~~~~~~~~~~~~~~~~~~~
      |          nrf_pwm_event_check
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:132:29: error: 'g_APinDescription' was not declared in this scope
  132 |    nrf_gpio_cfg_sense_input(g_APinDescription[pin].ulPin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
      |                             ^~~~~~~~~~~~~~~~~
c:\Users\eyesblue\SyncFolder\Coding\Arduino\libraries\Arduino_Low_Power\src\nrf52\ArduinoLowPower.cpp:134:29: error: 'g_APinDescription' was not declared in this scope
  134 |    nrf_gpio_cfg_sense_input(g_APinDescription[pin].ulPin, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
      |                             ^~~~~~~~~~~~~~~~~

exit status 1

Compilation error: exit status 1

Making Low Power great again

After days of work (I am a noob), I have finally achieved the following:

  • Deep sleep of the SAMD21G18
  • Sleep current at around 3µA
  • Wake up from sleep with external interrupt (button press) WITH edge detection (rising, falling or both edges)
  • No floating pins, therefore no unnecessary current draw during sleep (hundreds of microamps!)
  • no breaking of Arduino IO handling, all the pins are still in default (INPUT) state on initialization and during program execution

The issues:

  • The SAMD21G18 can only wake up with edge detection, if the external interrupt controller (EIC) is being clocked during sleep. For some reason, the LowPower library does not do this, although there is a OSCULP32K oscillator inside the MCU which runs all the time anyway and no matter what (even in the deepest of sleep modes).
  • The deep sleep current varies extremely if the pins are floating, which is the case for ALL pins by default with Arduino (all are set to INPUT at initialization). You'll see anything from 100µA to 500µA just because of the floating pins. Of course, one could just disconnect all the pins but with that there come two problems: 1) you can't wake up the MCU by bringing a pin low (i.e. pressing a button), and 2) all the pin config is lost (which pins are output, which are input, which are pulled up or down and which are muxed to peripherals) if you don't bother to save the registers somewhere first.
  • It is possible to disable the functionality that the Arduino core puts all pins into INPUT mode on initialization but apparently that breaks stuff
  • UART RX pins as well as the MISO pin are INPUT pins so I had to configure them as input pullups (for MISO, at least during sleep!)

So, what I have done to achieve my goals (actually not too complex):

In Setup(), first thing to do for me was to attach OCSULP32K to GCLK2:

GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );
	while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)

Then setup your pins according to your needs, I had some buttons connected:

pinMode(BTN2, INPUT_PULLUP);
pinMode(BTN3, INPUT_PULLUP);
pinMode(BTN4, INPUT_PULLUP);

Set the UART RX pins to INPUT_PULLUP as well

pinMode(0, INPUT_PULLUP);
pinMode(31, INPUT_PULLUP);

Attach my interrupt with an ISR on falling edge:
attachInterrupt(this->ButtonPin, myISR, FALLING);

Now comes the fat part, I wrote a sleep function which 1) saves all the pin configs 2) sets all pins which currently are INPUTs to INPUT_PULLUPs 3) sets MISO to INPUT_PULLUP (there might be more pins for which this should be done) and which puts the MCU to sleep and then after wakeup restores all the registers so the user program isn't affected by misconfigured GPIO pins.

	// Configure External Interrupt Controller (EIC) to GCLK2 which has been connected to OSCULP32K above, which in turn is ALWAYS running, even in deep sleep (can't be turned off)
	// It seems that this MUST happen AFTER the interrupt has been attached
	GCLK->CLKCTRL.reg = uint16_t(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | GCLK_CLKCTRL_ID( GCLK_CLKCTRL_ID_EIC_Val ) );
	while (GCLK->STATUS.bit.SYNCBUSY) {}
	
	USBDevice.detach();
	USBDevice.end();
	USBDevice.standby();

	Serial.println();

	for (uint8_t n = 0; n < PORT_GROUPS; n++)
	{
		regDir[n] = PORT->Group[n].DIR.reg;
		regOut[n] = PORT->Group[n].OUT.reg;
	}
	
	// Save current pin config and set all INPUT pins to INPUT_PULLUP
	for (uint8_t n=0; n<NUM_DIGITAL_PINS; n++)
	{
		this->regPinCFG[n] = PORT->Group[g_APinDescription[n].ulPort].PINCFG[g_APinDescription[n].ulPin].reg;
		
		if ((PORT->Group[g_APinDescription[n].ulPort].PINCFG[g_APinDescription[n].ulPin].reg & (uint8_t)(PORT_PINCFG_INEN)) == (uint8_t)(PORT_PINCFG_INEN) &&
			(PORT->Group[g_APinDescription[n].ulPort].DIR.reg & (uint32_t)(1<<g_APinDescription[n].ulPin)) == 0 &&
			(PORT->Group[g_APinDescription[n].ulPort].PINCFG[g_APinDescription[n].ulPin].reg & (uint8_t)(PORT_PINCFG_PULLEN)) == 0)
		{
			pinMode(n, INPUT_PULLUP);
		}
	}

	// Save MISO pin config
	this->pinSPICFG[0] = PORT->Group[g_APinDescription[PIN_SPI_MISO].ulPort].PINCFG[g_APinDescription[PIN_SPI_MISO].ulPin].reg;
	
	// Set MISO pin to non-floating states
	pinMode(PIN_SPI_MISO, INPUT_PULLUP);
	
	SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; //cth to fix hangs

	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__DSB();
	__WFI();
	
	SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //restore

	for (uint8_t n = 0; n < PORT_GROUPS; n++)
	{
		PORT->Group[n].DIR.reg = regDir[n];
		PORT->Group[n].OUT.reg = regOut[n];
	}

	// Restore previously saved pin config
	for (uint8_t n=0; n<NUM_DIGITAL_PINS; n++)
	{
		PORT->Group[g_APinDescription[n].ulPort].PINCFG[g_APinDescription[n].ulPin].reg = this->regPinCFG[n];
	}

	// Restore previously saved MISO pin config
	PORT->Group[g_APinDescription[PIN_SPI_MISO].ulPort].PINCFG[g_APinDescription[PIN_SPI_MISO].ulPin].reg = this->pinSPICFG[0];

	USBDevice.init();
	USBDevice.attach();

Most probably, to reach library quality and broad compatibility with all the possible configurations and SAMD21 boards, this needs to be refined very much but as I said: I am a noob and this took me days to find out and to do.

I would be very happy to see the fixes refined and implemented into the LowPower library because in the current state, with floating pins, only level detection external interrupts and so on, in my humble opinion this is a little bit useless for real low power applications.

I mean, the SAMD21 is a way more powerful MCU than the AVR (328p for example) and still it can achieve way lower standby power consumption and I think that it is a pity that this potential is kind of wasted.

Thank you for your attention.

SERCOM stops receiving after sleep

Hi,

The sleeping works fine, and after wake up the next function and Loop is called as well the timer Ticker function.

However on the below implementation of a serial bridge the SERCOM2 does not transmit anymore after external wake, my assumption is that it does not get initialized again.

Could it be something that kept running during sleep and overflowed?

ATSAMD21E18A MCU on a Adafruit Trinket M0

#include "Arduino.h"
#include "wiring_private.h"
#include "Ticker.h"
#include "ArduinoLowPower.h"

#define PIN_INT1          (7u)
#define PIN_INT2          (8u)
#define BATT              (23ul)

bool blink  = true;
uint32_t up = 0;

void blinky( void );
void goodNight( void );
void wakefromsleep( void );

Uart Serial_GNSS(&sercom2, 22, 21, SERCOM_RX_PAD_3, UART_TX_PAD_2);

void SERCOM2_Handler()
{
  Serial_GNSS.IrqHandler();
}

Ticker blinkIt( blinky, 800 );
Ticker faster( blinkD, 200 );

void wakefromsleep()
{
  faster.start();
}

void blinky()
{
  digitalWrite( 12, blink );
  blink = !blink;
  up++;

  if( up > 10 )
  {
    up = 0;
    blinkIt.stop();
    Serial_GNSS.end();
    LowPower.sleep();
    Serial_GNSS.begin(9600);
  }

}

void blinkD()
{
  digitalWrite( 12, blink );
  blink = !blink;
}

void setup() {

  blinkIt.start();

  pinMode( 12, OUTPUT );

  // Interrupt 1 to detect when it's moving -> PA00 pin 8
  pinMode(1, INPUT_PULLDOWN);
  LowPower.attachInterruptWakeup(1, wakefromsleep, RISING);

  pinPeripheral(21, PIO_SERCOM);
  pinPeripheral(22, PIO_SERCOM);

  Serial.begin( 9600 );

  Serial_GNSS.begin( 9600 );

}

void loop()
{
  blinkIt.update();
  faster.update();

  // If anything comes in Serial (USB),
  if (Serial.available()) 
  {
    Serial_GNSS.write(Serial.read());   // read it and send it out Serial_GNSS
  }

  // If anything comes in Serial_GNSS
  if (Serial_GNSS.available()) 
  {
    Serial.write(Serial_GNSS.read());   // read it and send it out Serial (USB)
  }

}

Serial not working after attachAdcInterrupt

I'm using a MKR WAN 1310 with the following code:

Serial.print("Battery voltage: ");
Serial.println(analogRead(BATTERY_ANALOG_PIN));
LowPower.attachAdcInterrupt(BATTERY_ANALOG_PIN, lowBatteryVoltage, ADC_INT_BETWEEN, minLowBattery, maxLowBattery);
Serial.println("Can you see me?");

I can see in my console that the battery voltage is printed but any other Serial.print() after attachAdcInterrupt() doesn't print anything.

Is it supposed to be like this? That when you attach the interrupt, Serial no longer works? Is there any other functions that may not work?

ArduinoLowPower working in all nRF52 architectures?

I am using ArduinoLowPower library on my Arduino Nano 33 BLE but during compile a "WARNING: library ArduinoLowPower-master claims to run on samd, nrf52 architecture(s) and may be incompatible with your current board which runs on mbed architecture(s)." is shown and then it is not compiled.
I have a doubt... Arduino Nano 33 BLE is a Nordic nRF52 !!, I have to specify this in my ino file?

Thanks

LowPower.DeepSleep 24h doesn't work

Hi Everyone,

I am using following code on the MKRFOX1200.
I need the board to goto sleep for 24h (or 48), wake up send a message and goto sleep again.

I have the following code:

#include <SigFox.h>
#include <ArduinoLowPower.h>
#include "Maxbotix.h"
#define ReportRequest 5
#define GotoSleep 4
#define SLEEPTIME 1440 * 60 * 1000 // Set the delay to 1440 minutes (1440 min x 60 seconds x 1000 milliseconds)
int DEBUG = true;
String strPercent;
String strPercentBat;
String strMessageLevel;
String strMessageBat;
boolean DailyLevelReported = false;

//afstandsensor
#define DISTANCE_SENSOR 6 //Maxbotix PW

long duration, cm, inches;
int BatteryValue;
long BatteryVoltage;
int BatteryPercent;
//distance
long distance;
int tanklevel;

//afstandsensor
Maxbotix rangeSensorPW(DISTANCE_SENSOR, Maxbotix::PW, Maxbotix::XL, Maxbotix::BEST);

//Response from Sigfox server
int sgfResponse = 0;

void setup() {

pinMode(ReportRequest, INPUT_PULLUP);
pinMode(GotoSleep, INPUT_PULLUP);

  if (!SigFox.begin()) {
  // Something is wrong
  reboot();
  }
    DailyLevelReported = false;

SigFox.end(); // Send module to standby until we need to send a message
SigFox.debug(); // Important (for more information check the Forum http://forum.arduino.cc/index.php?topic=478950.0;nowap)

LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, dummy, CHANGE);
}

void loop() {

distance = rangeSensorPW.getRange();
BatteryValue = analogRead(ADC_BATTERY);
BatteryVoltage = BatteryValue / 100;
BatteryPercent = map(BatteryValue, 0, 310, 0, 100);
tanklevel = map(distance, 1, 148, 100, 0);

SigFox.begin();
// Wait at least 30mS after first configuration (100mS before)
delay(100);
if (tanklevel < 10) strPercent = "%%%";
else strPercent = "%%";
if (BatteryPercent < 10) strPercentBat = "%%%";
else if (BatteryPercent = 100) strPercentBat = "%";
else strPercentBat = "%%";
strMessageLevel = "Tank ";
strMessageBat = "Battery ";
SigFox.beginPacket();
SigFox.print(tanklevel + strPercent + BatteryPercent + strPercentBat);

int ret = SigFox.endPacket();

if (ret == 0){

SigFox.end();
LowPower.deepSleep(uint32_t(SLEEPTIME));

}

}

void reboot() {
NVIC_SystemReset();
while (1);

}

void dummy() {
volatile int ttt = 0;
}

When I use 15mins for SLEEPTIME everything is good, but when I use 1440mins, the board goes to sleep but wakes up immediatly, sends the message, goes to sleep, wakes up again without delay.

I read in another post that the max sleep time is 49 days, so far I haven't tested where the limit is for my situation. I just know it works with 8mins and 15mins but not with 1440mins.

Someone any ideas?

Thanks,

Jef

Clock disabling code looks wrong

GCLK->CLKCTRL.bit.CLKEN = 0; //disable GCLK module

The comment at this line says "disable GCLK module". But my reading of the somewhat ambiguous documentation of the CLKCTRL register is different.

I believe each generic clock id has its own enable (although I don't see this spelled out clearly in the documentation). The documentation for CLKCTRL says:

This register allows the user to configure one of the generic clocks, as specified in the CLKCTRL.ID bit group. To write to the CLKCTRL register, do a 16-bit write with all configurations and the ID.

To read the CLKCTRL register, first do an 8-bit write to the CLKCTRL.ID bit group with the ID of the generic clock whose configuration is to be read, and then read the CLKCTRL register.

I believe what line 9 is actually doing (via a forbidden 8-bit write), is setting the enable to 0, setting the GEN field to 0 (which means select generic clock generator 0) and then applying these changes to the ID field that last happened to be set. So it's essentially disabling and corrupting the clock source for the most recently configured clock generator ID. Things will work ok if you don't intermingle this low power code with other libraries that configure clocks. In my case, trying to add an interrupt between calls to other library code (Adafruit_SSD1306) caused that other code to hang. I believe the reason that code hangs is that the clocks to SERCOM2 had been disabled by this bug.

As I understand things, this line should be:

  GCLK->CLKCTRL.reg =
      (uint16_t)(GCLK_CLKCTRL_ID(GCM_EIC));  // Disable EIC clock (also sets
                                             // GCLK_CTRL_CLKEN bit to 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.