mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 23:27:49 +01:00
118 lines
4.5 KiB
C++
118 lines
4.5 KiB
C++
//
|
|
// Created by Stepan Usatiuk on 02.03.2025.
|
|
//
|
|
|
|
#include "bat_mon.hpp"
|
|
|
|
#include <power_helper.hpp>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
|
|
#include "i2c_global.hpp"
|
|
#include "shutdowner.hpp"
|
|
|
|
static i2c_master_dev_handle_t dev_handle;
|
|
|
|
BatMon& BatMon::get() {
|
|
static BatMon bat_mon;
|
|
return bat_mon;
|
|
}
|
|
|
|
static void start_pooler(void* arg) { static_cast<BatMon*>(arg)->pooler(); }
|
|
|
|
void WriteRegister(uint8_t reg, uint16_t value) {
|
|
uint8_t buf2[3];
|
|
buf2[0] = reg;
|
|
buf2[1] = value & 0xFF;
|
|
buf2[2] = value >> 8;
|
|
ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1));
|
|
}
|
|
|
|
uint16_t ReadRegister(uint8_t reg) {
|
|
uint16_t buffer;
|
|
ESP_ERROR_CHECK(
|
|
i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast<uint8_t*>(&buffer), 2, -1));
|
|
return buffer;
|
|
}
|
|
void WriteAndVerifyRegister(char RegisterAddress, int RegisterValueToWrite) {
|
|
int attempt = 0;
|
|
uint16_t RegisterValueRead;
|
|
do {
|
|
WriteRegister(RegisterAddress, RegisterValueToWrite);
|
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
|
RegisterValueRead = ReadRegister(RegisterAddress);
|
|
} while (RegisterValueToWrite != RegisterValueRead && attempt++ < 3);
|
|
}
|
|
|
|
static constexpr float RSense = 0.1; // 100mOhm
|
|
static constexpr uint16_t DesignCapMah = 180; // 100mOhm
|
|
|
|
constexpr float mahToCap(float mah) { return mah * (1000.0 / 5.0) * RSense; }
|
|
constexpr float capToMah(uint16_t cap) { return cap * (5.0 / 1000.0) / RSense; }
|
|
constexpr float regToCurrent(uint16_t reg) {
|
|
return static_cast<float>(static_cast<int16_t>(reg)) * 0.0015625f / RSense; // Convert to mA
|
|
}
|
|
constexpr uint16_t currentToReg(float current) { return static_cast<uint16_t>(current * RSense / 0.0015625f); }
|
|
constexpr float regToVoltage(uint16_t reg) {
|
|
return reg * 0.078125f * 0.001f; // Convert to volts
|
|
}
|
|
constexpr uint16_t voltageToReg(float voltage) {
|
|
return static_cast<uint16_t>(voltage / (0.078125f * 0.001f)); // Convert to register value
|
|
}
|
|
static constexpr uint16_t DesignCap = mahToCap(DesignCapMah);
|
|
static constexpr uint16_t IchgTerm = currentToReg(10);
|
|
static constexpr uint16_t VEmpty = 0b1001011001100001; // (3V/3.88V)
|
|
static constexpr uint16_t dQAcc = (DesignCap / 32);
|
|
|
|
BatMon::BatMon() {
|
|
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cGlobal::get().get_bus_handle(), &_dev_cfg, &dev_handle));
|
|
|
|
bool StatusPOR = ReadRegister(0x00) & 0x0002;
|
|
if (StatusPOR) // POR reset
|
|
{
|
|
printf("Gas gauge reset!\n");
|
|
while (ReadRegister(0x3D) & 1)
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
|
|
uint16_t HibCFG = ReadRegister(0xBA); // Store original HibCFG value
|
|
WriteRegister(0x60, 0x90); // Exit Hibernate Mode step 1
|
|
WriteRegister(0xBA, 0x0); // Exit Hibernate Mode step 2
|
|
WriteRegister(0x60, 0x0); // Exit Hibernate Mode step 3
|
|
WriteRegister(0x18, DesignCap); // Write DesignCap
|
|
WriteRegister(0x45, DesignCap / 32); // Write dQAcc
|
|
WriteRegister(0x1E, IchgTerm); // Write IchgTerm
|
|
WriteRegister(0x3A, VEmpty); // Write VEmpty
|
|
WriteRegister(0x46, dQAcc * 44138 / DesignCap); // Write dPAcc
|
|
WriteRegister(0xDB, 0x8000); // Write ModelCFG
|
|
|
|
// Poll ModelCFG.Refresh(highest bit), proceed to Step 4 when ModelCFG.Refresh = 0.
|
|
while (ReadRegister(0xDB) & 0x8000)
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // 10ms wait loop. Do not continue until ModelCFG.Refresh == 0.
|
|
WriteRegister(0xBA, HibCFG); // Restore Original HibCFG value
|
|
|
|
uint16_t Status = ReadRegister(0x00); // Read Status
|
|
WriteAndVerifyRegister(0x00, Status & 0xFFFD); // Write and Verify Status with POR bit cleared
|
|
}
|
|
|
|
xTaskCreate(&start_pooler, "BatMon", 2048, this, tskIDLE_PRIORITY, &_pooler_task);
|
|
}
|
|
|
|
void BatMon::pooler() {
|
|
while (true) {
|
|
uint8_t reg = 8;
|
|
uint16_t buffer;
|
|
_charge = capToMah(ReadRegister(0x05));
|
|
_current = regToCurrent(ReadRegister(0x0B));
|
|
_voltage = regToVoltage(ReadRegister(0x09));
|
|
PowerHelper::get().delay(10000, 1000);
|
|
if (_voltage < 3.0f) {
|
|
Shutdowner::get().shutdown();
|
|
}
|
|
}
|
|
}
|
|
|
|
float BatMon::get_voltage() const { return _voltage; }
|
|
float BatMon::get_charge() const { return _charge; }
|
|
float BatMon::get_current() const { return _current; }
|