DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ina219.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ina219.cpp
6 * @brief TI INA219 current / power monitor codec - implementation. See ina219.h.
7 */
8
10#include "ServerConfig.h"
11
12#if DETWS_ENABLE_INA219
13
14int32_t ina219_bus_mv(uint16_t raw)
15{
16 return (int32_t)((raw >> 3) * 4); // value in bits [15:3], LSB 4 mV
17}
18
19int32_t ina219_shunt_uv(int16_t raw)
20{
21 return (int32_t)raw * 10; // LSB 10 uV, signed
22}
23
24uint16_t ina219_calibration(uint32_t current_lsb_ua, uint32_t shunt_mohm)
25{
26 uint32_t denom = current_lsb_ua * shunt_mohm;
27 if (denom == 0)
28 return 0;
29 // 0.04096 / (lsb[A] * R[ohm]) = 40960000 / (lsb_ua * shunt_mohm).
30 uint32_t cal = 40960000u / denom;
31 return (uint16_t)(cal > 0xFFFF ? 0xFFFF : cal);
32}
33
34int32_t ina219_current_ua(int16_t raw, uint32_t current_lsb_ua)
35{
36 return (int32_t)((int64_t)raw * current_lsb_ua);
37}
38
39int32_t ina219_power_uw(int16_t raw, uint32_t current_lsb_ua)
40{
41 return (int32_t)((int64_t)raw * 20 * current_lsb_ua); // power LSB = 20 * current LSB
42}
43
44// ---------------------------------------------------------------------------
45// I2C binding
46// ---------------------------------------------------------------------------
47
48#if defined(ARDUINO)
49
50#include "services/i2c.h"
51#include <Arduino.h>
52#include <Wire.h>
53
54namespace
55{
56// All INA219 I2C-binding state, owned by one instance (internal linkage): the device address
57// and the current LSB, grouped so it is one named owner, unreachable from any other TU.
58struct Ina219Ctx
59{
60 uint8_t addr = DETWS_INA219_I2C_ADDR;
61 uint32_t lsb_ua = DETWS_INA219_CURRENT_LSB_UA;
62};
63Ina219Ctx s_ina;
64
65bool wr16(uint8_t reg, uint16_t v)
66{
67 Wire.beginTransmission(s_ina.addr);
68 Wire.write(reg);
69 Wire.write((uint8_t)(v >> 8)); // INA219 registers are big-endian
70 Wire.write((uint8_t)(v & 0xFF));
71 return Wire.endTransmission() == 0;
72}
73
74bool rd16(uint8_t reg, uint16_t *v)
75{
76 Wire.beginTransmission(s_ina.addr);
77 Wire.write(reg);
78 if (Wire.endTransmission(false) != 0)
79 return false;
80 if (Wire.requestFrom((int)s_ina.addr, 2) != 2)
81 return false;
82 uint8_t hi = (uint8_t)Wire.read();
83 uint8_t lo = (uint8_t)Wire.read();
84 *v = (uint16_t)(((uint16_t)hi << 8) | lo);
85 return true;
86}
87} // namespace
88
89bool ina219_begin(uint8_t addr, uint32_t current_lsb_ua, uint32_t shunt_mohm)
90{
91 s_ina.addr = addr ? addr : (uint8_t)DETWS_INA219_I2C_ADDR;
92 s_ina.lsb_ua = current_lsb_ua ? current_lsb_ua : (uint32_t)DETWS_INA219_CURRENT_LSB_UA;
94 bool ok = true;
95 ok &= wr16(INA219_REG_CALIBRATION,
96 ina219_calibration(s_ina.lsb_ua, shunt_mohm ? shunt_mohm : (uint32_t)DETWS_INA219_SHUNT_MOHM));
97 ok &= wr16(INA219_REG_CONFIG, 0x399F); // 32 V range, /8 gain (320 mV), 12-bit, continuous
98 return ok;
99}
100
101bool ina219_read_bus_mv(int32_t *millivolts)
102{
103 uint16_t v = 0;
104 if (!rd16(INA219_REG_BUS, &v))
105 return false;
106 if (millivolts)
107 *millivolts = ina219_bus_mv(v);
108 return true;
109}
110
111bool ina219_read_shunt_uv(int32_t *microvolts)
112{
113 uint16_t v = 0;
114 if (!rd16(INA219_REG_SHUNT, &v))
115 return false;
116 if (microvolts)
117 *microvolts = ina219_shunt_uv((int16_t)v);
118 return true;
119}
120
121bool ina219_read_current_ua(int32_t *microamps)
122{
123 uint16_t v = 0;
124 if (!rd16(INA219_REG_CURRENT, &v))
125 return false;
126 if (microamps)
127 *microamps = ina219_current_ua((int16_t)v, s_ina.lsb_ua);
128 return true;
129}
130
131bool ina219_read_power_uw(int32_t *microwatts)
132{
133 uint16_t v = 0;
134 if (!rd16(INA219_REG_POWER, &v))
135 return false;
136 if (microwatts)
137 *microwatts = ina219_power_uw((int16_t)v, s_ina.lsb_ua);
138 return true;
139}
140
141#else // host build: no I2C. The decode / calibration / scaling above are host-tested.
142
143bool ina219_begin(uint8_t, uint32_t, uint32_t)
144{
145 return false;
146}
147bool ina219_read_bus_mv(int32_t *)
148{
149 return false;
150}
151bool ina219_read_shunt_uv(int32_t *)
152{
153 return false;
154}
155bool ina219_read_current_ua(int32_t *)
156{
157 return false;
158}
159bool ina219_read_power_uw(int32_t *)
160{
161 return false;
162}
163
164#endif // ARDUINO
165
166#endif // DETWS_ENABLE_INA219
User-facing configuration for DeterministicESPAsyncWebServer.
#define DETWS_INA219_CURRENT_LSB_UA
Default INA219 current LSB in microamps per bit (calibration input). The fallback when ina219_begin()...
#define DETWS_INA219_I2C_ADDR
I2C address of the INA219 (0x40 default; the A0/A1 pins select 0x40..0x4F).
#define DETWS_INA219_SHUNT_MOHM
Default INA219 shunt resistance in milliohms (calibration input). The fallback when ina219_begin() is...
The one owner of the shared I2C bus bring-up for the peripheral drivers.
void detws_i2c_begin()
Bring up the shared I2C bus on DETWS_I2C_SDA_PIN / DETWS_I2C_SCL_PIN (-1 = default).
Definition i2c.h:33
TI INA219 high-side current / power monitor codec (DETWS_ENABLE_INA219).
uint16_t ina219_calibration(uint32_t current_lsb_ua, uint32_t shunt_mohm)
Compute the calibration register from the current LSB (microamps per bit) and the shunt resistance (m...
bool ina219_read_bus_mv(int32_t *millivolts)
Read the bus voltage into millivolts.
#define INA219_REG_SHUNT
shunt voltage
Definition ina219.h:31
int32_t ina219_power_uw(int16_t raw, uint32_t current_lsb_ua)
Scale the raw power register to microwatts (power LSB is 20 * current LSB).
bool ina219_read_shunt_uv(int32_t *microvolts)
Read the shunt voltage into microvolts.
int32_t ina219_bus_mv(uint16_t raw)
Decode the bus-voltage register to millivolts (value is bits [15:3], LSB 4 mV).
int32_t ina219_shunt_uv(int16_t raw)
Decode the shunt-voltage register to microvolts (signed, LSB 10 uV).
bool ina219_begin(uint8_t addr, uint32_t current_lsb_ua, uint32_t shunt_mohm)
Program the INA219 at addr: write the calibration for current_lsb_ua (uA/bit) and shunt_mohm (millioh...
#define INA219_REG_CALIBRATION
calibration
Definition ina219.h:35
#define INA219_REG_CONFIG
configuration
Definition ina219.h:30
bool ina219_read_current_ua(int32_t *microamps)
Read the current into microamps (needs the calibration set by ina219_begin).
#define INA219_REG_BUS
bus voltage
Definition ina219.h:32
bool ina219_read_power_uw(int32_t *microwatts)
Read the power into microwatts (needs the calibration set by ina219_begin).
#define INA219_REG_POWER
power
Definition ina219.h:33
int32_t ina219_current_ua(int16_t raw, uint32_t current_lsb_ua)
Scale the raw current register to microamps (raw * current_lsb_ua).
#define INA219_REG_CURRENT
current
Definition ina219.h:34