From 02774210dc89bbd917799ee411474071cc2f6d60 Mon Sep 17 00:00:00 2001 From: pa-pa <(none)> Date: Sat, 23 Nov 2019 22:51:40 +0100 Subject: [PATCH] IRQ based battery measurement during active time --- Activity.h | 10 +++-- AskSinPP.h | 15 ++++++++ BatterySensor.h | 61 ++++++++++++++++++++++++++++++ Globals.cpp | 4 ++ examples/HM-SEC-RHS/HM-SEC-RHS.ino | 13 +++++-- 5 files changed, 96 insertions(+), 7 deletions(-) diff --git a/Activity.h b/Activity.h index bbb42b04..ac20623a 100644 --- a/Activity.h +++ b/Activity.h @@ -78,8 +78,9 @@ class Sleep : public Idle { uint32_t ticks = sysclock.next(); if( sysclock.isready() == false ) { if( ticks == 0 || ticks > millis2ticks(15) ) { - hal.radio.setIdle(); + hal.setIdle(); uint32_t offset = doSleep(ticks); + hal.unsetIdle(); sysclock.correct(offset); sysclock.enable(); } @@ -123,8 +124,9 @@ class SleepRTC : public Idle { uint32_t ticks = sysclock.next(); if( sysclock.isready() == false ) { if( ticks == 0 || ticks > millis2ticks(15) ) { - hal.radio.setIdle(); + hal.setIdle(); uint32_t offset = doSleep(ticks); + hal.unsetIdle(); sysclock.correct(offset); sysclock.enable(); } @@ -182,13 +184,13 @@ class Activity : public Alarm { } else { // ensure radio is up and running - hal.radio.wakeup(); + hal.wakeup(); } } template void sleepForever (Hal& hal) { - hal.radio.setIdle(); + hal.setIdle(); while( true ) { #if defined(ARDUINO_ARCH_AVR) && ! (defined(ARDUINO_AVR_ATmega32) || defined(__AVR_ATmega644__)) LowPower.powerDown(SLEEP_FOREVER,ADC_OFF,BOD_OFF); diff --git a/AskSinPP.h b/AskSinPP.h index f9962986..b33ba8de 100644 --- a/AskSinPP.h +++ b/AskSinPP.h @@ -196,12 +196,27 @@ class AskSin : public AskSinBase { radio.waitTimeout(millis); } + void setIdle () { + radio.setIdle(); + battery.setIdle(); + } + + void unsetIdle () { + battery.unsetIdle(); + } + + void wakeup () { + radio.wakeup(); + } + #ifdef ARDUINO_ARCH_AVR template void idle () { activity.savePower< Idle >(*this); } template void sleep () { activity.savePower< Sleep >(*this); } + + void sleepForever () { activity.sleepForever(*this); } #endif }; diff --git a/BatterySensor.h b/BatterySensor.h index cc4d6594..8d3ee24e 100644 --- a/BatterySensor.h +++ b/BatterySensor.h @@ -210,6 +210,9 @@ class BattSensor : public Alarm { uint8_t voltage() { return current(); } METER& meter () { return m_Meter; } + + void setIdle () {} + void unsetIdle () {} }; typedef BattSensor > BatterySensor; @@ -267,6 +270,64 @@ class BatterySensorExt : public BatterySensor { }; +extern volatile uint16_t __gb_BatCurrent; +extern void (*__gb_BatIrq)(); + +class IrqInternalBatt { + uint8_t m_Low, m_Critical; +public: + IrqInternalBatt () : m_Low(0), m_Critical(0) {} + ~IrqInternalBatt() {} + + uint8_t current () const { return (__gb_BatCurrent + 50) / 100; } + bool critical () const { return current() < m_Critical; } + void critical (uint8_t value ) { m_Critical = value; } + bool low () const { return current() < m_Low; } + void low (uint8_t value ) { m_Low = value; } + + void init(__attribute__((unused)) uint32_t period,__attribute__((unused)) AlarmClock& clock) { + unsetIdle(); + } + + // for backward compatibility + uint16_t voltageHighRes() { return __gb_BatCurrent; } + uint8_t voltage() { return current(); } + + void setIdle () { + __gb_BatIrq = 0; + } + + void unsetIdle () { + __gb_BatIrq = irq; + ADMUX &= ~(ADMUX_REFMASK | ADMUX_ADCMASK); + ADMUX |= ADMUX_REF_AVCC; // select AVCC as reference + ADMUX |= ADMUX_ADC_VBG; // measure bandgap reference voltage + ADCSRA |= (1 << ADIE); // enable interrupt + ADCSRA |= (1 << ADSC); // start conversion + } + + static void irq () { + uint16_t v = 1100UL * 1024 / ADC; + if( __gb_BatCurrent == 0 ) { + __gb_BatCurrent = v; + } + else { + v = (__gb_BatCurrent + v) / 2; + if( v < __gb_BatCurrent ) { + __gb_BatCurrent = v; + } + } + ADCSRA |= (1 << ADSC); // start conversion + } +}; + + +ISR(ADC_vect) { + if( __gb_BatIrq != 0 ) { + __gb_BatIrq(); + } +} + } #endif diff --git a/Globals.cpp b/Globals.cpp index 6205e02f..e0fd38a0 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -1,4 +1,5 @@ +#include namespace as { @@ -7,4 +8,7 @@ void* __gb_radio; const char* __gb_chartable = "0123456789ABCDEF"; +uint16_t __gb_BatCurrent = 0; +void (*__gb_BatIrq)() = 0; + } diff --git a/examples/HM-SEC-RHS/HM-SEC-RHS.ino b/examples/HM-SEC-RHS/HM-SEC-RHS.ino index c2cfc701..03635e04 100644 --- a/examples/HM-SEC-RHS/HM-SEC-RHS.ino +++ b/examples/HM-SEC-RHS/HM-SEC-RHS.ino @@ -5,6 +5,7 @@ // define this to read the device id, serial and device type from bootloader section // #define USE_OTA_BOOTLOADER +// #define BATTERY_IRQ #define CFG_STEPUP_BYTE 0x00 #define CFG_STEPUP_OFF 0x00 @@ -96,7 +97,11 @@ public: } }; -typedef BattSensor > BatSensor; +#ifdef BATTERY_IRQ + typedef IrqInternalBatt BatSensor; +#else + typedef BattSensor > BatSensor; +#endif /** * Configure the used hardware @@ -190,8 +195,10 @@ public: // set battery low/critical values battery().low(getConfigByte(CFG_BAT_LOW_BYTE)); battery().critical(getConfigByte(CFG_BAT_CRITICAL_BYTE)); + #ifndef BATTERY_IRQ // set the battery mode battery().meter().sensor().mode(getConfigByte(CFG_STEPUP_BYTE)); + #endif } }; @@ -219,10 +226,10 @@ void loop() { // if we drop below critical battery level - switch off all and sleep forever if( hal.battery.critical() ) { // this call will never return - hal.activity.sleepForever(hal); + hal.sleepForever(); } // if nothing to do - go sleep - hal.activity.savePower >(hal); + hal.sleep<>(); } }