-
Notifications
You must be signed in to change notification settings - Fork 594
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PCA9685: 16-channel, 12-bit PWM Fm+ I²C-bus LED controller (#250)
* added PCA9685 * Update Pca9685.Sample.cs * Update README.md * Update README.md * Update README.md * Update README.md * Fixed problems * private I2cDevice, Register comments, stackalloc byte, I2C address * Fixed comment * Change back * Change back * delete extra enters and commas
- Loading branch information
Showing
9 changed files
with
486 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
namespace Iot.Device.Pca9685 | ||
{ | ||
/// <summary> | ||
/// Values for Mode1 register | ||
/// </summary> | ||
internal enum Mode1 : byte | ||
{ | ||
RESTART = 0b10000000, // Bit 7 | ||
EXTCLK = 0b01000000, // Bit 6 | ||
AI = 0b00100000, // Bit 5 | ||
SLEEP = 0b00010000, // Bit 4 | ||
SUB1 = 0b00001000, // Bit 3 | ||
SUB2 = 0b00000100, // Bit 2 | ||
SUB3 = 0b00000010, // Bit 1 | ||
ALLCALL = 0x00000001 // Bit 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
namespace Iot.Device.Pca9685 | ||
{ | ||
/// <summary> | ||
/// Values for Mode2 register | ||
/// </summary> | ||
internal enum Mode2 : byte | ||
{ | ||
INVRT = 0b00010000, // Bit 4 | ||
OCH = 0b00001000, // Bit 3 | ||
OUTDRV = 0b00000100 // Bit 2 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Device.I2c; | ||
using System.Threading; | ||
using static Iot.Device.Pca9685.Register; | ||
using static Iot.Device.Pca9685.Mode1; | ||
using static Iot.Device.Pca9685.Mode2; | ||
|
||
namespace Iot.Device.Pca9685 | ||
{ | ||
/// <summary> | ||
/// PCA9685 PWM LED/servo controller | ||
/// </summary> | ||
public class Pca9685 : IDisposable | ||
{ | ||
/// <summary> | ||
/// I2C Device | ||
/// </summary> | ||
private I2cDevice _device; | ||
|
||
/// <summary> | ||
/// Get default clock rate. Set if you are using external clock. | ||
/// </summary> | ||
public double ClockRate { get; set; } = 25000000; // 25MHz | ||
|
||
/// <summary> | ||
/// Set PWM frequency or get effective value. | ||
/// </summary> | ||
public double PwmFrequency | ||
{ | ||
get => _pwmFrequency; | ||
set | ||
{ | ||
Prescale = GetPrescale(value); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Set PWM frequency using prescale value or get the value. | ||
/// </summary> | ||
public byte Prescale | ||
{ | ||
get => _prescale; | ||
set | ||
{ | ||
var v = value < 3 ? (byte)3 : value; // min value is 3 | ||
SetPwmFrequency(v); | ||
_prescale = v; | ||
_pwmFrequency = GetFreq(v); | ||
} | ||
} | ||
|
||
private double _pwmFrequency; | ||
private byte _prescale; | ||
|
||
/// <summary> | ||
/// Initialize PCA9685 | ||
/// </summary> | ||
/// <param name="i2cDevice">The I2C device to be used</param> | ||
public Pca9685(I2cDevice i2cDevice) | ||
{ | ||
// Setup I2C interface for the device. | ||
_device = i2cDevice; | ||
|
||
SetPwm(0, 0); | ||
|
||
Span<byte> buffer = stackalloc byte[2] { (byte)MODE2, (byte)OUTDRV }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)MODE1, (byte)ALLCALL }; | ||
_device.Write(buffer); | ||
|
||
Thread.Sleep(5); // wait for oscillator | ||
|
||
int mode1 = _device.ReadByte(); | ||
mode1 &= ~(byte)SLEEP; // wake up (reset sleep) | ||
|
||
buffer = stackalloc byte[2] { (byte)MODE1, (byte)mode1 }; | ||
_device.Write(buffer); | ||
|
||
Thread.Sleep(5); // wait for oscillator | ||
} | ||
|
||
/// <summary> | ||
/// Set a single PWM channel | ||
/// </summary> | ||
/// <param name="on">The turn-on time of specfied channel</param> | ||
/// <param name="off">The turn-off time of specfied channel</param> | ||
/// <param name="channel">target channel</param> | ||
public void SetPwm(int on, int off, int channel) | ||
{ | ||
on &= 0xFFF; | ||
off &= 0xFFF; | ||
channel &= 0xF; | ||
|
||
Span<byte> buffer = stackalloc byte[2] { (byte)((byte)LED0_ON_L + 4 * channel), (byte)on }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)((byte)LED0_ON_H + 4 * channel), (byte)(on >> 8) }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)((byte)LED0_OFF_L + 4 * channel), (byte)off }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)((byte)LED0_OFF_H + 4 * channel), (byte)(off >> 8) }; | ||
_device.Write(buffer); | ||
} | ||
|
||
/// <summary> | ||
/// Set all PWM channels | ||
/// </summary> | ||
/// <param name="on">The turn-on time of all channels</param> | ||
/// <param name="off">The turn-on time of all channels</param> | ||
public void SetPwm(int on, int off) | ||
{ | ||
on &= 0xFFF; | ||
off &= 0xFFF; | ||
|
||
Span<byte> buffer = stackalloc byte[2] { (byte)ALL_LED_ON_L, (byte)on }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)ALL_LED_ON_H, (byte)(on >> 8) }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)ALL_LED_OFF_L, (byte)off }; | ||
_device.Write(buffer); | ||
|
||
buffer = stackalloc byte[2] { (byte)ALL_LED_OFF_H, (byte)(off >> 8) }; | ||
_device.Write(buffer); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_device?.Dispose(); | ||
_device = null; | ||
} | ||
|
||
/// <summary> | ||
/// Get prescale of specified PWM frequency | ||
/// </summary> | ||
private byte GetPrescale(double freq_hz) | ||
{ | ||
var prescaleval = ClockRate / 4096 / freq_hz - 1; | ||
//Debug.Print($"Setting PWM frequency to {freq_hz} Hz"); | ||
//Debug.Print($"Estimated pre-scale: {prescaleval}"); | ||
|
||
var prescale = (byte)Math.Round(prescaleval); | ||
//Debug.Print($"Final pre-scale: {prescale}"); | ||
|
||
return prescale; | ||
} | ||
|
||
/// <summary> | ||
/// Get PWM frequency of specified prescale | ||
/// </summary> | ||
private double GetFreq(byte prescale) | ||
{ | ||
return ClockRate / 4096 / (prescale + 1); | ||
} | ||
|
||
/// <summary> | ||
/// Set PWM frequency by using prescale | ||
/// </summary> | ||
private void SetPwmFrequency(byte prescale) | ||
{ | ||
var oldmode = _device.ReadByte(); | ||
var newmode = (sbyte)oldmode | (byte)SLEEP; | ||
|
||
Span<byte> buffer = stackalloc byte[2] { (byte)MODE1, (byte)newmode }; | ||
_device.Write(buffer); // go to sleep | ||
|
||
buffer = stackalloc byte[2] { (byte)PRESCALE, prescale }; | ||
_device.Write(buffer); | ||
|
||
|
||
buffer = stackalloc byte[2] { (byte)MODE1, oldmode }; | ||
_device.Write(buffer); | ||
|
||
Thread.Sleep(5); | ||
|
||
buffer = stackalloc byte[2] { (byte)MODE1, (byte)(oldmode | (byte)RESTART) }; | ||
_device.Write(buffer); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<!--Disabling default items so samples source won't get build by the main library--> | ||
<EnableDefaultItems>false</EnableDefaultItems> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="Pca9685.cs" /> | ||
<Compile Include="Mode1.cs" /> | ||
<Compile Include="Mode2.cs" /> | ||
<Compile Include="Register.cs" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Include="README.md" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.Device.Gpio" Version="0.1.0-prerelease*" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Pca9685 | ||
|
||
## Summary | ||
|
||
The PCA9685 is an I²C-bus controlled 16-channel LED controller optimized for Red/Green/Blue/Amber (RGBA) color backlighting applications. | ||
|
||
You can also use this to control servos. | ||
|
||
## Data Sheets from NXP | ||
|
||
https://www.nxp.com/docs/en/data-sheet/PCA9685.pdf | ||
|
||
## References | ||
|
||
https://www.nxp.com/products/analog/interfaces/ic-bus/ic-led-controllers/16-channel-12-bit-pwm-fm-plus-ic-bus-led-controller:PCA9685 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
namespace Iot.Device.Pca9685 | ||
{ | ||
internal enum Register : byte | ||
{ | ||
/// <summary> | ||
/// Mode register 1 | ||
/// </summary> | ||
MODE1 = 0x00, | ||
|
||
/// <summary> | ||
/// Mode register 2 | ||
/// </summary> | ||
MODE2 = 0x01, | ||
|
||
/// <summary> | ||
/// I2C-bus subaddress 1 | ||
/// </summary> | ||
SUBADR1 = 0x02, | ||
|
||
/// <summary> | ||
/// I2C-bus subaddress 2 | ||
/// </summary> | ||
SUBADR2 = 0x03, | ||
|
||
/// <summary> | ||
/// I2C-bus subaddress 3 | ||
/// </summary> | ||
SUBADR3 = 0x04, | ||
|
||
/// <summary> | ||
/// LED All Call I2C-bus address | ||
/// </summary> | ||
ALLCALLADR = 0x05, | ||
|
||
/// <summary> | ||
/// LED0 output and brightness control byte 0 | ||
/// </summary> | ||
LED0_ON_L = 0x06, | ||
|
||
/// <summary> | ||
/// LED0 output and brightness control byte 1 | ||
/// </summary> | ||
LED0_ON_H = 0x07, | ||
|
||
/// <summary> | ||
/// LED0 output and brightness control byte 2 | ||
/// </summary> | ||
LED0_OFF_L = 0x08, | ||
|
||
/// <summary> | ||
/// LED0 output and brightness control byte 3 | ||
/// </summary> | ||
LED0_OFF_H = 0x09, | ||
|
||
/// <summary> | ||
/// load all the LEDn_ON registers, byte 0 | ||
/// </summary> | ||
ALL_LED_ON_L = 0xFA, | ||
|
||
/// <summary> | ||
/// load all the LEDn_ON registers, byte 1 | ||
/// </summary> | ||
ALL_LED_ON_H = 0xFB, | ||
|
||
/// <summary> | ||
/// load all the LEDn_OFF registers, byte 0 | ||
/// </summary> | ||
ALL_LED_OFF_L = 0xFC, | ||
|
||
/// <summary> | ||
/// load all the LEDn_OFF registers, byte 1 | ||
/// </summary> | ||
ALL_LED_OFF_H = 0xFD, | ||
|
||
/// <summary> | ||
/// prescaler for PWM output frequency | ||
/// </summary> | ||
PRESCALE = 0xFE | ||
} | ||
} |
Oops, something went wrong.