diff --git a/Adafruit_BQ25628E.cpp b/Adafruit_BQ25628E.cpp index 598f6a9..8e47a85 100644 --- a/Adafruit_BQ25628E.cpp +++ b/Adafruit_BQ25628E.cpp @@ -952,4 +952,405 @@ bq25628e_therm_curr_t Adafruit_BQ25628E::getWarmThermistorCurrent() { Adafruit_BusIO_RegisterBits ts_iset_warm_bits = Adafruit_BusIO_RegisterBits(&ntc_control_reg, 2, 2); return (bq25628e_therm_curr_t)ts_iset_warm_bits.read(); +} + +/*! + * @brief Gets combined charger status flags from both status registers + * @return 16-bit status flags: bits 15:8 = REG0x1E, bits 7:0 = REG0x1D + */ +uint16_t Adafruit_BQ25628E::getChargerStatusFlags() { + // Read REG0x1D (Charger Status 0) + Adafruit_BusIO_Register status0_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_STATUS_0, 1); + uint8_t status0 = status0_reg.read(); + + // Read REG0x1E (Charger Status 1) + Adafruit_BusIO_Register status1_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_STATUS_1, 1); + uint8_t status1 = status1_reg.read(); + + // Combine into 16-bit value: high byte = status1, low byte = status0 + return ((uint16_t)status1 << 8) | status0; +} + +/*! + * @brief Gets fault status flags from REG0x1F + * @return 8-bit fault status flags from REG0x1F_FAULT_Status_0 + */ +uint8_t Adafruit_BQ25628E::getFaultStatusFlags() { + // Read REG0x1F (FAULT Status 0) + Adafruit_BusIO_Register fault_status_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_FAULT_STATUS_0, 1); + + return fault_status_reg.read(); +} + +/*! + * @brief Gets combined charger flag registers (clears flags on read) + * @return 16-bit flag values: bits 15:8 = REG0x21, bits 7:0 = REG0x20 + * @note Reading this function clears all flag bits automatically + */ +uint16_t Adafruit_BQ25628E::getChargerFlags() { + // Read REG0x20 (Charger Flag 0) - clears flags on read + Adafruit_BusIO_Register flag0_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_FLAG_0, 1); + uint8_t flag0 = flag0_reg.read(); + + // Read REG0x21 (Charger Flag 1) - clears flags on read + Adafruit_BusIO_Register flag1_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_FLAG_1, 1); + uint8_t flag1 = flag1_reg.read(); + + // Combine into 16-bit value: high byte = flag1, low byte = flag0 + return ((uint16_t)flag1 << 8) | flag0; +} + +/*! + * @brief Gets fault flag register (clears flags on read) + * @return 8-bit fault flag values from REG0x22_FAULT_Flag_0 + * @note Reading this function clears all fault flag bits automatically + */ +uint8_t Adafruit_BQ25628E::getFaultFlags() { + // Read REG0x22 (FAULT Flag 0) - clears flags on read + Adafruit_BusIO_Register fault_flag_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_FAULT_FLAG_0, 1); + + return fault_flag_reg.read(); +} + +/*! + * @brief Sets interrupt mask for all interrupt sources + * @param mask + * 32-bit mask value (1 = disable interrupt, 0 = enable interrupt) + * @return True if successful, otherwise false. + * @note Use BQ25628E_INT_MASK_* defines to construct the mask + */ +bool Adafruit_BQ25628E::setInterruptMask(uint32_t mask) { + // Extract individual register values from 32-bit mask + // Mask0 (REG0x23): bits 6:0 (ADC_DONE, TREG, VSYS, IINDPM, VINDPM, SAFETY_TMR, WD) + uint8_t mask0 = (mask >> 0) & 0x7F; + + // Mask1 (REG0x24): bits 3,0 (CHG=bit11, VBUS=bit8) + uint8_t mask1 = 0; + if (mask & BQ25628E_INT_MASK_VBUS) mask1 |= BQ25628E_MASK1_VBUS_MASK; + if (mask & BQ25628E_INT_MASK_CHG) mask1 |= BQ25628E_MASK1_CHG_MASK; + + // FMask (REG0x25): bits 7,6,5,3,0 (VBUS_FAULT, BAT_FAULT, SYS_FAULT, TSHUT, TS) + uint8_t fmask = 0; + if (mask & BQ25628E_INT_MASK_TS) fmask |= BQ25628E_FMASK_TS_MASK; + if (mask & BQ25628E_INT_MASK_TSHUT) fmask |= BQ25628E_FMASK_TSHUT_MASK; + if (mask & BQ25628E_INT_MASK_SYS_FAULT) fmask |= BQ25628E_FMASK_SYS_FAULT_MASK; + if (mask & BQ25628E_INT_MASK_BAT_FAULT) fmask |= BQ25628E_FMASK_BAT_FAULT_MASK; + if (mask & BQ25628E_INT_MASK_VBUS_FAULT) fmask |= BQ25628E_FMASK_VBUS_FAULT_MASK; + + // Write to all three mask registers + Adafruit_BusIO_Register mask0_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_MASK_0, 1); + Adafruit_BusIO_Register mask1_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_MASK_1, 1); + Adafruit_BusIO_Register fmask_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_FAULT_MASK_0, 1); + + return mask0_reg.write(mask0) && mask1_reg.write(mask1) && fmask_reg.write(fmask); +} + +/*! + * @brief Gets interrupt mask for all interrupt sources + * @return 32-bit mask value (1 = interrupt disabled, 0 = interrupt enabled) + */ +uint32_t Adafruit_BQ25628E::getInterruptMask() { + // Read all three mask registers + Adafruit_BusIO_Register mask0_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_MASK_0, 1); + Adafruit_BusIO_Register mask1_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_CHARGER_MASK_1, 1); + Adafruit_BusIO_Register fmask_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_FAULT_MASK_0, 1); + + uint8_t mask0 = mask0_reg.read(); + uint8_t mask1 = mask1_reg.read(); + uint8_t fmask = fmask_reg.read(); + + // Combine into 32-bit mask + uint32_t combined_mask = 0; + + // Mask0 (REG0x23): bits 6:0 map directly to bits 6:0 + combined_mask |= (mask0 & 0x7F); + + // Mask1 (REG0x24): bits 3,0 map to specific bit positions + if (mask1 & BQ25628E_MASK1_VBUS_MASK) combined_mask |= BQ25628E_INT_MASK_VBUS; + if (mask1 & BQ25628E_MASK1_CHG_MASK) combined_mask |= BQ25628E_INT_MASK_CHG; + + // FMask (REG0x25): bits 7,6,5,3,0 map to specific bit positions + if (fmask & BQ25628E_FMASK_TS_MASK) combined_mask |= BQ25628E_INT_MASK_TS; + if (fmask & BQ25628E_FMASK_TSHUT_MASK) combined_mask |= BQ25628E_INT_MASK_TSHUT; + if (fmask & BQ25628E_FMASK_SYS_FAULT_MASK) combined_mask |= BQ25628E_INT_MASK_SYS_FAULT; + if (fmask & BQ25628E_FMASK_BAT_FAULT_MASK) combined_mask |= BQ25628E_INT_MASK_BAT_FAULT; + if (fmask & BQ25628E_FMASK_VBUS_FAULT_MASK) combined_mask |= BQ25628E_INT_MASK_VBUS_FAULT; + + return combined_mask; +} + +/*! + * @brief Enables or disables ADC conversion + * @param enable + * True to enable ADC, false to disable + * @return True if successful, otherwise false. + */ +bool Adafruit_BQ25628E::setADCEnable(bool enable) { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_enable = Adafruit_BusIO_RegisterBits(&adc_control_reg, 1, 7); + + return adc_enable.write(enable); +} + +/*! + * @brief Gets ADC enable status + * @return True if ADC is enabled, false otherwise + */ +bool Adafruit_BQ25628E::getADCEnable() { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_enable = Adafruit_BusIO_RegisterBits(&adc_control_reg, 1, 7); + + return adc_enable.read(); +} + +/*! + * @brief Sets ADC conversion mode + * @param one_shot + * True for one-shot conversion, false for continuous conversion + * @return True if successful, otherwise false. + */ +bool Adafruit_BQ25628E::setADCOneShot(bool one_shot) { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_rate = Adafruit_BusIO_RegisterBits(&adc_control_reg, 1, 6); + + return adc_rate.write(one_shot); +} + +/*! + * @brief Gets ADC conversion mode + * @return True if one-shot mode, false if continuous mode + */ +bool Adafruit_BQ25628E::getADCOneShot() { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_rate = Adafruit_BusIO_RegisterBits(&adc_control_reg, 1, 6); + + return adc_rate.read(); +} + +/*! + * @brief Sets ADC sample rate (bit resolution) + * @param sample_rate + * Sample rate setting (see bq25628e_adc_sample_t) + * @return True if successful, otherwise false. + */ +bool Adafruit_BQ25628E::setADCSampleRate(bq25628e_adc_sample_t sample_rate) { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_sample = Adafruit_BusIO_RegisterBits(&adc_control_reg, 2, 4); + + return adc_sample.write(sample_rate); +} + +/*! + * @brief Gets ADC sample rate setting + * @return Current sample rate setting (see bq25628e_adc_sample_t) + */ +bq25628e_adc_sample_t Adafruit_BQ25628E::getADCSampleRate() { + Adafruit_BusIO_Register adc_control_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_CONTROL, 1); + Adafruit_BusIO_RegisterBits adc_sample = Adafruit_BusIO_RegisterBits(&adc_control_reg, 2, 4); + + return (bq25628e_adc_sample_t)adc_sample.read(); +} + +/*! + * @brief Sets ADC function disable flags + * @param disable_flags + * Bitfield of ADC functions to disable (use BQ25628E_ADC_DIS_* flags) + * Setting a bit to 1 disables that ADC function + * Setting a bit to 0 enables that ADC function + * @return True if successful, otherwise false. + * @note Use BQ25628E_ADC_DIS_* defines to construct the disable_flags + */ +bool Adafruit_BQ25628E::setDisableADC(uint8_t disable_flags) { + Adafruit_BusIO_Register adc_func_disable_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_FUNCTION_DISABLE_0, 1); + + return adc_func_disable_reg.write(disable_flags); +} + +/*! + * @brief Gets ADC function disable flags + * @return Bitfield of disabled ADC functions (1 = disabled, 0 = enabled) + * @note Use BQ25628E_ADC_DIS_* defines to check individual flags + */ +uint8_t Adafruit_BQ25628E::getDisableADC() { + Adafruit_BusIO_Register adc_func_disable_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_ADC_FUNCTION_DISABLE_0, 1); + + return adc_func_disable_reg.read(); +} + +/*! + * @brief Gets IBUS current measurement from ADC + * @return Current in Amperes (positive = from VBUS to PMID, negative = reverse) + * @note Requires ADC to be enabled. Returns 2's complement 15-bit value + * converted to float with 2mA resolution + */ +float Adafruit_BQ25628E::getIBUScurrent() { + // Read 16-bit IBUS ADC register (little endian) + Adafruit_BusIO_Register ibus_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_IBUS_ADC, 2); + + uint16_t raw_value = ibus_adc_reg.read(); + + // Extract 15-bit ADC value from bits 15:1 (shift right by 1) + uint16_t adc_15bit = raw_value >> 1; + + // Convert from 15-bit 2's complement to signed 16-bit + int16_t signed_value; + if (adc_15bit & 0x4000) { + // Negative value - extend sign bit + signed_value = (int16_t)(adc_15bit | 0x8000); + } else { + // Positive value + signed_value = (int16_t)adc_15bit; + } + + // Convert to Amperes: 2mA per step + return (float)signed_value * 0.002f; +} + +/*! + * @brief Gets IBAT current measurement from ADC + * @return Current in Amperes (positive = charging, negative = discharging) + * @note Requires ADC to be enabled. Returns 2's complement 14-bit value + * converted to float with 4mA resolution. Range: -7.5A to +4.0A + */ +float Adafruit_BQ25628E::getIBATcurrent() { + // Read 16-bit IBAT ADC register (little endian) + Adafruit_BusIO_Register ibat_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_IBAT_ADC, 2); + + uint16_t raw_value = ibat_adc_reg.read(); + + // Extract 14-bit ADC value from bits 15:2 (shift right by 2) + uint16_t adc_14bit = raw_value >> 2; + + // Convert from 14-bit 2's complement to signed 16-bit + int16_t signed_value; + if (adc_14bit & 0x2000) { + // Negative value - extend sign bit + signed_value = (int16_t)(adc_14bit | 0xC000); + } else { + // Positive value + signed_value = (int16_t)adc_14bit; + } + + // Convert to Amperes: 4mA per step + return (float)signed_value * 0.004f; +} + +/*! + * @brief Gets VBUS voltage measurement from ADC + * @return Voltage in Volts. Range: 0V to 18V + * @note Requires ADC to be enabled. 3.97mV resolution + */ +float Adafruit_BQ25628E::getVBUSvoltage() { + // Read 16-bit VBUS ADC register (little endian) + Adafruit_BusIO_Register vbus_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_VBUS_ADC, 2); + + uint16_t raw_value = vbus_adc_reg.read(); + + // Extract voltage value from bits 15:2 (shift right by 2) + uint16_t voltage_value = raw_value >> 2; + + // Convert to Volts: 3.97mV per step + return (float)voltage_value * 0.00397f; +} + +/*! + * @brief Gets VPMID voltage measurement from ADC + * @return Voltage in Volts. Range: 0V to 18V + * @note Requires ADC to be enabled. 3.97mV resolution + */ +float Adafruit_BQ25628E::getVPMIDvoltage() { + // Read 16-bit VPMID ADC register (little endian) + Adafruit_BusIO_Register vpmid_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_VPMID_ADC, 2); + + uint16_t raw_value = vpmid_adc_reg.read(); + + // Extract voltage value from bits 15:2 (shift right by 2) + uint16_t voltage_value = raw_value >> 2; + + // Convert to Volts: 3.97mV per step + return (float)voltage_value * 0.00397f; +} + +/*! + * @brief Gets VBAT voltage measurement from ADC + * @return Voltage in Volts. Range: 0V to 5.572V + * @note Requires ADC to be enabled. 1.99mV resolution + */ +float Adafruit_BQ25628E::getVBATvoltage() { + // Read 16-bit VBAT ADC register (little endian) + Adafruit_BusIO_Register vbat_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_VBAT_ADC, 2); + + uint16_t raw_value = vbat_adc_reg.read(); + + // Extract voltage value from bits 15:1 (shift right by 1) + uint16_t voltage_value = raw_value >> 1; + + // Convert to Volts: 1.99mV per step + return (float)voltage_value * 0.00199f; +} + +/*! + * @brief Gets VSYS voltage measurement from ADC + * @return Voltage in Volts. Range: 0V to 5.572V + * @note Requires ADC to be enabled. 1.99mV resolution + */ +float Adafruit_BQ25628E::getVSYSvoltage() { + // Read 16-bit VSYS ADC register (little endian) + Adafruit_BusIO_Register vsys_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_VSYS_ADC, 2); + + uint16_t raw_value = vsys_adc_reg.read(); + + // Extract voltage value from bits 15:1 (shift right by 1) + uint16_t voltage_value = raw_value >> 1; + + // Convert to Volts: 1.99mV per step + return (float)voltage_value * 0.00199f; +} + +/*! + * @brief Gets thermistor reading as percentage of bias reference + * @return Percentage (0-100%). Range: 0% to 98.31% + * @note Requires ADC to be enabled and TS pin bias reference active + * Uses bits 11:0 with 0.0961% resolution + */ +float Adafruit_BQ25628E::getThermistorPercent() { + // Read 16-bit TS ADC register (little endian) + Adafruit_BusIO_Register ts_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_TS_ADC, 2); + + uint16_t raw_value = ts_adc_reg.read(); + + // Extract 12-bit value from bits 11:0 (no shift needed) + uint16_t ts_value = raw_value & 0x0FFF; + + // Convert to percentage: 0.0961% per step + return (float)ts_value * 0.0961f; +} + +/*! + * @brief Gets die temperature measurement from ADC + * @return Temperature in Celsius. Range: -40°C to +140°C + * @note Requires ADC to be enabled. Returns 2's complement 12-bit value + * with 0.5°C resolution using bits 11:0 + */ +float Adafruit_BQ25628E::getDieTempC() { + // Read 16-bit TDIE ADC register (little endian) + Adafruit_BusIO_Register tdie_adc_reg = Adafruit_BusIO_Register(i2c_dev, BQ25628E_REG_TDIE_ADC, 2); + + uint16_t raw_value = tdie_adc_reg.read(); + + // Extract 12-bit value from bits 11:0 (no shift needed) + uint16_t temp_12bit = raw_value & 0x0FFF; + + // Convert from 12-bit 2's complement to signed 16-bit + int16_t signed_value; + if (temp_12bit & 0x0800) { + // Negative value - extend sign bit + signed_value = (int16_t)(temp_12bit | 0xF000); + } else { + // Positive value + signed_value = (int16_t)temp_12bit; + } + + // Convert to Celsius: 0.5°C per step + return (float)signed_value * 0.5f; } \ No newline at end of file diff --git a/Adafruit_BQ25628E.h b/Adafruit_BQ25628E.h index 3fb0c7d..a1a175f 100644 --- a/Adafruit_BQ25628E.h +++ b/Adafruit_BQ25628E.h @@ -78,6 +78,126 @@ typedef enum { BQ25628E_THERM_CURR_UNCHANGED = 0b11 /*!< ICHG unchanged */ } bq25628e_therm_curr_t; +/*! Status register bit flags for REG0x1D_Charger_Status_0 */ +#define BQ25628E_STATUS0_WD_STAT (1 << 0) /*!< WD timer expired */ +#define BQ25628E_STATUS0_SAFETY_TMR_STAT (1 << 1) /*!< Safety timer expired */ +#define BQ25628E_STATUS0_VINDPM_STAT (1 << 2) /*!< In VINDPM regulation */ +#define BQ25628E_STATUS0_IINDPM_STAT (1 << 3) /*!< In IINDPM/ILIM regulation */ +#define BQ25628E_STATUS0_VSYS_STAT (1 << 4) /*!< In VSYSMIN regulation */ +#define BQ25628E_STATUS0_TREG_STAT (1 << 5) /*!< In thermal regulation */ +#define BQ25628E_STATUS0_ADC_DONE_STAT (1 << 6) /*!< ADC conversion complete */ + +/*! Status register bit masks for REG0x1E_Charger_Status_1 */ +#define BQ25628E_STATUS1_VBUS_STAT_MASK (0x07) /*!< VBUS status mask bits 2:0 */ +#define BQ25628E_STATUS1_CHG_STAT_MASK (0x18) /*!< Charge status mask bits 4:3 */ +#define BQ25628E_STATUS1_CHG_STAT_SHIFT (3) /*!< Charge status bit shift */ + +/*! VBUS Status values */ +#define BQ25628E_VBUS_STAT_NOT_POWERED (0x00) /*!< Not powered from VBUS */ +#define BQ25628E_VBUS_STAT_UNKNOWN_ADAPTER (0x04) /*!< Unknown adapter */ + +/*! Charge Status values */ +#define BQ25628E_CHG_STAT_NOT_CHARGING (0x00) /*!< Not charging or terminated */ +#define BQ25628E_CHG_STAT_CHARGING (0x01) /*!< Trickle/Pre/Fast charge */ +#define BQ25628E_CHG_STAT_TAPER (0x02) /*!< Taper charge (CV mode) */ +#define BQ25628E_CHG_STAT_TOPOFF (0x03) /*!< Top-off timer active */ + +/*! Fault status register bit flags for REG0x1F_FAULT_Status_0 */ +#define BQ25628E_FAULT_VBUS_FAULT_STAT (1 << 7) /*!< VBUS fault (OVP/sleep) */ +#define BQ25628E_FAULT_BAT_FAULT_STAT (1 << 6) /*!< Battery fault (OCP/OVP) */ +#define BQ25628E_FAULT_SYS_FAULT_STAT (1 << 5) /*!< System fault (short/OVP) */ +#define BQ25628E_FAULT_TSHUT_STAT (1 << 3) /*!< Thermal shutdown */ +#define BQ25628E_FAULT_TS_STAT_MASK (0x07) /*!< TS status mask bits 2:0 */ + +/*! TS Status values */ +#define BQ25628E_TS_STAT_NORMAL (0x00) /*!< TS Normal */ +#define BQ25628E_TS_STAT_COLD (0x01) /*!< TS Cold */ +#define BQ25628E_TS_STAT_HOT (0x02) /*!< TS Hot */ +#define BQ25628E_TS_STAT_COOL (0x03) /*!< TS Cool */ +#define BQ25628E_TS_STAT_WARM (0x04) /*!< TS Warm */ +#define BQ25628E_TS_STAT_PRECOOL (0x05) /*!< TS Pre-cool */ +#define BQ25628E_TS_STAT_PREWARM (0x06) /*!< TS Pre-warm */ +#define BQ25628E_TS_STAT_BIAS_FAULT (0x07) /*!< TS bias reference fault */ + +/*! Charger flag register bit flags for REG0x20_Charger_Flag_0 */ +#define BQ25628E_FLAG0_WD_FLAG (1 << 0) /*!< WD timer expired flag */ +#define BQ25628E_FLAG0_SAFETY_TMR_FLAG (1 << 1) /*!< Safety timer expired flag */ +#define BQ25628E_FLAG0_VINDPM_FLAG (1 << 2) /*!< VINDPM regulation flag */ +#define BQ25628E_FLAG0_IINDPM_FLAG (1 << 3) /*!< IINDPM/ILIM regulation flag */ +#define BQ25628E_FLAG0_VSYS_FLAG (1 << 4) /*!< VSYSMIN regulation flag */ +#define BQ25628E_FLAG0_TREG_FLAG (1 << 5) /*!< Thermal regulation flag */ +#define BQ25628E_FLAG0_ADC_DONE_FLAG (1 << 6) /*!< ADC conversion complete flag */ + +/*! Charger flag register bit flags for REG0x21_Charger_Flag_1 */ +#define BQ25628E_FLAG1_VBUS_FLAG (1 << 0) /*!< VBUS status changed flag */ +#define BQ25628E_FLAG1_CHG_FLAG (1 << 3) /*!< Charge status changed flag */ + +/*! Fault flag register bit flags for REG0x22_FAULT_Flag_0 */ +#define BQ25628E_FAULT_FLAG_VBUS_FAULT (1 << 7) /*!< VBUS OVP/sleep fault flag */ +#define BQ25628E_FAULT_FLAG_BAT_FAULT (1 << 6) /*!< Battery OCP/OVP fault flag */ +#define BQ25628E_FAULT_FLAG_SYS_FAULT (1 << 5) /*!< System OVP/short fault flag */ +#define BQ25628E_FAULT_FLAG_TSHUT (1 << 3) /*!< Thermal shutdown fault flag */ +#define BQ25628E_FAULT_FLAG_TS_CHANGED (1 << 0) /*!< TS status changed flag */ + +/*! Interrupt mask register bit flags for REG0x23_Charger_Mask_0 */ +#define BQ25628E_MASK0_ADC_DONE_MASK (1 << 6) /*!< ADC conversion mask */ +#define BQ25628E_MASK0_TREG_MASK (1 << 5) /*!< Thermal regulation mask */ +#define BQ25628E_MASK0_VSYS_MASK (1 << 4) /*!< VSYSMIN regulation mask */ +#define BQ25628E_MASK0_IINDPM_MASK (1 << 3) /*!< IINDPM/ILIM regulation mask */ +#define BQ25628E_MASK0_VINDPM_MASK (1 << 2) /*!< VINDPM regulation mask */ +#define BQ25628E_MASK0_SAFETY_TMR_MASK (1 << 1) /*!< Safety timer mask */ +#define BQ25628E_MASK0_WD_MASK (1 << 0) /*!< Watchdog timer mask */ + +/*! Interrupt mask register bit flags for REG0x24_Charger_Mask_1 */ +#define BQ25628E_MASK1_CHG_MASK (1 << 3) /*!< Charge status change mask */ +#define BQ25628E_MASK1_VBUS_MASK (1 << 0) /*!< VBUS status change mask */ + +/*! Interrupt mask register bit flags for REG0x25_FAULT_Mask_0 */ +#define BQ25628E_FMASK_VBUS_FAULT_MASK (1 << 7) /*!< VBUS fault mask */ +#define BQ25628E_FMASK_BAT_FAULT_MASK (1 << 6) /*!< Battery fault mask */ +#define BQ25628E_FMASK_SYS_FAULT_MASK (1 << 5) /*!< System fault mask */ +#define BQ25628E_FMASK_TSHUT_MASK (1 << 3) /*!< Thermal shutdown mask */ +#define BQ25628E_FMASK_TS_MASK (1 << 0) /*!< TS status change mask */ + +/*! Combined interrupt mask positions for 32-bit interface */ +#define BQ25628E_INT_MASK_WD (1UL << 0) /*!< Watchdog timer interrupt */ +#define BQ25628E_INT_MASK_SAFETY_TMR (1UL << 1) /*!< Safety timer interrupt */ +#define BQ25628E_INT_MASK_VINDPM (1UL << 2) /*!< VINDPM regulation interrupt */ +#define BQ25628E_INT_MASK_IINDPM (1UL << 3) /*!< IINDPM/ILIM regulation interrupt */ +#define BQ25628E_INT_MASK_VSYS (1UL << 4) /*!< VSYSMIN regulation interrupt */ +#define BQ25628E_INT_MASK_TREG (1UL << 5) /*!< Thermal regulation interrupt */ +#define BQ25628E_INT_MASK_ADC_DONE (1UL << 6) /*!< ADC conversion interrupt */ +#define BQ25628E_INT_MASK_VBUS (1UL << 8) /*!< VBUS status change interrupt */ +#define BQ25628E_INT_MASK_CHG (1UL << 11) /*!< Charge status change interrupt */ +#define BQ25628E_INT_MASK_TS (1UL << 16) /*!< TS status change interrupt */ +#define BQ25628E_INT_MASK_TSHUT (1UL << 19) /*!< Thermal shutdown interrupt */ +#define BQ25628E_INT_MASK_SYS_FAULT (1UL << 21) /*!< System fault interrupt */ +#define BQ25628E_INT_MASK_BAT_FAULT (1UL << 22) /*!< Battery fault interrupt */ +#define BQ25628E_INT_MASK_VBUS_FAULT (1UL << 23) /*!< VBUS fault interrupt */ + +/*! Default interrupt mask: Enable only CHG and VBUS interrupts, disable all others */ +#define BQ25628E_INT_MASK_DEFAULT (~(BQ25628E_INT_MASK_CHG | BQ25628E_INT_MASK_VBUS)) + +/*! + * @brief ADC sample rate settings + */ +typedef enum { + BQ25628E_ADC_SAMPLE_12BIT = 0b00, /*!< 12-bit effective resolution */ + BQ25628E_ADC_SAMPLE_11BIT = 0b01, /*!< 11-bit effective resolution */ + BQ25628E_ADC_SAMPLE_10BIT = 0b10, /*!< 10-bit effective resolution */ + BQ25628E_ADC_SAMPLE_9BIT = 0b11 /*!< 9-bit effective resolution */ +} bq25628e_adc_sample_t; + +/*! ADC function disable flags for REG0x27_ADC_Function_Disable_0 */ +#define BQ25628E_ADC_DIS_IBUS (1 << 7) /*!< Disable IBUS ADC */ +#define BQ25628E_ADC_DIS_IBAT (1 << 6) /*!< Disable IBAT ADC */ +#define BQ25628E_ADC_DIS_VBUS (1 << 5) /*!< Disable VBUS ADC */ +#define BQ25628E_ADC_DIS_VBAT (1 << 4) /*!< Disable VBAT ADC */ +#define BQ25628E_ADC_DIS_VSYS (1 << 3) /*!< Disable VSYS ADC */ +#define BQ25628E_ADC_DIS_TS (1 << 2) /*!< Disable TS ADC */ +#define BQ25628E_ADC_DIS_TDIE (1 << 1) /*!< Disable TDIE ADC */ +#define BQ25628E_ADC_DIS_VPMID (1 << 0) /*!< Disable VPMID ADC */ + /*! Register addresses for the BQ25628E */ #define BQ25628E_REG_CHARGE_CURRENT_LIMIT 0x02 #define BQ25628E_REG_CHARGE_VOLTAGE_LIMIT 0x04 @@ -217,6 +337,35 @@ public: bool setWarmThermistorCurrent(bq25628e_therm_curr_t setting); bq25628e_therm_curr_t getWarmThermistorCurrent(); + uint16_t getChargerStatusFlags(); + uint8_t getFaultStatusFlags(); + uint16_t getChargerFlags(); + uint8_t getFaultFlags(); + + bool setInterruptMask(uint32_t mask); + uint32_t getInterruptMask(); + + bool setADCEnable(bool enable); + bool getADCEnable(); + + bool setADCOneShot(bool one_shot); + bool getADCOneShot(); + + bool setADCSampleRate(bq25628e_adc_sample_t sample_rate); + bq25628e_adc_sample_t getADCSampleRate(); + + bool setDisableADC(uint8_t disable_flags); + uint8_t getDisableADC(); + + float getIBUScurrent(); + float getIBATcurrent(); + float getVBUSvoltage(); + float getVPMIDvoltage(); + float getVBATvoltage(); + float getVSYSvoltage(); + float getThermistorPercent(); + float getDieTempC(); + private: Adafruit_I2CDevice *i2c_dev; /*!< Pointer to I2C bus interface */ }; diff --git a/examples/test_BQ25628E/test_BQ25628E.ino b/examples/test_BQ25628E/test_BQ25628E.ino index a528d3c..b85875d 100644 --- a/examples/test_BQ25628E/test_BQ25628E.ino +++ b/examples/test_BQ25628E/test_BQ25628E.ino @@ -352,9 +352,358 @@ void setup() { break; } + // Enable ADC and set to 12-bit mode by default + Serial.println(F("Enabling ADC with 12-bit resolution...")); + if (bq.setADCEnable(true) && bq.setADCSampleRate(BQ25628E_ADC_SAMPLE_12BIT)) { + Serial.println(F("ADC configured successfully")); + } else { + Serial.println(F("Failed to configure ADC")); + } + + // Test ADC configuration functions + bool adc_enabled = bq.getADCEnable(); + Serial.print(F("ADC enabled: ")); + Serial.println(adc_enabled ? F("true") : F("false")); + + bool adc_oneshot = bq.getADCOneShot(); + Serial.print(F("ADC one-shot mode: ")); + Serial.println(adc_oneshot ? F("true") : F("false")); + + bq25628e_adc_sample_t sample_rate = bq.getADCSampleRate(); + Serial.print(F("ADC sample rate: ")); + switch (sample_rate) { + case BQ25628E_ADC_SAMPLE_12BIT: + Serial.println(F("12-bit")); + break; + case BQ25628E_ADC_SAMPLE_11BIT: + Serial.println(F("11-bit")); + break; + case BQ25628E_ADC_SAMPLE_10BIT: + Serial.println(F("10-bit")); + break; + case BQ25628E_ADC_SAMPLE_9BIT: + Serial.println(F("9-bit")); + break; + } + + // Ensure all ADC functions are enabled (disable_flags = 0x00) + Serial.println(F("Ensuring all ADC functions are enabled...")); + if (bq.setDisableADC(0x00)) { + Serial.println(F("ADC functions configured successfully")); + } else { + Serial.println(F("Failed to configure ADC functions")); + } + + // Display ADC function enable status + uint8_t adc_disable_flags = bq.getDisableADC(); + Serial.print(F("ADC Function Status (0x")); + Serial.print(adc_disable_flags, HEX); + Serial.println(F("):")); + + Serial.print(F(" IBUS ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_IBUS) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" IBAT ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_IBAT) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" VBUS ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_VBUS) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" VBAT ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_VBAT) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" VSYS ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_VSYS) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" TS ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_TS) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" TDIE ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_TDIE) ? F("Disabled") : F("Enabled")); + + Serial.print(F(" VPMID ADC: ")); + Serial.println((adc_disable_flags & BQ25628E_ADC_DIS_VPMID) ? F("Disabled") : F("Enabled")); + Serial.println(F("All tests completed!")); + + // Set interrupt mask to enable only CHG and VBUS interrupts, disable all others + Serial.println(F("Setting interrupt mask (CHG + VBUS enabled, others disabled)...")); + uint32_t intMask = BQ25628E_INT_MASK_WD | BQ25628E_INT_MASK_SAFETY_TMR | + BQ25628E_INT_MASK_VINDPM | BQ25628E_INT_MASK_IINDPM | + BQ25628E_INT_MASK_VSYS | BQ25628E_INT_MASK_TREG | + BQ25628E_INT_MASK_ADC_DONE | BQ25628E_INT_MASK_TS | + BQ25628E_INT_MASK_TSHUT | BQ25628E_INT_MASK_SYS_FAULT | + BQ25628E_INT_MASK_BAT_FAULT | BQ25628E_INT_MASK_VBUS_FAULT; + // CHG and VBUS interrupts NOT included in mask = they remain enabled + + if (bq.setInterruptMask(intMask)) { + Serial.println(F("Interrupt mask set successfully")); + } else { + Serial.println(F("Failed to set interrupt mask")); + } + + // Read back and display interrupt mask + uint32_t readMask = bq.getInterruptMask(); + Serial.print(F("Current interrupt mask: 0x")); + Serial.println(readMask, HEX); +} + +void printChargerStatus() { + uint16_t statusFlags = bq.getChargerStatusFlags(); + uint8_t faultFlags = bq.getFaultStatusFlags(); + uint16_t chargerFlags = bq.getChargerFlags(); + uint8_t faultFlagsCleared = bq.getFaultFlags(); + uint8_t status0 = statusFlags & 0xFF; + uint8_t status1 = (statusFlags >> 8) & 0xFF; + uint8_t flag0 = chargerFlags & 0xFF; + uint8_t flag1 = (chargerFlags >> 8) & 0xFF; + + Serial.println(F("=== Charger Status ===")); + Serial.print(F("Status: 0x")); + Serial.print(statusFlags, HEX); + Serial.print(F(", Fault: 0x")); + Serial.print(faultFlags, HEX); + Serial.print(F(", Flags: 0x")); + Serial.print(chargerFlags, HEX); + Serial.print(F(", FaultFlags: 0x")); + Serial.println(faultFlagsCleared, HEX); + + // REG0x1D Status 0 flags + Serial.print(F("Status 0 (0x")); + Serial.print(status0, HEX); + Serial.println(F("):")); + + if (status0 & BQ25628E_STATUS0_WD_STAT) { + Serial.println(F(" ⚠️ WD Timer Expired")); + } + if (status0 & BQ25628E_STATUS0_SAFETY_TMR_STAT) { + Serial.println(F(" ⚠️ Safety Timer Expired")); + } + if (status0 & BQ25628E_STATUS0_VINDPM_STAT) { + Serial.println(F(" 📉 VINDPM Regulation Active")); + } + if (status0 & BQ25628E_STATUS0_IINDPM_STAT) { + Serial.println(F(" 📉 IINDPM/ILIM Regulation Active")); + } + if (status0 & BQ25628E_STATUS0_VSYS_STAT) { + Serial.println(F(" 📉 VSYSMIN Regulation Active")); + } + if (status0 & BQ25628E_STATUS0_TREG_STAT) { + Serial.println(F(" 🌡️ Thermal Regulation Active")); + } + if (status0 & BQ25628E_STATUS0_ADC_DONE_STAT) { + Serial.println(F(" ✅ ADC Conversion Complete")); + } + + // REG0x1E Status 1 flags + Serial.print(F("Status 1 (0x")); + Serial.print(status1, HEX); + Serial.println(F("):")); + + // VBUS Status (bits 2:0) + uint8_t vbus_stat = status1 & BQ25628E_STATUS1_VBUS_STAT_MASK; + Serial.print(F(" 🔌 VBUS: ")); + switch (vbus_stat) { + case BQ25628E_VBUS_STAT_NOT_POWERED: + Serial.println(F("Not Powered")); + break; + case BQ25628E_VBUS_STAT_UNKNOWN_ADAPTER: + Serial.println(F("Unknown Adapter")); + break; + default: + Serial.print(F("Status Code ")); + Serial.println(vbus_stat); + break; + } + + // Charge Status (bits 4:3) + uint8_t chg_stat = (status1 & BQ25628E_STATUS1_CHG_STAT_MASK) >> BQ25628E_STATUS1_CHG_STAT_SHIFT; + Serial.print(F(" 🔋 Charge: ")); + switch (chg_stat) { + case BQ25628E_CHG_STAT_NOT_CHARGING: + Serial.println(F("Not Charging/Terminated")); + break; + case BQ25628E_CHG_STAT_CHARGING: + Serial.println(F("Charging (CC mode)")); + break; + case BQ25628E_CHG_STAT_TAPER: + Serial.println(F("Taper Charge (CV mode)")); + break; + case BQ25628E_CHG_STAT_TOPOFF: + Serial.println(F("Top-off Timer Active")); + break; + } + + // REG0x1F Fault Status flags + Serial.print(F("Fault Status (0x")); + Serial.print(faultFlags, HEX); + Serial.println(F("):")); + + if (faultFlags & BQ25628E_FAULT_VBUS_FAULT_STAT) { + Serial.println(F(" 🚨 VBUS Fault (OVP/Sleep)")); + } + if (faultFlags & BQ25628E_FAULT_BAT_FAULT_STAT) { + Serial.println(F(" 🚨 Battery Fault (OCP/OVP)")); + } + if (faultFlags & BQ25628E_FAULT_SYS_FAULT_STAT) { + Serial.println(F(" 🚨 System Fault (Short/OVP)")); + } + if (faultFlags & BQ25628E_FAULT_TSHUT_STAT) { + Serial.println(F(" 🔥 Thermal Shutdown")); + } + + // TS Status (bits 2:0) + uint8_t ts_stat = faultFlags & BQ25628E_FAULT_TS_STAT_MASK; + Serial.print(F(" 🌡️ TS Status: ")); + switch (ts_stat) { + case BQ25628E_TS_STAT_NORMAL: + Serial.println(F("Normal")); + break; + case BQ25628E_TS_STAT_COLD: + Serial.println(F("Cold")); + break; + case BQ25628E_TS_STAT_HOT: + Serial.println(F("Hot")); + break; + case BQ25628E_TS_STAT_COOL: + Serial.println(F("Cool")); + break; + case BQ25628E_TS_STAT_WARM: + Serial.println(F("Warm")); + break; + case BQ25628E_TS_STAT_PRECOOL: + Serial.println(F("Pre-cool")); + break; + case BQ25628E_TS_STAT_PREWARM: + Serial.println(F("Pre-warm")); + break; + case BQ25628E_TS_STAT_BIAS_FAULT: + Serial.println(F("Bias Reference Fault")); + break; + } + + // REG0x20/0x21 Charger Flag status (cleared on read!) + if (flag0 != 0 || flag1 != 0) { + Serial.print(F("Charger Flags (0x")); + Serial.print(flag1, HEX); + Serial.print(F("/0x")); + Serial.print(flag0, HEX); + Serial.println(F(") - CLEARED:")); + + // Flag0 bits + if (flag0 & BQ25628E_FLAG0_WD_FLAG) { + Serial.println(F(" 🚩 WD Timer Expired")); + } + if (flag0 & BQ25628E_FLAG0_SAFETY_TMR_FLAG) { + Serial.println(F(" 🚩 Safety Timer Expired")); + } + if (flag0 & BQ25628E_FLAG0_VINDPM_FLAG) { + Serial.println(F(" 🚩 VINDPM Regulation Event")); + } + if (flag0 & BQ25628E_FLAG0_IINDPM_FLAG) { + Serial.println(F(" 🚩 IINDPM/ILIM Regulation Event")); + } + if (flag0 & BQ25628E_FLAG0_VSYS_FLAG) { + Serial.println(F(" 🚩 VSYSMIN Regulation Event")); + } + if (flag0 & BQ25628E_FLAG0_TREG_FLAG) { + Serial.println(F(" 🚩 Thermal Regulation Event")); + } + if (flag0 & BQ25628E_FLAG0_ADC_DONE_FLAG) { + Serial.println(F(" 🚩 ADC Conversion Complete")); + } + + // Flag1 bits + if (flag1 & BQ25628E_FLAG1_VBUS_FLAG) { + Serial.println(F(" 🚩 VBUS Status Changed")); + } + if (flag1 & BQ25628E_FLAG1_CHG_FLAG) { + Serial.println(F(" 🚩 Charge Status Changed")); + } + } else { + Serial.println(F("No charger flags set")); + } + + // REG0x22 Fault Flag status (cleared on read!) + if (faultFlagsCleared != 0) { + Serial.print(F("Fault Flags (0x")); + Serial.print(faultFlagsCleared, HEX); + Serial.println(F(") - CLEARED:")); + + if (faultFlagsCleared & BQ25628E_FAULT_FLAG_VBUS_FAULT) { + Serial.println(F(" 💥 VBUS Fault Event (OVP/Sleep)")); + } + if (faultFlagsCleared & BQ25628E_FAULT_FLAG_BAT_FAULT) { + Serial.println(F(" 💥 Battery Fault Event (OCP/OVP)")); + } + if (faultFlagsCleared & BQ25628E_FAULT_FLAG_SYS_FAULT) { + Serial.println(F(" 💥 System Fault Event (OVP/Short)")); + } + if (faultFlagsCleared & BQ25628E_FAULT_FLAG_TSHUT) { + Serial.println(F(" 💥 Thermal Shutdown Event")); + } + if (faultFlagsCleared & BQ25628E_FAULT_FLAG_TS_CHANGED) { + Serial.println(F(" 💥 TS Status Changed Event")); + } + } else { + Serial.println(F("No fault flags set")); + } + + // Display current interrupt mask status + uint32_t currentMask = bq.getInterruptMask(); + Serial.print(F("INT Mask: CHG=")); + Serial.print((currentMask & BQ25628E_INT_MASK_CHG) ? F("OFF") : F("ON")); + Serial.print(F(", VBUS=")); + Serial.print((currentMask & BQ25628E_INT_MASK_VBUS) ? F("OFF") : F("ON")); + Serial.print(F(", Others=")); + Serial.println((currentMask & ~(BQ25628E_INT_MASK_CHG | BQ25628E_INT_MASK_VBUS)) ? F("OFF") : F("ON")); + + Serial.println(F("=====================")); + Serial.println(); } void loop() { - delay(1000); + static unsigned long lastStatusTime = 0; + static unsigned long lastADCTime = 0; + unsigned long currentTime = millis(); + + // Print all ADC values every 1 second + if (currentTime - lastADCTime >= 1000) { + float ibus_current = bq.getIBUScurrent(); + float ibat_current = bq.getIBATcurrent(); + float vbus_voltage = bq.getVBUSvoltage(); + float vpmid_voltage = bq.getVPMIDvoltage(); + float vbat_voltage = bq.getVBATvoltage(); + float vsys_voltage = bq.getVSYSvoltage(); + float thermistor_percent = bq.getThermistorPercent(); + float die_temp = bq.getDieTempC(); + + Serial.print(F("ADC: IBUS=")); + Serial.print(ibus_current, 3); + Serial.print(F("A, IBAT=")); + Serial.print(ibat_current, 3); + Serial.print(F("A, VBUS=")); + Serial.print(vbus_voltage, 3); + Serial.print(F("V, VPMID=")); + Serial.print(vpmid_voltage, 3); + Serial.print(F("V, VBAT=")); + Serial.print(vbat_voltage, 3); + Serial.print(F("V, VSYS=")); + Serial.print(vsys_voltage, 3); + Serial.print(F("V, TS=")); + Serial.print(thermistor_percent, 1); + Serial.print(F("%, TDIE=")); + Serial.print(die_temp, 1); + Serial.println(F("°C")); + + lastADCTime = currentTime; + } + + // Print status every 5 seconds + if (currentTime - lastStatusTime >= 5000) { + printChargerStatus(); + lastStatusTime = currentTime; + } + + delay(100); } \ No newline at end of file