106 lines
2.4 KiB
C++
106 lines
2.4 KiB
C++
#ifndef SENS_INA_3221
|
|
#define SENS_INA_3221
|
|
|
|
/** 3-Channel i2c volt/ampere sensor */
|
|
|
|
template <typename I2C> class INA3221 {
|
|
|
|
private:
|
|
|
|
I2C& i2c;
|
|
static constexpr const uint8_t ADDR = 0b1000000;
|
|
static constexpr const char* NAME = "INA3221";
|
|
|
|
static constexpr const uint8_t REG_CFG = 0x00;
|
|
|
|
static constexpr const uint8_t REG_CH1_VS = 0x01; // shunt voltage
|
|
static constexpr const uint8_t REG_CH1_VB = 0x02; // bus voltage
|
|
|
|
static constexpr const uint8_t REG_CH2_VS = 0x03;
|
|
static constexpr const uint8_t REG_CH2_VB = 0x04;
|
|
|
|
static constexpr const uint8_t REG_CH3_VS = 0x05;
|
|
static constexpr const uint8_t REG_CH3_VB = 0x06;
|
|
|
|
public:
|
|
|
|
struct Channel {
|
|
|
|
int16_t vShunt; // in uV * 10(!!!)
|
|
int16_t vBus; // in mV
|
|
|
|
int getMilliAmps(int shunt_milliOhm) const {
|
|
return (vShunt * 10) / shunt_milliOhm;
|
|
}
|
|
|
|
};
|
|
|
|
struct Voltages {
|
|
Channel ch1;
|
|
Channel ch2;
|
|
Channel ch3;
|
|
};
|
|
|
|
public:
|
|
|
|
INA3221(I2C& i2c) : i2c(i2c) {
|
|
|
|
}
|
|
|
|
/** get the current config */
|
|
uint16_t getConfig() {
|
|
uint16_t res = 0;
|
|
i2c.readReg(ADDR, REG_CFG, 2, (uint8_t*)&res);
|
|
return res;
|
|
}
|
|
|
|
/** read all 6 voltages (3 channels, each shunt and bus) */
|
|
Voltages getVoltages() {
|
|
|
|
uint8_t buf[2];
|
|
Voltages res;
|
|
|
|
i2c.readReg(ADDR, REG_CH1_VS, sizeof(buf), buf);
|
|
res.ch1.vShunt = getShuntVoltage(buf);
|
|
i2c.readReg(ADDR, REG_CH1_VB, sizeof(buf), buf);
|
|
res.ch1.vBus = getBusVoltage(buf);
|
|
|
|
i2c.readReg(ADDR, REG_CH2_VS, sizeof(buf), buf);
|
|
res.ch2.vShunt = getShuntVoltage(buf);
|
|
i2c.readReg(ADDR, REG_CH2_VB, sizeof(buf), buf);
|
|
res.ch2.vBus = getBusVoltage(buf);
|
|
|
|
i2c.readReg(ADDR, REG_CH3_VS, sizeof(buf), buf);
|
|
res.ch3.vShunt = getShuntVoltage(buf);
|
|
i2c.readReg(ADDR, REG_CH3_VB, sizeof(buf), buf);
|
|
res.ch3.vBus = getBusVoltage(buf);
|
|
|
|
return res;
|
|
}
|
|
|
|
/** is an INA3221 present on the bus? */
|
|
bool isPresent() {
|
|
return i2c.query(ADDR);
|
|
}
|
|
|
|
private:
|
|
|
|
/** convert to bytes into a mV reading */
|
|
int16_t getBusVoltage(const uint8_t* buf) {
|
|
return ((int16_t)(getU16(buf)&0b1111111111111000)); // Bit 0,1,2 are status indicators -> remove, Bit3 = 8mV -> (LSB = 1mV)
|
|
}
|
|
|
|
/** convert to bytes into a uV reading */
|
|
int16_t getShuntVoltage(const uint8_t* buf) {
|
|
return ((int16_t)(getU16(buf)&0b1111111111111000))/2; // Bit 0,1,2 are status indicators -> remove, Bit3 = 40 uV -> / 2 and result is in 10 uV
|
|
}
|
|
|
|
uint16_t getU16(const uint8_t* buf) {
|
|
return ((buf[0] << 8) | (buf[1] << 0));
|
|
}
|
|
|
|
};
|
|
|
|
|
|
#endif // SENS_INA_3221
|