From 97dbd076f2ea547c716b4400842d0d70b14ef8b8 Mon Sep 17 00:00:00 2001 From: "Mr.Blinky" <4971163+MrBlinky@users.noreply.github.com> Date: Sat, 24 Nov 2018 15:46:27 +0100 Subject: [PATCH] Add checkBatteryState functions Added _checkBatteryState()_ and _checkBatteryStateLED()_ functions --- keywords.txt | 6 ++++ src/Arduboy2.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Arduboy2.h | 62 ++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) diff --git a/keywords.txt b/keywords.txt index b5caf94..87f3f17 100644 --- a/keywords.txt +++ b/keywords.txt @@ -32,6 +32,8 @@ bootLogoSpritesOverwrite KEYWORD2 bootLogoSpritesSelfMasked KEYWORD2 bootLogoText KEYWORD2 buttonsState KEYWORD2 +checkBatteryState KEYWORD2 +checkBatteryStateLED KEYWORD2 clear KEYWORD2 collide KEYWORD2 cpuLoad KEYWORD2 @@ -165,3 +167,7 @@ RGB_ON LITERAL1 ARDUBOY_NO_USB LITERAL1 +BATTERY_STATE_LOW LITERAL1 +BATTERY_STATE_NORMAL LITERAL1 +BATTERY_STATE_INVALID LITERAL1 +FLASH_LED LITERAL1 \ No newline at end of file diff --git a/src/Arduboy2.cpp b/src/Arduboy2.cpp index 23a023a..715e8f7 100644 --- a/src/Arduboy2.cpp +++ b/src/Arduboy2.cpp @@ -32,6 +32,8 @@ Point::Point(int16_t x, int16_t y) uint8_t Arduboy2Base::sBuffer[]; +uint8_t Arduboy2Base::batteryLow = EEPROM.read(EEPROM_BATTERY_LOW); //Low battery bandgap value - 192 + Arduboy2Base::Arduboy2Base() { currentButtonState = 0; @@ -1176,6 +1178,92 @@ void Arduboy2Base::swap(int16_t& a, int16_t& b) b = temp; } +uint8_t Arduboy2Base::checkBatteryState() +{ + uint8_t state = BATTERY_STATE_INVALID; + asm volatile ( + " ldi r30, lo8(%[prr0]) \n" // if (bit_is_set(PRR0,PRADC)) //ADC power off + " ldi r31, hi8(%[prr0]) \n" // { + " ld r24, z \n" + " lds r25, %[adcsra] \n" + " sbrs r24, %[pradc] \n" + " rjmp 1f \n" + " \n" + " andi r24, ~(1<<%[pradc]) \n" // PRR0 &= ~_BV(PRADC); // ADC power on + " st z, r24 \n" + " ldi r24, %[admuxval] \n" // ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) + " sts %[admux], r24 \n" + " ori r25, 1<<%[adsc] \n" // ADCSRA |= _BV(ADSC) //start conversion + " sts %[adcsra], r25 \n" // } + " ;rjmp 2f \n" // bit is set so continue below to jump to 2f + "1: \n" + " sbrc r25, %[adsc] \n" // else if (!(ADCSRA & _BV(ADSC)) //ADC conversion ready + " rjmp 2f \n" // { + " \n" + " ori r24, 1<<%[pradc] \n" // PRR0 |= _BV(PRADC); // ADC power off + " st z, r24 \n" + " ldi r30, %[adcl] \n" // uint16_t bandgap = ADCL | (ADCH << 8); + " ld r24, z+ \n" + " ld r25, z \n" + " subi r24, 192 \n" // bandgap -= 192; + " sbci r25, 0 \n" + " and r25, r25 \n" // if (bandgap < 256) + " brne 2f \n" // { + " \n" + " ldi %[state],%[normal] \n" // state = BATTERY_STATE_NORMAL; + " lds r25, %[battlow] \n" + " cp r25, r24 \n" + " brcc 2f \n" // if (batteryLow < bandgap) state = BATTERY_STATE_LOW; + " ldi %[state],%[low] \n" // } + "2: \n" // } + :[state] "+d"(state) + :[prr0] "M" (_SFR_MEM_ADDR(PRR0)), + [adcsra] "M" (_SFR_MEM_ADDR(ADCSRA)), + [pradc] "I" (PRADC), + [admuxval] "M" (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)), + [admux] "M" (_SFR_MEM_ADDR(ADMUX)), + [adsc] "I" (ADSC), + [adcl] "M" (_SFR_MEM_ADDR(ADCL)), + [battlow] "" (&batteryLow), + [normal] "I" (BATTERY_STATE_NORMAL), + [low] "I" (BATTERY_STATE_LOW) + : "r24", "r25", "r30", "r31" + ); + return state; +} +#if 0 +// For reference, this is the C++ equivalent +uint8_t Arduboy2Base::checkBatteryState(); +{ + uint8_t state = BATTERY_STATE_UNDEFINED; + if (bit_is_set(PRR0,PRADC)) //only enable when ADC power is disabled + { + PRR0 &= ~_BV(PRADC); // ADC power on + ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); //meassure 1.1V bandgap against AVcc + ADCSRA |= _BV(ADSC); //start conversion + } + else if (!(ADCSRA & _BV(ADSC))) + { + PRR0 |= _BV(PRADC); // ADC power off + uint16_t bandgap = ADCL | (ADCH << 8); + bandgap -= 192; + if (bandgap < 256) + { + state = BATTERY_STATE_NORMAL; + if (batteryLow < (uint8_t)bandgap) state = BATTERY_STATE_LOW; + } + } + return state; +} +#endif + +uint8_t Arduboy2Base::checkBatteryStateLED(bool flash) +{ + uint8_t state = checkBatteryState(); + if (state == BATTERY_STATE_NORMAL | flash) TXLED0; + if (state == BATTERY_STATE_LOW) TXLED1; + return state; +} //==================================== //========== class Arduboy2 ========== diff --git a/src/Arduboy2.h b/src/Arduboy2.h index b12a50c..22b4156 100644 --- a/src/Arduboy2.h +++ b/src/Arduboy2.h @@ -41,6 +41,8 @@ #define EEPROM_VERSION 0 #define EEPROM_SYS_FLAGS 1 #define EEPROM_AUDIO_ON_OFF 2 +#define EEPROM_BANDGAP_CAL 6 //Bandgap calibration value +#define EEPROM_BATTERY_LOW 7 //Battery low threshold #define EEPROM_UNIT_ID 8 // A uint16_t binary unit ID #define EEPROM_UNIT_NAME 10 // An up to 6 character unit name. Cannot contain // 0x00 or 0xFF. Lengths less than 6 are padded @@ -87,6 +89,10 @@ #define CLEAR_BUFFER true /**< Value to be passed to `display()` to clear the screen buffer. */ +#define BATTERY_STATE_LOW 0 +#define BATTERY_STATE_NORMAL 1 +#define BATTERY_STATE_INVALID 0xFF +#define FLASH_LED true //============================================= //========== Rect (rectangle) object ========== @@ -1260,6 +1266,60 @@ class Arduboy2Base : public Arduboy2Core */ void writeShowBootLogoLEDsFlag(bool val); + /** \brief + * Returns the battery state. + * \details + * This function is intended as a method to determine a low battery state + * + * Returns the following states: + * - BATTERY_STATE_LOW The battery low threshold has been reached. + * - BATTERY_STATE_NORMAL The battery is considered normal. + * - BATTERY_STATE_INVALID The ADC conversion is not ready yet or the + * result is out of range. + * + * This fucntion depends on the EEPROM_BATTERY_LOW value been set to the + * low batterly bandgap voltage value. The default value (0xFF) will + * disable the EEPROM_BATTERY_LOW state. + * + * example: + * \code{.cpp} + * void loop() { + * if (!arduboy.nextFrame()) return; + * if (arduboy.everyXFrames(FRAMERATE) && arduboy.checkBatteryState() == BATTERY_STATE_LOW) + * { + * batteryLowWarning = true; + * } + * \endcode + * + * \see everyXFrames() + */ + uint8_t checkBatteryState(); + + /** \brief + * Returns battery state and sets TXLED as a low battery indicator + * \param flash defaults to 'false' for no flashing. use 'FLASH_LED' or + * `true` for flashing. + * \details + * This function is intended as a method to determine a low battery state. + * The TXLED is used as a battery low indicator. The TXLED will light up + * continiously by default when the battery state is low. The optional + * FLASH_LED parameter can be passed to make the LED toggle on or off on low + * battery state. + * + * This function is a quick way of adding a low battery indicator to a sketch. + * + * example: + * \code{.cpp} + * void loop() { + * if (!arduboy.nextFrame()) return; + * //turn TXLED alternately on 1 second and off 1 second when battery is low + * if (arduboy.everyXFrames(FRAMERATE)) checkBatteryStateLED(FLASH_LED); + * \endcode + * + * \see checkBatteryState() everyXFrames() + */ + uint8_t checkBatteryStateLED(bool flash = false); + /** \brief * A counter which is incremented once per frame. * @@ -1309,6 +1369,8 @@ class Arduboy2Base : public Arduboy2Core */ static uint8_t sBuffer[(HEIGHT*WIDTH)/8]; + static uint8_t batteryLow; + protected: // helper function for sound enable/disable system control void sysCtrlSound(uint8_t buttons, uint8_t led, uint8_t eeVal);