pkolt/ina226

1.0.0

Latest
uploaded 1 hour ago
ESP-IDF driver for the Texas Instruments INA226 current, voltage, and power monitor

Readme

# INA226 for ESP-IDF (ESP32)

- [INA226 for ESP-IDF (ESP32)](#ina226-for-esp-idf-esp32)
  - [Introduction](#introduction)
    - [Feature overview](#feature-overview)
    - [Register map](#register-map)
    - [Operating modes (`MODE` field, bits `2:0` of register `00h`)](#operating-modes-mode-field-bits-20-of-register-00h)
    - [`ALERT` pin](#alert-pin)
  - [Sensor configuration](#sensor-configuration)
    - [`ina226_config_t` parameters](#ina226_config_t-parameters)
    - [Allowed values](#allowed-values)
    - [Can I skip manual config?](#can-i-skip-manual-config)
  - [Single-shot measurement mode](#single-shot-measurement-mode)
  - [Continuous measurement mode](#continuous-measurement-mode)
  - [`ALERT` interrupt on threshold crossing](#alert-interrupt-on-threshold-crossing)
  - [`ALERT` interrupts on conversion ready](#alert-interrupts-on-conversion-ready)
  - [Power-Down mode](#power-down-mode)
  - [API](#api)
    - [Creation and lifecycle](#creation-and-lifecycle)
    - [Measurements and operating modes](#measurements-and-operating-modes)
    - [Reading measured values](#reading-measured-values)
    - [ALERT and threshold events](#alert-and-threshold-events)
    - [Default configuration](#default-configuration)
  - [License](#license)


## Introduction

`INA226` is a digital power monitor with an I2C interface. It measures bus voltage (`VBUS`) and shunt voltage drop (`VSHUNT`), and also calculates current and power (after calibration).

### Feature overview

- Measurement of:
  - bus voltage (`Bus Voltage`, register `02h`),
  - shunt voltage (`Shunt Voltage`, register `01h`),
  - current (`Current`, register `04h`, after writing calibration),
  - power (`Power`, register `03h`, after writing calibration).
- Flexible ADC setup via configuration register `00h`:
  - averaging (`AVG`),
  - conversion time for `VBUS` and `VSHUNT` (`VBUSCT`, `VSHCT`),
  - operating mode (`MODE`).
- Software reset support (`RST`, bit 15 of register `00h`).
- Calibration for a specific shunt via register `05h` (`Calibration`).
- Support for hardware `ALERT` output:
  - threshold events (over/under limit),
  - data-ready signal (`Conversion Ready`).
- Chip communication check via `Die ID` (`FFh`, default value `2260h`).

### Register map

| Address | Access | Register | Default | Purpose |
| :---: | :---: | :--- | :---: | :--- |
| `00h` | R/W | Configuration | `4127h` | ADC setup, averaging, conversion time, mode, reset |
| `01h` | R | Shunt Voltage | `0000h` | Measured shunt voltage drop |
| `02h` | R | Bus Voltage | `0000h` | Measured bus voltage |
| `03h` | R | Power | `0000h` | Calculated power (after calibration) |
| `04h` | R | Current | `0000h` | Calculated current (after calibration) |
| `05h` | R/W | Calibration | `0000h` | Calibration coefficient |
| `06h` | R/W | Mask/Enable | `0000h` | Masks, flags, and `ALERT` polarity/latch |
| `07h` | R/W | Alert Limit | `0000h` | Threshold for `ALERT` triggering |
| `FFh` | R | Die ID | `2260h` | Chip identifier |

### Operating modes (`MODE` field, bits `2:0` of register `00h`)

| MODE | Mode |
| :--: | :--- |
| `000` | Power-Down (disabled) |
| `001` | Shunt Voltage, trigger (single shunt measurement) |
| `010` | Bus Voltage, trigger (single bus measurement) |
| `011` | Shunt + Bus, trigger (single shunt and bus measurement) |
| `100` | Power-Down (disabled) |
| `101` | Shunt Voltage, continuous |
| `110` | Bus Voltage, continuous |
| `111` | Shunt + Bus, continuous (default mode) |

### `ALERT` pin

The `ALERT` output is configured through the `Mask/Enable` (`06h`) and `Alert Limit` (`07h`) registers.

- Threshold events:
  - `SOL`/`SUL` — shunt voltage out-of-range,
  - `BOL`/`BUL` — bus voltage out-of-range,
  - `POL` — power threshold exceeded.
- Data-ready event:
  - `CNVR` (source mask),
  - `CVRF` (conversion-ready flag).
- Service bits:
  - `AFF` — alert function flag,
  - `OVF` — math overflow,
  - `APOL` — `ALERT` polarity (`0` — active-low, `1` — active-high),
  - `LEN` — output mode (`0` — transparent, `1` — latched).

## Sensor configuration

After `ina226_create()`, configure the device using `ina226_init(sensor, bus, cfg)`.

- If `cfg != NULL`, your values from `ina226_config_t` are used.
- If `cfg == NULL`, the library uses `INA226_DEFAULT_CONFIG()`.

Important: after `ina226_init()`, the driver leaves INA226 in `Power-Down` mode; starting measurements is done separately (`ina226_measure()`, `ina226_start_single()`, or `ina226_start_continuous()`).

### `ina226_config_t` parameters

```c
typedef struct {
    float r_shunt_ohms;
    float max_expected_amps;
    ina226_avg_t avg;
    ina226_conv_t bus_ct;
    ina226_conv_t shunt_ct;
    uint8_t address;
    uint8_t measurements;
} ina226_config_t;
```

| Field | Meaning | Default value |
| :--- | :--- | :--- |
| `r_shunt_ohms` | Shunt resistance, ohms. Used for calibration and current/power conversion. | `0.1f` |
| `max_expected_amps` | Expected maximum current, amps. Affects `Current_LSB` and the calibration coefficient. | `1.0f` |
| `avg` | ADC averaging (`AVG`, register `00h`). | `INA226_AVG_1` |
| `bus_ct` | `VBUS` channel conversion time (`VBUSCT`, register `00h`). | `INA226_CONV_TIME_1_1MS` |
| `shunt_ct` | `VSHUNT` channel conversion time (`VSHCT`, register `00h`). | `INA226_CONV_TIME_1_1MS` |
| `address` | 7-bit INA226 I2C address. | `INA226_I2C_DEFAULT_ADDR` (`0x40`) |
| `measurements` | Bitmask of measured/read values (`ina226_measurements_t`). | `INA226_MEAS_ALL` |

### Allowed values

- `avg`: `INA226_AVG_1`, `INA226_AVG_4`, `INA226_AVG_16`, `INA226_AVG_64`, `INA226_AVG_128`, `INA226_AVG_256`, `INA226_AVG_512`, `INA226_AVG_1024`.
- `bus_ct` / `shunt_ct`: `INA226_CONV_TIME_140US`, `INA226_CONV_TIME_204US`, `INA226_CONV_TIME_332US`, `INA226_CONV_TIME_588US`, `INA226_CONV_TIME_1_1MS`, `INA226_CONV_TIME_2_116MS`, `INA226_CONV_TIME_4_156MS`, `INA226_CONV_TIME_8_244MS`.
- `address`: from `0x40` to `0x4F` inclusive.
- `measurements`: combination of flags:
  - `INA226_MEAS_BUS_VOLTAGE`
  - `INA226_MEAS_SHUNT_VOLTAGE`
  - `INA226_MEAS_CURRENT`
  - `INA226_MEAS_POWER`
  - or simply `INA226_MEAS_ALL`

> You must not pass an empty mask (`0`). At least one channel must be selected.

### Can I skip manual config?

Yes. You can skip configuration entirely and pass `NULL`:

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));
```

This is a valid and recommended quick-start option (and it is what the `examples/*` use).

If you need precise tuning for your hardware (different shunt, different address, different timings/averaging), create a config from defaults and change only required fields:

```c
ina226_config_t cfg = INA226_DEFAULT_CONFIG();
cfg.r_shunt_ohms = 0.02f;
cfg.max_expected_amps = 10.0f;
cfg.avg = INA226_AVG_16;
cfg.bus_ct = INA226_CONV_TIME_2_116MS;
cfg.shunt_ct = INA226_CONV_TIME_2_116MS;
cfg.address = 0x41;
cfg.measurements = INA226_MEAS_ALL;

ESP_ERROR_CHECK(ina226_init(sensor, bus, &cfg));
```

## Single-shot measurement mode

Single-shot (triggered) mode is convenient when measurements are needed on demand: for example once per second, on an event, or on command from another module.

This library provides two workflows:

1. `ina226_measure(sensor, &measure)` — the simplest way:
   - starts one conversion in trigger mode,
   - waits computed conversion time (taking `AVG`, `VBUSCT`, and `VSHCT` into account),
   - checks readiness,
   - reads selected channels into `ina226_measure_t`.

2. `ina226_start_single(sensor)` + `ina226_read_measure(sensor, &measure)` — manual way:
   - conversion start is separate,
   - waiting/synchronization is fully controlled by you (for example via `ALERT`/`CNVR`),
   - reading is done in a separate call.

`MODE` is chosen automatically from `cfg.measurements`:
- only `INA226_MEAS_BUS_VOLTAGE` → `Bus trigger` (`010`),
- only shunt/current (without power) → `Shunt trigger` (`001`),
- `INA226_MEAS_POWER` (even without other flags), mixed sets, or `INA226_MEAS_ALL` → `Shunt + Bus trigger` (`011`).

Example (as in `examples/triggered_mode`):

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));

while (true) {
    ina226_measure_t measure = {0};
    esp_err_t err = ina226_measure(sensor, &measure);

    if (err == ESP_OK) {
        // Use measure.bus_voltage_v, measure.shunt_voltage_mv,
        // measure.current_a, measure.power_w
    }

    vTaskDelay(pdMS_TO_TICKS(1000));
}
```

> In triggered mode, each new measurement cycle requires a new start (via `ina226_measure()` or `ina226_start_single()`).

## Continuous measurement mode

Continuous mode is suitable for nonstop monitoring: INA226 continuously performs conversions by itself, and the MCU only reads fresh values.

Basic flow:
1. `ina226_start_continuous(sensor)` — switches the sensor into continuous mode.
2. Periodically check data readiness with `ina226_get_ready(sensor, &ready)`.
3. When `ready == true`, read values via `ina226_read_measure(sensor, &measure)`.
4. Stop measurements when needed: `ina226_stop_continuous(sensor)` (returns to `Power-Down`).

`MODE` is also selected automatically from the `measurements` mask:
- only `INA226_MEAS_BUS_VOLTAGE` → `Bus continuous` (`110`),
- only shunt/current (without power) → `Shunt continuous` (`101`),
- `INA226_MEAS_POWER` (even without other flags), mixed sets, or `INA226_MEAS_ALL` → `Shunt + Bus continuous` (`111`).

Example (as in `examples/continuous_mode`):

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));
ESP_ERROR_CHECK(ina226_start_continuous(sensor));

while (true) {
    bool ready = false;

    while (!ready) {
        ESP_ERROR_CHECK(ina226_get_ready(sensor, &ready));
        if (!ready) {
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }

    ina226_measure_t measure = {0};
    ESP_ERROR_CHECK(ina226_read_measure(sensor, &measure));

    // Use measure.*
}
```

> `ina226_read_measure()` does not change INA226 mode; it only reads selected channel registers.

## `ALERT` interrupt on threshold crossing

This mode is used when you need a hardware signal as soon as a measured value crosses a threshold (for example, `VBUS` drops below an acceptable level).

Basic flow:
1. Initialize sensor: `ina226_init(sensor, bus, cfg_or_null)`.
2. Configure source/condition/threshold: `ina226_set_alert(...)`.
3. Start continuous measurements: `ina226_start_continuous(sensor)`.
4. In ISR/task, read status via `ina226_get_alert_status(sensor, &status)`.

Example (as in `examples/threshold_alert`, trigger when `VBUS < 2.6V`):

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));

ESP_ERROR_CHECK(ina226_set_alert(sensor,
    INA226_ALERT_BUS_VOLTAGE,
    INA226_ALERT_MODE_LATCHED,
    INA226_ALERT_BELOW,
    2.6f));

ESP_ERROR_CHECK(ina226_start_continuous(sensor));

// ... after ALERT IRQ
ina226_alert_status_t status = INA226_ALERT_STATUS_NONE;
ESP_ERROR_CHECK(ina226_get_alert_status(sensor, &status));

if (status == INA226_ALERT_STATUS_BUS_UNDER_LIMIT) {
    float vbus = 0.0f;
    ESP_ERROR_CHECK(ina226_read_bus_voltage(sensor, &vbus));
    // fault handling
}
```

Important:
- `INA226_ALERT_MODE_TRANSPARENT` (`LEN=0`) — `ALERT` is released automatically when the condition disappears.
- `INA226_ALERT_MODE_LATCHED` (`LEN=1`) — `ALERT` stays latched until register `06h` is read.
- In this library, reading `ina226_get_alert_status()` / `ina226_get_alert_flags()` also acknowledges the event (ACK): it clears `ALERT` latch (when `LEN=1`) and clears corresponding status flags.

## `ALERT` interrupts on conversion ready

This mode is useful to synchronize reading of fresh data without constant polling.

To enable it, use:
- `ina226_set_conversion_ready_alert(sensor, true)` — enables `CNVR`, sets `ALERT` to transparent mode, and disables threshold sources so `ALERT` is used only for conversion-ready events.

Typical flow (as in `examples/conversion_ready`):
1. `ina226_set_conversion_ready_alert(sensor, true)`.
2. Start measurement (`ina226_start_single(sensor)` for single-shot or continuous mode).
3. Wait for `ALERT` IRQ.
4. In task, read `ina226_get_alert_status(sensor, &status)` and ensure `status == INA226_ALERT_STATUS_CONVERSION_READY`.
5. Read data using `ina226_read_measure(sensor, &measure)`.

Single-shot example:

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));
ESP_ERROR_CHECK(ina226_set_conversion_ready_alert(sensor, true));

ESP_ERROR_CHECK(ina226_start_single(sensor));
// wait IRQ ...

ina226_alert_status_t status = INA226_ALERT_STATUS_NONE;
ESP_ERROR_CHECK(ina226_get_alert_status(sensor, &status));

if (status == INA226_ALERT_STATUS_CONVERSION_READY) {
    ina226_measure_t measure = {0};
    ESP_ERROR_CHECK(ina226_read_measure(sensor, &measure));
    // handle measure.*
}
```

> Note: `ina226_get_ready(sensor, &ready)` also checks readiness via `CVRF` (by reading `06h`), but this is a polling approach. For IRQ-based flow, `ALERT + ina226_get_alert_status()` is usually more convenient.

## Power-Down mode

In `Power-Down`, INA226 does not perform conversions, but registers are still accessible via I2C.

How this library uses it:
- After `ina226_init()`, the device is already in `Power-Down`.
- `ina226_stop_continuous(sensor)` puts the sensor back into `Power-Down`.
- Exit from `Power-Down` by starting measurements:
  - `ina226_start_single(sensor)`,
  - `ina226_start_continuous(sensor)`,
  - or `ina226_measure(sensor, &measure)` (internally starts a trigger cycle).

Power control example:

```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL)); // already in Power-Down

// ... when measurement is needed
ESP_ERROR_CHECK(ina226_start_continuous(sensor));

// ... when measurement is no longer needed
ESP_ERROR_CHECK(ina226_stop_continuous(sensor)); // back to Power-Down
```

In practice, this helps reduce power consumption during pauses between measurements. When designing timings, keep in mind that exit from `Power-Down` takes time (per INA226 datasheet — up to tens of milliseconds, typically up to ~40 ms is used as guidance).

## API

### Creation and lifecycle

- `esp_err_t ina226_create(ina226_handle_t *out_dev)` - Create a driver instance (memory allocation, no I2C operations)
- `esp_err_t ina226_init(ina226_handle_t dev, i2c_master_bus_handle_t bus, ina226_config_t *cfg)` - Initialize sensor on I2C bus, verify chip, reset, calibrate, and apply configuration (after init the device is in `Power-Down`)
- `esp_err_t ina226_destroy(ina226_handle_t dev)` - Remove device from I2C bus and release resources

### Measurements and operating modes

- `esp_err_t ina226_measure(ina226_handle_t dev, ina226_measure_t *measure)` - Perform a full single trigger cycle with ready wait and channel read
- `esp_err_t ina226_start_single(ina226_handle_t dev)` - Start a single trigger measurement without waiting for completion
- `esp_err_t ina226_start_continuous(ina226_handle_t dev)` - Start continuous autonomous measurements
- `esp_err_t ina226_get_ready(ina226_handle_t dev, bool *ready)` - Check new-measurement ready flag (`CVRF`) for polling in continuous mode
- `esp_err_t ina226_stop_continuous(ina226_handle_t dev)` - Stop continuous measurements and switch to `Power-Down`

### Reading measured values

- `esp_err_t ina226_read_measure(ina226_handle_t dev, ina226_measure_t *measure)` - Read all active channels without changing current operating mode
- `esp_err_t ina226_read_bus_voltage(ina226_handle_t dev, float *voltage_v)` - Read bus voltage (V)
- `esp_err_t ina226_read_shunt_voltage(ina226_handle_t dev, float *voltage_mv)` - Read shunt voltage (mV)
- `esp_err_t ina226_read_current(ina226_handle_t dev, float *current_a)` - Read current (A)
- `esp_err_t ina226_read_power(ina226_handle_t dev, float *power_w)` - Read power (W)
- `esp_err_t ina226_set_measurements(ina226_handle_t dev, uint8_t measurements)` - Configure active measurement mask (`ina226_measurements_t`) for `ina226_read_measure()` and `ina226_measure()`

### ALERT and threshold events

- `esp_err_t ina226_set_alert(ina226_handle_t dev, ina226_alert_source_t source, ina226_alert_mode_t mode, ina226_alert_condition_t condition, float threshold)` - Configure ALERT source, mode (transparent/latched), condition (above/below threshold), and threshold
- `esp_err_t ina226_disable_alert(ina226_handle_t dev)` - Disable all ALERT event sources (keeping `APOL` polarity)
- `esp_err_t ina226_set_conversion_ready_alert(ina226_handle_t dev, bool enable)` - Enable/disable “conversion ready” signaling (`CNVR`) on ALERT pin
- `esp_err_t ina226_get_alert_flags(ina226_handle_t dev, uint16_t *flags)` - Read raw flags from Mask/Enable register (`0x06`)
- `esp_err_t ina226_get_alert_status(ina226_handle_t dev, ina226_alert_status_t *status)` - Read and decode reason of last ALERT event
- `const char *ina226_alert_status_to_str(ina226_alert_status_t status)` - Convert ALERT status to human-readable string

### Default configuration

- `#define INA226_DEFAULT_CONFIG()` - Macro that builds `ina226_config_t` with default values (`Rshunt=0.1 Ω`, `Imax=1.0 A`, `AVG=1`, `CT=1.1 ms`, address `INA226_I2C_DEFAULT_ADDR`, measurements `INA226_MEAS_ALL`)

> Note: `ina226_get_alert_flags()` and `ina226_get_alert_status()` read register `0x06` (Mask/Enable), which acknowledges/clears part of INA226 status flags (`CVRF`, and ALERT latch when `LEN=1`).

## License

[MIT](./LICENSE)

Links

Supports all targets

To add this component to your project, run:

idf.py add-dependency "pkolt/ina226^1.0.0"

download archive

Stats

  • Archive size
    Archive size ~ 45.57 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

pkolt/ina226 version: 1.0.0
|