Browse Source

add sleep(1000)

master
Ralf Behrens 4 years ago
parent
commit
db83aa3f99
  1. 225
      lib/Low_Power/ArduinoLowPower.cpp
  2. 106
      lib/Low_Power/ArduinoLowPower.h
  3. 8
      src/main.cpp

225
lib/Low_Power/ArduinoLowPower.cpp

@ -0,0 +1,225 @@ @@ -0,0 +1,225 @@
#if defined(ARDUINO_ARCH_SAMD)
#include "ArduinoLowPower.h"
static void configGCLK6()
{
// 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);
/* 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;
}
void ArduinoLowPowerClass::idle() {
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
PM->SLEEP.reg = 2;
__DSB();
__WFI();
}
void ArduinoLowPowerClass::idle(uint32_t millis) {
setAlarmIn(millis);
idle();
}
void ArduinoLowPowerClass::sleep() {
bool restoreUSBDevice = false;
if (SERIAL_PORT_USBVIRTUAL) {
USBDevice.standby();
} else {
USBDevice.detach();
restoreUSBDevice = true;
}
// Ralf
//USBDevice.detach();
//restoreUSBDevice = true;
//----------
// Disable systick interrupt: See https://www.avrfreaks.net/forum/samd21-samd21e16b-sporadically-locks-and-does-not-wake-standby-sleep-mode
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__DSB();
__WFI();
// Enable systick interrupt
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
if (restoreUSBDevice) {
USBDevice.attach();
}
}
void ArduinoLowPowerClass::sleep(uint32_t millis) {
setAlarmIn(millis);
sleep();
}
void ArduinoLowPowerClass::deepSleep() {
sleep();
}
void ArduinoLowPowerClass::deepSleep(uint32_t millis) {
sleep(millis);
}
void ArduinoLowPowerClass::setAlarmIn(uint32_t millis) {
if (!rtc.isConfigured()) {
attachInterruptWakeup(RTC_ALARM_WAKEUP, NULL, (irq_mode)0);
}
uint32_t now = rtc.getEpoch();
rtc.setAlarmEpoch(now + millis/1000);
rtc.enableAlarm(rtc.MATCH_YYMMDDHHMMSS);
}
void ArduinoLowPowerClass::attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, irq_mode 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);
configGCLK6();
// Enable wakeup capability on pin in case being used during sleep
EIC->WAKEUP.reg |= (1 << in);
}
void ArduinoLowPowerClass::attachAdcInterrupt(uint32_t pin, voidFuncPtr callback, adc_interrupt mode, uint16_t lo, uint16_t hi)
{
uint8_t winmode = 0;
switch (mode) {
case ADC_INT_BETWEEN: winmode = ADC_WINCTRL_WINMODE_MODE3; break;
case ADC_INT_OUTSIDE: winmode = ADC_WINCTRL_WINMODE_MODE4; break;
case ADC_INT_ABOVE_MIN: winmode = ADC_WINCTRL_WINMODE_MODE1; break;
case ADC_INT_BELOW_MAX: winmode = ADC_WINCTRL_WINMODE_MODE2; break;
default: return;
}
adc_cb = callback;
configGCLK6();
// Configure ADC to use GCLK6 (OSCULP32K)
while (GCLK->STATUS.bit.SYNCBUSY) {}
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_ADC
| GCLK_CLKCTRL_GEN_GCLK6
| GCLK_CLKCTRL_CLKEN;
while (GCLK->STATUS.bit.SYNCBUSY) {}
// Set ADC prescaler as low as possible
ADC->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV4;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Configure window mode
ADC->WINLT.reg = lo;
ADC->WINUT.reg = hi;
ADC->WINCTRL.reg = winmode;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Enable window interrupt
ADC->INTENSET.bit.WINMON = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Enable ADC in standby mode
ADC->CTRLA.bit.RUNSTDBY = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Enable continuous conversions
ADC->CTRLB.bit.FREERUN = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Configure input mux
ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Enable the ADC
ADC->CTRLA.bit.ENABLE = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Start continuous conversions
ADC->SWTRIG.bit.START = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Enable the ADC interrupt
NVIC_EnableIRQ(ADC_IRQn);
}
void ArduinoLowPowerClass::detachAdcInterrupt()
{
// Disable the ADC interrupt
NVIC_DisableIRQ(ADC_IRQn);
// Disable the ADC
ADC->CTRLA.bit.ENABLE = 0;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Disable continuous conversions
ADC->CTRLB.bit.FREERUN = 0;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Disable ADC in standby mode
ADC->CTRLA.bit.RUNSTDBY = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Disable window interrupt
ADC->INTENCLR.bit.WINMON = 1;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Disable window mode
ADC->WINCTRL.reg = ADC_WINCTRL_WINMODE_DISABLE;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Restore ADC prescaler
ADC->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV512_Val;
while (ADC->STATUS.bit.SYNCBUSY) {}
// Restore ADC clock
while (GCLK->STATUS.bit.SYNCBUSY) {}
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_ADC
| GCLK_CLKCTRL_GEN_GCLK0
| GCLK_CLKCTRL_CLKEN;
while (GCLK->STATUS.bit.SYNCBUSY) {}
adc_cb = nullptr;
}
void ADC_Handler()
{
// Clear the interrupt flag
ADC->INTFLAG.bit.WINMON = 1;
LowPower.adc_cb();
}
ArduinoLowPowerClass LowPower;
#endif // ARDUINO_ARCH_SAMD

106
lib/Low_Power/ArduinoLowPower.h

@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
#ifndef _ARDUINO_LOW_POWER_H_
#define _ARDUINO_LOW_POWER_H_
#include <Arduino.h>
#ifdef ARDUINO_ARCH_AVR
#error The library is not compatible with AVR boards
#endif
#ifdef ARDUINO_ARCH_SAMD
#include "RTCZero.h"
#endif
#if defined(ARDUINO_SAMD_TIAN) || defined(ARDUINO_NRF52_PRIMO)
// add here any board with companion chip which can be woken up
#define BOARD_HAS_COMPANION_CHIP
#endif
#define RTC_ALARM_WAKEUP 0xFF
#ifdef ARDUINO_API_VERSION
using irq_mode = PinStatus;
#else
using irq_mode = uint32_t;
#endif
//typedef void (*voidFuncPtr)( void ) ;
typedef void (*onOffFuncPtr)( bool ) ;
typedef enum{
OTHER_WAKEUP = 0,
GPIO_WAKEUP = 1,
NFC_WAKEUP = 2,
ANALOG_COMPARATOR_WAKEUP = 3
} wakeup_reason;
#ifdef ARDUINO_ARCH_SAMD
enum adc_interrupt
{
ADC_INT_BETWEEN,
ADC_INT_OUTSIDE,
ADC_INT_ABOVE_MIN,
ADC_INT_BELOW_MAX,
};
#endif
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, irq_mode 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
#ifdef ARDUINO_ARCH_SAMD
void attachAdcInterrupt(uint32_t pin, voidFuncPtr callback, adc_interrupt mode, uint16_t lo, uint16_t hi);
void detachAdcInterrupt();
#endif
private:
void setAlarmIn(uint32_t millis);
#ifdef ARDUINO_ARCH_SAMD
RTCZero rtc;
voidFuncPtr adc_cb;
friend void ADC_Handler();
#endif
#ifdef BOARD_HAS_COMPANION_CHIP
void (*companionSleepCB)(bool);
#endif
};
extern ArduinoLowPowerClass LowPower;
#endif

8
src/main.cpp

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
#include <SPI.h>
#include "hseSensorProtocol.h"
#include "MessenSensoren.h"
#include "ArduinoLowPower.h"
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
@ -226,6 +227,9 @@ void onEvent(ev_t ev) { @@ -226,6 +227,9 @@ void onEvent(ev_t ev) {
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
LowPower.sleep(1000);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
@ -276,7 +280,7 @@ void setup() { @@ -276,7 +280,7 @@ void setup() {
delay(5000);
//while (!Serial);
Serial.begin(19200);
Serial.println(F("Starting 1.03"));
Serial.println(F("Starting 1.04"));
#ifdef __SAMD21G18A__
Serial.println(F("SAMD21G18A ARM Cortex-M0+ detected"));
@ -310,6 +314,8 @@ void setup() { @@ -310,6 +314,8 @@ void setup() {
void loop() {
os_runloop_once();
}

Loading…
Cancel
Save