Adafruit_INA237_INA238/Adafruit_INA237.cpp
2025-05-14 09:54:38 -04:00

210 lines
7.2 KiB
C++

/*!
* @file Adafruit_INA237.cpp
*
* @section ina237_intro Introduction
*
* I2C Driver for the INA237/INA238 I2C Current and Power sensor
*
* Note: INA237 and INA238 are functionally identical devices with different
* part numbers. This class implements all functionality for both chips.
*
* This is a library for the Adafruit INA237/INA238 breakouts:
* http://www.adafruit.com/products/xxxx
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing products from
* Adafruit!
*
* @section ina237_dependencies Dependencies
*
* This library depends on the Adafruit BusIO library
*
* @section ina237_author Author
*
* Limor "Ladyada" Fried for Adafruit Industries
*
* @section ina237_license License
*
* MIT (see license.txt)
*
* @section ina237_history HISTORY
*
* v1.0 - First release
*/
#include "Adafruit_INA237.h"
#include <Wire.h>
#include "Arduino.h"
/*!
* @brief Instantiates a new INA237 class
*/
Adafruit_INA237::Adafruit_INA237(void) {}
/*!
* @brief Sets up the HW
* @param i2c_address
* The I2C address to be used.
* @param theWire
* The Wire object to be used for I2C connections.
* @param skipReset
* When set to true, will omit resetting all INA237 registers to
* their default values. Default: false.
* @return True if initialization was successful, otherwise false.
*/
bool Adafruit_INA237::begin(uint8_t i2c_address, TwoWire* theWire,
bool skipReset) {
if (!Adafruit_INA2xx::begin(i2c_address, theWire, skipReset)) {
return false;
}
// make sure we're talking to the right chip
if (_device_id != INA237_DEVICE_ID) {
return false;
}
return true;
}
/**************************************************************************/
/*!
@brief Updates the shunt calibration value to the INA237 register.
The INA237 uses a different calculation than the INA228.
*/
/**************************************************************************/
void Adafruit_INA237::_updateShuntCalRegister() {
// Formula from INA237 datasheet (SBOSA20A)
// SHUNT_CAL = 819.2 x 10^6 x CURRENT_LSB x RSHUNT
float scale = 1;
if (getADCRange()) {
scale = 4; // For lower range (+/-40.96mV)
}
// Correct calculation for INA237
float shunt_cal = 819.2e6 * _current_lsb * _shunt_res * scale;
Adafruit_I2CRegister shunt =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_SHUNTCAL, 2, MSBFIRST);
shunt.write(shunt_cal);
}
/**************************************************************************/
/*!
@brief Returns the current alert type
@return The current alert type
*/
/**************************************************************************/
INA237_AlertType Adafruit_INA237::getAlertType(void) {
// The alert bits are in different positions in the INA237
Adafruit_I2CRegisterBits alert_type =
Adafruit_I2CRegisterBits(Diag_Alert, 7, 5);
return (INA237_AlertType)alert_type.read();
}
/**************************************************************************/
/*!
@brief Sets a new alert type
@param alert
The new alert type to be set
*/
/**************************************************************************/
void Adafruit_INA237::setAlertType(INA237_AlertType alert) {
// The alert bits are in different positions in the INA237
Adafruit_I2CRegisterBits alert_type =
Adafruit_I2CRegisterBits(Diag_Alert, 7, 5);
alert_type.write(alert);
}
/**************************************************************************/
/*!
@brief Reads the die temperature with the INA237-specific conversion factor
@return The current die temp in deg C
*/
/**************************************************************************/
float Adafruit_INA237::readDieTemp(void) {
Adafruit_I2CRegister temp =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_DIETEMP, 2, MSBFIRST);
int16_t t = temp.read();
// INA237 uses 12 bits for temperature (bits 15:4) with 125 m°C/LSB
// Shift by 4 to get the actual value from register bits 15:4
return (float)(t >> 4) * 125.0 / 1000.0;
}
/**************************************************************************/
/*!
@brief Reads and scales the current value of the Bus Voltage register
using INA237-specific conversion factor.
@return The current bus voltage measurement in V
*/
/**************************************************************************/
float Adafruit_INA237::readBusVoltage(void) {
Adafruit_I2CRegister bus_voltage =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_VBUS, 2, MSBFIRST);
// INA237 uses 3.125 mV/LSB for bus voltage
// Bus voltage is a 16-bit value in the INA237 (unlike INA228 which is 24-bit)
return (float)((uint16_t)bus_voltage.read()) * 3.125 / 1000.0;
}
/**************************************************************************/
/*!
@brief Reads and scales the current value of the Shunt Voltage register
using INA237-specific conversion factor.
@return The current shunt voltage measurement in V
*/
/**************************************************************************/
float Adafruit_INA237::readShuntVoltage(void) {
float scale = 5.0; // 5 µV/LSB in normal mode
if (getADCRange()) {
scale = 1.25; // 1.25 µV/LSB in low range mode
}
Adafruit_I2CRegister shunt_voltage =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_VSHUNT, 2, MSBFIRST);
int16_t v = shunt_voltage.read();
return (float)v * scale / 1000000.0; // Convert µV to V
}
/**************************************************************************/
/*!
@brief Reads and scales the current value of the Current register
using INA237-specific handling.
@return The current measurement in mA
*/
/**************************************************************************/
float Adafruit_INA237::readCurrent(void) {
Adafruit_I2CRegister current =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_CURRENT, 2, MSBFIRST);
int16_t i = current.read();
return (float)i * _current_lsb * 1000.0; // Convert A to mA
}
/**************************************************************************/
/*!
@brief Reads and scales the current value of the Power register
using INA237-specific handling.
@return The current Power calculation in mW
*/
/**************************************************************************/
float Adafruit_INA237::readPower(void) {
Adafruit_I2CRegister power =
Adafruit_I2CRegister(i2c_dev, INA2XX_REG_POWER, 2, MSBFIRST);
// INA237 power LSB = 20 * current_lsb
return (float)power.read() * 20.0 * _current_lsb * 1000.0; // Convert W to mW
}
/**************************************************************************/
/*!
@brief Sets the shunt calibration by resistor for INA237.
@param shunt_res Resistance of the shunt in ohms (floating point)
@param max_current Maximum expected current in A (floating point)
*/
/**************************************************************************/
void Adafruit_INA237::setShunt(float shunt_res, float max_current) {
_shunt_res = shunt_res;
// INA237 uses 2^15 as the divisor
_current_lsb = max_current / (float)(1UL << 15);
_updateShuntCalRegister();
}