diff --git a/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoderWithButton_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoderWithButton_Sample/MeadowApp.cs
index 7b610746e7..73e16dd073 100644
--- a/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoderWithButton_Sample/MeadowApp.cs
+++ b/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoderWithButton_Sample/MeadowApp.cs
@@ -1,6 +1,7 @@
using Meadow;
using Meadow.Devices;
using Meadow.Foundation.Sensors.Rotary;
+using Meadow.Peripherals;
using Meadow.Peripherals.Sensors.Rotary;
using System.Threading.Tasks;
diff --git a/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoder_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoder_Sample/MeadowApp.cs
index c22fe4aba7..2d414d144d 100644
--- a/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoder_Sample/MeadowApp.cs
+++ b/Source/Meadow.Foundation.Core.Samples/Sensors.Rotary.RotaryEncoder_Sample/MeadowApp.cs
@@ -1,6 +1,7 @@
using Meadow;
using Meadow.Devices;
using Meadow.Foundation.Sensors.Rotary;
+using Meadow.Peripherals;
using Meadow.Peripherals.Sensors.Rotary;
using System.Threading.Tasks;
@@ -37,7 +38,7 @@ public override Task Initialize()
return Task.CompletedTask;
}
- void RotaryEncoder_Rotated(object sender, RotaryChangeResult e)
+ private void RotaryEncoder_Rotated(object sender, RotaryChangeResult e)
{
switch (e.New)
{
diff --git a/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoder.cs b/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoder.cs
index ecc8c5b9fa..08daf3a9cc 100644
--- a/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoder.cs
+++ b/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoder.cs
@@ -1,142 +1,142 @@
using Meadow.Hardware;
+using Meadow.Peripherals;
using Meadow.Peripherals.Sensors.Rotary;
using System;
-namespace Meadow.Foundation.Sensors.Rotary
+namespace Meadow.Foundation.Sensors.Rotary;
+
+///
+/// Digital rotary encoder that uses two-bit Gray Code to encode rotation.
+///
+public class RotaryEncoder : IRotaryEncoder
{
///
- /// Digital rotary encoder that uses two-bit Gray Code to encode rotation.
+ /// Raised when the rotary encoder is rotated and returns a RotaryTurnedEventArgs object which describes the direction of rotation.
///
- public class RotaryEncoder : IRotaryEncoder
- {
- ///
- /// Raised when the rotary encoder is rotated and returns a RotaryTurnedEventArgs object which describes the direction of rotation.
- ///
- public event EventHandler Rotated = delegate { };
-
- ///
- /// Returns the pin connected to the A-phase output on the rotary encoder.
- ///
- protected IDigitalInterruptPort APhasePort { get; }
-
- ///
- /// Returns the pin connected to the B-phase output on the rotary encoder.
- ///
- protected IDigitalInterruptPort BPhasePort { get; }
-
- ///
- /// Gets the last direction of rotation
- ///
- public RotationDirection? LastDirectionOfRotation { get; protected set; }
-
- ///
- /// Contains the previous offset used to find direction information
- ///
- private int dynamicOffset = 0;
-
- ///
- /// The rotary encoder has 2 inputs, called A and B. Because of its design
- /// either A or B changes but not both on each notification when the encoder
- /// is rotated. Because of this the direction to be determined. If A goes
- /// High before B then we are rotating one direction if B goes high before A
- /// we are rotating the other direction. For each change we must consider the
- /// previous state of A and B and the current state of A and B. This can be
- /// represented as 4-bit number.
- /// 3 2 1 0
- /// |old|new|
- /// |A|B|A|B|
- ///
- /// Bits 0 and 1 represent the current state of A and B while bits 2 and 3
- /// represent previous states of A and B. This 4-bit number yields 16 possible
- /// combination, however, there are combination that for which no change is
- /// represent. For example, the if bits 0-3 are all 0, this would mean that A
- /// was Low and is Low, and that B was Low and is Low (nothing changed.)
- ///
- private readonly int[] RotEncLookup = { 0, -1, 1, 0,
- 1, 0, 0, -1,
- -1, 0, 0, 1,
- 0, 1, -1, 0 };
-
- ///
- /// Instantiate a new RotaryEncoder on the specified pins
- ///
- /// Pin A
- /// Pin B
- /// Do the encode pins use a common ground (true) or common positive (false)
- public RotaryEncoder(IPin aPhasePin, IPin bPhasePin, bool isCommonGround = false) :
- this(aPhasePin.CreateDigitalInterruptPort(InterruptMode.EdgeBoth, isCommonGround ? ResistorMode.InternalPullUp : ResistorMode.InternalPullDown, TimeSpan.Zero, TimeSpan.FromMilliseconds(0.1)),
- bPhasePin.CreateDigitalInterruptPort(InterruptMode.EdgeBoth, isCommonGround ? ResistorMode.InternalPullUp : ResistorMode.InternalPullDown, TimeSpan.Zero, TimeSpan.FromMilliseconds(0.1)))
- { }
-
- ///
- /// Instantiate a new RotaryEncoder on the specified ports
- ///
- ///
- ///
- public RotaryEncoder(IDigitalInterruptPort aPhasePort, IDigitalInterruptPort bPhasePort)
- {
- APhasePort = aPhasePort;
- BPhasePort = bPhasePort;
+ public event EventHandler Rotated = delegate { };
- APhasePort.Changed += PhaseAPinChanged;
- BPhasePort.Changed += PhaseBPinChanged;
- }
+ ///
+ /// Returns the pin connected to the A-phase output on the rotary encoder.
+ ///
+ protected IDigitalInterruptPort APhasePort { get; }
- private void PhaseAPinChanged(object s, DigitalPortResult result)
- {
- // Clear bit A bit
- int new2LsBits = dynamicOffset & 0x02; // Save bit 2 (B)
+ ///
+ /// Returns the pin connected to the B-phase output on the rotary encoder.
+ ///
+ protected IDigitalInterruptPort BPhasePort { get; }
- if (result.New.State)
- {
- new2LsBits |= 0x01; // Set bit 1 (A)
- }
+ ///
+ /// Gets the last direction of rotation
+ ///
+ public RotationDirection? LastDirectionOfRotation { get; protected set; }
- FindDirection(new2LsBits);
- }
+ ///
+ /// Contains the previous offset used to find direction information
+ ///
+ private int dynamicOffset = 0;
- private void PhaseBPinChanged(object s, DigitalPortResult result)
- {
- // Clear bit B bit
- int new2LsBits = dynamicOffset & 0x01; // Save bit 1 (A)
+ ///
+ /// The rotary encoder has 2 inputs, called A and B. Because of its design
+ /// either A or B changes but not both on each notification when the encoder
+ /// is rotated. Because of this the direction to be determined. If A goes
+ /// High before B then we are rotating one direction if B goes high before A
+ /// we are rotating the other direction. For each change we must consider the
+ /// previous state of A and B and the current state of A and B. This can be
+ /// represented as 4-bit number.
+ /// 3 2 1 0
+ /// |old|new|
+ /// |A|B|A|B|
+ ///
+ /// Bits 0 and 1 represent the current state of A and B while bits 2 and 3
+ /// represent previous states of A and B. This 4-bit number yields 16 possible
+ /// combination, however, there are combination that for which no change is
+ /// represent. For example, the if bits 0-3 are all 0, this would mean that A
+ /// was Low and is Low, and that B was Low and is Low (nothing changed.)
+ ///
+ private readonly int[] RotEncLookup = { 0, -1, 1, 0,
+ 1, 0, 0, -1,
+ -1, 0, 0, 1,
+ 0, 1, -1, 0 };
- if (result.New.State)
- {
- new2LsBits |= 0x02; // Set bit 2 (B)
- }
+ ///
+ /// Instantiate a new RotaryEncoder on the specified pins
+ ///
+ /// Pin A
+ /// Pin B
+ /// Do the encode pins use a common ground (true) or common positive (false)
+ public RotaryEncoder(IPin aPhasePin, IPin bPhasePin, bool isCommonGround = false) :
+ this(aPhasePin.CreateDigitalInterruptPort(InterruptMode.EdgeBoth, isCommonGround ? ResistorMode.InternalPullUp : ResistorMode.InternalPullDown, TimeSpan.Zero, TimeSpan.FromMilliseconds(0.1)),
+ bPhasePin.CreateDigitalInterruptPort(InterruptMode.EdgeBoth, isCommonGround ? ResistorMode.InternalPullUp : ResistorMode.InternalPullDown, TimeSpan.Zero, TimeSpan.FromMilliseconds(0.1)))
+ { }
- FindDirection(new2LsBits);
+ ///
+ /// Instantiate a new RotaryEncoder on the specified ports
+ ///
+ ///
+ ///
+ public RotaryEncoder(IDigitalInterruptPort aPhasePort, IDigitalInterruptPort bPhasePort)
+ {
+ APhasePort = aPhasePort;
+ BPhasePort = bPhasePort;
+
+ APhasePort.Changed += PhaseAPinChanged;
+ BPhasePort.Changed += PhaseBPinChanged;
+ }
+
+ private void PhaseAPinChanged(object s, DigitalPortResult result)
+ {
+ // Clear bit A bit
+ int new2LsBits = dynamicOffset & 0x02; // Save bit 2 (B)
+
+ if (result.New.State)
+ {
+ new2LsBits |= 0x01; // Set bit 1 (A)
}
- private void FindDirection(int new2LsBits)
+ FindDirection(new2LsBits);
+ }
+
+ private void PhaseBPinChanged(object s, DigitalPortResult result)
+ {
+ // Clear bit B bit
+ int new2LsBits = dynamicOffset & 0x01; // Save bit 1 (A)
+
+ if (result.New.State)
{
- dynamicOffset <<= 2; // Move previous A & B to bits 2 & 3
- dynamicOffset |= new2LsBits; // Set the current A & B states in bits 0 & 1
- dynamicOffset &= 0x0000000f; // Save only lowest 4 bits
-
- int direction = RotEncLookup[dynamicOffset];
-
- // save state
- var oldRotation = LastDirectionOfRotation;
-
- switch (direction)
- {
- case 0: // no valid change
- return;
- case 1: // clockwise
- LastDirectionOfRotation = RotationDirection.Clockwise;
- RaiseRotatedAndNotify(new RotaryChangeResult(RotationDirection.Clockwise, oldRotation));
- break;
- default: // counter clockwise
- LastDirectionOfRotation = RotationDirection.CounterClockwise;
- RaiseRotatedAndNotify(new RotaryChangeResult(RotationDirection.CounterClockwise, oldRotation));
- break;
- }
+ new2LsBits |= 0x02; // Set bit 2 (B)
}
- private void RaiseRotatedAndNotify(RotaryChangeResult result)
+ FindDirection(new2LsBits);
+ }
+
+ private void FindDirection(int new2LsBits)
+ {
+ dynamicOffset <<= 2; // Move previous A & B to bits 2 & 3
+ dynamicOffset |= new2LsBits; // Set the current A & B states in bits 0 & 1
+ dynamicOffset &= 0x0000000f; // Save only lowest 4 bits
+
+ int direction = RotEncLookup[dynamicOffset];
+
+ // save state
+ var oldRotation = LastDirectionOfRotation;
+
+ switch (direction)
{
- Rotated?.Invoke(this, result);
+ case 0: // no valid change
+ return;
+ case 1: // clockwise
+ LastDirectionOfRotation = RotationDirection.Clockwise;
+ RaiseRotatedAndNotify(new RotaryChangeResult(RotationDirection.Clockwise, oldRotation));
+ break;
+ default: // counter clockwise
+ LastDirectionOfRotation = RotationDirection.CounterClockwise;
+ RaiseRotatedAndNotify(new RotaryChangeResult(RotationDirection.CounterClockwise, oldRotation));
+ break;
}
}
+
+ private void RaiseRotatedAndNotify(RotaryChangeResult result)
+ {
+ Rotated?.Invoke(this, result);
+ }
}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoderWithButton.cs b/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoderWithButton.cs
index ab289eeafe..2cd19c666d 100644
--- a/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoderWithButton.cs
+++ b/Source/Meadow.Foundation.Core/Sensors/Rotary/RotaryEncoderWithButton.cs
@@ -4,108 +4,107 @@
using System;
using System.Threading.Tasks;
-namespace Meadow.Foundation.Sensors.Rotary
+namespace Meadow.Foundation.Sensors.Rotary;
+
+///
+/// Digital rotary encoder that uses two-bit Gray Code to encode rotation and has an integrated push button
+///
+public class RotaryEncoderWithButton : RotaryEncoder, IRotaryEncoderWithButton
{
///
- /// Digital rotary encoder that uses two-bit Gray Code to encode rotation and has an integrated push button
+ /// Returns the PushButton that represents the integrated button
///
- public class RotaryEncoderWithButton : RotaryEncoder, IRotaryEncoderWithButton
- {
- ///
- /// Returns the PushButton that represents the integrated button
- ///
- public PushButton Button { get; private set; }
-
- ///
- /// Returns the push button's state
- ///
- public bool State => Button.State;
+ public PushButton Button { get; private set; }
- ///
- /// Raised when the button circuit is re-opened after it has been closed
- ///
- public event EventHandler Clicked = delegate { };
+ ///
+ /// Returns the push button's state
+ ///
+ public bool State => Button.State;
- ///
- /// Raised when a press ends
- ///
- public event EventHandler PressEnded = delegate { };
+ ///
+ /// Raised when the button circuit is re-opened after it has been closed
+ ///
+ public event EventHandler Clicked = delegate { };
- ///
- /// Raised when a press starts
- ///
- public event EventHandler PressStarted = delegate { };
+ ///
+ /// Raised when a press ends
+ ///
+ public event EventHandler PressEnded = delegate { };
- ///
- /// Raised when the button circuit is pressed for LongPressDuration
- ///
- public event EventHandler LongClicked = delegate { };
+ ///
+ /// Raised when a press starts
+ ///
+ public event EventHandler PressStarted = delegate { };
- ///
- /// The minimum duration for a long press
- ///
- public TimeSpan LongClickedThreshold
- {
- get => Button.LongClickedThreshold;
- set => Button.LongClickedThreshold = value;
- }
+ ///
+ /// Raised when the button circuit is pressed for LongPressDuration
+ ///
+ public event EventHandler LongClicked = delegate { };
- ///
- /// Instantiates a new RotaryEncoder on the specified pins that has an integrated button.
- ///
- ///
- ///
- ///
- ///
- public RotaryEncoderWithButton(IPin aPhasePin, IPin bPhasePin, IPin buttonPin, ResistorMode buttonResistorMode = ResistorMode.InternalPullDown)
- : base(aPhasePin, bPhasePin)
- {
- Button = new PushButton(buttonPin, buttonResistorMode);
+ ///
+ /// The minimum duration for a long press
+ ///
+ public TimeSpan LongClickedThreshold
+ {
+ get => Button.LongClickedThreshold;
+ set => Button.LongClickedThreshold = value;
+ }
- Button.Clicked += ButtonClicked;
- Button.PressEnded += ButtonPressEnded;
- Button.PressStarted += ButtonPressStarted;
- Button.LongClicked += ButtonLongClicked;
- }
+ ///
+ /// Instantiates a new RotaryEncoder on the specified pins that has an integrated button.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public RotaryEncoderWithButton(IPin aPhasePin, IPin bPhasePin, IPin buttonPin, ResistorMode buttonResistorMode = ResistorMode.InternalPullDown)
+ : base(aPhasePin, bPhasePin)
+ {
+ Button = new PushButton(buttonPin, buttonResistorMode);
- private void ButtonLongClicked(object sender, EventArgs e)
- {
- LongClicked(this, e);
- }
+ Button.Clicked += ButtonClicked;
+ Button.PressEnded += ButtonPressEnded;
+ Button.PressStarted += ButtonPressStarted;
+ Button.LongClicked += ButtonLongClicked;
+ }
- ///
- /// Method when button is clicked (down then up)
- ///
- /// sender object
- /// event arguments
- protected void ButtonClicked(object sender, EventArgs e)
- {
- Clicked(this, e);
- }
+ private void ButtonLongClicked(object sender, EventArgs e)
+ {
+ LongClicked(this, e);
+ }
- ///
- /// Method called when button press is started (up state)
- ///
- /// sender object
- /// event arguments
- protected void ButtonPressEnded(object sender, EventArgs e)
- {
- PressEnded(this, e);
- }
+ ///
+ /// Method when button is clicked (down then up)
+ ///
+ /// sender object
+ /// event arguments
+ protected void ButtonClicked(object sender, EventArgs e)
+ {
+ Clicked(this, e);
+ }
- ///
- /// Method called when button press is started (down state)
- ///
- /// sender object
- /// event arguments
- protected void ButtonPressStarted(object sender, EventArgs e)
- {
- PressStarted(this, e);
- }
+ ///
+ /// Method called when button press is started (up state)
+ ///
+ /// sender object
+ /// event arguments
+ protected void ButtonPressEnded(object sender, EventArgs e)
+ {
+ PressEnded(this, e);
+ }
- ///
- /// Convenience method to get the current sensor reading
- ///
- public Task Read() => Button.Read();
+ ///
+ /// Method called when button press is started (down state)
+ ///
+ /// sender object
+ /// event arguments
+ protected void ButtonPressStarted(object sender, EventArgs e)
+ {
+ PressStarted(this, e);
}
+
+ ///
+ /// Convenience method to get the current sensor reading
+ ///
+ public Task Read() => Button.Read();
}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.ElectronicSpeedController/Samples/ElectronicSpeedController_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Motors.ElectronicSpeedController/Samples/ElectronicSpeedController_Sample/MeadowApp.cs
index 761926f1f5..1afdb35f7d 100644
--- a/Source/Meadow.Foundation.Peripherals/Motors.ElectronicSpeedController/Samples/ElectronicSpeedController_Sample/MeadowApp.cs
+++ b/Source/Meadow.Foundation.Peripherals/Motors.ElectronicSpeedController/Samples/ElectronicSpeedController_Sample/MeadowApp.cs
@@ -3,6 +3,7 @@
using Meadow.Foundation;
using Meadow.Foundation.Motors;
using Meadow.Foundation.Sensors.Rotary;
+using Meadow.Peripherals;
using Meadow.Peripherals.Sensors.Rotary;
using Meadow.Units;
using System.Threading.Tasks;
@@ -13,12 +14,11 @@ public class MeadowApp : App
{
//
- readonly Frequency frequency = new Frequency(50, Frequency.UnitType.Hertz);
- const float armMs = 0.5f;
- const float powerIncrement = 0.05f;
-
- ElectronicSpeedController esc;
- RotaryEncoderWithButton rotary;
+ private readonly Frequency frequency = new Frequency(50, Frequency.UnitType.Hertz);
+ private const float armMs = 0.5f;
+ private const float powerIncrement = 0.05f;
+ private ElectronicSpeedController esc;
+ private RotaryEncoderWithButton rotary;
public override Task Initialize()
{
@@ -44,7 +44,7 @@ private void RotaryRotated(object sender, RotaryChangeResult e)
esc.Power += (e.New == RotationDirection.Clockwise) ? powerIncrement : -powerIncrement;
DisplayPowerOnLed(esc.Power);
- Resolver.Log.Info($"New Power: {esc.Power * (float)100:n0}%");
+ Resolver.Log.Info($"New Power: {esc.Power * 100:n0}%");
}
///
@@ -52,7 +52,7 @@ private void RotaryRotated(object sender, RotaryChangeResult e)
/// blue @ `0%`, and a proportional mix, in between those speeds.
///
///
- void DisplayPowerOnLed(float power)
+ private void DisplayPowerOnLed(float power)
{
// `0.0` - `1.0`
int r = (int)ExtensionMethods.Map(power, 0f, 1f, 0f, 255f);
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/A4988.cs b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/A4988.cs
index 168976159b..bda3dfcede 100644
--- a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/A4988.cs
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/A4988.cs
@@ -1,4 +1,5 @@
using Meadow.Hardware;
+using Meadow.Peripherals;
using Meadow.Units;
using System;
using System.Linq;
@@ -38,7 +39,8 @@ public int RotationSpeedDivisor
rotationSpeedDivisor = value;
}
}
- int rotationSpeedDivisor;
+
+ private int rotationSpeedDivisor;
///
/// Sets or gets the direction of rotation used for Step or Rotate methods
@@ -102,16 +104,15 @@ public int StepsPerRevolution
}
}
- readonly IDigitalOutputPort stepPort;
- readonly IDigitalOutputPort directionPort;
- readonly IDigitalOutputPort? enablePort;
- readonly IDigitalOutputPort? ms1Port;
- readonly IDigitalOutputPort? ms2Port;
- readonly IDigitalOutputPort? ms3Port;
- readonly object syncRoot = new object();
-
- StepDivisor divisor;
- Angle stepAngle;
+ private readonly IDigitalOutputPort stepPort;
+ private readonly IDigitalOutputPort directionPort;
+ private readonly IDigitalOutputPort enablePort;
+ private readonly IDigitalOutputPort ms1Port;
+ private readonly IDigitalOutputPort ms2Port;
+ private readonly IDigitalOutputPort ms3Port;
+ private readonly object syncRoot = new object();
+ private StepDivisor divisor;
+ private Angle stepAngle;
///
/// Creates an instance of the A4988 Stepper Motor Driver
@@ -156,7 +157,7 @@ public A4988(IPin step, IPin direction, IPin enable)
/// The (optional) Meadow pin connected to the MS2 pin of the A4988
/// The (optional) Meadow pin connected to the MS3 pin of the A4988
/// You must provide either all of the micro-step (MS) lines or none of them
- public A4988(IPin step, IPin direction, IPin? enablePin, IPin? ms1Pin, IPin? ms2Pin, IPin? ms3Pin)
+ public A4988(IPin step, IPin direction, IPin enablePin, IPin ms1Pin, IPin ms2Pin, IPin ms3Pin)
{
stepPort = step.CreateDigitalOutputPort();
@@ -168,13 +169,13 @@ public A4988(IPin step, IPin direction, IPin? enablePin, IPin? ms1Pin, IPin? ms2
}
// micro-step lines (for now) are all-or-nothing TODO: rethink this?
- if (new IPin?[] { ms1Pin, ms2Pin, ms3Pin }.All(p => p != null))
+ if (new IPin[] { ms1Pin, ms2Pin, ms3Pin }.All(p => p != null))
{
- ms1Port = ms1Pin?.CreateDigitalOutputPort();
- ms2Port = ms2Pin?.CreateDigitalOutputPort();
- ms3Port = ms3Pin?.CreateDigitalOutputPort();
+ ms1Port = ms1Pin.CreateDigitalOutputPort();
+ ms2Port = ms2Pin.CreateDigitalOutputPort();
+ ms3Port = ms3Pin.CreateDigitalOutputPort();
}
- else if (new IPin?[] { ms1Pin, ms2Pin, ms3Pin }.All(p => p == null))
+ else if (new IPin[] { ms1Pin, ms2Pin, ms3Pin }.All(p => p == null))
{ // nop
}
else
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/RotationDirection.cs b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/RotationDirection.cs
deleted file mode 100644
index 815cc39b88..0000000000
--- a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Driver/RotationDirection.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Meadow.Foundation.Motors.Stepper
-{
- ///
- /// Stepper motor direction
- ///
- public enum RotationDirection
- {
- ///
- /// Clockwise
- ///
- Clockwise,
- ///
- /// Counter-clockwise
- ///
- CounterClockwise,
- }
-}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Samples/A4988_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Samples/A4988_Sample/MeadowApp.cs
index 5b1e289631..829a5d07ec 100644
--- a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Samples/A4988_Sample/MeadowApp.cs
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.A4988/Samples/A4988_Sample/MeadowApp.cs
@@ -1,6 +1,7 @@
using Meadow;
using Meadow.Devices;
using Meadow.Foundation.Motors.Stepper;
+using Meadow.Peripherals;
using System;
using System.Threading;
using System.Threading.Tasks;
@@ -11,7 +12,7 @@ public class MeadowApp : App
{
//
- A4988 a4988;
+ private A4988 a4988;
public override Task Initialize()
{
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Datasheet/dm542e.pdf b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Datasheet/dm542e.pdf
new file mode 100644
index 0000000000..fc56e535d9
Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Datasheet/dm542e.pdf differ
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Em542s.cs b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Em542s.cs
new file mode 100644
index 0000000000..f1cff5ceab
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Em542s.cs
@@ -0,0 +1,157 @@
+using Meadow.Hardware;
+using Meadow.Peripherals;
+using Meadow.Peripherals.Motors;
+using Meadow.Units;
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Meadow.Foundation.Motors.Stepper;
+
+///
+/// This class is for the A4988 Stepper Motor Driver
+///
+public class Em542s : IStepperMotor
+{
+ private readonly IDigitalOutputPort _pulsePort;
+ private readonly IDigitalOutputPort _directionPort;
+ private readonly IDigitalOutputPort? _enablePort;
+ private const int MinimumStartupDelayMicroseconds = 50;
+ private const int LinearAccelerationConstant = 40;
+ private const int MinimumMicrosecondDelayRequiredByDrive = 5;
+ private float _usPerCall;
+
+ private readonly object _syncRoot = new();
+
+ ///
+ public RotationDirection Direction { get; set; }
+
+ ///
+ public int StepsPerRevolution { get; }
+
+ ///
+ /// Gets a value indicating whether the logic for the stepper motor driver is inverted.
+ ///
+ public bool InverseLogic { get; }
+
+ ///
+ /// Initializes a new instance of the class with the specified parameters.
+ ///
+ /// The digital output port for controlling the pulse signal.
+ /// The digital output port for controlling the direction of rotation.
+ /// The optional digital output port for enabling or disabling the motor (if available).
+ /// The number of steps per revolution for the stepper motor (default is 200).
+ /// A value indicating whether the logic for the stepper motor driver is inverted (default is false).
+
+ public Em542s(
+ IDigitalOutputPort pulse,
+ IDigitalOutputPort direction,
+ IDigitalOutputPort? enable = null,
+ int stepsPerRevolution = 200,
+ bool inverseLogic = false
+ )
+ {
+ StepsPerRevolution = stepsPerRevolution;
+ InverseLogic = inverseLogic;
+
+ _pulsePort = pulse;
+ _directionPort = direction;
+ _enablePort = enable;
+
+ _pulsePort.State = !InverseLogic;
+ _directionPort.State = InverseLogic;
+
+ if (_enablePort != null)
+ {
+ _enablePort.State = false;
+ }
+
+ CalculateCallDuration();
+ }
+
+ [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
+ private void CalculateCallDuration()
+ {
+ Task.Run(() =>
+ {
+ var temp = 0;
+ var calls = 100000;
+
+ var start = Environment.TickCount;
+
+ for (var i = 0; i < calls; i++)
+ {
+ temp = i;
+ }
+
+ var et = Environment.TickCount - start;
+
+ _usPerCall = et * 1000 / (float)calls;
+
+ Resolver.Log.Info($"us per call: {calls} / {et} = {_usPerCall}");
+ });
+ }
+
+ [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
+ private void MicrosecondSleep(int microseconds)
+ {
+ var temp = 0;
+
+ for (var i = 0; i < microseconds / _usPerCall; i++)
+ {
+ temp = i;
+ }
+ }
+
+ ///
+ public void Step(int steps, RotationDirection direction, Frequency rate)
+ {
+ while (_usPerCall == 0)
+ {
+ Thread.Sleep(10);
+ }
+
+ lock (_syncRoot)
+ {
+ var directionState = direction == RotationDirection.Clockwise;
+ if (InverseLogic) directionState = !directionState;
+ _directionPort.State = directionState;
+
+ if (_enablePort != null)
+ {
+ _enablePort.State = !InverseLogic;
+ }
+
+ var targetus = (int)(1000000d / rate.Hertz);
+
+ if (targetus < MinimumMicrosecondDelayRequiredByDrive) throw new ArgumentOutOfRangeException(
+ "Rate cannot have pulses shorter than 5us. Use 200KHz or less.");
+
+ var us = targetus < MinimumStartupDelayMicroseconds ? MinimumStartupDelayMicroseconds : targetus;
+
+ for (var step = 0; step < steps; step++)
+ {
+ _pulsePort.State = InverseLogic; // low means "step"
+
+ MicrosecondSleep(us);
+
+ _pulsePort.State = !InverseLogic;
+
+ MicrosecondSleep(us);
+
+ // DEV NOTE:
+ // naive linear acceleration tested only with STP-MTR-34066 motor
+ if (us > targetus && step % LinearAccelerationConstant == 0)
+ {
+ us--;
+ }
+ }
+
+ if (_enablePort != null)
+ {
+ _enablePort.State = !InverseLogic;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Motors.Stepper.Em542s.csproj b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Motors.Stepper.Em542s.csproj
new file mode 100644
index 0000000000..585d10884a
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Driver/Motors.Stepper.Em542s.csproj
@@ -0,0 +1,25 @@
+
+
+ enable
+ 10.0
+ Apache-2.0
+ true
+ icon.png
+ Wilderness Labs, Inc
+ netstandard2.1
+ Library
+ Em542s
+ Wilderness Labs, Inc
+ http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/
+ Meadow.Foundation.Motors.Stepper.Em542s
+ https://github.com/WildernessLabs/Meadow.Foundation
+ Meadow, Meadow.Foundation, Motor, Stepper, Leadshine, Em542s
+ 0.1.49
+ true
+ The Leadshine EM542S Stepper Motor Drive
+
+
+
+
+
+
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/Em542s_Sample.csproj b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/Em542s_Sample.csproj
new file mode 100644
index 0000000000..500f53f3d4
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/Em542s_Sample.csproj
@@ -0,0 +1,20 @@
+
+
+ https://github.com/WildernessLabs/Meadow.Foundation
+ Wilderness Labs, Inc
+ Wilderness Labs, Inc
+ true
+ netstandard2.1
+ Library
+ App
+
+
+
+
+
+
+
+ Always
+
+
+
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/MeadowApp.cs
new file mode 100644
index 0000000000..18c4d0cc16
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/MeadowApp.cs
@@ -0,0 +1,52 @@
+using Meadow;
+using Meadow.Devices;
+using Meadow.Foundation.Motors.Stepper;
+using Meadow.Hardware;
+using Meadow.Peripherals;
+using Meadow.Peripherals.Motors;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MeadowApp
+{
+ public class MeadowApp : App
+ {
+ //
+ private IStepperMotor stepper;
+
+ public override Task Initialize()
+ {
+ stepper = new Em542s(
+ Device.Pins.D15.CreateDigitalOutputPort(),
+ Device.Pins.D14.CreateDigitalOutputPort(),
+ inverseLogic: true);
+
+ return base.Initialize();
+ }
+
+ public override Task Run()
+ {
+ var direction = RotationDirection.Clockwise;
+
+ // max rate for this drive
+ var rate = new Meadow.Units.Frequency(200, Meadow.Units.Frequency.UnitType.Kilohertz);
+
+ while (true)
+ {
+ Resolver.Log.Info($"{direction}");
+
+ stepper.Rotate(360f, direction, rate);
+ Thread.Sleep(1000);
+
+ direction = direction switch
+ {
+ RotationDirection.CounterClockwise => RotationDirection.Clockwise,
+ _ => RotationDirection.CounterClockwise
+ };
+ }
+ }
+
+ //
+
+ }
+}
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/meadow.config.yaml b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/meadow.config.yaml
new file mode 100644
index 0000000000..32363cb69c
--- /dev/null
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/meadow.config.yaml
@@ -0,0 +1,2 @@
+MonoControl:
+ Options: --jit
\ No newline at end of file
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/wiring_example.png b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/wiring_example.png
new file mode 100644
index 0000000000..39bdfe5b4a
Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/Motors.Stepper.Em542s/Samples/Em542s_Sample/wiring_example.png differ
diff --git a/Source/Meadow.Foundation.Peripherals/Motors.Tb67h420ftg/Samples/Tb67h420ftg_Encoder_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Motors.Tb67h420ftg/Samples/Tb67h420ftg_Encoder_Sample/MeadowApp.cs
index bd74a0840b..20e5ac9b0a 100644
--- a/Source/Meadow.Foundation.Peripherals/Motors.Tb67h420ftg/Samples/Tb67h420ftg_Encoder_Sample/MeadowApp.cs
+++ b/Source/Meadow.Foundation.Peripherals/Motors.Tb67h420ftg/Samples/Tb67h420ftg_Encoder_Sample/MeadowApp.cs
@@ -6,6 +6,7 @@
using Meadow.Foundation.Sensors.Buttons;
using Meadow.Foundation.Sensors.Rotary;
using Meadow.Hardware;
+using Meadow.Peripherals;
using System;
using System.Threading.Tasks;
@@ -13,12 +14,11 @@ namespace Motors.Tb67h420ftg_Encoder_Sample
{
public class MeadowApp : App
{
- Tb67h420ftg motorDriver;
- RotaryEncoder encoder;
- MicroGraphics display;
-
- PushButton button1;
- PushButton button2;
+ private Tb67h420ftg motorDriver;
+ private RotaryEncoder encoder;
+ private MicroGraphics display;
+ private PushButton button1;
+ private PushButton button2;
public override Task Initialize()
{
@@ -64,11 +64,11 @@ public override Task Initialize()
return base.Initialize();
}
- int forwardCount = 0;
- int backwardsCount = 0;
- private void Encoder_Rotated(object sender, Meadow.Peripherals.Sensors.Rotary.RotaryChangeResult e)
+ private int forwardCount = 0;
+ private int backwardsCount = 0;
+ private void Encoder_Rotated(object _, Meadow.Peripherals.Sensors.Rotary.RotaryChangeResult e)
{
- if (e.New == Meadow.Peripherals.Sensors.Rotary.RotationDirection.Clockwise)
+ if (e.New == RotationDirection.Clockwise)
{
forwardCount++;
}
@@ -83,7 +83,7 @@ private void Encoder_Rotated(object sender, Meadow.Peripherals.Sensors.Rotary.Ro
// Resolver.Log.Info($"{++count} - {e.Direction}");
}
- void UpdateDisplay(string line1, string line2)
+ private void UpdateDisplay(string line1, string line2)
{
display.Clear();
display.DrawText(0, 0, line1);
@@ -91,8 +91,8 @@ void UpdateDisplay(string line1, string line2)
display.Show();
}
- long pressed;
- int count;
+ private long pressed;
+ private int count;
private void Button1_PressStarted(object sender, EventArgs e)
{
count = forwardCount + backwardsCount;
diff --git a/Source/Meadow.Foundation.sln b/Source/Meadow.Foundation.sln
index 6fd073dfd9..90a95377f0 100644
--- a/Source/Meadow.Foundation.sln
+++ b/Source/Meadow.Foundation.sln
@@ -1389,7 +1389,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.DigiPots.Mcp4xxx", "Mea
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mcp4162_Sample", "Meadow.Foundation.Peripherals\ICs.DigiPots.Mcp4xxx\Samples\Mcp4162_Sample\Mcp4162_Sample.csproj", "{E175FDF8-103D-4920-9E46-CC180AF703E7}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Displays.Uc1609c", "Meadow.Foundation.Peripherals\Displays.Uc1609c\Driver\Displays.Uc1609c.csproj", "{8B397E9F-61BF-4499-B703-9C78A81A9FD7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Motors.Stepper.Em542s", "Meadow.Foundation.Peripherals\Motors.Stepper.Em542s\Driver\Motors.Stepper.Em542s.csproj", "{5A071DD9-8943-421C-81CF-0B7E91A24B57}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stepper.Em542s", "Stepper.Em542s", "{FC63A488-29DD-4E30-89BB-507923BC2392}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{91F3576B-CD16-4364-84E6-3F205F6D9A37}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Em542s_Sample", "Meadow.Foundation.Peripherals\Motors.Stepper.Em542s\Samples\Em542s_Sample\Em542s_Sample.csproj", "{0BB431FD-EDD2-47EB-A49F-2F3954C4357B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Displays.Uc1609c", "Meadow.Foundation.Peripherals\Displays.Uc1609c\Driver\Displays.Uc1609c.csproj", "{68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -3351,12 +3359,24 @@ Global
{E175FDF8-103D-4920-9E46-CC180AF703E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E175FDF8-103D-4920-9E46-CC180AF703E7}.Release|Any CPU.Build.0 = Release|Any CPU
{E175FDF8-103D-4920-9E46-CC180AF703E7}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Release|Any CPU.Build.0 = Release|Any CPU
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -4050,7 +4070,11 @@ Global
{91EE39A7-2A2B-4584-A341-52F5143E4ABA} = {CD113034-407F-4FA7-9706-8004406551D2}
{68AA3433-B429-4462-B4F4-7D7E163DE8EB} = {CD113034-407F-4FA7-9706-8004406551D2}
{E175FDF8-103D-4920-9E46-CC180AF703E7} = {91EE39A7-2A2B-4584-A341-52F5143E4ABA}
- {8B397E9F-61BF-4499-B703-9C78A81A9FD7} = {F962EC81-2B65-4187-B93A-F49BA004A7BA}
+ {5A071DD9-8943-421C-81CF-0B7E91A24B57} = {FC63A488-29DD-4E30-89BB-507923BC2392}
+ {FC63A488-29DD-4E30-89BB-507923BC2392} = {2486B48D-D4A2-4505-BF50-F33B2E15DA97}
+ {91F3576B-CD16-4364-84E6-3F205F6D9A37} = {FC63A488-29DD-4E30-89BB-507923BC2392}
+ {0BB431FD-EDD2-47EB-A49F-2F3954C4357B} = {91F3576B-CD16-4364-84E6-3F205F6D9A37}
+ {68D57BFA-2EE8-4EC6-83C9-B95F97FD5CE1} = {F962EC81-2B65-4187-B93A-F49BA004A7BA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AF7CA16F-8C38-4546-87A2-5DAAF58A1520}