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 }