SensorLib 0.5.0
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 "../../SensorBuildOpt.h"
33#if !SENSORLIB_EXCLUDE_GAUGE_AXP2602
34
36#include "../GaugeBase.hpp"
37
38// AXP2602 Unique device address
39static constexpr uint8_t AXP2602_SLAVE_ADDRESS = (0x62);
40
42{
43public:
50
58
66 // It has relatively high power consumption, but can be used for both charging and discharging.
68 // In default mode, it can be used for both charging and discharging.
70 // With relatively low power consumption, it can only be used in low-power scenarios during discharge.
71 // In other scenarios, software switching to normal mode or high-precision mode is required.
73 };
74
75 struct GaugeData {
76
77 uint8_t chipID; // Chip ID
78 // Voltage, current, and temperature measurements
79 uint16_t voltage; // mV
80 int16_t currentRaw; // mA (Signed, two's complement representation)
81 int8_t temperature; // °C
82 uint16_t tdieTemperatureRaw; // Thermosensitive Temperature ADC Raw Value
83
84 // Battery status information
85 uint8_t soc; // Battery percentage (0-100)
86 uint8_t soh; // Battery health status (0-100)
87 uint16_t timeToEmpty; // Time remaining (minutes)
88 uint16_t timeToFull; // Full time (minutes)
89
90 // IRQ status
92
93 // Operating mode
95
96 // Configuration status
102
103 float current; // Actual current calculated from the sampling resistor(mA)
104 float actualDieTemperature; // die temperature calculated according to the formula(℃)
105 float power; // Instantaneous power (W), positive indicates discharging, negative indicates charging.
106
108 chipID(0),
109 voltage(0),
110 currentRaw(0),
111 temperature(0),
113 soc(0),
114 soh(0),
115 timeToEmpty(0),
116 timeToFull(0),
119 thermalDieEnabled(true),
122 sleepModeEnabled(false),
124 current(0.0f),
126 power(0.0f)
127 {}
128 };
129
130 GaugeAXP2602() = default;
131
132 ~GaugeAXP2602() = default;
133
134#if defined(ARDUINO)
143 bool begin(TwoWire &wire, int sda = -1, int scl = -1)
144 {
145 return I2CDeviceWithHal::begin(wire, AXP2602_SLAVE_ADDRESS, sda, scl);
146 }
147
148#elif defined(ESP_PLATFORM)
149
150#if defined(SENSORLIB_USE_I2C_LEGACY)
159 bool begin(i2c_port_t port_num, int sda = -1, int scl = -1)
160 {
161 return I2CDeviceWithHal::begin(port_num, AXP2602_SLAVE_ADDRESS, sda, scl);
162 }
163#else
170 bool begin(i2c_master_bus_handle_t handle)
171 {
172 return I2CDeviceWithHal::begin(handle, AXP2602_SLAVE_ADDRESS);
173 }
174#endif //ESP_PLATFORM
175#endif //ARDUINO
176
186 {
187 return I2CDeviceWithHal::begin(callback, hal_callback, AXP2602_SLAVE_ADDRESS);
188 }
189
195 bool refresh() override
196 {
197 if (!comm) return false;
198
199 if (data.chipID != AXP2602_CHIP_ID) {
200 SENSORLIB_LOG_E("Chip id not match : %" PRIu32, data.chipID);
201 return false;
202 }
203
205 // Chip is in sleep mode, no need to read other registers
206 return true;
207 }
208
209 // Read voltage (14-bit ADC, 0-4500mV)
210 int vbatHigh = readReg(REG_VBAT_ADC_HIGH);
211 int vbatLow = readReg(REG_VBAT_ADC_LOW);
212 if (vbatHigh >= 0 && vbatLow >= 0) {
213 data.voltage = ((vbatHigh & 0x3F) << 8) | vbatLow; // High 6 bits + Low 8 bits
214 }
215
216 // Read current (16-bit ADC, two's complement)
217 int ibatHigh = readReg(REG_IBAT_ADC_HIGH);
218 int ibatLow = readReg(REG_IBAT_ADC_LOW);
219 if (ibatHigh >= 0 && ibatLow >= 0) {
220 uint16_t raw = (ibatHigh << 8) | ibatLow;
221 data.currentRaw = static_cast<int16_t>(raw); // Convert to signed 16-bit
222
223 // Calculate actual current value (mA) based on sense resistor
224 float resolution = getCurrentResolution(data.senseResistor);
225 data.current = data.currentRaw * resolution;
226 }
227
228 // Read temperature
229 int temp = readReg(REG_TEMP_RESULT);
230 if (temp >= 0) {
231 // 1 LSB = 1°C, range -128°C to +127°C
232 data.temperature = static_cast<int8_t>(temp);
233 }
234
235 // Read die temperature (13-bit ADC)
236 int tdieHigh = readReg(REG_TDIE_ADC_HIGH);
237 int tdieLow = readReg(REG_TDIE_ADC_LOW);
238 if (tdieHigh >= 0 && tdieLow >= 0) {
239 data.tdieTemperatureRaw = ((tdieHigh & 0x1F) << 8) | tdieLow; // High 5 bits + Low 8 bits
240 // Formula on page 10 of the manual: Temperature (°C) = (3415 - xDie) * 10 / 95 + 26
241 data.actualDieTemperature = (3415.0 - data.tdieTemperatureRaw) * 10.0 / 95.0 + 26.0;
243 SENSORLIB_LOG_E("Die temperature out of range: %d", data.actualDieTemperature);
244 data.actualDieTemperature = 0; // Reset to 0 if out of range
245 }
246 }
247
248 // Read battery status
251
252 // Read time to empty estimation
253 int timeEmptyHigh = readReg(REG_TIME_TO_EMPTY_HIGH);
254 int timeEmptyLow = readReg(REG_TIME_TO_EMPTY_LOW);
255 if (timeEmptyHigh >= 0 && timeEmptyLow >= 0) {
256 data.timeToEmpty = (timeEmptyHigh << 8) | timeEmptyLow;
257 }
258
259 int timeFullHigh = readReg(REG_TIME_TO_FULL_HIGH);
260 int timeFullLow = readReg(REG_TIME_TO_FULL_LOW);
261 if (timeFullHigh >= 0 && timeFullLow >= 0) {
262 data.timeToFull = (timeFullHigh << 8) | timeFullLow;
263 }
264
265 // Read IRQ status
266 int irqStatus = readReg(REG_IRQ_STATUS);
267 if (irqStatus >= 0) {
268 data.irqStatus = static_cast<IRQStatus>(irqStatus & 0x0F);
269 }
270
271 // Read configuration
272 int config = readReg(REG_COMM_CONFIG);
273 if (config >= 0) {
274 data.thermalDieEnabled = (config & sensorlib::_bv(6)) != 0;
275 data.currentMeasurementEnabled = (config & sensorlib::_bv(5)) != 0;
276 data.batteryDetectionEnabled = (config & sensorlib::_bv(4)) != 0;
277 data.senseResistor = static_cast<CurrentSenseResistor>(config & 0x03);
278 }
279
280 // Calculate instantaneous power (W): P = V * I
281 data.power = (data.voltage * data.current) / 1000000.0f;
282
283 return true;
284 }
285
292 {
293 switch (resistor) {
295 return 0.5f; // 500uA/LSB = 0.5mA/LSB
297 return 0.25f; // 250uA/LSB = 0.25mA/LSB
299 return 0.125f; // 125uA/LSB = 0.125mA/LSB
301 return 0.0625f; // 62.5uA/LSB = 0.0625mA/LSB
302 default:
303 return 0.25f; // Default 10mΩ
304 }
305 }
306
312 uint16_t getChipID() override
313 {
314 return readReg(REG_AXP2602_ID);
315 }
316
321 float getTemperature() override
322 {
323 return data.temperature;
324 }
325
331 {
332 return data.soh;
333 }
334
339 uint16_t getStateOfCharge() override
340 {
341 return data.soc;
342 }
343
348 uint16_t getTimeToEmpty() override
349 {
350 return data.timeToEmpty;
351 }
352
357 uint16_t getTimeToFull() override
358 {
359 return data.timeToFull;
360 }
361
367 {
368 int lowSoc = readReg(REG_LOW_SOC_THLD);
369 if (lowSoc >= 0) {
370 return lowSoc & 0x3F; // Low 6 bits valid
371 }
372 return 0;
373 }
374
380 {
381 int otThld = readReg(REG_OT_THLD);
382 if (otThld >= 0) {
383 return otThld & 0x7F; // Low 7 bits valid
384 }
385 return 0;
386 }
387
393 {
395 }
396
402 {
404 }
405
410 uint16_t getVoltage() override
411 {
412 return data.voltage;
413 }
414
415
420 bool isCharging() override
421 {
422 return data.current > 0;
423 }
424
429 bool isDischarging() override
430 {
431 return data.current < 0;
432 }
433
439 {
440 return (data.current > 0) ? data.power : 0.0f;
441 }
442
448 {
449 return (data.current < 0) ? -data.power : 0.0f;
450 }
451
457 {
458 return fabs(data.power);
459 }
460
465 float getCurrent() override
466 {
467 return data.current;
468 }
469
475 {
476 return data.currentRaw;
477 }
478
482 void reset() override
483 {
485 hal->delay(50);
487 hal->delay(100);
488 }
489
493 void sleep()
494 {
495 if (setRegBit(REG_MODE, 0)) {
496 data.sleepModeEnabled = true;
497 }
498 }
499
505 {
506 return getRegBit(REG_MODE, 0);
507 }
508
512 void wakeup()
513 {
514 if (clrRegBit(REG_MODE, 0)) {
515 data.sleepModeEnabled = false;
516 }
517 }
518
523 void setLowBatterySOCThreshold(uint8_t threshold)
524 {
525 if (threshold > 63) {
526 threshold = 63;
527 }
528 // Read low SOC threshold
529 int lowSoc = readReg(REG_LOW_SOC_THLD);
530 if (lowSoc >= 0) {
531 lowSoc &= 0xC0;
532 lowSoc |= (threshold & 0x3F); // Low 6 bits valid
533 writeReg(REG_LOW_SOC_THLD, lowSoc);
534 }
535 }
536
541 void setOverTemperatureThreshold(uint8_t threshold)
542 {
543 if (threshold > 127) {
544 threshold = 127;
545 }
546 writeReg(REG_OT_THLD, threshold & 0x7F);
547 }
548
553 void setThermalDieMeasurement(bool enable)
554 {
555 if (enable) {
557 } else {
559 }
560 data.thermalDieEnabled = enable;
561 }
562
571
576 void setCurrentMeasurement(bool enable)
577 {
578 if (enable) {
580 } else {
582 }
584 }
585
594
599 void setBatteryDetection(bool enable)
600 {
601 if (enable) {
603 } else {
605 }
607 }
608
617
623 {
624 int val = readReg(REG_COMM_CONFIG);
625 if (val < 0) return;
626
627 val = (val & ~0x03) | (resistorValue & 0x03);
629 data.senseResistor = resistorValue;
630 }
631
640
641
647 {
648 return data.irqStatus;
649 }
650
656 {
657 enableIRQ(irq, true);
658 }
659
665 {
666 enableIRQ(irq, false);
667 }
668
674 {
676 }
677
684 void enableIRQ(IRQEnable irq, bool enable, bool low_level_trigger = true)
685 {
686 int val = readReg(REG_IRQ_ENABLE);
687 if (val < 0) {
688 return;
689 }
690 // Set trigger mode: bit7=0 for low level, bit7=1 for low pulse.
691 if (low_level_trigger) {
692 val &= ~0x80; // Low level trigger
693 } else {
694 val |= 0x80; // Low pulse trigger
695 }
696 // Set IRQ enable bit
697 if (enable) {
698 val |= irq;
699 } else {
700 val &= ~irq;
701 }
703 }
704
709 {
711 hal->delay(2);
714 }
715
721 {
722 switch (mode) {
726 break;
727 default:
728 return;
729 }
731 data.operatingMode = mode;
732 }
733
739 {
740 // Read operating mode
741 int opMode = readReg(REG_OPERATING_MODE);
742 if (opMode >= 0) {
743 data.operatingMode = static_cast<OperatingMode>(opMode & 0x07);
744 }
745 return data.operatingMode;
746 }
747
755 bool writeGaugeData(uint8_t *data, uint8_t len)
756 {
757 if (len != 128 || data == NULL)return false;
758 // Reset gauge first
759 writeReg(REG_MODE, 0x01);
760 hal->delay(50);
761 writeReg(REG_MODE, 0x00);
762 hal->delay(50);
763
764 // Enabled BROM register
767 // Write data to buffer
768 for (uint8_t i = 0; i < 128; i++) {
770 }
771
772 // Reenable ROM register
775
776 return compareGaugeData(data, len);
777 }
778
786 bool compareGaugeData(uint8_t *data, uint8_t len)
787 {
788 if (len != 128 || data == NULL)return false;
789 // Reset gauge to load new data
790 uint8_t buffer[128];
791 memset(buffer, 0, sizeof(buffer));
792 // Reenable BROM register
795 for (uint8_t i = 0; i < 128; i++) {
796 buffer[i] = readReg(REG_BROM);
797 }
798 // Disable BROM register
800 // Set data interface
802 // Reset gauge
805
806 return memcmp(data, buffer, 128) == 0;
807 }
808
810 {
812 }
813
815 {
817 }
818
819private:
820 bool initImpl(uint8_t param) override
821 {
823 if (data.chipID != AXP2602_CHIP_ID) {
824 SENSORLIB_LOG_E("Chip id not match : %02X\n", data.chipID);
825 return false;
826 }
827 reset(); // Reset Configuration
828 hal->delay(100);
829 wakeup(); // Wake Up Chip
833 return true;
834 }
835
836protected:
838
839 static constexpr uint8_t REG_AXP2602_ID = 0x00;
840 static constexpr uint8_t REG_BROM = 0x01;
841 static constexpr uint8_t REG_MODE = 0x02;
842 static constexpr uint8_t REG_PARA_CONFIG = 0x03;
843 static constexpr uint8_t REG_VBAT_ADC_HIGH = 0x04;
844 static constexpr uint8_t REG_VBAT_ADC_LOW = 0x05;
845 static constexpr uint8_t REG_TEMP_RESULT = 0x06;
846 static constexpr uint8_t REG_SOH = 0x07;
847 static constexpr uint8_t REG_SOC = 0x08;
848
849 static constexpr uint8_t REG_TIME_TO_EMPTY_HIGH = 0x0A;
850 static constexpr uint8_t REG_TIME_TO_EMPTY_LOW = 0x0B;
851 static constexpr uint8_t REG_TIME_TO_FULL_HIGH = 0x0C;
852 static constexpr uint8_t REG_TIME_TO_FULL_LOW = 0x0D;
853 static constexpr uint8_t REG_LOW_SOC_THLD = 0x0E;
854 static constexpr uint8_t REG_OT_THLD = 0x0F;
855
856 static constexpr uint8_t REG_COMM_CONFIG = 0x11;
857 static constexpr uint8_t REG_IBAT_ADC_HIGH = 0x14;
858 static constexpr uint8_t REG_IBAT_ADC_LOW = 0x15;
859 static constexpr uint8_t REG_RDC25_CONFIG_HIGH = 0x1A;
860 static constexpr uint8_t REG_RDC25_CONFIG_LOW = 0x1B;
861 static constexpr uint8_t REG_QMAX_CONFIG_HIGH = 0x1E;
862 static constexpr uint8_t REG_QMAX_CONFIG_LOW = 0x1F;
863
864 static constexpr uint8_t REG_IRQ_STATUS = 0x20;
865 static constexpr uint8_t REG_IRQ_ENABLE = 0x21;
866 static constexpr uint8_t REG_TDIE_ADC_HIGH = 0xC2;
867 static constexpr uint8_t REG_TDIE_ADC_LOW = 0xC3;
868 static constexpr uint8_t REG_RDC25_QMAX_SEL = 0xC5;
869 static constexpr uint8_t REG_OPERATING_MODE = 0xC6;
870
871 static constexpr uint8_t AXP2602_CHIP_ID = 0x1C;
872};
873
874#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