From ff28931eebcc0c16d0a15369a13c2fa47815d1e5 Mon Sep 17 00:00:00 2001 From: Jesse Vincent Date: Mon, 7 Oct 2024 16:09:01 -0700 Subject: [PATCH] Add MAX1704x fuel gauge library and examples as of 6ea1765a513dde65e433dde12a70fced73b65fed Sparkfun's upstream is https://github.com/sparkfun/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library and the library is available under the MIT License --- .../.gitattributes | 2 + .../LICENSE | 21 + .../README.md | 59 ++ .../Example1_Simple/Example1_Simple.ino | 88 ++ .../Example2_AlternatePorts.ino | 92 ++ .../Example3_MAX17044/Example3_MAX17044.ino | 87 ++ .../Example4_MAX17048_KitchenSink.ino | 181 ++++ .../keywords.txt | 65 ++ .../library.properties | 9 + ...un_MAX1704x_Fuel_Gauge_Arduino_Library.cpp | 958 ++++++++++++++++++ ...kFun_MAX1704x_Fuel_Gauge_Arduino_Library.h | 403 ++++++++ 11 files changed, 1965 insertions(+) create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/.gitattributes create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/LICENSE create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/README.md create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example1_Simple/Example1_Simple.ino create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example2_AlternatePorts/Example2_AlternatePorts.ino create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example3_MAX17044/Example3_MAX17044.ino create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example4_MAX17048_KitchenSink/Example4_MAX17048_KitchenSink.ino create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/keywords.txt create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/library.properties create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.cpp create mode 100644 libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/.gitattributes b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/.gitattributes new file mode 100644 index 000000000..dfe077042 --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/LICENSE b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/LICENSE new file mode 100644 index 000000000..b08933d57 --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 SparkFun Electronics + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/README.md b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/README.md new file mode 100644 index 000000000..966e9e608 --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/README.md @@ -0,0 +1,59 @@ +SparkFun MAX1704x Fuel Gauge Arduino Library +======================================== + + + + + + + + + + +
SparkFun LiPo Fuel Gauge - MAX17043 SparkX Qwiic Fuel Gauge - MAX17048
SparkFun LiPo Fuel Gauge - MAX17043 [TOL-20680]SparkX Qwiic Fuel Gauge - MAX17048 [SPX-17715]
+ + +The MAX17043/MAX17044 are ultra-compact, low-cost, +host-side fuel-gauge systems for lithium-ion (Li+) batteries +in handheld and portable equipment. The MAX17043 +is configured to operate with a single lithium cell and the +MAX17044 is configured for a dual-cell 2S pack. + +The MAX17048/MAX17049 ICs are tiny, micropower current +fuel gauges for lithium-ion (Li+) batteries in handheld +and portable equipment. The MAX17048 operates with +a single lithium cell and the MAX17049 with two lithium +cells in series. + +This Arduino library provides support for all four devices. + +## Thanks + +Parts of this library were inspired by [Daniel Porrey's max1704x library](https://github.com/porrey/max1704x). Thank you Daniel. + +## Repository Contents + +- **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. +- **/src** - Source files for the library (.cpp, .h). +- **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. +- **library.properties** - General library properties for the Arduino package manager. + +## Products That Use This Library + +- [Qduino Mini - Arduino Dev Board (DEV-13614)](https://www.sparkfun.com/products/13614) - Built in MAX17048 +- [SparkFun IoT RedBoard - ESP32 Development Board (WRL-19177)](https://www.sparkfun.com/products/19177) - Built in MAX17048 +- [SparkX Qwiic Fuel Gauge - MAX17048 (SPX-17715) ](https://www.sparkfun.com/products/17715) +- [SparkFun LiPo Fuel Gauge - MAX17043 (TOL-20680)](https://www.sparkfun.com/products/20680) +- [SparkFun LiPo Fuel Gauge - MAX17043 (TOL-10617)](https://www.sparkfun.com/products/10617) + + +## Documentation + +- **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. +- **[LiPo Fuel Gauge (MAX1704X) Hookup Guide](https://learn.sparkfun.com/tutorials/lipo-fuel-gauge-max1704x-hookup-guide)** - Basic hookup guide for the MAX1704X (i.e. MAX1703 and MAX17048). + + + +## License Information + +Please see [LICENSE.md](./LICENSE.md) for the license information. diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example1_Simple/Example1_Simple.ino b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example1_Simple/Example1_Simple.ino new file mode 100644 index 000000000..893479fdd --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example1_Simple/Example1_Simple.ino @@ -0,0 +1,88 @@ +/****************************************************************************** +Example1_Simple +By: Paul Clark +Date: October 23rd 2020 + +Based extensively on: +MAX17043_Simple_Serial.cpp +SparkFun MAX17043 Example Code +Jim Lindblom @ SparkFun Electronics +Original Creation Date: June 22, 2015 + +This file demonstrates the simple API of the SparkFun MAX17043 Arduino library. + +This example will print the gauge's voltage and state-of-charge (SOC) readings +to Serial (115200 baud) + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ + +#include // Needed for I2C + +#include // Click here to get the library: http://librarymanager/All#SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library + +SFE_MAX1704X lipo; // Defaults to the MAX17043 + +//SFE_MAX1704X lipo(MAX1704X_MAX17043); // Create a MAX17043 +//SFE_MAX1704X lipo(MAX1704X_MAX17044); // Create a MAX17044 +//SFE_MAX1704X lipo(MAX1704X_MAX17048); // Create a MAX17048 +//SFE_MAX1704X lipo(MAX1704X_MAX17049); // Create a MAX17049 + +double voltage = 0; // Variable to keep track of LiPo voltage +double soc = 0; // Variable to keep track of LiPo state-of-charge (SOC) +bool alert; // Variable to keep track of whether alert has been triggered + +void setup() +{ + Serial.begin(115200); // Start serial, to output debug data + while (!Serial) + ; //Wait for user to open terminal + Serial.println(F("MAX17043 Example")); + + Wire.begin(); + + lipo.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // Set up the MAX17043 LiPo fuel gauge: + if (lipo.begin() == false) // Connect to the MAX17043 using the default wire port + { + Serial.println(F("MAX17043 not detected. Please check wiring. Freezing.")); + while (1) + ; + } + + // Quick start restarts the MAX17043 in hopes of getting a more accurate + // guess for the SOC. + lipo.quickStart(); + + // We can set an interrupt to alert when the battery SoC gets too low. + // We can alert at anywhere between 1% - 32%: + lipo.setThreshold(20); // Set alert threshold to 20%. +} + +void loop() +{ + // lipo.getVoltage() returns a voltage value (e.g. 3.93) + voltage = lipo.getVoltage(); + // lipo.getSOC() returns the estimated state of charge (e.g. 79%) + soc = lipo.getSOC(); + // lipo.getAlert() returns a 0 or 1 (0=alert not triggered) + alert = lipo.getAlert(); + + // Print the variables: + Serial.print("Voltage: "); + Serial.print(voltage); // Print the battery voltage + Serial.println(" V"); + + Serial.print("Percentage: "); + Serial.print(soc); // Print the battery state of charge + Serial.println(" %"); + + Serial.print("Alert: "); + Serial.println(alert); + Serial.println(); + + delay(500); +} diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example2_AlternatePorts/Example2_AlternatePorts.ino b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example2_AlternatePorts/Example2_AlternatePorts.ino new file mode 100644 index 000000000..7fd651aad --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example2_AlternatePorts/Example2_AlternatePorts.ino @@ -0,0 +1,92 @@ +/****************************************************************************** +Example2_AlternatePorts +By: Paul Clark +Date: October 23rd 2020 + +Based extensively on: +MAX17043_Simple_Serial.cpp +SparkFun MAX17043 Example Code +Jim Lindblom @ SparkFun Electronics +Original Creation Date: June 22, 2015 + +This file demonstrates the simple API of the SparkFun MAX17043 Arduino library using non-standard Wire and Serial ports. + +This example will print the gauge's voltage and state-of-charge (SOC) readings +to serial (115200 baud) + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ + +#include // Needed for I2C + +#include // Click here to get the library: http://librarymanager/All#SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library + +SFE_MAX1704X lipo; // Defaults to the MAX17043 + +//SFE_MAX1704X lipo(MAX1704X_MAX17043); // Create a MAX17043 +//SFE_MAX1704X lipo(MAX1704X_MAX17044); // Create a MAX17044 +//SFE_MAX1704X lipo(MAX1704X_MAX17048); // Create a MAX17048 +//SFE_MAX1704X lipo(MAX1704X_MAX17049); // Create a MAX17049 + +// Define our non-standard ports: +#define mySerial Serial1 +TwoWire myWire(0); + +double voltage = 0; // Variable to keep track of LiPo voltage +double soc = 0; // Variable to keep track of LiPo state-of-charge (SOC) +bool alert; // Variable to keep track of whether alert has been triggered + +void setup() +{ + mySerial.begin(115200); // Start serial, to output debug data + while (!mySerial) + ; //Wait for user to open terminal + mySerial.println(F("MAX17043 Example")); + + myWire.begin(); + + lipo.enableDebugging(mySerial); // Uncomment this line to enable helpful debug messages on non-standard serial + + // Set up the MAX17043 LiPo fuel gauge: + if (lipo.begin(myWire) == false) // Connect to the MAX17043 using non-standard wire port + { + mySerial.println(F("MAX17043 not detected. Please check wiring. Freezing.")); + while (1) + ; + } + + // Quick start restarts the MAX17043 in hopes of getting a more accurate + // guess for the SOC. + lipo.quickStart(); + + // We can set an interrupt to alert when the battery SoC gets too low. + // We can alert at anywhere between 1% - 32%: + lipo.setThreshold(20); // Set alert threshold to 20%. +} + +void loop() +{ + // lipo.getVoltage() returns a voltage value (e.g. 3.93) + voltage = lipo.getVoltage(); + // lipo.getSOC() returns the estimated state of charge (e.g. 79%) + soc = lipo.getSOC(); + // lipo.getAlert() returns a 0 or 1 (0=alert not triggered) + alert = lipo.getAlert(); + + // Print the variables: + mySerial.print("Voltage: "); + mySerial.print(voltage); // Print the battery voltage + mySerial.println(" V"); + + mySerial.print("Percentage: "); + mySerial.print(soc); // Print the battery state of charge + mySerial.println(" %"); + + mySerial.print("Alert: "); + mySerial.println(alert); + mySerial.println(); + + delay(500); +} diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example3_MAX17044/Example3_MAX17044.ino b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example3_MAX17044/Example3_MAX17044.ino new file mode 100644 index 000000000..439f8566a --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example3_MAX17044/Example3_MAX17044.ino @@ -0,0 +1,87 @@ +/****************************************************************************** +Example3_MAX17044 +By: Paul Clark +Date: October 23rd 2020 + +Based extensively on: +MAX17043_Simple_Serial.cpp +SparkFun MAX17043 Example Code +Jim Lindblom @ SparkFun Electronics +Original Creation Date: June 22, 2015 + +This file demonstrates how to talk to the MAX17044 using the SparkFun MAX17043 Arduino library. + +This example will print the gauge's voltage and state-of-charge (SOC) readings +to Serial (115200 baud) + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ + +#include // Needed for I2C + +#include // Click here to get the library: http://librarymanager/All#SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library + +SFE_MAX1704X lipo(MAX1704X_MAX17044); // Create a MAX17044 + +//SFE_MAX1704X lipo(MAX1704X_MAX17043); // Create a MAX17043 +//SFE_MAX1704X lipo(MAX1704X_MAX17048); // Create a MAX17048 +//SFE_MAX1704X lipo(MAX1704X_MAX17049); // Create a MAX17049 + +double voltage = 0; // Variable to keep track of LiPo voltage +double soc = 0; // Variable to keep track of LiPo state-of-charge (SOC) +bool alert; // Variable to keep track of whether alert has been triggered + +void setup() +{ + Serial.begin(115200); // Start serial, to output debug data + while (!Serial) + ; //Wait for user to open terminal + Serial.println(F("MAX17044 Example")); + + Wire.begin(); + + lipo.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // Set up the MAX17044 LiPo fuel gauge: + if (lipo.begin() == false) // Connect to the MAX17044 using the default wire port + { + Serial.println(F("MAX17044 not detected. Please check wiring. Freezing.")); + while (1) + ; + } + + // Quick start restarts the MAX17044 in hopes of getting a more accurate + // guess for the SOC. + lipo.quickStart(); + + // We can set an interrupt to alert when the battery SoC gets too low. + // We can alert at anywhere between 1% - 32%: + lipo.setThreshold(20); // Set alert threshold to 20%. +} + +void loop() +{ + // lipo.getVoltage() returns a voltage value (e.g. 7.86) + voltage = lipo.getVoltage(); + // lipo.getSOC() returns the estimated state of charge (e.g. 79%) + soc = lipo.getSOC(); + // lipo.getAlert() returns a 0 or 1 (0=alert not triggered) + alert = lipo.getAlert(); + + // Print the variables: + Serial.print("Voltage: "); + Serial.print(voltage); // Print the battery voltage + Serial.println(" V"); + + Serial.print("Percentage: "); + Serial.print(soc); // Print the battery state of charge + Serial.println(" %"); + + Serial.print("Alert: "); + Serial.println(alert); + Serial.println(); + + delay(500); +} diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example4_MAX17048_KitchenSink/Example4_MAX17048_KitchenSink.ino b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example4_MAX17048_KitchenSink/Example4_MAX17048_KitchenSink.ino new file mode 100644 index 000000000..d04f057ec --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/examples/Example4_MAX17048_KitchenSink/Example4_MAX17048_KitchenSink.ino @@ -0,0 +1,181 @@ +/****************************************************************************** +Example4: test all the things on the MAX17048 +By: Paul Clark, SparkFun Electronics +Date: October 23rd 2020 + +This example is an everything-but-the-kitchen-sink test of the MAX17048. + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ + +#include // Needed for I2C + +#include // Click here to get the library: http://librarymanager/All#SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library + +SFE_MAX1704X lipo(MAX1704X_MAX17048); // Create a MAX17048 + +void setup() +{ + Serial.begin(115200); // Start serial, to output debug data + while (!Serial) + ; //Wait for user to open terminal + Serial.println(F("MAX17048 Example")); + + Wire.begin(); + + lipo.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // Set up the MAX17048 LiPo fuel gauge: + if (lipo.begin() == false) // Connect to the MAX17048 using the default wire port + { + Serial.println(F("MAX17048 not detected. Please check wiring. Freezing.")); + while (1) + ; + } + + // Just because we can, let's reset the MAX17048 + Serial.println(F("Resetting the MAX17048...")); + delay(1000); // Give it time to get its act back together + + // Read and print the reset indicator + Serial.print(F("Reset Indicator was: ")); + bool RI = lipo.isReset(true); // Read the RI flag and clear it automatically if it is set + Serial.println(RI); // Print the RI + // If RI was set, check it is now clear + if (RI) + { + Serial.print(F("Reset Indicator is now: ")); + RI = lipo.isReset(); // Read the RI flag + Serial.println(RI); // Print the RI + } + + // To quick-start or not to quick-start? That is the question! + // Read the following and then decide if you do want to quick-start the fuel gauge. + // "Most systems should not use quick-start because the ICs handle most startup problems transparently, + // such as intermittent battery-terminal connection during insertion. If battery voltage stabilizes + // faster than 17ms then do not use quick-start. The quick-start command restarts fuel-gauge calculations + // in the same manner as initial power-up of the IC. If the system power-up sequence is so noisy that the + // initial estimate of SOC has unacceptable error, the system microcontroller might be able to reduce the + // error by using quick-start." + // If you still want to try a quick-start then uncomment the next line: + //lipo.quickStart(); + + // Read and print the device ID + Serial.print(F("Device ID: 0x")); + uint8_t id = lipo.getID(); // Read the device ID + if (id < 0x10) Serial.print(F("0")); // Print the leading zero if required + Serial.println(id, HEX); // Print the ID as hexadecimal + + // Read and print the device version + Serial.print(F("Device version: 0x")); + uint8_t ver = lipo.getVersion(); // Read the device version + if (ver < 0x10) Serial.print(F("0")); // Print the leading zero if required + Serial.println(ver, HEX); // Print the version as hexadecimal + + // Read and print the battery threshold + Serial.print(F("Battery empty threshold is currently: ")); + Serial.print(lipo.getThreshold()); + Serial.println(F("%")); + + // We can set an interrupt to alert when the battery SoC gets too low. + // We can alert at anywhere between 1% and 32%: + lipo.setThreshold(20); // Set alert threshold to 20%. + + // Read and print the battery empty threshold + Serial.print(F("Battery empty threshold is now: ")); + Serial.print(lipo.getThreshold()); + Serial.println(F("%")); + + // Read and print the high voltage threshold + Serial.print(F("High voltage threshold is currently: ")); + float highVoltage = ((float)lipo.getVALRTMax()) * 0.02; // 1 LSb is 20mV. Convert to Volts. + Serial.print(highVoltage, 2); + Serial.println(F("V")); + + // Set the high voltage threshold + lipo.setVALRTMax((float)4.1); // Set high voltage threshold (Volts) + + // Read and print the high voltage threshold + Serial.print(F("High voltage threshold is now: ")); + highVoltage = ((float)lipo.getVALRTMax()) * 0.02; // 1 LSb is 20mV. Convert to Volts. + Serial.print(highVoltage, 2); + Serial.println(F("V")); + + // Read and print the low voltage threshold + Serial.print(F("Low voltage threshold is currently: ")); + float lowVoltage = ((float)lipo.getVALRTMin()) * 0.02; // 1 LSb is 20mV. Convert to Volts. + Serial.print(lowVoltage, 2); + Serial.println(F("V")); + + // Set the low voltage threshold + lipo.setVALRTMin((float)3.9); // Set low voltage threshold (Volts) + + // Read and print the low voltage threshold + Serial.print(F("Low voltage threshold is now: ")); + lowVoltage = ((float)lipo.getVALRTMin()) * 0.02; // 1 LSb is 20mV. Convert to Volts. + Serial.print(lowVoltage, 2); + Serial.println(F("V")); + + // Enable the State Of Change alert + Serial.print(F("Enabling the 1% State Of Change alert: ")); + if (lipo.enableSOCAlert()) + { + Serial.println(F("success.")); + } + else + { + Serial.println(F("FAILED!")); + } + + // Read and print the HIBRT Active Threshold + Serial.print(F("Hibernate active threshold is: ")); + float actThr = ((float)lipo.getHIBRTActThr()) * 0.00125; // 1 LSb is 1.25mV. Convert to Volts. + Serial.print(actThr, 5); + Serial.println(F("V")); + + // Read and print the HIBRT Hibernate Threshold + Serial.print(F("Hibernate hibernate threshold is: ")); + float hibThr = ((float)lipo.getHIBRTHibThr()) * 0.208; // 1 LSb is 0.208%/hr. Convert to %/hr. + Serial.print(hibThr, 3); + Serial.println(F("%/h")); +} + +void loop() +{ + // Print the variables: + Serial.print("Voltage: "); + Serial.print(lipo.getVoltage()); // Print the battery voltage + Serial.print("V"); + + Serial.print(" Percentage: "); + Serial.print(lipo.getSOC(), 2); // Print the battery state of charge with 2 decimal places + Serial.print("%"); + + Serial.print(" Change Rate: "); + Serial.print(lipo.getChangeRate(), 2); // Print the battery change rate with 2 decimal places + Serial.print("%/hr"); + + Serial.print(" Alert: "); + Serial.print(lipo.getAlert()); // Print the generic alert flag + + Serial.print(" Voltage High Alert: "); + Serial.print(lipo.isVoltageHigh()); // Print the alert flag + + Serial.print(" Voltage Low Alert: "); + Serial.print(lipo.isVoltageLow()); // Print the alert flag + + Serial.print(" Empty Alert: "); + Serial.print(lipo.isLow()); // Print the alert flag + + Serial.print(" SOC 1% Change Alert: "); + Serial.print(lipo.isChange()); // Print the alert flag + + Serial.print(" Hibernating: "); + Serial.print(lipo.isHibernating()); // Print the alert flag + + Serial.println(); + + delay(500); +} diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/keywords.txt b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/keywords.txt new file mode 100644 index 000000000..c915999ce --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/keywords.txt @@ -0,0 +1,65 @@ +####################################### +# Syntax Coloring Map For MAX1704x +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SFE_MAX17043 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +setDevice KEYWORD2 +setWirePort KEYWORD2 +begin KEYWORD2 +isConnected KEYWORD2 +enableDebugging KEYWORD2 +disableDebugging KEYWORD2 +quickStart KEYWORD2 +getVoltage KEYWORD2 +getSOC KEYWORD2 +getVersion KEYWORD2 +getThreshold KEYWORD2 +setThreshold KEYWORD2 +getAlert KEYWORD2 +clearAlert KEYWORD2 +enableSOCAlert KEYWORD2 +disableSOCAlert KEYWORD2 +sleep KEYWORD2 +wake KEYWORD2 +reset KEYWORD2 +getConfigRegister KEYWORD2 +getCompensation KEYWORD2 +setCompensation KEYWORD2 +setResetVoltage KEYWORD2 +getResetVoltage KEYWORD2 +enableComparator KEYWORD2 +disableComparator KEYWORD2 +getChangeRate KEYWORD2 +getStatus KEYWORD2 +isReset KEYWORD2 +isVoltageHigh KEYWORD2 +isVoltageLow KEYWORD2 +isVoltageReset KEYWORD2 +isLow KEYWORD2 +isChange KEYWORD2 +enableAlert KEYWORD2 +disableAlert KEYWORD2 +getVALRTMax KEYWORD2 +getVALRTMin KEYWORD2 +setVALRTMax KEYWORD2 +setVALRTMin KEYWORD2 +isHibernating KEYWORD2 +getHIBRTActThr KEYWORD2 +setHIBRTActThr KEYWORD2 +getHIBRTHibThr KEYWORD2 +setHIBRTHibThr KEYWORD2 +enableHibernate KEYWORD2 +disableHibernate KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/library.properties b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/library.properties new file mode 100644 index 000000000..c47676fb9 --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/library.properties @@ -0,0 +1,9 @@ +name=SparkFun MAX1704x Fuel Gauge Arduino Library +version=1.0.4 +author=SparkFun Electronics +maintainer=SparkFun Electronics +sentence=Arduino library for the MAX17043/44/48/49 fuel gauges +paragraph=An Arduino library to let you access all of the features of the MAX17043, MAX17044, MAX17048 and MAX17049 battery fuel gauges +category=Sensors +url=https://github.com/sparkfun/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library +architectures=* diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.cpp b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.cpp new file mode 100644 index 000000000..324677450 --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.cpp @@ -0,0 +1,958 @@ +/****************************************************************************** +SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h +By: Paul Clark +October 23rd 2020 + +Based extensively on: +SparkFunMAX17043.cpp +SparkFun MAX17043 Library Source File +Jim Lindblom @ SparkFun Electronics +Original Creation Date: June 22, 2015 +https://github.com/sparkfun/SparkFun_MAX17043_Particle_Library + +This file implements all functions of the MAX17043 class. Functions here range +from higher level stuff, like reading/writing MAX17043 registers to low-level, +hardware reads and writes. + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ +#include "SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h" + +SFE_MAX1704X::SFE_MAX1704X(sfe_max1704x_devices_e device) +{ + // Constructor + setDevice(device); +} + +// Change the device type if required. Do this after instantiation but before .begin +void SFE_MAX1704X::setDevice(sfe_max1704x_devices_e device) +{ + // Record the device type + _device = device; + + // Define the full-scale voltage for VCELL based on the device + switch (device) + { + case MAX1704X_MAX17044: + _full_scale = 10.24; // MAX17044 VCELL is 12-bit, 2.50mV per LSB + break; + case MAX1704X_MAX17048: + _full_scale = 5.12; // MAX17048 VCELL is 16-bit, 78.125uV/cell per LSB + break; + case MAX1704X_MAX17049: + _full_scale = 10.24; // MAX17049 VCELL is 16-bit, 78.125uV/cell per LSB (i.e. 156.25uV per LSB) + break; + default: // Default is the MAX17043 + _full_scale = 5.12; // MAX17043 VCELL is 12-bit, 1.25mV per LSB + break; + } +} + +bool SFE_MAX1704X::begin(TwoWire &wirePort) +{ + setWirePort(wirePort); //Grab which port the user wants us to use + + if (isConnected() == false) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("begin: isConnected returned false")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (false); + } + + return (true); +} + +// Allow _i2CPort to be set manually, so that isConnected can be called before .begin if required +void SFE_MAX1704X::setWirePort(TwoWire &wirePort) +{ + _i2cPort = &wirePort; //Grab which port the user wants us to use +} + +//Returns true if device is present +bool SFE_MAX1704X::isConnected(void) +{ + //Updated to resolve issue #4 Dec 27th 2021 + //Also avoid using the standard "if device answers on _deviceAddress" test + //(https://github.com/sparkfun/Arduino_Apollo3/issues/400#issuecomment-992631994) + bool success = false; + uint8_t retries = 3; + uint16_t version = 0; + + while ((success == false) && (retries > 0)) + { + _i2cPort->beginTransmission(MAX1704x_ADDRESS); + _i2cPort->write(MAX17043_VERSION); // Attempt to read the version register + _i2cPort->endTransmission(false); // Don't release the bus + + if (_i2cPort->requestFrom(MAX1704x_ADDRESS, 2) == 2) // Attempt to read the version (2 bytes) + { + uint8_t msb = _i2cPort->read(); + uint8_t lsb = _i2cPort->read(); + version = ((uint16_t)msb << 8) | lsb; + success = true; + } + else + { + retries--; + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("SFE_MAX1704X::isConnected: retrying...")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + delay(50); + } + } + + if (!success) // Return now if the version could not be read + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("SFE_MAX1704X::isConnected: failed to detect IC!")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (success); + } + + //Extra test - but only for MAX17048/9 - see issue #4 + if (_device >= MAX1704X_MAX17048) + { + //Get version should return 0x001_ + //Not a great test but something + //Supported on 48/49 + if ((version & (1 << 4)) == 0) + success = false; + } + + return (success); +} + +//Enable or disable the printing of debug messages +void SFE_MAX1704X::enableDebugging(Stream &debugPort) +{ + #if MAX1704X_ENABLE_DEBUGLOG + _debugPort = &debugPort; //Grab which port the user wants us to use for debugging + _printDebug = true; //Should we print the commands we send? Good for debugging + #endif // if MAX1704X_ENABLE_DEBUGLOG +} + +void SFE_MAX1704X::disableDebugging(void) +{ + #if MAX1704X_ENABLE_DEBUGLOG + _printDebug = false; //Turn off extra print statements + #endif // if MAX1704X_ENABLE_DEBUGLOG +} + +uint8_t SFE_MAX1704X::quickStart() +{ + // A quick-start allows the MAX17043 to restart fuel-gauge calculations in the + // same manner as initial power-up of the IC. If an application’s power-up + // sequence is exceedingly noisy such that excess error is introduced into the + // IC’s “first guess” of SOC, the host can issue a quick-start to reduce the + // error. A quick-start is initiated by a rising edge on the QSTRT pin, or + // through software by writing 4000h to MODE register. + + // Note: on the MAX17048/49 this will also clear / disable EnSleep + + return write16(MAX17043_MODE_QUICKSTART, MAX17043_MODE); +} + +float SFE_MAX1704X::getVoltage() +{ + uint16_t vCell; + vCell = read16(MAX17043_VCELL); + + if (_device <= MAX1704X_MAX17044) + { + // On the MAX17043/44: vCell is a 12-bit register where each bit represents: + // 1.25mV on the MAX17043 + // 2.5mV on the MAX17044 + vCell = (vCell) >> 4; // Align the 12 bits + + float divider = 4096.0 / _full_scale; + + return (((float)vCell) / divider); + } + else + { + // On the MAX17048/49: vCell is a 16-bit register where each bit represents 78.125uV/cell per LSB + // i.e. 78.125uV per LSB on the MAX17048 + // i.e. 156.25uV per LSB on the MAX17049 + + float divider = 65536.0 / _full_scale; + + return (((float)vCell) / divider); + } +} + +float SFE_MAX1704X::getSOC() +{ + uint16_t soc; + float percent; + soc = read16(MAX17043_SOC); + percent = (float)((soc & 0xFF00) >> 8); + percent += ((float)(soc & 0x00FF)) / 256.0; + + return percent; +} + +uint16_t SFE_MAX1704X::getVersion() +{ + return read16(MAX17043_VERSION); +} + +//Supported on MAX17048/49 +uint8_t SFE_MAX1704X::getID() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getID: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t vresetID = read16(MAX17048_VRESET_ID); + return (vresetID & 0xFF); +} + +//Default is 0x4B = 75 (7bit, shifted from 0x96__) +//40mV per bit. So default is 3.0V. +uint8_t SFE_MAX1704X::setResetVoltage(uint8_t threshold) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("setResetVoltage: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t vreset = read16(MAX17048_VRESET_ID); + vreset &= 0x01FF; // Mask out bits to set + vreset |= ((uint16_t)threshold << 9); // Add new threshold + + return write16(vreset, MAX17048_VRESET_ID); +} +uint8_t SFE_MAX1704X::setResetVoltage(float threshold) +{ + // 7 bits. LSb = 40mV + uint8_t thresh = (uint8_t)(constrain(threshold, 0.0, 5.08) / 0.04); + return setResetVoltage(thresh); +} + +uint8_t SFE_MAX1704X::getResetVoltage(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getResetVoltage: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t threshold = read16(MAX17048_VRESET_ID) >> 9; + return ((uint8_t)threshold); +} + +uint8_t SFE_MAX1704X::enableComparator(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("enableComparator: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t vresetReg = read16(MAX17048_VRESET_ID); + vresetReg &= ~(1 << 8); //Clear bit to enable comparator + return write16(vresetReg, MAX17048_VRESET_ID); +} + +uint8_t SFE_MAX1704X::disableComparator(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("disableComparator: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t vresetReg = read16(MAX17048_VRESET_ID); + vresetReg |= (1 << 8); //Set bit to disable comparator + return write16(vresetReg, MAX17048_VRESET_ID); +} + +float SFE_MAX1704X::getChangeRate(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getChangeRate: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0.0); + } + + int16_t changeRate = read16(MAX17048_CRATE); + float changerate_f = changeRate * 0.208; + return (changerate_f); +} + +uint8_t SFE_MAX1704X::getStatus(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getStatus: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint8_t statusReg = read16(MAX17048_STATUS) >> 8; + return (statusReg & 0x7F); //Highest bit is don't care +} + +bool SFE_MAX1704X::isReset(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_RI) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_RI << 8); + } + return (flag); +} +bool SFE_MAX1704X::isVoltageHigh(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_VH) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_VH << 8); + } + return (flag); +} +bool SFE_MAX1704X::isVoltageLow(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_VL) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_VL << 8); + } + return (flag); +} +bool SFE_MAX1704X::isVoltageReset(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_VR) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_VR << 8); + } + return (flag); +} +bool SFE_MAX1704X::isLow(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_HD) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_HD << 8); + } + return (flag); +} +bool SFE_MAX1704X::isChange(bool clear) +{ + uint8_t status = getStatus(); + bool flag = (status & MAX1704x_STATUS_SC) > 0; + if (flag && clear) // Clear the flag if requested + { + // Clear the aligned bit in the status register + clearStatusRegBits(MAX1704x_STATUS_SC << 8); + } + return (flag); +} + +// Clear the specified bit in the MAX17048/49 status register (PRIVATE) +// This requires the bits in mask to be correctly aligned. +// MAX1704x_STATUS_RI etc. will need to be shifted left by 8 bits to become aligned. +uint8_t SFE_MAX1704X::clearStatusRegBits(uint16_t mask) +{ + uint16_t statusReg = read16(MAX17048_STATUS); + statusReg &= ~mask; // Clear the specified bits + return (write16(statusReg, MAX17048_STATUS)); // Write the contents back again +} + +uint8_t SFE_MAX1704X::clearAlert() +{ + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + configReg &= ~MAX17043_CONFIG_ALERT; // Clear ALRT bit manually. + + return write16(configReg, MAX17043_CONFIG); +} + +// getAlert([clear]) - Check if the MAX1704X's ALRT alert interrupt has been +// triggered. +// INPUT: [clear] - If [clear] is true, the alert flag will be cleared if it +// was set. +// OUTPUT: Returns 1 if interrupt is/was triggered, 0 if not. +uint8_t SFE_MAX1704X::getAlert(bool clear) +{ + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + if (configReg & MAX17043_CONFIG_ALERT) + { + if (clear) // If the clear flag is set + { + configReg &= ~MAX17043_CONFIG_ALERT; // Clear ALRT bit manually. + write16(configReg, MAX17043_CONFIG); + } + return 1; + } + + return 0; +} + +// enableSOCAlert() - (MAX17048/49) Enable the SOC change alert +// Returns true if the SOC change alert was enabled successfully +bool SFE_MAX1704X::enableSOCAlert() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("enableSOCAlert: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (false); + } + + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + configReg |= MAX17043_CONFIG_ALSC; // Set the ALSC bit + // Update the config register, return false if the write fails + if (write16(configReg, MAX17043_CONFIG) > 0) + return (false); + // Re-Read the config reg + configReg = read16(MAX17043_CONFIG); + // Return true if the ALSC bit is set, otherwise return false + return ((configReg & MAX17043_CONFIG_ALSC) > 0); +} + +// disableSOCAlert() - (MAX17048/49) Disable the SOC change alert +// Returns true if the SOC change alert was disabled successfully +bool SFE_MAX1704X::disableSOCAlert() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("disableSOCAlert: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (false); + } + + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + configReg &= ~MAX17043_CONFIG_ALSC; // Clear the ALSC bit + // Update the config register, return false if the write fails + if (write16(configReg, MAX17043_CONFIG) > 0) + return (false); + // Re-Read the config reg + configReg = read16(MAX17043_CONFIG); + // Return true if the ALSC bit is clear, otherwise return false + return ((configReg & MAX17043_CONFIG_ALSC) == 0); +} + +// Enable or Disable MAX17048 VRESET Alert: +// EnVr (enable voltage reset alert) when set to 1 asserts +// the ALRT pin when a voltage-reset event occurs under +// the conditions described by the VRESET/ ID register. +uint8_t SFE_MAX1704X::enableAlert(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("enableAlert: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t statusReg = read16(MAX17048_STATUS); + statusReg |= MAX1704x_STATUS_EnVR; // Set EnVR bit + return write16(statusReg, MAX17048_STATUS); +} + +uint8_t SFE_MAX1704X::disableAlert(void) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("disableAlert: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t statusReg = read16(MAX17048_STATUS); + statusReg &= ~MAX1704x_STATUS_EnVR; // Clear EnVR bit + return write16(statusReg, MAX17048_STATUS); +} + +uint8_t SFE_MAX1704X::getThreshold() +{ + uint16_t configReg = read16(MAX17043_CONFIG); + uint8_t threshold = (configReg & 0x001F); + + // It has an LSb weight of 1%, and can be programmed from 1% to 32%. + // The value is (32 - ATHD)%, e.g.: 00000=32%, 00001=31%, 11111=1%. + // Let's convert our percent to that first: + threshold = 32 - threshold; + return threshold; +} + +uint8_t SFE_MAX1704X::setThreshold(uint8_t percent) +{ + // The alert threshold is a 5-bit value that sets the state of charge level + // where an interrupt is generated on the ALRT pin. + + // It has an LSb weight of 1%, and can be programmed from 1% to 32%. + // The value is (32 - ATHD)%, e.g.: 00000=32%, 00001=31%, 11111=1%. + // Let's convert our percent to that first: + percent = (uint8_t)constrain((float)percent, 0.0, 32.0); + percent = 32 - percent; + + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + configReg &= 0xFFE0; // Mask out threshold bits + configReg |= percent; // Add new threshold + + return write16(configReg, MAX17043_CONFIG); +} + +// In sleep mode, the IC halts all operations, reducing current +// consumption to below 1μA. After exiting sleep mode, +// the IC continues normal operation. In sleep mode, the +// IC does not detect self-discharge. If the battery changes +// state while the IC sleeps, the IC cannot detect it, causing +// SOC error. Wake up the IC before charging or discharging. +uint8_t SFE_MAX1704X::sleep() +{ + if (_device > MAX1704X_MAX17044) + { + // On the MAX17048, we also have to set the EnSleep bit in the MODE register + uint8_t result = write16(MAX17048_MODE_ENSLEEP, MAX17043_MODE); + if (result) + return (result); // Write failed. Bail. + } + + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + if (configReg & MAX17043_CONFIG_SLEEP) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("sleep: MAX17043 is already sleeping!")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return MAX17043_GENERIC_ERROR; // Already sleeping, do nothing but return an error + } + + configReg |= MAX17043_CONFIG_SLEEP; // Set sleep bit + + return write16(configReg, MAX17043_CONFIG); +} + +uint8_t SFE_MAX1704X::wake() +{ + // Read config reg, so we don't modify any other values: + uint16_t configReg = read16(MAX17043_CONFIG); + if (!(configReg & MAX17043_CONFIG_SLEEP)) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("wake: MAX17043 is already awake!")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return MAX17043_GENERIC_ERROR; // Already sleeping, do nothing but return an error + } + configReg &= ~MAX17043_CONFIG_SLEEP; // Clear sleep bit + + uint8_t result = write16(configReg, MAX17043_CONFIG); + + if (result) + return (result); // Write failed. Bail. + + if (_device > MAX1704X_MAX17044) + { + // On the MAX17048, we should also clear the EnSleep bit in the MODE register + // Strictly, this will clear the QuickStart bit too. Which is probably a good thing, + // as I don't think we can do a read-modify-write? + return write16(0x0000, MAX17043_MODE); + } + else + { + return (result); + } +} + +// Writing a value of 0x5400 to the CMD Register causes +// the device to completely reset as if power had been +// removed (see the Power-On Reset (POR) section). The +// reset occurs when the last bit has been clocked in. The +// IC does not respond with an I2C ACK after this command +// sequence. +// Output: Positive integer on success, 0 on fail. +uint8_t SFE_MAX1704X::reset() +{ + return write16(MAX17043_COMMAND_POR, MAX17043_COMMAND); +} + +uint8_t SFE_MAX1704X::getCompensation() +{ + uint16_t configReg = read16(MAX17043_CONFIG); + uint8_t compensation = (configReg & 0xFF00) >> 8; + return compensation; +} + +uint16_t SFE_MAX1704X::getConfigRegister() +{ + return read16(MAX17043_CONFIG); +} + +uint8_t SFE_MAX1704X::setCompensation(uint8_t newCompensation) +{ + // The CONFIG register compensates the ModelGauge algorith. The upper 8 bits + // of the 16-bit register control the compensation. + // Read the original configReg, so we can leave the lower 8 bits alone: + uint16_t configReg = read16(MAX17043_CONFIG); + configReg &= 0x00FF; // Mask out compensation bits + configReg |= ((uint16_t)newCompensation) << 8; + return write16(configReg, MAX17043_CONFIG); +} + +// VALRT Register: +// This register is divided into two thresholds: Voltage alert +// maximum (VALRT.MAX) and minimum (VALRT. MIN). +// Both registers have 1 LSb = 20mV. The IC alerts while +// VCELL > VALRT.MAX or VCELL < VALRT.MIN +uint8_t SFE_MAX1704X::setVALRTMax(uint8_t threshold) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("setVALRTMax: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t valrt = read16(MAX17048_CVALRT); + valrt &= 0xFF00; // Mask off max bits + valrt |= (uint16_t)threshold; + return write16(valrt, MAX17048_CVALRT); +} +uint8_t SFE_MAX1704X::setVALRTMax(float threshold) +{ + uint8_t thresh = (uint8_t)(constrain(threshold, 0.0, 5.1) / 0.02); + return setVALRTMax(thresh); +} + +uint8_t SFE_MAX1704X::getVALRTMax() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getVALRTMax: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t valrt = read16(MAX17048_CVALRT); + valrt &= 0x00FF; // Mask off max bits + return ((uint8_t)valrt); +} + +uint8_t SFE_MAX1704X::setVALRTMin(uint8_t threshold) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("setVALRTMin: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t valrt = read16(MAX17048_CVALRT); + valrt &= 0x00FF; // Mask off min bits + valrt |= ((uint16_t)threshold) << 8; + return write16(valrt, MAX17048_CVALRT); +} +uint8_t SFE_MAX1704X::setVALRTMin(float threshold) +{ + uint8_t thresh = (uint8_t)(constrain(threshold, 0.0, 5.1) / 0.02); + return setVALRTMin(thresh); +} + +uint8_t SFE_MAX1704X::getVALRTMin() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getVALRTMin: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t valrt = read16(MAX17048_CVALRT); + valrt >>= 8; // Shift min into LSB + return ((uint8_t)valrt); +} + +bool SFE_MAX1704X::isHibernating() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("isHibernating: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (false); + } + + uint16_t mode = read16(MAX17043_MODE); + return ((mode & MAX17048_MODE_HIBSTAT) > 0); +} + +uint8_t SFE_MAX1704X::getHIBRTActThr() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getHIBRTActThr: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t hibrt = read16(MAX17048_HIBRT); + hibrt &= 0x00FF; // Mask off Act bits + return ((uint8_t)hibrt); +} + +uint8_t SFE_MAX1704X::setHIBRTActThr(uint8_t threshold) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("setHIBRTActThr: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t hibrt = read16(MAX17048_HIBRT); + hibrt &= 0xFF00; // Mask off Act bits + hibrt |= (uint16_t)threshold; + return write16(hibrt, MAX17048_HIBRT); +} +uint8_t SFE_MAX1704X::setHIBRTActThr(float threshold) +{ + // LSb = 1.25mV + uint8_t thresh = (uint8_t)(constrain(threshold, 0.0, 0.31875) / 0.00125); + return setHIBRTActThr(thresh); +} + +uint8_t SFE_MAX1704X::getHIBRTHibThr() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("getHIBRTHibThr: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (0); + } + + uint16_t hibrt = read16(MAX17048_HIBRT); + hibrt >>= 8; // Shift HibThr into LSB + return ((uint8_t)hibrt); +} + +uint8_t SFE_MAX1704X::setHIBRTHibThr(uint8_t threshold) +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("setHIBRTHibThr: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + uint16_t hibrt = read16(MAX17048_HIBRT); + hibrt &= 0x00FF; // Mask off Hib bits + hibrt |= ((uint16_t)threshold) << 8; + return write16(hibrt, MAX17048_HIBRT); +} +uint8_t SFE_MAX1704X::setHIBRTHibThr(float threshold) +{ + // LSb = 0.208%/hr + uint8_t thresh = (uint8_t)(constrain(threshold, 0.0, 53.04) / 0.208); + return setHIBRTHibThr(thresh); +} + +uint8_t SFE_MAX1704X::enableHibernate() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("enableHibernate: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + return write16(MAX17048_HIBRT_ENHIB, MAX17048_HIBRT); +} + +uint8_t SFE_MAX1704X::disableHibernate() +{ + if (_device <= MAX1704X_MAX17044) + { + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("disableHibernate: not supported on this device")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + return (MAX17043_GENERIC_ERROR); + } + + return write16(MAX17048_HIBRT_DISHIB, MAX17048_HIBRT); +} + +uint8_t SFE_MAX1704X::write16(uint16_t data, uint8_t address) +{ + uint8_t msb, lsb; + msb = (data & 0xFF00) >> 8; + lsb = (data & 0x00FF); + _i2cPort->beginTransmission(MAX1704x_ADDRESS); + _i2cPort->write(address); + _i2cPort->write(msb); + _i2cPort->write(lsb); + return (_i2cPort->endTransmission()); +} + +uint16_t SFE_MAX1704X::read16(uint8_t address) +{ + bool success = false; + uint8_t retries = 3; + uint16_t result = 0; + + while ((success == false) && (retries > 0)) + { + _i2cPort->beginTransmission(MAX1704x_ADDRESS); + _i2cPort->write(address); + _i2cPort->endTransmission(false); // Don't release the bus + + if (_i2cPort->requestFrom(MAX1704x_ADDRESS, 2) == 2) + { + uint8_t msb = _i2cPort->read(); + uint8_t lsb = _i2cPort->read(); + result = ((uint16_t)msb << 8) | lsb; + success = true; + } + else + { + retries--; + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + _debugPort->println(F("SFE_MAX1704X::read16: retrying...")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + delay(50); + } + } + + #if MAX1704X_ENABLE_DEBUGLOG + if (_printDebug == true) + { + if (!success) + _debugPort->println(F("SFE_MAX1704X::read16: failed to read data!")); + } + #endif // if MAX1704X_ENABLE_DEBUGLOG + + return (result); +} diff --git a/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h new file mode 100644 index 000000000..3bb63073b --- /dev/null +++ b/libraries/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library/src/SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h @@ -0,0 +1,403 @@ +/****************************************************************************** +SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h +By: Paul Clark +October 23rd 2020 + +Based extensively on: +SparkFunMAX17043.h +SparkFun MAX17043 Library Header File +Jim Lindblom @ SparkFun Electronics +Original Creation Date: June 22, 2015 +https://github.com/sparkfun/SparkFun_MAX17043_Particle_Library + +This file implements all functions of the MAX17043 class. Functions here range +from higher level stuff, like reading/writing MAX17043 registers to low-level, +hardware reads and writes. + +This code is released under the MIT license. + +Distributed as-is; no warranty is given. +******************************************************************************/ +#ifndef MAX1704X_ARDUINO_LIBRARY_H +#define MAX1704X_ARDUINO_LIBRARY_H + +// Uncomment the next #define to EXclude any debug logging from the code, by default debug logging code will be included + +// #define MAX1704X_ENABLE_DEBUGLOG 0 // OFF/disabled/excluded on demand + +#if (ARDUINO >= 100) +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#include + +//Enable/disable including debug log (to allow saving some space) +#ifndef MAX1704X_ENABLE_DEBUGLOG + #if defined(LIBRARIES_NO_LOG) && LIBRARIES_NO_LOG + #define MAX1704X_ENABLE_DEBUGLOG 0 // OFF/disabled/excluded on demand + #else + #define MAX1704X_ENABLE_DEBUGLOG 1 // ON/enabled/included by default + #endif +#endif + +//#include "application.h" + +////////////////////////// +// MAX1704x Device Enum // +////////////////////////// + +typedef enum { + MAX1704X_MAX17043 = 0, + MAX1704X_MAX17044, // 2-cell version of the MAX17043 (full-scale range of 10V) + MAX1704X_MAX17048, + MAX1704X_MAX17049 // 2-cell version of the MAX17048 +} sfe_max1704x_devices_e; + +/////////////////////////////////// +// MAX1704x Register Definitions // +/////////////////////////////////// +// All registers contain two bytes of data and span two addresses. +// Registers which are present on the MAX17048/49 only are prefixed with MAX17048_ +#define MAX17043_VCELL 0x02 // R - 12-bit A/D measurement of battery voltage +#define MAX17043_SOC 0x04 // R - 16-bit state of charge (SOC) +#define MAX17043_MODE 0x06 // W - Sends special commands to IC +#define MAX17043_VERSION 0x08 // R - Returns IC version +#define MAX17048_HIBRT 0x0A // R/W - (MAX17048/49) Thresholds for entering hibernate +#define MAX17043_CONFIG 0x0C // R/W - Battery compensation (default 0x971C) +#define MAX17048_CVALRT 0x14 // R/W - (MAX17048/49) Configures vcell range to generate alerts (default 0x00FF) +#define MAX17048_CRATE 0x16 // R - (MAX17048/49) Charge rate 0.208%/hr +#define MAX17048_VRESET_ID 0x18 // R/W - (MAX17048/49) Reset voltage and ID (default 0x96__) +#define MAX17048_STATUS 0x1A // R/W - (MAX17048/49) Status of ID (default 0x01__) +#define MAX17043_COMMAND 0xFE // W - Sends special comands to IC + +/////////////////////////////////// +// MAX17043 Config Register Bits // +/////////////////////////////////// +#define MAX17043_CONFIG_SLEEP (1 << 7) +#define MAX17043_CONFIG_ALSC 0x0040 // MAX17048/49 only +#define MAX17043_CONFIG_ALERT (1 << 5) +#define MAX17043_CONFIG_THRESHOLD 0 + +///////////////////////////////////// +// MAX17043 Mode Register Commands // +///////////////////////////////////// +#define MAX17043_MODE_QUICKSTART 0x4000 // On the MAX17048/49 this also clears the EnSleep bit + +///////////////////////////////// +// MAX17048 Mode Register Bits // +///////////////////////////////// +#define MAX17048_MODE_ENSLEEP 0x2000 // W - _Enables_ sleep mode (the SLEEP bit in the CONFIG reg engages sleep) +#define MAX17048_MODE_HIBSTAT 0x1000 // R - indicates when the IC is in hibernate mode + +///////////////////////////////////// +// MAX17048/9 Status Register Bits // +///////////////////////////////////// +#define MAX1704x_STATUS_RI (1 << 0) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_VH (1 << 1) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_VL (1 << 2) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_VR (1 << 3) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_HD (1 << 4) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_SC (1 << 5) // Assumes the MSB has been shifted >> 8 +#define MAX1704x_STATUS_EnVR (1 << 14) // ** Unshifted ** + +//////////////////////////////////////// +// MAX17043 Command Register Commands // +//////////////////////////////////////// +#define MAX17043_COMMAND_POR 0x5400 + +/////////////////////////////////////// +// MAX17048 Hibernate Enable/Disable // +/////////////////////////////////////// +#define MAX17048_HIBRT_ENHIB 0xFFFF // always use hibernate mode +#define MAX17048_HIBRT_DISHIB 0x0000 // disable hibernate mode + +//////////////////////////////// +// MAX1704x 7-Bit I2C Address // +//////////////////////////////// +#define MAX1704x_ADDRESS 0x36 // Unshifted I2C address. Becomes 0x6C for write and 0x6D for read. + +// Generic error: +// Wire.endTransmission will return: +// 0:success +// 1:data too long to fit in transmit buffer +// 2:received NACK on transmit of address +// 3:received NACK on transmit of data +// 4:other error +// So, let's use "5" as a generic error value +#define MAX17043_GENERIC_ERROR 5 + +class SFE_MAX1704X +{ +public: + SFE_MAX1704X(sfe_max1704x_devices_e device = MAX1704X_MAX17043); // Default to the 5V MAX17043 + + // Change the device type if required. Do this after instantiation but before .begin + void setDevice(sfe_max1704x_devices_e device); + + // Allow _i2CPort to be set manually, so that isConnected can be called before .begin if required + void setWirePort(TwoWire &wirePort); + + // begin() - Initializes the MAX17043. + bool begin(TwoWire &wirePort = Wire); //Returns true if module is detected + + //Returns true if device is present + bool isConnected(void); + + // Debug + void enableDebugging(Stream &debugPort = Serial); // enable debug messages + void disableDebugging(); // disable debug messages + + // quickStart() - Restarts the MAX17043 to allow it to re-"guess" the + // parameters that go into its SoC algorithms. Calling this in your setup() + // usually results in more accurate SoC readings. + // Output: 0 on success, positive integer on fail. + uint8_t quickStart(); + + // getVoltage() - Get the MAX17043's voltage reading. + // Output: floating point value between 0-5V in 1.25mV increments. + float getVoltage(); + + // getSOC() - Get the MAX17043's state-of-charge (SOC) reading, as calculated + // by the IC's "ModelGauge" algorithm. + // The first update is available approximately 1s after POR of the IC. + // Output: floating point value between 0-100, representing a percentage of + // full charge. + float getSOC(); + + // getVersion() - Get the MAX17043's production version number. + // Output: 3 on success + uint16_t getVersion(); + + // getThreshold() - Get the MAX17043's current percentage threshold that will + // trigger an alert. + // Output: An integer value between 1 and 32, representing a % that will + // trigger an alert interrupt. + uint8_t getThreshold(); + + // setThreshold([percent]) - Set the MAX17043's percentage threshold that will + // trigger an alert. + // Input: [percent] - Percentage value that will trigger an alert interrupt. + // Any value between 1 and 32 is valid. Default value is 0x1C == 4% + // Output: 0 on success, positive integer on fail. + uint8_t setThreshold(uint8_t percent = 4); + + // sleep() - Set the MAX17043 into sleep mode. + // Output: 0 on success, positive integer on fail. + // In sleep mode, the IC halts all operations, reducing current + // consumption to below 1μA. After exiting sleep mode, + // the IC continues normal operation. In sleep mode, the + // IC does not detect self-discharge. If the battery changes + // state while the IC sleeps, the IC cannot detect it, causing + // SOC error. Wake up the IC before charging or discharging. + uint8_t sleep(); + + // wake() - Wake the MAX17043 up from sleep. + // Output: 0 on success, positive integer on fail. + uint8_t wake(); + + // reset() - Issue a Power-on-reset command to the MAX17043. This function + // will reset every register in the MAX17043 to its default value. + // Output: Positive integer on success, 0 on fail. + uint8_t reset(); + + // getConfigRegister() - Read the 16-bit value of the CONFIG Register. + // Output: 16-bit integer value representing the msb and lsb bytes of the + // CONFIG register. + uint16_t getConfigRegister(); + + // getCompensation() - Get the ModelGauge compensation value - an obscure + // 8-bit value set to 0x97 by default. + // Output: 8-bit value read from the CONFIG register's MSB. + uint8_t getCompensation(); + + // setCompensation([newCompensation]) - Set the 8-bit compensation value. This + // is an obscure 8-bit value that has some effect on Maxim's ModelGauge + // algorithm. The POR value of RCOMP is 0x97. + // From the datasheet: "Contact Maxim for instructions for optimization." + // For best performance, the host microcontroller must measure + // battery temperature periodically, and compensate + // the RCOMP ModelGauge parameter accordingly, at least + // once per minute. Each custom model defines constants + // RCOMP0 (default is 0x97), TempCoUp (default is -0.5), + // and TempCoDown (default is -5.0). To calculate the new + // value of CONFIG.RCOMP: + // // T is battery temperature (degrees Celsius) + // if (T > 20) { + // RCOMP = RCOMP0 + (T - 20) x TempCoUp; + // } + // else { + // RCOMP = RCOMP0 + (T - 20) x TempCoDown; + // } + // Input: [newCompensation] - Should be a value between 0-255. + // Output: 0 on success, positive integer on fail. + uint8_t setCompensation(uint8_t newCompensation = 0x97); + + // getID() - (MAX17048/49) Returns 8-bit OTP bits set at factory. Can be used to + // 'to distinguish multiple cell types in production'. + // Writes to these bits are ignored. + uint8_t getID(void); + + // setResetVoltage([threshold]) - (MAX17048/49) Set the 7-bit VRESET value. + // A 7-bit value that controls the comparator for detecting when + // a battery is detached and re-connected. 40mV per bit. Default is 3.0V. + // For captive batteries, set to 2.5V. For + // removable batteries, set to at least 300mV below the + // application’s empty voltage, according to the desired + // reset threshold for your application. + // Input: [threshold] - Should be a value between 0-127. + // Output: 0 on success, positive integer on fail. + uint8_t setResetVoltage(uint8_t threshold = (0x96 >> 1)); + uint8_t setResetVoltage(float threshold = 3.0); // Helper function: set threshold in Volts + + // getResetVoltage() - (MAX17048/49) Get the 7-bit VRESET value + // Output: 7-bit value read from the VRESET/ID register's MSB. + // Returned value is 40mV per bit. + uint8_t getResetVoltage(void); + + // enableComparator() - (MAX17048/49) Set bit in VRESET/ID reg + // Comparator is enabled by default. (Re)enable the analog comparator, uses 0.5uA. + // Output: 0 on success, positive integer on fail. + uint8_t enableComparator(void); + + // disableComparator() - (MAX17048/49) Clear bit in VRESET/ID reg + // Disable the analog comparator, saves 0.5uA in hibernate mode. + // Output: 0 on success, positive integer on fail. + uint8_t disableComparator(void); + + // getChangeRate() - (MAX17048/49) Get rate of change per hour in % + // Output: (signed) Float (that is the 0.208% * CRATE register value) + // A positive rate is charging, negative is discharge. + float getChangeRate(); + + // getStatus() - (MAX17048/49) Get the 7 bits of status register + // Output: 7-bits indicating various alerts + uint8_t getStatus(); + + //(MAX17048/49) Various helper functions to check bits in status register + // INPUT: [clear] - If [clear] is true, the alert flag will be cleared if it + // was set. + bool isReset(bool clear = false); //True after POR + bool isVoltageHigh(bool clear = false); //True when VCELL goes above VALRTMAX (see setVALRTMax) + bool isVoltageLow(bool clear = false); //True when VCELL goes below VALRTMIN (see setVALRTMin) + bool isVoltageReset(bool clear = false); + bool isLow(bool clear = false); //True when SOC crosses the value in ATHD (see setThreshold) + bool isChange(bool clear = false); //True when SOC changes by at least 1% and SOCAlert is enabled + + // getAlert([clear]) - Check if the MAX1704X's ALRT alert interrupt has been + // triggered. + // INPUT: [clear] - If [clear] is true, the alert flag will be cleared if it + // was set. + // OUTPUT: Returns 1 if interrupt is/was triggered, 0 if not. + uint8_t getAlert(bool clear = false); + + // clearAlert() - Clear the MAX1704X's ALRT alert flag. + // Output: 0 on success, positive integer on fail. + uint8_t clearAlert(); + + // enableSOCAlert() - (MAX17048/49) Enable the SOC change alert + // Returns true if the SOC change alert was enabled successfully + bool enableSOCAlert(); + + // disableSOCAlert() - (MAX17048/49) Disable the SOC change alert + // Returns true if the SOC change alert was disabled successfully + bool disableSOCAlert(); + + // Enable or Disable MAX17048/49 VRESET Alert: + // EnVr (enable voltage reset alert) when set to 1 asserts + // the ALRT pin when a voltage-reset event occurs under + // the conditions described by the VRESET/ ID register. + // enableAlert() - Set ENvR bit in STATUS register 0x1A + // Output: 0 on success, positive integer on fail. + uint8_t enableAlert(); + // disableAlert() - Clear the ENvR bit in STATUS register 0x1A + // Output: 0 on success, positive integer on fail. + uint8_t disableAlert(); + + // Read and return the MAX17048/49 VALRT Maximum threshold + // LSb = 20mV + uint8_t getVALRTMax(); + + // Read and return the MAX17048/49 VALRT Minimum threshold + // LSb = 20mV + uint8_t getVALRTMin(); + + // Set the MAX17048/49 VALRT Maximum threshold + // Output: 0 on success, positive integer on fail. + // Note: this sets the threshold voltage _per cell_ (MAX17049 monitors two cells) + uint8_t setVALRTMax(uint8_t threshold = 0xFF); // LSb = 20mV + uint8_t setVALRTMax(float threshold = 5.1); // threshold is defined in Volts + + // Set the MAX17048/49 VALRT Minimum threshold + // Output: 0 on success, positive integer on fail. + // Note: this sets the threshold voltage _per cell_ (MAX17049 monitors two cells) + uint8_t setVALRTMin(uint8_t threshold = 0x00); // LSb = 20mV + uint8_t setVALRTMin(float threshold = 0.0); // threshold is defined in Volts + + // Read and return the MAX17048/49 Hibernate Status flag + bool isHibernating(); + + // Read and return the MAX17048/49 HIBRT Active Threshold + // LSb = 1.25mV + uint8_t getHIBRTActThr(); + + // Set the MAX17048/49 HIBRT Active Threshold + // Output: 0 on success, positive integer on fail. + uint8_t setHIBRTActThr(uint8_t threshold); // LSb = 1.25mV + uint8_t setHIBRTActThr(float threshold); // Helper function: set threshold in Volts + + // Read and return the MAX17048/49 HIBRT Hibernate Threshold + // LSb = 0.208%/hr + uint8_t getHIBRTHibThr(); + + // Set the MAX17048/49 HIBRT Hibernate Threshold + // Output: 0 on success, positive integer on fail. + uint8_t setHIBRTHibThr(uint8_t threshold); // LSb = 0.208%/hr + uint8_t setHIBRTHibThr(float threshold); // Helper function: set threshold in percent + + // Place the MAX17048/49 into hibernate + // Sets the HIBRT register to 0xFFFF + // Output: 0 on success, positive integer on fail. + uint8_t enableHibernate(); + + // Disable hibernate on the MAX17048/49 + // Sets the HIBRT register to 0x0000 + // Output: 0 on success, positive integer on fail. + uint8_t disableHibernate(); + + //Lower level functions but exposed incase user wants them + + // write16([data], [address]) - Write 16 bits to the requested address. After + // writing the address to be written, two sequential 8-bit writes will occur. + // the msb is written first, then lsb. + // Input: [data] - A 16-bit integer to be written to the device. + // [address] - An 8-bit address to be written to. + // Output: 0 on success, positive integer on fail. + uint8_t write16(uint16_t data, uint8_t address); + + // read16([address]) - Read 16-bits from the requested address of a device. + // Input: [address] - An 8-bit address to be read from. + // Output: A 16-bit value read from the device's address will be returned. + uint16_t read16(uint8_t address); + +private: + //Variables + TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware + + #if MAX1704X_ENABLE_DEBUGLOG + Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial. + bool _printDebug = false; //Flag to print debugging variables + #endif // if MAX1704X_ENABLE_DEBUGLOG + + // Clear the specified bit(s) in the MAX17048/49 status register + // This requires the bits in mask to be correctly aligned. + // MAX1704x_STATUS_RI etc. will need to be shifted left by 8 bits to become aligned. + // Output: 0 on success, positive integer on fail. + uint8_t clearStatusRegBits(uint16_t mask); + + int _device = MAX1704X_MAX17043; // Default to MAX17043 + float _full_scale = 5.12; // Default: full-scale for the MAX17043 +}; + +#endif