Skip to content

Commit

Permalink
Merge pull request #550 from WildernessLabs/bug/pwm
Browse files Browse the repository at this point in the history
Bug/pwm
  • Loading branch information
adrianstevens authored Jun 21, 2024
2 parents 8def52d + 2e51aee commit 787bd12
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 188 deletions.
346 changes: 169 additions & 177 deletions source/Meadow.Core/Hardware/SoftPwmPort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,217 +2,209 @@
using System;
using System.Threading;

namespace Meadow.Hardware
namespace Meadow.Hardware;

/// <summary>
/// A Pulse Width Modulation Generator that can
/// generates waveforms in software. The maximum
/// Frequency is about 100 Hz.
///
/// Note: This class is not yet implemented.
/// </summary>
public class SoftPwmPort : IPwmPort
{
/// <summary>
/// A Pulse Width Modulation Generator that can
/// generates waveforms in software. The maximum
/// Frequency is about 100 Hz.
///
/// Note: This class is not yet implemented.
/// Digital output port used for PWM
/// </summary>
public class SoftPwmPort : IPwmPort
protected IDigitalOutputPort Port { get; set; }

/// <summary>
/// PWM duration in ms
/// </summary>
public TimeSpan Duration
{
/// <summary>
/// Digital output port used for PWM
/// </summary>
protected IDigitalOutputPort Port { get; set; }

/// <summary>
/// PWM duration in ms
/// </summary>
public float Duration
{
get => Period * DutyCycle;
set { }
}
get => TimeSpan.FromSeconds(Period.TotalSeconds * DutyCycle);
set { }
}

/// <summary>
/// Period of PWM
/// </summary>
public float Period
{
get => 1 / (float)frequency.Hertz;
set => frequency = new Frequency(1 / value, Units.Frequency.UnitType.Hertz);
}
/// <summary>
/// Period of PWM
/// </summary>
public TimeSpan Period
{
get => TimeSpan.FromSeconds(1 / frequency.Hertz);
set => frequency = new Frequency(1 / value.TotalSeconds, Frequency.UnitType.Hertz);
}

/// <summary>
/// Is the PWM signal inverted
/// </summary>
public bool Inverted { get; set; }
/// <summary>
/// Is the PWM signal inverted
/// </summary>
public bool Inverted { get; set; }


/// <summary>
/// Duty cycle of PWM
/// </summary>
public float DutyCycle
/// <summary>
/// Duty cycle of PWM
/// </summary>
public double DutyCycle
{
get => dutyCycle;
set
{
get => dutyCycle;
set
{
dutyCycle = value;
onTimeMilliseconds = CalculateOnTimeMillis();
offTimeMilliseconds = CalculateOffTimeMillis();
}
dutyCycle = value;
onTimeMilliseconds = CalculateOnTimeMillis();
offTimeMilliseconds = CalculateOffTimeMillis();
}
float dutyCycle;
}

private double dutyCycle;

/// <summary>
/// Frequency of soft PWM
/// </summary>
public Frequency Frequency
/// <summary>
/// Frequency of soft PWM
/// </summary>
public Frequency Frequency
{
get => frequency;
set
{
get => frequency;
set
{
frequency = value;
onTimeMilliseconds = CalculateOnTimeMillis();
offTimeMilliseconds = CalculateOffTimeMillis();
}
frequency = value;
onTimeMilliseconds = CalculateOnTimeMillis();
offTimeMilliseconds = CalculateOffTimeMillis();
}
Frequency frequency = new Frequency(1.0, Units.Frequency.UnitType.Hertz); // in the case it doesn't get set before duty cycle, initialize to 1
}

/// <summary>
/// Channel info for PWM port
/// </summary>
public IPwmChannelInfo Channel { get; protected set; }
private Frequency frequency = new Frequency(1.0, Units.Frequency.UnitType.Hertz); // in the case it doesn't get set before duty cycle, initialize to 1

/// <summary>
/// State of PWM port (running / not running)
/// </summary>
public bool State => running;
/// <summary>
/// Channel info for PWM port
/// </summary>
public IPwmChannelInfo Channel { get; protected set; }

/// <summary>
/// Pin used for soft PWM
/// </summary>
public IPin Pin => Port.Pin;
/// <summary>
/// State of PWM port (running / not running)
/// </summary>
public bool State => running;

IDigitalChannelInfo IPort<IDigitalChannelInfo>.Channel => throw new NotImplementedException();
/// <summary>
/// Pin used for soft PWM
/// </summary>
public IPin Pin => Port.Pin;

/// <summary>
/// Timescale
/// </summary>
public TimeScale TimeScale
{
get => TimeScale.Seconds;
set { }
}
IDigitalChannelInfo IPort<IDigitalChannelInfo>.Channel => throw new NotImplementedException();

Thread? thread = null;
int onTimeMilliseconds = 0;
int offTimeMilliseconds = 0;
bool running = false;

/// <summary>
/// Instantiate a SoftPwm object that can perform PWM using digital pins
/// </summary>
/// <param name="outputPin"></param>
/// <param name="dutyCycle"></param>
/// <param name="frequency"></param>
public SoftPwmPort(IPin outputPin, float dutyCycle = 0.5f, float frequency = 1.0f) :
this(outputPin.CreateDigitalOutputPort(false), dutyCycle, frequency)
{
}
private Thread? thread = null;
private int onTimeMilliseconds = 0;
private int offTimeMilliseconds = 0;
private bool running = false;

/// <summary>
/// Instantiate a SoftPwm object that can perform PWM using digital pins
/// </summary>
/// <param name="outputPort"></param>
/// <param name="dutyCycle"></param>
/// <param name="frequencyInHertz"></param>
public SoftPwmPort(IDigitalOutputPort outputPort, float dutyCycle = 0.0f, float frequencyInHertz = 1000)
{
Port = outputPort;
DutyCycle = dutyCycle;
frequency = new Frequency(frequencyInHertz, Units.Frequency.UnitType.Hertz);
/// <summary>
/// Instantiate a SoftPwm object that can perform PWM using digital pins
/// </summary>
/// <param name="outputPin"></param>
/// <param name="dutyCycle"></param>
/// <param name="frequency"></param>
public SoftPwmPort(IPin outputPin, float dutyCycle = 0.5f, float frequency = 1.0f) :
this(outputPin.CreateDigitalOutputPort(false), dutyCycle, frequency)
{
}

Channel = new PwmChannelInfo("SoftPwmChannel", 0, 0, 1000, 1000, false, false);
}
/// <summary>
/// Instantiate a SoftPwm object that can perform PWM using digital pins
/// </summary>
/// <param name="outputPort"></param>
/// <param name="dutyCycle"></param>
/// <param name="frequencyInHertz"></param>
public SoftPwmPort(IDigitalOutputPort outputPort, float dutyCycle = 0.0f, float frequencyInHertz = 1000)
{
Port = outputPort;
DutyCycle = dutyCycle;
frequency = new Frequency(frequencyInHertz, Units.Frequency.UnitType.Hertz);

/// <summary>
/// Start the pulse width modulation
/// </summary>
public void Start()
{
running = true;
Channel = new PwmChannelInfo("SoftPwmChannel", 0, 0, 1000, 1000, false, false);
}

// create a new thread that actually writes the pwm to the output port
thread = new Thread(() =>
{
while (running)
{
Port.State = !Inverted;
Thread.Sleep(onTimeMilliseconds);
Port.State = Inverted;
Thread.Sleep(offTimeMilliseconds);
}
});
thread.Start();
}
/// <summary>
/// Start the pulse width modulation
/// </summary>
public void Start()
{
running = true;

/// <summary>
/// Stop the pulse width modulation
/// </summary>
public void Stop()
// create a new thread that actually writes the pwm to the output port
thread = new Thread(() =>
{
// setting this will wrap up the thread
running = false;
while (running)
{
Port.State = !Inverted;
Thread.Sleep(onTimeMilliseconds);
Port.State = Inverted;
Thread.Sleep(offTimeMilliseconds);
}
});
thread.Start();
}

// need to make sure the port is off, otherwise it can get
// stuck in an ON state.
Port.State = false;
}
/// <summary>
/// Stop the pulse width modulation
/// </summary>
public void Stop()
{
// setting this will wrap up the thread
running = false;

/// <summary>
/// Calculates the pulse on time in milliseconds
/// </summary>
protected int CalculateOnTimeMillis()
{
var dc = DutyCycle;
// clamp
if (dc < 0) dc = 0;
if (dc > 1) dc = 1;
// on time =
return (int)(dc / frequency.Kilohertz);
}
// need to make sure the port is off, otherwise it can get
// stuck in an ON state.
Port.State = false;
}

/// <summary>
/// Calculates the off time of pulse in milliseconds
/// </summary>
/// <returns></returns>
protected int CalculateOffTimeMillis()
{
var dc = DutyCycle;
// clamp
if (dc < 0) dc = 0;
if (dc > 1) dc = 1;
// off time =
return (int)((1 - dc) / frequency.Kilohertz);
}
/// <summary>
/// Calculates the pulse on time in milliseconds
/// </summary>
protected int CalculateOnTimeMillis()
{
var dc = DutyCycle;
// clamp
if (dc < 0) dc = 0;
if (dc > 1) dc = 1;
// on time =
return (int)(dc / frequency.Kilohertz);
}

/// <summary>
/// Calculates the off time of pulse in milliseconds
/// </summary>
/// <returns></returns>
protected int CalculateOffTimeMillis()
{
var dc = DutyCycle;
// clamp
if (dc < 0) dc = 0;
if (dc > 1) dc = 1;
// off time =
return (int)((1 - dc) / frequency.Kilohertz);
}

private bool disposedValue = false; // To detect redundant calls
private bool disposedValue = false; // To detect redundant calls

/// <summary>
/// Dispose of the object
/// </summary>
/// <param name="disposing">Is disposing</param>
protected virtual void Dispose(bool disposing)
/// <summary>
/// Dispose of the object
/// </summary>
/// <param name="disposing">Is disposing</param>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (!disposedValue)
if (disposing)
{
if (disposing)
{
}

disposedValue = true;
}
}

///<inheritdoc/>
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
disposedValue = true;
}
}

///<inheritdoc/>
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
}
Loading

0 comments on commit 787bd12

Please sign in to comment.