#ifndef SENS_INA_3221 #define SENS_INA_3221 /** 3-Channel i2c volt/ampere sensor */ template 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; int16_t vBus; }; 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 = getVoltage(buf); i2c.readReg(ADDR, REG_CH1_VB, sizeof(buf), buf); res.ch1.vBus = getVoltage(buf); i2c.readReg(ADDR, REG_CH2_VS, sizeof(buf), buf); res.ch2.vShunt = getVoltage(buf); i2c.readReg(ADDR, REG_CH2_VB, sizeof(buf), buf); res.ch2.vBus = getVoltage(buf); i2c.readReg(ADDR, REG_CH3_VS, sizeof(buf), buf); res.ch3.vShunt = getVoltage(buf); i2c.readReg(ADDR, REG_CH3_VB, sizeof(buf), buf); res.ch3.vBus = getVoltage(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 getVoltage(const uint8_t* buf) { return ((buf[0] << 8) | (buf[1] << 0)); // the lowest 3 bits are always zero. no shift required! } }; #endif // SENS_INA_3221