gobot.io/x/gobot@v1.16.0/drivers/i2c/pca9685_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"strconv"
     5  	"time"
     6  
     7  	"gobot.io/x/gobot"
     8  )
     9  
    10  const pca9685Address = 0x40
    11  
    12  const (
    13  	PCA9685_MODE1        = 0x00
    14  	PCA9685_MODE2        = 0x01
    15  	PCA9685_PRESCALE     = 0xFE
    16  	PCA9685_SUBADR1      = 0x02
    17  	PCA9685_SUBADR2      = 0x03
    18  	PCA9685_SUBADR3      = 0x04
    19  	PCA9685_LED0_ON_L    = 0x06
    20  	PCA9685_LED0_ON_H    = 0x07
    21  	PCA9685_LED0_OFF_L   = 0x08
    22  	PCA9685_LED0_OFF_H   = 0x09
    23  	PCA9685_ALLLED_ON_L  = 0xFA
    24  	PCA9685_ALLLED_ON_H  = 0xFB
    25  	PCA9685_ALLLED_OFF_L = 0xFC
    26  	PCA9685_ALLLED_OFF_H = 0xFD
    27  
    28  	PCA9685_RESTART = 0x80
    29  	PCA9685_SLEEP   = 0x10
    30  	PCA9685_ALLCALL = 0x01
    31  	PCA9685_INVRT   = 0x10
    32  	PCA9685_OUTDRV  = 0x04
    33  )
    34  
    35  // PCA9685Driver is a Gobot Driver for the PCA9685 16-channel 12-bit PWM/Servo controller.
    36  //
    37  // For example, here is the Adafruit board that uses this chip:
    38  // https://www.adafruit.com/product/815
    39  //
    40  type PCA9685Driver struct {
    41  	name       string
    42  	connector  Connector
    43  	connection Connection
    44  	Config
    45  	gobot.Commander
    46  }
    47  
    48  // NewPCA9685Driver creates a new driver with specified i2c interface
    49  // Params:
    50  //		conn Connector - the Adaptor to use with this Driver
    51  //
    52  // Optional params:
    53  //		i2c.WithBus(int):	bus to use with this driver
    54  //		i2c.WithAddress(int):	address to use with this driver
    55  //
    56  func NewPCA9685Driver(a Connector, options ...func(Config)) *PCA9685Driver {
    57  	p := &PCA9685Driver{
    58  		name:      gobot.DefaultName("PCA9685"),
    59  		connector: a,
    60  		Config:    NewConfig(),
    61  		Commander: gobot.NewCommander(),
    62  	}
    63  
    64  	for _, option := range options {
    65  		option(p)
    66  	}
    67  
    68  	p.AddCommand("PwmWrite", func(params map[string]interface{}) interface{} {
    69  		pin := params["pin"].(string)
    70  		val, _ := strconv.Atoi(params["val"].(string))
    71  		return p.PwmWrite(pin, byte(val))
    72  	})
    73  	p.AddCommand("ServoWrite", func(params map[string]interface{}) interface{} {
    74  		pin := params["pin"].(string)
    75  		val, _ := strconv.Atoi(params["val"].(string))
    76  		return p.ServoWrite(pin, byte(val))
    77  	})
    78  	p.AddCommand("SetPWM", func(params map[string]interface{}) interface{} {
    79  		channel, _ := strconv.Atoi(params["channel"].(string))
    80  		on, _ := strconv.Atoi(params["on"].(string))
    81  		off, _ := strconv.Atoi(params["off"].(string))
    82  		return p.SetPWM(channel, uint16(on), uint16(off))
    83  	})
    84  	p.AddCommand("SetPWMFreq", func(params map[string]interface{}) interface{} {
    85  		freq, _ := strconv.ParseFloat(params["freq"].(string), 32)
    86  		return p.SetPWMFreq(float32(freq))
    87  	})
    88  
    89  	return p
    90  }
    91  
    92  // Name returns the Name for the Driver
    93  func (p *PCA9685Driver) Name() string { return p.name }
    94  
    95  // SetName sets the Name for the Driver
    96  func (p *PCA9685Driver) SetName(n string) { p.name = n }
    97  
    98  // Connection returns the connection for the Driver
    99  func (p *PCA9685Driver) Connection() gobot.Connection { return p.connector.(gobot.Connection) }
   100  
   101  // Start initializes the pca9685
   102  func (p *PCA9685Driver) Start() (err error) {
   103  	bus := p.GetBusOrDefault(p.connector.GetDefaultBus())
   104  	address := p.GetAddressOrDefault(pca9685Address)
   105  
   106  	p.connection, err = p.connector.GetConnection(address, bus)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	if err := p.SetAllPWM(0, 0); err != nil {
   112  		return err
   113  	}
   114  
   115  	if _, err := p.connection.Write([]byte{PCA9685_MODE2, PCA9685_OUTDRV}); err != nil {
   116  		return err
   117  	}
   118  
   119  	if _, err := p.connection.Write([]byte{PCA9685_MODE1, PCA9685_ALLCALL}); err != nil {
   120  		return err
   121  	}
   122  
   123  	time.Sleep(5 * time.Millisecond)
   124  
   125  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
   126  		return err
   127  	}
   128  	oldmode, err := p.connection.ReadByte()
   129  	if err != nil {
   130  		return err
   131  	}
   132  	oldmode = oldmode &^ byte(PCA9685_SLEEP)
   133  
   134  	if _, err := p.connection.Write([]byte{PCA9685_MODE1, oldmode}); err != nil {
   135  		return err
   136  	}
   137  
   138  	time.Sleep(5 * time.Millisecond)
   139  
   140  	return
   141  }
   142  
   143  // Halt stops the device
   144  func (p *PCA9685Driver) Halt() (err error) {
   145  	_, err = p.connection.Write([]byte{PCA9685_ALLLED_OFF_H, 0x10})
   146  	return
   147  }
   148  
   149  // SetPWM sets a specific channel to a pwm value from 0-4095.
   150  // Params:
   151  //		channel int - the channel to send the pulse
   152  //		on uint16 - the time to start the pulse
   153  //		off uint16 - the time to stop the pulse
   154  //
   155  // Most typically you set "on" to a zero value, and then set "off" to your desired duty.
   156  //
   157  func (p *PCA9685Driver) SetPWM(channel int, on uint16, off uint16) (err error) {
   158  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on) & 0xFF}); err != nil {
   159  		return err
   160  	}
   161  
   162  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_H + 4*channel), byte(on >> 8)}); err != nil {
   163  		return err
   164  	}
   165  
   166  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_OFF_L + 4*channel), byte(off) & 0xFF}); err != nil {
   167  		return err
   168  	}
   169  
   170  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_OFF_H + 4*channel), byte(off >> 8)}); err != nil {
   171  		return err
   172  	}
   173  
   174  	return
   175  }
   176  
   177  // SetAllPWM sets all channels to a pwm value from 0-4095.
   178  // Params:
   179  //		on uint16 - the time to start the pulse
   180  //		off uint16 - the time to stop the pulse
   181  //
   182  // Most typically you set "on" to a zero value, and then set "off" to your desired duty.
   183  //
   184  func (p *PCA9685Driver) SetAllPWM(on uint16, off uint16) (err error) {
   185  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_ON_L), byte(on) & 0xFF}); err != nil {
   186  		return err
   187  	}
   188  
   189  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_ON_H), byte(on >> 8)}); err != nil {
   190  		return err
   191  	}
   192  
   193  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_OFF_L), byte(off) & 0xFF}); err != nil {
   194  		return err
   195  	}
   196  
   197  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_OFF_H), byte(off >> 8)}); err != nil {
   198  		return err
   199  	}
   200  
   201  	return
   202  }
   203  
   204  // SetPWMFreq sets the PWM frequency in Hz
   205  func (p *PCA9685Driver) SetPWMFreq(freq float32) error {
   206  	// IC oscillator frequency is 25 MHz
   207  	var prescalevel float32 = 25000000
   208  	// Find frequency of PWM waveform
   209  	prescalevel /= 4096
   210  	// Ratio between desired frequency and maximum
   211  	prescalevel /= freq
   212  	prescalevel -= 1
   213  	// Round value to nearest whole
   214  	prescale := byte(prescalevel + 0.5)
   215  
   216  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
   217  		return err
   218  	}
   219  	oldmode, err := p.connection.ReadByte()
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	// Put oscillator in sleep mode, clear bit 7 here to avoid overwriting
   225  	// previous setting
   226  	newmode := (oldmode & 0x7F) | 0x10
   227  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(newmode)}); err != nil {
   228  		return err
   229  	}
   230  	// Write prescaler value
   231  	if _, err := p.connection.Write([]byte{byte(PCA9685_PRESCALE), prescale}); err != nil {
   232  		return err
   233  	}
   234  	// Put back to old settings
   235  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode)}); err != nil {
   236  		return err
   237  	}
   238  
   239  	time.Sleep(5 * time.Millisecond)
   240  
   241  	// Enable response to All Call address, enable auto-increment, clear restart
   242  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode | 0x80)}); err != nil {
   243  		return err
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  // PwmWrite writes a PWM signal to the specified channel aka "pin".
   250  // Value values are from 0-255, to conform to the PwmWriter interface.
   251  // If you need finer control, please look at SetPWM().
   252  //
   253  func (p *PCA9685Driver) PwmWrite(pin string, val byte) (err error) {
   254  	i, err := strconv.Atoi(pin)
   255  	if err != nil {
   256  		return
   257  	}
   258  	v := gobot.ToScale(gobot.FromScale(float64(val), 0, 255), 0, 4095)
   259  	return p.SetPWM(i, 0, uint16(v))
   260  }
   261  
   262  // ServoWrite writes a servo signal to the specified channel aka "pin".
   263  // Valid values are from 0-180, to conform to the ServoWriter interface.
   264  // If you need finer control, please look at SetPWM().
   265  //
   266  func (p *PCA9685Driver) ServoWrite(pin string, val byte) (err error) {
   267  	i, err := strconv.Atoi(pin)
   268  	if err != nil {
   269  		return
   270  	}
   271  	v := gobot.ToScale(gobot.FromScale(float64(val), 0, 180), 200, 500)
   272  	return p.SetPWM(i, 0, uint16(v))
   273  }