INA monitors/Two builds and a check/09. Read one rail on an ESP32
Two builds and a check · 09 of 11

Read one rail on an ESP32

Six wires and a sketch that prints all four numbers, so you can see which two were measured. The one thing to get right is that SCL is the third pin on this board and SDA the fourth.

Six wires, in this order

Six wires, and the order matters
nothing connected
Six wires. Press the button and connect them in the order that keeps the rail dead while you work.

Ground, supply, clock, data, then the rail. The order is not superstition: the last two connections are made with a screwdriver inside a terminal block, and the rail should not be live while that is happening.

Note the third and fourth wires. This board prints SCL before SDA, which is the opposite of the INA3221 in the same box. Getting it wrong does no damage and produces a board that cannot be found on the bus.

What the sketch prints

Five columns: the shunt voltage, the bus voltage, the current, the power, and the supply voltage worked back out.

The first two are the chip's measurements. The next two are its arithmetic. The fifth is ours — the bus voltage plus the shunt drop, which is what the supply is producing rather than what the load is receiving.

Watching all five is the quickest way to learn what these boards do. Put a load on and the shunt voltage rises, the bus voltage falls by exactly the same amount, and the supply column stays put.

The zero reading is worth writing down

Before you connect a load, run the sketch with nothing in the LOAD terminal and read the current column. It will not be zero: the chip's fixed offset is worth about a milliamp either way, and that is within specification.

Put that number into ZERO_MA and subtract it. It is stable, so subtracting works — unlike the gain error, which needs a known load and a scale factor.

Picking a range in one line

The library offers three calibrations and they are the gain setting in disguise. setCalibration_32V_2A() uses the widest ±320 mV range, so it reaches 3.2 A; setCalibration_16V_400mA() uses the narrowest, which halves the zero-point error and saturates at 400 mA.

Read that last name carefully, because it changes two things rather than one: it also drops the bus range from 32 V to 16 V, so on a 24 V rail the voltage reading saturates as well as the current. There is no library call for the narrow current range with the wide bus range — that combination is a write to the config register.

Use the narrow one when you know the current is small. As the range chapter says, it does not make one count smaller — it makes the count you get more trustworthy.

The code

tk119_one_rail.ino

It prints the shunt voltage, the bus voltage, the current and the power, in that order, once every half second. The first two are measurements and the second two are arithmetic, so if the voltages agree with a meter and the current does not, the fault is the calibration line rather than the wiring.

// TK119 INA219 wiring for this sketch.
//
//   ESP32 GND  -> GND       (first pin on the board)
//   ESP32 3V3  -> 3V3       (second pin; 3 to 5.5 V, and it sets the bus level)
//   ESP32 SCL  -> SCL       (THIRD pin - the clock comes before the data here)
//   ESP32 SDA  -> SDA       (fourth pin)
//
//   supply + -> POWER +     supply - -> POWER -
//   load   + -> LOAD  +     load   - -> LOAD  -
//
// Connect the rail last, so nothing is live while a screwdriver is in a
// terminal. The supply's negative and the ESP32's ground are the same net
// through this board, which is what makes the voltage reading possible.
//
// Arduino IDE: any ESP32 board. Sketch > Include Library > Manage
// Libraries, then install "Adafruit INA219". No other Tools settings.

#include <Wire.h>
#include <Adafruit_INA219.h>

// 0x40 with neither pad soldered. 0x41 with A0, 0x44 with A1, 0x45 with both.
Adafruit_INA219 ina219(0x40);

// Read with nothing in the LOAD terminal and put the number here, in
// milliamps. It is the chip's fixed zero-point error and it does not scale,
// so subtracting it is the one correction worth making by hand.
const float ZERO_MA = 0.0;

void setup() {
  Serial.begin(115200);
  delay(500);
  Wire.begin();

  if (!ina219.begin()) {
    Serial.println("no INA219 at 0x40 - SCL is the third pin on this board, SDA the fourth");
    while (1) delay(10);
  }

  // Three ranges to choose from in this library. The widest reaches 3.2 A;
  // the narrow one halves the zero-point error, so use it if you know the
  // current is small. Nothing here changes the size of one count: that is
  // always 0.1 mA on a 100 mohm shunt.
  ina219.setCalibration_32V_2A();      // +-320 mV, up to 3.2 A
  // ina219.setCalibration_32V_1A();   // +-320 mV, scaled for 1 A
  // ina219.setCalibration_16V_400mA(); // +-40 mV, the accurate one

  Serial.println("shunt mV\tbus V\tmA\tmW\tsupply V");
}

void loop() {
  // Measured.
  float shunt_mv = ina219.getShuntVoltage_mV();
  float bus_v    = ina219.getBusVoltage_V();
  // Worked out, from a shunt resistance the calibration call set.
  float ma       = ina219.getCurrent_mA() - ZERO_MA;
  float mw       = ina219.getPower_mW();

  // The bus voltage is the load's, not the supply's: it is measured on the
  // far side of the shunt. Add the shunt drop back on for the supply's.
  float supply_v = bus_v + shunt_mv / 1000.0;

  Serial.printf("%.2f\t%.3f\t%.1f\t%.1f\t%.3f\n", shunt_mv, bus_v, ma, mw, supply_v);
  delay(500);
}

If it stops at “no INA219 at 0x40”, check SCL and SDA before anything else: on this board the clock is the third pin and the data the fourth, which is the other way round from the INA3221 and from the other I²C blocks. After that, check that the red power LED is lit.

When it does not work

It prints “no INA219 at 0x40”

SCL and SDA, nine times out of ten. This board prints GND, 3V3, SCL, SDA, so the clock is the third pin — the opposite order to the INA3221 and to the other I²C blocks. Then check that the red power LED is on, which tells you GND and 3V3 are right, and that you have not soldered an address pad without changing the address in the sketch.

Everything reads zero but the board is found

The bus is fine and the rail is not. Either the supply is not connected to POWER, or a screw has closed on insulation rather than copper, or the load has a second path back to the supply that misses the board. Unscrew LOAD + with the supply on: the current should already have been zero, which tells you which side the problem is.

The current is negative

The supply and the load are in the wrong terminals. Current is meant to flow POWER → LOAD, which is the direction the two arrows printed between them point. Swap both pairs of wires. Nothing is damaged the wrong way round, but the bus voltage you were reading was the supply's rather than the load's.

The numbers jump about on a supply that is not changing

Each reading is one 532 microsecond conversion, and a switching supply or a PWM load is not the same thing during any two of them. Set the config register to average — the INA219 will average up to 128 samples — or average in your sketch. A slower reading is the price, which is fine unless you were looking for the spike.

It works on 3.3 V but not from the Arduino's 5 V

Check what the bus level became. The board's 10 kΩ pull-ups pull SDA and SCL to whatever is on its supply pin, so a board fed 5 V puts 5 V on those lines. That is right for an Uno and wrong for an ESP32. Feed the board from the same rail your microcontroller's logic uses and the question disappears.

Where this goes next

Three rails and an alert

Edit this page — content/books/inaset/read-one-rail-on-an-esp32.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

This page covers several products. Choose yours to see the right discussions.

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum