# INA226 for ESP-IDF (ESP32)
- [INA226 for ESP-IDF (ESP32)](#ina226-for-esp-idf-esp32)
- [Введение](#введение)
- [Кратко о возможностях](#кратко-о-возможностях)
- [Карта регистров](#карта-регистров)
- [Режимы работы (поле `MODE`, биты `2:0` регистра `00h`)](#режимы-работы-поле-mode-биты-20-регистра-00h)
- [Пин `ALERT`](#пин-alert)
- [Настройка датчика](#настройка-датчика)
- [Параметры `ina226_config_t`](#параметры-ina226_config_t)
- [Допустимые значения](#допустимые-значения)
- [Можно ли не задавать конфиг вручную?](#можно-ли-не-задавать-конфиг-вручную)
- [Режим одиночного измерения](#режим-одиночного-измерения)
- [Режим постоянного измерения](#режим-постоянного-измерения)
- [Прерывание на пине ALERT при достижении порогового значения](#прерывание-на-пине-alert-при-достижении-порогового-значения)
- [Прерывания на пине ALERT при готовности данных](#прерывания-на-пине-alert-при-готовности-данных)
- [Режим работы Power-Down](#режим-работы-power-down)
- [API](#api)
- [Создание и жизненный цикл](#создание-и-жизненный-цикл)
- [Измерения и режимы работы](#измерения-и-режимы-работы)
- [Чтение измеренных величин](#чтение-измеренных-величин)
- [ALERT и пороговые события](#alert-и-пороговые-события)
- [Конфигурация по умолчанию](#конфигурация-по-умолчанию)
- [Лицензия](#лицензия)
## Введение
`INA226` — цифровой монитор питания с интерфейсом I2C, который измеряет напряжение шины (`VBUS`) и падение напряжения на шунте (`VSHUNT`), а также вычисляет ток и мощность (после калибровки).
### Кратко о возможностях
- Измерение:
- напряжения шины (`Bus Voltage`, регистр `02h`),
- напряжения на шунте (`Shunt Voltage`, регистр `01h`),
- тока (`Current`, регистр `04h`, после записи калибровки),
- мощности (`Power`, регистр `03h`, после записи калибровки).
- Гибкая настройка АЦП через регистр конфигурации `00h`:
- усреднение (`AVG`),
- время преобразования для `VBUS` и `VSHUNT` (`VBUSCT`, `VSHCT`),
- режим работы (`MODE`).
- Поддержка программного сброса (`RST`, бит 15 регистра `00h`).
- Калибровка под конкретный шунт через регистр `05h` (`Calibration`).
- Работа с аппаратным выходом `ALERT`:
- пороговые события (over/under limit),
- сигнал готовности данных (`Conversion Ready`).
- Проверка связи с микросхемой через `Die ID` (`FFh`, значение по умолчанию `2260h`).
### Карта регистров
| Адрес | Доступ | Регистр | По умолчанию | Назначение |
| :---: | :---: | :--- | :---: | :--- |
| `00h` | R/W | Configuration | `4127h` | Настройка АЦП, усреднения, времени преобразования, режима, сброс |
| `01h` | R | Shunt Voltage | `0000h` | Измеренное падение напряжения на шунте |
| `02h` | R | Bus Voltage | `0000h` | Измеренное напряжение шины |
| `03h` | R | Power | `0000h` | Рассчитанная мощность (после калибровки) |
| `04h` | R | Current | `0000h` | Рассчитанный ток (после калибровки) |
| `05h` | R/W | Calibration | `0000h` | Калибровочный коэффициент |
| `06h` | R/W | Mask/Enable | `0000h` | Маски, флаги и полярность/защёлка `ALERT` |
| `07h` | R/W | Alert Limit | `0000h` | Порог для срабатывания `ALERT` |
| `FFh` | R | Die ID | `2260h` | Идентификатор кристалла |
### Режимы работы (поле `MODE`, биты `2:0` регистра `00h`)
| MODE | Режим |
| :--: | :--- |
| `000` | Power-Down (отключен) |
| `001` | Shunt Voltage, trigger (одиночное измерение шунта) |
| `010` | Bus Voltage, trigger (одиночное измерение шины) |
| `011` | Shunt + Bus, trigger (одиночное измерение шунта и шины) |
| `100` | Power-Down (отключен) |
| `101` | Shunt Voltage, continuous (непрерывно) |
| `110` | Bus Voltage, continuous (непрерывно) |
| `111` | Shunt + Bus, continuous (непрерывно, режим по умолчанию) |
### Пин `ALERT`
Вывод `ALERT` настраивается регистрами `Mask/Enable` (`06h`) и `Alert Limit` (`07h`).
- Пороговые события:
- `SOL`/`SUL` — выход за пределы по напряжению шунта,
- `BOL`/`BUL` — выход за пределы по напряжению шины,
- `POL` — превышение порога мощности.
- Событие готовности данных:
- `CNVR` (маска источника),
- `CVRF` (флаг готовности преобразования).
- Служебные биты:
- `AFF` — флаг аварийного события,
- `OVF` — математическое переполнение,
- `APOL` — полярность `ALERT` (`0` — active-low, `1` — active-high),
- `LEN` — режим вывода (`0` — прозрачный, `1` — с защёлкой).
## Настройка датчика
После `ina226_create()` устройство настраивается через `ina226_init(sensor, bus, cfg)`.
- Если `cfg != NULL` — используются ваши значения из `ina226_config_t`.
- Если `cfg == NULL` — библиотека подставляет `INA226_DEFAULT_CONFIG()`.
Важно: после `ina226_init()` драйвер оставляет INA226 в режиме `Power-Down`; запуск измерений делается отдельно (`ina226_measure()`, `ina226_start_single()` или `ina226_start_continuous()`).
### Параметры `ina226_config_t`
```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;
```
| Поле | Что задаёт | Значение по умолчанию |
| :--- | :--- | :--- |
| `r_shunt_ohms` | Номинал шунта, Ом. Используется при калибровке и пересчёте тока/мощности. | `0.1f` |
| `max_expected_amps` | Ожидаемый максимальный ток, А. Влияет на `Current_LSB` и коэффициент калибровки. | `1.0f` |
| `avg` | Усреднение АЦП (`AVG`, регистр `00h`). | `INA226_AVG_1` |
| `bus_ct` | Время преобразования канала `VBUS` (`VBUSCT`, регистр `00h`). | `INA226_CONV_TIME_1_1MS` |
| `shunt_ct` | Время преобразования канала `VSHUNT` (`VSHCT`, регистр `00h`). | `INA226_CONV_TIME_1_1MS` |
| `address` | 7-битный I2C-адрес INA226. | `INA226_I2C_DEFAULT_ADDR` (`0x40`) |
| `measurements` | Битовая маска измеряемых/читаемых величин (`ina226_measurements_t`). | `INA226_MEAS_ALL` |
### Допустимые значения
- `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`: от `0x40` до `0x4F` включительно.
- `measurements`: комбинация флагов:
- `INA226_MEAS_BUS_VOLTAGE`
- `INA226_MEAS_SHUNT_VOLTAGE`
- `INA226_MEAS_CURRENT`
- `INA226_MEAS_POWER`
- или сразу `INA226_MEAS_ALL`
> Нельзя передавать пустую маску (`0`). Должен быть выбран хотя бы один канал.
### Можно ли не задавать конфиг вручную?
Да. Можно полностью пропустить настройку и передать `NULL`:
```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL));
```
Это рабочий и рекомендуемый вариант для быстрого старта (он же используется в примерах в `examples/*`).
Если нужна точная подстройка под вашу схему (другой шунт, другой адрес, иные времена/усреднение), создайте конфиг от дефолта и поменяйте только нужные поля:
```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));
```
## Режим одиночного измерения
Одиночный режим (triggered) удобен, когда измерения нужны по запросу: например, раз в секунду, по событию или по команде от другого модуля.
В этой библиотеке есть два способа работы:
1. `ina226_measure(sensor, &measure)` — самый простой путь:
- запускает одно преобразование в trigger-режиме,
- ждёт рассчитанное время преобразования (с учётом `AVG`, `VBUSCT`, `VSHCT`),
- проверяет готовность,
- читает выбранные каналы в `ina226_measure_t`.
2. `ina226_start_single(sensor)` + `ina226_read_measure(sensor, &measure)` — ручной путь:
- запуск преобразования делается отдельно,
- ожидание/синхронизацию вы контролируете сами (например, через `ALERT`/`CNVR`),
- чтение выполняется отдельным вызовом.
Режим `MODE` выбирается автоматически из `cfg.measurements`:
- только `INA226_MEAS_BUS_VOLTAGE` → `Bus trigger` (`010`),
- только шунт/ток (без мощности) → `Shunt trigger` (`001`),
- `INA226_MEAS_POWER` (в том числе без остальных флагов), смешанный набор или `INA226_MEAS_ALL` → `Shunt + Bus trigger` (`011`).
Пример (как в `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) {
// Используйте measure.bus_voltage_v, measure.shunt_voltage_mv,
// measure.current_a, measure.power_w
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
```
> В triggered-режиме после каждого завершённого цикла для следующего измерения нужен новый запуск (через `ina226_measure()` или `ina226_start_single()`).
## Режим постоянного измерения
Постоянный режим (continuous) подходит для непрерывного мониторинга: INA226 сам циклически выполняет преобразования, а МК только читает свежие данные.
Базовый сценарий:
1. `ina226_start_continuous(sensor)` — переводит датчик в continuous-режим.
2. Периодически проверяйте готовность данных через `ina226_get_ready(sensor, &ready)`.
3. Когда `ready == true`, читайте значения через `ina226_read_measure(sensor, &measure)`.
4. При необходимости остановите измерения: `ina226_stop_continuous(sensor)` (переход в `Power-Down`).
Режим `MODE` также выбирается автоматически по маске `measurements`:
- только `INA226_MEAS_BUS_VOLTAGE` → `Bus continuous` (`110`),
- только шунт/ток (без мощности) → `Shunt continuous` (`101`),
- `INA226_MEAS_POWER` (в том числе без остальных флагов), смешанный набор или `INA226_MEAS_ALL` → `Shunt + Bus continuous` (`111`).
Пример (как в `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));
// Используйте measure.*
}
```
> `ina226_read_measure()` не меняет режим INA226: она только читает регистры выбранных каналов.
## Прерывание на пине ALERT при достижении порогового значения
Этот режим нужен, когда важен аппаратный сигнал при выходе измеряемой величины за порог (например, `VBUS` ниже допустимого уровня).
Базовый сценарий:
1. Инициализируйте датчик: `ina226_init(sensor, bus, cfg_or_null)`.
2. Настройте источник/условие/порог: `ina226_set_alert(...)`.
3. Запустите непрерывные измерения: `ina226_start_continuous(sensor)`.
4. В обработчике прерывания/таске прочитайте статус через `ina226_get_alert_status(sensor, &status)`.
Пример (как в `examples/threshold_alert`, срабатывание при `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));
// ... после IRQ на ALERT
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));
// обработка аварии
}
```
Важно:
- `INA226_ALERT_MODE_TRANSPARENT` (`LEN=0`) — `ALERT` отпускается автоматически, когда условие ушло.
- `INA226_ALERT_MODE_LATCHED` (`LEN=1`) — `ALERT` защёлкивается до чтения регистра `06h`.
- В этой библиотеке чтение `ina226_get_alert_status()`/`ina226_get_alert_flags()` одновременно является подтверждением события (ACK): снимает защёлку `ALERT` (при `LEN=1`) и очищает соответствующие статус-флаги.
## Прерывания на пине ALERT при готовности данных
Этот режим полезен для синхронизации чтения «свежих» данных без постоянного polling.
Для включения используйте:
- `ina226_set_conversion_ready_alert(sensor, true)` — включает `CNVR`, переводит `ALERT` в прозрачный режим и отключает пороговые источники, чтобы `ALERT` использовался только под событие готовности преобразования.
Типовой поток (как в `examples/conversion_ready`):
1. `ina226_set_conversion_ready_alert(sensor, true)`.
2. Запустите измерение (`ina226_start_single(sensor)` для single-shot или continuous-режим).
3. Ждите IRQ от `ALERT`.
4. В таске прочитайте `ina226_get_alert_status(sensor, &status)` и убедитесь, что `status == INA226_ALERT_STATUS_CONVERSION_READY`.
5. Считайте данные через `ina226_read_measure(sensor, &measure)`.
Пример single-shot:
```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));
// обработка measure.*
}
```
> Замечание: `ina226_get_ready(sensor, &ready)` тоже проверяет готовность по `CVRF` (через чтение `06h`), но это polling-подход. Для IRQ-сценария обычно удобнее `ALERT + ina226_get_alert_status()`.
## Режим работы Power-Down
В `Power-Down` INA226 не выполняет преобразования, но регистры остаются доступны по I2C.
Как используется в библиотеке:
- После `ina226_init()` устройство уже находится в `Power-Down`.
- `ina226_stop_continuous(sensor)` переводит датчик обратно в `Power-Down`.
- Выход из `Power-Down` — запуском измерений:
- `ina226_start_single(sensor)`,
- `ina226_start_continuous(sensor)`,
- или `ina226_measure(sensor, &measure)` (внутри запускает trigger-цикл).
Пример управления питанием:
```c
ESP_ERROR_CHECK(ina226_init(sensor, bus, NULL)); // уже Power-Down
// ... когда нужно измерять
ESP_ERROR_CHECK(ina226_start_continuous(sensor));
// ... когда измерения больше не нужны
ESP_ERROR_CHECK(ina226_stop_continuous(sensor)); // снова Power-Down
```
Практически это удобно для снижения потребления в паузах между измерениями. При проектировании таймингов учитывайте, что выход из `Power-Down` требует времени (по даташиту INA226 — до десятков миллисекунд, обычно ориентируются на значение до ~40 мс).
## API
### Создание и жизненный цикл
- `esp_err_t ina226_create(ina226_handle_t *out_dev)` - Создание экземпляра драйвера (выделение памяти, без I2C-операций)
- `esp_err_t ina226_init(ina226_handle_t dev, i2c_master_bus_handle_t bus, ina226_config_t *cfg)` - Инициализация датчика на шине I2C, проверка чипа, сброс, калибровка и применение конфигурации (после инициализации устройство в `Power-Down`)
- `esp_err_t ina226_destroy(ina226_handle_t dev)` - Удаление устройства с I2C-шины и освобождение ресурсов
### Измерения и режимы работы
- `esp_err_t ina226_measure(ina226_handle_t dev, ina226_measure_t *measure)` - Выполнение полного одиночного trigger-цикла с ожиданием готовности и чтением каналов
- `esp_err_t ina226_start_single(ina226_handle_t dev)` - Запуск одиночного trigger-измерения без ожидания завершения
- `esp_err_t ina226_start_continuous(ina226_handle_t dev)` - Запуск непрерывных автономных измерений
- `esp_err_t ina226_get_ready(ina226_handle_t dev, bool *ready)` - Проверка флага готовности нового измерения (`CVRF`) для polling в continuous-режиме
- `esp_err_t ina226_stop_continuous(ina226_handle_t dev)` - Остановка непрерывных измерений и перевод в `Power-Down`
### Чтение измеренных величин
- `esp_err_t ina226_read_measure(ina226_handle_t dev, ina226_measure_t *measure)` - Чтение всех активных каналов без изменения текущего режима работы
- `esp_err_t ina226_read_bus_voltage(ina226_handle_t dev, float *voltage_v)` - Чтение напряжения шины (В)
- `esp_err_t ina226_read_shunt_voltage(ina226_handle_t dev, float *voltage_mv)` - Чтение напряжения на шунте (мВ)
- `esp_err_t ina226_read_current(ina226_handle_t dev, float *current_a)` - Чтение тока (А)
- `esp_err_t ina226_read_power(ina226_handle_t dev, float *power_w)` - Чтение мощности (Вт)
- `esp_err_t ina226_set_measurements(ina226_handle_t dev, uint8_t measurements)` - Настройка маски активных измерений (`ina226_measurements_t`) для `ina226_read_measure()` и `ina226_measure()`
### ALERT и пороговые события
- `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)` - Настройка источника ALERT, режима (transparent/latched), условия (выше/ниже порога) и порога
- `esp_err_t ina226_disable_alert(ina226_handle_t dev)` - Отключение всех источников событий ALERT (с сохранением полярности `APOL`)
- `esp_err_t ina226_set_conversion_ready_alert(ina226_handle_t dev, bool enable)` - Включение/выключение сигнализации «данные готовы» (`CNVR`) на пине ALERT
- `esp_err_t ina226_get_alert_flags(ina226_handle_t dev, uint16_t *flags)` - Чтение сырых флагов регистра Mask/Enable (`0x06`)
- `esp_err_t ina226_get_alert_status(ina226_handle_t dev, ina226_alert_status_t *status)` - Чтение и декодирование причины последнего ALERT-события
- `const char *ina226_alert_status_to_str(ina226_alert_status_t status)` - Преобразование статуса ALERT в человекочитаемую строку
### Конфигурация по умолчанию
- `#define INA226_DEFAULT_CONFIG()` - Макрос для построения `ina226_config_t` со значениями по умолчанию (`Rshunt=0.1 Ом`, `Imax=1.0 А`, `AVG=1`, `CT=1.1 мс`, адрес `INA226_I2C_DEFAULT_ADDR`, измерения `INA226_MEAS_ALL`)
> Примечание: функции `ina226_get_alert_flags()` и `ina226_get_alert_status()` читают регистр `0x06` (Mask/Enable), а это подтверждает/сбрасывает часть статусных флагов INA226 (`CVRF`, а также latch ALERT при `LEN=1`).
## Лицензия
[MIT](./LICENSE)
idf.py add-dependency "pkolt/ina226^1.0.0"