├── LICENSE.md ├── Documentation ├── bq24075.pdf ├── bq27441-g1.pdf └── BQ27441-G1-users.pdf ├── Libraries └── Arduino │ ├── README.md │ ├── LICENSE.md │ ├── .gitignore │ ├── library.properties │ ├── keywords.txt │ ├── examples │ ├── BQ27441_Basic │ │ └── BQ27441_Basic.ino │ ├── BQ27441_GPOUT_BAT_LOW │ │ └── BQ27441_GPOUT_BAT_LOW.ino │ └── BQ27441_GPOUT_SOC_INT │ │ └── BQ27441_GPOUT_SOC_INT.ino │ └── src │ ├── BQ27441_Definitions.h │ ├── SparkFunBQ27441.h │ └── SparkFunBQ27441.cpp ├── .gitignore └── README.md /LICENSE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/LICENSE.md -------------------------------------------------------------------------------- /Documentation/bq24075.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/Documentation/bq24075.pdf -------------------------------------------------------------------------------- /Libraries/Arduino/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/Libraries/Arduino/README.md -------------------------------------------------------------------------------- /Documentation/bq27441-g1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/Documentation/bq27441-g1.pdf -------------------------------------------------------------------------------- /Libraries/Arduino/LICENSE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/Libraries/Arduino/LICENSE.md -------------------------------------------------------------------------------- /Documentation/BQ27441-G1-users.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/Battery_Babysitter/HEAD/Documentation/BQ27441-G1-users.pdf -------------------------------------------------------------------------------- /Libraries/Arduino/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /Libraries/Arduino/library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun BQ72441 LiPo Fuel Gauge Arduino Library 2 | version=1.0.0 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=An Arduino library for interfacing with the BQ72441-G1 LiPo Fuel Gauge 6 | paragraph=An Arduino library for interfacing with the BQ72441-G1 LiPo Fuel Gauge 7 | category=sensors 8 | url=https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore list for Eagle, a PCB layout tool 2 | 3 | # Eagle Backup/Lock files 4 | *.s#? 5 | *.b#? 6 | *.l#? 7 | *.lck 8 | 9 | # Eagle project file 10 | # It contains a serial number and references to the file structure 11 | # on your computer. 12 | # comment the following line if you want to have your project file included. 13 | eagle.epf 14 | 15 | # CAM files 16 | *.$$$ 17 | *.cmp 18 | *.ly2 19 | *.l15 20 | *.sol 21 | *.plc 22 | *.stc 23 | *.sts 24 | *.crc 25 | *.crs 26 | 27 | *.dri 28 | *.drl 29 | *.gpi 30 | *.pls 31 | 32 | *.drd 33 | *.drd.* 34 | 35 | *.info 36 | 37 | *.eps 38 | -------------------------------------------------------------------------------- /Libraries/Arduino/keywords.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # Syntax Coloring Map for SparkFun BQ27441 LiPo Gauge Library # 3 | ############################################################### 4 | # Class 5 | ############################################################### 6 | 7 | BQ27441 KEYWORD1 8 | SparkFunBQ27441 KEYWORD1 9 | lipo KEYWORD1 10 | 11 | ############################################################### 12 | # Methods and Functions 13 | ############################################################### 14 | 15 | begin KEYWORD2 16 | setCapacity KEYWORD2 17 | voltage KEYWORD2 18 | current KEYWORD2 19 | capacity KEYWORD2 20 | power KEYWORD2 21 | soc KEYWORD2 22 | soh KEYWORD2 23 | temperature KEYWORD2 24 | GPOUTPolarity KEYWORD2 25 | setGPOUTPolarity KEYWORD2 26 | GPOUTFunction KEYWORD2 27 | setGPOUTFunction KEYWORD2 28 | SOC1SetThreshold KEYWORD2 29 | SOC1ClearThreshold KEYWORD2 30 | setSOC1Thresholds KEYWORD2 31 | SOCFSetThreshold KEYWORD2 32 | SOCFClearThreshold KEYWORD2 33 | setSOCFThresholds KEYWORD2 34 | socFlag KEYWORD2 35 | socfFlag KEYWORD2 36 | sociDelta KEYWORD2 37 | setSOCIDelta KEYWORD2 38 | pulseGPOUT KEYWORD2 39 | deviceType KEYWORD2 40 | enterConfig KEYWORD2 41 | exitConfig KEYWORD2 42 | flags KEYWORD2 43 | status KEYWORD2 44 | 45 | ############################################################### 46 | # Constants 47 | ############################################################### 48 | 49 | BQ27441_CONTROL_DEVICE_TYPE LITERAL1 50 | AVG LITERAL1 51 | STBY LITERAL1 52 | MAX LITERAL1 53 | REMAIN LITERAL1 54 | FULL LITERAL1 55 | AVAIL LITERAL1 56 | AVAIL_FULL LITERAL1 57 | REMAIN_F LITERAL1 58 | REMAIN_UF LITERAL1 59 | FULL_F LITERAL1 60 | FULL_UF LITERAL1 61 | DESIGN LITERAL1 62 | FILTERED LITERAL1 63 | UNFILTERED LITERAL1 64 | PERCENT LITERAL1 65 | SOH_STAT LITERAL1 66 | BATTERY LITERAL1 67 | INTERNAL_TEMP LITERAL1 68 | SOC_INT LITERAL1 69 | BAT_LOW LITERAL1 -------------------------------------------------------------------------------- /Libraries/Arduino/examples/BQ27441_Basic/BQ27441_Basic.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | BQ27441_Basic 3 | BQ27441 Library Basic Example 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | Demonstrates how to set up the BQ27441 and read state-of-charge (soc), 9 | battery voltage, average current, remaining capacity, average power, and 10 | state-of-health (soh). 11 | 12 | After uploading, open up the serial monitor to 115200 baud to view your 13 | battery's stats. 14 | 15 | Hardware Resources: 16 | - Arduino Development Board 17 | - SparkFun Battery Babysitter 18 | 19 | Development environment specifics: 20 | Arduino 1.6.7 21 | SparkFun Battery Babysitter v1.0 22 | Arduino Uno (any 'duino should do) 23 | ******************************************************************************/ 24 | #include 25 | 26 | // Set BATTERY_CAPACITY to the design capacity of your battery. 27 | const unsigned int BATTERY_CAPACITY = 850; // e.g. 850mAh battery 28 | 29 | void setupBQ27441(void) 30 | { 31 | // Use lipo.begin() to initialize the BQ27441-G1A and confirm that it's 32 | // connected and communicating. 33 | if (!lipo.begin()) // begin() will return true if communication is successful 34 | { 35 | // If communication fails, print an error message and loop forever. 36 | Serial.println("Error: Unable to communicate with BQ27441."); 37 | Serial.println(" Check wiring and try again."); 38 | Serial.println(" (Battery must be plugged into Battery Babysitter!)"); 39 | while (1) ; 40 | } 41 | Serial.println("Connected to BQ27441!"); 42 | 43 | // Uset lipo.setCapacity(BATTERY_CAPACITY) to set the design capacity 44 | // of your battery. 45 | lipo.setCapacity(BATTERY_CAPACITY); 46 | } 47 | 48 | void printBatteryStats() 49 | { 50 | // Read battery stats from the BQ27441-G1A 51 | unsigned int soc = lipo.soc(); // Read state-of-charge (%) 52 | unsigned int volts = lipo.voltage(); // Read battery voltage (mV) 53 | int current = lipo.current(AVG); // Read average current (mA) 54 | unsigned int fullCapacity = lipo.capacity(FULL); // Read full capacity (mAh) 55 | unsigned int capacity = lipo.capacity(REMAIN); // Read remaining capacity (mAh) 56 | int power = lipo.power(); // Read average power draw (mW) 57 | int health = lipo.soh(); // Read state-of-health (%) 58 | 59 | // Now print out those values: 60 | String toPrint = String(soc) + "% | "; 61 | toPrint += String(volts) + " mV | "; 62 | toPrint += String(current) + " mA | "; 63 | toPrint += String(capacity) + " / "; 64 | toPrint += String(fullCapacity) + " mAh | "; 65 | toPrint += String(power) + " mW | "; 66 | toPrint += String(health) + "%"; 67 | 68 | Serial.println(toPrint); 69 | } 70 | 71 | void setup() 72 | { 73 | Serial.begin(115200); 74 | setupBQ27441(); 75 | } 76 | 77 | void loop() 78 | { 79 | printBatteryStats(); 80 | delay(1000); 81 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun Battery Babysitter 2 | ======================================== 3 | 4 | [![SparkFun Battery Babysitter](https://cdn.sparkfun.com/assets/parts/1/1/3/3/1/13777-01.jpg)](https://www.sparkfun.com/products/13777) 5 | 6 | [*SparkFun Battery Babysitter (PRT-13777)*](https://www.sparkfun.com/products/13777) 7 | 8 | The [SparkFun Battery Babysitter](https://www.sparkfun.com/products/13777) is an all-in-one single-cell lithium polymer (LiPo) battery manager. It’s half **battery-charger**, half **battery monitor**, and it’s all you’ll ever need to keep your battery-powered project running safely and extensively. 9 | 10 | The Battery Babysitter features a pair of Texas Instruments LiPo-management IC’s: a [BQ24075 battery charger](http://www.ti.com/product/BQ24075) and a [BQ27441-G1A fuel gauge](http://www.ti.com/product/BQ27441-G1). The BQ24075 supports adjustable charge rates up to 1.5A, as well as USB-compliant 100mA and 500mA options. It also features power-path management, guaranteeing reliable power to your project. 11 | 12 | The self-calibrating, I2C-based BQ27441-G1A measures your battery’s voltage to estimate its charge percentage and remaining capacity. The chip is also hooked up to a current-sensing resistor, which allows it to measure current and power! It’s a handy IC to have, especially if you ever need to keep an extra eye on your project’s power draw. 13 | 14 | Repository Contents 15 | ------------------- 16 | 17 | * **/Documentation** - Data sheets, additional product information 18 | * **/Hardware** - Eagle design files (.brd, .sch) 19 | * **/Libraries** - Libraries for use with the Battery Babysitter 20 | * **/Production** - Production panel files (.brd) 21 | 22 | Documentation 23 | -------------- 24 | * **[BQ27441 LiPo Fuel Gauge Arduino Library](https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library)** - Arduino library for the Battery Babysitter's BQ27441-G1A LiPo Fuel Gauge. 25 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/battery-babysitter-hookup-guide)** - Basic hookup guide for the Battery Babysitter. 26 | * **[SparkFun Fritzing repo](https://github.com/sparkfun/Fritzing_Parts)** - Fritzing diagrams for SparkFun products. 27 | * **[SparkFun 3D Model repo](https://github.com/sparkfun/3D_Models)** - 3D models of SparkFun products. 28 | * **[SparkFun Graphical Datasheets](https://github.com/sparkfun/Graphical_Datasheets)** -Graphical Datasheets for various SparkFun products. 29 | 30 | Product Versions 31 | ---------------- 32 | * [Battery Babysitter v1.0 (PRT-13777)](https://www.sparkfun.com/products/13777)- Initial release of the SparkFun Battery Babysitter. 33 | 34 | Version History 35 | --------------- 36 | * [1.0](https://github.com/sparkfun/Battery_Babysitter/releases/tag/V_1.0) - v1.0 Hardware release 37 | 38 | License Information 39 | ------------------- 40 | 41 | This product is _**open source**_! 42 | 43 | Please review the LICENSE.md file for license information. 44 | 45 | If you have any questions or concerns on licensing, please contact techsupport@sparkfun.com. 46 | 47 | Distributed as-is; no warranty is given. 48 | 49 | - Your friends at SparkFun. 50 | 51 | __ 52 | -------------------------------------------------------------------------------- /Libraries/Arduino/examples/BQ27441_GPOUT_BAT_LOW/BQ27441_GPOUT_BAT_LOW.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | BQ27441_GPOUT_BAT_LOW 3 | BQ27441 Library GPOUT Example - Battery low Mode 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | Demonstrates how to use the BQ27441's BAT_LOW function on GPOUT. In this mode 9 | GPOUT will become active whenever the battery goes below a set threshold. 10 | 11 | In addition to I2C, connect GPOUT to pin 2 of your Arduino. 12 | 13 | After uploading, open up the serial monitor to 115200 baud to view your 14 | battery's stats. They should only print when the percentage goes up or down 15 | by 1%. 16 | 17 | Hardware Resources: 18 | - Arduino Development Board 19 | - SparkFun Battery Babysitter 20 | 21 | Development environment specifics: 22 | Arduino 1.6.7 23 | SparkFun Battery Babysitter v1.0 24 | Arduino Uno (any 'duino should do) 25 | ******************************************************************************/ 26 | #include 27 | 28 | // Set BATTERY_CAPACITY to the design capacity of your battery. 29 | const unsigned int BATTERY_CAPACITY = 850; // e.g. 850mAh battery 30 | 31 | const byte SOCI_SET = 15; // Interrupt set threshold at 20% 32 | const byte SOCI_CLR = 20; // Interrupt clear threshold at 25% 33 | const byte SOCF_SET = 5; // Final threshold set at 5% 34 | const byte SOCF_CLR = 10; // Final threshold clear at 10% 35 | 36 | // Arduino pin connected to BQ27441's GPOUT pin 37 | const int GPOUT_PIN = 2; 38 | 39 | void setupBQ27441(void) 40 | { 41 | pinMode(GPOUT_PIN, INPUT_PULLUP); // Set the GPOUT pin as an input w/ pullup 42 | 43 | // Use lipo.begin() to initialize the BQ27441-G1A and confirm that it's 44 | // connected and communicating. 45 | if (!lipo.begin()) // begin() will return true if communication is successful 46 | { 47 | // If communication fails, print an error message and loop forever. 48 | Serial.println("Error: Unable to communicate with BQ27441."); 49 | Serial.println(" Check wiring and try again."); 50 | Serial.println(" (Battery must be plugged into Battery Babysitter!)"); 51 | while (1) ; 52 | } 53 | Serial.println("Connected to BQ27441!"); 54 | 55 | // In this example, we'll manually enter and exit config mode. By controlling 56 | // config mode manually, you can set the chip up faster -- completing all of 57 | // the set up in a single config mode sweep. 58 | lipo.enterConfig(); // To configure the values below, you must be in config mode 59 | lipo.setCapacity(BATTERY_CAPACITY); // Set the battery capacity 60 | lipo.setGPOUTPolarity(LOW); // Set GPOUT to active-high 61 | lipo.setGPOUTFunction(BAT_LOW); // Set GPOUT to BAT_LOW mode 62 | lipo.setSOC1Thresholds(SOCI_SET, SOCI_CLR); // Set SOCI set and clear thresholds 63 | lipo.setSOCFThresholds(SOCF_SET, SOCF_CLR); // Set SOCF set and clear thresholds 64 | lipo.exitConfig(); 65 | 66 | // Use lipo.GPOUTPolarity to read from the chip and confirm the changes 67 | if (lipo.GPOUTPolarity()) 68 | Serial.println("GPOUT set to active-HIGH"); 69 | else 70 | Serial.println("GPOUT set to active-LOW"); 71 | 72 | // Use lipo.GPOUTFunction to confirm the functionality of GPOUT 73 | if (lipo.GPOUTFunction()) 74 | Serial.println("GPOUT function set to BAT_LOW"); 75 | else 76 | Serial.println("GPOUT function set to SOC_INT"); 77 | 78 | // Read the set and clear thresholds to make sure they were set correctly 79 | Serial.println("SOC1 Set Threshold: " + String(lipo.SOC1SetThreshold())); 80 | Serial.println("SOC1 Clear Threshold: " + String(lipo.SOC1ClearThreshold())); 81 | Serial.println("SOCF Set Threshold: " + String(lipo.SOCFSetThreshold())); 82 | Serial.println("SOCF Clear Threshold: " + String(lipo.SOCFClearThreshold())); 83 | } 84 | 85 | void printBatteryStats() 86 | { 87 | // Read battery stats from the BQ27441-G1A 88 | unsigned int soc = lipo.soc(); // Read state-of-charge (%) 89 | unsigned int volts = lipo.voltage(); // Read battery voltage (mV) 90 | int current = lipo.current(AVG); // Read average current (mA) 91 | unsigned int fullCapacity = lipo.capacity(FULL); // Read full capacity (mAh) 92 | unsigned int capacity = lipo.capacity(REMAIN); // Read remaining capacity (mAh) 93 | int power = lipo.power(); // Read average power draw (mW) 94 | int health = lipo.soh(); // Read state-of-health (%) 95 | 96 | // Assemble a string to print 97 | String toPrint = String(soc) + "% | "; 98 | toPrint += String(volts) + " mV | "; 99 | toPrint += String(current) + " mA | "; 100 | toPrint += String(capacity) + " / "; 101 | toPrint += String(fullCapacity) + " mAh | "; 102 | toPrint += String(power) + " mW | "; 103 | toPrint += String(health) + "%"; 104 | toPrint += " | 0x" + String(lipo.flags(), HEX); 105 | 106 | // Print the string 107 | Serial.println(toPrint); 108 | } 109 | 110 | void setup() 111 | { 112 | Serial.begin(115200); 113 | setupBQ27441(); 114 | } 115 | 116 | void loop() 117 | { 118 | printBatteryStats(); 119 | 120 | // If the GPOUT interrupt is active (low) 121 | if (!digitalRead(GPOUT_PIN)) 122 | { 123 | // Check which of the flags triggered the interrupt 124 | if (lipo.socfFlag()) 125 | Serial.println(""); 126 | else if (lipo.socFlag()) 127 | Serial.println(""); 128 | } 129 | delay(1000); 130 | } -------------------------------------------------------------------------------- /Libraries/Arduino/examples/BQ27441_GPOUT_SOC_INT/BQ27441_GPOUT_SOC_INT.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | BQ27441_GPOUT_SOC_INT 3 | BQ27441 Library GPOUT Example - State-of-charge interval mode 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | Demonstrates how to use the BQ27441's SOC_INT function on GPOUT. In this mode 9 | GPOUT will pulse every time the state-of-charge (soc) goes up or down by a 10 | set percentage integer. 11 | 12 | In addition to I2C, connect GPOUT to pin 2 of your Arduino. 13 | 14 | After uploading, open up the serial monitor to 115200 baud to view your 15 | battery's stats. They should only print when the percentage goes up or down 16 | by 1%. 17 | 18 | Hardware Resources: 19 | - Arduino Development Board 20 | - SparkFun Battery Babysitter 21 | 22 | Development environment specifics: 23 | Arduino 1.6.7 24 | SparkFun Battery Babysitter v1.0 25 | Arduino Uno (any 'duino should do) 26 | ******************************************************************************/ 27 | #include 28 | 29 | // Set BATTERY_CAPACITY to the design capacity of your battery. 30 | const unsigned int BATTERY_CAPACITY = 850; // e.g. 850mAh battery 31 | 32 | // Arduino pin connected to BQ27441's GPOUT pin 33 | const int GPOUT_PIN = 2; 34 | 35 | // Set the integer percentage change that triggers an interrupt 36 | const int PERCENTAGE_INTERVAL = 1; 37 | 38 | void setupBQ27441(void) 39 | { 40 | pinMode(GPOUT_PIN, INPUT_PULLUP); // Set the GPOUT pin as an input w/ pullup 41 | 42 | // Use lipo.begin() to initialize the BQ27441-G1A and confirm that it's 43 | // connected and communicating. 44 | if (!lipo.begin()) // begin() will return true if communication is successful 45 | { 46 | // If communication fails, print an error message and loop forever. 47 | Serial.println("Error: Unable to communicate with BQ27441."); 48 | Serial.println(" Check wiring and try again."); 49 | Serial.println(" (Battery must be plugged into Battery Babysitter!)"); 50 | while (1) ; 51 | } 52 | Serial.println("Connected to BQ27441!"); 53 | 54 | // In this example, we'll manually enter and exit config mode. By controlling 55 | // config mode manually, you can set the chip up faster -- completing all of 56 | // the set up in a single config mode sweep. 57 | lipo.enterConfig(); // To configure the values below, you must be in config mode 58 | lipo.setCapacity(BATTERY_CAPACITY); // Set the battery capacity 59 | lipo.setGPOUTPolarity(LOW); // Set GPOUT to active-low 60 | lipo.setGPOUTFunction(SOC_INT); // Set GPOUT to SOC_INT mode 61 | lipo.setSOCIDelta(PERCENTAGE_INTERVAL); // Set percentage change integer 62 | lipo.exitConfig(); // Exit config mode to save changes 63 | 64 | // Use lipo.GPOUTPolarity to read from the chip and confirm the changes 65 | if (lipo.GPOUTPolarity()) 66 | Serial.println("GPOUT set to active-HIGH"); 67 | else 68 | Serial.println("GPOUT set to active-LOW"); 69 | 70 | // Use lipo.GPOUTFunction to confirm the functionality of GPOUT 71 | if (lipo.GPOUTFunction()) 72 | Serial.println("GPOUT function set to BAT_LOW"); 73 | else 74 | Serial.println("GPOUT function set to SOC_INT"); 75 | 76 | // Read lipo.sociDelta() to confirm the integer change value 77 | Serial.println("SOCI Delta: " + String(lipo.sociDelta())); 78 | Serial.println(); 79 | 80 | // Use lipo.pulseGPOUT() to trigger a pulse on GPOUT. This only works 81 | // in SOC_INT mode. 82 | Serial.println("Testing GPOUT Pulse"); 83 | lipo.pulseGPOUT(); 84 | int timeout = 10000; // The pulse can take a while to occur. Set max to 10s 85 | while ((digitalRead(GPOUT_PIN)) && timeout--) 86 | delay(1); // Wait for GPOUT to go high, or timeout to occur 87 | if (timeout > 0) 88 | { 89 | // If GPOUT pulsed, print success message. 90 | Serial.print("GPOUT test successful!"); 91 | Serial.println("(" + String(10000 - timeout) + ")"); 92 | Serial.print("GPOUT will pulse whenever the SoC "); 93 | Serial.println("value changes by SOCI delta."); 94 | Serial.print("Or when the battery changes from"); 95 | Serial.println(" charging to discharging, or vice-versa."); 96 | Serial.println(); 97 | } 98 | else 99 | { 100 | // If GPOUT didn't pulse, something went wrong. Print error message 101 | // and loop forever. 102 | Serial.println("GPOUT didn't pulse."); 103 | Serial.print("Make sure it's connected to pin "); 104 | Serial.print(GPOUT_PIN); 105 | Serial.println(" and reset."); 106 | while (1) ; 107 | } 108 | } 109 | 110 | void printBatteryStats() 111 | { 112 | // Read battery stats from the BQ27441-G1A 113 | unsigned int soc = lipo.soc(); // Read state-of-charge (%) 114 | unsigned int volts = lipo.voltage(); // Read battery voltage (mV) 115 | int current = lipo.current(AVG); // Read average current (mA) 116 | unsigned int fullCapacity = lipo.capacity(FULL); // Read full capacity (mAh) 117 | unsigned int capacity = lipo.capacity(REMAIN); // Read remaining capacity (mAh) 118 | int power = lipo.power(); // Read average power draw (mW) 119 | int health = lipo.soh(); // Read state-of-health (%) 120 | 121 | // Assemble a string to print 122 | String toPrint = "[" + String(millis()/1000) + "] "; 123 | toPrint += String(soc) + "% | "; 124 | toPrint += String(volts) + " mV | "; 125 | toPrint += String(current) + " mA | "; 126 | toPrint += String(capacity) + " / "; 127 | toPrint += String(fullCapacity) + " mAh | "; 128 | toPrint += String(power) + " mW | "; 129 | toPrint += String(health) + "%"; 130 | 131 | // Print the string 132 | Serial.println(toPrint); 133 | } 134 | 135 | void setup() 136 | { 137 | Serial.begin(115200); 138 | setupBQ27441(); 139 | } 140 | 141 | void loop() 142 | { 143 | // The interrupt is set to active-low. If the GPOUT pin goes low... 144 | if (digitalRead(GPOUT_PIN) == LOW) 145 | { 146 | // ...SOC_INT occurred. Print battery stats. 147 | printBatteryStats(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Libraries/Arduino/src/BQ27441_Definitions.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | BQ27441_Definitions.h 3 | BQ27441 LiPo Fuel Gauge Definitions 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | BQ27441 hardware constants, register addresses, and bit positions. 9 | 10 | Hardware Resources: 11 | - Arduino Development Board 12 | - SparkFun Battery Babysitter 13 | 14 | Development environment specifics: 15 | Arduino 1.6.7 16 | SparkFun Battery Babysitter v1.0 17 | Arduino Uno (any 'duino should do) 18 | ******************************************************************************/ 19 | #define BQ72441_I2C_ADDRESS 0x55 // Default I2C address of the BQ27441-G1A 20 | 21 | /////////////////////// 22 | // General Constants // 23 | /////////////////////// 24 | #define BQ27441_UNSEAL_KEY 0x8000 // Secret code to unseal the BQ27441-G1A 25 | #define BQ27441_DEVICE_ID 0x0421 // Default device ID 26 | 27 | /////////////////////// 28 | // Standard Commands // 29 | /////////////////////// 30 | // The fuel gauge uses a series of 2-byte standard commands to enable system 31 | // reading and writing of battery information. Each command has an associated 32 | // sequential command-code pair. 33 | #define BQ27441_COMMAND_CONTROL 0x00 // Control() 34 | #define BQ27441_COMMAND_TEMP 0x02 // Temperature() 35 | #define BQ27441_COMMAND_VOLTAGE 0x04 // Voltage() 36 | #define BQ27441_COMMAND_FLAGS 0x06 // Flags() 37 | #define BQ27441_COMMAND_NOM_CAPACITY 0x08 // NominalAvailableCapacity() 38 | #define BQ27441_COMMAND_AVAIL_CAPACITY 0x0A // FullAvailableCapacity() 39 | #define BQ27441_COMMAND_REM_CAPACITY 0x0C // RemainingCapacity() 40 | #define BQ27441_COMMAND_FULL_CAPACITY 0x0E // FullChargeCapacity() 41 | #define BQ27441_COMMAND_AVG_CURRENT 0x10 // AverageCurrent() 42 | #define BQ27441_COMMAND_STDBY_CURRENT 0x12 // StandbyCurrent() 43 | #define BQ27441_COMMAND_MAX_CURRENT 0x14 // MaxLoadCurrent() 44 | #define BQ27441_COMMAND_AVG_POWER 0x18 // AveragePower() 45 | #define BQ27441_COMMAND_SOC 0x1C // StateOfCharge() 46 | #define BQ27441_COMMAND_INT_TEMP 0x1E // InternalTemperature() 47 | #define BQ27441_COMMAND_SOH 0x20 // StateOfHealth() 48 | #define BQ27441_COMMAND_REM_CAP_UNFL 0x28 // RemainingCapacityUnfiltered() 49 | #define BQ27441_COMMAND_REM_CAP_FIL 0x2A // RemainingCapacityFiltered() 50 | #define BQ27441_COMMAND_FULL_CAP_UNFL 0x2C // FullChargeCapacityUnfiltered() 51 | #define BQ27441_COMMAND_FULL_CAP_FIL 0x2E // FullChargeCapacityFiltered() 52 | #define BQ27441_COMMAND_SOC_UNFL 0x30 // StateOfChargeUnfiltered() 53 | 54 | ////////////////////////// 55 | // Control Sub-commands // 56 | ////////////////////////// 57 | // Issuing a Control() command requires a subsequent 2-byte subcommand. These 58 | // additional bytes specify the particular control function desired. The 59 | // Control() command allows the system to control specific features of the fuel 60 | // gauge during normal operation and additional features when the device is in 61 | // different access modes. 62 | #define BQ27441_CONTROL_STATUS 0x00 63 | #define BQ27441_CONTROL_DEVICE_TYPE 0x01 64 | #define BQ27441_CONTROL_FW_VERSION 0x02 65 | #define BQ27441_CONTROL_DM_CODE 0x04 66 | #define BQ27441_CONTROL_PREV_MACWRITE 0x07 67 | #define BQ27441_CONTROL_CHEM_ID 0x08 68 | #define BQ27441_CONTROL_BAT_INSERT 0x0C 69 | #define BQ27441_CONTROL_BAT_REMOVE 0x0D 70 | #define BQ27441_CONTROL_SET_HIBERNATE 0x11 71 | #define BQ27441_CONTROL_CLEAR_HIBERNATE 0x12 72 | #define BQ27441_CONTROL_SET_CFGUPDATE 0x13 73 | #define BQ27441_CONTROL_SHUTDOWN_ENABLE 0x1B 74 | #define BQ27441_CONTROL_SHUTDOWN 0x1C 75 | #define BQ27441_CONTROL_SEALED 0x20 76 | #define BQ27441_CONTROL_PULSE_SOC_INT 0x23 77 | #define BQ27441_CONTROL_RESET 0x41 78 | #define BQ27441_CONTROL_SOFT_RESET 0x42 79 | #define BQ27441_CONTROL_EXIT_CFGUPDATE 0x43 80 | #define BQ27441_CONTROL_EXIT_RESIM 0x44 81 | 82 | /////////////////////////////////////////// 83 | // Control Status Word - Bit Definitions // 84 | /////////////////////////////////////////// 85 | // Bit positions for the 16-bit data of CONTROL_STATUS. 86 | // CONTROL_STATUS instructs the fuel gauge to return status information to 87 | // Control() addresses 0x00 and 0x01. The read-only status word contains status 88 | // bits that are set or cleared either automatically as conditions warrant or 89 | // through using specified subcommands. 90 | #define BQ27441_STATUS_SHUTDOWNEN (1<<15) 91 | #define BQ27441_STATUS_WDRESET (1<<14) 92 | #define BQ27441_STATUS_SS (1<<13) 93 | #define BQ27441_STATUS_CALMODE (1<<12) 94 | #define BQ27441_STATUS_CCA (1<<11) 95 | #define BQ27441_STATUS_BCA (1<<10) 96 | #define BQ27441_STATUS_QMAX_UP (1<<9) 97 | #define BQ27441_STATUS_RES_UP (1<<8) 98 | #define BQ27441_STATUS_INITCOMP (1<<7) 99 | #define BQ27441_STATUS_HIBERNATE (1<<6) 100 | #define BQ27441_STATUS_SLEEP (1<<4) 101 | #define BQ27441_STATUS_LDMD (1<<3) 102 | #define BQ27441_STATUS_RUP_DIS (1<<2) 103 | #define BQ27441_STATUS_VOK (1<<1) 104 | 105 | //////////////////////////////////// 106 | // Flag Command - Bit Definitions // 107 | //////////////////////////////////// 108 | // Bit positions for the 16-bit data of Flags() 109 | // This read-word function returns the contents of the fuel gauging status 110 | // register, depicting the current operating status. 111 | #define BQ27441_FLAG_OT (1<<15) 112 | #define BQ27441_FLAG_UT (1<<14) 113 | #define BQ27441_FLAG_FC (1<<9) 114 | #define BQ27441_FLAG_CHG (1<<8) 115 | #define BQ27441_FLAG_OCVTAKEN (1<<7) 116 | #define BQ27441_FLAG_ITPOR (1<<5) 117 | #define BQ27441_FLAG_CFGUPMODE (1<<4) 118 | #define BQ27441_FLAG_BAT_DET (1<<3) 119 | #define BQ27441_FLAG_SOC1 (1<<2) 120 | #define BQ27441_FLAG_SOCF (1<<1) 121 | #define BQ27441_FLAG_DSG (1<<0) 122 | 123 | //////////////////////////// 124 | // Extended Data Commands // 125 | //////////////////////////// 126 | // Extended data commands offer additional functionality beyond the standard 127 | // set of commands. They are used in the same manner; however, unlike standard 128 | // commands, extended commands are not limited to 2-byte words. 129 | #define BQ27441_EXTENDED_OPCONFIG 0x3A // OpConfig() 130 | #define BQ27441_EXTENDED_CAPACITY 0x3C // DesignCapacity() 131 | #define BQ27441_EXTENDED_DATACLASS 0x3E // DataClass() 132 | #define BQ27441_EXTENDED_DATABLOCK 0x3F // DataBlock() 133 | #define BQ27441_EXTENDED_BLOCKDATA 0x40 // BlockData() 134 | #define BQ27441_EXTENDED_CHECKSUM 0x60 // BlockDataCheckSum() 135 | #define BQ27441_EXTENDED_CONTROL 0x61 // BlockDataControl() 136 | 137 | //////////////////////////////////////// 138 | // Configuration Class, Subclass ID's // 139 | //////////////////////////////////////// 140 | // To access a subclass of the extended data, set the DataClass() function 141 | // with one of these values. 142 | // Configuration Classes 143 | #define BQ27441_ID_SAFETY 2 // Safety 144 | #define BQ27441_ID_CHG_TERMINATION 36 // Charge Termination 145 | #define BQ27441_ID_CONFIG_DATA 48 // Data 146 | #define BQ27441_ID_DISCHARGE 49 // Discharge 147 | #define BQ27441_ID_REGISTERS 64 // Registers 148 | #define BQ27441_ID_POWER 68 // Power 149 | // Gas Gauging Classes 150 | #define BQ27441_ID_IT_CFG 80 // IT Cfg 151 | #define BQ27441_ID_CURRENT_THRESH 81 // Current Thresholds 152 | #define BQ27441_ID_STATE 82 // State 153 | // Ra Tables Classes 154 | #define BQ27441_ID_R_A_RAM 89 // R_a RAM 155 | // Calibration Classes 156 | #define BQ27441_ID_CALIB_DATA 104 // Data 157 | #define BQ27441_ID_CC_CAL 105 // CC Cal 158 | #define BQ27441_ID_CURRENT 107 // Current 159 | // Security Classes 160 | #define BQ27441_ID_CODES 112 // Codes 161 | 162 | ///////////////////////////////////////// 163 | // OpConfig Register - Bit Definitions // 164 | ///////////////////////////////////////// 165 | // Bit positions of the OpConfig Register 166 | #define BQ27441_OPCONFIG_BIE (1<<13) 167 | #define BQ27441_OPCONFIG_BI_PU_EN (1<<12) 168 | #define BQ27441_OPCONFIG_GPIOPOL (1<<11) 169 | #define BQ27441_OPCONFIG_SLEEP (1<<5) 170 | #define BQ27441_OPCONFIG_RMFCC (1<<4) 171 | #define BQ27441_OPCONFIG_BATLOWEN (1<<2) 172 | #define BQ27441_OPCONFIG_TEMPS (1<<0) -------------------------------------------------------------------------------- /Libraries/Arduino/src/SparkFunBQ27441.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SparkFunBQ27441.h 3 | BQ27441 Arduino Library Main Header File 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | Definition of the BQ27441 library, which implements all features of the 9 | BQ27441 LiPo Fuel Gauge. 10 | 11 | Hardware Resources: 12 | - Arduino Development Board 13 | - SparkFun Battery Babysitter 14 | 15 | Development environment specifics: 16 | Arduino 1.6.7 17 | SparkFun Battery Babysitter v1.0 18 | Arduino Uno (any 'duino should do) 19 | ******************************************************************************/ 20 | 21 | #ifndef SparkFunBQ27441_h 22 | #define SparkFunBQ27441_h 23 | 24 | #include "Arduino.h" 25 | #include "BQ27441_Definitions.h" 26 | 27 | #define BQ72441_I2C_TIMEOUT 2000 28 | 29 | // Parameters for the current() function, to specify which current to read 30 | typedef enum { 31 | AVG, // Average Current (DEFAULT) 32 | STBY, // Standby Current 33 | MAX // Max Current 34 | } current_measure; 35 | 36 | // Parameters for the capacity() function, to specify which capacity to read 37 | typedef enum { 38 | REMAIN, // Remaining Capacity (DEFAULT) 39 | FULL, // Full Capacity 40 | AVAIL, // Available Capacity 41 | AVAIL_FULL, // Full Available Capacity 42 | REMAIN_F, // Remaining Capacity Filtered 43 | REMAIN_UF, // Remaining Capacity Unfiltered 44 | FULL_F, // Full Capacity Filtered 45 | FULL_UF, // Full Capacity Unfiltered 46 | DESIGN // Design Capacity 47 | } capacity_measure; 48 | 49 | // Parameters for the soc() function 50 | typedef enum { 51 | FILTERED, // State of Charge Filtered (DEFAULT) 52 | UNFILTERED // State of Charge Unfiltered 53 | } soc_measure; 54 | 55 | // Parameters for the soh() function 56 | typedef enum { 57 | PERCENT, // State of Health Percentage (DEFAULT) 58 | SOH_STAT // State of Health Status Bits 59 | } soh_measure; 60 | 61 | // Parameters for the temperature() function 62 | typedef enum { 63 | BATTERY, // Battery Temperature (DEFAULT) 64 | INTERNAL_TEMP // Internal IC Temperature 65 | } temp_measure; 66 | 67 | // Parameters for the setGPOUTFunction() funciton 68 | typedef enum { 69 | SOC_INT, // Set GPOUT to SOC_INT functionality 70 | BAT_LOW // Set GPOUT to BAT_LOW functionality 71 | } gpout_function; 72 | 73 | class BQ27441 { 74 | public: 75 | ////////////////////////////// 76 | // Initialization Functions // 77 | ////////////////////////////// 78 | /** 79 | Initializes class variables 80 | */ 81 | BQ27441(); 82 | 83 | /** 84 | Initializes I2C and verifies communication with the BQ27441. 85 | Must be called before using any other functions. 86 | 87 | @return true if communication was successful. 88 | */ 89 | bool begin(void); 90 | 91 | /** 92 | Configures the design capacity of the connected battery. 93 | 94 | @param capacity of battery (unsigned 16-bit value) 95 | @return true if capacity successfully set. 96 | */ 97 | bool setCapacity(uint16_t capacity); 98 | 99 | ///////////////////////////// 100 | // Battery Characteristics // 101 | ///////////////////////////// 102 | /** 103 | Reads and returns the battery voltage 104 | 105 | @return battery voltage in mV 106 | */ 107 | uint16_t voltage(void); 108 | 109 | /** 110 | Reads and returns the specified current measurement 111 | 112 | @param current_measure enum specifying current value to be read 113 | @return specified current measurement in mA. >0 indicates charging. 114 | */ 115 | int16_t current(current_measure type = AVG); 116 | 117 | /** 118 | Reads and returns the specified capacity measurement 119 | 120 | @param capacity_measure enum specifying capacity value to be read 121 | @return specified capacity measurement in mAh. 122 | */ 123 | uint16_t capacity(capacity_measure type = REMAIN); 124 | 125 | /** 126 | Reads and returns measured average power 127 | 128 | @return average power in mAh. >0 indicates charging. 129 | */ 130 | int16_t power(void); 131 | 132 | /** 133 | Reads and returns specified state of charge measurement 134 | 135 | @param soc_measure enum specifying filtered or unfiltered measurement 136 | @return specified state of charge measurement in % 137 | */ 138 | uint16_t soc(soc_measure type = FILTERED); 139 | 140 | /** 141 | Reads and returns specified state of health measurement 142 | 143 | @param soh_measure enum specifying filtered or unfiltered measurement 144 | @return specified state of health measurement in %, or status bits 145 | */ 146 | uint8_t soh(soh_measure type = PERCENT); 147 | 148 | /** 149 | Reads and returns specified temperature measurement 150 | 151 | @param temp_measure enum specifying internal or battery measurement 152 | @return specified temperature measurement in degrees C 153 | */ 154 | uint16_t temperature(temp_measure type = BATTERY); 155 | 156 | //////////////////////////// 157 | // GPOUT Control Commands // 158 | //////////////////////////// 159 | /** 160 | Get GPOUT polarity setting (active-high or active-low) 161 | 162 | @return true if active-high, false if active-low 163 | */ 164 | bool GPOUTPolarity(void); 165 | 166 | /** 167 | Set GPOUT polarity to active-high or active-low 168 | 169 | @param activeHigh is true if active-high, false if active-low 170 | @return true on success 171 | */ 172 | bool setGPOUTPolarity(bool activeHigh); 173 | 174 | /** 175 | Get GPOUT function (BAT_LOW or SOC_INT) 176 | 177 | @return true if BAT_LOW or false if SOC_INT 178 | */ 179 | bool GPOUTFunction(void); 180 | 181 | /** 182 | Set GPOUT function to BAT_LOW or SOC_INT 183 | 184 | @param function should be either BAT_LOW or SOC_INT 185 | @return true on success 186 | */ 187 | bool setGPOUTFunction(gpout_function function); 188 | 189 | /** 190 | Get SOC1_Set Threshold - threshold to set the alert flag 191 | 192 | @return state of charge value between 0 and 100% 193 | */ 194 | uint8_t SOC1SetThreshold(void); 195 | 196 | /** 197 | Get SOC1_Clear Threshold - threshold to clear the alert flag 198 | 199 | @return state of charge value between 0 and 100% 200 | */ 201 | uint8_t SOC1ClearThreshold(void); 202 | 203 | /** 204 | Set the SOC1 set and clear thresholds to a percentage 205 | 206 | @param set and clear percentages between 0 and 100. clear > set. 207 | @return true on success 208 | */ 209 | bool setSOC1Thresholds(uint8_t set, uint8_t clear); 210 | 211 | /** 212 | Get SOCF_Set Threshold - threshold to set the alert flag 213 | 214 | @return state of charge value between 0 and 100% 215 | */ 216 | uint8_t SOCFSetThreshold(void); 217 | 218 | /** 219 | Get SOCF_Clear Threshold - threshold to clear the alert flag 220 | 221 | @return state of charge value between 0 and 100% 222 | */ 223 | uint8_t SOCFClearThreshold(void); 224 | 225 | /** 226 | Set the SOCF set and clear thresholds to a percentage 227 | 228 | @param set and clear percentages between 0 and 100. clear > set. 229 | @return true on success 230 | */ 231 | bool setSOCFThresholds(uint8_t set, uint8_t clear); 232 | 233 | /** 234 | Check if the SOC1 flag is set in flags() 235 | 236 | @return true if flag is set 237 | */ 238 | bool socFlag(void); 239 | 240 | /** 241 | Check if the SOCF flag is set in flags() 242 | 243 | @return true if flag is set 244 | */ 245 | bool socfFlag(void); 246 | 247 | /** 248 | Get the SOC_INT interval delta 249 | 250 | @return interval percentage value between 1 and 100 251 | */ 252 | uint8_t sociDelta(void); 253 | 254 | /** 255 | Set the SOC_INT interval delta to a value between 1 and 100 256 | 257 | @param interval percentage value between 1 and 100 258 | @return true on success 259 | */ 260 | bool setSOCIDelta(uint8_t delta); 261 | 262 | /** 263 | Pulse the GPOUT pin - must be in SOC_INT mode 264 | 265 | @return true on success 266 | */ 267 | bool pulseGPOUT(void); 268 | 269 | ////////////////////////// 270 | // Control Sub-commands // 271 | ////////////////////////// 272 | 273 | /** 274 | Read the device type - should be 0x0421 275 | 276 | @return 16-bit value read from DEVICE_TYPE subcommand 277 | */ 278 | uint16_t deviceType(void); 279 | 280 | /** 281 | Enter configuration mode - set userControl if calling from an Arduino 282 | sketch and you want control over when to exitConfig. 283 | 284 | @param userControl is true if the Arduino sketch is handling entering 285 | and exiting config mode (should be false in library calls). 286 | @return true on success 287 | */ 288 | bool enterConfig(bool userControl = true); 289 | 290 | /** 291 | Exit configuration mode with the option to perform a resimulation 292 | 293 | @param resim is true if resimulation should be performed after exiting 294 | @return true on success 295 | */ 296 | bool exitConfig(bool resim = true); 297 | 298 | /** 299 | Read the flags() command 300 | 301 | @return 16-bit representation of flags() command register 302 | */ 303 | uint16_t flags(void); 304 | 305 | /** 306 | Read the CONTROL_STATUS subcommand of control() 307 | 308 | @return 16-bit representation of CONTROL_STATUS subcommand 309 | */ 310 | uint16_t status(void); 311 | 312 | private: 313 | uint8_t _deviceAddress; // Stores the BQ27441-G1A's I2C address 314 | bool _sealFlag; // Global to identify that IC was previously sealed 315 | bool _userConfigControl; // Global to identify that user has control over 316 | // entering/exiting config 317 | 318 | /** 319 | Check if the BQ27441-G1A is sealed or not. 320 | 321 | @return true if the chip is sealed 322 | */ 323 | bool sealed(void); 324 | 325 | /** 326 | Seal the BQ27441-G1A 327 | 328 | @return true on success 329 | */ 330 | bool seal(void); 331 | 332 | /** 333 | UNseal the BQ27441-G1A 334 | 335 | @return true on success 336 | */ 337 | bool unseal(void); 338 | 339 | /** 340 | Read the 16-bit opConfig register from extended data 341 | 342 | @return opConfig register contents 343 | */ 344 | uint16_t opConfig(void); 345 | 346 | /** 347 | Write the 16-bit opConfig register in extended data 348 | 349 | @param New 16-bit value for opConfig 350 | @return true on success 351 | */ 352 | bool writeOpConfig(uint16_t value); 353 | 354 | /** 355 | Issue a soft-reset to the BQ27441-G1A 356 | 357 | @return true on success 358 | */ 359 | bool softReset(void); 360 | 361 | /** 362 | Read a 16-bit command word from the BQ27441-G1A 363 | 364 | @param subAddress is the command to be read from 365 | @return 16-bit value of the command's contents 366 | */ 367 | uint16_t readWord(uint16_t subAddress); 368 | 369 | /** 370 | Read a 16-bit subcommand() from the BQ27441-G1A's control() 371 | 372 | @param function is the subcommand of control() to be read 373 | @return 16-bit value of the subcommand's contents 374 | */ 375 | uint16_t readControlWord(uint16_t function); 376 | 377 | /** 378 | Execute a subcommand() from the BQ27441-G1A's control() 379 | 380 | @param function is the subcommand of control() to be executed 381 | @return true on success 382 | */ 383 | bool executeControlWord(uint16_t function); 384 | 385 | //////////////////////////// 386 | // Extended Data Commands // 387 | //////////////////////////// 388 | /** 389 | Issue a BlockDataControl() command to enable BlockData access 390 | 391 | @return true on success 392 | */ 393 | bool blockDataControl(void); 394 | 395 | /** 396 | Issue a DataClass() command to set the data class to be accessed 397 | 398 | @param id is the id number of the class 399 | @return true on success 400 | */ 401 | bool blockDataClass(uint8_t id); 402 | 403 | /** 404 | Issue a DataBlock() command to set the data block to be accessed 405 | 406 | @param offset of the data block 407 | @return true on success 408 | */ 409 | bool blockDataOffset(uint8_t offset); 410 | 411 | /** 412 | Read the current checksum using BlockDataCheckSum() 413 | 414 | @return true on success 415 | */ 416 | uint8_t blockDataChecksum(void); 417 | 418 | /** 419 | Use BlockData() to read a byte from the loaded extended data 420 | 421 | @param offset of data block byte to be read 422 | @return true on success 423 | */ 424 | uint8_t readBlockData(uint8_t offset); 425 | 426 | /** 427 | Use BlockData() to write a byte to an offset of the loaded data 428 | 429 | @param offset is the position of the byte to be written 430 | data is the value to be written 431 | @return true on success 432 | */ 433 | bool writeBlockData(uint8_t offset, uint8_t data); 434 | 435 | /** 436 | Read all 32 bytes of the loaded extended data and compute a 437 | checksum based on the values. 438 | 439 | @return 8-bit checksum value calculated based on loaded data 440 | */ 441 | uint8_t computeBlockChecksum(void); 442 | 443 | /** 444 | Use the BlockDataCheckSum() command to write a checksum value 445 | 446 | @param csum is the 8-bit checksum to be written 447 | @return true on success 448 | */ 449 | bool writeBlockChecksum(uint8_t csum); 450 | 451 | /** 452 | Read a byte from extended data specifying a class ID and position offset 453 | 454 | @param classID is the id of the class to be read from 455 | offset is the byte position of the byte to be read 456 | @return 8-bit value of specified data 457 | */ 458 | uint8_t readExtendedData(uint8_t classID, uint8_t offset); 459 | 460 | /** 461 | Write a specified number of bytes to extended data specifying a 462 | class ID, position offset. 463 | 464 | @param classID is the id of the class to be read from 465 | offset is the byte position of the byte to be read 466 | data is the data buffer to be written 467 | len is the number of bytes to be written 468 | @return true on success 469 | */ 470 | bool writeExtendedData(uint8_t classID, uint8_t offset, uint8_t * data, uint8_t len); 471 | 472 | ///////////////////////////////// 473 | // I2C Read and Write Routines // 474 | ///////////////////////////////// 475 | 476 | /** 477 | Read a specified number of bytes over I2C at a given subAddress 478 | 479 | @param subAddress is the 8-bit address of the data to be read 480 | dest is the data buffer to be written to 481 | count is the number of bytes to be read 482 | @return true on success 483 | */ 484 | int16_t i2cReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count); 485 | 486 | /** 487 | Write a specified number of bytes over I2C to a given subAddress 488 | 489 | @param subAddress is the 8-bit address of the data to be written to 490 | src is the data buffer to be written 491 | count is the number of bytes to be written 492 | @return true on success 493 | */ 494 | uint16_t i2cWriteBytes(uint8_t subAddress, uint8_t * src, uint8_t count); 495 | }; 496 | 497 | extern BQ27441 lipo; // Use lipo.[] to interact with the library in an Arduino sketch 498 | // Thanks for reading! 499 | 500 | #endif 501 | -------------------------------------------------------------------------------- /Libraries/Arduino/src/SparkFunBQ27441.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SparkFunBQ27441.cpp 3 | BQ27441 Arduino Library Main Source File 4 | Jim Lindblom @ SparkFun Electronics 5 | May 9, 2016 6 | https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library 7 | 8 | Implementation of all features of the BQ27441 LiPo Fuel Gauge. 9 | 10 | Hardware Resources: 11 | - Arduino Development Board 12 | - SparkFun Battery Babysitter 13 | 14 | Development environment specifics: 15 | Arduino 1.6.7 16 | SparkFun Battery Babysitter v1.0 17 | Arduino Uno (any 'duino should do) 18 | ******************************************************************************/ 19 | 20 | #include "Arduino.h" 21 | #include 22 | #include "SparkFunBQ27441.h" 23 | #include "BQ27441_Definitions.h" 24 | 25 | /***************************************************************************** 26 | ************************** Initialization Functions ************************* 27 | *****************************************************************************/ 28 | // Initializes class variables 29 | BQ27441::BQ27441() : _deviceAddress(BQ72441_I2C_ADDRESS), _sealFlag(false), _userConfigControl(false) 30 | { 31 | } 32 | 33 | // Initializes I2C and verifies communication with the BQ27441. 34 | bool BQ27441::begin(void) 35 | { 36 | uint16_t deviceID = 0; 37 | 38 | Wire.begin(); // Initialize I2C master 39 | 40 | deviceID = deviceType(); // Read deviceType from BQ27441 41 | 42 | if (deviceID == BQ27441_DEVICE_ID) 43 | { 44 | return true; // If device ID is valid, return true 45 | } 46 | 47 | return false; // Otherwise return false 48 | } 49 | 50 | // Configures the design capacity of the connected battery. 51 | bool BQ27441::setCapacity(uint16_t capacity) 52 | { 53 | // Write to STATE subclass (82) of BQ27441 extended memory. 54 | // Offset 0x0A (10) 55 | // Design capacity is a 2-byte piece of data - MSB first 56 | uint8_t capMSB = capacity >> 8; 57 | uint8_t capLSB = capacity & 0x00FF; 58 | uint8_t capacityData[2] = {capMSB, capLSB}; 59 | return writeExtendedData(BQ27441_ID_STATE, 10, capacityData, 2); 60 | } 61 | 62 | /***************************************************************************** 63 | ********************** Battery Characteristics Functions ******************** 64 | *****************************************************************************/ 65 | 66 | // Reads and returns the battery voltage 67 | uint16_t BQ27441::voltage(void) 68 | { 69 | return readWord(BQ27441_COMMAND_VOLTAGE); 70 | } 71 | 72 | // Reads and returns the specified current measurement 73 | int16_t BQ27441::current(current_measure type) 74 | { 75 | int16_t current = 0; 76 | switch (type) 77 | { 78 | case AVG: 79 | current = (int16_t) readWord(BQ27441_COMMAND_AVG_CURRENT); 80 | break; 81 | case STBY: 82 | current = (int16_t) readWord(BQ27441_COMMAND_STDBY_CURRENT); 83 | break; 84 | case MAX: 85 | current = (int16_t) readWord(BQ27441_COMMAND_MAX_CURRENT); 86 | break; 87 | } 88 | 89 | return current; 90 | } 91 | 92 | // Reads and returns the specified capacity measurement 93 | uint16_t BQ27441::capacity(capacity_measure type) 94 | { 95 | uint16_t capacity = 0; 96 | switch (type) 97 | { 98 | case REMAIN: 99 | return readWord(BQ27441_COMMAND_REM_CAPACITY); 100 | break; 101 | case FULL: 102 | return readWord(BQ27441_COMMAND_FULL_CAPACITY); 103 | break; 104 | case AVAIL: 105 | capacity = readWord(BQ27441_COMMAND_NOM_CAPACITY); 106 | break; 107 | case AVAIL_FULL: 108 | capacity = readWord(BQ27441_COMMAND_AVAIL_CAPACITY); 109 | break; 110 | case REMAIN_F: 111 | capacity = readWord(BQ27441_COMMAND_REM_CAP_FIL); 112 | break; 113 | case REMAIN_UF: 114 | capacity = readWord(BQ27441_COMMAND_REM_CAP_UNFL); 115 | break; 116 | case FULL_F: 117 | capacity = readWord(BQ27441_COMMAND_FULL_CAP_FIL); 118 | break; 119 | case FULL_UF: 120 | capacity = readWord(BQ27441_COMMAND_FULL_CAP_UNFL); 121 | break; 122 | case DESIGN: 123 | capacity = readWord(BQ27441_EXTENDED_CAPACITY); 124 | } 125 | 126 | return capacity; 127 | } 128 | 129 | // Reads and returns measured average power 130 | int16_t BQ27441::power(void) 131 | { 132 | return (int16_t) readWord(BQ27441_COMMAND_AVG_POWER); 133 | } 134 | 135 | // Reads and returns specified state of charge measurement 136 | uint16_t BQ27441::soc(soc_measure type) 137 | { 138 | uint16_t socRet = 0; 139 | switch (type) 140 | { 141 | case FILTERED: 142 | socRet = readWord(BQ27441_COMMAND_SOC); 143 | break; 144 | case UNFILTERED: 145 | socRet = readWord(BQ27441_COMMAND_SOC_UNFL); 146 | break; 147 | } 148 | 149 | return socRet; 150 | } 151 | 152 | // Reads and returns specified state of health measurement 153 | uint8_t BQ27441::soh(soh_measure type) 154 | { 155 | uint16_t sohRaw = readWord(BQ27441_COMMAND_SOH); 156 | uint8_t sohStatus = sohRaw >> 8; 157 | uint8_t sohPercent = sohRaw & 0x00FF; 158 | 159 | if (type == PERCENT) 160 | return sohPercent; 161 | else 162 | return sohStatus; 163 | } 164 | 165 | // Reads and returns specified temperature measurement 166 | uint16_t BQ27441::temperature(temp_measure type) 167 | { 168 | uint16_t temp = 0; 169 | switch (type) 170 | { 171 | case BATTERY: 172 | temp = readWord(BQ27441_COMMAND_TEMP); 173 | break; 174 | case INTERNAL_TEMP: 175 | temp = readWord(BQ27441_COMMAND_INT_TEMP); 176 | break; 177 | } 178 | return temp; 179 | } 180 | 181 | /***************************************************************************** 182 | ************************** GPOUT Control Functions ************************** 183 | *****************************************************************************/ 184 | // Get GPOUT polarity setting (active-high or active-low) 185 | bool BQ27441::GPOUTPolarity(void) 186 | { 187 | uint16_t opConfigRegister = opConfig(); 188 | 189 | return (opConfigRegister & BQ27441_OPCONFIG_GPIOPOL); 190 | } 191 | 192 | // Set GPOUT polarity to active-high or active-low 193 | bool BQ27441::setGPOUTPolarity(bool activeHigh) 194 | { 195 | uint16_t oldOpConfig = opConfig(); 196 | 197 | // Check to see if we need to update opConfig: 198 | if ((activeHigh && (oldOpConfig & BQ27441_OPCONFIG_GPIOPOL)) || 199 | (!activeHigh && !(oldOpConfig & BQ27441_OPCONFIG_GPIOPOL))) 200 | return true; 201 | 202 | uint16_t newOpConfig = oldOpConfig; 203 | if (activeHigh) 204 | newOpConfig |= BQ27441_OPCONFIG_GPIOPOL; 205 | else 206 | newOpConfig &= ~(BQ27441_OPCONFIG_GPIOPOL); 207 | 208 | return writeOpConfig(newOpConfig); 209 | } 210 | 211 | // Get GPOUT function (BAT_LOW or SOC_INT) 212 | bool BQ27441::GPOUTFunction(void) 213 | { 214 | uint16_t opConfigRegister = opConfig(); 215 | 216 | return (opConfigRegister & BQ27441_OPCONFIG_BATLOWEN); 217 | } 218 | 219 | // Set GPOUT function to BAT_LOW or SOC_INT 220 | bool BQ27441::setGPOUTFunction(gpout_function function) 221 | { 222 | uint16_t oldOpConfig = opConfig(); 223 | 224 | // Check to see if we need to update opConfig: 225 | if ((function && (oldOpConfig & BQ27441_OPCONFIG_BATLOWEN)) || 226 | (!function && !(oldOpConfig & BQ27441_OPCONFIG_BATLOWEN))) 227 | return true; 228 | 229 | // Modify BATLOWN_EN bit of opConfig: 230 | uint16_t newOpConfig = oldOpConfig; 231 | if (function) 232 | newOpConfig |= BQ27441_OPCONFIG_BATLOWEN; 233 | else 234 | newOpConfig &= ~(BQ27441_OPCONFIG_BATLOWEN); 235 | 236 | // Write new opConfig 237 | return writeOpConfig(newOpConfig); 238 | } 239 | 240 | // Get SOC1_Set Threshold - threshold to set the alert flag 241 | uint8_t BQ27441::SOC1SetThreshold(void) 242 | { 243 | return readExtendedData(BQ27441_ID_DISCHARGE, 0); 244 | } 245 | 246 | // Get SOC1_Clear Threshold - threshold to clear the alert flag 247 | uint8_t BQ27441::SOC1ClearThreshold(void) 248 | { 249 | return readExtendedData(BQ27441_ID_DISCHARGE, 1); 250 | } 251 | 252 | // Set the SOC1 set and clear thresholds to a percentage 253 | bool BQ27441::setSOC1Thresholds(uint8_t set, uint8_t clear) 254 | { 255 | uint8_t thresholds[2]; 256 | thresholds[0] = constrain(set, 0, 100); 257 | thresholds[1] = constrain(clear, 0, 100); 258 | return writeExtendedData(BQ27441_ID_DISCHARGE, 0, thresholds, 2); 259 | } 260 | 261 | // Get SOCF_Set Threshold - threshold to set the alert flag 262 | uint8_t BQ27441::SOCFSetThreshold(void) 263 | { 264 | return readExtendedData(BQ27441_ID_DISCHARGE, 2); 265 | } 266 | 267 | // Get SOCF_Clear Threshold - threshold to clear the alert flag 268 | uint8_t BQ27441::SOCFClearThreshold(void) 269 | { 270 | return readExtendedData(BQ27441_ID_DISCHARGE, 3); 271 | } 272 | 273 | // Set the SOCF set and clear thresholds to a percentage 274 | bool BQ27441::setSOCFThresholds(uint8_t set, uint8_t clear) 275 | { 276 | uint8_t thresholds[2]; 277 | thresholds[0] = constrain(set, 0, 100); 278 | thresholds[1] = constrain(clear, 0, 100); 279 | return writeExtendedData(BQ27441_ID_DISCHARGE, 2, thresholds, 2); 280 | } 281 | 282 | // Check if the SOC1 flag is set 283 | bool BQ27441::socFlag(void) 284 | { 285 | uint16_t flagState = flags(); 286 | 287 | return flagState & BQ27441_FLAG_SOC1; 288 | } 289 | 290 | // Check if the SOCF flag is set 291 | bool BQ27441::socfFlag(void) 292 | { 293 | uint16_t flagState = flags(); 294 | 295 | return flagState & BQ27441_FLAG_SOCF; 296 | 297 | } 298 | 299 | // Get the SOC_INT interval delta 300 | uint8_t BQ27441::sociDelta(void) 301 | { 302 | return readExtendedData(BQ27441_ID_STATE, 26); 303 | } 304 | 305 | // Set the SOC_INT interval delta to a value between 1 and 100 306 | bool BQ27441::setSOCIDelta(uint8_t delta) 307 | { 308 | uint8_t soci = constrain(delta, 0, 100); 309 | return writeExtendedData(BQ27441_ID_STATE, 26, &soci, 1); 310 | } 311 | 312 | // Pulse the GPOUT pin - must be in SOC_INT mode 313 | bool BQ27441::pulseGPOUT(void) 314 | { 315 | return executeControlWord(BQ27441_CONTROL_PULSE_SOC_INT); 316 | } 317 | 318 | /***************************************************************************** 319 | *************************** Control Sub-Commands **************************** 320 | *****************************************************************************/ 321 | 322 | // Read the device type - should be 0x0421 323 | uint16_t BQ27441::deviceType(void) 324 | { 325 | return readControlWord(BQ27441_CONTROL_DEVICE_TYPE); 326 | } 327 | 328 | // Enter configuration mode - set userControl if calling from an Arduino sketch 329 | // and you want control over when to exitConfig 330 | bool BQ27441::enterConfig(bool userControl) 331 | { 332 | if (userControl) _userConfigControl = true; 333 | 334 | if (sealed()) 335 | { 336 | _sealFlag = true; 337 | unseal(); // Must be unsealed before making changes 338 | } 339 | 340 | if (executeControlWord(BQ27441_CONTROL_SET_CFGUPDATE)) 341 | { 342 | int16_t timeout = BQ72441_I2C_TIMEOUT; 343 | while ((timeout--) && (!(status() & BQ27441_FLAG_CFGUPMODE))) 344 | delay(1); 345 | 346 | if (timeout > 0) 347 | return true; 348 | } 349 | 350 | return false; 351 | } 352 | 353 | // Exit configuration mode with the option to perform a resimulation 354 | bool BQ27441::exitConfig(bool resim) 355 | { 356 | // There are two methods for exiting config mode: 357 | // 1. Execute the EXIT_CFGUPDATE command 358 | // 2. Execute the SOFT_RESET command 359 | // EXIT_CFGUPDATE exits config mode _without_ an OCV (open-circuit voltage) 360 | // measurement, and without resimulating to update unfiltered-SoC and SoC. 361 | // If a new OCV measurement or resimulation is desired, SOFT_RESET or 362 | // EXIT_RESIM should be used to exit config mode. 363 | if (resim) 364 | { 365 | if (softReset()) 366 | { 367 | int16_t timeout = BQ72441_I2C_TIMEOUT; 368 | while ((timeout--) && ((flags() & BQ27441_FLAG_CFGUPMODE))) 369 | delay(1); 370 | if (timeout > 0) 371 | { 372 | if (_sealFlag) seal(); // Seal back up if we IC was sealed coming in 373 | return true; 374 | } 375 | } 376 | return false; 377 | } 378 | else 379 | { 380 | return executeControlWord(BQ27441_CONTROL_EXIT_CFGUPDATE); 381 | } 382 | } 383 | 384 | // Read the flags() command 385 | uint16_t BQ27441::flags(void) 386 | { 387 | return readWord(BQ27441_COMMAND_FLAGS); 388 | } 389 | 390 | // Read the CONTROL_STATUS subcommand of control() 391 | uint16_t BQ27441::status(void) 392 | { 393 | return readControlWord(BQ27441_CONTROL_STATUS); 394 | } 395 | 396 | /***************************** Private Functions *****************************/ 397 | 398 | // Check if the BQ27441-G1A is sealed or not. 399 | bool BQ27441::sealed(void) 400 | { 401 | uint16_t stat = status(); 402 | return stat & BQ27441_STATUS_SS; 403 | } 404 | 405 | // Seal the BQ27441-G1A 406 | bool BQ27441::seal(void) 407 | { 408 | return readControlWord(BQ27441_CONTROL_SEALED); 409 | } 410 | 411 | // UNseal the BQ27441-G1A 412 | bool BQ27441::unseal(void) 413 | { 414 | // To unseal the BQ27441, write the key to the control 415 | // command. Then immediately write the same key to control again. 416 | if (readControlWord(BQ27441_UNSEAL_KEY)) 417 | { 418 | return readControlWord(BQ27441_UNSEAL_KEY); 419 | } 420 | return false; 421 | } 422 | 423 | // Read the 16-bit opConfig register from extended data 424 | uint16_t BQ27441::opConfig(void) 425 | { 426 | return readWord(BQ27441_EXTENDED_OPCONFIG); 427 | } 428 | 429 | // Write the 16-bit opConfig register in extended data 430 | bool BQ27441::writeOpConfig(uint16_t value) 431 | { 432 | uint8_t opConfigMSB = value >> 8; 433 | uint8_t opConfigLSB = value & 0x00FF; 434 | uint8_t opConfigData[2] = {opConfigMSB, opConfigLSB}; 435 | 436 | // OpConfig register location: BQ27441_ID_REGISTERS id, offset 0 437 | return writeExtendedData(BQ27441_ID_REGISTERS, 0, opConfigData, 2); 438 | } 439 | 440 | // Issue a soft-reset to the BQ27441-G1A 441 | bool BQ27441::softReset(void) 442 | { 443 | return executeControlWord(BQ27441_CONTROL_SOFT_RESET); 444 | } 445 | 446 | // Read a 16-bit command word from the BQ27441-G1A 447 | uint16_t BQ27441::readWord(uint16_t subAddress) 448 | { 449 | uint8_t data[2]; 450 | i2cReadBytes(subAddress, data, 2); 451 | return ((uint16_t) data[1] << 8) | data[0]; 452 | } 453 | 454 | // Read a 16-bit subcommand() from the BQ27441-G1A's control() 455 | uint16_t BQ27441::readControlWord(uint16_t function) 456 | { 457 | uint8_t subCommandMSB = (function >> 8); 458 | uint8_t subCommandLSB = (function & 0x00FF); 459 | uint8_t command[2] = {subCommandLSB, subCommandMSB}; 460 | uint8_t data[2] = {0, 0}; 461 | 462 | i2cWriteBytes((uint8_t) 0, command, 2); 463 | 464 | if (i2cReadBytes((uint8_t) 0, data, 2)) 465 | { 466 | return ((uint16_t)data[1] << 8) | data[0]; 467 | } 468 | 469 | return false; 470 | } 471 | 472 | // Execute a subcommand() from the BQ27441-G1A's control() 473 | bool BQ27441::executeControlWord(uint16_t function) 474 | { 475 | uint8_t subCommandMSB = (function >> 8); 476 | uint8_t subCommandLSB = (function & 0x00FF); 477 | uint8_t command[2] = {subCommandLSB, subCommandMSB}; 478 | uint8_t data[2] = {0, 0}; 479 | 480 | if (i2cWriteBytes((uint8_t) 0, command, 2)) 481 | return true; 482 | 483 | return false; 484 | } 485 | 486 | /***************************************************************************** 487 | ************************** Extended Data Commands *************************** 488 | *****************************************************************************/ 489 | 490 | // Issue a BlockDataControl() command to enable BlockData access 491 | bool BQ27441::blockDataControl(void) 492 | { 493 | uint8_t enableByte = 0x00; 494 | return i2cWriteBytes(BQ27441_EXTENDED_CONTROL, &enableByte, 1); 495 | } 496 | 497 | // Issue a DataClass() command to set the data class to be accessed 498 | bool BQ27441::blockDataClass(uint8_t id) 499 | { 500 | return i2cWriteBytes(BQ27441_EXTENDED_DATACLASS, &id, 1); 501 | } 502 | 503 | // Issue a DataBlock() command to set the data block to be accessed 504 | bool BQ27441::blockDataOffset(uint8_t offset) 505 | { 506 | return i2cWriteBytes(BQ27441_EXTENDED_DATABLOCK, &offset, 1); 507 | } 508 | 509 | // Read the current checksum using BlockDataCheckSum() 510 | uint8_t BQ27441::blockDataChecksum(void) 511 | { 512 | uint8_t csum; 513 | i2cReadBytes(BQ27441_EXTENDED_CHECKSUM, &csum, 1); 514 | return csum; 515 | } 516 | 517 | // Use BlockData() to read a byte from the loaded extended data 518 | uint8_t BQ27441::readBlockData(uint8_t offset) 519 | { 520 | uint8_t ret; 521 | uint8_t address = offset + BQ27441_EXTENDED_BLOCKDATA; 522 | i2cReadBytes(address, &ret, 1); 523 | return ret; 524 | } 525 | 526 | // Use BlockData() to write a byte to an offset of the loaded data 527 | bool BQ27441::writeBlockData(uint8_t offset, uint8_t data) 528 | { 529 | uint8_t address = offset + BQ27441_EXTENDED_BLOCKDATA; 530 | return i2cWriteBytes(address, &data, 1); 531 | } 532 | 533 | // Read all 32 bytes of the loaded extended data and compute a 534 | // checksum based on the values. 535 | uint8_t BQ27441::computeBlockChecksum(void) 536 | { 537 | uint8_t data[32]; 538 | i2cReadBytes(BQ27441_EXTENDED_BLOCKDATA, data, 32); 539 | 540 | uint8_t csum = 0; 541 | for (int i=0; i<32; i++) 542 | { 543 | csum += data[i]; 544 | } 545 | csum = 255 - csum; 546 | 547 | return csum; 548 | } 549 | 550 | // Use the BlockDataCheckSum() command to write a checksum value 551 | bool BQ27441::writeBlockChecksum(uint8_t csum) 552 | { 553 | return i2cWriteBytes(BQ27441_EXTENDED_CHECKSUM, &csum, 1); 554 | } 555 | 556 | // Read a byte from extended data specifying a class ID and position offset 557 | uint8_t BQ27441::readExtendedData(uint8_t classID, uint8_t offset) 558 | { 559 | uint8_t retData = 0; 560 | if (!_userConfigControl) enterConfig(false); 561 | 562 | if (!blockDataControl()) // // enable block data memory control 563 | return false; // Return false if enable fails 564 | if (!blockDataClass(classID)) // Write class ID using DataBlockClass() 565 | return false; 566 | 567 | blockDataOffset(offset / 32); // Write 32-bit block offset (usually 0) 568 | 569 | computeBlockChecksum(); // Compute checksum going in 570 | uint8_t oldCsum = blockDataChecksum(); 571 | /*for (int i=0; i<32; i++) 572 | Serial.print(String(readBlockData(i)) + " ");*/ 573 | retData = readBlockData(offset % 32); // Read from offset (limit to 0-31) 574 | 575 | if (!_userConfigControl) exitConfig(); 576 | 577 | return retData; 578 | } 579 | 580 | // Write a specified number of bytes to extended data specifying a 581 | // class ID, position offset. 582 | bool BQ27441::writeExtendedData(uint8_t classID, uint8_t offset, uint8_t * data, uint8_t len) 583 | { 584 | if (len > 32) 585 | return false; 586 | 587 | if (!_userConfigControl) enterConfig(false); 588 | 589 | if (!blockDataControl()) // // enable block data memory control 590 | return false; // Return false if enable fails 591 | if (!blockDataClass(classID)) // Write class ID using DataBlockClass() 592 | return false; 593 | 594 | blockDataOffset(offset / 32); // Write 32-bit block offset (usually 0) 595 | computeBlockChecksum(); // Compute checksum going in 596 | uint8_t oldCsum = blockDataChecksum(); 597 | 598 | // Write data bytes: 599 | for (int i = 0; i < len; i++) 600 | { 601 | // Write to offset, mod 32 if offset is greater than 32 602 | // The blockDataOffset above sets the 32-bit block 603 | writeBlockData((offset % 32) + i, data[i]); 604 | } 605 | 606 | // Write new checksum using BlockDataChecksum (0x60) 607 | uint8_t newCsum = computeBlockChecksum(); // Compute the new checksum 608 | writeBlockChecksum(newCsum); 609 | 610 | if (!_userConfigControl) exitConfig(); 611 | 612 | return true; 613 | } 614 | 615 | /***************************************************************************** 616 | ************************ I2C Read and Write Routines ************************ 617 | *****************************************************************************/ 618 | 619 | // Read a specified number of bytes over I2C at a given subAddress 620 | int16_t BQ27441::i2cReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count) 621 | { 622 | int16_t timeout = BQ72441_I2C_TIMEOUT; 623 | Wire.beginTransmission(_deviceAddress); 624 | Wire.write(subAddress); 625 | Wire.endTransmission(true); 626 | 627 | Wire.requestFrom(_deviceAddress, count); 628 | while ((Wire.available() < count) && timeout--) 629 | delay(1); 630 | if (timeout) 631 | { 632 | for (int i=0; i