Skip to content

Instantly share code, notes, and snippets.

@kurtnelle
Last active June 6, 2019 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kurtnelle/7368de27537d07296af7fab8854d83a8 to your computer and use it in GitHub Desktop.
Save kurtnelle/7368de27537d07296af7fab8854d83a8 to your computer and use it in GitHub Desktop.
PocketBeagle PWM Controller
using System;
using System.Collections.Generic;
using System.IO;
public class PocketBeaglePWMController : BBBandVariantsPWMController
{
public PWMChannel ChipZeroChannelZero
{
get
{
return this["pwmchip0"][0];
}
}
public PWMChannel ChipZeroChannelOne
{
get
{
return this["pwmchip0"][1];
}
}
public PWMChannel ChipTwoChannelZero
{
get
{
return this["pwmchip2"][0];
}
}
public PWMChannel ChipTwoChannelOne
{
get
{
return this["pwmchip2"][1];
}
}
public PWMChannel ChipFourChannelZero
{
get
{
return this["pwmchip4"][0];
}
}
public PWMChannel ChipFourChannelOne
{
get
{
return this["pwmchip4"][1];
}
}
}
public class BBBandVariantsPWMController : Dictionary<string, PWMChip>
{
const string PWM_ROOT = "/sys/class/pwm";
public BBBandVariantsPWMController()
{
var _chips = new List<PWMChip>();
foreach (var dir in Directory.GetDirectories(PWM_ROOT, "pwmchip*"))
{
var _chip = new PWMChip(dir);
Add(_chip.ChipName, _chip);
}
}
}
public class PWMChip : List<PWMChannel>
{
public int ChipNumber
{
get;
private set;
}
public string ChipPath
{
get;
private set;
}
public string ChipName
{
get;
private set;
}
public PWMChip(string chipPath)
{
ChipPath = chipPath;
ChipNumber = int.Parse(chipPath.Substring(chipPath.Length - 1, 1));
ChipName = chipPath.Substring(chipPath.LastIndexOf("/") + 1);
var _channelCount = int.Parse(File.ReadAllText($"{chipPath}/npwm"));
for(var i = 0; i < _channelCount; i++)
{
Add(new PWMChannel($"{chipPath}/pwm-{ChipNumber}:{i}"));
}
}
}
public class PWMChannel
{
const string ONE_VALUE = "1";
const string ZERO_VALUE = "0";
const string NORMAL_VALUE = "normal";
const string INVERSED_VALUE = "inversed";
string enablePath = "{0}/enable";
string periodPath = "{0}/period";
string dutyCyclePath = "{0}/duty_cycle";
string polarityPath = "{0}/polarity";
public string ChannelPath
{
get;
private set;
}
public PWMChannel Enable()
{
IsEnabled = true;
return this;
}
public PWMChannel Disable()
{
IsEnabled = false;
return this;
}
public bool IsEnabled
{
get
{
return File.ReadAllText(enablePath) == ONE_VALUE;
}
set
{
File.WriteAllText(enablePath, value ? ONE_VALUE : ZERO_VALUE);
}
}
/// <summary>
/// The active time of the PWM signal (read/write). Value is in nanoseconds and must be less than the period.
/// </summary>
public UInt64 DutyCycle
{
get
{
return UInt64.Parse(File.ReadAllText(dutyCyclePath));
}
set
{
File.WriteAllText(dutyCyclePath, value.ToString());
}
}
/// <summary>
/// The active time of the PWM signal as a ratio of the period value must be greater than 0 and less than 1
/// </summary>
/// <param name="dutyCycle"></param>
/// <returns></returns>
public PWMChannel SetDutyCycle(double dutyCycle)
{
if(dutyCycle >= 1 || dutyCycle <=0)
{
throw new ArgumentException("This method only accepts values that represent a ratio of the period e.g. 0.5 = 50%");
}
var period = Period;
if (period == 0)
{
throw new ArgumentException("The period must not be 0 for the duty cycle to be set");
}
else
{
DutyCycle = (UInt64)(period * dutyCycle);
}
return this;
}
/// <summary>
/// The total period of the PWM signal (read/write). Value is in nanoseconds and is the sum of the active and inactive time of the PWM.
/// </summary>
public UInt64 Period
{
get
{
return UInt64.Parse(File.ReadAllText(periodPath));
}
set
{
if (DutyCycle != 0)
{
if ((value / DutyCycle) <= 0)
{
DutyCycle = 0;
}
}
File.WriteAllText(periodPath, value.ToString());
}
}
/// <summary>
/// The total period of the PWM signal (read/write). Value is in nanoseconds and is the sum of the active and inactive time of the PWM.
/// </summary>
/// <param name="period">number of nano seconds per cycle</param>
/// <returns></returns>
public PWMChannel SetPeriod(UInt64 period)
{
try
{
Period = period;
}
catch (IOException ioEx)
{
throw new ArgumentException($"Invalid value when setting period \"{period}\"", ioEx);
}
return this;
}
public bool Polarity
{
get
{
return File.ReadAllText(polarityPath) == NORMAL_VALUE;
}
set
{
IsEnabled = false;
File.WriteAllText(polarityPath, value ? NORMAL_VALUE : INVERSED_VALUE);
}
}
public PWMChannel SetPolarity(bool normal)
{
Polarity = normal;
return this;
}
public PWMChannel(string channelPath)
{
enablePath = string.Format(enablePath, channelPath);
dutyCyclePath = string.Format(dutyCyclePath, channelPath);
periodPath = string.Format(periodPath, channelPath);
polarityPath = string.Format(polarityPath, channelPath);
}
}
@kurtnelle
Copy link
Author

kurtnelle commented Jun 5, 2019

Test by connecting Scope to Pin labeled PWM1A on silk screen.

        Console.WriteLine("Starting PWM...");

        new PocketBeaglePWMController()
            .ChipTwoChannelZero
            .SetPeriod(1 * 100 * 1000 * 1000)
            .SetDutyCycle(.5)
            .Enable();

DS1Z_QuickPrint1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment