gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/pca9685_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"strconv"
     5  	"time"
     6  
     7  	"gobot.io/x/gobot/v2"
     8  )
     9  
    10  const pca9685DefaultAddress = 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  type PCA9685Driver struct {
    40  	*Driver
    41  }
    42  
    43  // NewPCA9685Driver creates a new driver with specified i2c interface
    44  // Params:
    45  //
    46  //	c Connector - the Adaptor to use with this Driver
    47  //
    48  // Optional params:
    49  //
    50  //	i2c.WithBus(int):	bus to use with this driver
    51  //	i2c.WithAddress(int):	address to use with this driver
    52  func NewPCA9685Driver(c Connector, options ...func(Config)) *PCA9685Driver {
    53  	p := &PCA9685Driver{
    54  		Driver: NewDriver(c, "PCA9685", pca9685DefaultAddress),
    55  	}
    56  	p.afterStart = p.initialize
    57  	p.beforeHalt = p.shutdown
    58  
    59  	for _, option := range options {
    60  		option(p)
    61  	}
    62  
    63  	p.AddCommand("PwmWrite", func(params map[string]interface{}) interface{} {
    64  		pin := params["pin"].(string)
    65  		val, _ := strconv.Atoi(params["val"].(string))
    66  		return p.PwmWrite(pin, byte(val))
    67  	})
    68  	p.AddCommand("ServoWrite", func(params map[string]interface{}) interface{} {
    69  		pin := params["pin"].(string)
    70  		val, _ := strconv.Atoi(params["val"].(string))
    71  		return p.ServoWrite(pin, byte(val))
    72  	})
    73  	p.AddCommand("SetPWM", func(params map[string]interface{}) interface{} {
    74  		channel, _ := strconv.Atoi(params["channel"].(string))
    75  		on, _ := strconv.Atoi(params["on"].(string))
    76  		off, _ := strconv.Atoi(params["off"].(string))
    77  		return p.SetPWM(channel, uint16(on), uint16(off))
    78  	})
    79  	p.AddCommand("SetPWMFreq", func(params map[string]interface{}) interface{} {
    80  		freq, _ := strconv.ParseFloat(params["freq"].(string), 32)
    81  		return p.SetPWMFreq(float32(freq))
    82  	})
    83  
    84  	return p
    85  }
    86  
    87  // SetPWM sets a specific channel to a pwm value from 0-4095.
    88  // Params:
    89  //
    90  //	channel int - the channel to send the pulse
    91  //	on uint16 - the time to start the pulse
    92  //	off uint16 - the time to stop the pulse
    93  //
    94  // Most typically you set "on" to a zero value, and then set "off" to your desired duty.
    95  func (p *PCA9685Driver) SetPWM(channel int, on uint16, off uint16) (err error) {
    96  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on) & 0xFF}); err != nil {
    97  		return err
    98  	}
    99  
   100  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_H + 4*channel), byte(on >> 8)}); err != nil {
   101  		return err
   102  	}
   103  
   104  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_OFF_L + 4*channel), byte(off) & 0xFF}); err != nil {
   105  		return err
   106  	}
   107  
   108  	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_OFF_H + 4*channel), byte(off >> 8)}); err != nil {
   109  		return err
   110  	}
   111  
   112  	return
   113  }
   114  
   115  // SetAllPWM sets all channels to a pwm value from 0-4095.
   116  // Params:
   117  //
   118  //	on uint16 - the time to start the pulse
   119  //	off uint16 - the time to stop the pulse
   120  //
   121  // Most typically you set "on" to a zero value, and then set "off" to your desired duty.
   122  func (p *PCA9685Driver) SetAllPWM(on uint16, off uint16) (err error) {
   123  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_ON_L), byte(on) & 0xFF}); err != nil {
   124  		return err
   125  	}
   126  
   127  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_ON_H), byte(on >> 8)}); err != nil {
   128  		return err
   129  	}
   130  
   131  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_OFF_L), byte(off) & 0xFF}); err != nil {
   132  		return err
   133  	}
   134  
   135  	if _, err := p.connection.Write([]byte{byte(PCA9685_ALLLED_OFF_H), byte(off >> 8)}); err != nil {
   136  		return err
   137  	}
   138  
   139  	return
   140  }
   141  
   142  // SetPWMFreq sets the PWM frequency in Hz
   143  func (p *PCA9685Driver) SetPWMFreq(freq float32) error {
   144  	// IC oscillator frequency is 25 MHz
   145  	var prescalevel float32 = 25000000
   146  	// Find frequency of PWM waveform
   147  	prescalevel /= 4096
   148  	// Ratio between desired frequency and maximum
   149  	prescalevel /= freq
   150  	prescalevel--
   151  	// Round value to nearest whole
   152  	prescale := byte(prescalevel + 0.5)
   153  
   154  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
   155  		return err
   156  	}
   157  	oldmode, err := p.connection.ReadByte()
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	// Put oscillator in sleep mode, clear bit 7 here to avoid overwriting
   163  	// previous setting
   164  	newmode := (oldmode & 0x7F) | 0x10
   165  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(newmode)}); err != nil {
   166  		return err
   167  	}
   168  	// Write prescaler value
   169  	if _, err := p.connection.Write([]byte{byte(PCA9685_PRESCALE), prescale}); err != nil {
   170  		return err
   171  	}
   172  	// Put back to old settings
   173  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode)}); err != nil {
   174  		return err
   175  	}
   176  
   177  	time.Sleep(5 * time.Millisecond)
   178  
   179  	// Enable response to All Call address, enable auto-increment, clear restart
   180  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode | 0x80)}); err != nil {
   181  		return err
   182  	}
   183  
   184  	return nil
   185  }
   186  
   187  // PwmWrite writes a PWM signal to the specified channel aka "pin".
   188  // Value values are from 0-255, to conform to the PwmWriter interface.
   189  // If you need finer control, please look at SetPWM().
   190  func (p *PCA9685Driver) PwmWrite(pin string, val byte) (err error) {
   191  	i, err := strconv.Atoi(pin)
   192  	if err != nil {
   193  		return
   194  	}
   195  	v := gobot.ToScale(gobot.FromScale(float64(val), 0, 255), 0, 4095)
   196  	return p.SetPWM(i, 0, uint16(v))
   197  }
   198  
   199  // ServoWrite writes a servo signal to the specified channel aka "pin".
   200  // Valid values are from 0-180, to conform to the ServoWriter interface.
   201  // If you need finer control, please look at SetPWM().
   202  func (p *PCA9685Driver) ServoWrite(pin string, val byte) (err error) {
   203  	i, err := strconv.Atoi(pin)
   204  	if err != nil {
   205  		return
   206  	}
   207  	v := gobot.ToScale(gobot.FromScale(float64(val), 0, 180), 200, 500)
   208  	return p.SetPWM(i, 0, uint16(v))
   209  }
   210  
   211  func (p *PCA9685Driver) initialize() error {
   212  	if err := p.SetAllPWM(0, 0); err != nil {
   213  		return err
   214  	}
   215  
   216  	if _, err := p.connection.Write([]byte{PCA9685_MODE2, PCA9685_OUTDRV}); err != nil {
   217  		return err
   218  	}
   219  
   220  	if _, err := p.connection.Write([]byte{PCA9685_MODE1, PCA9685_ALLCALL}); err != nil {
   221  		return err
   222  	}
   223  
   224  	time.Sleep(5 * time.Millisecond)
   225  
   226  	if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
   227  		return err
   228  	}
   229  	oldmode, err := p.connection.ReadByte()
   230  	if err != nil {
   231  		return err
   232  	}
   233  	oldmode = oldmode &^ byte(PCA9685_SLEEP)
   234  
   235  	if _, err := p.connection.Write([]byte{PCA9685_MODE1, oldmode}); err != nil {
   236  		return err
   237  	}
   238  
   239  	time.Sleep(5 * time.Millisecond)
   240  
   241  	return nil
   242  }
   243  
   244  func (p *PCA9685Driver) shutdown() error {
   245  	_, err := p.connection.Write([]byte{PCA9685_ALLLED_OFF_H, 0x10})
   246  	return err
   247  }