diff --git a/Source/MF.Sensors.slnf b/Source/MF.Sensors.slnf
index d5564d95dc..7657c7b980 100644
--- a/Source/MF.Sensors.slnf
+++ b/Source/MF.Sensors.slnf
@@ -5,8 +5,9 @@
"..\\..\\MQTTnet\\Source\\MQTTnet\\MQTTnet.csproj",
"..\\..\\Meadow.Contracts\\Source\\Meadow.Contracts\\Meadow.Contracts.csproj",
"..\\..\\Meadow.Core\\source\\Meadow.Core\\Meadow.Core.csproj",
- "..\\..\\Meadow.Core\\source\\Meadow.F7\\Meadow.F7.csproj",
- "..\\..\\Meadow.Logging\\lib\\Meadow.Logging.csproj",
+ "..\\..\\Meadow.Core\\source\\implementations\\f7\\Meadow.F7\\Meadow.F7.csproj",
+ "..\\..\\Meadow.Logging\\Source\\Meadow.Logging\\lib\\Meadow.Logging.csproj",
+ "..\\..\\Meadow.Modbus\\src\\Meadow.Modbus\\Meadow.Modbus.csproj",
"..\\..\\Meadow.Units\\Source\\Meadow.Units\\Meadow.Units.csproj",
"Meadow.Foundation.Core\\Meadow.Foundation.Core.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Atmospheric.AdafruitMPRLS\\Driver\\Sensors.Atmospheric.AdafruitMPRLS.csproj",
@@ -138,8 +139,10 @@
"Meadow.Foundation.Peripherals\\Sensors.Motion.Mpu6050\\Samples\\Mpu6050_Sample\\Mpu6050_Sample.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Motion.ParallaxPir\\Driver\\Sensors.Motion.ParallaxPir.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Motion.ParallaxPir\\Samples\\ParallaxPir_Sample\\ParallaxPir_Sample.csproj",
- "Meadow.Foundation.Peripherals\\Sensors.Power.Ina260\\Driver\\Sensors.Power.Ina260.csproj",
- "Meadow.Foundation.Peripherals\\Sensors.Power.Ina260\\Samples\\Ina260_Sample\\Ina260_Sample.csproj",
+ "Meadow.Foundation.Peripherals\\Sensors.Power.Ina2xx\\Driver\\Sensors.Power.Ina2xx.csproj",
+ "Meadow.Foundation.Peripherals\\Sensors.Power.Ina2xx\\Samples\\Ina219_Sample\\Ina219_Sample.csproj",
+ "Meadow.Foundation.Peripherals\\Sensors.Power.Ina2xx\\Samples\\Ina228_Sample\\Ina228_Sample.csproj",
+ "Meadow.Foundation.Peripherals\\Sensors.Power.Ina2xx\\Samples\\Ina260_Sample\\Ina260_Sample.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Radio.Rfid.IDxxLA\\Driver\\Sensors.Radio.Rfid.IDxxLA.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Radio.Rfid.IDxxLA\\Samples\\IDxxLA_Sample\\IDxxLA_Sample.csproj",
"Meadow.Foundation.Peripherals\\Sensors.Radio.Rfid.Rc522\\Driver\\Sensors.Radio.Rfid.Rc522.csproj",
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.Enums.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.Enums.cs
deleted file mode 100644
index 535aa8fa96..0000000000
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.Enums.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-namespace Meadow.Foundation.Sensors.Power
-{
- public partial class Ina260
- {
- ///
- /// Valid I2C addresses for the sensor
- ///
- public enum Addresses : byte
- {
- ///
- /// Bus address 0x40
- ///
- Address_0x40 = 0x40,
- ///
- /// Bus address 0x41
- ///
- Address_0x41 = 0x41,
- ///
- /// Default bus address
- ///
- Default = Address_0x40
- }
-
- private enum Register : byte
- {
- Config = 0x00,
- Current = 0x01,
- Voltage = 0x02,
- Power = 0x03,
- MaskEnable = 0x06,
- AlertLimit = 0x07,
- ManufacturerID = 0xFE,
- DieID = 0xFF
- }
- }
-}
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.cs
deleted file mode 100644
index 62ecbc1678..0000000000
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Ina260.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Meadow.Hardware;
-using Meadow.Units;
-using System;
-using System.Threading.Tasks;
-
-namespace Meadow.Foundation.Sensors.Power
-{
- ///
- /// Represents a INA260 Precision Digital Current and Power Monitor
- ///
- public partial class Ina260
- : ByteCommsSensorBase<(Units.Power? Power, Voltage? Voltage, Current? Current)>,
- II2cPeripheral
- {
- ///
- /// The default I2C address for the peripheral
- ///
- public byte DefaultI2cAddress => (byte)Addresses.Default;
-
- ///
- /// Raised when the power value changes
- ///
- public event EventHandler> PowerUpdated = default!;
-
- ///
- /// Raised when the voltage value changes
- ///
- public event EventHandler> VoltageUpdated = default!;
-
- ///
- /// Raised when the current value changes
- ///
- public event EventHandler> CurrentUpdated = default!;
-
- private const float MeasurementScale = 0.00125f;
-
- ///
- /// The value of the current (in Amps) flowing through the shunt resistor from the last reading
- ///
- public Current? Current => Conditions.Current;
-
- ///
- /// The voltage from the last reading..
- ///
- public Voltage? Voltage => Conditions.Voltage;
-
- ///
- /// The power from the last reading..
- ///
- public Units.Power? Power => Conditions.Power;
-
- ///
- /// Create a new INA260 object
- ///
- /// The I2C bus
- /// The I2C address
- public Ina260(II2cBus i2cBus, byte address = (byte)Addresses.Default)
- : base(i2cBus, address)
- {
- switch (address)
- {
- case (byte)Addresses.Address_0x40:
- case (byte)Addresses.Address_0x41:
- // valid;
- break;
- default:
- throw new ArgumentOutOfRangeException("INA260 device address must be either 0x40 or 0x41");
- }
- }
-
- ///
- /// Reads data from the sensor
- ///
- /// The latest sensor reading
- protected override Task<(Units.Power? Power, Voltage? Voltage, Current? Current)> ReadSensor()
- {
- (Units.Power? Power, Voltage? Voltage, Current? Current) conditions;
-
- conditions.Voltage = new Voltage(BusComms.ReadRegister((byte)Register.Voltage) * MeasurementScale, Units.Voltage.UnitType.Volts);
- conditions.Current = new Current(BusComms.ReadRegister((byte)Register.Current) * MeasurementScale, Units.Current.UnitType.Amps);
- conditions.Power = new Units.Power(BusComms.ReadRegister((byte)Register.Power) * 0.01f, Units.Power.UnitType.Watts);
-
- return Task.FromResult(conditions);
- }
-
- ///
- /// Raise events for subscribers and notify of value changes
- ///
- /// The updated sensor data
- protected override void RaiseEventsAndNotify(IChangeResult<(Units.Power? Power, Voltage? Voltage, Current? Current)> changeResult)
- {
- if (changeResult.New.Power is { } power)
- {
- PowerUpdated?.Invoke(this, new ChangeResult(power, changeResult.Old?.Power));
- }
- if (changeResult.New.Voltage is { } volts)
- {
- VoltageUpdated?.Invoke(this, new ChangeResult(volts, changeResult.Old?.Voltage));
- }
- if (changeResult.New.Current is { } amps)
- {
- CurrentUpdated?.Invoke(this, new ChangeResult(amps, changeResult.Old?.Current));
- }
-
- base.RaiseEventsAndNotify(changeResult);
- }
-
- ///
- /// Reads the unique manufacturer identification number
- ///
- public int ManufacturerID => BusComms.ReadRegister((byte)Register.ManufacturerID);
-
- ///
- /// Reads the unique die identification number
- ///
- public int DieID => BusComms.ReadRegister((byte)Register.ManufacturerID);
- }
-}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/MeadowApp.cs
deleted file mode 100644
index c395e4f091..0000000000
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/MeadowApp.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Meadow;
-using Meadow.Devices;
-using Meadow.Foundation.Sensors.Power;
-using System;
-using System.Threading.Tasks;
-
-namespace MeadowApp
-{
- public class MeadowApp : App
- {
- //
-
- Ina260 ina260;
-
- public override Task Initialize()
- {
- Resolver.Log.Info("Initialize...");
-
- var bus = Device.CreateI2cBus();
- ina260 = new Ina260(bus);
-
- Resolver.Log.Info($"-- INA260 Sample App ---");
- Resolver.Log.Info($"Manufacturer: {ina260.ManufacturerID}");
- Resolver.Log.Info($"Die: {ina260.DieID}");
- ina260.Updated += (s, v) =>
- {
- Resolver.Log.Info($"{v.New.Item2}V @ {v.New.Item3}A");
- };
-
- return Task.CompletedTask;
- }
-
- public override Task Run()
- {
- ina260.StartUpdating(TimeSpan.FromSeconds(2));
- return Task.CompletedTask;
- }
-
- //
- }
-}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina219.pdf b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina219.pdf
new file mode 100644
index 0000000000..cae8594bef
Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina219.pdf differ
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina228.pdf b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina228.pdf
new file mode 100644
index 0000000000..ae4aa8a698
Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina228.pdf differ
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Datasheet/ina260.pdf b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina260.pdf
similarity index 100%
rename from Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Datasheet/ina260.pdf
rename to Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Datasheet/ina260.pdf
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina219.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina219.cs
new file mode 100644
index 0000000000..1dc46fbc13
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina219.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Runtime.CompilerServices;
+using Meadow.Hardware;
+using Meadow.Units;
+
+namespace Meadow.Foundation.Sensors.Power;
+
+///
+/// Represents a INA219 Precision Digital Current and Power Monitor
+///
+public class Ina219 : Ina2xx
+{
+ private readonly Voltage _shuntVoltageScale;
+ private Current _maxExpectedCurrent;
+ private ushort _calibration;
+
+ ///
+ /// Create a new INA219 object
+ ///
+ /// The I2C bus
+ /// The I2C address
+ /// Resistance used for measuring current. null uses default of 0.1 Ohms, to match Adafruit's INA219 breakout board.
+ protected Ina219(II2cBus i2cBus, byte address, Units.Resistance shuntResistance)
+ : base(i2cBus, address)
+ {
+ _voltageScale = new Voltage(4, Units.Voltage.UnitType.Millivolts);
+ _shuntVoltageScale = new Voltage(10, Units.Voltage.UnitType.Microvolts);
+ _shuntResistor = shuntResistance;
+ }
+
+ ///
+ /// Create a new INA219 object, with the default current and resistor values to match Adafruit's INA219 breakout board.
+ ///
+ /// The I2C bus
+ /// The I2C address
+ public Ina219(II2cBus i2cBus, byte address = (byte)Addresses.Default)
+ : this(i2cBus, address, new Resistance(0.1))
+ { }
+
+ ///
+ public override void Configure()
+ {
+ Configure(BusVoltageRange.Range_32V, ADCModes.ADCMode_12bit_532us,
+ ShuntVoltageRange.Range_320mV, ADCModes.ADCMode_12bit_532us,
+ Mode.ContinuousAll);
+ }
+
+ ///
+ /// Sets Configuration of sensor
+ ///
+ /// to use for Bus Voltage measurement
+ /// ADC resolution/averaging for Bus Voltage
+ /// to use for Shunt Voltage measurement
+ /// ADC resolution/averaging for Shunt Voltage
+ /// selection of values and trigger mode
+ public void Configure(
+ BusVoltageRange busVoltageRange = BusVoltageRange.Range_32V,
+ ADCModes busADCMode = ADCModes.ADCMode_12bit_532us,
+ ShuntVoltageRange shuntVoltageRange = ShuntVoltageRange.Range_320mV,
+ ADCModes shuntADCMode = ADCModes.ADCMode_12bit_532us,
+ Mode mode = Mode.ContinuousAll
+ )
+ {
+ ushort config = (ushort)((ushort)busVoltageRange | (ushort)shuntVoltageRange | (ushort) busADCMode << 7 | (ushort)shuntADCMode << 3 | (ushort)mode);
+ WriteRegister(Registers.Config, config);
+ if (_calibration > 0)
+ WriteRegister(Registers.Calibration, _calibration);
+ }
+
+ ///
+ /// Sets Configuration of sensor, using best shunt voltage range possible based on the max expected current.
+ ///
+ /// voltage measurement range
+ /// Maximum expected current for the application.
+ /// ADC resolution/averaging setting common to both ADCs
+ /// selection of values and trigger mode
+ public void Configure(
+ BusVoltageRange busVoltageRange,
+ Current maxExpectedCurrent,
+ ADCModes adcMode = ADCModes.ADCMode_12bit_532us,
+ Mode mode = Mode.ContinuousAll)
+ {
+ _maxExpectedCurrent = maxExpectedCurrent;
+ var shuntVoltageRange = SetCalibration(_maxExpectedCurrent); // NOTE: Calibration register needs to be calculated and populated before Current or Power registers will work.
+ Configure(busVoltageRange, adcMode, shuntVoltageRange, adcMode, mode);
+ }
+
+ ///
+ /// _currentScale and _powerScale are set along with _calibration using logic outlined in the datasheet for the INA219
+ ///
+ /// Maximum expected Current in the specific application.
+ /// suggested to use in configuration
+ private ShuntVoltageRange SetCalibration(Current maxExpectedCurrent)
+ {
+ var maxShuntVoltage = 0.32;
+ var minimumLSB = maxExpectedCurrent.Microamps / 0x7FFF;
+ var maximumLSB = maxExpectedCurrent.Microamps / 0x1000;
+ var selectedLSB = Math.Ceiling(minimumLSB);
+ _currentScale = new Current(selectedLSB, Units.Current.UnitType.Microamps);
+ _powerScale = new Units.Power(_currentScale.Amps * 20, Units.Power.UnitType.Watts);
+ _calibration = (ushort)(0.04096 / (_currentScale.Amps * _shuntResistor.Ohms));
+
+ var maxCurrentBeforeOverflow = Math.Min(maxShuntVoltage / _shuntResistor.Ohms, _currentScale.Amps * 0x7FFF);
+ var maxShuntVoltageBeforeOverflow = Math.Min(maxExpectedCurrent.Amps * _shuntResistor.Ohms, maxShuntVoltage);
+
+ return maxShuntVoltageBeforeOverflow switch
+ {
+ <= 0.04 => ShuntVoltageRange.Range_40mV,
+ <= 0.08 => ShuntVoltageRange.Range_80mV,
+ <= 0.16 => ShuntVoltageRange.Range_160mV,
+ _ => ShuntVoltageRange.Range_320mV,
+ };
+ }
+
+ ///
+ public override Units.Current ReadCurrent() => new Current((short)ReadRegisterAsUShort(Registers.Current) * _currentScale.Amps);
+
+ ///
+ public override Units.Voltage ReadBusVoltage()
+ {
+ var rawRegister = ReadRegisterAsUShort(Registers.BusVoltage);
+ var mathOverflow = (rawRegister & 0x0001) != 0;
+ return new Voltage((rawRegister >> 3) * _voltageScale.Volts);
+ }
+ ///
+ public override Units.Voltage ReadShuntVoltage() => new Voltage(ReadRegisterAsUShort(Registers.ShuntVoltage) * _shuntVoltageScale.Volts);
+ ///
+ public override Units.Power ReadPower() => new Units.Power(ReadRegisterAsUShort(Registers.Power) * _powerScale.Watts);
+
+ ///
+ internal override void ReadDeviceInfo()
+ {
+ ManufacturerID = string.Empty;
+ DeviceID = DeviceRevision = 0;
+ }
+
+ #region Enumerations
+ private enum Registers : byte
+ {
+ Config = 0x00,
+ ShuntVoltage = 0x01,
+ BusVoltage = 0x02,
+ Power = 0x03,
+ Current = 0x04,
+ Calibration = 0x05,
+ }
+
+ ///
+ /// Enumeration of supported voltage measurement ranges.
+ ///
+ /// There is no actual reason to not use 32V, as it has the same resolution.
+ public enum BusVoltageRange : ushort
+ {
+ /// 16 Volt measurement range.
+ Range_16V = 0x0000,
+ /// 32 Volt measurement range.
+ Range_32V = 0x2000,
+ }
+
+ ///
+ /// Enumeration of supported shunt voltage measurement ranges.
+ ///
+ public enum ShuntVoltageRange : ushort
+ {
+ /// 40 millivolt measurement range.
+ Range_40mV = 0x0000,
+ /// 80 millivolt measurement range.
+ Range_80mV = 0x0800,
+ /// 160 millivolt measurement range.
+ Range_160mV = 0x1000,
+ /// 320 millivolt measurement range.
+ Range_320mV = 0x1800,
+ }
+
+ ///
+ /// Enumeration of supported ADC Averaging and Conversion time settings.
+ ///
+ public enum ADCModes : byte
+ {
+ /// 9-bit measurement resolution with 84 µs conversion time.
+ ADCMode_9bit_84us = 0x00,
+ /// 10-bit measurement resolution with 148 µs conversion time.
+ ADCMode_10bit_148us = 0x01,
+ /// 11-bit measurement resolution with 276 µs conversion time.
+ ADCMode_11bit_276us = 0x02,
+ /// 12-bit measurement resolution with 532 µs conversion time.
+ ADCMode_12bit_532us = 0x03,
+ /// 12-bit measurement resolution with 532 µs conversion time, averaging 1 sample.
+ ADCMode_1xAvg_532us = 0x08,
+ /// 12-bit measurement resolution with 1.064 ms conversion time, averaging 2 samples.
+ ADCMode_2xAvg_1064us = 0x09,
+ /// 12-bit measurement resolution with 2.128 ms conversion time, averaging 4 samples.
+ ADCMode_4xAvg_2128us = 0x0A,
+ /// 12-bit measurement resolution with 4.256 ms conversion time, averaging 8 samples.
+ ADCMode_8xAvg_4256us = 0x0B,
+ /// 12-bit measurement resolution with 8.512 ms conversion time, averaging 16 samples.
+ ADCMode_16xAvg_8512us = 0x0C,
+ /// 12-bit measurement resolution with 17.024 ms conversion time, averaging 32 samples.
+ ADCMode_32xAvg_17024us = 0x0D,
+ /// 12-bit measurement resolution with 34.048 ms conversion time, averaging 64 samples.
+ ADCMode_64xAvg_34048us = 0x0E,
+ /// 12-bit measurement resolution with 68.096 ms conversion time, averaging 128 samples.
+ ADCMode_128xAvg_68096us = 0x0F,
+
+ }
+
+ ///
+ /// Enumeration of supported operation modes.
+ ///
+ public enum Mode
+ {
+ /// Power down (no conversions).
+ PowerDown = 0x0,
+ /// Measure Current once.
+ TriggeredCurrent = 0x1,
+ /// Measure Voltage once.
+ TriggeredVoltage = 0x2,
+ /// Measure Voltage and Current once.
+ TriggeredAll = 0x3,
+ /// Power down (no conversions).
+ PowerDown2 = 0x4,
+ /// Measure Current continuously.
+ ContinuousCurrent = 0x5,
+ /// Measure Voltage continuously.
+ ContinuousVoltage = 0x6,
+ /// Measure Voltage and Current continuously (default).
+ ContinuousAll = 0x7, // default at POR
+ }
+
+ #endregion
+
+ #region Shorthand
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, byte value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, ushort value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, uint value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void ReadRegister(Registers register, Span buffer) => BusComms.ReadRegister((byte)register, buffer);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private byte ReadRegister(Registers register) => BusComms.ReadRegister((byte)register);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ushort ReadRegisterAsUShort(Registers register) => BusComms.ReadRegisterAsUShort((byte)register, ByteOrder.BigEndian);
+ #endregion
+
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina228.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina228.cs
new file mode 100644
index 0000000000..d4594914be
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina228.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Text;
+using Meadow.Hardware;
+
+namespace Meadow.Foundation.Sensors.Power;
+
+///
+/// Represents a INA228 Precision Digital Current and Power Monitor
+///
+public class Ina228 : Ina2xx
+{
+ private readonly Units.Temperature _temperatureScale;
+ private Units.Voltage _shuntVoltageScale;
+ private Units.Energy _energyScale;
+ private double _chargeScale;
+ private ushort _calibration = 0x1000; // default on startup
+
+ ///
+ /// Create a new INA228 object
+ ///
+ /// The I2C bus
+ /// The I2C address
+ /// Resistor value (in Ohms) used for measuring current. Default matches Adafruit's Breakout board.
+ public Ina228(II2cBus i2cBus, byte address = (byte)Addresses.Default, double shuntResistance = 0.015)
+ : base(i2cBus, address)
+ {
+ _shuntResistor = new Units.Resistance(shuntResistance);
+ _voltageScale = new Units.Voltage(195.3125, Units.Voltage.UnitType.Microvolts);
+ _shuntVoltageScale = new Units.Voltage(312.5, Units.Voltage.UnitType.Nanovolts);
+ _temperatureScale = new Units.Temperature(7.8125e-6);
+ // TODO: set scaling/calibration dynamically
+ _currentScale = new Units.Current(_calibration / (13107.2 * 1e6 * _shuntResistor.Ohms));
+ _powerScale = new Units.Power(3.2 * _currentScale.Amps);
+ _energyScale = new Units.Energy(_powerScale.Watts * 16);
+ _chargeScale = _currentScale.Amps;
+
+ ReadDeviceInfo();
+ }
+
+ ///
+ public override void Configure()
+ {
+ Configure(false, false, 0);
+ ConfigureConversion(Mode.ContinuousAll, Averaging.Average_1,
+ voltageTime: ConversionTime.ConversionTime_1052us,
+ currentTime: ConversionTime.ConversionTime_1052us,
+ temperatureTime: ConversionTime.ConversionTime_1052us
+ );
+ }
+
+ ///
+ /// Sets Configuration
+ ///
+ public void Configure(bool shuntGain4x = false, bool temperatureCompensation = false, ushort initialConversionDelayMs = 0)
+ {
+ if (initialConversionDelayMs > 510)
+ throw new ArgumentOutOfRangeException(nameof(initialConversionDelayMs), initialConversionDelayMs, null);
+ ushort config = (ushort)((shuntGain4x ? 0x10 : 0x00) | (temperatureCompensation ? 0x20 : 0x00) | ((initialConversionDelayMs / 2) << 6));
+ WriteRegister(Registers.Config, config);
+ }
+
+ ///
+ /// Sets Configuration of ADC conversions
+ ///
+ /// selection of values and trigger mode
+ /// On-chip value averaging
+ /// Conversion time for Voltage measurements
+ /// Conversion time for Current measurements
+ /// Conversion time for Die Temperature measurements
+ public void ConfigureConversion(Mode mode = Mode.ContinuousAll,
+ Averaging averaging = Averaging.Average_1,
+ ConversionTime voltageTime = ConversionTime.ConversionTime_1052us,
+ ConversionTime currentTime = ConversionTime.ConversionTime_1052us,
+ ConversionTime temperatureTime = ConversionTime.ConversionTime_1052us
+ )
+ {
+ ushort adcConfig = (ushort)((ushort)mode << 12 | ((ushort)voltageTime << 9) | ((ushort)currentTime << 6) | ((ushort)temperatureTime << 3) | (ushort)averaging);
+ WriteRegister(Registers.ADCConfig, adcConfig);
+ }
+
+ ///
+ /// _currentScale and _powerScale are set along with _calibration using logic outlined in the datasheet for the INA228
+ ///
+ /// Maximum expected Current in the specific application.
+ /// true applies 4x gain to shunt measurements
+ public void SetCalibration(Units.Current maxExpectedCurrent, bool shuntGain4x = false)
+ {
+ // apply shuntGain4x to the config register (Read, set/clear bit, write)
+ ushort config = ReadRegisterAsUShort(Registers.Config);
+ config = (ushort)((config & ~0x10) | (shuntGain4x ? 0x10 : 0x00));
+ WriteRegister(Registers.Config, config);
+
+ // shuntGain4x also affects the calibration and other current derived values
+ _shuntVoltageScale = new Units.Voltage(shuntGain4x ? 78.125 : 312.5 , Units.Voltage.UnitType.Nanovolts);
+ var maxShuntVoltage = new Units.Voltage(shuntGain4x ? 40.96 : 163.84, Units.Voltage.UnitType.Millivolts);
+ var maxCurrent = maxShuntVoltage.Volts / _shuntResistor.Ohms;
+ var currentLSB = Math.Min(maxExpectedCurrent.Amps, maxCurrent) / (1 << 19);
+ _calibration = (ushort)(13107.2 * 1e6 * currentLSB * _shuntResistor.Ohms * (shuntGain4x ? 4 : 1));
+ WriteRegister(Registers.ShuntCal, _calibration);
+
+ _currentScale = new Units.Current(currentLSB);
+ _powerScale = new Units.Power(_currentScale.Amps * 3.2);
+ _energyScale = new Units.Energy(_powerScale.Watts * 16);
+ _chargeScale = _currentScale.Amps;
+ }
+
+ ///
+ internal override void ReadDeviceInfo()
+ {
+ Span buffer = stackalloc byte[2];
+ ReadRegister(Registers.ManufacturerID, buffer);
+ ManufacturerID = Encoding.ASCII.GetString(buffer);
+ var deviceInfo = ReadRegisterAsUShort(Registers.DeviceID);
+ DeviceID = (ushort)(deviceInfo >> 4);
+ DeviceRevision = (byte)(deviceInfo & 0xF);
+ }
+
+ #region Measurement
+ ///
+ public override Units.Current ReadCurrent()
+ {
+ Span buffer = stackalloc byte[3];
+ ReadRegister(Registers.Current, buffer);
+ var sign = buffer[0] >= 0x80;
+ int register = (sign ? 0x0FFF : 0x0000) << 20 | buffer[0] << 12 | buffer[1] << 4 | buffer[2] >> 4;
+ return new Units.Current(register * _currentScale.Amps);
+ }
+
+ ///
+ public override Units.Voltage ReadBusVoltage()
+ {
+ Span buffer = stackalloc byte[3];
+ ReadRegister(Registers.BusVoltage, buffer);
+ int register = buffer[0] << 12 | buffer[1] << 4 | buffer[2] >> 4;
+ return new Units.Voltage(register * _voltageScale.Volts);
+ }
+
+ ///
+ public override Units.Voltage ReadShuntVoltage()
+ {
+ Span buffer = stackalloc byte[3];
+ ReadRegister(Registers.ShuntVoltage, buffer);
+ var sign = buffer[0] >= 0x80;
+ int register = (sign ? 0x0FFF : 0x0000) << 20 | buffer[0] << 12 | buffer[1] << 4 | buffer[2] >> 4;
+ return new Units.Voltage(register * _shuntVoltageScale.Volts);
+ }
+
+ ///
+ public override Units.Power ReadPower()
+ {
+ Span buffer = stackalloc byte[3];
+ ReadRegister(Registers.Power, buffer);
+ uint register = (uint)(buffer[0] << 16 | buffer[1] << 8 | buffer[2]);
+ return new Units.Power(register * _powerScale.Watts);
+ }
+
+ ///
+ /// Read the Energy accumulator from the power monitor IC.
+ ///
+ /// representing the energy accumulator value.
+ public Units.Energy ReadEnergyAccumulator()
+ {
+ Span buffer = stackalloc byte[5];
+ ReadRegister(Registers.Energy, buffer);
+ long register = (long)buffer[0] << 32 | (long)(buffer[1] << 24 | buffer[2] << 16 | buffer[3] << 8 | buffer[4]);
+ return new Units.Energy(register * _energyScale.Joules);
+ }
+
+ ///
+ /// Read the Charge accumulator from the power monitor IC.
+ ///
+ /// representing the charge accumulator value.
+ public double ReadChargeAccumulator()
+ {
+ Span buffer = stackalloc byte[5];
+ ReadRegister(Registers.Charge, buffer);
+ long register = (long)buffer[0] << 32 | (long)(buffer[1] << 24 | buffer[2] << 16 | buffer[3] << 8 | buffer[4]);
+ return register * _chargeScale;
+ }
+
+ ///
+ /// Resets the Energy and Charge accumulators on the power monitor IC.
+ ///
+ public void ResetAccumulators()
+ {
+ // Read config, set bit, write config
+ ushort config = ReadRegisterAsUShort(Registers.Config);
+ config |= 0x4000;
+ WriteRegister(Registers.Config, config);
+ }
+
+ #endregion
+
+ #region Enumerations
+ ///
+ /// Enumeration of supported operation modes.
+ ///
+ public enum Mode
+ {
+ /// Power down (no conversions).
+ PowerDown = 0x0,
+ /// Measure Voltage once.
+ TriggeredVoltage = 0x1,
+ /// Measure Current once.
+ TriggeredCurrent = 0x2,
+ /// Measure Voltage and Current once.
+ TriggeredVoltageCurrent = 0x3,
+ /// Measure Die Temperature once.
+ TriggeredTemperature = 0x4,
+ /// Measure Voltage and Die Temperature once.
+ TriggeredTemperatureVoltage = 0x5,
+ /// Measure Current and Die Temperature once.
+ TriggeredTemperatureCurrent = 0x6,
+ /// Measure Voltage, Current, and Die Temperature once.
+ TriggeredAll = 0x7,
+ /// Power down (no conversions).
+ PowerDown2 = 0x8,
+ /// Measure Voltage continuously.
+ ContinuousVoltage = 0x9,
+ /// Measure Current continuously.
+ ContinuousCurrent = 0xA,
+ /// Measure Voltage and Current continuously.
+ ContinuousVoltageCurrent = 0xB,
+ /// Measure Die Temperature continuously.
+ ContinuousTemperature = 0xC,
+ /// Measure Voltage and Die Temperature continuously.
+ ContinuousTemperatureVoltage = 0xD,
+ /// Measure Current and Die Temperature continuously.
+ ContinuousTemperatureCurrent = 0xE,
+ /// Measure Voltage, Current, and Die Temperature continuously (default).
+ ContinuousAll = 0xF, // default at POR
+ }
+
+ ///
+ /// Enumeration of supported ADC conversion times.
+ ///
+ /// Note: This is used for Voltage, Current, and Die Temperature with different amounts of bit shifting
+ public enum ConversionTime
+ {
+ /// 50 µs ADC conversion.
+ ConversionTime_50us = 0x00,
+ /// 84 µs ADC conversion.
+ ConversionTime_84us = 0x01,
+ /// 150 µs ADC conversion.
+ ConversionTime_150us = 0x02,
+ /// 280 µs ADC conversion.
+ ConversionTime_280us = 0x03,
+ /// 540 µs ADC conversion.
+ ConversionTime_540us = 0x04,
+ /// 1.052 ms ADC conversion. (default)
+ ConversionTime_1052us = 0x05, // default at POR
+ /// 2.074 ms ADC conversion.
+ ConversionTime_2074us = 0x06,
+ /// 4.12 ms ADC conversion.
+ ConversionTime_4120us = 0x07,
+ }
+
+ ///
+ /// Enumeration of supported ADC Sample Averaging values.
+ ///
+ public enum Averaging
+ {
+ /// No Averaging. (default)
+ Average_1 = 0x00, // default at POR
+ /// 4x Sample Averaging.
+ Average_4 = 0x01,
+ /// 16x Sample Averaging.
+ Average_16 = 0x02,
+ /// 64x Sample Averaging.
+ Average_64 = 0x03,
+ /// 128x Sample Averaging.
+ Average_128 = 0x04,
+ /// 256x Sample Averaging.
+ Average_256 = 0x05,
+ /// 512x Sample Averaging.
+ Average_512 = 0x06,
+ /// 1024x Sample Averaging.
+ Average_1024 = 0x07,
+ }
+
+ ///
+ /// Enumeration of device memory registers.
+ ///
+ /// Note: Some registers are wider than 16 bits. >
+ private enum Registers : byte
+ {
+ Config = 0x00,
+ ADCConfig = 0x01,
+ ShuntCal = 0x02,
+ ShuntVoltage = 0x04, // 24 bits
+ BusVoltage = 0x05, // 24 bits
+ DieTemp = 0x06,
+ Current = 0x07, // 24 bits
+ Power = 0x08, // 24 bits
+ Energy = 0x09, // 40 bits
+ Charge = 0x0A, // 40 bits
+ DiagnosticAlert = 0x0B,
+ ManufacturerID = 0x3E,
+ DeviceID = 0x3F
+ }
+ #endregion
+
+ #region Shorthand
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, byte value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, ushort value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, uint value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void ReadRegister(Registers register, Span buffer) => BusComms.ReadRegister((byte)register, buffer);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private byte ReadRegister(Registers register) => BusComms.ReadRegister((byte)register);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ushort ReadRegisterAsUShort(Registers register) => BusComms.ReadRegisterAsUShort((byte)register, ByteOrder.BigEndian);
+ #endregion
+
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina260.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina260.cs
new file mode 100644
index 0000000000..dfecf01e28
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Drivers/Ina260.cs
@@ -0,0 +1,345 @@
+using Meadow.Hardware;
+using Meadow.Units;
+using System;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Meadow.Foundation.Sensors.Power;
+
+///
+/// Represents a INA260 Precision Digital Current and Power Monitor
+///
+public class Ina260 : Ina2xx
+{
+ ///
+ /// Create a new INA260 object
+ ///
+ /// The I2C bus
+ /// The I2C address
+ /// that can be used to monitor for Alert outputs, triggering
+ public Ina260(II2cBus i2cBus, byte address = (byte)Addresses.Default, IDigitalInterruptPort? alertPort = null)
+ : base(i2cBus, address)
+ {
+ _voltageScale = new Voltage(1.25, Units.Voltage.UnitType.Millivolts);
+ _currentScale = new Current(1.25, Units.Current.UnitType.Milliamps);
+ _powerScale = new Units.Power(10, Units.Power.UnitType.Milliwatts);
+ _shuntResistor = new Resistance(2, Resistance.UnitType.Milliohms); // Integrated in IC
+
+ _alertPort = alertPort;
+
+ if (_alertPort != null)
+ {
+ // TODO: configure _alertPort for open-drain active low signaling.
+ //_alertPort.Resistor = ;
+ _alertPort.Changed += AlertPortOnChanged;
+ }
+
+ ReadDeviceInfo();
+ }
+
+ ///
+ /// Create a new INA2xx object, using the address pin connections to calculate the correct I2C address.
+ ///
+ /// The I2C bus
+ /// specifying what A0 is connected to.
+ /// specifying what A1 is connected to.
+ public Ina260(II2cBus i2cBus, AddressConnection a0, AddressConnection a1)
+ : this(i2cBus, GetAddress(a0, a1))
+ { }
+
+ ///
+ public override void Configure()
+ {
+ Configure(); // Call the implementation's version.
+ }
+
+ ///
+ /// Sets Configuration of sensor
+ ///
+ /// selection of values and trigger mode
+ /// Conversion time for Current measurements
+ /// Conversion time for Voltage measurements
+ /// On-chip value averaging
+ public void Configure(ConversionTime currentConversionTime = ConversionTime.ConversionTime_1100us,
+ ConversionTime voltageConversionTime = ConversionTime.ConversionTime_1100us,
+ Averaging averaging = Averaging.Average_1,
+ Mode mode = Mode.ContinuousAll)
+ {
+ ushort config = (ushort)((ushort)averaging << 9 | ((ushort)voltageConversionTime << 6) | ((ushort)currentConversionTime << 3) | (ushort)mode);
+ BusComms.WriteRegister(ConfigRegister, config, ByteOrder.BigEndian);
+ }
+
+ ///
+ public override Units.Current ReadCurrent() => new Current((short)ReadRegisterAsUShort(Registers.Current) * _currentScale.Amps, Units.Current.UnitType.Amps);
+ ///
+ public override Units.Voltage ReadBusVoltage() => new Voltage(ReadRegisterAsUShort(Registers.BusVoltage) * _voltageScale.Volts, Units.Voltage.UnitType.Volts);
+ ///
+ /// Ina260 doesn't directly have a register for this, so we compute from known values.
+ public override Units.Voltage ReadShuntVoltage() => new((ReadCurrent().Amps * _shuntResistor.Ohms), Units.Voltage.UnitType.Volts);
+ ///
+ public override Units.Power ReadPower() => new Units.Power(ReadRegisterAsUShort(Registers.Power) * _powerScale.Watts, Units.Power.UnitType.Watts);
+
+ // TODO: Helpers for triggered measurement?
+
+ ///
+ internal override void ReadDeviceInfo()
+ {
+ Span buffer = stackalloc byte[2];
+ ReadRegister(Registers.ManufacturerID, buffer);
+ ManufacturerID = Encoding.ASCII.GetString(buffer);
+ var deviceInfo = ReadRegisterAsUShort(Registers.DeviceID);
+ DeviceID = (ushort)(deviceInfo >> 4);
+ DeviceRevision = (byte)(deviceInfo & 0xF);
+ }
+ private readonly IDigitalInterruptPort? _alertPort;
+
+ #region Alerts
+ ///
+ /// Raised when the Alert signal changes.
+ ///
+ public event EventHandler AlertChanged = default!;
+
+ private void AlertPortOnChanged(object sender, DigitalPortResult e)
+ {
+ OnAlert(sender, EventArgs.Empty);
+ }
+
+ private void OnAlert(object sender, EventArgs e)
+ {
+ AlertChanged?.Invoke(sender, e);
+ }
+
+ private const double minVoltage = 0;
+ private const double maxVoltage = 36;
+ private const double minCurrent = -15;
+ private const double maxCurrent = 15;
+ private const double minPower = 0;
+ private const double maxPower = 419.43;
+
+ ///
+ /// Configures the Voltage Limit Alert function.
+ ///
+ /// threshold for triggering the Alert.
+ /// State of the alert pin to use for the Alert Signal
+ /// Whether to latch the Alert until cleared.
+ /// Set true to trigger an alert when the measured voltage is above the .
+ /// Thrown if the is outside the limits of the power monitor IC.
+ public void AlertOnVoltageLimit(Units.Voltage threshold, bool activeHigh = false, bool latching = false, bool overLimit = false)
+ {
+ if (threshold.Volts is < minVoltage or > maxVoltage)
+ throw new ArgumentOutOfRangeException(nameof(threshold), threshold.Volts, null);
+
+ var maskValue = ((overLimit ? MaskEnable.AlertOverVoltageLimit : MaskEnable.AlertUnderVoltageLimit) |
+ (activeHigh ? MaskEnable.AlertPolarity : 0) |
+ (latching ? MaskEnable.LatchEnable : 0));
+ ushort limitValue = (ushort)(threshold.Volts / _voltageScale.Volts);
+
+ WriteRegister(Registers.MaskEnable, (ushort)maskValue);
+ WriteRegister(Registers.AlertLimit, limitValue);
+ }
+
+ ///
+ /// Configures the Current Limit Alert function.
+ ///
+ /// threshold for triggering the Alert.
+ /// State of the alert pin to use for the Alert Signal
+ /// Whether to latch the Alert until cleared.
+ /// Set true to trigger an alert when the measured Current is above the .
+ /// Thrown if the is outside the limits of the power monitor IC.
+ public void AlertOnCurrentLimit(Units.Current threshold, bool activeHigh = false, bool latching = false, bool overLimit = false)
+ {
+ if (threshold.Amps is < minCurrent or > maxCurrent)
+ throw new ArgumentOutOfRangeException(nameof(threshold), threshold.Amps, null);
+
+ var maskValue = ((overLimit ? MaskEnable.AlertOverCurrentLimit : MaskEnable.AlertUnderCurrentLimit) |
+ (activeHigh ? MaskEnable.AlertPolarity : 0) |
+ (latching ? MaskEnable.LatchEnable : 0));
+ // TODO: negative current is allowed.
+ ushort limitValue = (ushort)(threshold.Amps / _currentScale.Amps);
+
+ WriteRegister(Registers.MaskEnable, (ushort)maskValue);
+ WriteRegister(Registers.AlertLimit, limitValue);
+ }
+
+ ///
+ /// Configures the Power Limit Alert function.
+ ///
+ /// threshold for triggering the Alert.
+ /// State of the alert pin to use for the Alert Signal
+ /// Whether to latch the Alert until cleared.
+ /// Thrown if the is outside the limits of the power monitor IC.
+ public void AlertOnPowerLimit(Units.Power threshold, bool activeHigh = false, bool latching = false)
+ {
+ if (threshold.Watts is < minPower or > maxPower)
+ throw new ArgumentOutOfRangeException(nameof(threshold), threshold.Watts, null);
+ var maskValue = ((MaskEnable.AlertOverPowerLimit) |
+ (activeHigh ? MaskEnable.AlertPolarity : 0) |
+ (latching ? MaskEnable.LatchEnable : 0));
+ ushort limitValue = (ushort)(threshold.Watts / _powerScale.Watts);
+
+ WriteRegister(Registers.MaskEnable, (ushort)maskValue);
+ WriteRegister(Registers.AlertLimit, limitValue);
+ }
+
+ ///
+ /// Configures the Alert function to activate when all ADC conversions are complete.
+ ///
+ /// State of the alert pin to use for the Alert Signal
+ /// Whether to latch the Alert until cleared.
+ public void AlertOnConversionComplete(bool activeHigh = false, bool latching = false)
+ {
+ var maskValue = ((MaskEnable.AlertConversionReady) |
+ (activeHigh ? MaskEnable.AlertPolarity : 0) |
+ (latching ? MaskEnable.LatchEnable : 0));
+
+ WriteRegister(Registers.MaskEnable, (ushort)maskValue);
+ }
+ #endregion
+
+ ///
+ /// Reads all status bits.
+ ///
+ /// true if the Alert condition was the source of the Alert pin output.
+ /// true if all conversions and calculations are completed since last time this bit was read.
+ /// true indicates the internal arithmetic for Power may have exceeded the maximum of 419.43 W
+ public void GetStatus(out bool alert, out bool conversionReady, out bool overflow)
+ {
+ var maskValue = (MaskEnable)ReadRegisterAsUShort(Registers.MaskEnable);
+ alert = (maskValue & MaskEnable.AlertFunctionFlag) != 0;
+ conversionReady = (maskValue & MaskEnable.ConversionReady) != 0;
+ overflow = (maskValue & MaskEnable.MathOverFlow) != 0;
+ }
+
+ #region Enumerations
+ private enum Registers : byte
+ {
+ Config = 0x00,
+ Current = 0x01,
+ BusVoltage = 0x02,
+ Power = 0x03,
+ MaskEnable = 0x06,
+ AlertLimit = 0x07,
+ ManufacturerID = 0xFE,
+ DeviceID = 0xFF
+ }
+
+ ///
+ /// Enumeration of supported operation modes.
+ ///
+ public enum Mode
+ {
+ /// Power down (no conversions).
+ PowerDown = 0x0,
+ /// Measure Current once.
+ TriggeredCurrent = 0x1,
+ /// Measure Voltage once.
+ TriggeredVoltage = 0x2,
+ /// Measure Voltage and Current once.
+ TriggeredAll = 0x3,
+ /// Power down (no conversions).
+ PowerDown2 = 0x4,
+ /// Measure Current continuously.
+ ContinuousCurrent = 0x5,
+ /// Measure Voltage continuously.
+ ContinuousVoltage = 0x6,
+ /// Measure Voltage and Current continuously (default).
+ ContinuousAll = 0x7, // default at POR
+ }
+
+ ///
+ /// Enumeration of supported ADC conversion times.
+ ///
+ /// Note: This is used for Voltage and Current with different amounts of shifting
+ public enum ConversionTime
+ {
+ /// 140 µs ADC conversion.
+ ConversionTime_140us = 0x00,
+ /// 204 µs ADC conversion.
+ ConversionTime_204us = 0x01,
+ /// 332 µs ADC conversion.
+ ConversionTime_332us = 0x02,
+ /// 588 µs ADC conversion.
+ ConversionTime_588us = 0x03,
+ /// 1.1 ms ADC conversion. (default)
+ ConversionTime_1100us = 0x04, // default at POR
+ /// 2.116 ms ADC conversion.
+ ConversionTime_2116us = 0x05,
+ /// 4.156 ms ADC conversion.
+ ConversionTime_4156us = 0x06,
+ /// 8.244 ms ADC conversion.
+ ConversionTime_8244us = 0x07,
+ }
+
+ ///
+ /// Enumeration of supported ADC Sample Averaging values.
+ ///
+ public enum Averaging
+ {
+ /// No Averaging. (default)
+ Average_1 = 0x00, // default at POR
+ /// 4x Sample Averaging.
+ Average_4 = 0x01,
+ /// 16x Sample Averaging.
+ Average_16 = 0x02,
+ /// 64x Sample Averaging.
+ Average_64 = 0x03,
+ /// 128x Sample Averaging.
+ Average_128 = 0x04,
+ /// 256x Sample Averaging.
+ Average_256 = 0x05,
+ /// 512x Sample Averaging.
+ Average_512 = 0x06,
+ /// 1024x Sample Averaging.
+ Average_1024 = 0x07,
+ }
+
+ [Flags]
+ private enum MaskEnable : ushort
+ {
+ LatchEnable = 0x01,
+ AlertPolarity = 0x02,
+ MathOverFlow = 0x04,
+ ConversionReady = 0x08,
+ AlertFunctionFlag = 0x10,
+ AlertConversionReady = 0x400,
+ AlertOverPowerLimit = 0x800,
+ AlertUnderVoltageLimit = 0x1000,
+ AlertOverVoltageLimit = 0x2000,
+ AlertUnderCurrentLimit = 0x4000,
+ AlertOverCurrentLimit = 0x8000,
+ }
+ #endregion
+
+ #region Shorthand
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, byte value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, ushort value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void WriteRegister(Registers register, uint value) => BusComms.WriteRegister((byte)register, value, ByteOrder.BigEndian);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void ReadRegister(Registers register, Span buffer) => BusComms.ReadRegister((byte)register, buffer);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private byte ReadRegister(Registers register) => BusComms.ReadRegister((byte)register);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ushort ReadRegisterAsUShort(Registers register) => BusComms.ReadRegisterAsUShort((byte)register, ByteOrder.BigEndian);
+ #endregion
+
+ #region IDisposable extras
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_alertPort != null)
+ _alertPort.Changed -= AlertPortOnChanged;
+ base.Dispose(disposing);
+ }
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.Enums.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.Enums.cs
new file mode 100644
index 0000000000..09a776369d
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.Enums.cs
@@ -0,0 +1,66 @@
+namespace Meadow.Foundation.Sensors.Power;
+
+public abstract partial class Ina2xx
+{
+ ///
+ /// Valid I2C addresses for the sensor
+ ///
+ public enum Addresses : byte
+ {
+ /// Bus address 0x40, A1 -> GND, A0 -> GND
+ Address_0x40 = 0x40,
+ /// Bus address 0x41, A1 -> GND, A0 -> VS
+ Address_0x41 = 0x41,
+ /// Bus address 0x42, A1 -> GND, A0 -> SDA
+ Address_0x42 = 0x42,
+ /// Bus address 0x43, A1 -> GND, A0 -> SCL
+ Address_0x43 = 0x43,
+ /// Bus address 0x44, A1 -> VS, A0 -> GND
+ Address_0x44 = 0x44,
+ /// Bus address 0x45, A1 -> VS, A0 -> VS
+ Address_0x45 = 0x45,
+ /// Bus address 0x46, A1 -> VS, A0 -> SDA
+ Address_0x46 = 0x46,
+ /// Bus address 0x47, A1 -> VS, A0 -> SCL
+ Address_0x47 = 0x47,
+ /// Bus address 0x48, A1 -> SDA, A0 -> GND
+ Address_0x48 = 0x48,
+ /// Bus address 0x49, A1 -> SDA, A0 -> VS
+ Address_0x49 = 0x49,
+ /// Bus address 0x4A, A1 -> SDA, A0 -> SDA
+ Address_0x4A = 0x4A,
+ /// Bus address 0x4B, A1 -> SDA, A0 -> SCL
+ Address_0x4B = 0x4B,
+ /// Bus address 0x4C, A1 -> SCL, A0 -> GND
+ Address_0x4C = 0x4C,
+ /// Bus address 0x4D, A1 -> SCL, A0 -> VS
+ Address_0x4D = 0x4D,
+ /// Bus address 0x4E, A1 -> SCL, A0 -> SDA
+ Address_0x4E = 0x4E,
+ /// Bus address 0x4F, A1 -> SCL, A0 -> SCL
+ Address_0x4F = 0x4F,
+ /// Default bus address
+ Default = Address_0x40
+ }
+
+ ///
+ /// Potential connections for the address pins of the IC
+ ///
+ public enum AddressConnection : byte
+ {
+ /// Address pin is connected to GND
+ GND = 0,
+ /// Address pin is connected to VS
+ VS = 1,
+ /// Address pin is connected to SDA
+ SDA = 2,
+ /// Address pin is connected to SCL
+ SCL = 3
+ }
+
+ ///
+ /// Common Configuration Register (16 bits)
+ ///
+ protected const byte ConfigRegister = 0x00;
+ private const uint ResetIna2xx = 0x8000;
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.cs
new file mode 100644
index 0000000000..5a8a44d2f7
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Ina2xx.cs
@@ -0,0 +1,163 @@
+using Meadow.Hardware;
+using Meadow.Units;
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+namespace Meadow.Foundation.Sensors.Power;
+
+///
+/// Represents a INA2xx Series Precision Digital Current and Power Monitor
+///
+public abstract partial class Ina2xx
+ : ByteCommsSensorBase<(Units.Current? Current, Units.Voltage? Voltage, Units.Power? Power)>, II2cPeripheral
+{
+ ///
+ /// The default I2C address for the peripheral
+ ///
+ public byte DefaultI2cAddress => (byte)Addresses.Default;
+
+ ///
+ /// Default I2C Bus Speed to use for communication.
+ ///
+ public static I2cBusSpeed DefaultBusSpeed => I2cBusSpeed.Fast;
+
+ /// Value of the LSB of the voltage register.
+ internal Units.Voltage _voltageScale;
+ /// Value of the LSB of the current register.
+ internal Units.Current _currentScale;
+ /// Value of the LSB of the power register.
+ internal Units.Power _powerScale;
+ /// Value of the shunt resistor used for current measurements.
+ internal Units.Resistance _shuntResistor;
+
+ ///
+ /// Create a new INA2xx object.
+ ///
+ /// The I2C bus
+ /// The I2C address
+ protected Ina2xx(II2cBus i2cBus, byte address = (byte)Addresses.Default)
+ : base(i2cBus, address)
+ { }
+
+ ///
+ /// Create a new INA2xx object, using the address pin connections to calculate the correct I2C address.
+ ///
+ /// The I2C bus
+ /// specifying what A0 is connected to.
+ /// specifying what A1 is connected to.
+ protected Ina2xx(II2cBus i2cBus, AddressConnection a0 = AddressConnection.GND, AddressConnection a1 = AddressConnection.GND)
+ : this(i2cBus, GetAddress(a0, a1))
+ { }
+
+ ///
+ /// Lookup the correct address to use for the INA2xx based on the address pin connections.
+ ///
+ /// specifying what A0 is connected to.
+ /// specifying what A1 is connected to.
+ /// correct value to use, as a byte
+ public static byte GetAddress(AddressConnection a0, AddressConnection a1) => (byte)((byte)Addresses.Address_0x40 | (byte)a0 | ((byte)a1 << 2));
+
+ ///
+ /// Sets the sensor Configuration to default values. Each implementation should provide overloads for specific available options.
+ ///
+ public abstract void Configure();
+
+ ///
+ /// Resets Ina2xx to default settings.
+ ///
+ public void Reset()
+ {
+ BusComms.WriteRegister(ConfigRegister, ResetIna2xx, ByteOrder.BigEndian);
+ }
+
+ #region Sensor Values and Events
+ ///
+ /// The value of the current (in Amps) flowing through the shunt resistor from the last reading.
+ ///
+ public Units.Current? Current => Conditions.Current;
+
+ ///
+ /// Raised when the current value changes.
+ ///
+ public event EventHandler> CurrentUpdated = default!;
+
+ ///
+ /// The voltage from the last reading.
+ ///
+ public Units.Voltage? Voltage => Conditions.Voltage;
+
+ ///
+ /// Raised when the voltage value changes.
+ ///
+ public event EventHandler> VoltageUpdated = default!;
+
+ ///
+ /// The power from the last reading.
+ ///
+ public Units.Power? Power => Conditions.Power;
+
+ ///
+ /// Raised when the power value changes.
+ ///
+ public event EventHandler> PowerUpdated = default!;
+
+ ///
+ /// Raise events for subscribers and notify of value changes.
+ ///
+ /// The updated sensor data
+ protected override void RaiseEventsAndNotify(IChangeResult<(Units.Current? Current, Units.Voltage? Voltage, Units.Power? Power)> changeResult)
+ {
+ if (changeResult.New.Current is { } amps)
+ {
+ CurrentUpdated?.Invoke(this, new ChangeResult(amps, changeResult.Old?.Current));
+ }
+ if (changeResult.New.Voltage is { } volts)
+ {
+ VoltageUpdated?.Invoke(this, new ChangeResult(volts, changeResult.Old?.Voltage));
+ }
+ if (changeResult.New.Power is { } power)
+ {
+ PowerUpdated?.Invoke(this, new ChangeResult(power, changeResult.Old?.Power));
+ }
+ base.RaiseEventsAndNotify(changeResult);
+ }
+
+ ///
+ protected override Task<(Units.Current? Current, Units.Voltage? Voltage, Units.Power? Power)> ReadSensor()
+ {
+ (Units.Current? Current, Units.Voltage? Voltage, Units.Power? Power) conditions;
+
+ // TODO: What if Mode is not ContinuousAll, so some data might be stale?
+ conditions.Current = ReadCurrent();
+ conditions.Voltage = ReadBusVoltage();
+ conditions.Power = ReadPower();
+
+ return Task.FromResult(conditions);
+ }
+
+ /// Read the Current measurement from the power monitor IC.
+ public abstract Units.Current ReadCurrent();
+
+ /// Read the Voltage measurement from the power monitor IC.
+ public abstract Units.Voltage ReadBusVoltage();
+
+ /// Read the Voltage across the Shunt (sense) resistor from the power monitor IC.
+ public abstract Units.Voltage ReadShuntVoltage();
+
+ /// Read the Power measurement from the power monitor IC.
+ public abstract Units.Power ReadPower();
+ #endregion
+
+ /// The manufacturer identification, if supported. Otherwise returns an empty string.
+ public string ManufacturerID { get; internal set; } = string.Empty;
+
+ /// The device identification number, if supported. Otherwise returns 0.
+ public ushort DeviceID { get; internal set; }
+
+ /// The Device Revision code, if supported. Otherwise returns 0.
+ public byte DeviceRevision { get; internal set; }
+
+ /// Method for reading the , , and
+ internal abstract void ReadDeviceInfo();
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Readme.md b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Readme.md
similarity index 53%
rename from Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Readme.md
rename to Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Readme.md
index 24724d12d2..a24eb5e703 100644
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Readme.md
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Readme.md
@@ -2,19 +2,14 @@
**INA260 I2C current and power monitor**
-The **Ina260** library is included in the **Meadow.Foundation.Sensors.Power.Ina260** nuget package and is designed for the [Wilderness Labs](www.wildernesslabs.co) Meadow .NET IoT platform.
+The **Ina260** library is designed for the [Wilderness Labs](www.wildernesslabs.co) Meadow .NET IoT platform and is part of [Meadow.Foundation](https://developer.wildernesslabs.co/Meadow/Meadow.Foundation/).
-This driver is part of the [Meadow.Foundation](https://developer.wildernesslabs.co/Meadow/Meadow.Foundation/) peripherals library, an open-source repository of drivers and libraries that streamline and simplify adding hardware to your C# .NET Meadow IoT applications.
+The **Meadow.Foundation** peripherals library is an open-source repository of drivers and libraries that streamline and simplify adding hardware to your C# .NET Meadow IoT application.
For more information on developing for Meadow, visit [developer.wildernesslabs.co](http://developer.wildernesslabs.co/).
To view all Wilderness Labs open-source projects, including samples, visit [github.com/wildernesslabs](https://github.com/wildernesslabs/).
-## Installation
-
-You can install the library from within Visual studio using the the NuGet Package Manager or from the command line using the .NET CLI:
-
-`dotnet add package Meadow.Foundation.Sensors.Power.Ina260`
## Usage
```csharp
@@ -55,20 +50,3 @@ public override Task Run()
## Need Help?
If you have questions or need assistance, please join the Wilderness Labs [community on Slack](http://slackinvite.wildernesslabs.co/).
-## About Meadow
-
-Meadow is a complete, IoT platform with defense-grade security that runs full .NET applications on embeddable microcontrollers and Linux single-board computers including Raspberry Pi and NVIDIA Jetson.
-
-### Build
-
-Use the full .NET platform and tooling such as Visual Studio and plug-and-play hardware drivers to painlessly build IoT solutions.
-
-### Connect
-
-Utilize native support for WiFi, Ethernet, and Cellular connectivity to send sensor data to the Cloud and remotely control your peripherals.
-
-### Deploy
-
-Instantly deploy and manage your fleet in the cloud for OtA, health-monitoring, logs, command + control, and enterprise backend integrations.
-
-
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Sensors.Power.Ina260.csproj b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Sensors.Power.Ina2xx.csproj
similarity index 78%
rename from Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Sensors.Power.Ina260.csproj
rename to Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Sensors.Power.Ina2xx.csproj
index 34da475499..85cabc5a5b 100644
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Driver/Sensors.Power.Ina260.csproj
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Driver/Sensors.Power.Ina2xx.csproj
@@ -1,19 +1,19 @@
- 1.9.0
true
icon.png
Wilderness Labs, Inc
netstandard2.1
Library
- Ina260
+ Ina2xx
Wilderness Labs, Inc
http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/
- Meadow.Foundation.Sensors.Power.Ina260
+ Meadow.Foundation.Sensors.Power.Ina2xx
https://github.com/WildernessLabs/Meadow.Foundation
- Meadow.Foundation, Sensor, Power, Ina260
+ Meadow.Foundation, Sensor, Power, Current, Voltage, Ina260, Ina219, Ina228
+ 1.9.0
true
- INA260 I2C current and power monitor
+ INA2xx Series I2C current and power monitor
Readme.md
@@ -24,6 +24,8 @@
+
+
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/Ina219_Sample.csproj b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/Ina219_Sample.csproj
new file mode 100644
index 0000000000..895d8b02d4
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/Ina219_Sample.csproj
@@ -0,0 +1,23 @@
+
+
+ netstandard2.1
+ true
+ Library
+ App
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/MeadowApp.cs
new file mode 100644
index 0000000000..ba1ced9058
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/MeadowApp.cs
@@ -0,0 +1,46 @@
+using Meadow;
+using Meadow.Devices;
+using Meadow.Foundation.Sensors.Power;
+using System;
+using System.Threading.Tasks;
+using Meadow.Hardware;
+using Meadow.Units;
+
+namespace MeadowApp
+{
+ public class MeadowApp : App
+ {
+ //
+
+ Ina219 ina219;
+
+ public override Task Initialize()
+ {
+ Resolver.Log.Debug("Initialize...");
+
+ var bus = Device.CreateI2cBus(I2cBusSpeed.Fast);
+ ina219 = new Ina219(bus);
+ ina219.Configure(busVoltageRange: Ina219.BusVoltageRange.Range_32V,
+ maxExpectedCurrent: new Current(1.0),
+ adcMode: Ina219.ADCModes.ADCMode_4xAvg_2128us);
+ Resolver.SensorService.RegisterSensor(ina219);
+
+ Resolver.Log.Info($"--- INA219 Sample App ---");
+ ina219.Updated += (sender, result) =>
+ {
+ Resolver.Log.Info($"{result.New.Voltage:N3} V @ {result.New.Current:N3} A");
+ };
+
+ return Task.CompletedTask;
+ }
+
+ public override Task Run()
+ {
+ Resolver.Log.Debug("Run...");
+ ina219.StartUpdating(TimeSpan.FromSeconds(2));
+ return Task.CompletedTask;
+ }
+
+ //
+ }
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/app.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/app.config.yaml
new file mode 100644
index 0000000000..0bdfee3574
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/app.config.yaml
@@ -0,0 +1,14 @@
+# Uncomment additional options as needed.
+# To learn more about these config options, including custom application configuration settings, check out the Application Settings Configuration documentation.
+# http://developer.wildernesslabs.co/Meadow/Meadow.OS/Configuration/Application_Settings_Configuration/
+
+Lifecycle:
+ # Control whether Meadow will restart when an unhandled app exception occurs. Combine with Lifecycle > AppFailureRestartDelaySeconds to control restart timing.
+ RestartOnAppFailure: false
+ # # When app set to restart automatically on app failure,
+ #AppFailureRestartDelaySeconds: 15
+
+# # Adjust the level of logging detail.
+#Logging:
+# LogLevel:
+# Default: Trace
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/meadow.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/meadow.config.yaml
new file mode 100644
index 0000000000..f7ca12c910
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/meadow.config.yaml
@@ -0,0 +1,57 @@
+# Uncommented these options as needed.
+# To learn more about these config options, check out the OS & Device Configuration documentation.
+# http://developer.wildernesslabs.co/Meadow/Meadow.OS/Configuration/OS_Device_Configuration/
+
+#Device:
+ # Name of the device on the network.
+# Name: MeadowF7V2_ConfigSample
+
+ # Uncomment if SD card hardware present on this hardware (e.g., Core-Compute module with SD add-on)? Optional; default value is `false`.
+# SdStorageSupported: true
+
+# Control how the ESP coprocessor will start and operate.
+#Coprocessor:
+ # Should the ESP32 automatically attempt to connect to an access point at startup?
+ # If set to true, wifi.config.yaml credentials must be stored in the device.
+# AutomaticallyStartNetwork: true
+
+ # Should the ESP32 automatically reconnect to the configured access point?
+# AutomaticallyReconnect: true
+
+ # Maximum number of retry attempts for connections etc. before an error code is returned.
+# MaximumRetryCount: 7
+
+# Network configuration.
+#Network:
+# Interfaces:
+# - Name: Ethernet
+# UseDHCP: false
+# IPAddress: 192.168.1.60
+# NetMask: 255.255.255.0
+# Gateway: 192.168.1.254
+# - Name: WiFi
+# UseDHCP: true
+# IPAddress:
+# NetMask:
+# Gateway:
+
+ # Which interface should be used?
+# DefaultInterface: WiFi
+
+ # Automatically attempt to get the time at startup?
+# GetNetworkTimeAtStartup: true
+
+ # Time synchronization period in seconds.
+# NtpRefreshPeriodSeconds: 600
+
+ # Name of the NTP servers.
+# NtpServers:
+# - 0.pool.ntp.org
+# - 1.pool.ntp.org
+# - 2.pool.ntp.org
+# - 3.pool.ntp.org
+
+ # IP addresses of the DNS servers.
+# DnsServers:
+# - 1.1.1.1
+# - 8.8.8.8
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/wifi.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/wifi.config.yaml
new file mode 100644
index 0000000000..6c48cc4e85
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina219_Sample/wifi.config.yaml
@@ -0,0 +1,8 @@
+# Uncomment to set the default Wi-Fi credentials. (This file will be processed into secure storage on the ESP32 and then deleted from the device.)
+# To learn more about these config options, including custom application configuration settings, check out the Application Settings Configuration documentation.
+# http://developer.wildernesslabs.co/Meadow/Meadow.OS/Configuration/WiFi_Configuration/
+
+# # To enable automatically connecting to a default network, make sure to enable the Coprocessor > AutomaticallyStartNetwork value in meadow.config.yaml.
+#Credentials:
+# Ssid: YourSSID
+# Password: SSIDPassword
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/Ina228_Sample.csproj b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/Ina228_Sample.csproj
new file mode 100644
index 0000000000..cb38b84430
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/Ina228_Sample.csproj
@@ -0,0 +1,20 @@
+
+
+ netstandard2.1
+ true
+ Library
+ App
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/MeadowApp.cs
new file mode 100644
index 0000000000..e1f48ae7fb
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/MeadowApp.cs
@@ -0,0 +1,49 @@
+using Meadow;
+using Meadow.Devices;
+using Meadow.Foundation.Sensors.Power;
+using System;
+using System.Threading.Tasks;
+using Meadow.Hardware;
+using Meadow.Units;
+
+namespace MeadowApp
+{
+ public class MeadowApp : App
+ {
+ //
+
+ Ina228 ina228;
+
+ public override Task Initialize()
+ {
+ Resolver.Log.Debug("Initialize...");
+
+ var bus = Device.CreateI2cBus(I2cBusSpeed.Fast);
+ ina228 = new Ina228(bus);
+ ina228.ConfigureConversion(averaging:Ina228.Averaging.Average_4);
+ ina228.SetCalibration(new Current(10.0, Current.UnitType.Amps), false);
+ Resolver.SensorService.RegisterSensor(ina228);
+
+ Resolver.Log.Info($"--- INA228 Sample App ---");
+ Resolver.Log.Info($"Manufacturer: {ina228.ManufacturerID}");
+ Resolver.Log.Info($"DeviceID: 0x{ina228.DeviceID:X3}");
+ Resolver.Log.Info($"Revision: 0x{ina228.DeviceRevision:X2}");
+ ina228.Updated += (sender, result) =>
+ {
+ if (result.New is { Current: { }, Voltage: { } })
+ Resolver.Log.Info($"{result.New.Voltage.Value.Millivolts:N3} mV @ {result.New.Current.Value.Milliamps:N3} mA");
+ };
+
+ return Task.CompletedTask;
+ }
+
+ public override Task Run()
+ {
+ Resolver.Log.Debug("Run...");
+ ina228.StartUpdating(TimeSpan.FromSeconds(2));
+ return Task.CompletedTask;
+ }
+
+ //
+ }
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/meadow.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/meadow.config.yaml
similarity index 100%
rename from Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/meadow.config.yaml
rename to Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/meadow.config.yaml
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/wifi.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/wifi.config.yaml
new file mode 100644
index 0000000000..6c48cc4e85
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina228_Sample/wifi.config.yaml
@@ -0,0 +1,8 @@
+# Uncomment to set the default Wi-Fi credentials. (This file will be processed into secure storage on the ESP32 and then deleted from the device.)
+# To learn more about these config options, including custom application configuration settings, check out the Application Settings Configuration documentation.
+# http://developer.wildernesslabs.co/Meadow/Meadow.OS/Configuration/WiFi_Configuration/
+
+# # To enable automatically connecting to a default network, make sure to enable the Coprocessor > AutomaticallyStartNetwork value in meadow.config.yaml.
+#Credentials:
+# Ssid: YourSSID
+# Password: SSIDPassword
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/Ina260_Sample.csproj b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/Ina260_Sample.csproj
similarity index 92%
rename from Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/Ina260_Sample.csproj
rename to Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/Ina260_Sample.csproj
index 3933dab743..357e35adfa 100644
--- a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina260/Samples/Ina260_Sample/Ina260_Sample.csproj
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/Ina260_Sample.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/MeadowApp.cs
new file mode 100644
index 0000000000..5b34b452cc
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/MeadowApp.cs
@@ -0,0 +1,46 @@
+using Meadow;
+using Meadow.Devices;
+using Meadow.Foundation.Sensors.Power;
+using System;
+using System.Threading.Tasks;
+using Meadow.Hardware;
+
+namespace MeadowApp
+{
+ public class MeadowApp : App
+ {
+ //
+
+ Ina260 ina260;
+
+ public override Task Initialize()
+ {
+ Resolver.Log.Debug("Initialize...");
+
+ var bus = Device.CreateI2cBus(I2cBusSpeed.Fast);
+ ina260 = new Ina260(bus);
+ ina260.Configure(Ina260.ConversionTime.ConversionTime_8244us, Ina260.ConversionTime.ConversionTime_8244us, Ina260.Averaging.Average_4);
+ //Resolver.SensorService.RegisterSensor(ina260);
+
+ Resolver.Log.Info($"--- INA260 Sample App ---");
+ Resolver.Log.Info($"Manufacturer: {ina260.ManufacturerID}");
+ Resolver.Log.Info($"DeviceID: 0x{ina260.DeviceID:X3}");
+ Resolver.Log.Info($"Revision: 0x{ina260.DeviceRevision:X2}");
+ ina260.Updated += (sender, result) =>
+ {
+ Resolver.Log.Info($"{result.New.Voltage:N3} V @ {result.New.Current:N3} A");
+ };
+
+ return Task.CompletedTask;
+ }
+
+ public override Task Run()
+ {
+ Resolver.Log.Debug("Run...");
+ ina260.StartUpdating(TimeSpan.FromSeconds(2));
+ return Task.CompletedTask;
+ }
+
+ //
+ }
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/meadow.config.yaml b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/meadow.config.yaml
new file mode 100644
index 0000000000..32363cb69c
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Sensors.Power.Ina2xx/Samples/Ina260_Sample/meadow.config.yaml
@@ -0,0 +1,2 @@
+MonoControl:
+ Options: --jit
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.sln b/Source/Meadow.Foundation.sln
index 769e5fe490..277bbdc212 100644
--- a/Source/Meadow.Foundation.sln
+++ b/Source/Meadow.Foundation.sln
@@ -409,14 +409,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Motion.Hcsens0040",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hcsens0040_Sample", "Meadow.Foundation.Peripherals\Sensors.Motion.Hcsens0040\Samples\Hcsens0040_Sample\Hcsens0040_Sample.csproj", "{DA828BA9-E57F-4579-B6B0-55910247408F}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ina260", "Ina260", "{18BD90D6-3D88-44A4-A366-134D12F3F823}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ina2xx", "Ina2xx", "{18BD90D6-3D88-44A4-A366-134D12F3F823}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Power.Ina260", "Meadow.Foundation.Peripherals\Sensors.Power.Ina260\Driver\Sensors.Power.Ina260.csproj", "{9B4196EC-9485-43FB-B579-C2E50D0E9A3F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ina260_Sample", "Meadow.Foundation.Peripherals\Sensors.Power.Ina260\Samples\Ina260_Sample\Ina260_Sample.csproj", "{22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tsl2591", "Tsl2591", "{C453850E-43AD-4AE5-82F1-76E0168E7260}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{882011AD-05A3-43F9-9B64-2032982948D6}"
@@ -1479,6 +1475,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroJson_Sample", "Meadow.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroJson_ArrayList_Sample", "Meadow.Foundation.Libraries_and_Frameworks\Serialization.MicroJson\Samples\MicroJson_ArrayList_Sample\MicroJson_ArrayList_Sample.csproj", "{9F5DD1C6-4A3E-4170-BE18-3FAC3A1E0D48}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Power.Ina2xx", "Meadow.Foundation.Peripherals\Sensors.Power.Ina2xx\Driver\Sensors.Power.Ina2xx.csproj", "{E04713B8-12B6-484A-AE20-4D808BBDA38B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ina219_Sample", "Meadow.Foundation.Peripherals\Sensors.Power.Ina2xx\Samples\Ina219_Sample\Ina219_Sample.csproj", "{CCA3369C-469F-42C6-9BB3-AF124A8A2428}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ina228_Sample", "Meadow.Foundation.Peripherals\Sensors.Power.Ina2xx\Samples\Ina228_Sample\Ina228_Sample.csproj", "{357E421A-0E86-4CB1-8210-B115951A6BE2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ina260_Sample", "Meadow.Foundation.Peripherals\Sensors.Power.Ina2xx\Samples\Ina260_Sample\Ina260_Sample.csproj", "{E06A278F-282F-4FB4-9F4F-902833B0E6E2}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroJson_Complex_Sample", "Meadow.Foundation.Libraries_and_Frameworks\Serialization.MicroJson\Samples\MicroJson_Complex_Sample\MicroJson_Complex_Sample.csproj", "{6FD1D41A-1A80-4E04-B7FF-5EDCE6A526AC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{4B7EFCFD-6454-45CF-9C95-C1BF94B17E27}"
@@ -1933,18 +1937,6 @@ Global
{DA828BA9-E57F-4579-B6B0-55910247408F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA828BA9-E57F-4579-B6B0-55910247408F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA828BA9-E57F-4579-B6B0-55910247408F}.Release|Any CPU.Build.0 = Release|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Release|Any CPU.Build.0 = Release|Any CPU
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Release|Any CPU.Build.0 = Release|Any CPU
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A}.Release|Any CPU.Deploy.0 = Release|Any CPU
{267DBD91-4ABE-4B34-A788-32EC7B34B4FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{267DBD91-4ABE-4B34-A788-32EC7B34B4FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{267DBD91-4ABE-4B34-A788-32EC7B34B4FE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
@@ -3575,6 +3567,30 @@ Global
{9F5DD1C6-4A3E-4170-BE18-3FAC3A1E0D48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F5DD1C6-4A3E-4170-BE18-3FAC3A1E0D48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F5DD1C6-4A3E-4170-BE18-3FAC3A1E0D48}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {357E421A-0E86-4CB1-8210-B115951A6BE2}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2}.Release|Any CPU.Deploy.0 = Release|Any CPU
{6FD1D41A-1A80-4E04-B7FF-5EDCE6A526AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FD1D41A-1A80-4E04-B7FF-5EDCE6A526AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD1D41A-1A80-4E04-B7FF-5EDCE6A526AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -3795,8 +3811,6 @@ Global
{DA828BA9-E57F-4579-B6B0-55910247408F} = {D78EB96C-0105-4D6A-A34D-BD271912617E}
{18BD90D6-3D88-44A4-A366-134D12F3F823} = {C95CDA6C-3968-467E-80ED-5A963BE96215}
{9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F} = {18BD90D6-3D88-44A4-A366-134D12F3F823}
- {9B4196EC-9485-43FB-B579-C2E50D0E9A3F} = {18BD90D6-3D88-44A4-A366-134D12F3F823}
- {22FC6812-1336-47EC-9F9B-BF2FFC9CE67A} = {9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F}
{C453850E-43AD-4AE5-82F1-76E0168E7260} = {C12ECFF4-2767-4764-8B98-85A239B9E756}
{882011AD-05A3-43F9-9B64-2032982948D6} = {C453850E-43AD-4AE5-82F1-76E0168E7260}
{267DBD91-4ABE-4B34-A788-32EC7B34B4FE} = {C453850E-43AD-4AE5-82F1-76E0168E7260}
@@ -4327,6 +4341,10 @@ Global
{CA32D6C5-DD19-4787-8EE1-B92415FEF903} = {B9C2605C-AC98-4BF1-8E3F-8F0F23A694C9}
{5F905795-94F9-43F3-A3F8-AD667C55A730} = {CA32D6C5-DD19-4787-8EE1-B92415FEF903}
{9F5DD1C6-4A3E-4170-BE18-3FAC3A1E0D48} = {CA32D6C5-DD19-4787-8EE1-B92415FEF903}
+ {E04713B8-12B6-484A-AE20-4D808BBDA38B} = {18BD90D6-3D88-44A4-A366-134D12F3F823}
+ {CCA3369C-469F-42C6-9BB3-AF124A8A2428} = {9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F}
+ {357E421A-0E86-4CB1-8210-B115951A6BE2} = {9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F}
+ {E06A278F-282F-4FB4-9F4F-902833B0E6E2} = {9E14DFF3-2BD0-4C3D-91A0-DD3063D5245F}
{6FD1D41A-1A80-4E04-B7FF-5EDCE6A526AC} = {CA32D6C5-DD19-4787-8EE1-B92415FEF903}
{4B7EFCFD-6454-45CF-9C95-C1BF94B17E27} = {B9C2605C-AC98-4BF1-8E3F-8F0F23A694C9}
{BB121196-8958-466C-B899-025C12DC2B76} = {4B7EFCFD-6454-45CF-9C95-C1BF94B17E27}