/** * @file bq27220.h * * Quite problematic chip with quite bad documentation. * * Couple things to keep in mind: * * - Datasheet and technical reference manual are full of bullshit * - bqstudio is ignoring them * - bqstudio i2c exchange tracing gives some ideas on timings that works, but there is a catch * - bqstudio timings contradicts to gm.fs file specification * - it's impossible to reproduce all situations in bqstudio * - experiments with blackbox can not cover all edge cases * - final timings are kinda blend between all of those sources * - device behavior differs depending on i2c clock speed * - The Hero Himmel would not have used this gauge in the first place * * Couple advises if you'll need to modify this driver: * - Reset and wait for INITCOMP if something is not right. * - Do not do partial config update, it takes unpredictable amount of time to apply. * - Don't forget to reset chip before writing new config. * - If something fails at config update stage, wait for 4 seconds before doing next cycle. * - If you can program and lock chip at factory stage - do it. It will save you a lot of time. * - Keep sealed or strange things may happen. * - There is a condition when it may stuck at INITCOMP state, just "press reset button". * */ #pragma once #include #include #include #define BQ27220_ERROR 0x0 #define BQ27220_SUCCESS 0x1 typedef struct { // Low byte, Low bit first uint8_t BATT_ID : 3; /**< Battery Identification */ bool SNOOZE : 1; /**< SNOOZE mode is enabled */ bool BCA : 1; /**< fuel gauge board calibration routine is active */ bool CCA : 1; /**< Coulomb Counter Calibration routine is active */ uint8_t RSVD0 : 2; /**< Reserved */ // High byte, Low bit first uint8_t RSVD1; /**< Reserved */ } Bq27220ControlStatus; _Static_assert(sizeof(Bq27220ControlStatus) == 2, "Incorrect Bq27220ControlStatus structure size"); typedef struct { // Low byte, Low bit first bool DSG : 1; /**< The device is in DISCHARGE */ bool SYSDWN : 1; /**< System down bit indicating the system should shut down */ bool TDA : 1; /**< Terminate Discharge Alarm */ bool BATTPRES : 1; /**< Battery Present detected */ bool AUTH_GD : 1; /**< Detect inserted battery */ bool OCVGD : 1; /**< Good OCV measurement taken */ bool TCA : 1; /**< Terminate Charge Alarm */ bool RSVD : 1; /**< Reserved */ // High byte, Low bit first bool CHGINH : 1; /**< Charge inhibit */ bool FC : 1; /**< Full-charged is detected */ bool OTD : 1; /**< Overtemperature in discharge condition is detected */ bool OTC : 1; /**< Overtemperature in charge condition is detected */ bool SLEEP : 1; /**< Device is operating in SLEEP mode when set */ bool OCVFAIL : 1; /**< Status bit indicating that the OCV reading failed due to current */ bool OCVCOMP : 1; /**< An OCV measurement update is complete */ bool FD : 1; /**< Full-discharge is detected */ } Bq27220BatteryStatus; _Static_assert(sizeof(Bq27220BatteryStatus) == 2, "Incorrect Bq27220BatteryStatus structure size"); typedef enum { Bq27220OperationStatusSecSealed = 0b11, Bq27220OperationStatusSecUnsealed = 0b10, Bq27220OperationStatusSecFull = 0b01, } Bq27220OperationStatusSec; typedef struct { // Low byte, Low bit first bool CALMD : 1; /**< Calibration mode enabled */ uint8_t SEC : 2; /**< Current security access */ bool EDV2 : 1; /**< EDV2 threshold exceeded */ bool VDQ : 1; /**< Indicates if Current discharge cycle is NOT qualified or qualified for an FCC updated */ bool INITCOMP : 1; /**< gauge initialization is complete */ bool SMTH : 1; /**< RemainingCapacity is scaled by smooth engine */ bool BTPINT : 1; /**< BTP threshold has been crossed */ // High byte, Low bit first uint8_t RSVD1 : 2; /**< Reserved */ bool CFGUPDATE : 1; /**< Gauge is in CONFIG UPDATE mode */ uint8_t RSVD0 : 5; /**< Reserved */ } Bq27220OperationStatus; _Static_assert( sizeof(Bq27220OperationStatus) == 2, "Incorrect Bq27220OperationStatus structure size"); typedef struct { // Low byte, Low bit first bool FD : 1; /**< Full Discharge */ bool FC : 1; /**< Full Charge */ bool TD : 1; /**< Terminate Discharge */ bool TC : 1; /**< Terminate Charge */ bool RSVD0 : 1; /**< Reserved */ bool EDV : 1; /**< Cell voltage is above or below EDV0 threshold */ bool DSG : 1; /**< DISCHARGE or RELAXATION */ bool CF : 1; /**< Battery conditioning is needed */ // High byte, Low bit first uint8_t RSVD1 : 2; /**< Reserved */ bool FCCX : 1; /**< fcc1hz clock going into CC: 0 = 1 Hz, 1 = 16 Hz*/ uint8_t RSVD2 : 2; /**< Reserved */ bool EDV1 : 1; /**< Cell voltage is above or below EDV1 threshold */ bool EDV2 : 1; /**< Cell voltage is above or below EDV2 threshold */ bool VDQ : 1; /**< Charge cycle FCC update qualification */ } Bq27220GaugingStatus; _Static_assert(sizeof(Bq27220GaugingStatus) == 2, "Incorrect Bq27220GaugingStatus structure size"); typedef struct BQ27220DMData BQ27220DMData; /** Initialize Driver * * This routine performs a lot of things under the hood: * - Verifies that gauge is present on i2c bus and got correct ID(0220) * - Unseals gauge * - Checks various internal statuses * - Checks that current profile is 0 * - Checks configuration again provided data_memory * - Reset gauge if something on previous stages was fishy * - Updates configuration if needed * - Sealing gauge to prevent configuration and state from accidental damage * * @param handle The I2C Bus handle * @param[in] data_memory The data memory to be uploaded into gauge * * @return true on success, false otherwise */ bool bq27220_init(const FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory); /** Reset gauge * * @param handle The I2C Bus handle * * @return true on success, false otherwise */ bool bq27220_reset(const FuriHalI2cBusHandle* handle); /** Seal gauge access * * @param handle The I2C Bus handle * * @return true on success, false otherwise */ bool bq27220_seal(const FuriHalI2cBusHandle* handle); /** Unseal gauge access * * @param handle The I2C Bus handle * * @return true on success, false otherwise */ bool bq27220_unseal(const FuriHalI2cBusHandle* handle); /** Get full access * * @warning must be done in unsealed state * * @param handle The I2C Bus handle * * @return true on success, false otherwise */ bool bq27220_full_access(const FuriHalI2cBusHandle* handle); /** Get battery voltage * * @param handle The I2C Bus handle * * @return voltage in mV or BQ27220_ERROR */ uint16_t bq27220_get_voltage(const FuriHalI2cBusHandle* handle); /** Get current * * @param handle The I2C Bus handle * * @return current in mA or BQ27220_ERROR */ int16_t bq27220_get_current(const FuriHalI2cBusHandle* handle); /** Get control status * * @param handle The handle * @param control_status The control status * * @return true on success, false otherwise */ bool bq27220_get_control_status( const FuriHalI2cBusHandle* handle, Bq27220ControlStatus* control_status); /** Get battery status * * @param handle The handle * @param battery_status The battery status * * @return true on success, false otherwise */ bool bq27220_get_battery_status( const FuriHalI2cBusHandle* handle, Bq27220BatteryStatus* battery_status); /** Get operation status * * @param handle The handle * @param operation_status The operation status * * @return true on success, false otherwise */ bool bq27220_get_operation_status( const FuriHalI2cBusHandle* handle, Bq27220OperationStatus* operation_status); /** Get gauging status * * @param handle The handle * @param gauging_status The gauging status * * @return true on success, false otherwise */ bool bq27220_get_gauging_status( const FuriHalI2cBusHandle* handle, Bq27220GaugingStatus* gauging_status); /** Get temperature * * @param handle The I2C Bus handle * * @return temperature in units of 0.1°K */ uint16_t bq27220_get_temperature(const FuriHalI2cBusHandle* handle); /** Get compensated full charge capacity * * @param handle The I2C Bus handle * * @return full charge capacity in mAh or BQ27220_ERROR */ uint16_t bq27220_get_full_charge_capacity(const FuriHalI2cBusHandle* handle); /** Get design capacity * * @param handle The I2C Bus handle * * @return design capacity in mAh or BQ27220_ERROR */ uint16_t bq27220_get_design_capacity(const FuriHalI2cBusHandle* handle); /** Get remaining capacity * * @param handle The I2C Bus handle * * @return remaining capacity in mAh or BQ27220_ERROR */ uint16_t bq27220_get_remaining_capacity(const FuriHalI2cBusHandle* handle); /** Get predicted remaining battery capacity * * @param handle The I2C Bus handle * * @return state of charge in percents or BQ27220_ERROR */ uint16_t bq27220_get_state_of_charge(const FuriHalI2cBusHandle* handle); /** Get ratio of full charge capacity over design capacity * * @param handle The I2C Bus handle * * @return state of health in percents or BQ27220_ERROR */ uint16_t bq27220_get_state_of_health(const FuriHalI2cBusHandle* handle);