Skip to content

Commit

Permalink
Merge branch 'alternative'
Browse files Browse the repository at this point in the history
  • Loading branch information
googolgl committed Aug 6, 2020
2 parents 77f4e62 + 81c202c commit 5b4b457
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 53 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,37 @@ import (
"log"
"time"

i2c "github.com/d2r2/go-i2c"
"github.com/googolgl/go-i2c"
"github.com/googolgl/go-pca9685"
)

func main() {
// Create new connection to i2c-bus on 1 line with address 0x40.
// Use i2cdetect utility to find device address over the i2c-bus
i2c, err := i2c.NewI2C(pca9685.Address, 1)
i2c, err := i2c.New(pca9685.Address, 1)
if err != nil {
log.Fatal(err)
}

pca0 := pca9685.New(i2c, nil)
if err := pca0.Init(); err != nil {
pca0, err = pca9685.New(i2c, nil)
if err != nil {
log.Fatal(err)
}

// Sets frequency for channel 0
// Sets a single PWM channel 0
pca0.SetChannel(0, 0, 130)
time.Sleep(1 * time.Second)

// Servo on channel 0
servo0 := pca0.ServoNew(0, nil)

// Angle in degrees. Must be in the range `0` to `Range`
// Rotates from 0 to 130 degrees
servo1 := pca0.ServoNew(0, nil)
for i := 0; i < 130; i++ {
servo1.Angle(i)
servo0.Angle(i)
time.Sleep(10 * time.Millisecond)
}

// Fraction as pulse width expressed between 0.0 `MinPulse` and 1.0 `MaxPulse`
servo1.Fraction(0.5)
servo0.Fraction(0.5)
}
```

Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/googolgl/go-pca9685

go 1.14

require github.com/googolgl/go-i2c v0.0.5
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/googolgl/go-i2c v0.0.5 h1:KKtpcXx4H0mhlMonVc1QKqzRgf6u7wt2JeRXy95JTFA=
github.com/googolgl/go-i2c v0.0.5/go.mod h1:ZAqTSwjnPXqglNaEixRmgAUatGpTMm0xyJp/wK6ZDgk=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
54 changes: 28 additions & 26 deletions pca9685.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
OUT OF OR IN i2cECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

Expand All @@ -27,7 +27,7 @@ import (
"fmt"
"time"

i2c "github.com/d2r2/go-i2c"
"github.com/googolgl/go-i2c"
)

const (
Expand All @@ -49,8 +49,8 @@ const (

// PCA9685 is a Driver for the PCA9685 16-channel 12-bit PWM/Servo controller
type PCA9685 struct {
Conn *i2c.I2C
Optn *Options
i2c *i2c.Options
optn *Options
}

// Options for controller
Expand All @@ -60,30 +60,32 @@ type Options struct {
ClockSpeed float32
}

// New creates a new driver with specified i2c interface
func New(i2c *i2c.I2C, optn *Options) *PCA9685 {
// New creates the new PCA9685 driver with specified i2c interface and options
func New(i2c *i2c.Options, optn *Options) (*PCA9685, error) {
adr := i2c.GetAddr()
if adr == 0 {
return nil, fmt.Errorf(`I2C device is not initiated`)
}

pca := &PCA9685{
Conn: i2c,
Optn: &Options{
i2c: i2c,
optn: &Options{
Name: "Controller" + fmt.Sprintf("-0x%x", adr),
Frequency: DefaultPWMFrequency,
ClockSpeed: ReferenceClockSpeed,
},
}
if optn != nil {
pca.Optn = optn
pca.optn = optn
}
return pca
}

// Init initialize the PCA9685
func (pca *PCA9685) Init() (err error) {
if pca.Conn.GetAddr() == 0 {
return fmt.Errorf(`device %v is not initiated`, pca.Optn.Name)
if err := pca.i2c.WriteRegU8(Mode1, 0x00|0xA1); err != nil { // Mode 1, autoincrement on)
return nil, err
}
if err := pca.SetFreq(DefaultPWMFrequency); err != nil {
return nil, err
}
pca.Conn.WriteRegU8(Mode1, 0x00|0xA1) // Mode 1, autoincrement on)
return pca.SetFreq(pca.Optn.Frequency)
return pca, nil
}

// SetFreq sets the PWM frequency in Hz for controller
Expand All @@ -92,32 +94,32 @@ func (pca *PCA9685) SetFreq(freq float32) (err error) {
if prescaleVal < 3.0 {
return fmt.Errorf("PCA9685 cannot output at the given frequency")
}
oldMode, err := pca.Conn.ReadRegU8(Mode1)
oldMode, err := pca.i2c.ReadRegU8(Mode1)
if err != nil {
return err
}
newMode := (oldMode & 0x7F) | 0x10 // Mode 1, sleep
if err := pca.Conn.WriteRegU8(Mode1, newMode); err != nil {
if err := pca.i2c.WriteRegU8(Mode1, newMode); err != nil {
return err
}
if err := pca.Conn.WriteRegU8(Prescale, byte(prescaleVal)); err != nil {
if err := pca.i2c.WriteRegU8(Prescale, byte(prescaleVal)); err != nil {
return err
}
if err := pca.Conn.WriteRegU8(Mode1, oldMode); err != nil {
if err := pca.i2c.WriteRegU8(Mode1, oldMode); err != nil {
return err
}
time.Sleep(5 * time.Millisecond)
return
return nil
}

// GetFreq returns frequency value
func (pca *PCA9685) GetFreq() float32 {
return pca.Optn.Frequency
return pca.optn.Frequency
}

// Reset reset the chip
// Reset the chip
func (pca *PCA9685) Reset() (err error) {
return pca.Conn.WriteRegU8(Mode1, 0x00)
return pca.i2c.WriteRegU8(Mode1, 0x00)
}

// SetChannel sets a single PWM channel
Expand All @@ -133,6 +135,6 @@ func (pca *PCA9685) SetChannel(chn, on, off int) (err error) {
}

buf := []byte{Led0On + byte(4*chn), byte(on) & 0xFF, byte(on >> 8), byte(off) & 0xFF, byte(off >> 8)}
_, err = pca.Conn.WriteBytes(buf)
_, err = pca.i2c.WriteBytes(buf)
return err
}
34 changes: 17 additions & 17 deletions servo.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,41 @@ const (

// Servo structure
type Servo struct {
PCA *PCA9685
Channel int
Options *ServOptions
pca *PCA9685
channel int
options *ServOptions
}

// ServOptions for servo
type ServOptions struct {
Range int // actuation range
AcRange int // actuation range
MinPulse float32
MaxPulse float32
}

// ServoNew creates a new servo driver
func (pca *PCA9685) ServoNew(chn int, o *ServOptions) *Servo {
s := &Servo{
PCA: pca,
Channel: chn,
Options: &ServOptions{
Range: ServoRangeDef,
pca: pca,
channel: chn,
options: &ServOptions{
AcRange: ServoRangeDef,
MinPulse: ServoMinPulseDef,
MaxPulse: ServoMaxPulseDef,
},
}
if o != nil {
s.Options = o
s.options = o
}
return s
}

// Angle in degrees. Must be in the range `0` to `Range`.
func (s *Servo) Angle(a int) (err error) {
if a < 0 || a > s.Options.Range {
if a < 0 || a > s.options.AcRange {
return fmt.Errorf("Angle out of range")
}
return s.Fraction(float32(a) / float32(s.Options.Range))
return s.Fraction(float32(a) / float32(s.options.AcRange))
}

// Fraction as pulse width expressed between 0.0 `MinPulse` and 1.0 `MaxPulse`.
Expand All @@ -86,17 +86,17 @@ func (s *Servo) Fraction(f float32) (err error) {
return fmt.Errorf("Must be 0.0 to 1.0")
}

freq := s.PCA.GetFreq()
freq := s.pca.GetFreq()

minDuty := s.Options.MinPulse * freq / 1000000 * 0xFFFF
maxDuty := s.Options.MaxPulse * freq / 1000000 * 0xFFFF
minDuty := s.options.MinPulse * freq / 1000000 * 0xFFFF
maxDuty := s.options.MaxPulse * freq / 1000000 * 0xFFFF
dutyRange := maxDuty - minDuty
dutyCycle := (int(minDuty+f*dutyRange) + 1) >> 4

return s.PCA.SetChannel(s.Channel, 0, dutyCycle)
return s.pca.SetChannel(int(s.channel), 0, dutyCycle)
}

// Reset servo
// Reset channel
func (s *Servo) Reset() (err error) {
return s.PCA.SetChannel(s.Channel, 0, 0)
return s.pca.SetChannel(s.channel, 0, 0)
}

0 comments on commit 5b4b457

Please sign in to comment.