SensorLib 0.5.1
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
gauge/xpowers/GaugeAXP2602.hpp
Go to the documentation of this file.
1
30#pragma once
31
32#include <math.h>
33
34#include "../../SensorBuildOpt.h"
35#if !SENSORLIB_EXCLUDE_GAUGE_AXP2602
36
38#include "../GaugeBase.hpp"
39
40// AXP2602 Unique device address
41static constexpr uint8_t AXP2602_SLAVE_ADDRESS = (0x62);
42
44{
45public:
52
60
68 // It has relatively high power consumption, but can be used for both charging and discharging.
70 // In default mode, it can be used for both charging and discharging.
72 // With relatively low power consumption, it can only be used in low-power scenarios during discharge.
73 // In other scenarios, software switching to normal mode or high-precision mode is required.
75 };
76
77 struct GaugeData {
78
79 uint8_t chipID; // Chip ID
80 // Voltage, current, and temperature measurements
81 uint16_t voltage; // mV
82 int16_t currentRaw; // mA (Signed, two's complement representation)
83 int8_t temperature; // °C
84 uint16_t tdieTemperatureRaw; // Thermosensitive Temperature ADC Raw Value
85
86 // Battery status information
87 uint8_t soc; // Battery percentage (0-100)
88 uint8_t soh; // Battery health status (0-100)
89 uint16_t timeToEmpty; // Time remaining (minutes)
90 uint16_t timeToFull; // Full time (minutes)
91
92 // IRQ status
94
95 // Operating mode
97
98 // Configuration status
104
105 float current; // Actual current calculated from the sampling resistor(mA)
106 float actualDieTemperature; // die temperature calculated according to the formula(℃)
107 float power; // Instantaneous power (W), positive indicates discharging, negative indicates charging.
108
110 chipID(0),
111 voltage(0),
112 currentRaw(0),
113 temperature(0),
115 soc(0),
116 soh(0),
117 timeToEmpty(0),
118 timeToFull(0),
121 thermalDieEnabled(true),
124 sleepModeEnabled(false),
126 current(0.0f),
128 power(0.0f)
129 {}
130 };
131
132 GaugeAXP2602() = default;
133
134 ~GaugeAXP2602() = default;
135
136#if defined(ARDUINO)
145 bool begin(TwoWire &wire, int sda = -1, int scl = -1)
146 {
147 return I2CDeviceWithHal::begin(wire, AXP2602_SLAVE_ADDRESS, sda, scl);
148 }
149
150#elif defined(ESP_PLATFORM)
151
152#if defined(SENSORLIB_USE_I2C_LEGACY)
161 bool begin(i2c_port_t port_num, int sda = -1, int scl = -1)
162 {
163 return I2CDeviceWithHal::begin(port_num, AXP2602_SLAVE_ADDRESS, sda, scl);
164 }
165#else
172 bool begin(i2c_master_bus_handle_t handle)
173 {
174 return I2CDeviceWithHal::begin(handle, AXP2602_SLAVE_ADDRESS);
175 }
176#endif //ESP_PLATFORM
177#endif //ARDUINO
178
188 {
189 return I2CDeviceWithHal::begin(callback, hal_callback, AXP2602_SLAVE_ADDRESS);
190 }
191
197 bool refresh() override
198 {
199 if (!comm) return false;
200
201 if (data.chipID != AXP2602_CHIP_ID) {
202 SENSORLIB_LOG_E("Chip id not match : %" PRIu32, data.chipID);
203 return false;
204 }
205
207 // Chip is in sleep mode, no need to read other registers
208 return true;
209 }
210
211 // Read voltage (14-bit ADC, 0-4500mV)
212 int vbatHigh = readReg(REG_VBAT_ADC_HIGH);
213 int vbatLow = readReg(REG_VBAT_ADC_LOW);
214 if (vbatHigh >= 0 && vbatLow >= 0) {
215 data.voltage = ((vbatHigh & 0x3F) << 8) | vbatLow; // High 6 bits + Low 8 bits
216 }
217
218 // Read current (16-bit ADC, two's complement)
219 int ibatHigh = readReg(REG_IBAT_ADC_HIGH);
220 int ibatLow = readReg(REG_IBAT_ADC_LOW);
221 if (ibatHigh >= 0 && ibatLow >= 0) {
222 uint16_t raw = (ibatHigh << 8) | ibatLow;
223 data.currentRaw = static_cast<int16_t>(raw); // Convert to signed 16-bit
224
225 // Calculate actual current value (mA) based on sense resistor
226 float resolution = getCurrentResolution(data.senseResistor);
227 data.current = data.currentRaw * resolution;
228 }
229
230 // Read temperature
231 int temp = readReg(REG_TEMP_RESULT);
232 if (temp >= 0) {
233 // 1 LSB = 1°C, range -128°C to +127°C
234 data.temperature = static_cast<int8_t>(temp);
235 }
236
237 // Read die temperature (13-bit ADC)
238 int tdieHigh = readReg(REG_TDIE_ADC_HIGH);
239 int tdieLow = readReg(REG_TDIE_ADC_LOW);
240 if (tdieHigh >= 0 && tdieLow >= 0) {
241 data.tdieTemperatureRaw = ((tdieHigh & 0x1F) << 8) | tdieLow; // High 5 bits + Low 8 bits
242 // Formula on page 10 of the manual: Temperature (°C) = (3415 - xDie) * 10 / 95 + 26
243 data.actualDieTemperature = (3415.0 - data.tdieTemperatureRaw) * 10.0 / 95.0 + 26.0;
245 SENSORLIB_LOG_E("Die temperature out of range: %d", data.actualDieTemperature);
246 data.actualDieTemperature = 0; // Reset to 0 if out of range
247 }
248 }
249
250 // Read battery status
253
254 // Read time to empty estimation
255 int timeEmptyHigh = readReg(REG_TIME_TO_EMPTY_HIGH);
256 int timeEmptyLow = readReg(REG_TIME_TO_EMPTY_LOW);
257 if (timeEmptyHigh >= 0 && timeEmptyLow >= 0) {
258 data.timeToEmpty = (timeEmptyHigh << 8) | timeEmptyLow;
259 }
260
261 int timeFullHigh = readReg(REG_TIME_TO_FULL_HIGH);
262 int timeFullLow = readReg(REG_TIME_TO_FULL_LOW);
263 if (timeFullHigh >= 0 && timeFullLow >= 0) {
264 data.timeToFull = (timeFullHigh << 8) | timeFullLow;
265 }
266
267 // Read IRQ status
268 int irqStatus = readReg(REG_IRQ_STATUS);
269 if (irqStatus >= 0) {
270 data.irqStatus = static_cast<IRQStatus>(irqStatus & 0x0F);
271 }
272
273 // Read configuration
274 int config = readReg(REG_COMM_CONFIG);
275 if (config >= 0) {
276 data.thermalDieEnabled = (config & sensorlib::_bv(6)) != 0;
277 data.currentMeasurementEnabled = (config & sensorlib::_bv(5)) != 0;
278 data.batteryDetectionEnabled = (config & sensorlib::_bv(4)) != 0;
279 data.senseResistor = static_cast<CurrentSenseResistor>(config & 0x03);
280 }
281
282 // Calculate instantaneous power (W): P = V * I
283 data.power = (data.voltage * data.current) / 1000000.0f;
284
285 return true;
286 }
287
294 {
295 switch (resistor) {
297 return 0.5f; // 500uA/LSB = 0.5mA/LSB
299 return 0.25f; // 250uA/LSB = 0.25mA/LSB
301 return 0.125f; // 125uA/LSB = 0.125mA/LSB
303 return 0.0625f; // 62.5uA/LSB = 0.0625mA/LSB
304 default:
305 return 0.25f; // Default 10mΩ
306 }
307 }
308
314 uint16_t getChipID() override
315 {
316 return readReg(REG_AXP2602_ID);
317 }
318
323 float getTemperature() override
324 {
325 return data.temperature;
326 }
327
333 {
334 return data.soh;
335 }
336
341 uint16_t getStateOfCharge() override
342 {
343 return data.soc;
344 }
345
350 uint16_t getTimeToEmpty() override
351 {
352 return data.timeToEmpty;
353 }
354
359 uint16_t getTimeToFull() override
360 {
361 return data.timeToFull;
362 }
363
369 {
370 int lowSoc = readReg(REG_LOW_SOC_THLD);
371 if (lowSoc >= 0) {
372 return lowSoc & 0x3F; // Low 6 bits valid
373 }
374 return 0;
375 }
376
382 {
383 int otThld = readReg(REG_OT_THLD);
384 if (otThld >= 0) {
385 return otThld & 0x7F; // Low 7 bits valid
386 }
387 return 0;
388 }
389
395 {
397 }
398
404 {
406 }
407
412 uint16_t getVoltage() override
413 {
414 return data.voltage;
415 }
416
417
422 bool isCharging() override
423 {
424 return data.current > 0;
425 }
426
431 bool isDischarging() override
432 {
433 return data.current < 0;
434 }
435
441 {
442 return (data.current > 0) ? data.power : 0.0f;
443 }
444
450 {
451 return (data.current < 0) ? -data.power : 0.0f;
452 }
453
459 {
460 return fabsf(data.power);
461 }
462
467 float getCurrent() override
468 {
469 return data.current;
470 }
471
477 {
478 return data.currentRaw;
479 }
480
484 void reset() override
485 {
487 hal->delay(50);
489 hal->delay(100);
490 }
491
495 void sleep()
496 {
497 if (setRegBit(REG_MODE, 0)) {
498 data.sleepModeEnabled = true;
499 }
500 }
501
507 {
508 return getRegBit(REG_MODE, 0);
509 }
510
514 void wakeup()
515 {
516 if (clrRegBit(REG_MODE, 0)) {
517 data.sleepModeEnabled = false;
518 }
519 }
520
525 void setLowBatterySOCThreshold(uint8_t threshold)
526 {
527 if (threshold > 63) {
528 threshold = 63;
529 }
530 // Read low SOC threshold
531 int lowSoc = readReg(REG_LOW_SOC_THLD);
532 if (lowSoc >= 0) {
533 lowSoc &= 0xC0;
534 lowSoc |= (threshold & 0x3F); // Low 6 bits valid
535 writeReg(REG_LOW_SOC_THLD, lowSoc);
536 }
537 }
538
543 void setOverTemperatureThreshold(uint8_t threshold)
544 {
545 if (threshold > 127) {
546 threshold = 127;
547 }
548 writeReg(REG_OT_THLD, threshold & 0x7F);
549 }
550
555 void setThermalDieMeasurement(bool enable)
556 {
557 if (enable) {
559 } else {
561 }
562 data.thermalDieEnabled = enable;
563 }
564
573
578 void setCurrentMeasurement(bool enable)
579 {
580 if (enable) {
582 } else {
584 }
586 }
587
596
601 void setBatteryDetection(bool enable)
602 {
603 if (enable) {
605 } else {
607 }
609 }
610
619
625 {
626 int val = readReg(REG_COMM_CONFIG);
627 if (val < 0) return;
628
629 val = (val & ~0x03) | (resistorValue & 0x03);
631 data.senseResistor = resistorValue;
632 }
633
642
643
649 {
650 return data.irqStatus;
651 }
652
658 {
659 enableIRQ(irq, true);
660 }
661
667 {
668 enableIRQ(irq, false);
669 }
670
676 {
678 }
679
686 void enableIRQ(IRQEnable irq, bool enable, bool low_level_trigger = true)
687 {
688 int val = readReg(REG_IRQ_ENABLE);
689 if (val < 0) {
690 return;
691 }
692 // Set trigger mode: bit7=0 for low level, bit7=1 for low pulse.
693 if (low_level_trigger) {
694 val &= ~0x80; // Low level trigger
695 } else {
696 val |= 0x80; // Low pulse trigger
697 }
698 // Set IRQ enable bit
699 if (enable) {
700 val |= irq;
701 } else {
702 val &= ~irq;
703 }
705 }
706
711 {
713 hal->delay(2);
716 }
717
723 {
724 switch (mode) {
728 break;
729 default:
730 return;
731 }
733 data.operatingMode = mode;
734 }
735
741 {
742 // Read operating mode
743 int opMode = readReg(REG_OPERATING_MODE);
744 if (opMode >= 0) {
745 data.operatingMode = static_cast<OperatingMode>(opMode & 0x07);
746 }
747 return data.operatingMode;
748 }
749
757 bool writeGaugeData(uint8_t *data, uint8_t len)
758 {
759 if (len != 128 || data == NULL)return false;
760 // Reset gauge first
761 writeReg(REG_MODE, 0x01);
762 hal->delay(50);
763 writeReg(REG_MODE, 0x00);
764 hal->delay(50);
765
766 // Enabled BROM register
769 // Write data to buffer
770 for (uint8_t i = 0; i < 128; i++) {
772 }
773
774 // Reenable ROM register
777
778 return compareGaugeData(data, len);
779 }
780
788 bool compareGaugeData(uint8_t *data, uint8_t len)
789 {
790 if (len != 128 || data == NULL)return false;
791 // Reset gauge to load new data
792 uint8_t buffer[128];
793 memset(buffer, 0, sizeof(buffer));
794 // Reenable BROM register
797 for (uint8_t i = 0; i < 128; i++) {
798 buffer[i] = readReg(REG_BROM);
799 }
800 // Disable BROM register
802 // Set data interface
804 // Reset gauge
807
808 return memcmp(data, buffer, 128) == 0;
809 }
810
812 {
814 }
815
817 {
819 }
820
821private:
822 bool initImpl(uint8_t param) override
823 {
825 if (data.chipID != AXP2602_CHIP_ID) {
826 SENSORLIB_LOG_E("Chip id not match : %02X\n", data.chipID);
827 return false;
828 }
829 reset(); // Reset Configuration
830 hal->delay(100);
831 wakeup(); // Wake Up Chip
835 return true;
836 }
837
838protected:
840
841 static constexpr uint8_t REG_AXP2602_ID = 0x00;
842 static constexpr uint8_t REG_BROM = 0x01;
843 static constexpr uint8_t REG_MODE = 0x02;
844 static constexpr uint8_t REG_PARA_CONFIG = 0x03;
845 static constexpr uint8_t REG_VBAT_ADC_HIGH = 0x04;
846 static constexpr uint8_t REG_VBAT_ADC_LOW = 0x05;
847 static constexpr uint8_t REG_TEMP_RESULT = 0x06;
848 static constexpr uint8_t REG_SOH = 0x07;
849 static constexpr uint8_t REG_SOC = 0x08;
850
851 static constexpr uint8_t REG_TIME_TO_EMPTY_HIGH = 0x0A;
852 static constexpr uint8_t REG_TIME_TO_EMPTY_LOW = 0x0B;
853 static constexpr uint8_t REG_TIME_TO_FULL_HIGH = 0x0C;
854 static constexpr uint8_t REG_TIME_TO_FULL_LOW = 0x0D;
855 static constexpr uint8_t REG_LOW_SOC_THLD = 0x0E;
856 static constexpr uint8_t REG_OT_THLD = 0x0F;
857
858 static constexpr uint8_t REG_COMM_CONFIG = 0x11;
859 static constexpr uint8_t REG_IBAT_ADC_HIGH = 0x14;
860 static constexpr uint8_t REG_IBAT_ADC_LOW = 0x15;
861 static constexpr uint8_t REG_RDC25_CONFIG_HIGH = 0x1A;
862 static constexpr uint8_t REG_RDC25_CONFIG_LOW = 0x1B;
863 static constexpr uint8_t REG_QMAX_CONFIG_HIGH = 0x1E;
864 static constexpr uint8_t REG_QMAX_CONFIG_LOW = 0x1F;
865
866 static constexpr uint8_t REG_IRQ_STATUS = 0x20;
867 static constexpr uint8_t REG_IRQ_ENABLE = 0x21;
868 static constexpr uint8_t REG_TDIE_ADC_HIGH = 0xC2;
869 static constexpr uint8_t REG_TDIE_ADC_LOW = 0xC3;
870 static constexpr uint8_t REG_RDC25_QMAX_SEL = 0xC5;
871 static constexpr uint8_t REG_OPERATING_MODE = 0xC6;
872
873 static constexpr uint8_t AXP2602_CHIP_ID = 0x1C;
874};
875
876#endif
@license MIT License
#define SENSORLIB_LOG_E(...)
std::unique_ptr< SensorCommBase > comm
std::unique_ptr< SensorHal > hal
bool writeGaugeData(uint8_t *data, uint8_t len)
Write Gauge Data.
static constexpr uint8_t REG_IRQ_STATUS
float getCurrentResolution(CurrentSenseResistor resistor)
Obtain current resolution based on the sampling resistor.
uint16_t getStateOfCharge() override
Get the battery percentage.
static constexpr uint8_t REG_PARA_CONFIG
static constexpr uint8_t REG_TDIE_ADC_LOW
static constexpr uint8_t REG_TEMP_RESULT
static constexpr uint8_t REG_TIME_TO_EMPTY_LOW
static constexpr uint8_t REG_OPERATING_MODE
void sleep()
Put the AXP2602 chip into sleep mode.
void reset() override
Reset Gauge AXP2602.
bool begin(SensorCommCustom::CustomCallback callback, SensorCommCustomHal::CustomHalCallback hal_callback)
Begin with custom callback functions.
void setThermalDieMeasurement(bool enable)
Enable or disable the thermal die measurement.
static constexpr uint8_t REG_IBAT_ADC_HIGH
uint16_t getTimeToFull() override
Get the battery time to full.
bool isSleepModeEnabled()
Check if the AXP2602 chip is in sleep mode.
static constexpr uint8_t REG_RDC25_CONFIG_LOW
static constexpr uint8_t REG_SOH
static constexpr uint8_t REG_IBAT_ADC_LOW
static constexpr uint8_t REG_TIME_TO_FULL_HIGH
uint16_t getTimeToEmpty() override
Get the battery time to empty.
static constexpr uint8_t REG_RDC25_QMAX_SEL
bool compareGaugeData(uint8_t *data, uint8_t len)
Compare Gauge Data.
static constexpr uint8_t REG_RDC25_CONFIG_HIGH
void enableIRQ(IRQEnable irq, bool enable, bool low_level_trigger=true)
Enable or disable specific IRQs.
void setOverTemperatureThreshold(uint8_t threshold)
Set the over-temperature threshold.
bool isDischarging() override
Checks if the battery is discharging.
static constexpr uint8_t REG_LOW_SOC_THLD
float getTemperature() override
Get the temperature.
void disableIRQ(IRQEnable irq)
Disable a specific IRQ.
uint16_t getVoltage() override
Get the battery voltage.
float getCurrent() override
Get the actual current value (considering the sampling resistor)
void setLowBatterySOCThreshold(uint8_t threshold)
Set the low battery SOC threshold.
~GaugeAXP2602()=default
static constexpr uint8_t REG_TDIE_ADC_HIGH
static constexpr uint8_t AXP2602_CHIP_ID
uint8_t getBatteryStatus()
Get the battery health status.
bool isCurrentMeasurementEnabled()
Check if battery current measurement is enabled.
static constexpr uint8_t REG_TIME_TO_FULL_LOW
static constexpr uint8_t REG_BROM
bool isBatteryVoltageMeasurementEnabled()
Check if battery voltage measurement is enabled.
bool isThermalDieMeasurementEnabled()
Check if thermal die measurement is enabled.
void setCurrentMeasurement(bool enable)
Enable or disable battery current detection.
OperatingMode getOperatingMode()
Get the operating mode.
void disableAllIRQ()
Disable all IRQs.
float getThermalDieTemperature()
Get the actual die temperature.
static constexpr uint8_t REG_IRQ_ENABLE
CurrentSenseResistor getCurrentSenseResistor()
Get the current sense resistor value.
uint16_t getThermalDieTemperatureRaw()
Get the thermal die temperature.
static constexpr uint8_t REG_VBAT_ADC_LOW
float getChargingPower()
Get charging power (positive or 0)
int16_t getCurrentRaw()
Get the battery current.
float getDischargingPower()
Get discharging power (positive or 0)
static constexpr uint8_t REG_QMAX_CONFIG_LOW
static constexpr uint8_t REG_MODE
bool refresh() override
Refresh the AXP2602 chip data.
static constexpr uint8_t REG_VBAT_ADC_HIGH
static constexpr uint8_t REG_COMM_CONFIG
void setOperatingMode(OperatingMode mode)
Set the operating mode.
float getAbsolutePower()
Get the absolute power (always positive)
static constexpr uint8_t REG_SOC
IRQStatus getIRQStatus()
Get the IRQ status.
static constexpr uint8_t REG_TIME_TO_EMPTY_HIGH
uint8_t getLowBatterySOCThreshold()
Get the low battery SOC threshold.
static constexpr uint8_t REG_AXP2602_ID
static constexpr uint8_t REG_QMAX_CONFIG_HIGH
uint8_t getOverTemperatureThreshold()
Get the over-temperature threshold.
void setBatteryDetection(bool enable)
Enable or disable battery voltage detection.
void clearIRQStatus()
Clear the IRQ status.
void enableIRQ(IRQEnable irq)
Enable a specific IRQ.
static constexpr uint8_t REG_OT_THLD
uint16_t getChipID() override
Get the chip ID.
GaugeAXP2602()=default
void setCurrentSenseResistor(CurrentSenseResistor resistorValue)
Set the current sense resistor value.
void wakeup()
Wake up the AXP2602 chip.
bool isCharging() override
Checks if the battery is charging.
Base class for battery gauge implementations.
Definition GaugeBase.hpp:40
bool begin(SensorCommCustom::CustomCallback cb, SensorCommCustomHal::CustomHalCallback hal_cb, uint8_t addr)
Initialize the sensor using custom callback interface.
uint32_t(*)(Operation op, void *param1, void *param2) CustomHalCallback
bool(*)(uint8_t addr, uint8_t reg, uint8_t *buf, size_t len, bool writeReg, bool isWrite) CustomCallback
bool clrRegBit(uint8_t reg, uint8_t bit)
bool getRegBit(uint8_t reg, uint8_t bit)
int readReg(uint8_t reg) const
int writeReg(uint8_t reg, uint8_t val)
bool setRegBit(uint8_t reg, uint8_t bit)
uint32_t hal_callback(SensorCommCustomHal::Operation op, void *param1, void *param2)
constexpr uint32_t _bv(uint8_t b)
Definition SensorLib.h:62
uint8_t i