-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* implement max17261 driver * fix LSB, add comments * add back uint8_t* cast --------- Co-authored-by: Preston Dresser <pgdresse@uwaterloo.ca>
- Loading branch information
Showing
3 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#pragma once | ||
#include <stdint.h> | ||
|
||
#include "i2c.h" | ||
#include "max17261_fuel_gauge_defs.h" | ||
|
||
/* Notes: | ||
* 3 things are required for configuring the max17261: | ||
* - Design Capacity (in milliamp hours) | ||
* - Empty Voltage | ||
* - Charge Termination Current | ||
* | ||
* Some of the units of the registers (like capacity and current) depend on RSense, | ||
* it looks like max17261 automatically determines this value, it should be provided | ||
* to the driver for conversions from register values to actual units | ||
* | ||
* See data sheet P.15 for more info on how registers are formatted | ||
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max17261.pdf | ||
*/ | ||
|
||
typedef struct { | ||
I2CPort i2c_port; | ||
I2CAddress i2c_address; | ||
|
||
uint16_t design_capacity; // LSB = 5.0 (micro Volt Hours / R Sense) | ||
uint16_t empty_voltage; // Only a 9-bit field, LSB = 78.125 (micro Volts) | ||
uint16_t charge_term_current; // LSB = 1.5625 (micro Volts / R Sense) | ||
|
||
uint16_t r_sense_ohms; | ||
} Max17261Settings; | ||
|
||
typedef struct { | ||
Max17261Settings settings; | ||
} Max17261Storage; | ||
|
||
/* @brief Gets the current state of charge given by the max17261 in percentage | ||
* @param storage - a pointer to an already initialized Max17261Storage struct | ||
* @param soc_pct - state of charge in percentage will be returned in this var | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_state_of_charge(Max17261Storage *storage, uint16_t *soc_pct); | ||
|
||
/* @brief Gets the current remaining capactity in micro amp hours | ||
* @param storage - a pointer to an already initialized Max17261Storage struct | ||
* @param soc_pct - remaining capactity in micro amp hours returned in this var | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_uAhr); | ||
|
||
/* @brief Gets the full charge capacity of the battery in micro amp hours | ||
* @param storage - a pointer to an already initialized Max17261Storage struct | ||
* @param soc_pct - full charge capacitry in micro amp hours returned in this var | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_full_capacity(Max17261Storage *storage, uint16_t *full_cap_uAhr); | ||
|
||
/* @brief Gets the time to empty in milliseconds | ||
* @param storage - a pointer to an already initialized Max17261Storage struct | ||
* @param soc_pct - time to empty in milliseconds returned in this var | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_time_to_empty(Max17261Storage *storage, uint16_t *tte_ms); | ||
|
||
/* @brief Gets the time to full in milliseconds | ||
* @param storage - a pointer to an already initialized Max17261Storage struct | ||
* @param soc_pct - time to full in milliseconds returned in this var | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_time_to_full(Max17261Storage *storage, uint16_t *ttf_ms); | ||
|
||
/* @brief Gets the time to full in milliseconds | ||
* @param storage - a pointer to an uninitialized Max17261Storage struct | ||
* @param settings - populated settings struct | ||
* @return STATUS_CODE_OK on success | ||
*/ | ||
StatusCode max17261_init(Max17261Storage *storage, Max17261Settings settings); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#pragma once | ||
// reg map is on P.27: | ||
// https://www.analog.com/media/en/technical-documentation/user-guides/max1726x-modelgauge-m5-ez-user-guide.pdf | ||
typedef enum { | ||
MAX17261_STATUS = 0x00, | ||
MAX17261_VOLT_ALRT_THRSH, | ||
MAX17261_TEMP_ALRT_THRSH, | ||
MAX17261_SOC_ALRT_THRSH, | ||
MAX17261_AT_RATE, | ||
MAX17261_CAP, | ||
MAX17261_SOC, | ||
MAX17261_AGE, | ||
MAX17261_TEMP, | ||
MAX17261_VCELL, | ||
MAX17261_CURRENT, | ||
MAX17261_AVG_CURRENT, | ||
MAX17261_Q_RESIDUAL, | ||
MAX17261_MIX_SOC, | ||
MAX17261_AV_SOC, | ||
MAX17261_MIX_CAP, | ||
|
||
MAX17261_FULL_CAP_REP = 0x10, | ||
MAX17261_TIME_TO_EMPTY, | ||
MAX17261_QR_TABLE00, | ||
MAX17261_FULL_SOC_THRSH, | ||
MAX17261_R_CELL, | ||
MAX17261_AVG_TA = 0x16, | ||
MAX17261_CYCLES, | ||
MAX17261_DESIGN_CAP, | ||
MAX17261_AVG_V_CELL, | ||
MAX17261_MAX_MIN_TEMP, | ||
MAX17261_MAX_MIN_VOLT, | ||
MAX17261_MAX_MIN_CURR, | ||
MAX17261_CONFIG, | ||
MAX17261_I_CHG_TERM, | ||
MAX17261_AV_CAP, | ||
|
||
MAX17261_TIME_TO_FULL = 0x20, | ||
MAX17261_DEV_NAME, | ||
MAX17261_QR_TABLE10, | ||
MAX17261_FULL_CAP_NOM, | ||
MAX17261_AIN = 0x27, | ||
MAX17261_LEARN_CFG, | ||
MAX17261_FILTER_CFG, | ||
MAX17261_RELAX_CFG, | ||
MAX17261_MISC_CFG, | ||
MAX17261_T_GAIN, | ||
MAX17261_T_OFF, | ||
MAX17261_C_GAIN, | ||
MAX17261_C_OFF, | ||
|
||
MAX17261_QR_TABLE20 = 0x32, | ||
MAX17261_DIE_TEMP = 0x34, | ||
MAX17261_FULL_CAP, | ||
MAX17261_R_COMP0 = 0x38, | ||
MAX17261_TEMP_CO, | ||
MAX17261_V_EMPTY, | ||
MAX17261_FSTAT = 0x3D, | ||
MAX17261_TIMER, | ||
MAX17261_SHDN_TIMER, | ||
|
||
MAX17261_QR_TABLE30 = 0x42, | ||
MAX17261_R_GAIN, | ||
MAX17261_DQ_ACC = 0x45, | ||
MAX17261_DP_ACC, | ||
MAX17261_CONVG_CFG = 0x49, | ||
MAX17261_VF_REM_CAP, | ||
MAX17261_QH = 0x4D, | ||
|
||
MAX17261_STATUS2 = 0xB0, | ||
MAX17261_POWER, | ||
MAX17261_ID, // UserMem2 | ||
MAX17261_AVG_POWER, | ||
MAX17261_I_ALRT_TH, | ||
MAX17261_TTF_CFG, | ||
MAX17261_CV_MIX_CAP, | ||
MAX17261_CV_HALF_TIME, | ||
MAX17261_CG_TEMP_CO, | ||
MAX17261_CURVE, | ||
MAX17261_HIB_CFG, | ||
MAX17261_CONFIG2, | ||
MAX17261_VRIPPLE, | ||
MAX17261_RIPPLE_CFG, | ||
MAX17261_TIMERH, | ||
|
||
MAX17261_RSENSE = 0xD0, // UserMem3 | ||
MAX17261_SC_OCV_LIM, | ||
MAX17261_VGAIN, | ||
MAX17261_SOC_HOLD, | ||
MAX17261_MAX_PEAK_POWER, | ||
MAX17261_SUS_PEAK_POWER, | ||
MAX17261_PACK_RESISTANCE, | ||
MAX17261_SYS_RESISTANCE, | ||
MAX17261_MIN_SYS_VOLTAGE, | ||
MAX17261_MPP_CURRENT, | ||
MAX17261_SPP_CURRENT, | ||
MAX17261_MODEL_I_CFG, | ||
MAX17261_AT_Q_RESIDUAL, | ||
MAX17261_AT_TTE, | ||
MAX17261_AT_AV_SOC, | ||
MAX17261_AT_AV_CAP, | ||
} Max17261Registers; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#include "max17261_fuel_gauge.h" | ||
|
||
#define PCT_LSB (1.0 / 256) // LSBit is 1/256% | ||
#define CAP_LSB (5.0 / storage->settings.r_sense_ohms) // LSBit is 5 micro Volt hrs / Rsense | ||
#define TIM_LSB (5625U) // LSBit is 5625ms | ||
|
||
StatusCode max17261_get_reg(Max17261Storage *storage, Max17261Registers reg, uint16_t *value) { | ||
// unsure of underlying type of enum, cast to uint8_t to be sure | ||
uint8_t reg8 = reg; | ||
status_ok_or_return( | ||
i2c_write(storage->settings.i2c_port, storage->settings.i2c_address, ®8, sizeof(uint8_t))); | ||
// TODO: max17261 sends LSByte then MSByte, need to check if bytes are correctly written to | ||
status_ok_or_return(i2c_read(storage->settings.i2c_port, storage->settings.i2c_address, | ||
(uint8_t *)value, sizeof(uint16_t))); | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_set_reg(Max17261Storage *storage, Max17261Registers reg, uint16_t value) { | ||
uint8_t buf[3]; | ||
buf[0] = reg; | ||
// send LSByte then MSByte as per datasheet | ||
buf[1] = value & 0x00FF; | ||
buf[2] = value >> 8; | ||
status_ok_or_return( | ||
i2c_write(storage->settings.i2c_port, storage->settings.i2c_address, buf, sizeof(buf))); | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_state_of_charge(Max17261Storage *storage, uint16_t *soc_pct) { | ||
uint16_t soc_reg_val = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_SOC, &soc_reg_val)); | ||
*soc_pct = soc_reg_val * PCT_LSB; | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_uAhr) { | ||
uint16_t rem_cap_reg_val = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_CAP, &rem_cap_reg_val)); | ||
*rem_cap_uAhr = rem_cap_reg_val * CAP_LSB; | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_full_capacity(Max17261Storage *storage, uint16_t *full_cap_uAhr) { | ||
uint16_t full_cap_reg_val = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_FULL_CAP_REP, &full_cap_reg_val)); | ||
*full_cap_uAhr = full_cap_reg_val * CAP_LSB; | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_time_to_empty(Max17261Storage *storage, uint16_t *tte_ms) { | ||
uint16_t tte_reg_val = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_TIME_TO_EMPTY, &tte_reg_val)); | ||
*tte_ms = tte_reg_val * TIM_LSB; | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_time_to_full(Max17261Storage *storage, uint16_t *ttf_ms) { | ||
uint16_t ttf_reg_val = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_TIME_TO_FULL, &ttf_reg_val)); | ||
*ttf_ms = ttf_reg_val * TIM_LSB; | ||
return STATUS_CODE_OK; | ||
} | ||
|
||
StatusCode max17261_init(Max17261Storage *storage, Max17261Settings settings) { | ||
if (settings.i2c_port >= NUM_I2C_PORTS) { | ||
return STATUS_CODE_INVALID_ARGS; | ||
} | ||
|
||
storage->settings = settings; | ||
|
||
status_ok_or_return(max17261_set_reg(storage, MAX17261_DESIGN_CAP, settings.design_capacity)); | ||
status_ok_or_return(max17261_set_reg(storage, MAX17261_I_CHG_TERM, settings.charge_term_current)); | ||
uint16_t old_vempty = 0; | ||
status_ok_or_return(max17261_get_reg(storage, MAX17261_V_EMPTY, &old_vempty)); | ||
// the 7 LSBits of the vempty reg is the recovery voltage, the last 9 are the empty voltage | ||
uint16_t new_vempty = (settings.empty_voltage << 7) + (old_vempty & 0x7F); | ||
status_ok_or_return(max17261_set_reg(storage, MAX17261_V_EMPTY, new_vempty)); | ||
|
||
return STATUS_CODE_OK; | ||
} |