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}