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 }