max17055
This commit is contained in:
jLynx 2024-07-16 08:17:55 +12:00 committed by GitHub
parent 9ef58b7763
commit ae75540d35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1122 additions and 18 deletions

View File

@ -177,6 +177,7 @@ set(CPPSRC
${COMMON}/utility.cpp
${COMMON}/wm8731.cpp
${COMMON}/ads1110.cpp
${COMMON}/max17055.cpp
${COMMON}/battery.cpp
${COMMON}/performance_counter.cpp
${COMMON}/bmpfile.cpp

View File

@ -53,7 +53,7 @@ void BattinfoView::update_result() {
return;
}
bool uichg = false;
battery::BatteryManagement::getBatteryInfo(percent, voltage, current, isCharging);
battery::BatteryManagement::getBatteryInfo(percent, voltage, current);
// update text fields
if (percent <= 100)
text_percent.set(to_string_dec_uint(percent) + " %");
@ -69,8 +69,8 @@ void BattinfoView::update_result() {
labels_opt.hidden(false);
text_current.hidden(false);
text_charge.hidden(false);
text_current.set(to_string_dec_int(current) + " mA");
text_charge.set(isCharging ? "charge" : "discharge");
text_current.set(to_string_decimal(current / 100000.0, 3) + " mA");
text_charge.set(current >= 0 ? "Charging" : "Discharging");
labels_opt.hidden(false);
} else {
if (!labels_opt.hidden()) uichg = true;
@ -80,7 +80,7 @@ void BattinfoView::update_result() {
}
if (uichg) set_dirty();
// to update status bar too, send message in behalf of batt manager
BatteryStateMessage msg{percent, isCharging, voltage};
BatteryStateMessage msg{percent, current >= 0, voltage};
EventDispatcher::send_message(msg);
}

View File

@ -50,7 +50,6 @@ class BattinfoView : public View {
uint8_t percent = 0;
uint16_t voltage = 0;
int32_t current = 0;
bool isCharging = false;
Labels labels{
{{2 * 8, 1 * 16}, "Percent:", Theme::getInstance()->fg_light->foreground},

View File

@ -225,6 +225,8 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) {
return radio::debug::second_if::register_read(register_number);
case CT_SI5351:
return portapack::clock_generator.read_register(register_number);
case CT_BATTERY:
return battery::BatteryManagement::read_register(register_number);
case CT_AUDIO:
return audio::debug::reg_read(register_number);
}
@ -246,6 +248,9 @@ void RegistersWidget::reg_write(const uint32_t register_number, const uint32_t v
case CT_SI5351:
portapack::clock_generator.write_register(register_number, value);
break;
case CT_BATTERY:
battery::BatteryManagement::write_register(register_number, value);
break;
case CT_AUDIO:
audio::debug::reg_write(register_number, value);
break;
@ -459,6 +464,10 @@ void DebugPeripheralsMenuView::on_populate() {
{si5351x, Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
{audio::debug::codec_name(), Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
});
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BatteryModules::BATT_MAX17055) {
add_item(
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_BATTERY, 256, 16, 16}); }});
}
set_max_rows(2); // allow wider buttons
}
@ -496,10 +505,10 @@ void DebugMenuView::on_populate() {
{"Peripherals", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<DebugPeripheralsMenuView>(); }},
{"Pers. Memory", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_memory, [this]() { nav_.push<DebugPmemView>(); }},
//{ "Radio State", ui::Theme::getInstance()->bg_darkest->foreground, nullptr, [this](){ nav_.push<NotImplementedView>(); } },
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
{"SD Card", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_sdcard, [this]() { nav_.push<SDCardDebugView>(); }},
{"Temperature", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_temperature, [this]() { nav_.push<TemperatureView>(); }},
{"Touch Test", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_notepad, [this]() { nav_.push<DebugScreenTest>(); }},
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
});
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav_)) {

View File

@ -139,6 +139,7 @@ typedef enum {
CT_MAX283X,
CT_SI5351,
CT_AUDIO,
CT_BATTERY,
} chip_type_t;
struct RegistersWidgetConfig {

View File

@ -34,6 +34,7 @@
#include "usb_serial.hpp"
#include "ads1110.hpp"
#include "max17055.hpp"
#include "radio.hpp"
#include "clock_manager.hpp"

View File

@ -2,6 +2,7 @@
#include "event_m0.hpp"
#include "portapack.hpp"
#include "ads1110.hpp"
#include "max17055.hpp"
// uncomment if you want to emulate batt management system
// #define USE_BATT_EMULATOR
@ -14,6 +15,7 @@ constexpr uint32_t BATTERY_UPDATE_INTERVAL = 30000;
BatteryManagement::BatteryModules BatteryManagement::detected_ = BatteryManagement::BATT_NONE;
ads1110::ADS1110 battery_ads1110{portapack::i2c0, 0x48};
max17055::MAX17055 battery_max17055{portapack::i2c0, 0x36};
Thread* BatteryManagement::thread = nullptr;
@ -23,6 +25,9 @@ void BatteryManagement::init() {
if (battery_ads1110.detect()) {
battery_ads1110.init();
detected_ = BATT_ADS1110;
} else if (battery_max17055.detect()) {
battery_max17055.init();
detected_ = BATT_MAX17055;
}
// add new supported module detect + init here
@ -40,11 +45,15 @@ void BatteryManagement::init() {
}
// sets the values, it the currend module supports it.
bool BatteryManagement::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current, bool& isCharging) {
if (detected_ == BATT_NONE) return false;
if (detected_ == BATT_ADS1110) {
bool BatteryManagement::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
if (detected_ == BATT_NONE) {
return false;
} else if (detected_ == BATT_ADS1110) {
battery_ads1110.getBatteryInfo(batteryPercentage, voltage);
return true;
} else if (detected_ == BATT_MAX17055) {
battery_max17055.getBatteryInfo(batteryPercentage, voltage, current);
return true;
}
// add new module query here
@ -59,18 +68,30 @@ bool BatteryManagement::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& vol
}
#endif
(void)isCharging; // keep the compiler calm
(void)current;
return false;
}
uint16_t BatteryManagement::read_register(const uint8_t reg) {
if (detected_ == BATT_MAX17055) {
return battery_max17055.read_register(reg);
}
return 0xFFFF;
}
bool BatteryManagement::write_register(const uint8_t reg, const uint16_t value) {
if (detected_ == BATT_MAX17055) {
return battery_max17055.write_register(reg, value);
}
return false;
}
uint8_t BatteryManagement::getPercent() {
if (detected_ == BATT_NONE) return 102;
uint8_t batteryPercentage = 0;
bool isCharging = false;
uint16_t voltage = 0;
int32_t current = 0;
getBatteryInfo(batteryPercentage, voltage, current, isCharging);
getBatteryInfo(batteryPercentage, voltage, current);
return batteryPercentage;
}
@ -78,10 +99,9 @@ uint16_t BatteryManagement::getVoltage() {
if (detected_ == BATT_NONE) return 0;
if (detected_ == BATT_NONE) return 102;
uint8_t batteryPercentage = 0;
bool isCharging = false;
uint16_t voltage = 0;
int32_t current = 0;
getBatteryInfo(batteryPercentage, voltage, current, isCharging);
getBatteryInfo(batteryPercentage, voltage, current);
return voltage;
}
@ -89,14 +109,13 @@ msg_t BatteryManagement::timer_fn(void* arg) {
(void)arg;
if (!detected_) return 0;
uint8_t batteryPercentage = 102;
bool isCharging = false;
uint16_t voltage = 0;
int32_t current = 0;
chThdSleepMilliseconds(1000); // wait ui for fully load
while (1) {
if (BatteryManagement::getBatteryInfo(batteryPercentage, voltage, current, isCharging)) {
if (BatteryManagement::getBatteryInfo(batteryPercentage, voltage, current)) {
// send local message
BatteryStateMessage msg{batteryPercentage, isCharging, voltage};
BatteryStateMessage msg{batteryPercentage, current >= 0, voltage};
EventDispatcher::send_message(msg);
}
chThdSleepMilliseconds(BATTERY_UPDATE_INTERVAL);

View File

@ -32,13 +32,17 @@ class BatteryManagement {
enum BatteryModules {
BATT_NONE = 0,
BATT_ADS1110 = 1,
BATT_MAX17055 = 2,
BATT_EMULATOR = 254
};
static void init();
static bool isDetected() { return detected_ != BATT_NONE; }
static bool getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current, bool& isCharging);
static BatteryModules detectedModule() { return detected_; }
static bool getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
static uint16_t getVoltage();
static uint8_t getPercent();
static uint16_t read_register(const uint8_t reg);
static bool write_register(const uint8_t reg, const uint16_t value);
private:
static void create_thread();

View File

@ -0,0 +1,753 @@
/*
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 <cstring>
#include <algorithm>
#include <cstdint>
namespace battery {
namespace max17055 {
void MAX17055::init() {
if (!detected_) {
detected_ = detect();
} else {
config();
setHibCFG(0x0000);
// Design Capacity Register
setDesignCapacity(__MAX17055_Design_Capacity__);
// ModelCfg Register
setModelCfg(__MAX17055_Battery_Model__);
// IChgTerm Register
setChargeTerminationCurrent(__MAX17055_Termination_Current__);
// VEmpty Register
setEmptyVoltage(__MAX17055_Empty_Voltage__);
// VRecovery Register
setRecoveryVoltage(__MAX17055_Recovery_Voltage__);
// Set Minimum Voltage
setMinVoltage(__MAX17055_Min_Voltage__);
// Set Maximum Voltage
setMaxVoltage(__MAX17055_Max_Voltage__);
// Set Maximum Current
setMaxCurrent(__MAX17055_Max_Current__);
// Set Minimum SOC
setMinSOC(__MAX17055_Min_SOC__);
// Set Maximum SOC
setMaxSOC(__MAX17055_Max_SOC__);
// Set Minimum Temperature
setMinTemperature(__MAX17055_Min_Temperature__);
// Set Maximum Temperature
setMaxTemperature(__MAX17055_Max_Temperature__);
// Clear Bits
statusClear();
}
}
bool MAX17055::detect() {
uint8_t _MAX17055_Data[2];
// Get Data from IC
if (readMultipleRegister(0x00, _MAX17055_Data, 2, false)) {
detected_ = true;
return true;
}
detected_ = false;
return false;
}
bool bitRead(uint8_t value, uint8_t bit) {
return (value >> bit) & 0x01;
}
void bitSet(uint16_t& value, uint8_t bit) {
value |= (1 << bit);
}
void bitSet(uint8_t& value, uint8_t bit) {
value |= (1 << bit);
}
void bitClear(uint16_t& value, uint8_t bit) {
value &= ~(1 << bit);
}
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());
return success;
}
bool MAX17055::readMultipleRegister(uint8_t reg, uint8_t* data, uint8_t length, bool endTransmission) {
if (bus.transmit(bus_address, &reg, 1)) {
if (bus.receive(bus_address, data, length)) {
if (endTransmission) {
// bus.stop(); // Testing if we need this line
// Perform any necessary end transmission actions
// For example, you can use bus.endTransmission()
}
return true;
}
}
return false;
}
bool MAX17055::writeMultipleRegister(uint8_t reg, const uint8_t* data, uint8_t length) {
uint8_t buffer[length + 1];
buffer[0] = reg;
memcpy(buffer + 1, data, length);
if (bus.transmit(bus_address, buffer, length + 1)) {
// Perform any necessary end transmission actions
// For example, you can use bus.endTransmission()
return true;
}
return false;
}
void MAX17055::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
voltage = averageVoltage();
batteryPercentage = stateOfCharge();
current = instantCurrent();
}
bool MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
// Set Voltage Value
uint16_t _Raw_Voltage = ((uint16_t)((uint16_t)_Empty_Voltage * 100) << 7) & 0b1111111110000000;
// Define Data Variable
uint8_t MAX17055_RAW_Data[2];
// Handle Data
MAX17055_RAW_Data[1] = (uint8_t)(_Raw_Voltage >> 8);
MAX17055_RAW_Data[0] = (uint8_t)(_Raw_Voltage & 0x00FF);
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x3A, MAX17055_Current_Data, 2, true);
// Clear Current Value
MAX17055_Current_Data[0] &= 0b01111111;
MAX17055_Current_Data[1] &= 0b00000000;
// Define Data Variable
uint8_t MAX17055_Handle_Data[2];
// Handle Data
MAX17055_Handle_Data[0] = MAX17055_Current_Data[0] | MAX17055_RAW_Data[0];
MAX17055_Handle_Data[1] = MAX17055_Current_Data[1] | MAX17055_RAW_Data[1];
// Set Register
bool _Result = writeMultipleRegister(0x3A, MAX17055_Handle_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
// Handle Value
_Recovery_Voltage = _Recovery_Voltage * 1000 / 40;
// Set Voltage Value
uint16_t _Raw_Voltage = ((uint16_t)_Recovery_Voltage);
// Define Data Variable
uint8_t MAX17055_RAW_Data[2];
// Handle Data
MAX17055_RAW_Data[1] = (uint8_t)(_Raw_Voltage >> 8);
MAX17055_RAW_Data[0] = (uint8_t)(_Raw_Voltage & 0x00FF);
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x3A, MAX17055_Current_Data, 2, true);
// Clear Current Value
MAX17055_Current_Data[0] &= 0b10000000;
MAX17055_Current_Data[1] &= 0b11111111;
// Define Data Variable
uint8_t MAX17055_Handle_Data[2];
// Handle Data
MAX17055_Handle_Data[0] = MAX17055_Current_Data[0] | MAX17055_RAW_Data[0];
MAX17055_Handle_Data[1] = MAX17055_Current_Data[1] | MAX17055_RAW_Data[1];
// Set Register
bool _Result = writeMultipleRegister(0x3A, MAX17055_Handle_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
// Set Voltage Value
uint8_t _Raw_Voltage = (uint8_t)(_Minimum_Voltage * 1000 / 20);
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x01, MAX17055_Current_Data, 2, true);
// Set Voltage Value
MAX17055_Current_Data[0] = _Raw_Voltage;
// Set Register
bool _Result = writeMultipleRegister(0x01, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
// Set Voltage Value
uint8_t _Raw_Voltage = (uint8_t)(_Maximum_Voltage * 1000 / 20);
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x01, MAX17055_Current_Data, 2, true);
// Set Voltage Value
MAX17055_Current_Data[1] = _Raw_Voltage;
// Set Register
bool _Result = writeMultipleRegister(0x01, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
// Set Current Value
uint8_t _Raw_Current = (uint8_t)(_Maximum_Current * 1000 / 40);
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0xB4, MAX17055_Current_Data, 2, true);
// Set Current Value
MAX17055_Current_Data[1] = _Raw_Current;
// Set Register
bool _Result = writeMultipleRegister(0xB4, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setChargeTerminationCurrent(uint16_t _Charge_Termination_Current) {
// Handle Raw Data
uint16_t _RAW_Data = (uint16_t)(_Charge_Termination_Current * 1000000 * __MAX17055_Resistor__ / 1.5625);
// Declare Default Data Array
uint8_t _Data[2];
// Set Data Low/High Byte
_Data[0] = ((_RAW_Data & (uint16_t)0x00FF));
_Data[1] = ((_RAW_Data & (uint16_t)0xFF00) >> 8);
// Set Register
bool _Result = writeMultipleRegister(0x1E, _Data, 2);
// End Function
return _Result;
}
bool MAX17055::setDesignCapacity(const uint16_t _Capacity) {
// Set Raw
uint16_t _Raw_Cap = (uint16_t)_Capacity * 2;
// Declare Default Data Array
uint8_t _Data[2];
// Set Data Low/High Byte
_Data[0] = ((_Raw_Cap & (uint16_t)0x00FF));
_Data[1] = ((_Raw_Cap & (uint16_t)0xFF00) >> 8);
// Set Register
bool _Result = writeMultipleRegister(0x18, _Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x03, MAX17055_Current_Data, 2, true);
// Scale Value
uint8_t _MinSOC = (_Minimum_SOC / 100) * 255;
// Set Voltage Value
MAX17055_Current_Data[0] = _MinSOC;
// Set Register
bool _Result = writeMultipleRegister(0x03, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x03, MAX17055_Current_Data, 2, true);
// Scale Value
uint8_t _MaxSOC = (_Maximum_SOC / 100) * 255;
// Set Voltage Value
MAX17055_Current_Data[1] = _MaxSOC;
// Set Register
bool _Result = writeMultipleRegister(0x03, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x02, MAX17055_Current_Data, 2, true);
// Set Voltage Value
MAX17055_Current_Data[0] = _Minimum_Temperature;
// Set Register
bool _Result = writeMultipleRegister(0x02, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
// Define Data Variable
uint8_t MAX17055_Current_Data[2];
// Read Current Register
readMultipleRegister(0x02, MAX17055_Current_Data, 2, true);
// Set Voltage Value
MAX17055_Current_Data[1] = _Maximum_Temperature;
// Set Register
bool _Result = writeMultipleRegister(0x02, MAX17055_Current_Data, 2);
// End Function
return _Result;
}
bool MAX17055::setModelCfg(const uint8_t _Model_ID) {
// Declare Variable
uint16_t _Data_Set = 0x00;
// Set Charge Voltage
bitSet(_Data_Set, 10);
// Set Battery Model
if (_Model_ID == 0) {
bitClear(_Data_Set, 4);
bitClear(_Data_Set, 5);
bitClear(_Data_Set, 6);
bitClear(_Data_Set, 7);
}
if (_Model_ID == 2) {
bitClear(_Data_Set, 4);
bitSet(_Data_Set, 5);
bitClear(_Data_Set, 6);
bitClear(_Data_Set, 7);
}
if (_Model_ID == 6) {
bitClear(_Data_Set, 4);
bitSet(_Data_Set, 5);
bitSet(_Data_Set, 6);
bitClear(_Data_Set, 7);
}
// Declare Default Data Array
uint8_t _Data[2];
// Set Data Low/High Byte
_Data[0] = ((_Data_Set & (uint16_t)0x00FF));
_Data[1] = ((_Data_Set & (uint16_t)0xFF00) >> 8);
// Set Register
bool _Result = writeMultipleRegister(0xDB, _Data, 2);
// End Function
return _Result;
}
bool MAX17055::setHibCFG(const uint16_t _Config) {
// Declare Default Data Array
uint8_t _Data[2];
// Set Data Low/High Byte
_Data[0] = ((_Config & (uint16_t)0x00FF));
_Data[1] = ((_Config & (uint16_t)0xFF00) >> 8);
// Set Register
bool _Result = writeMultipleRegister(0xBA, _Data, 2);
// End Function
return _Result;
}
void MAX17055::config(void) {
// Declare Default Data Array
uint8_t _Config1[2];
uint8_t _Config2[2];
// Set Default Data
_Config1[0] = 0b00000000;
_Config1[1] = 0b00000000;
_Config2[0] = 0b00011000;
_Config2[1] = 0b00000110;
// Set Configuration bits [Config1]
if (MAX17055_Ber) bitSet(_Config1[0], 0);
if (MAX17055_Bei) bitSet(_Config1[0], 1);
if (MAX17055_Aen) bitSet(_Config1[0], 2);
if (MAX17055_FTHRM) bitSet(_Config1[0], 3);
if (MAX17055_ETHRM) bitSet(_Config1[0], 4);
if (MAX17055_COMMSH) bitSet(_Config1[0], 6);
if (MAX17055_SHDN) bitSet(_Config1[0], 7);
if (MAX17055_Tex) bitSet(_Config1[1], 0);
if (MAX17055_Ten) bitSet(_Config1[1], 1);
if (MAX17055_AINSH) bitSet(_Config1[1], 2);
if (MAX17055_IS) bitSet(_Config1[1], 3);
if (MAX17055_VS) bitSet(_Config1[1], 4);
if (MAX17055_TS) bitSet(_Config1[1], 5);
if (MAX17055_SS) bitSet(_Config1[1], 6);
if (MAX17055_TSel) bitSet(_Config1[1], 7);
// Set Configuration bits [Config2]
if (MAX17055_CPMode) bitSet(_Config2[0], 1);
if (MAX17055_LDMDL) bitSet(_Config2[0], 5);
if (MAX17055_TAIrtEN) bitSet(_Config2[0], 6);
if (MAX17055_dSOCen) bitSet(_Config2[0], 7);
if (MAX17055_DPEn) bitSet(_Config2[1], 4);
if (MAX17055_AtRateEn) bitSet(_Config2[1], 5);
// Config1 Setting
writeMultipleRegister(0x1D, _Config1, 2);
writeMultipleRegister(0xBB, _Config2, 2);
}
uint16_t MAX17055::instantVoltage(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x09);
// Calculate Measurement
uint16_t _Value = ((uint32_t)_Measurement_Raw * 1.25 / 16);
// End Function
return _Value;
}
uint16_t MAX17055::averageVoltage(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x19);
// Calculate Measurement
uint16_t _Value = ((uint32_t)_Measurement_Raw * 1.25 / 16);
// End Function
return _Value;
}
uint16_t MAX17055::emptyVoltage(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x3A);
_Measurement_Raw = ((_Measurement_Raw & 0xFF80) >> 7);
// Calculate Measurement
uint16_t _Value = ((uint32_t)_Measurement_Raw * 10);
// End Function
return _Value;
}
uint16_t MAX17055::recoveryVoltage(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x3A);
_Measurement_Raw = (_Measurement_Raw & 0x7F);
// Calculate Measurement
uint16_t _Value = ((uint32_t)_Measurement_Raw * 40);
// End Function
return _Value;
}
int32_t MAX17055::instantCurrent(void) {
// 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);
// End Function
return _Value;
}
int32_t MAX17055::averageCurrent(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x0B);
// 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);
// End Function
return _Value;
}
uint16_t MAX17055::stateOfCharge(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x06); // RepSOC
// Calculate Measurement
uint8_t _Value = (_Measurement_Raw >> 8) & 0xFF;
// End Function
return _Value;
}
uint16_t MAX17055::averageStateOfCharge(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x0E);
// Calculate Measurement
uint16_t _Value = ((uint32_t)_Measurement_Raw * 100 / 256);
// End Function
return _Value;
}
uint16_t MAX17055::instantCapacity(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x05);
// Calculate Data
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
// End Function
return _Value;
}
uint16_t MAX17055::designCapacity(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x18);
// Calculate Data
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
// End Function
return _Value;
}
uint16_t MAX17055::fullCapacity(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x35);
// Calculate Data
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
// End Function
return _Value;
}
uint16_t MAX17055::icTemperature(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x08);
// Declare Variables
bool _Signiture = false;
// Control for Negative Value
if ((_Measurement_Raw >> 12) == 0xF) {
// Calculate Data
_Measurement_Raw = 0xFFFF - _Measurement_Raw;
// Assign Signiture
_Signiture = true;
}
// Calculate Data
uint16_t _Value = ((uint32_t)_Measurement_Raw * 100 / 256);
// Assign Signiture
if (_Signiture) _Value = -_Value;
// End Function
return _Value;
}
uint16_t MAX17055::timeToEmpty(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x11);
// Calculate Data
uint16_t _Value = ((uint32_t)_Measurement_Raw * 5625 / 60 / 60 / 100);
// End Function
return _Value;
}
uint16_t MAX17055::timeToFull(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x20);
// Calculate Data
uint16_t _Value = ((uint32_t)_Measurement_Raw * 5625 / 60 / 60 / 100);
// End Function
return _Value;
}
uint16_t MAX17055::batteryAge(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x07);
// End Function
return _Measurement_Raw;
}
uint16_t MAX17055::chargeCycle(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x17);
// End Function
return _Measurement_Raw;
}
bool MAX17055::statusControl(const uint8_t _Status) {
// Define Data Variable
uint8_t _Status_Register[2] = {0x00, 0x00};
// Read Status Register
readMultipleRegister(0x00, _Status_Register, 2, false);
// Control for Status
if (_Status == MAX17055_POR)
return bitRead(_Status_Register[0], 1);
else if (_Status == MAX17055_IMin)
return bitRead(_Status_Register[0], 2);
else if (_Status == MAX17055_IMax)
return bitRead(_Status_Register[0], 6);
else if (_Status == MAX17055_VMin)
return bitRead(_Status_Register[1], 0);
else if (_Status == MAX17055_VMax)
return bitRead(_Status_Register[1], 4);
else if (_Status == MAX17055_TMin)
return bitRead(_Status_Register[1], 1);
else if (_Status == MAX17055_TMax)
return bitRead(_Status_Register[1], 5);
else if (_Status == MAX17055_SOC_Min)
return bitRead(_Status_Register[1], 2);
else if (_Status == MAX17055_SOC_Max)
return bitRead(_Status_Register[1], 6);
else if (_Status == MAX17055_SOC_Change)
return bitRead(_Status_Register[0], 7);
else if (_Status == MAX17055_Bat_Status)
return bitRead(_Status_Register[0], 3);
else if (_Status == MAX17055_Bat_Insert)
return bitRead(_Status_Register[1], 3);
else if (_Status == MAX17055_Bat_Remove)
return bitRead(_Status_Register[1], 7);
// End Function
return false;
}
void MAX17055::statusClear(void) {
// Define Data Variable
const uint8_t _Status_Register[2] = {0x00, 0x00};
// Write Status Register
writeMultipleRegister(0x00, _Status_Register, 2);
}
uint16_t MAX17055::chargeTerminationCurrent(void) {
// Get Data from IC
uint16_t _Measurement_Raw = read_register(0x1E);
// Calculate Data
uint16_t Value = (((uint32_t)_Measurement_Raw * 1.5625) / __MAX17055_Resistor__);
// End Function
return Value;
}
} /* namespace max17055 */
} // namespace battery

View File

@ -0,0 +1,317 @@
/*
* 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.
*/
#ifndef __MAX17055_H__
#define __MAX17055_H__
#include <cstdint>
#include <array>
#include <string>
#include "i2c_pp.hpp"
#define MAX17055_POR 0
#define MAX17055_IMin 1
#define MAX17055_IMax 2
#define MAX17055_VMin 3
#define MAX17055_VMax 4
#define MAX17055_TMin 5
#define MAX17055_TMax 6
#define MAX17055_SOC_Min 7
#define MAX17055_SOC_Max 8
#define MAX17055_SOC_Change 9
#define MAX17055_Bat_Status 10
#define MAX17055_Bat_Insert 11
#define MAX17055_Bat_Remove 12
// Design Parameters
//----------------------------------------------
// Define Battery Capacity
#ifndef __MAX17055_Design_Capacity__
#define __MAX17055_Design_Capacity__ 1500 // Battery Capacity
#endif
// Define Gauge Resistor
#ifndef __MAX17055_Resistor__
#define __MAX17055_Resistor__ 0.01 // Shunt Resistor
#endif
// Define Minimum Voltage
#ifndef __MAX17055_Min_Voltage__
#define __MAX17055_Min_Voltage__ 3.0 // Minimum Voltage
#endif
// Define Maximum Voltage
#ifndef __MAX17055_Max_Voltage__
#define __MAX17055_Max_Voltage__ 4.2 // Maximum Voltage
#endif
// Define Empty Voltage
#ifndef __MAX17055_Empty_Voltage__
#define __MAX17055_Empty_Voltage__ 3.0 // Empty Voltage
#endif
// Define Recovery Voltage
#ifndef __MAX17055_Recovery_Voltage__
#define __MAX17055_Recovery_Voltage__ 3.7 // Recovery Voltage
#endif
// Define Maximum Current
#ifndef __MAX17055_Max_Current__
#define __MAX17055_Max_Current__ 3.0 // Maximum Current
#endif
// Define Termination Current
#ifndef __MAX17055_Termination_Current__
#define __MAX17055_Termination_Current__ 0.1 // Termination Current
#endif
// Define Minimum Temperature
#ifndef __MAX17055_Min_Temperature__
#define __MAX17055_Min_Temperature__ -20 // Minimum Temperature
#endif
// Define Maximum Temperature
#ifndef __MAX17055_Max_Temperature__
#define __MAX17055_Max_Temperature__ 60 // Maximum Temperature
#endif
// Define Battery Model
#ifndef __MAX17055_Battery_Model__
#define __MAX17055_Battery_Model__ 0 // Battery Model
#endif
// Define Limits
//----------------------------------------------
// Define Minimum SOC
#ifndef __MAX17055_Min_SOC__
#define __MAX17055_Min_SOC__ 20 // Minimum SOC
#endif
// Define Maximum SOC
#ifndef __MAX17055_Max_SOC__
#define __MAX17055_Max_SOC__ 90 // Maximum SOC
#endif
// Config1 (0x1D) Configuration
//----------------------------------------------
// Enable alert on battery removal when the IC is mounted host side.
// When Ber = 1, a battery-removal condition, as detected by the AIN pin voltage, triggers an alert.
#ifndef MAX17055_Ber
#define MAX17055_Ber 0
#endif
// Enable alert on battery insertion when the IC is mounted host side.
// When Bei = 1, a battery-insertion condition, as detected by the AIN pin voltage, triggers an alert.
#ifndef MAX17055_Bei
#define MAX17055_Bei 0
#endif
// When Aen = 1, violation of any of the alert threshold register values
// by temperature, voltage, or SOC triggers an alert. This bit
// affects the ALRT pin operation only. The Smx, Smn, Tmx,
// Tmn, Vmx, Vmn, Imx, and Imn bits of the Status register
// (00h) are not disabled.
#ifndef MAX17055_Aen
#define MAX17055_Aen 1
#endif
// This allows the host to control the bias of the thermistor switch or
// enable fast detection of battery removal. Set FTHRM = 1
// to always enable the thermistor bias switch. With a standard 10kΩ thermistor,
// this adds an additional ~200μA to the current drain of the circuit.
#ifndef MAX17055_FTHRM
#define MAX17055_FTHRM 0
#endif
// Set to logic 1 to enable the automatic THRM output bias and AIN measurement.
#ifndef MAX17055_ETHRM
#define MAX17055_ETHRM 0
#endif
// Set to logic 1 to force the device to enter shutdown mode if both
// SDA and SCL are held low for more than timeout of the
// ShdnTimer register.
#ifndef MAX17055_COMMSH
#define MAX17055_COMMSH 0
#endif
// Write this bit to logic 1 to force a shutdown of the device after timeout of the ShdnTimer register (default 45s delay).
#ifndef MAX17055_SHDN
#define MAX17055_SHDN 0
#endif
// When set to 1, the fuel gauge requires external temperature measurements to be
// written from the host. When set to 0, the IC's own measurements as used as selected by Config.TSEL.
#ifndef MAX17055_Tex
#define MAX17055_Tex 0
#endif
// Set to 1 and set ETHRM or FTHRM to 1 to enable temperature measurements selected by Config.TSel.
#ifndef MAX17055_Ten
#define MAX17055_Ten 1
#endif
// Set to 1 to enable device shutdown when the IC is mounted host side and the battery is removed.
#ifndef MAX17055_AINSH
#define MAX17055_AINSH 0
#endif
// When IS = 1, current alerts can only be cleared through software. When IS = 0,
// current alerts are cleared automatically when the thresholdis no longer exceeded.
#ifndef MAX17055_IS
#define MAX17055_IS 0
#endif
// When VS = 1, voltage alerts can only be cleared through software. When VS = 0,
// voltage alerts are cleared automatically when the threshold is no longer exceeded.
#ifndef MAX17055_VS
#define MAX17055_VS 0
#endif
// When TS = 1, temperature alerts can only be cleared through software. WhenTS = 0,
// temperature alerts are cleared automatically whenthe threshold is no longer exceeded.
#ifndef MAX17055_TS
#define MAX17055_TS 0
#endif
// When SS = 1, SOC alerts can only be cleared through software. When SS = 0,
// SOC alerts are cleared automatically when the threshold is no longer exceeded.
#ifndef MAX17055_SS
#define MAX17055_SS 0
#endif
// 0 to use internal die temperature. 1 to use temperature information from thermistor.
// ETHRM bit should be set to 1 when TSel is 1.
#ifndef MAX17055_TSel
#define MAX17055_TSel 0
#endif
// Config1 (0xBB) Configuration
//----------------------------------------------
// Set to 1 to enable constant-power mode. If it is set to 0,
// AtRate/AvgCurrent is used for (At)TTE/(At) QResidual/(At)AvSOC/(At)AvCap.
#ifndef MAX17055_CPMode
#define MAX17055_CPMode 0
#endif
// Host sets this bit to 1 in order to initiate firmware to finish processing a newly loaded model.
// Firmware clears this bit to zero to indicate that model loading is finished.
#ifndef MAX17055_LDMDL
#define MAX17055_LDMDL 0
#endif
// Set this bit to 1 to enable temperature based alerts.
// Write this bit to 0 to disable temperature alerts. This bit is set to 1 at power-up.
#ifndef MAX17055_TAIrtEN
#define MAX17055_TAIrtEN 1
#endif
// Set this bit to 1 to enable alert output with the Status.dSOCi bit function.
// Write this bit to 0 to disable alert output with the Status. dSOCi bit. This bit is set to 0 at power-up.
#ifndef MAX17055_dSOCen
#define MAX17055_dSOCen 0
#endif
// When this bit is set to 0, Dynamic Power calculations are disabled and registers
// MaxPeakPower/SusPeakPower/MPPCurrent/ SPPCurrent can be used as general purpose memory.
#ifndef MAX17055_DPEn
#define MAX17055_DPEn 0
#endif
// When this bit is set to 0, AtRate calculations are disabled and registers
// AtQResidual/AtTTE/AtAvSOC/AtAvCap can be used as general purpose memory.
#ifndef MAX17055_AtRateEn
#define MAX17055_AtRateEn 0
#endif
namespace battery {
namespace max17055 {
using address_t = uint8_t;
class MAX17055 {
public:
constexpr MAX17055(I2C& bus, const I2C::address_t bus_address)
: bus(bus), bus_address(bus_address), detected_(false) {}
void init();
bool detect();
bool isDetected() const { return detected_; }
uint16_t readVoltage();
uint8_t readPercentage();
void getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
uint16_t instantVoltage(void);
uint16_t averageVoltage(void);
uint16_t emptyVoltage(void);
uint16_t recoveryVoltage(void);
int32_t instantCurrent(void);
int32_t averageCurrent(void);
uint16_t stateOfCharge(void);
uint16_t averageStateOfCharge(void);
uint16_t instantCapacity(void);
uint16_t designCapacity(void);
uint16_t fullCapacity(void);
uint16_t icTemperature(void);
uint16_t timeToEmpty(void);
uint16_t timeToFull(void);
uint16_t batteryAge(void);
uint16_t chargeCycle(void);
bool statusControl(const uint8_t _Status);
void statusClear(void);
uint16_t chargeTerminationCurrent(void);
uint16_t read_register(const uint8_t reg);
bool write_register(const uint8_t reg, const uint16_t value);
private:
I2C& bus;
const I2C::address_t bus_address;
bool detected_;
bool readRegister(uint8_t reg, uint16_t& value);
bool readMultipleRegister(uint8_t reg, uint8_t* data, uint8_t length, bool endTransmission);
bool writeMultipleRegister(uint8_t reg, const uint8_t* data, uint8_t length);
bool setEmptyVoltage(uint16_t _Empty_Voltage);
bool setRecoveryVoltage(uint16_t _Recovery_Voltage);
bool setMinVoltage(uint16_t _Minimum_Voltage);
bool setMaxVoltage(uint16_t _Maximum_Voltage);
bool setMaxCurrent(uint16_t _Maximum_Current);
bool setChargeTerminationCurrent(uint16_t _Charge_Termination_Current);
bool setDesignCapacity(const uint16_t _Capacity);
bool setMinSOC(uint8_t _Minimum_SOC);
bool setMaxSOC(uint8_t _Maximum_SOC);
bool setMinTemperature(uint8_t _Minimum_Temperature);
bool setMaxTemperature(uint8_t _Maximum_Temperature);
bool setModelCfg(const uint8_t _Model_ID);
bool setHibCFG(const uint16_t _Config);
void config(void);
};
} /* namespace max17055 */
} // namespace battery
#endif /* __MAX17055_H__ */