portapack-mayhem/firmware/common/max17055.cpp
jLynx 7feef9d38b
Learn ic fix (#2253)
* WIP

* Fixed merge

* Added test code

* WIP

* Clean up

* add reset learned params

* ui fix

* ui fix2

* Updated func

* Fixed english

* WIP

* WIP testing

* Added new debug app

* Got new app for debug

* Got new app for debug

* Got one full page showing

* Got app working with all reg

* Got app working with all reg

* Got full hex showing

* Fixed dp

* Fixed dp

* Moved entities

* Enabled apps again

* SHow battery debug if ic

* WIP

* Refactored further

* WIP

* Refactor and clean up

* Refactor and clean up

* fix warning, add tte/ttf, add cycles counter.

* wip

* morse tx to ext app

* fix morse crash

* fix ui

* Updated wording

* WIP

* WIP

* Updated to display hours and minutes

---------

Co-authored-by: HTotoo <ttotoo@gmail.com>
2024-09-20 09:59:17 +00:00

625 lines
27 KiB
C++

/*
Copyright (C) 2024 jLynx.
*
This file is part of PortaPack.
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street,
Boston, MA 02110-1301, USA.
*/
#include "max17055.hpp"
#include "utility.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <algorithm>
#include <cstdint>
namespace battery {
namespace max17055 {
const RegisterEntry MAX17055::entries[] = {
{"Status", 0x00, "", 1, false, "", false, 0, true, false, false, 0, false},
{"VAlrtTh", 0x01, "", 1, false, "", false, 0, true, false, false, 0, false},
{"TAlrtTh", 0x02, "", 1, false, "", false, 0, true, false, false, 0, false},
{"SAlrtTh", 0x03, "", 1, false, "", false, 0, true, false, false, 0, false},
{"AtRate", 0x04, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"RepCap", 0x05, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"RepSOC", 0x06, "percent", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"Age", 0x07, "percent", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"Temp", 0x08, "temperature", 0.00390625, true, "C", true, 6, true, false, false, 0, false},
{"VCell", 0x09, "voltage", 0.000078125, false, "V", true, 9, true, false, false, 0, false},
{"Current", 0x0A, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"AvgCurrent", 0x0B, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"QResidual", 0x0C, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"MixSOC", 0x0D, "percent", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"AvSOC", 0x0E, "percent", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"MixCap", 0x0F, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"FullCapRep", 0x10, "capacity", 0.5, false, "mAh", true, 1, true, true, false, 0, false},
{"TTE", 0x11, "time", 0.0015625, false, "hr", true, 6, true, false, false, 0, false},
{"QRTable00", 0x12, "model", 1, false, "", false, 0, true, true, false, 0, false},
{"FullSocThr", 0x13, "model", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"RCell", 0x14, "resistance", 0.244140625, false, "mOhms", false, 6, true, false, false, 0, false},
{"Reserved", 0x15, "", 0.244140625, false, "mOhms", false, 6, true, false, false, 0, true},
{"AvgTA", 0x16, "temperature", 0.00390625, true, "C", true, 6, true, false, false, 0, false},
{"Cycles", 0x17, "cycles", 0.01, false, "Cycles", false, 2, true, true, false, 0, false},
{"DesignCap", 0x18, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"AvgVCell", 0x19, "voltage", 0.000078125, false, "V", true, 9, true, false, false, 0, false},
{"MaxMinTemp", 0x1A, "", 1, false, "", false, 0, true, false, false, 0, false},
{"MaxMinVolt", 0x1B, "", 1, false, "", false, 0, true, false, false, 0, false},
{"MaxMinCurr", 0x1C, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Config", 0x1D, "model", 1, false, "", false, 0, true, false, false, 0, false},
{"IChgTerm", 0x1E, "model", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"AvCap", 0x1F, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"TTF", 0x20, "time", 0.0015625, false, "hr", true, 6, true, false, false, 0, false},
{"DevName", 0x21, "", 1, false, "", false, 0, true, false, false, 0, false},
{"QRTable10", 0x22, "model", 1, false, "", false, 0, true, true, false, 0, false},
{"FullCapNom", 0x23, "capacity", 0.5, false, "mAh", true, 1, true, true, false, 0, false},
{"Reserved", 0x24, "", 0.00390625, true, "C", true, 6, true, false, false, 0, true},
{"Reserved", 0x25, "", 0.00390625, true, "C", true, 6, true, false, false, 0, true},
{"Reserved", 0x26, "", 0.00390625, true, "C", true, 6, true, false, false, 0, true},
{"AIN", 0x27, "temperature", 0.0015259, false, "%", true, 6, true, false, false, 0, false},
{"LearnCfg", 0x28, "model", 1, false, "", false, 0, true, false, false, 0, false},
{"FilterCfg", 0x29, "model", 1, false, "", false, 0, true, false, false, 0, false},
{"RelaxCfg", 0x2A, "model", 1, false, "", false, 0, true, false, false, 0, false},
{"MiscCfg", 0x2B, "model", 1, false, "", false, 0, true, false, false, 0, false},
{"TGain", 0x2C, "temperature", 1, false, "", false, 0, true, false, false, 0, false},
{"TOff", 0x2D, "temperature", 1, false, "", false, 0, true, false, false, 0, false},
{"CGain", 0x2E, "current", 0.09765625, true, "%", true, 8, true, false, false, 0, false},
{"COff", 0x2F, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"Reserved", 0x30, "", 0.00125, false, "V", true, 5, true, false, false, 0, true},
{"Reserved", 0x31, "", 0.005, true, "mA", true, 3, true, false, false, 0, true},
{"QRTable20", 0x32, "model", 1, false, "", false, 0, true, true, false, 0, false},
{"Reserved", 0x33, "", 0.0015625, false, "hr", true, 6, true, true, false, 0, true},
{"DieTemp", 0x34, "temperature", 0.00390625, true, "C", true, 6, true, false, false, 0, false},
{"FullCap", 0x35, "model", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"Reserved", 0x36, "", 0.15625, true, "mA", true, 5, true, false, false, 0, true},
{"Reserved", 0x37, "led", 1, false, "", false, 0, true, true, false, 0, false},
{"RComp0", 0x38, "model", 1, false, "", false, 0, true, true, false, 0, false},
{"TempCo", 0x39, "model", 1, false, "", false, 0, true, true, false, 0, false},
{"VEmpty", 0x3A, "model", 0.000078125, false, "", false, 1, true, false, false, 0, false},
{"Reserved", 0x3B, "", 0.15625, true, "mA", true, 5, true, false, false, 0, true},
{"Reserved", 0x3C, "", 0.000976563, false, "s", true, 6, true, false, false, 0, true},
{"FStat", 0x3D, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Timer", 0x3E, "time", 4.88E-05, false, "hr", true, 7, true, false, false, 0, false},
{"ShdnTimer", 0x3F, "", 0.000366, false, "hr", true, 6, true, false, false, 0, false},
{"UserMem1", 0x40, "led", 1, false, "", false, 0, true, false, false, 0, false},
{"Reserved", 0x41, "", 1, false, "", false, 0, true, false, false, 0, true},
{"QRTable30", 0x42, "model", 0.15625, false, "", false, 0, true, true, false, 0, false},
{"RGain", 0x43, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Reserved", 0x44, "", 0.000078125, false, "V", true, 9, true, false, false, 0, true},
{"dQAcc", 0x45, "capacity", 16, false, "mAh", true, 0, true, true, false, 0, false},
{"dPAcc", 0x46, "percent", 0.0625, false, "%", true, 4, true, true, false, 0, false},
{"Reserved", 0x47, "", 0.00390625, true, "%", true, 6, true, true, false, 0, true},
{"Reserved", 0x48, "", 0.00390625, false, "%", true, 6, true, true, false, 0, true},
{"ConvgCfg", 0x49, "", 1, false, "", false, 0, true, false, false, 0, false},
{"VFRemCap", 0x4A, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"Reserved", 0x4B, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Reserved", 0x4C, "", 0.5, true, "mAh", true, 1, true, false, false, 0, true},
{"QH", 0x4D, "capacity", 0.5, true, "mAh", true, 1, true, false, false, 0, false},
{"Reserved", 0x4E, "", 7.63E-06, false, "mAh", true, 8, true, false, false, 0, true},
{"Reserved", 0x4F, "", 0.5, false, "mAh", true, 1, true, false, false, 0, true},
{"Status2", 0xB0, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Power", 0xB1, "", 0.8, true, "", false, 1, true, false, false, 0, false},
{"ID", 0xB2, "", 1, false, "", false, 0, true, false, false, 0, false},
{"AvgPower", 0xB3, "", 0.8, true, "", false, 1, true, false, false, 0, false},
{"IAlrtTh", 0xB4, "", 1, false, "", false, 0, true, false, false, 0, false},
{"TTFCfg", 0xB5, "", 1, false, "", false, 0, true, false, false, 0, false},
{"CVMixCap", 0xB6, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"CVHalfTime", 0xB7, "time", 0.000195313, false, "hr", true, 6, true, false, false, 0, false},
{"CGTempCo", 0xB8, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Curve", 0xB9, "", 1, false, "", false, 0, true, false, false, 0, false},
{"HibCfg", 0xBA, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Config2", 0xBB, "", 1, false, "", false, 0, true, false, false, 0, false},
{"VRipple", 0xBC, "voltage", 9.77E-06, false, "V", true, 8, true, false, false, 0, false},
{"RippleCfg", 0xBD, "", 1, false, "", false, 0, true, false, false, 0, false},
{"TimerH", 0xBE, "time", 3.2, false, "hr", true, 1, true, false, false, 0, false},
{"Reserved", 0xBF, "", 0.00390625, false, "%", true, 6, true, false, false, 0, true},
{"Rsense", 0xD0, "", 1, false, "", false, 0, true, false, false, 0, false},
{"ScOcvLim", 0xD1, "", 1, false, "", false, 0, true, false, false, 0, false},
{"Reserved", 0xD2, "", 1, false, "", false, 0, true, false, false, 0, true},
{"SOCHold", 0xD3, "", 1, false, "", false, 0, true, false, false, 0, false},
{"MaxPeakPower", 0xD4, "", 0.8, true, "", false, 0, true, false, false, 0, false},
{"SusPeakPower", 0xD5, "", 0.8, true, "", false, 0, true, false, false, 0, false},
{"PackResistance", 0xD6, "", 0.244141063, false, "", false, 0, true, false, false, 0, false},
{"SysResistance", 0xD7, "", 0.244141063, false, "", false, 0, true, false, false, 0, false},
{"MinSysVoltage", 0xD8, "", 0.000078125, false, "", false, 0, true, false, false, 0, false},
{"MPPCurrent", 0xD9, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"SPPCurrent", 0xDA, "current", 0.15625, true, "mA", true, 5, true, false, false, 0, false},
{"ModelCfg", 0xDB, "", 1, false, "", false, 0, true, false, false, 0, false},
{"AtQResidual", 0xDC, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"AtTTE", 0xDD, "time", 0.0015625, false, "hr", true, 6, true, false, false, 0, false},
{"AtAvSOC", 0xDE, "percent", 0.00390625, false, "%", true, 6, true, false, false, 0, false},
{"AtAvCap", 0xDF, "capacity", 0.5, false, "mAh", true, 1, true, false, false, 0, false},
{"Reserved", 0xE0, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE1, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE2, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE3, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE4, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE5, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE6, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE7, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE8, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xE9, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xEA, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xEB, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xEC, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xED, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xEE, "voltage", 0.000078125, false, "V", true, 9, true, false, false, 0, true},
{"Reserved", 0xEF, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF0, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF1, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF2, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF3, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF4, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF5, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xF6, "", 0.00390625, false, "%", true, 6, true, false, false, 0, true},
{"Reserved", 0xF7, "", 0.001, true, "s", true, 3, true, false, false, 0, true},
{"Reserved", 0xF8, "", 0.003051758, true, "C", true, 6, true, false, false, 0, true},
{"Reserved", 0xF9, "", 0.00015625, false, "V", true, 6, true, false, false, 0, true},
{"Reserved", 0xFA, "", 0.15625, true, "mA", true, 5, true, false, false, 0, true},
{"Reserved", 0xFB, "", 0.000078125, false, "V", true, 9, true, false, false, 0, true},
{"Reserved", 0xFC, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xFD, "", 1, false, "", false, 0, true, false, false, 0, true},
{"Reserved", 0xFE, "", 0.000078125, false, "V", true, 9, true, false, false, 0, true},
{"Reserved", 0xFF, "", 0.00390625, false, "%", true, 6, true, false, false, 0, true},
};
void MAX17055::init() {
if (!detected_) {
detected_ = detect();
}
if (detected_) {
if (needsInitialization()) {
// First-time or POR initialization
full_reset_and_init();
} else {
// Subsequent boot
partialInit();
}
partialInit();
// statusClear(); I am not sure if this should be here or not
}
}
bool MAX17055::full_reset_and_init() {
if (!soft_reset()) {
return false;
}
if (!initialize_custom_parameters()) {
return false;
}
if (!load_custom_parameters()) {
return false;
}
if (!clear_por()) {
return false;
}
return true;
}
bool MAX17055::soft_reset() {
return write_register(0x0BB, 0x0000);
}
bool MAX17055::initialize_custom_parameters() {
if (!write_register(0xD0, 0x03E8)) return false; // Unknown register, possibly related to battery profile
if (!write_register(0xDB, 0x0000)) return false; // ModelCfg
if (!write_register(0x05, 0x0000)) return false; // RepCap
if (!write_register(0x18, 0x1388)) return false; // DesignCap
if (!write_register(0x45, 0x009C)) return false; // dQAcc
if (!write_register(0x1E, 0x03C0)) return false; // IChgTerm
if (!write_register(0x3A, 0x9661)) return false; // VEmpty
if (!write_register(0x60, 0x0090)) return false; // Unknown register
if (!write_register(0x46, 0x0561)) return false; // dPAcc
if (!write_register(0xDB, 0x8000)) return false; // ModelCfg
if (!write_register(0x40, 0x0001)) return false; // Set user mem to 1
return true;
}
bool MAX17055::load_custom_parameters() {
uint16_t hib_cfg = read_register(0xBA);
if (!write_register(0xBA, 0x0000)) return false; // Disable hibernate mode
if (!write_register(0x60, 0x0000)) return false; // Unknown register
// Wait for the model to be loaded
for (int i = 0; i < 10; i++) {
uint16_t model_cfg = read_register(0xDB);
if ((model_cfg & 0x8000) == 0) {
break;
}
chThdSleepMilliseconds(10);
}
if (!write_register(0xBA, hib_cfg)) return false; // Restore hibernate config
return true;
}
bool MAX17055::clear_por() {
uint16_t status = read_register(0x00);
status &= ~(1 << 1);
return write_register(0x00, status);
}
bool MAX17055::needsInitialization() {
uint16_t UserMem1 = read_register(0x40);
if (UserMem1 == 0) {
return true;
}
return false;
}
void MAX17055::partialInit() {
// Only update necessary volatile settings
setHibCFG(0x0000); // If you always want hibernation disabled
// Add any other volatile settings that need updating
}
bool MAX17055::reset_learned() {
// this if for reset all the learned parameters by ic
// the full inis should do this
full_reset_and_init();
return true;
}
bool MAX17055::detect() {
// Read the DevName register (0x21)
uint16_t dev_name = read_register(0x21);
// The DevName register should return 0x4010 for MAX17055
if (dev_name == 0x4010) {
detected_ = true;
return true;
}
// If DevName doesn't match, try reading Status register as a fallback
uint16_t status = read_register(0x00);
if (status != 0xFFFF && status != 0x0000) {
detected_ = true;
return true;
}
detected_ = false;
return false;
}
const RegisterEntry* MAX17055::findEntry(const char* name) const {
for (const auto& entry : entries) {
if (std::strcmp(entry.name, name) == 0) {
return &entry;
}
}
return nullptr;
}
uint16_t MAX17055::read_register(const uint8_t reg) {
const std::array<uint8_t, 1> tx{reg};
std::array<uint8_t, 2> rx{0x00, 0x00};
bus.transmit(bus_address, tx.data(), tx.size());
bus.receive(bus_address, rx.data(), rx.size());
// Combine the two bytes into a 16-bit value
// little-endian format (LSB first)
return static_cast<uint16_t>((rx[1] << 8) | rx[0]);
}
bool MAX17055::write_register(const uint8_t reg, const uint16_t value) {
std::array<uint8_t, 3> tx;
tx[0] = reg;
tx[1] = value & 0xFF; // Low byte
tx[2] = (value >> 8) & 0xFF; // High byte
bool success = bus.transmit(bus_address, tx.data(), tx.size());
chThdSleepMilliseconds(1);
return success;
}
void MAX17055::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
if (detected_) {
// Read Status Register
uint16_t status = read_register(0x00);
voltage = averageMVoltage();
if ((status == 0 && voltage == 0) || (status == 0x0002 && voltage == 3600) || (status == 0x0002 && voltage == 0)) {
valid_mask = 0;
return;
}
batteryPercentage = stateOfCharge();
current = instantCurrent();
valid_mask = 31; // BATT_VALID_VOLTAGE + CURRENT + PERCENT + BATT_VALID_CYCLES + BATT_VALID_TTEF
} else {
// let's indicate the data is wrong. ui will handle this by display UNK values.
valid_mask = 0;
}
}
float MAX17055::getValue(const char* entityName) {
const RegisterEntry* entry = findEntry(entityName);
if (entry) {
uint16_t raw_value = read_register(entry->address);
float scaled_value;
if (entry->is_signed) {
int16_t signed_value = static_cast<int16_t>(raw_value);
scaled_value = signed_value * entry->scalar;
} else {
scaled_value = raw_value * entry->scalar;
}
return scaled_value;
}
return 0; // Return 0 if entry not found
}
uint16_t MAX17055::averageMVoltage(void) {
return static_cast<uint16_t>(getValue("AvgVCell") * 1000.0f); // Convert to millivolts
}
int32_t MAX17055::instantCurrent(void) {
return getValue("Current");
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x0A);
// Convert to signed int16_t (two's complement)
int32_t _Signed_Raw = static_cast<int16_t>(_Measurement_Raw);
int32_t _Value = (_Signed_Raw * 15625) / (__MAX17055_Resistor__ * 100) / 100000;
// End Function
return _Value;
}
uint16_t MAX17055::stateOfCharge(void) {
return getValue("RepSOC");
}
bool MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
// Calculate the new VE_Empty value (upper 9 bits)
uint16_t ve_empty = ((_Empty_Voltage * 100) / 10) & 0xFF80;
// Read the current register value
uint16_t current_value = read_register(0x3A);
// Preserve the lower 7 bits (VR_Empty) and combine with new VE_Empty
uint16_t new_value = (ve_empty & 0xFF80) | (current_value & 0x007F);
// Write the new value back to the register
return write_register(0x3A, new_value);
}
bool MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
// Calculate the new VR_Empty value (lower 7 bits)
uint16_t vr_empty = (_Recovery_Voltage * 25) & 0x007F; // 40mV per bit, 25 = 1000/40
// Read the current register value
uint16_t current_value = read_register(0x3A);
// Preserve the upper 9 bits (VE_Empty) and combine with new VR_Empty
uint16_t new_value = (current_value & 0xFF80) | vr_empty;
// Write the new value back to the register
return write_register(0x3A, new_value);
}
bool MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
uint16_t current_value = read_register(0x01);
uint16_t min_voltage_raw = (_Minimum_Voltage * 50) & 0x00FF; // 20mV per bit, 50 = 1000/20
uint16_t new_value = (current_value & 0xFF00) | min_voltage_raw;
return write_register(0x01, new_value);
}
bool MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
uint16_t current_value = read_register(0x01);
uint16_t max_voltage_raw = ((_Maximum_Voltage * 50) & 0x00FF) << 8; // 20mV per bit, 50 = 1000/20
uint16_t new_value = (current_value & 0x00FF) | max_voltage_raw;
return write_register(0x01, new_value);
}
bool MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
uint16_t current_value = read_register(0xB4);
uint16_t max_current_raw = ((_Maximum_Current * 25) & 0x00FF) << 8; // 40mV per bit, 25 = 1000/40
uint16_t new_value = (current_value & 0x00FF) | max_current_raw;
return write_register(0xB4, new_value);
}
bool MAX17055::setChargeTerminationCurrent(uint16_t _Charge_Termination_Current) {
float lsb_mA = 1.5625 / (__MAX17055_Resistor__ * 1000); // Convert to mA
uint16_t ichgterm_value = static_cast<uint16_t>(round(_Charge_Termination_Current / lsb_mA));
return write_register(0x1E, ichgterm_value);
}
bool MAX17055::setDesignCapacity(const uint16_t _Capacity) {
uint16_t raw_cap = (uint16_t)_Capacity * 2;
return write_register(0x18, raw_cap);
}
bool MAX17055::setFullCapRep(const uint16_t _Capacity) {
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
return write_register(0x10, raw_cap);
}
bool MAX17055::setFullCapNom(const uint16_t _Capacity) {
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
return write_register(0x23, raw_cap);
}
bool MAX17055::setRepCap(const uint16_t _Capacity) {
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
return write_register(0x05, raw_cap);
}
bool MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
uint16_t current_value = read_register(0x03);
uint16_t min_soc_raw = ((_Minimum_SOC * 256) / 100) & 0x00FF;
uint16_t new_value = (current_value & 0xFF00) | min_soc_raw;
return write_register(0x03, new_value);
}
bool MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
uint16_t current_value = read_register(0x03);
uint16_t max_soc_raw = (((_Maximum_SOC * 256) / 100) & 0x00FF) << 8;
uint16_t new_value = (current_value & 0x00FF) | max_soc_raw;
return write_register(0x03, new_value);
}
bool MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
uint16_t current_value = read_register(0x02);
uint16_t min_temp_raw = (uint8_t)_Minimum_Temperature;
uint16_t new_value = (current_value & 0xFF00) | min_temp_raw;
return write_register(0x02, new_value);
}
bool MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
uint16_t current_value = read_register(0x02);
uint16_t max_temp_raw = ((uint8_t)_Maximum_Temperature) << 8;
uint16_t new_value = (current_value & 0x00FF) | max_temp_raw;
return write_register(0x02, new_value);
}
bool MAX17055::setModelCfg(const uint8_t _Model_ID) {
uint16_t model_cfg = 0x0400; // Set Charge Voltage (bit 10)
// Set Battery Model
switch (_Model_ID) {
case 0: // Default model
break;
case 2: // EZ model
model_cfg |= 0x0020;
break;
case 6: // Short EZ model
model_cfg |= 0x0060;
break;
default:
return false; // Invalid model ID
}
return write_register(0xDB, model_cfg);
}
bool MAX17055::setHibCFG(const uint16_t _Config) {
return write_register(0xBA, _Config);
}
void MAX17055::config(void) {
uint16_t config1 = 0x0000;
uint16_t config2 = 0x0618; // Default value: 0b00011000 00000110
// Set Configuration bits [Config1]
if (MAX17055_Ber) config1 |= 0x0001;
if (MAX17055_Bei) config1 |= 0x0002;
if (MAX17055_Aen) config1 |= 0x0004;
if (MAX17055_FTHRM) config1 |= 0x0008;
if (MAX17055_ETHRM) config1 |= 0x0010;
if (MAX17055_COMMSH) config1 |= 0x0040;
if (MAX17055_SHDN) config1 |= 0x0080;
if (MAX17055_Tex) config1 |= 0x0100;
if (MAX17055_Ten) config1 |= 0x0200;
if (MAX17055_AINSH) config1 |= 0x0400;
if (MAX17055_IS) config1 |= 0x0800;
if (MAX17055_VS) config1 |= 0x1000;
if (MAX17055_TS) config1 |= 0x2000;
if (MAX17055_SS) config1 |= 0x4000;
if (MAX17055_TSel) config1 |= 0x8000;
// Set Configuration bits [Config2]
if (MAX17055_CPMode) config2 |= 0x0002;
if (MAX17055_LDMDL) config2 |= 0x0020;
if (MAX17055_TAIrtEN) config2 |= 0x0040;
if (MAX17055_dSOCen) config2 |= 0x0080;
if (MAX17055_DPEn) config2 |= 0x1000;
if (MAX17055_AtRateEn) config2 |= 0x2000;
// Write configurations to registers
write_register(0x1D, config1);
write_register(0xBB, config2);
}
bool MAX17055::statusClear() {
// Clear all bits in the Status register (0x00)
return write_register(0x00, 0x0000);
}
bool bitRead(uint8_t value, uint8_t bit) {
return (value >> bit) & 0x01;
}
bool MAX17055::statusControl(const uint8_t _Status) {
// Read Status Register (0x00)
uint16_t status_register = read_register(0x00);
// Control for Status
switch (_Status) {
case MAX17055_POR:
return bitRead(status_register & 0xFF, 1);
case MAX17055_IMin:
return bitRead(status_register & 0xFF, 2);
case MAX17055_IMax:
return bitRead(status_register & 0xFF, 6);
case MAX17055_SOC_Change:
return bitRead(status_register & 0xFF, 7);
case MAX17055_Bat_Status:
return bitRead(status_register & 0xFF, 3);
case MAX17055_VMin:
return bitRead(status_register >> 8, 0);
case MAX17055_VMax:
return bitRead(status_register >> 8, 4);
case MAX17055_TMin:
return bitRead(status_register >> 8, 1);
case MAX17055_TMax:
return bitRead(status_register >> 8, 5);
case MAX17055_SOC_Min:
return bitRead(status_register >> 8, 2);
case MAX17055_SOC_Max:
return bitRead(status_register >> 8, 6);
case MAX17055_Bat_Insert:
return bitRead(status_register >> 8, 3);
case MAX17055_Bat_Remove:
return bitRead(status_register >> 8, 7);
default:
return false;
}
}
} /* namespace max17055 */
} // namespace battery