Skip to content

Commit

Permalink
Merge pull request #16 from senseshift/feature/max170xx
Browse files Browse the repository at this point in the history
✨ Add MAX170xx fuel gauge
  • Loading branch information
leon0399 authored Jul 28, 2024
2 parents 3ac7669 + 03eb497 commit 8db7eab
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 4 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
- "PCA9685/Servo"
- "PCA9685/VibroPulse"
- "MPU6050/BasicReadings"
- "MAX170XX/Simple"
boards: [ [ uno, esp32dev ] ]

steps:
Expand Down Expand Up @@ -79,15 +80,12 @@ jobs:
pio pkg update --global
- name: Build example
shell: bash
run: |
set -o pipefail
# for whatever reason, if we specify the build dir, it doesn't work
# mkdir -p ${{ env.PLATFORMIO_BUILD_DIR }}
pio ci --lib="." --board=${{ join(matrix.boards, ' --board=') }} --keep-build-dir 2>&1 | tee output.log
if [ $? -ne 0 ]; then exit 1; fi
export PLATFORMIO_BUILD_DIR=$(grep -oP 'The following files/directories have been created in \K.*' output.log)
echo "PLATFORMIO_BUILD_DIR=$PLATFORMIO_BUILD_DIR" >> "$GITHUB_ENV"
env:
Expand Down
37 changes: 37 additions & 0 deletions examples/MAX170XX/Simple/Simple.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <I2CDevLib.h>
#include <i2cdev/max170xx.hpp>

i2cdev::MAX17048 max17048;

void setup() {
Serial.begin(115200);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens

Wire.begin();

Serial.println("I2CDevLibContrib MAX170XX test!");

// Wait for the MAX170XX to be ready
delay(1000);

if (max17048.check() != I2CDEV_RESULT_OK) {
Serial.println("Failed to find MAX170XX chip");
while (true) {}
}
Serial.println("MAX170XX Found!");
if (max17048.quickStart() != I2CDEV_RESULT_OK) {
Serial.println("Failed to quick start MAX170XX chip");
while (true) {}
}
}

void loop() {
auto voltage = max17048.readVoltage();
auto soc = max17048.readSoc();

Serial.print("Voltage: "); Serial.print(voltage); Serial.print(" V");
Serial.print(" SoC: "); Serial.print(soc); Serial.println(" %");

delay(500);
}
48 changes: 48 additions & 0 deletions src/i2cdev/max170xx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef __I2CDEVLIB_MAX170XX_H__
#define __I2CDEVLIB_MAX170XX_H__

#include "i2cdevbus.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#define MAX1704X_I2CADDR_BASE (0x36)

typedef enum max170xx_reg_t {
/// Cell voltage
MAX170XX_REG_VCELL = 0x02,

/// State of charge
MAX170XX_REG_SOC = 0x04,
MAX170XX_REG_MODE = 0x06,
MAX170XX_REG_VERSION = 0x08,

/// MAC17048/MAX17049 only
MAX170XX_REG_HIBRT = 0x0A,
MAX170XX_REG_CONFIG = 0x0C,

/// MAC17048/MAX17049 only
MAX170XX_REG_VALERT = 0x14,

/// MAC17048/MAX17049 only
MAX170XX_REG_CRATE = 0x16,

/// MAC17048/MAX17049 only
MAX170XX_REG_VRESET_ID = 0x18,
MAX170XX_REG_CHIP_ID = 0x19,
MAX170XX_REG_STATUS = 0x1A,

MAX1704X_REG_COMMAND = 0xFE
} max1704x_reg_t;

#define MAX1704X_MODE_QUICKSTART (0x4000)

#define MAX1704_COMMAND_POR_43_44 (0x0054)
#define MAX1704_COMMAND_POR_X8_X9 (0x5400)

#ifdef __cplusplus
};
#endif // __cplusplus

#endif //__I2CDEVLIB_MAX170XX_H__
173 changes: 173 additions & 0 deletions src/i2cdev/max170xx.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#ifndef __I2CDEVLIB_MAX170XX_HPP__
#define __I2CDEVLIB_MAX170XX_HPP__

#include "i2cdev/max170xx.h"
#include "i2cdevbus.hpp"

namespace i2cdev {
class MAX170XX {
public:
#ifdef I2CDEV_DEFAULT_BUS
MAX170XX(uint8_t addr = MAX1704X_I2CADDR_BASE, I2CDevBus& bus = I2CDEV_DEFAULT_BUS) : _addr(addr), _bus(bus) {}
#else
MAX170XX(uint8_t addr, I2CDevBus& bus) : _addr(addr), _bus(bus) {}
#endif

[[nodiscard]] auto check() -> i2cdev_result_t;

[[nodiscard]] inline auto quickStart() -> i2cdev_result_t;

protected:
uint8_t _addr;
I2CDevBus& _bus;
};

class MAX17043 : public MAX170XX {
public:
using MAX170XX::MAX170XX;

inline auto readVoltage() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_VCELL, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return (data >> 4) / 800.0f;
}

inline auto readSoc() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_SOC, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return ((data & 0xFF00) >> 8) + ((data & 0x00FF) / 256.0f);
}

[[nodiscard]] inline auto reset() -> i2cdev_result_t
{
return this->_bus.writeReg16(this->_addr, MAX1704X_REG_COMMAND, static_cast<uint16_t>(MAX1704_COMMAND_POR_43_44));
}
};

class MAX17044 : public MAX170XX {
public:
using MAX170XX::MAX170XX;

inline auto readVoltage() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_VCELL, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return (data >> 4) / 400.0f;
}

inline auto readSoc() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_SOC, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return ((data & 0xFF00) >> 8) + ((data & 0x00FF) / 256.0f);
}

[[nodiscard]] inline auto reset() -> i2cdev_result_t
{
return this->_bus.writeReg16(this->_addr, MAX1704X_REG_COMMAND, static_cast<uint16_t>(MAX1704_COMMAND_POR_43_44));
}
};

class MAX170x8 : public MAX170XX {
public:
using MAX170XX::MAX170XX;

inline auto readVoltage() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_VCELL, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return data * 5.0f / 64000.0f;
}

inline auto readSoc() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_SOC, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return data / 256.0f;
}

[[nodiscard]] inline auto reset() -> i2cdev_result_t
{
return this->_bus.writeReg16(this->_addr, MAX1704X_REG_COMMAND, static_cast<uint16_t>(MAX1704_COMMAND_POR_X8_X9));
}
};

using MAX17048 = MAX170x8;
using MAX17058 = MAX170x8;

class MAX170x9 : public MAX170XX {
public:
using MAX170XX::MAX170XX;

inline auto readVoltage() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_VCELL, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return data * 5.0f / 32000.0f;
}

inline auto readSoc() -> float
{
uint16_t data;
if (this->_bus.readReg16(this->_addr, MAX170XX_REG_SOC, &data) != I2CDEV_RESULT_OK) {
return 0.0f;
}

return data / 256.0f;
}

[[nodiscard]] inline auto reset() -> i2cdev_result_t
{
return this->_bus.writeReg16(this->_addr, MAX1704X_REG_COMMAND, static_cast<uint16_t>(MAX1704_COMMAND_POR_X8_X9));
}
};

using MAX17049 = MAX170x9;
using MAX17059 = MAX170x9;

inline auto MAX170XX::check() -> i2cdev_result_t {
uint16_t data;
i2cdev_result_t result;

// wait for the device to be ready
for (int i = 0; i < 5; i++) {
result = this->_bus.readReg16(this->_addr, MAX170XX_REG_VERSION, &data);
if (result == I2CDEV_RESULT_OK) {
break;
}

i2cdev_platform_sleep_us(10000);
}

return result;
}

inline auto MAX170XX::quickStart() -> i2cdev_result_t {
return this->_bus.writeReg16(this->_addr, MAX170XX_REG_MODE, static_cast<uint16_t>(MAX1704X_MODE_QUICKSTART));
}
}

#endif //__I2CDEVLIB_MAX170XX_HPP__

0 comments on commit 8db7eab

Please sign in to comment.