gobot.io/x/gobot@v1.16.0/drivers/i2c/adxl345_driver.go (about) 1 package i2c 2 3 import ( 4 "encoding/binary" 5 6 "github.com/pkg/errors" 7 "gobot.io/x/gobot" 8 ) 9 10 const ADXL345AddressLow = 0x53 11 const ADXL345AddressHigh = 0x1D 12 13 const ( 14 // Data rate 15 ADXL345_RATE_3200HZ = 0x0F // 3200 Hz 16 ADXL345_RATE_1600HZ = 0x0E // 1600 Hz 17 ADXL345_RATE_800HZ = 0x0D // 800 Hz 18 ADXL345_RATE_400HZ = 0x0C // 400 Hz 19 ADXL345_RATE_200HZ = 0x0B // 200 Hz 20 ADXL345_RATE_100HZ = 0x0A // 100 Hz 21 ADXL345_RATE_50HZ = 0x09 // 50 Hz 22 ADXL345_RATE_25HZ = 0x08 // 25 Hz 23 ADXL345_RATE_12_5HZ = 0x07 // 12.5 Hz 24 ADXL345_RATE_6_25HZ = 0x06 // 6.25 Hz 25 ADXL345_RATE_3_13HZ = 0x05 // 3.13 Hz 26 ADXL345_RATE_1_56HZ = 0x04 // 1.56 Hz 27 ADXL345_RATE_0_78HZ = 0x03 // 0.78 Hz 28 ADXL345_RATE_0_39HZ = 0x02 // 0.39 Hz 29 ADXL345_RATE_0_20HZ = 0x01 // 0.20 Hz 30 ADXL345_RATE_0_10HZ = 0x00 // 0.10 Hz 31 32 // Data range 33 ADXL345_RANGE_2G = 0x00 // +-2 g 34 ADXL345_RANGE_4G = 0x01 // +-4 g 35 ADXL345_RANGE_8G = 0x02 // +-8 g 36 ADXL345_RANGE_16G = 0x03 // +-16 g) 37 38 ADXL345_REG_DEVID = 0x00 // R, 11100101, Device ID 39 ADXL345_REG_THRESH_TAP = 0x1D // R/W, 00000000, Tap threshold 40 ADXL345_REG_OFSX = 0x1E // R/W, 00000000, X-axis offset 41 ADXL345_REG_OFSY = 0x1F // R/W, 00000000, Y-axis offset 42 ADXL345_REG_OFSZ = 0x20 // R/W, 00000000, Z-axis offset 43 ADXL345_REG_DUR = 0x21 // R/W, 00000000, Tap duration 44 ADXL345_REG_LATENT = 0x22 // R/W, 00000000, Tap latency 45 ADXL345_REG_WINDOW = 0x23 // R/W, 00000000, Tap window 46 ADXL345_REG_THRESH_ACT = 0x24 // R/W, 00000000, Activity threshold 47 ADXL345_REG_THRESH_INACT = 0x25 // R/W, 00000000, Inactivity threshold 48 ADXL345_REG_TIME_INACT = 0x26 // R/W, 00000000, Inactivity time 49 ADXL345_REG_ACT_INACT_CTL = 0x27 // R/W, 00000000, Axis enable control for activity and inactiv ity detection 50 ADXL345_REG_THRESH_FF = 0x28 // R/W, 00000000, Free-fall threshold 51 ADXL345_REG_TIME_FF = 0x29 // R/W, 00000000, Free-fall time 52 ADXL345_REG_TAP_AXES = 0x2A // R/W, 00000000, Axis control for single tap/double tap 53 ADXL345_REG_ACT_TAP_STATUS = 0x2B // R, 00000000, Source of single tap/double tap 54 ADXL345_REG_BW_RATE = 0x2C // R/W, 00001010, Data rate and power mode control 55 ADXL345_REG_POWER_CTL = 0x2D // R/W, 00000000, Power-saving features control 56 ADXL345_REG_INT_ENABLE = 0x2E // R/W, 00000000, Interrupt enable control 57 ADXL345_REG_INT_MAP = 0x2F // R/W, 00000000, Interrupt mapping control 58 ADXL345_REG_INT_SOUCE = 0x30 // R, 00000010, Source of interrupts 59 ADXL345_REG_DATA_FORMAT = 0x31 // R/W, 00000000, Data format control 60 ADXL345_REG_DATAX0 = 0x32 // R, 00000000, X-Axis Data 0 61 ADXL345_REG_DATAX1 = 0x33 // R, 00000000, X-Axis Data 1 62 ADXL345_REG_DATAY0 = 0x34 // R, 00000000, Y-Axis Data 0 63 ADXL345_REG_DATAY1 = 0x35 // R, 00000000, Y-Axis Data 1 64 ADXL345_REG_DATAZ0 = 0x36 // R, 00000000, Z-Axis Data 0 65 ADXL345_REG_DATAZ1 = 0x37 // R, 00000000, Z-Axis Data 1 66 ADXL345_REG_FIFO_CTL = 0x38 // R/W, 00000000, FIFO control 67 ADXL345_REG_FIFO_STATUS = 0x39 // R, 00000000, FIFO status 68 ) 69 70 // ADXL345Driver is the gobot driver for the digital accelerometer ADXL345 71 // 72 // Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf 73 // Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf 74 // 75 // Ported from the Arduino driver https://github.com/jakalada/Arduino-ADXL345 76 type ADXL345Driver struct { 77 name string 78 connector Connector 79 connection Connection 80 81 powerCtl adxl345PowerCtl 82 dataFormat adxl345DataFormat 83 bwRate adxl345BwRate 84 85 x, y, z float64 86 rawX, rawY, rawZ int16 87 88 Config 89 } 90 91 // Internal structure for the power configuration 92 type adxl345PowerCtl struct { 93 link uint8 94 autoSleep uint8 95 measure uint8 96 sleep uint8 97 wakeUp uint8 98 } 99 100 // Internal structure for the sensor's data format configuration 101 type adxl345DataFormat struct { 102 selfTest uint8 103 spi uint8 104 intInvert uint8 105 fullRes uint8 106 justify uint8 107 sensorRange uint8 108 } 109 110 // Internal structure for the sampling rate configuration 111 type adxl345BwRate struct { 112 lowPower uint8 113 rate uint8 114 } 115 116 // NewADXL345Driver creates a new driver with specified i2c interface 117 // Params: 118 // conn Connector - the Adaptor to use with this Driver 119 // 120 // Optional params: 121 // i2c.WithBus(int): bus to use with this driver 122 // i2c.WithAddress(int): address to use with this driver 123 // 124 func NewADXL345Driver(a Connector, options ...func(Config)) *ADXL345Driver { 125 m := &ADXL345Driver{ 126 name: gobot.DefaultName("ADXL345"), 127 connector: a, 128 powerCtl: adxl345PowerCtl{ 129 measure: 1, 130 }, 131 dataFormat: adxl345DataFormat{ 132 sensorRange: ADXL345_RANGE_2G, 133 }, 134 bwRate: adxl345BwRate{ 135 lowPower: 1, 136 rate: ADXL345_RATE_100HZ, 137 }, 138 Config: NewConfig(), 139 } 140 141 for _, option := range options { 142 option(m) 143 } 144 145 // TODO: add commands for API 146 return m 147 } 148 149 // Name returns the Name for the Driver 150 func (h *ADXL345Driver) Name() string { return h.name } 151 152 // SetName sets the Name for the Driver 153 func (h *ADXL345Driver) SetName(n string) { h.name = n } 154 155 // Connection returns the connection for the Driver 156 func (h *ADXL345Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) } 157 158 // Start initialized the adxl345 159 func (h *ADXL345Driver) Start() (err error) { 160 bus := h.GetBusOrDefault(h.connector.GetDefaultBus()) 161 address := h.GetAddressOrDefault(ADXL345AddressLow) 162 163 h.connection, err = h.connector.GetConnection(address, bus) 164 if err != nil { 165 return err 166 } 167 168 if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil { 169 return err 170 } 171 172 if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil { 173 return err 174 } 175 176 if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil { 177 return err 178 } 179 180 return 181 } 182 183 // Stop adxl345 184 func (h *ADXL345Driver) Stop() (err error) { 185 h.powerCtl.measure = 0 186 if h.connection == nil { 187 return errors.New("connection not available") 188 } 189 if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil { 190 return err 191 } 192 193 return 194 } 195 196 // Halt returns true if devices is halted successfully 197 func (h *ADXL345Driver) Halt() (err error) { 198 h.Stop() 199 return 200 } 201 202 // XYZ returns the adjusted x, y and z axis from the adxl345 203 func (h *ADXL345Driver) XYZ() (float64, float64, float64, error) { 204 err := h.update() 205 return h.x, h.y, h.z, err 206 } 207 208 // XYZ returns the raw x,y and z axis from the adxl345 209 func (h *ADXL345Driver) RawXYZ() (int16, int16, int16, error) { 210 err := h.update() 211 return h.rawX, h.rawY, h.rawZ, err 212 } 213 214 // update the cached values for the axis to avoid errors if the connection is not available (polling too frequently) 215 func (h *ADXL345Driver) update() (err error) { 216 217 if h.connection == nil { 218 return errors.New("connection not available") 219 } 220 221 h.connection.Write([]byte{ADXL345_REG_DATAX0}) 222 buf := []byte{0, 0, 0, 0, 0, 0} 223 224 _, err = h.connection.Read(buf) 225 if err != nil { 226 return 227 } 228 229 h.rawX = int16(binary.LittleEndian.Uint16(buf[0:2])) 230 h.rawY = int16(binary.LittleEndian.Uint16(buf[2:4])) 231 h.rawZ = int16(binary.LittleEndian.Uint16(buf[4:6])) 232 233 h.x = h.dataFormat.ConvertToSI(h.rawX) 234 h.y = h.dataFormat.ConvertToSI(h.rawY) 235 h.z = h.dataFormat.ConvertToSI(h.rawZ) 236 237 return 238 } 239 240 // SetRate change the current rate of the sensor 241 func (h *ADXL345Driver) UseLowPower(power bool) (err error) { 242 if power { 243 h.bwRate.lowPower = 1 244 } else { 245 h.bwRate.lowPower = 0 246 } 247 if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil { 248 return err 249 } 250 return 251 } 252 253 // SetRate change the current rate of the sensor 254 func (h *ADXL345Driver) SetRate(rate byte) (err error) { 255 if rate <= ADXL345_RATE_3200HZ { 256 return errors.New("not a valid rate") 257 } 258 h.bwRate.rate = rate & 0x0F 259 if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil { 260 return err 261 } 262 return 263 } 264 265 // SetRange change the current range of the sensor 266 func (h *ADXL345Driver) SetRange(sensorRange byte) (err error) { 267 if sensorRange != ADXL345_RANGE_2G && 268 sensorRange != ADXL345_RANGE_4G && 269 sensorRange != ADXL345_RANGE_8G && 270 sensorRange != ADXL345_RANGE_16G { 271 return errors.New("not a valid range") 272 } 273 h.dataFormat.sensorRange = sensorRange & 0x03 274 if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil { 275 return err 276 } 277 return 278 } 279 280 // ConvertToSI adjusts the raw values from the adxl345 with the range configuration 281 func (d *adxl345DataFormat) ConvertToSI(rawValue int16) float64 { 282 switch d.sensorRange { 283 case ADXL345_RANGE_2G: 284 return float64(rawValue) * 2 / 512 285 case ADXL345_RANGE_4G: 286 return float64(rawValue) * 4 / 512 287 case ADXL345_RANGE_8G: 288 return float64(rawValue) * 8 / 512 289 case ADXL345_RANGE_16G: 290 return float64(rawValue) * 16 / 512 291 default: 292 return 0 293 } 294 } 295 296 // toByte returns a byte from the powerCtl configuration 297 func (p *adxl345PowerCtl) toByte() (bits uint8) { 298 bits = 0x00 299 bits = bits | (p.link << 5) 300 bits = bits | (p.autoSleep << 4) 301 bits = bits | (p.measure << 3) 302 bits = bits | (p.sleep << 2) 303 bits = bits | p.wakeUp 304 305 return bits 306 } 307 308 // toByte returns a byte from the dataFormat configuration 309 func (d *adxl345DataFormat) toByte() (bits uint8) { 310 bits = 0x00 311 bits = bits | (d.selfTest << 7) 312 bits = bits | (d.spi << 6) 313 bits = bits | (d.intInvert << 5) 314 bits = bits | (d.fullRes << 3) 315 bits = bits | (d.justify << 2) 316 bits = bits | d.sensorRange 317 318 return bits 319 } 320 321 // toByte returns a byte from the bwRate configuration 322 func (b *adxl345BwRate) toByte() (bits uint8) { 323 bits = 0x00 324 bits = bits | (b.lowPower << 4) 325 bits = bits | b.rate 326 327 return bits 328 }