mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
@@ -0,0 +1,29 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ina219"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
|
||||||
|
dev := ina219.New(machine.I2C0)
|
||||||
|
dev.Configure()
|
||||||
|
|
||||||
|
for {
|
||||||
|
busVoltage, shuntVoltage, current, power, err := dev.Measurements()
|
||||||
|
if err != nil {
|
||||||
|
println("Error reading measurements", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Bus Voltage:", busVoltage, "V")
|
||||||
|
println("Shunt Voltage:", shuntVoltage/100, "mV")
|
||||||
|
println("Current:", current, "mA")
|
||||||
|
println("Power:", power, "mW")
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package ina219
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
// BusVoltageRange sets the bus voltage range.
|
||||||
|
BusVoltageRange BusVoltageRange
|
||||||
|
|
||||||
|
// PGA sets the programmable gain amplifier.
|
||||||
|
PGA PGA
|
||||||
|
|
||||||
|
// BusADC sets the bus ADC resolution.
|
||||||
|
BusADC BusADC
|
||||||
|
|
||||||
|
// ShuntADC sets the shunt ADC resolution.
|
||||||
|
ShuntADC ShuntADC
|
||||||
|
|
||||||
|
// Mode sets the operating mode.
|
||||||
|
Mode Mode
|
||||||
|
|
||||||
|
// Calibration sets the calibration value for the expected
|
||||||
|
// voltage and current values.
|
||||||
|
Calibration Calibration
|
||||||
|
|
||||||
|
// 1000 / uA per bit
|
||||||
|
CurrentDivider float32
|
||||||
|
|
||||||
|
// 1mW per bit
|
||||||
|
PowerMultiplier float32
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterValue returns the register value of the configuration.
|
||||||
|
func (c *Config) RegisterValue() uint16 {
|
||||||
|
return c.BusVoltageRange.RegisterValue() |
|
||||||
|
c.PGA.RegisterValue() |
|
||||||
|
c.BusADC.RegisterValue() |
|
||||||
|
c.ShuntADC.RegisterValue() |
|
||||||
|
c.Mode.RegisterValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new configuration from a register value.
|
||||||
|
func NewConfig(config int16, calibration int16) Config {
|
||||||
|
return Config{
|
||||||
|
BusVoltageRange: BusVoltageRange(config >> 13 & 0x1),
|
||||||
|
PGA: PGA(config >> 11 & 0x3),
|
||||||
|
BusADC: BusADC(config >> 7 & 0xF),
|
||||||
|
ShuntADC: ShuntADC(config >> 3 & 0xF),
|
||||||
|
Mode: Mode(config & 0x7),
|
||||||
|
Calibration: Calibration(calibration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configurations from
|
||||||
|
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
|
||||||
|
var (
|
||||||
|
// Config32V2A is a configuration for a 32V 2A range.
|
||||||
|
Config32V2A = Config{
|
||||||
|
BusVoltageRange: Range32V,
|
||||||
|
PGA: PGA8,
|
||||||
|
BusADC: ADC12,
|
||||||
|
ShuntADC: SADC12,
|
||||||
|
Mode: ModeContShuntBus,
|
||||||
|
Calibration: Calibration16V400mA,
|
||||||
|
CurrentDivider: 10.0,
|
||||||
|
PowerMultiplier: 2.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config32V1A is a configuration for a 32V 1A range.
|
||||||
|
Config32V1A = Config{
|
||||||
|
BusVoltageRange: Range32V,
|
||||||
|
PGA: PGA8,
|
||||||
|
BusADC: ADC12,
|
||||||
|
ShuntADC: SADC12,
|
||||||
|
Mode: ModeContShuntBus,
|
||||||
|
Calibration: Calibration32V1A,
|
||||||
|
CurrentDivider: 25.0,
|
||||||
|
PowerMultiplier: 0.8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config16V400mA is a configuration for a 16V 400mA range.
|
||||||
|
Config16V400mA = Config{
|
||||||
|
BusVoltageRange: Range16V,
|
||||||
|
PGA: PGA1,
|
||||||
|
BusADC: ADC12,
|
||||||
|
ShuntADC: SADC12,
|
||||||
|
Mode: ModeContShuntBus,
|
||||||
|
Calibration: Calibration16V400mA,
|
||||||
|
CurrentDivider: 20.0,
|
||||||
|
PowerMultiplier: 1.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// BusVoltageRange is the bus voltage range.
|
||||||
|
type BusVoltageRange int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
Range16V BusVoltageRange = 0 // 0-16V
|
||||||
|
Range32V BusVoltageRange = 1 // 0-32V
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r BusVoltageRange) RegisterValue() uint16 {
|
||||||
|
return uint16(r) << 13
|
||||||
|
}
|
||||||
|
|
||||||
|
// PGA is the programmable gain amplifier.
|
||||||
|
type PGA int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
PGA1 PGA = 0 // 40mV
|
||||||
|
PGA2 PGA = 1 // 80mV
|
||||||
|
PGA4 PGA = 2 // 160mV
|
||||||
|
PGA8 PGA = 3 // 320mV
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p PGA) RegisterValue() uint16 {
|
||||||
|
return uint16(p) << 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// BusADC is the bus ADC resolution.
|
||||||
|
type BusADC int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ADC9 BusADC = 0 // 9-bit
|
||||||
|
ADC10 BusADC = 1 // 10-bit
|
||||||
|
ADC11 BusADC = 2 // 11-bit
|
||||||
|
ADC12 BusADC = 3 // 12-bit
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b BusADC) RegisterValue() uint16 {
|
||||||
|
return uint16(b) << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShuntADC is the shunt ADC resolution.
|
||||||
|
type ShuntADC int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
SADC9 ShuntADC = 0 // 9-bit
|
||||||
|
SADC10 ShuntADC = 1 // 10-bit
|
||||||
|
SADC11 ShuntADC = 2 // 11-bit
|
||||||
|
SADC12 ShuntADC = 3 // 12-bit
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s ShuntADC) RegisterValue() uint16 {
|
||||||
|
return uint16(s) << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode is the operating mode.
|
||||||
|
type Mode int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModePowerDown Mode = 0 // power-down
|
||||||
|
ModeTrigShunt Mode = 1 // triggered shunt voltage
|
||||||
|
ModeTrigBus Mode = 2 // triggered bus voltage
|
||||||
|
ModeTrigShuntBus Mode = 3 // triggered shunt and bus voltage
|
||||||
|
ModeADCOff Mode = 4 // ADC off
|
||||||
|
ModeContShunt Mode = 5 // continuous shunt voltage
|
||||||
|
ModeContBus Mode = 6 // continuous bus voltage
|
||||||
|
ModeContShuntBus Mode = 7 // continuous shunt and bus voltage
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModeTriggered is a mask for triggered modes.
|
||||||
|
const ModeTriggeredMask Mode = 0x4
|
||||||
|
|
||||||
|
// ModeTriggered returns true if the mode is a triggered mode.
|
||||||
|
func ModeTriggered(m Mode) bool {
|
||||||
|
return m != ModePowerDown && m&ModeTriggeredMask == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mode) RegisterValue() uint16 {
|
||||||
|
return uint16(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calibration is the calibration register for the INA219. Values from:
|
||||||
|
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
|
||||||
|
type Calibration uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
Calibration32V2A Calibration = 4096
|
||||||
|
Calibration32V1A Calibration = 10240
|
||||||
|
Calibration16V400mA Calibration = 8192
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c Calibration) RegisterValue() uint16 {
|
||||||
|
return uint16(c)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ina219
|
||||||
|
|
||||||
|
type ErrOverflow struct{}
|
||||||
|
|
||||||
|
func (e ErrOverflow) Error() string { return "overflow" }
|
||||||
|
|
||||||
|
type ErrNotReady struct{}
|
||||||
|
|
||||||
|
func (e ErrNotReady) Error() string { return "not ready" }
|
||||||
|
|
||||||
|
type ErrConfigMismatch struct{}
|
||||||
|
|
||||||
|
func (e ErrConfigMismatch) Error() string { return "config mismatch" }
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
package ina219
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
"tinygo.org/x/drivers/tester"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultAddress(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
dev := New(bus)
|
||||||
|
c.Assert(dev.Address, qt.Equals, uint16(Address))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBusVoltage(t *testing.T) {
|
||||||
|
t.Run("valid", func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegBusVoltage: (4200 << 3) / 4, // 4.2V
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
voltage, err := dev.BusVoltage()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(voltage, qt.Equals, int16(4200))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("overflow", func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegBusVoltage: (1 >> 0), // overflow
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
_, err := dev.BusVoltage()
|
||||||
|
c.Assert(err, qt.Not(qt.IsNil))
|
||||||
|
c.Assert(err, qt.ErrorMatches, ErrOverflow{}.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not ready", func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegBusVoltage: ((4200 << 3) / 4) | (1 << 1), // not ready
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config.Mode = ModeTrigBus
|
||||||
|
_, err := dev.BusVoltage()
|
||||||
|
c.Assert(err, qt.Not(qt.IsNil))
|
||||||
|
c.Assert(err, qt.ErrorMatches, ErrNotReady{}.Error())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShuntVoltage(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegShuntVoltage: 0x1234,
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
voltage, err := dev.ShuntVoltage()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(voltage, qt.Equals, int16(0x1234))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCurrent(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegCurrent: 420 * 6.9, // 420mA
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config.CurrentDivider = 6.9
|
||||||
|
current, err := dev.Current()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(current, qt.Equals, float32(420))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPower(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegPower: 420 / 0.8, // 420mW
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config.PowerMultiplier = 0.8
|
||||||
|
power, err := dev.Power()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(power, qt.Equals, float32(420))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadConfig(t *testing.T) {
|
||||||
|
// use the default configurations
|
||||||
|
for _, tc := range []Config{
|
||||||
|
Config16V400mA,
|
||||||
|
Config32V2A,
|
||||||
|
Config32V1A,
|
||||||
|
} {
|
||||||
|
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegConfig: tc.RegisterValue(),
|
||||||
|
RegCalibration: tc.Calibration.RegisterValue(),
|
||||||
|
}
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
config, err := dev.ReadConfig()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(config.BusADC, qt.Equals, tc.BusADC)
|
||||||
|
c.Assert(config.BusVoltageRange, qt.Equals, tc.BusVoltageRange)
|
||||||
|
c.Assert(config.Calibration, qt.Equals, tc.Calibration)
|
||||||
|
c.Assert(config.Mode, qt.Equals, tc.Mode)
|
||||||
|
c.Assert(config.PGA, qt.Equals, tc.PGA)
|
||||||
|
c.Assert(config.ShuntADC, qt.Equals, tc.ShuntADC)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteConfig(t *testing.T) {
|
||||||
|
// use the default configurations
|
||||||
|
for _, tc := range []Config{
|
||||||
|
Config16V400mA,
|
||||||
|
Config32V2A,
|
||||||
|
Config32V1A,
|
||||||
|
} {
|
||||||
|
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegConfig: 0,
|
||||||
|
RegCalibration: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config = tc
|
||||||
|
err := dev.Configure()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(fake.Registers[RegConfig], qt.Equals, tc.RegisterValue())
|
||||||
|
c.Assert(fake.Registers[RegCalibration], qt.Equals, tc.Calibration.RegisterValue())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetConfig(t *testing.T) {
|
||||||
|
for _, tc := range []Config{
|
||||||
|
Config16V400mA,
|
||||||
|
Config32V2A,
|
||||||
|
Config32V1A,
|
||||||
|
} {
|
||||||
|
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
dev := New(bus)
|
||||||
|
dev.SetConfig(tc)
|
||||||
|
c.Assert(dev.config, qt.Equals, tc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrigger(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegConfig: Config32V2A.RegisterValue(),
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config = Config32V2A
|
||||||
|
dev.config.Mode = ModeTrigBus
|
||||||
|
err := dev.Trigger()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(fake.Registers[RegConfig], qt.Equals, dev.config.RegisterValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMeasurements(t *testing.T) {
|
||||||
|
bvVal := int16(4200)
|
||||||
|
svVal := int16(1234)
|
||||||
|
iVal := float32(420)
|
||||||
|
pVal := float32(420)
|
||||||
|
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := tester.NewI2CBus(c)
|
||||||
|
fake := tester.NewI2CDevice16(c, Address)
|
||||||
|
bus.AddDevice(fake)
|
||||||
|
fake.Registers = map[uint8]uint16{
|
||||||
|
RegBusVoltage: uint16(((4200 << 3) / 4) | (1 << 1)),
|
||||||
|
RegShuntVoltage: uint16(svVal),
|
||||||
|
RegCurrent: uint16(iVal * Config16V400mA.CurrentDivider),
|
||||||
|
RegPower: uint16(pVal / Config16V400mA.PowerMultiplier),
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := New(bus)
|
||||||
|
dev.config = Config16V400mA
|
||||||
|
bv, sv, i, p, err := dev.Measurements()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(bv, qt.Equals, bvVal)
|
||||||
|
c.Assert(sv, qt.Equals, svVal)
|
||||||
|
c.Assert(i, qt.Equals, iVal)
|
||||||
|
c.Assert(p, qt.Equals, pVal)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ina219
|
||||||
|
|
||||||
|
// The default I2C address for this device.
|
||||||
|
const Address = 0x40
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegConfig uint8 = 0x0
|
||||||
|
RegShuntVoltage uint8 = 0x1
|
||||||
|
RegBusVoltage uint8 = 0x2
|
||||||
|
RegPower uint8 = 0x3
|
||||||
|
RegCurrent uint8 = 0x4
|
||||||
|
RegCalibration uint8 = 0x5
|
||||||
|
)
|
||||||
@@ -109,6 +109,7 @@ tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/tim
|
|||||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/qmi8658c/main.go
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/qmi8658c/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/pcf8591/
|
tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/pcf8591/
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
|
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina219/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
|
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
|
||||||
|
|||||||
Reference in New Issue
Block a user