INA226 I2C Current/Power Monitor
The Ina226 class implements support for the Texas Instruments INA226 current and power monitor. It exposes helpers to configure averaging and conversion times, program calibration based on shunt resistance and desired current LSB, and read shunt voltage, bus voltage, current, and power.
API Reference
Header File
Classes
-
class Ina226 : public espp::BasePeripheral<uint8_t, true>
INA226 Current/Power Monitor (I2C)
Provides helpers to configure and read bus voltage, shunt voltage, current, and power. Uses BasePeripheral for I2C access, 8-bit register addresses.
Section: Example
extern "C" void app_main(void) { espp::Logger logger({.tag = "INA226 Example", .level = espp::Logger::Verbosity::INFO}); espp::I2c i2c({ .port = I2C_NUM_1, .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO, .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO, .clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_SPEED_HZ, }); // since the ina226 can have addresses ranging from 0x40 to 0x4F, we probe for // it #if defined(CONFIG_EXAMPLE_USE_STATIC_ADDRESS) uint8_t address = CONFIG_EXAMPLE_I2C_ADDRESS; #else uint8_t address = espp::Ina226::DEFAULT_ADDRESS; static constexpr uint8_t max_address = 0x4F; while (!i2c.probe_device(address) && address <= max_address) { address++; } if (address > max_address) { logger.info("INA226 not found on I2C bus!"); return; } #endif logger.info("Using INA226 address 0x{:02X}", address); // Configure INA226 with reasonable defaults and known shunt resistor espp::Ina226 ina({ .device_address = address, .averaging = espp::Ina226::Avg::AVG_16, .bus_conv_time = espp::Ina226::ConvTime::MS_1_1, .shunt_conv_time = espp::Ina226::ConvTime::MS_1_1, .mode = espp::Ina226::Mode::SHUNT_BUS_CONT, .current_lsb = 0.001f, // 1mA / LSB .shunt_resistance_ohms = 0.1f, // 0.1 ohm .probe = std::bind(&espp::I2c::probe_device, &i2c, std::placeholders::_1), .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), .read_register = std::bind(&espp::I2c::read_at_register, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), .write_then_read = std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), .log_level = espp::Logger::Verbosity::WARN, }); std::error_code ec; // Optional explicit initialize ina.initialize(ec); if (ec) { logger.info("INA226 init failed: {}", ec.message()); return; } auto task_fn = [&](std::mutex &m, std::condition_variable &cv) { auto now = std::chrono::high_resolution_clock::now(); float vbus = ina.bus_voltage_volts(ec); float vshunt = ina.shunt_voltage_volts(ec); float current = ina.current_amps(ec); float power = ina.power_watts(ec); if (ec) { logger.info("INA226 read failed: {}", ec.message()); return true; // stop } logger.info("Vbus={:.3f}V, Vshunt={:.6f}V, I={:.3f}A, P={:.3f}W", vbus, vshunt, current, power); { std::unique_lock<std::mutex> lk(m); cv.wait_until(lk, now + 250ms); } return false; }; espp::Task task({.callback = task_fn, .task_config = {.name = "INA226 Task", .stack_size_bytes = 4 * 1024}, .log_level = espp::Logger::Verbosity::WARN}); task.start(); while (true) { std::this_thread::sleep_for(1s); } }
Public Types
-
enum class Avg : uint16_t
Averaging (AVG) field values (bits 14..12 of CONFIG)
Values:
-
enumerator AVG_1
-
enumerator AVG_4
-
enumerator AVG_16
-
enumerator AVG_64
-
enumerator AVG_128
-
enumerator AVG_256
-
enumerator AVG_512
-
enumerator AVG_1024
-
enumerator AVG_1
-
enum class ConvTime : uint16_t
Bus/Shunt conversion time (VBUSCT/VSHCT) field values (bits 11..9, 8..6)
Values:
-
enumerator US_140
-
enumerator US_204
-
enumerator US_332
-
enumerator US_588
-
enumerator MS_1_1
-
enumerator MS_2_116
-
enumerator MS_4_156
-
enumerator MS_8_244
-
enumerator US_140
-
enum class Mode : uint16_t
Operating mode (MODE bits 2..0)
Values:
-
enumerator POWER_DOWN
-
enumerator SHUNT_TRIG
-
enumerator BUS_TRIG
-
enumerator SHUNT_BUS_TRIG
-
enumerator ADC_OFF
-
enumerator SHUNT_CONT
-
enumerator BUS_CONT
-
enumerator SHUNT_BUS_CONT
-
enumerator POWER_DOWN
-
typedef std::function<bool(uint8_t)> probe_fn
Function to probe the peripheral
- Param address:
The address to probe
- Return:
True if the peripheral is found at the given address
Public Functions
-
inline explicit Ina226(const Config &config)
Constructor with configuration
- Parameters:
config – Configuration structure with device address, averaging, conversion times, mode, current LSB, shunt resistance, and I/O hooks
-
inline bool initialize(std::error_code &ec)
Initialize the INA226
- Parameters:
ec – Error code to capture any initialization errors
- Returns:
true if initialization succeeded, false if it failed
-
inline uint16_t manufacturer_id(std::error_code &ec)
Read manufacturer ID (0x5449 for Texas Instruments)
- Parameters:
ec – Error code to capture any read errors
- Returns:
Manufacturer ID (0x5449) or 0 on error
-
inline uint16_t die_id(std::error_code &ec)
Read die ID (0x2260 for INA226)
- Parameters:
ec – Error code to capture any read errors
- Returns:
Die ID (0x2260) or 0 on error
-
inline float shunt_voltage_volts(std::error_code &ec)
Read shunt voltage in volts
Note
The shunt voltage is signed, so it can be negative if the current flows in the reverse direction. The LSB is 2.5 uV
- Parameters:
ec – Error code to capture any read errors
- Returns:
Shunt voltage in volts, or 0.0f on error
-
inline float bus_voltage_volts(std::error_code &ec)
Read bus voltage in volts
Note
The bus voltage is unsigned, so it cannot be negative. The LSB is 1.25 mV
- Parameters:
ec – Error code to capture any read errors
- Returns:
Bus voltage in volts, or 0.0f on error
-
inline float current_amps(std::error_code &ec)
Read current in amps
Note
The current is signed, so it can be negative if the current flows in the reverse direction. The LSB is set via the calibrate() method and is in Amps/LSB.
- Parameters:
ec – Error code to capture any read errors
- Returns:
Current in amps, or 0.0f on error
-
inline float power_watts(std::error_code &ec)
Read power in watts
Note
The power is unsigned, so it cannot be negative. The LSB is 25 * current_lsb, where current_lsb is set via the calibrate() method.
- Parameters:
ec – Error code to capture any read errors
- Returns:
Power in watts, or 0.0f on error
-
inline bool configure(Avg avg, ConvTime vbus, ConvTime vshunt, Mode mode, std::error_code &ec)
Configure the INA226 with averaging, conversion times, and mode
- Parameters:
avg – Averaging mode
vbus – Bus voltage conversion time
vshunt – Shunt voltage conversion time
mode – Operating mode
ec – Error code to capture any write errors
- Returns:
true if configuration succeeded, false if it failed
-
inline bool calibrate(float current_lsb, float shunt_res_ohms, std::error_code &ec)
Calibrate the INA226 with current LSB and shunt resistance
Note
This function programs the CALIBRATION register based on the provided current_lsb and shunt resistance. The current_lsb is used to determine the scaling of the CURRENT and POWER registers. The shunt resistance is used to calculate the calibration value.
Note
The current_lsb should be chosen based on the expected maximum current and the resolution required. A smaller current_lsb provides higher resolution but reduces the maximum measurable current.
Note
Per the datasheet, the calibration value is calculated as:
\[ Cal = floor(0.00512 / (current_lsb * shunt_res_ohms)) \]This ensures that the calibration value is non-zero and avoids division by zero. If the calculated value is zero, it is set to 1 to avoid issues. This function should be called after configuring the INA226.- Parameters:
current_lsb – Current LSB in Amps/LSB
shunt_res_ohms – Shunt resistance in Ohms
ec – Error code to capture any write errors
- Returns:
true if calibration succeeded, false if it failed
-
inline bool probe(std::error_code &ec)
Probe the peripheral
Note
This function is thread safe
Note
If the probe function is not set, this function will return false and set the error code to operation_not_supported
Note
This function is only available if UseAddress is true
- Parameters:
ec – The error code to set if there is an error
- Returns:
True if the peripheral is found
-
inline void set_address(uint8_t address)
Set the address of the peripheral
Note
This function is thread safe
Note
This function is only available if UseAddress is true
- Parameters:
address – The address of the peripheral
-
inline void set_probe(const probe_fn &probe)
Set the probe function
Note
This function is thread safe
Note
This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.
Note
This function is only available if UseAddress is true
- Parameters:
probe – The probe function
-
inline void set_write(const write_fn &write)
Set the write function
Note
This function is thread safe
Note
This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.
- Parameters:
write – The write function
-
inline void set_read(const read_fn &read)
Set the read function
Note
This function is thread safe
Note
This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.
- Parameters:
read – The read function
-
inline void set_read_register(const read_register_fn &read_register)
Set the read register function
Note
This function is thread safe
Note
This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.
- Parameters:
read_register – The read register function
-
inline void set_write_then_read(const write_then_read_fn &write_then_read)
Set the write then read function
Note
This function is thread safe
Note
This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then
- Parameters:
write_then_read – The write then read function
-
inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
Set the delay between the write and read operations in write_then_read
Note
This function is thread safe
Note
This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.
Note
This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.
- Parameters:
delay – The delay between the write and read operations in write_then_read
-
inline void set_config(const Config &config)
Set the configuration for the peripheral
Note
This function is thread safe
Note
The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.
- Parameters:
config – The configuration for the peripheral
-
inline void set_config(Config &&config)
Set the configuration for the peripheral
Note
This function is thread safe
Note
The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.
- Parameters:
config – The configuration for the peripheral
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
Public Static Attributes
-
static constexpr uint8_t DEFAULT_ADDRESS = 0x40
Default I2C address if A0/A1=GND.
Address is configured based on whether A0/A1 are connected to GND, VCC, SDA, or SCL, address can be 0x40..0x4F
-
struct Config
Configuration structure for INA226.
Public Members
-
uint8_t device_address = DEFAULT_ADDRESS
I2C address, 0x40..0x4F.
-
Mode mode = Mode::SHUNT_BUS_CONT
Operating mode.
-
BasePeripheral::probe_fn probe = {nullptr}
Probe function to check I2C device presence.
-
BasePeripheral::write_fn write = {nullptr}
Write function to send data to I2C device.
-
BasePeripheral::read_register_fn read_register{nullptr}
Read function to read a register from I2C device.
-
BasePeripheral::write_then_read_fn write_then_read{nullptr}
Write then read function for I2C device.
-
bool auto_init = true
Automatically initialize on construction.
-
uint8_t device_address = DEFAULT_ADDRESS
-
enum class Avg : uint16_t