1+ /*
2+ ArduinoLowPower class for nRF52.
3+
4+ Written by Chiara Ruggeri (chiara@arduino.org)
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
0 commit comments