Skip to content

Commit 21d2f75

Browse files
chiararuggerifacchinm
authored andcommitted
Added nRF52 compatibility
Waking from deepSleep() is comparable to an hard reset; the sketch won't restart from the sleep invocation but the wakeuup source can be retrieved with wakeupReason()
1 parent fcbf16f commit 21d2f75

File tree

6 files changed

+303
-4
lines changed

6 files changed

+303
-4
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
PrimoDeepSleep.ino
3+
4+
Written by Chiara Ruggeri ([email protected])
5+
6+
This example for the Arduino Primo board shows how to use
7+
low power library to enter in power off mode and save power.
8+
This mode ensure the deepest power saving mode. If you need
9+
a faster response from the board use standby function instead.
10+
11+
Please note that once exited from the deepest sleep mode the
12+
board will reset (so setup will be run again).
13+
14+
The functions enableWakeupFrom set the peripheral that will wake up
15+
the board. By calling it more than once you can choose more than
16+
a wakeup source.
17+
The board will be reset when it wakes up from power off.
18+
You can use wakeUpCause() function to find out what signals woke up
19+
the board if you use more than one wakeUpBy.. function.
20+
21+
This example code is in the public domain.
22+
*/
23+
24+
#include "ArduinoLowPower.h"
25+
26+
27+
// Pin used to wakeup the board
28+
const int digitalPin = 10;
29+
30+
// Pin used in Compatarot module to wake up the board
31+
const int analogPin = A0;
32+
33+
34+
void StmEspPM(bool sleep){
35+
// enable USER1_BUTTON to turn STM32 off and on when pressed.
36+
// note that when STM32 is off you cannot load any new sketch.
37+
pinMode(USER1_BUTTON, STM32_IT);
38+
39+
// turn ESP8266 off or on
40+
digitalWrite(GPIO_ESP_PW, sleep ? LOW: HIGH);
41+
}
42+
43+
void setup() {
44+
Serial.begin(9600);
45+
pinMode(LED_BUILTIN, OUTPUT);
46+
digitalWrite(LED_BUILTIN, HIGH);
47+
delay(500);
48+
digitalWrite(LED_BUILTIN, LOW);
49+
delay(500);
50+
51+
//look for what peripheral woke up the board
52+
//reason is 0 at the first execution
53+
wakeup_reason reason=LowPower.wakeupReason();
54+
if(reason==GPIO_WAKEUP) //GPIO caused the wake up
55+
doMyStuff();
56+
else
57+
if(reason==NFC_WAKEUP) //NFC caused the wake up
58+
doMyStuffWithNFC();
59+
else
60+
if(reason==ANALOG_COMPARATOR_WAKEUP) //Comparator caused the wake up
61+
doOtherStuff();
62+
63+
Serial.println("Hi all, I return to sleep");
64+
65+
LowPower.companionLowPowerCallback(StmEspPM);
66+
// Send sleep command to ESP and enable USER1_BUTTON to turn STM off
67+
LowPower.companionSleep();
68+
69+
//set digital pin 10 to wake up the board when LOW level is detected
70+
LowPower.enableWakeupFrom(GPIO_WAKEUP, digitalPin, LOW);
71+
//let the board be woken up by any NFC field
72+
LowPower.enableWakeupFrom(NFC_WAKEUP);
73+
//wake up the board when the voltage on pin A0 goes below the voltage on pin AREF
74+
LowPower.enableWakeupFrom(ANALOG_COMPARATOR_WAKEUP, analogPin, AREF, UP);
75+
//go in low power mode. Note that the board will reset once it is woken up
76+
LowPower.deepSleep();
77+
}
78+
79+
80+
void loop() {}
81+
82+
void doMyStuff(){
83+
//insert your code here
84+
}
85+
86+
void doMyStuffWithNFC(){
87+
//insert your code here
88+
}
89+
90+
void doOtherStuff(){
91+
//insert your code here
92+
}

keywords.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ idle KEYWORD2
1717
sleep KEYWORD2
1818
deepSleep KEYWORD2
1919
attachInterruptWakeup KEYWORD2
20+
enableWakeupFrom KEYWORD2
21+
companionLowPowerCallback KEYWORD2
22+
companionSleep KEYWORD2
23+
companionWakeup KEYWORD2
24+
wakeupReason KEYWORD2
2025

2126
#######################################
2227
# Constants (LITERAL1)
2328
#######################################
29+
30+
OTHER_WAKEUP LITERAL1
31+
GPIO_WAKEUP LITERAL1
32+
NFC_WAKEUP LITERAL1
33+
ANALOG_COMPARATOR_WAKEUP LITERAL1

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name=Arduino Low Power
22
version=1.0.0
33
author=Arduino
44
maintainer=Arduino LLC
5-
sentence=Power save primitives features for SAMD 32bit boards
5+
sentence=Power save primitives features for SAMD and nRF52 32bit boards
66
paragraph=With this library you can manage the low power states of newer Arduino boards
77
category=Device Control
88
url=http://arduino.cc/libraries/ArduinoLowPower
9-
architectures=samd
9+
architectures=samd,nrf52

src/ArduinoLowPower.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "RTCZero.h"
1212
#endif
1313

14-
#if defined(ARDUINO_SAMD_TIAN)
14+
#if defined(ARDUINO_SAMD_TIAN) || defined(ARDUINO_NRF52_PRIMO)
1515
// add here any board with companion chip which can be woken up
1616
#define BOARD_HAS_COMPANION_CHIP
1717
#endif
@@ -21,6 +21,14 @@
2121
//typedef void (*voidFuncPtr)( void ) ;
2222
typedef void (*onOffFuncPtr)( bool ) ;
2323

24+
typedef enum{
25+
OTHER_WAKEUP = 0,
26+
GPIO_WAKEUP = 1,
27+
NFC_WAKEUP = 2,
28+
ANALOG_COMPARATOR_WAKEUP = 3
29+
} wakeup_reason;
30+
31+
2432
class ArduinoLowPowerClass {
2533
public:
2634
void idle(void);
@@ -55,9 +63,16 @@ class ArduinoLowPowerClass {
5563
}
5664
#endif
5765

66+
#ifdef ARDUINO_ARCH_NRF52
67+
void enableWakeupFrom(wakeup_reason peripheral, uint32_t pin = 0xFF, uint32_t event = 0xFF, uint32_t option = 0xFF);
68+
wakeup_reason wakeupReason();
69+
#endif
70+
5871
private:
5972
void setAlarmIn(uint32_t millis);
73+
#ifdef ARDUINO_ARCH_SAMD
6074
RTCZero rtc;
75+
#endif
6176
#ifdef BOARD_HAS_COMPANION_CHIP
6277
void (*companionSleepCB)(bool);
6378
#endif

src/nrf52/ArduinoLowPower.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
ArduinoLowPower class for nRF52.
3+
4+
Written by Chiara Ruggeri ([email protected])
5+
6+
Copyright (c) 2017 Arduino AG. All right reserved.
7+
8+
This library is free software; you can redistribute it and/or
9+
modify it under the terms of the GNU Lesser General Public
10+
License as published by the Free Software Foundation; either
11+
version 2.1 of the License, or (at your option) any later version.
12+
13+
This library is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16+
See the GNU Lesser General Public License for more details.
17+
18+
You should have received a copy of the GNU Lesser General Public
19+
License along with this library; if not, write to the Free Software
20+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
23+
#if defined(ARDUINO_ARCH_NRF52)
24+
25+
#include "ArduinoLowPower.h"
26+
#include "WInterrupts.h"
27+
#include "nrf_rtc.h"
28+
29+
volatile bool event = false;
30+
void (*functionPointer)(void);
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};
32+
33+
void wakeUpGpio(){
34+
event = true;
35+
if(functionPointer)
36+
functionPointer();
37+
}
38+
39+
void ArduinoLowPowerClass::idle() {
40+
// nRF52 has just two low power modes. Call sleep if idle is called.
41+
sleep();
42+
}
43+
44+
void ArduinoLowPowerClass::idle(uint32_t millis) {
45+
setAlarmIn(millis);
46+
idle();
47+
}
48+
49+
void ArduinoLowPowerClass::sleep() {
50+
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
51+
event=false;
52+
while(!event){
53+
sd_app_evt_wait();
54+
}
55+
}
56+
57+
void ArduinoLowPowerClass::sleep(uint32_t millis) {
58+
setAlarmIn(millis);
59+
sleep();
60+
}
61+
62+
void ArduinoLowPowerClass::deepSleep() {
63+
//Enter in systemOff mode only when no EasyDMA transfer is active
64+
//this is achieved by disabling all peripheral that use it
65+
NRF_UARTE0->ENABLE = UARTE_ENABLE_ENABLE_Disabled; //disable UART
66+
NRF_SAADC ->ENABLE = (SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos); //disable ADC
67+
NRF_PWM0 ->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos); //disable all pwm instance
68+
NRF_PWM1 ->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
69+
NRF_PWM2 ->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
70+
NRF_TWIM1 ->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos); //disable TWI Master
71+
NRF_TWIS1 ->ENABLE = (TWIS_ENABLE_ENABLE_Disabled << TWIS_ENABLE_ENABLE_Pos); //disable TWI Slave
72+
73+
//Enter in System OFF mode
74+
sd_power_system_off();
75+
76+
/*Only for debugging purpose, will not be reached without connected debugger*/
77+
while(1);
78+
}
79+
80+
void ArduinoLowPowerClass::setAlarmIn(uint32_t millis) {
81+
nrf_rtc_prescaler_set(NRF_RTC1, 32);
82+
//enable interrupt
83+
NVIC_SetPriority(RTC1_IRQn, 2); //high priority
84+
NVIC_ClearPendingIRQ(RTC1_IRQn);
85+
NVIC_EnableIRQ(RTC1_IRQn);
86+
nrf_rtc_event_clear(NRF_RTC1, NRF_RTC_EVENT_COMPARE_0);
87+
nrf_rtc_int_enable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
88+
//Tick every 1 ms
89+
nrf_rtc_cc_set(NRF_RTC1, 0, millis);
90+
91+
//start RTC
92+
nrf_rtc_task_trigger(NRF_RTC1, NRF_RTC_TASK_START);
93+
}
94+
95+
void ArduinoLowPowerClass::attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode) {
96+
functionPointer = callback;
97+
98+
if(pin == RTC_ALARM_WAKEUP)
99+
return;
100+
101+
pinMode(pin, INPUT_PULLUP);
102+
attachInterrupt(pin, wakeUpGpio, mode);
103+
}
104+
105+
void ArduinoLowPowerClass::enableWakeupFrom(wakeup_reason peripheral, uint32_t pin, uint32_t event, uint32_t option){
106+
if(peripheral == NFC_WAKEUP){
107+
NRF_NFCT->TASKS_SENSE=1;
108+
return;
109+
}
110+
if(peripheral == ANALOG_COMPARATOR_WAKEUP){
111+
detect_mode mode;
112+
if(option == DOWN)
113+
mode = DOWN;
114+
else if(option == UP)
115+
mode = UP;
116+
else
117+
mode = CROSS;
118+
nrf_lpcomp_config_t config={(nrf_lpcomp_ref_t)event, (nrf_lpcomp_detect_t)mode};
119+
nrf_lpcomp_configure(&config);
120+
if(pin<14 && pin>19)
121+
return; //no analog pin is choosen
122+
nrf_lpcomp_input_select(aPin[pin-14]);
123+
nrf_lpcomp_enable();
124+
nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_START);
125+
while(!nrf_lpcomp_event_check(NRF_LPCOMP_EVENT_READY));
126+
return;
127+
}
128+
if(peripheral == GPIO_WAKEUP){
129+
if(pin > 20)// allow wake up only from digital and analog pins
130+
return;
131+
if(event==LOW)
132+
nrf_gpio_cfg_sense_input(g_APinDescription[pin].ulPin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
133+
else
134+
nrf_gpio_cfg_sense_input(g_APinDescription[pin].ulPin, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
135+
}
136+
}
137+
138+
wakeup_reason ArduinoLowPowerClass::wakeupReason(){
139+
uint32_t guilty;
140+
sd_power_reset_reason_get(&guilty);
141+
if(guilty & 0x10000){ // GPIO
142+
//RESETREAS is a cumulative register. We need to clear it by writing 1 in the relative field
143+
sd_power_reset_reason_clr(1 << 16);
144+
return GPIO_WAKEUP;
145+
}
146+
if(guilty & 0x80000){ //NFC
147+
sd_power_reset_reason_clr(1 << 19);
148+
return NFC_WAKEUP;
149+
}
150+
if(guilty & 0x20000){ //COMP
151+
sd_power_reset_reason_clr(1 << 17);
152+
return ANALOG_COMPARATOR_WAKEUP;
153+
}
154+
return OTHER_WAKEUP;
155+
}
156+
157+
158+
ArduinoLowPowerClass LowPower;
159+
160+
#ifdef __cplusplus
161+
extern "C"{
162+
#endif
163+
164+
void RTC1_IRQHandler(void)
165+
{
166+
event=true;
167+
nrf_rtc_event_clear(NRF_RTC1, NRF_RTC_EVENT_COMPARE_0);
168+
nrf_rtc_task_trigger(NRF_RTC1, NRF_RTC_TASK_CLEAR);
169+
nrf_rtc_task_trigger(NRF_RTC1, NRF_RTC_TASK_STOP);
170+
if(functionPointer)
171+
functionPointer();
172+
}
173+
174+
#ifdef __cplusplus
175+
}
176+
#endif
177+
178+
#endif // ARDUINO_ARCH_NRF52

src/ArduinoLowPower.cpp renamed to src/samd/ArduinoLowPower.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#if defined(ARDUINO_ARCH_SAMD)
2+
13
#include "ArduinoLowPower.h"
24
#include "WInterrupts.h"
35

@@ -87,4 +89,6 @@ void ArduinoLowPowerClass::attachInterruptWakeup(uint32_t pin, voidFuncPtr callb
8789
NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
8890
}
8991

90-
ArduinoLowPowerClass LowPower;
92+
ArduinoLowPowerClass LowPower;
93+
94+
#endif // ARDUINO_ARCH_SAMD

0 commit comments

Comments
 (0)