This is a library for the MAX17055 Li+ Battery Fuel Gauge.
Fork of max17055 by
max17055.cpp
- Committer:
- fneirab
- Date:
- 2017-11-02
- Revision:
- 8:ca8765c30ed2
- Parent:
- 7:479a36909ced
- Child:
- 9:f29d5e49b190
File content as of revision 8:ca8765c30ed2:
/******************************************************************//** * @file max17055.cpp * * @author Felipe Neira - Maxim Integrated - TTS * * @version 1.0 * * Started: 11SEP17 * * Updated: * * @brief Source file for MAX31855 class * ******************************************************************************** * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. * ******************************************************************************/ #include "mbed.h" #include "max17055.h" #define DRV_NAME "max17055" /* CONFIG register bits */ #define MAX17055_CONFIG_ALRT_EN (1 << 2) #define MAX17055_CONFIG2_LDMDL (1 << 5) /* STATUS register bits */ #define MAX17055_STATUS_BST (1 << 3) #define MAX17055_STATUS_POR (1 << 1) /* MODELCFG register bits */ #define MAX17055_MODELCFG_REFRESH (1 << 15) /* TALRTTH register bits */ #define MIN_TEMP_ALERT 0 #define MAX_TEMP_ALERT 8 /* FSTAT register bits */ #define MAX17055_FSTAT_DNR (1) /* STATUS interrupt status bits */ #define MAX17055_STATUS_ALRT_CLR_MASK (0x88BB) #define MAX17055_STATUS_SOC_MAX_ALRT (1 << 14) #define MAX17055_STATUS_TEMP_MAX_ALRT (1 << 13) #define MAX17055_STATUS_VOLT_MAX_ALRT (1 << 12) #define MAX17055_STATUS_SOC_MIN_ALRT (1 << 10) #define MAX17055_STATUS_TEMP_MIN_ALRT (1 << 9) #define MAX17055_STATUS_VOLT_MIN_ALRT (1 << 8) #define MAX17055_STATUS_CURR_MAX_ALRT (1 << 6) #define MAX17055_STATUS_CURR_MIN_ALRT (1 << 2) #define MAX17055_VMAX_TOLERANCE 50 /* 50 mV */ /////////////////////////////////////////////////////////////////////////////// MAX17055::MAX17055(I2C &i2c): m_i2cBus(i2c) { //empty block } /////////////////////////////////////////////////////////////////////////////// MAX17055::~MAX17055() { //empty block } /////////////////////////////////////////////////////////////////////////////// /** * \brief Write a value to a MAX17055 register * \par Details * This function writes a value to a MAX17055 register * * \param[in] reg_addr - register address * \param[in] reg_data - register data * * \retval 1 on success */ int MAX17055::writeReg(Registers_e reg_addr, uint16_t reg_data) { uint16_t mask = 0x00FF; uint8_t dataLSB; uint8_t dataMSB; dataLSB = reg_data & mask; dataMSB = (reg_data >> 8) & mask; char addr_plus_data[3] = {reg_addr, dataLSB, dataMSB}; if ( m_i2cBus.write(I2C_W_ADRS, addr_plus_data, 3, false) == 0) return 1; else return 0; } /////////////////////////////////////////////////////////////////////////////// /** * \brief Read a MAX17055 register * \par Details * This function reads a MAX17055 register * * \param[in] reg_addr - register address * \param[out] &value - pointer that stores the register data * * \retval 1 on success */ int32_t MAX17055::readReg(Registers_e reg_addr, uint16_t &value) { int32_t result; uint16_t mask = 0x00FF; char local_data[1]; local_data[0] = reg_addr; char read_data[2]; result = m_i2cBus.write(I2C_W_ADRS, local_data, 1); if(result == 0) { result = m_i2cBus.read(I2C_R_ADRS, read_data , 2, false); if (result == 0) { value = ( ((read_data[1] & mask) << 8) + (read_data[0])); result = 1; } } return result; } /////////////////////////////////////////////////////////////////////////////// /** * \brief Write and Verify a MAX17055 register * \par Details * This function wites and verifies if the writing process was successful * * \param[in] reg_addr - register address * \param[out] reg_data - the variable that contains the data to write * to the register address * * \retval 1 on success */ int MAX17055::write_and_verify_reg(Registers_e reg_addr, uint16_t reg_data) { int retries = 8; int ret; int statusRead; int statusWrite; uint16_t read_data; do { statusWrite = writeReg(reg_addr, reg_data); if (statusWrite != 1) ret = -1; wait_ms(3); statusRead = readReg(reg_addr, read_data); if (statusRead != 1) ret = -2; if (read_data != reg_data) { ret = -3; retries--; } } while (retries && read_data != reg_data); if (ret<0) return ret; else return 1; } //////////////////////////////////////////////////////////////////////////////// /** * \brief Initialise Function for MAX17055 * \par Details * This function intitializes the MAX17055 * * \retval 1 on success * 0 if device is not present * -1 if errors exist */ int MAX17055::init(platform_data des_data) { int status, ret; uint16_t read_data, hibcfg_value, reg; status = readReg(VERSION_REG, read_data); if (status == 0) return status; //Device is not present in the i2c Bus /* Step 0: Check for POR */ /* Skip load model if POR bit is cleared */ readReg(STATUS_REG, read_data); if (!(read_data & MAX17055_STATUS_POR ) ) return -1; //POR is not set. Skip Initialization. /* Step 1: Check if FStat.DNR == 0 */ // Do not continue until FSTAT.DNR == 0 printf("step 0 check \r\n"); int time_out = 500; ret = poll_flag_clear(FSTAT_REG, MAX17055_FSTAT_DNR, time_out); if (ret < 0) { printf("Unsuccessful init: Data Not Ready!\n"); return ret; } /* Force exit from hibernate */ hibcfg_value = forcedExitHyberMode(); printf("step 1 check \r\n"); /* Step 2: Initialize configuration */ switch (1) { case MODEL_LOADING_OPTION1: /* Step 2.1: Option 1 EZ Config */ EZconfig_init(des_data); /* Poll ModelCFG.ModelRefresh bit for clear */ int time_out = 500; //msec ret = poll_flag_clear(MODELCFG_REG, MAX17055_MODELCFG_REFRESH, time_out); if(ret < 0) { //dev_err(priv->dev, "Option1 model refresh not completed!\n"); return ret; } break; } /* Restore original HibCfg */ writeReg(HIBCFG_REG, hibcfg_value); printf("Last section check \r\n"); /* Optional step - alert threshold initialization */ //set_alert_thresholds(priv); /* Clear Status.POR */ readReg(STATUS_REG, reg); write_and_verify_reg(STATUS_REG, (reg & ~MAX17055_STATUS_POR)); return 1; } /////////////////////////////////////////////////////////////////////////////// /** * \brief Poll Flag clear * \par Details * This function clears status flags for the MAX17055 * * \param[in] reg_addr - register address * \param[in] mask - register address * \param[in] timeout - register data * * \retval 1 on success * -1 on Failure */ int MAX17055::poll_flag_clear (Registers_e reg_addr, int mask, int timeout) { uint16_t data; int ret; do { wait_ms(10); ret = readReg(reg_addr, data); if(ret < 0) return ret; if(!(data & mask)) return 1; timeout -= 10; } while(timeout > 0); return -1; } //////////////////////////////////////////////////////////////////////////////// /** * \brief Get Internal Temperature Function for MAX17055 * \par Details * This function sends a request to access the internal * of the MAX17055 * * * \retval temperature value * -1 if errors exist */ int MAX17055::get_temperature() { int ret; uint16_t data; ret = readReg(TEMP_REG, data); if (ret < 0) return ret; /* The value is signed. */ if (data & 0x8000) data |= 0xFFFF0000; /* The value is converted into centigrade scale */ /* Units of LSB = 1 / 256 degree Celsius */ data >>= 8; return data ; } //////////////////////////////////////////////////////////////////////////////// /** * \brief Forced Exit Hibernate Mode Function for MAX17055 * \par Details * This function executes a force exit from hibernate mode. * * \retval returns HibCFG original value before forced Exit Hybernate mode * */ uint16_t MAX17055::forcedExitHyberMode() { uint16_t hibcfg; /* Force exit from hibernate */ //STEP 0: Store original HibCFG value readReg(HIBCFG_REG, hibcfg); //STEP 1: Write to Soft-Wakeup Commannd Register writeReg(VFSOC0_QH0_LOCK_REG, 0x90); //Soft-Wakeup from hybernate //STEP 2: Write to Hibernate Configuration register writeReg(HIBCFG_REG, 0x0); //disable hibernate mode //STEP 3:Write to Soft-Wakeup Commannd Register writeReg(VFSOC0_QH0_LOCK_REG, 0x0); //Clear All commnads return hibcfg; } //////////////////////////////////////////////////////////////////////////////// /** * \brief EZ COnfing Init function * \par Details * This function implements the steps for the EZ confing m5 FuelGauge * * \retval returns TBD * */ uint16_t MAX17055::EZconfig_init(platform_data des_data) { const int charger_th = 4275; const int chg_V_high = 51200; const int chg_V_low = 44138; const int param_EZ_FG1 = 0x8400; const int param_EZ_FG2 = 0x8000; uint16_t dpacc, ret; /* Step 2.1: Option 1 EZ Config */ writeReg(DESIGNCAP_REG, des_data.designcap); writeReg(DQACC_REG, des_data.designcap >> 5); writeReg(ICHGTERM_REG, des_data.ichgterm); writeReg(VEMPTY_REG, des_data.vempty); if (des_data.vcharge > charger_th) { dpacc = (des_data.designcap >> 5) * chg_V_high / des_data.designcap; writeReg(DPACC_REG, dpacc); writeReg(MODELCFG_REG, param_EZ_FG1); //Why 0x8400 } else { dpacc = (des_data.designcap >> 5) * chg_V_low / des_data.designcap; writeReg(DPACC_REG, dpacc); writeReg(MODELCFG_REG, param_EZ_FG2); } return ret; } //////////////////////////////////////////////////////////////////////////////// /** * \brief Get State Of Charge(SOC) Function for MAX17055 * \par Details * This function sends a request to access the internal * of the MAX17055 * * \param[in] reg_addr - register address * \param[out] reg_data - SOC data from the REPSOC_REG register * \retval 1 on success * * -1 if errors exist */ int MAX17055::get_SOC() { int ret; uint16_t data; ret = readReg(REPSOC_REG, data); if (ret < 0) return ret; data = data >> 8; /* RepSOC LSB: 1/256 % */ return data; } //////////////////////////////////////////////////////////////////////////////// /** * \brief Get Average State Of Charge(SOC) Function for MAX17055 * \par Details * This function sends a request to access the internal * of the MAX17055 * * \param[in] reg_addr - register address * \param[out] * \retval data - avSOC data from the AVSOC_REG register * */ int MAX17055::get_avSOC() { int ret; uint16_t data; ret = readReg(AVSOC_REG, data); if (ret < 0) return ret; data = data >> 8; /* avSOC LSB: 1/256 % */ return data; } /////////////////////////////////////////////////////////////////////////////// /** * \brief Get the remaining Time to Empty(TTE) Function for MAX17055 * \par Details * This function sends a request to access the internal register * of the MAX17055 * * \retval tte_data - Time to Empty data from the TTE_REG register * * -1 if errors exist */ int MAX17055::get_TTE() { int ret; uint16_t data; ret = readReg(TTE_REG, data); if (ret < 0) return ret; else data = (data * 45) >> 3; /* TTE LSB: 5.625 sec */ return data; } /////////////////////////////////////////////////////////////////////////////// /** * \brief Get the remaining Time to Full(TTF) Function for MAX17055 * \par Details * This function sends a request to access the internal register * of the MAX17055 * * \retval ttf_data - Time to Empty data from the TTF_REG register * * -1 if errors exist */ int MAX17055::get_TTF() { int ret; uint16_t ttf_data; ret = readReg(TTF_REG, ttf_data); if (ret < 0) return ret; else ttf_data = (ttf_data * 45) >> 3; /* TTF LSB: 5.625 sec */ return ttf_data; } //////////////////////////////////////////////////////////////////////////// /** * \brief Get voltage of the cell Function for MAX17055 * \par Details * This function sends a request to access the internal register * of the MAX17055 to read the voltage of the cell * * \retval vcell_data - vcell data from the VCELL_REG register * * -1 if errors exist */ int MAX17055::get_Vcell() { int ret; uint16_t vcell_data; ret = readReg(VCELL_REG, vcell_data); if (ret < 0) return ret; else //printf("Vcell Reg= %d \r\n",vcell_data); ret = lsb_to_uvolts(vcell_data); //printf("Vcell Conv= %d \r\n",ret); return ret; } //////////////////////////////////////////////////////////////////////////// /** * \brief Get current Function for MAX17055 * \par Details * This function sends a request to access the internal register * of the MAX17055 to read the current register. * * \retval curr_data - vcell data from the VCELL_REG register * * -1 if errors exist */ int MAX17055::get_Current( platform_data des_data ) { int ret,design_rsense; uint16_t data; ret = readReg(CURRENT_REG, data); if (ret < 0) return ret; else design_rsense = des_data.rsense; ret = raw_current_to_uamps((uint32_t)data, design_rsense); return ret; } //////////////////////////////////////////////////////////////////////////// /** * \brief Get Average Current Function for MAX17055 * \par Details * This function sends a request to access the internal register * of the MAX17055 to read the average current register. * * \retval curr_data - vcell data from the AVGCURRENT_REG register * * -1 if errors exist */ int MAX17055::get_AvgCurrent( platform_data des_data ) { int ret, design_rsense; uint16_t data; uint32_t aveCurr_data; ret = readReg(AVGCURRENT_REG, data); if (ret < 0) return ret; else aveCurr_data = data; design_rsense = des_data.rsense; aveCurr_data = raw_current_to_uamps(aveCurr_data, design_rsense); return aveCurr_data; } /////////////////////////////////////////////////////////////////////////////// /** * \brief lsb_to_uvolts Converssion Function * \par Details * This function takes the lsb value of the register and convert it * to uvolts * * \param[in] lsb - value of register lsb * \retval lsb - converted lsb to uvolts * */ int MAX17055:: lsb_to_uvolts(uint16_t lsb) { int store; store = (lsb * 625) / 8; /* 78.125uV per bit */ return store; } /////////////////////////////////////////////////////////////////////////////// /** * \brief raw_current_to_uamp Converssion Function * \par Details * This function takes the raw current value of the register and * converts it to uamps * * \param[in] curr - raw current value of register * \retval res - converted raw current to uamps - Signed 2's complement * */ int MAX17055::raw_current_to_uamps(uint32_t curr, int rsense_value) { int res = curr; /* Negative */ if (res & 0x8000) { res |= 0xFFFF0000; } else { res *= 1562500 /(rsense_value * 1000); //Change to interact with the rsense of customer } return res; }