mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
6d431e0726
INA219: add INA219 driver
203 lines
4.8 KiB
Go
203 lines
4.8 KiB
Go
package ina219
|
|
|
|
import (
|
|
"tinygo.org/x/drivers"
|
|
"tinygo.org/x/drivers/internal/legacy"
|
|
)
|
|
|
|
// An INA219 device.
|
|
type Device struct {
|
|
bus drivers.I2C
|
|
Address uint16
|
|
config Config
|
|
}
|
|
|
|
// Create a new INA219 device with the default configuration
|
|
// and the given I2C bus at the default address.
|
|
//
|
|
// Set Address after New to change the address.
|
|
//
|
|
// Call Configure after New to write the configuration to the
|
|
// device. If you don't call Configure, the device may have a
|
|
// different configuration and the power divider and current
|
|
// multiplier are probably wrong.
|
|
func New(bus drivers.I2C) Device {
|
|
return Device{
|
|
bus: bus,
|
|
Address: Address,
|
|
config: Config32V2A,
|
|
}
|
|
}
|
|
|
|
// Set the configuration for the device. This only changes the
|
|
// configuration in memory, not on the device. Call Configure
|
|
// to write the configuration to the device.
|
|
func (d *Device) SetConfig(config Config) {
|
|
d.config = config
|
|
}
|
|
|
|
// Write the current configuration to the device.
|
|
func (d *Device) Configure() (err error) {
|
|
if err = d.WriteRegister(
|
|
RegConfig,
|
|
d.config.RegisterValue(),
|
|
); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = d.WriteRegister(
|
|
RegCalibration,
|
|
d.config.Calibration.RegisterValue(),
|
|
); err != nil {
|
|
return
|
|
}
|
|
|
|
var readConfig Config
|
|
// make sure the configuration is read back correctly
|
|
if readConfig, err = d.ReadConfig(); err != nil {
|
|
return
|
|
} else if readConfig.RegisterValue() != d.config.RegisterValue() {
|
|
err = ErrConfigMismatch{}
|
|
} else if readConfig.Calibration.RegisterValue() != d.config.Calibration.RegisterValue() {
|
|
err = ErrConfigMismatch{}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Trigger a conversion. This is only necessary if the device is in
|
|
// trigger mode. In continuous mode (the default), the device will
|
|
// automatically trigger conversions and this has no effect. See
|
|
// config.go.
|
|
//
|
|
// Triggering a conversion or reading the "power" register resets
|
|
// the conversion ready bit.
|
|
func (d *Device) Trigger() (err error) {
|
|
// Only trigger if the mode is one of the triggered modes.
|
|
if ModeTriggered(d.config.Mode) {
|
|
err = d.WriteRegister(RegConfig, d.config.RegisterValue())
|
|
}
|
|
return
|
|
}
|
|
|
|
// Measurements reads the bus voltage, shunt voltage, current, and power
|
|
// from the device.
|
|
func (d *Device) Measurements() (
|
|
busVoltage int16,
|
|
shuntVoltage int16,
|
|
current float32,
|
|
power float32,
|
|
err error,
|
|
) {
|
|
// Attempt to read bus voltage first, so we can check for overflow
|
|
// or conversion not ready.
|
|
if busVoltage, err = d.BusVoltage(); err != nil {
|
|
return
|
|
}
|
|
|
|
// Read the rest of the values, reading Power last, which resets
|
|
// the conversion ready bit (relevant for triggered modes).
|
|
if shuntVoltage, err = d.ShuntVoltage(); err != nil {
|
|
return
|
|
}
|
|
|
|
if current, err = d.Current(); err != nil {
|
|
return
|
|
}
|
|
|
|
if power, err = d.Power(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// BusVoltage reads the "bus" voltage in millivolts.
|
|
//
|
|
// It returns an error if the value is invalid due to overflow
|
|
// or if the conversion is not ready yet. In a continuous mode
|
|
// there should always be a measurement available after the
|
|
// device is ready. See above notes on Trigger.
|
|
func (d *Device) BusVoltage() (voltage int16, err error) {
|
|
val, err := d.ReadRegister(RegBusVoltage)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// The overflow bit is set, so the values are invalid.
|
|
if val&(1<<0) != 0 {
|
|
err = ErrOverflow{}
|
|
return
|
|
}
|
|
|
|
// The conversion is not ready yet.
|
|
if ModeTriggered(d.config.Mode) && val&(1<<1) != 0 {
|
|
err = ErrNotReady{}
|
|
return
|
|
}
|
|
|
|
voltage = (int16(val) >> 3) * 4
|
|
return
|
|
}
|
|
|
|
// ShuntVoltage reads the "shunt" voltage in 100ths of a millivolt.
|
|
func (d *Device) ShuntVoltage() (voltage int16, err error) {
|
|
return d.ReadRegister(RegShuntVoltage)
|
|
}
|
|
|
|
// Current reads the current in milliamps.
|
|
func (d *Device) Current() (current float32, err error) {
|
|
val, err := d.ReadRegister(RegCurrent)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
current = float32(val) / d.config.CurrentDivider
|
|
return
|
|
}
|
|
|
|
// Power reads the power in milliwatts.
|
|
func (d *Device) Power() (power float32, err error) {
|
|
val, err := d.ReadRegister(RegPower)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
power = float32(val) * d.config.PowerMultiplier
|
|
return
|
|
}
|
|
|
|
// Read the configuration from the device.
|
|
func (d *Device) ReadConfig() (config Config, err error) {
|
|
var cfg, cal int16
|
|
if cfg, err = d.ReadRegister(RegConfig); err != nil {
|
|
return
|
|
}
|
|
|
|
if cal, err = d.ReadRegister(RegCalibration); err != nil {
|
|
return
|
|
}
|
|
|
|
config = NewConfig(cfg, cal)
|
|
return
|
|
}
|
|
|
|
// Read a register from the device.
|
|
func (d *Device) ReadRegister(reg uint8) (val int16, err error) {
|
|
buf := make([]byte, 2)
|
|
|
|
err = legacy.ReadRegister(d.bus, uint8(d.Address), reg, buf)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
val = int16(buf[0])<<8 | int16(buf[1]&0xff)
|
|
return
|
|
}
|
|
|
|
// Write to a register on the device.
|
|
func (d *Device) WriteRegister(reg uint8, val uint16) error {
|
|
buf := []byte{byte(val >> 8), byte(val & 0xff)}
|
|
return legacy.WriteRegister(d.bus, uint8(d.Address), reg, buf)
|
|
}
|