ina219-async
Version:
Node.js INA219 driver for Adafruit INA219 High Side DC Current Sensor using promises
316 lines (267 loc) • 14 kB
JavaScript
"use strict";
/*
This is an async modification of https://github.com/brettmarl/node-ina219/ which in turn is a
* Node driver for INA219 ported from https://github.com/adafruit/Adafruit_INA219
*/
var i2c = require('i2c-bus'); // https://github.com/fivdi/i2c-bus
// ===========================================================================
// I2C ADDRESS/BITS
// ==========================================================================
var INA219_ADDRESS = 0x40 ; // 1000000 (A0+A1=GND)
var INA219_ADDRESS_A0 = 0x41 ;
var INA219_ADDRESS_A1 = 0x44 ;
var INA219_ADDRESS_A0_A1 = 0x45 ;
var INA219_READ = 0x01;
// ===========================================================================
// CONFIG REGISTER (R/W)
// ===========================================================================
var INA219_REG_CONFIG = 0x00;
// ===========================================================================
var INA219_CONFIG_RESET = 0x8000 ; // Reset Bit
var INA219_CONFIG_BVOLTAGERANGE_MASK = 0x2000 ; // Bus Voltage Range Mask
var INA219_CONFIG_BVOLTAGERANGE_16V = 0x0000 ; // 0-16V Range
var INA219_CONFIG_BVOLTAGERANGE_32V = 0x2000 ; // 0-32V Range
var INA219_CONFIG_GAIN_MASK = 0x1800 ; // Gain Mask
var INA219_CONFIG_GAIN_1_40MV = 0x0000 ; // Gain 1, 40mV Range
var INA219_CONFIG_GAIN_2_80MV = 0x0800 ; // Gain 2, 80mV Range
var INA219_CONFIG_GAIN_4_160MV = 0x1000 ; // Gain 4, 160mV Range
var INA219_CONFIG_GAIN_8_320MV = 0x1800 ; // Gain 8, 320mV Range
var INA219_CONFIG_BADCRES_MASK = 0x0780 ; // Bus ADC Resolution Mask
var INA219_CONFIG_BADCRES_9BIT = 0x0080 ; // 9-bit bus res = 0..511
var INA219_CONFIG_BADCRES_10BIT = 0x0100 ; // 10-bit bus res = 0..1023
var INA219_CONFIG_BADCRES_11BIT = 0x0200 ; // 11-bit bus res = 0..2047
var INA219_CONFIG_BADCRES_12BIT = 0x0400 ; // 12-bit bus res = 0..4097
var INA219_CONFIG_SADCRES_MASK = 0x0078 ; // Shunt ADC Resolution and Averaging Mask
var INA219_CONFIG_SADCRES_9BIT_1S_84US = 0x0000 ; // 1 x 9-bit shunt sample
var INA219_CONFIG_SADCRES_10BIT_1S_148US = 0x0008 ; // 1 x 10-bit shunt sample
var INA219_CONFIG_SADCRES_11BIT_1S_276US = 0x0010 ; // 1 x 11-bit shunt sample
var INA219_CONFIG_SADCRES_12BIT_1S_532US = 0x0018 ; // 1 x 12-bit shunt sample
var INA219_CONFIG_SADCRES_12BIT_2S_1060US = 0x0048 ; // 2 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_4S_2130US = 0x0050 ; // 4 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_8S_4260US = 0x0058 ; // 8 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_16S_8510US = 0x0060 ; // 16 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_32S_17MS = 0x0068 ; // 32 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_64S_34MS = 0x0070 ; // 64 x 12-bit shunt samples averaged together
var INA219_CONFIG_SADCRES_12BIT_128S_69MS = 0x0078 ; // 128 x 12-bit shunt samples averaged together
var INA219_CONFIG_MODE_MASK = 0x0007 ; // Operating Mode Mask
var INA219_CONFIG_MODE_POWERDOWN = 0x0000;
var INA219_CONFIG_MODE_SVOLT_TRIGGERED = 0x0001;
var INA219_CONFIG_MODE_BVOLT_TRIGGERED = 0x0002;
var INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED = 0x0003;
var INA219_CONFIG_MODE_ADCOFF = 0x0004;
var INA219_CONFIG_MODE_SVOLT_CONTINUOUS = 0x0005;
var INA219_CONFIG_MODE_BVOLT_CONTINUOUS = 0x0006;
var INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS = 0x0007;
// ===========================================================================
// SHUNT VOLTAGE REGISTER (R)
// ===========================================================================
var INA219_REG_SHUNTVOLTAGE = 0x01
// ===========================================================================
// ===========================================================================
// BUS VOLTAGE REGISTER (R)
// ===========================================================================
var INA219_REG_BUSVOLTAGE = 0x02
// ===========================================================================
// ===========================================================================
// POWER REGISTER (R)
// ===========================================================================
var INA219_REG_POWER = 0x03
// ===========================================================================
// ==========================================================================
// CURRENT REGISTER (R)
// ===========================================================================
var INA219_REG_CURRENT = 0x04
// ===========================================================================
// ===========================================================================
// CALIBRATION REGISTER (R/W)
// ===========================================================================
var INA219_REG_CALIBRATION = 0x05
// ===========================================================================
/**
* Called to initilize the INA219 board, you should calibrate it after this.
* @param {string} address - Address you want to use. Defaults to INA219_ADDRESS
* @param {integer} busNumber - the number of the I2C bus/adapter to open, 0 for /dev/i2c-0, 1 for /dev/i2c-1, (See github.com/fivdi/i2c-bus)
*/
module.exports = (address = INA219_ADDRESS, busNumber = 1) => {
let currentDivider_mA = 0;
let powerDivider_mW = 0;
let calValue = 0;
const wire = i2c.openSync(busNumber);
const writeRegister = async (register, value) => {
var bytes = Buffer.alloc(2);
bytes[0] = (value >> 8) & 0xFF;
bytes[1] = value & 0xFF;
wire.writeI2cBlockSync(address, register, 2, bytes);
};
const readRegister = async (register) => {
var res = Buffer.alloc(2);
wire.readI2cBlockSync(address, register, 2, res);
return res.readInt16BE();
};
return {
/**
* Configures to INA219 to be able to measure up to 32V and 1A of current.
* Each unit of current corresponds to 40uA, and each unit of power corresponds
* to 800mW. Counter overflow occurs at 1.3A.
* Note: These calculations assume a 0.1 ohm resistor is present
*/
calibrate32V1A: async () => {
// By default we use a pretty huge range for the input voltage,
// which probably isn't the most appropriate choice for system
// that don't use a lot of power. But all of the calculations
// are shown below if you want to change the settings. You will
// also need to change any relevant register settings, such as
// setting the VBUS_MAX to 16V instead of 32V, etc.
// VBUS_MAX = 32V (Assumes 32V, can also be set to 16V)
// VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
// RSHUNT = 0.1 (Resistor value in ohms)
// 1. Determine max possible current
// MaxPossible_I = VSHUNT_MAX / RSHUNT
// MaxPossible_I = 3.2A
// 2. Determine max expected current
// MaxExpected_I = 1.0A
// 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
// MinimumLSB = MaxExpected_I/32767
// MinimumLSB = 0.0000305 (30.5�A per bit)
// MaximumLSB = MaxExpected_I/4096
// MaximumLSB = 0.000244 (244�A per bit)
// 4. Choose an LSB between the min and max values
// (Preferrably a roundish number close to MinLSB)
// CurrentLSB = 0.0000400 (40�A per bit)
// 5. Compute the calibration register
// Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
// Cal = 10240 (0x2800)
calValue = 10240;
// 6. Calculate the power LSB
// PowerLSB = 20 * CurrentLSB
// PowerLSB = 0.0008 (800�W per bit)
// 7. Compute the maximum current and shunt voltage values before overflow
//
// Max_Current = Current_LSB * 32767
// Max_Current = 1.31068A before overflow
//
// If Max_Current > Max_Possible_I then
// Max_Current_Before_Overflow = MaxPossible_I
// Else
// Max_Current_Before_Overflow = Max_Current
// End If
//
// ... In this case, we're good though since Max_Current is less than MaxPossible_I
//
// Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
// Max_ShuntVoltage = 0.131068V
//
// If Max_ShuntVoltage >= VSHUNT_MAX
// Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
// Else
// Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
// End If
// 8. Compute the Maximum Power
// MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
// MaximumPower = 1.31068 * 32V
// MaximumPower = 41.94176W
// Set multipliers to convert raw current/power values
currentDivider_mA = 25; // Current LSB = 40uA per bit (1000/40 = 25)
powerDivider_mW = 2; // Power LSB = 800�W per bit
return writeRegister(INA219_REG_CALIBRATION, calValue)
.then(() => {
var config = INA219_CONFIG_BVOLTAGERANGE_32V |
INA219_CONFIG_GAIN_8_320MV |
INA219_CONFIG_BADCRES_12BIT |
INA219_CONFIG_SADCRES_12BIT_1S_532US |
INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
return writeRegister(INA219_REG_CONFIG, config);
});
},
calibrate32V2A: async () => {
// By default we use a pretty huge range for the input voltage,
// which probably isn't the most appropriate choice for system
// that don't use a lot of power. But all of the calculations
// are shown below if you want to change the settings. You will
// also need to change any relevant register settings, such as
// setting the VBUS_MAX to 16V instead of 32V, etc.
// VBUS_MAX = 32V (Assumes 32V, can also be set to 16V)
// VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08,
// 0.04) RSHUNT = 0.1 (Resistor value in ohms)
// 1. Determine max possible current
// MaxPossible_I = VSHUNT_MAX / RSHUNT
// MaxPossible_I = 3.2A
// 2. Determine max expected current
// MaxExpected_I = 2.0A
// 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
// MinimumLSB = MaxExpected_I/32767
// MinimumLSB = 0.000061 (61uA per bit)
// MaximumLSB = MaxExpected_I/4096
// MaximumLSB = 0,000488 (488uA per bit)
// 4. Choose an LSB between the min and max values
// (Preferrably a roundish number close to MinLSB)
// CurrentLSB = 0.0001 (100uA per bit)
// 5. Compute the calibration register
// Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
// Cal = 4096 (0x1000)
calValue = 4096;
// 6. Calculate the power LSB
// PowerLSB = 20 * CurrentLSB
// PowerLSB = 0.002 (2mW per bit)
// 7. Compute the maximum current and shunt voltage values before overflow
//
// Max_Current = Current_LSB * 32767
// Max_Current = 3.2767A before overflow
//
// If Max_Current > Max_Possible_I then
// Max_Current_Before_Overflow = MaxPossible_I
// Else
// Max_Current_Before_Overflow = Max_Current
// End If
//
// Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
// Max_ShuntVoltage = 0.32V
//
// If Max_ShuntVoltage >= VSHUNT_MAX
// Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
// Else
// Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
// End If
// 8. Compute the Maximum Power
// MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
// MaximumPower = 3.2 * 32V
// MaximumPower = 102.4W
// Set multipliers to convert raw current/power values
currentDivider_mA = 10; // Current LSB = 40uA per bit (1000/40 = 25)
powerDivider_mW = 2; // Power LSB = 800�W per bit
return writeRegister(INA219_REG_CALIBRATION, calValue)
.then(() => {
var config = INA219_CONFIG_BVOLTAGERANGE_32V |
INA219_CONFIG_GAIN_8_320MV |
INA219_CONFIG_BADCRES_12BIT |
INA219_CONFIG_SADCRES_12BIT_1S_532US |
INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
return writeRegister(INA219_REG_CONFIG, config);
});
},
/**
* Gets the bus voltage in volts
*/
getBusVoltage_V: async () => readRegister(INA219_REG_BUSVOLTAGE)
.then(value => (value >> 3) * 4 * 0.001),
/**
* Gets the shunt voltage in mV (so +-327mV)
*/
getShuntVoltage_mV: async () => readRegister(INA219_REG_SHUNTVOLTAGE)
.then(value => value * 0.01),
/**
* Gets the current value in mA, taking into account the config settings and current LSB
*/
// Sometimes a sharp load will reset the INA219, which will
// reset the cal register, meaning CURRENT and POWER will
// not be available ... avoid this by always setting a cal
// value even if it's an unfortunate extra step
getCurrent_mA: async () => writeRegister(INA219_REG_CALIBRATION, calValue)
.then(() => readRegister(INA219_REG_CURRENT))
.then(value => value / currentDivider_mA),
/**
* Closes the underlying i2c bus object to free resources
*/
closeSync: () => wire.closeSync()
};
};