~aleteoryx/muditaos

5da8b4ee2fa13a4c72844aad6cdedf273a330875 — Wojtek Rzepecki 5 years ago 8f80126
[EGD-5367] Add Fuel Gauge parameters

Batery fuel aguge parametrized. Battery charger
parameters also added. Appropriate measurements
added and configured.
M module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp => module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp +17 -2
@@ 77,6 77,7 @@ namespace bsp::battery_charger
        VEmpty_REG     = 0x3A,
        TIMER_REG      = 0x3E,
        SHDNTIMER_REG  = 0x3F,
        CURVE          = 0xb9,

        QRtable30_REG = 0x42,
        dQ_acc_REG    = 0x45,


@@ 84,8 85,22 @@ namespace bsp::battery_charger
        ConvgCfg_REG  = 0x49,
        VFRemCap_REG  = 0x4A,
        QH_REG        = 0x4D,
        CHG_INT_REG   = 0xb0,
        CHG_INT_OK    = 0xb2

        CHG_INT_REG = 0xB0,
        CHG_INT_OK  = 0xB2,
        CHG_CNFG_00 = 0xB7,
        CHG_CNFG_01 = 0xB8,
        CHG_CNFG_02 = 0xB9,
        CHG_CNFG_03 = 0xBA,
        CHG_CNFG_04 = 0xBB,
        CHG_CNFG_05 = 0xBC,
        CHG_CNFG_06 = 0xBD,
        CHG_CNFG_07 = 0xBE,
        CHG_CNFG_09 = 0xC0,
        CHG_CNFG_10 = 0xC1,
        CHG_CNFG_11 = 0xC2,
        CHG_CNFG_12 = 0xC3

    };

    // STATUS register bits

M module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp => module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp +204 -94
@@ 11,6 11,8 @@
#include "drivers/i2c/DriverI2C.hpp"
#include <purefs/filesystem_paths.hpp>
#include <utility>
#include <bitset>
#include <fstream>

namespace bsp::battery_charger
{


@@ 18,32 20,63 @@ namespace bsp::battery_charger
    {
        constexpr std::uint32_t i2cSubaddresSize = 1;

        const auto cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
        const auto cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";
        const auto cfgFile              = purefs::dir::getCurrentOSPath() / "batteryFuelGaugeConfig.cfg";
        constexpr auto registersToStore = 0xFF + 1;

        constexpr std::uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
            0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
        constexpr std::uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
            0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
        constexpr std::uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
            0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
        constexpr std::uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
            0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
        constexpr std::uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;
        constexpr std::uint16_t ENABLE_ALL_IRQ_MASK = 0xF8;
        constexpr std::uint8_t UNLOCK_CHARGER       = 0x3 << 2;

        constexpr auto ENABLE_ALL_IRQ_MASK = 0xf8;
        constexpr std::uint8_t VSYS_MIN              = 0x80; // 3.6V
        constexpr std::uint8_t CHARGE_TARGET_VOLTAGE = 0x1D; // 4.35V

        constexpr std::uint16_t nominalCapacitymAh = 3000;
        constexpr std::uint8_t MAX_CHARGE_CURRENT  = 0x30; // 1600mA -> 1C
        constexpr std::uint8_t FAST_CHARGE_CURRENT = 0x0A; // 500mA

        constexpr std::uint8_t fullyChargedPercent = 100;
        constexpr std::uint8_t DischargedPercent   = 15;
        constexpr std::uint16_t nominalCapacitymAh = 1600;

        constexpr std::uint8_t maxTemperatureDegrees = 50;
        constexpr std::uint8_t minTemperatureDegrees = 5;

        constexpr std::uint16_t maxVoltagemV = 4200;
        constexpr std::uint16_t maxVoltagemV = 4350;
        constexpr std::uint16_t minVoltagemV = 3600;

        constexpr auto currentSenseGain = 0.15625;  // mA
        constexpr auto voltageSenseGain = 0.078125; // mV

        // NTC calibration values
        constexpr std::uint16_t temperatureConversionGain   = 0xEE56;
        constexpr std::uint16_t temperatureConversionOffset = 0x1DA4;

        namespace fuel_gauge_params
        {
            /// Parameters calculated in in MAXIM EVKIT software
            /// Initial parameters for fuel gauge battery model

            constexpr std::uint16_t LearnCFG    = 0x2602;
            constexpr std::uint16_t FilterCFG   = 0xCEA4;
            constexpr std::uint16_t MiscCFG     = 0x01D0;
            constexpr std::uint16_t RelaxCFG    = 0x2039;
            constexpr std::uint16_t RCOMP0      = 0x0070;
            constexpr std::uint16_t TempCo      = 0x263D;
            constexpr std::uint16_t QResidual00 = 0x2280;
            constexpr std::uint16_t QResidual10 = 0x1000;
            constexpr std::uint16_t QResidual20 = 0x0681;
            constexpr std::uint16_t QResidual30 = 0x0682;
            /// 1600mAh initial battery capacity
            constexpr std::uint16_t FullCAPNom = 0x0C80;
            constexpr std::uint16_t FullCAPRep = 0x0C80;
            constexpr std::uint16_t DesignCap  = 0x0C80;
            constexpr std::uint16_t dQacc      = 0x00C8;
            constexpr std::uint16_t dPacc      = 0x0C80;
            /// Charge termination current = 150mA
            constexpr std::uint16_t ICHGTerm = 0x03C0;
            /// Empty battery = 3V
            constexpr std::uint16_t V_empty = 0x965A;
            /// Fully charged threshold = 90%
            constexpr std::uint16_t FullSOCthr = 0x5A00;

        } // namespace fuel_gauge_params

        std::shared_ptr<drivers::DriverI2C> i2c;
        std::shared_ptr<drivers::DriverGPIO> gpio;



@@ 125,97 158,121 @@ namespace bsp::battery_charger
            return std::make_pair(status, value);
        }

        batteryRetval loadConfiguration()
        batteryRetval unlockProtectedChargerRegisters()
        {
            auto fd = std::fopen(cfgFile.c_str(), "r");
            if (fd == nullptr) {
                LOG_WARN("Configuration file [%s] could not be opened. Trying to open file [%s]",
                         cfgFile.c_str(),
                         cfgFilePrev.c_str());
                fd = std::fopen(cfgFilePrev.c_str(), "r");
                if (fd == nullptr) {
                    LOG_WARN("Configuration file [%s] could not be opened.", cfgFilePrev.c_str());
                    return batteryRetval::ChargerError;
                }
            if (chargerWrite(Registers::CHG_CNFG_06, UNLOCK_CHARGER) != kStatus_Success) {
                LOG_ERROR("Charger registers unlock failed!");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

            std::uint16_t regValue = 0;
            for (auto i = 0; i < 0xff; ++i) {
                if (std::fread(&regValue, sizeof(regValue), 1, fd) != sizeof(regValue)) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }

                if (fuelGaugeWrite(static_cast<Registers>(i), regValue) != kStatus_Success) {
                    LOG_ERROR("Writing register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }
        batteryRetval lockProtectedChargerRegisters()
        {
            if (chargerWrite(Registers::CHG_CNFG_06, 0) != kStatus_Success) {
                LOG_ERROR("Charger registers lock failed!");
                return batteryRetval::ChargerError;
            }

            std::fclose(fd);
            return batteryRetval::OK;
        }

        batteryRetval storeConfiguration()
        void configureBatteryCharger()
        {
            // TODO:M.P procedure below seems to crash system, it should be fixed.
            if (ff_rename(cfgFile.c_str(), cfgFilePrev.c_str(), false) != 0) {
                LOG_ERROR("Could not move configuration file");
                return batteryRetval::ChargerError;
            unlockProtectedChargerRegisters();

            std::uint8_t value = CHARGE_TARGET_VOLTAGE | VSYS_MIN;
            if (chargerWrite(Registers::CHG_CNFG_04, value) != kStatus_Success) {
                LOG_ERROR("Charge target voltage write fail");
            }

            auto fd = std::fopen(cfgFile.c_str(), "w");
            if (fd == nullptr) {
                LOG_ERROR("Could not open configuration file");
            value = MAX_CHARGE_CURRENT;
            if (chargerWrite(Registers::CHG_CNFG_09, value) != kStatus_Success) {
                LOG_ERROR("Maximum charge current write fail");
            }

            value = FAST_CHARGE_CURRENT;
            if (chargerWrite(Registers::CHG_CNFG_02, value) != kStatus_Success) {
                LOG_ERROR("Fast charge current write fail");
            }

            lockProtectedChargerRegisters();
        }

        batteryRetval configureFuelGaugeBatteryModel()
        {
            int status = fuelGaugeWrite(Registers::LearnCFG_REG, fuel_gauge_params::LearnCFG);
            status |= fuelGaugeWrite(Registers::FilterCFG_REG, fuel_gauge_params::FilterCFG);
            status |= fuelGaugeWrite(Registers::MiscCFG_REG, fuel_gauge_params::MiscCFG);
            status |= fuelGaugeWrite(Registers::RelaxCFG_REG, fuel_gauge_params::RelaxCFG);
            status |= fuelGaugeWrite(Registers::RCOMP0_REG, fuel_gauge_params::RCOMP0);
            status |= fuelGaugeWrite(Registers::TempCo_REG, fuel_gauge_params::TempCo);
            status |= fuelGaugeWrite(Registers::QRtable00_REG, fuel_gauge_params::QResidual00);
            status |= fuelGaugeWrite(Registers::QRtable10_REG, fuel_gauge_params::QResidual10);
            status |= fuelGaugeWrite(Registers::QRtable20_REG, fuel_gauge_params::QResidual20);
            status |= fuelGaugeWrite(Registers::QRtable30_REG, fuel_gauge_params::QResidual30);
            status |= fuelGaugeWrite(Registers::FullCAPNom_REG, fuel_gauge_params::FullCAPNom);
            status |= fuelGaugeWrite(Registers::FullCapRep_REG, fuel_gauge_params::FullCAPRep);
            status |= fuelGaugeWrite(Registers::DesignCap_REG, fuel_gauge_params::DesignCap);
            status |= fuelGaugeWrite(Registers::dQ_acc_REG, fuel_gauge_params::dQacc);
            status |= fuelGaugeWrite(Registers::dP_acc_REG, fuel_gauge_params::dPacc);
            status |= fuelGaugeWrite(Registers::ICHGTERM_REG, fuel_gauge_params::ICHGTerm);
            status |= fuelGaugeWrite(Registers::VEmpty_REG, fuel_gauge_params::V_empty);
            status |= fuelGaugeWrite(Registers::FullSOCthr_REG, fuel_gauge_params::FullSOCthr);

            if (status != kStatus_Success) {
                LOG_ERROR("configureFuelGaugeBatteryModel failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

            for (unsigned int i = 0; i < 0xff; ++i) {
                auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                if (regVal.first != kStatus_Success) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
        batteryRetval loadConfiguration()
        {
            std::ifstream file(cfgFile.c_str(), std::ios::binary | std::ios::in);
            if (!file.is_open()) {
                LOG_WARN("Configuration file [%s] could not be opened. Loading initial configuration.",
                         cfgFile.c_str());
                if (configureFuelGaugeBatteryModel() == batteryRetval::OK) {
                    return batteryRetval::OK;
                }
                else {
                    return batteryRetval::ChargerError;
                }
            }

                if (std::fwrite(&regVal.second, sizeof(regVal.second), 1, fd) != sizeof(regVal.second)) {
                    LOG_ERROR("Storing register 0x%x failed.", i);
                    std::fclose(fd);
                    std::remove(cfgFile.c_str());
            std::uint16_t regVal;
            for (auto i = 0; i < registersToStore; ++i) {
                file.read(reinterpret_cast<char *>(&regVal), sizeof(std::uint16_t));
                if (fuelGaugeWrite(static_cast<Registers>(i), regVal) != kStatus_Success) {
                    LOG_ERROR("Writing register 0x%x failed.", i);
                    file.close();
                    return batteryRetval::ChargerError;
                }
            }
            file.close();

            std::fclose(fd);
            return batteryRetval::OK;
        }

        batteryRetval setAvgCalcPeriods()
        batteryRetval storeConfiguration()
        {
            std::uint16_t regVal = 0;
            regVal |= (BATT_SERVICE_AVG_CURRENT_PERIOD << 0);
            regVal |= (BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD << 4);
            regVal |= (BATT_SERVICE_AVG_MIXING_PERIOD << 7);
            regVal |= (BATT_SERVICE_AVG_TEMP_PERIOD << 11);
            regVal |= (BATT_SERVICE_AVG_NEMPTY_PERIOD << 14);

            if (fuelGaugeWrite(Registers::FilterCFG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setAvgCalcPeriods failed.");
            std::ofstream file(cfgFile.c_str(), std::ios::binary | std::ios::out);
            if (!file.is_open()) {
                LOG_WARN("Configuration file [%s] could not be opened.", cfgFile.c_str());
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval setNominalBatteryCapacity(std::uint16_t capacity)
        {
            std::uint16_t regVal = capacity * 2;

            if (fuelGaugeWrite(Registers::DesignCap_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setNominalBatteryCapacity failed.");
                return batteryRetval::ChargerError;
            for (unsigned int i = 0; i < registersToStore; ++i) {
                auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                if (regVal.first != kStatus_Success) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    file.close();
                    return batteryRetval::ChargerError;
                }
                file.write(reinterpret_cast<const char *>(&regVal.second), sizeof(std::uint16_t));
            }
            file.close();

            return batteryRetval::OK;
        }



@@ 254,24 311,38 @@ namespace bsp::battery_charger
            return batteryRetval::OK;
        }

        batteryRetval enableFuelGuageIRQs()
        batteryRetval fillConfig2RegisterValue()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG2::dSOCen);
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG2::dSOCen) | // SOC 1% change alert
                                   static_cast<std::uint16_t>(CONFIG2::OCVQen);  // Enable  automatic empty compensation

            if (fuelGaugeWrite(Registers::CONFIG2_REG, regVal) != kStatus_Success) {
                LOG_ERROR("enableFuelGuageIRQs failed.");
                LOG_ERROR("fillConfig2RegisterValue failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval configureAlerts()
        batteryRetval fillConfigRegisterValue()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG::Aen);
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG::Aen)      // Enable alerts
                                   | static_cast<std::uint16_t>(CONFIG::Ten)    // Enable tepreature conversion
                                   | static_cast<std::uint16_t>(CONFIG::ETHRM); // External thermistor

            if (fuelGaugeWrite(Registers::CONFIG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("configureAlerts failed.");
                LOG_ERROR("fillConfigRegisterValue failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval configureTemperatureMeasurement()
        {
            if ((fuelGaugeWrite(Registers::TGAIN_REG, temperatureConversionGain) &
                 fuelGaugeWrite(Registers::TOFF_REG, temperatureConversionOffset)) != kStatus_Success) {
                LOG_ERROR("configureTemperatureMeasurement failed.");
                return batteryRetval::ChargerError;
            }



@@ 313,6 384,45 @@ namespace bsp::battery_charger
            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
        }

        int getCellTemperature()
        {
            auto value      = fuelGaugeRead(Registers::TEMP_REG);
            int temperature = value.second >> 8;
            if (value.second & 0x8000) {
                temperature *= -1;
            }
            LOG_INFO("Battery cell temperature = %d Cdeg.", temperature);
            return temperature;
        }

        int getCurrentMeasurement()
        {
            auto value = fuelGaugeRead(Registers::Current_REG);
            int current;
            // 2's compliment into decimal
            if (value.second & 0x8000) {
                // negative numbers
                std::bitset<16> currentBitset = std::bitset<16>(value.second - 1);
                currentBitset.flip();
                current =
                    static_cast<int>((static_cast<std::uint16_t>(currentBitset.to_ulong()) * -1) * currentSenseGain);
            }
            else {
                // positive numbers
                current = static_cast<int>(value.second * currentSenseGain);
            }
            LOG_INFO("Battery current measurement = %d mA.", current);
            return current;
        }

        int getCellVoltage()
        {
            auto value  = fuelGaugeRead(Registers::VCELL_REG);
            int voltage = value.second * voltageSenseGain;
            LOG_INFO("Battery cell voltage measurement = %d mV.", voltage);
            return voltage;
        }
    } // namespace

    int init(xQueueHandle queueHandle)


@@ 324,21 434,22 @@ namespace bsp::battery_charger

        IRQQueueHandle = queueHandle;

        configureBatteryCharger();

        // check Power-On reset bit
        std::uint16_t status = fuelGaugeRead(Registers::STATUS_REG).second;

        if (status & static_cast<std::uint16_t>(STATUS::POR)) {
            LOG_INFO("Initializing battery charger");
            LOG_INFO("Initializing battery fuel gauge model.");
            loadConfiguration();
            setAvgCalcPeriods();
            setNominalBatteryCapacity(nominalCapacitymAh);
            setChargingDischargingThresholds(fullyChargedPercent, DischargedPercent);
            setTemperatureThresholds(maxTemperatureDegrees, minTemperatureDegrees);
            setServiceVoltageThresholds(maxVoltagemV, minVoltagemV);
        }

        configureAlerts();
        enableFuelGuageIRQs();
        setTemperatureThresholds(maxTemperatureDegrees, minTemperatureDegrees);
        setServiceVoltageThresholds(maxVoltagemV, minVoltagemV);

        fillConfigRegisterValue();
        fillConfig2RegisterValue();
        configureTemperatureMeasurement();

        StateOfCharge level = getBatteryLevel();
        bool charging       = getChargeStatus();


@@ 346,7 457,6 @@ namespace bsp::battery_charger

        clearAllIRQs();
        enableTopIRQs();

        IRQPinsInit();

        return 0;

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +1 -1
@@ 262,5 262,5 @@ void WorkerEvent::processKeyEvent(bsp::KeyEvents event, bsp::KeyCodes code)

void WorkerEvent::checkBatteryLevelCritical()
{
    battery_level_check::checkBatteryLevelCritical();
    battery_level_check::checkBatteryLevelCriticalWithConfirmation();
}

M module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.cpp => module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.cpp +6 -0
@@ 78,6 78,12 @@ namespace battery_level_check
        }
    }

    void checkBatteryLevelCriticalWithConfirmation()
    {
        state = CheckState::InitialCheck;
        checkBatteryLevelCritical();
    }

    void setBatteryCriticalLevel(unsigned int level)
    {
        batteryLevelCritical = level;

M module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.hpp => module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.hpp +2 -0
@@ 16,5 16,7 @@ namespace battery_level_check

    void checkBatteryLevelCritical();

    void checkBatteryLevelCriticalWithConfirmation();

    void setBatteryCriticalLevel(unsigned int level);
} // namespace battery_level_check