gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/hmc5883l_driver.go (about) 1 package i2c 2 3 import ( 4 "fmt" 5 "log" 6 "math" 7 "sort" 8 ) 9 10 const ( 11 hmc5883lDebug = false 12 hmc5883lDefaultAddress = 0x1E // default I2C Address 13 ) 14 15 const ( 16 hmc5883lRegA = 0x00 // Address of Configuration register A 17 hmc5883lRegB = 0x01 // Address of Configuration register B 18 hmc5883lRegMode = 0x02 // Address of node register 19 hmc5883lAxisX = 0x03 // Address of X-axis MSB data register 20 hmc5883lAxisZ = 0x05 // Address of Z-axis MSB data register 21 hmc5883lAxisY = 0x07 // Address of Y-axis MSB data register 22 hmc5883lRegStatus = 0x09 // Address of status register 23 hmc5883lRegIdA = 0x0A // Address of identification register A 24 hmc5883lRegIdB = 0x0B // Address of identification register B 25 hmc5883lRegIdC = 0x0C // Address of identification register C 26 27 hmc5883lRegA_SamplesAvg1 = 0x00 // no samples averaged 28 hmc5883lRegA_SamplesAvg2 = 0x01 // 2 samples averaged 29 hmc5883lRegA_SamplesAvg4 = 0x02 // 4 samples averaged 30 hmc5883lRegA_SamplesAvg8 = 0x03 // 8 samples averaged 31 hmc5883lRegA_OutputRate750 = 0x00 // data output rate 0.75 Hz 32 hmc5883lRegA_OutputRate1500 = 0x01 // data output rate 1.5 Hz 33 hmc5883lRegA_OutputRate3000 = 0x02 // data output rate 3.0 Hz 34 hmc5883lRegA_OutputRate7500 = 0x03 // data output rate 7.5 Hz 35 hmc5883lRegA_OutputRate15000 = 0x04 // data output rate 15.0 Hz 36 hmc5883lRegA_OutputRate30000 = 0x05 // data output rate 30.0 Hz 37 hmc5883lRegA_OutputRate75000 = 0x06 // data output rate 75.0 Hz 38 hmc5883lRegA_MeasNormal = 0x00 // normal measurement configuration 39 hmc5883lRegA_MeasPositiveBias = 0x01 // positive bias for X, Y, Z 40 hmc5883lRegA_MeasNegativeBias = 0x02 // negative bias for X, Y, Z 41 42 hmc5883lRegB_Gain1370 = 0x00 // gain is 1370 Gauss 43 hmc5883lRegB_Gain1090 = 0x01 // gain is 1090 Gauss 44 hmc5883lRegB_Gain820 = 0x02 // gain is 820 Gauss 45 hmc5883lRegB_Gain660 = 0x03 // gain is 660 Gauss 46 hmc5883lRegB_Gain440 = 0x04 // gain is 440 Gauss 47 hmc5883lRegB_Gain390 = 0x05 // gain is 390 Gauss 48 hmc5883lRegB_Gain330 = 0x06 // gain is 330 Gauss 49 hmc5883lRegB_Gain230 = 0x07 // gain is 230 Gauss 50 51 hmc5883lRegM_Continuous = 0x00 // continuous measurement mode 52 hmc5883lRegM_Single = 0x01 // return to idle after a single measurement 53 hmc5883lRegM_Idle = 0x10 // idle mode 54 ) 55 56 // HMC5883LDriver is a Gobot Driver for a HMC5883 I2C 3 axis digital compass. 57 // 58 // This driver was tested with Tinkerboard & Digispark adaptor and a HMC5883L breakout board GY-273, 59 // available from various distributors. 60 // 61 // datasheet: 62 // http://www.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf 63 // 64 // reference implementations: 65 // * https://github.com/gvalkov/micropython-esp8266-hmc5883l 66 // * https://github.com/adafruit/Adafruit_HMC5883_Unified 67 type HMC5883LDriver struct { 68 *Driver 69 samplesAvg uint8 70 outputRate uint32 // in mHz 71 applyBias int8 72 measurementMode int 73 gain float64 // in 1/Gauss 74 } 75 76 var hmc5883lSamplesAvgBits = map[uint8]int{ 77 1: hmc5883lRegA_SamplesAvg1, 78 2: hmc5883lRegA_SamplesAvg2, 79 4: hmc5883lRegA_SamplesAvg4, 80 8: hmc5883lRegA_SamplesAvg8, 81 } 82 83 var hmc5883lOutputRateBits = map[uint32]int{ 84 750: hmc5883lRegA_OutputRate750, 85 1500: hmc5883lRegA_OutputRate1500, 86 3000: hmc5883lRegA_OutputRate3000, 87 7500: hmc5883lRegA_OutputRate7500, 88 15000: hmc5883lRegA_OutputRate15000, 89 30000: hmc5883lRegA_OutputRate30000, 90 75000: hmc5883lRegA_OutputRate75000, 91 } 92 93 var hmc5883lMeasurementFlowBits = map[int8]int{ 94 0: hmc5883lRegA_MeasNormal, 95 1: hmc5883lRegA_MeasPositiveBias, 96 -1: hmc5883lRegA_MeasNegativeBias, 97 } 98 99 var hmc5883lGainBits = map[float64]int{ 100 1370.0: hmc5883lRegB_Gain1370, 101 1090.0: hmc5883lRegB_Gain1090, 102 820.0: hmc5883lRegB_Gain820, 103 660.0: hmc5883lRegB_Gain660, 104 440.0: hmc5883lRegB_Gain440, 105 390.0: hmc5883lRegB_Gain390, 106 330.0: hmc5883lRegB_Gain330, 107 230.0: hmc5883lRegB_Gain230, 108 } 109 110 // NewHMC5883LDriver creates a new driver with specified i2c interface 111 // Params: 112 // c Connector - the Adaptor to use with this Driver 113 // 114 // Optional params: 115 // i2c.WithBus(int): bus to use with this driver 116 // i2c.WithAddress(int): address to use with this driver 117 // i2c.WithHMC5883LSamplesAveraged(int) 118 // i2c.WithHMC5883LDataOutputRate(int) 119 // i2c.WithHMC5883LMeasurementFlow(int) 120 // i2c.WithHMC5883LGain(int) 121 // 122 func NewHMC5883LDriver(c Connector, options ...func(Config)) *HMC5883LDriver { 123 h := &HMC5883LDriver{ 124 Driver: NewDriver(c, "HMC5883L", hmc5883lDefaultAddress), 125 samplesAvg: 8, 126 outputRate: 15000, 127 applyBias: 0, 128 measurementMode: hmc5883lRegM_Continuous, 129 gain: 390, 130 } 131 h.afterStart = h.initialize 132 133 for _, option := range options { 134 option(h) 135 } 136 137 return h 138 } 139 140 // WithHMC5883LSamplesAveraged option sets the number of samples averaged per measurement. 141 // Valid settings are 1, 2, 4, 8. 142 func WithHMC5883LSamplesAveraged(val int) func(Config) { 143 return func(c Config) { 144 d, ok := c.(*HMC5883LDriver) 145 if ok { 146 if err := hmc5883lValidateSamplesAveraged(val); err != nil { 147 panic(err) 148 } 149 d.samplesAvg = uint8(val) 150 } else if hmc5883lDebug { 151 log.Printf("Trying to set samples averaged for non-HMC5883LDriver %v", c) 152 } 153 } 154 } 155 156 // WithHMC5883LDataOutputRate option sets the data output rate in mHz. 157 // Valid settings are 750, 1500, 3000, 7500, 15000, 30000, 75000. 158 func WithHMC5883LDataOutputRate(val int) func(Config) { 159 return func(c Config) { 160 d, ok := c.(*HMC5883LDriver) 161 if ok { 162 if err := hmc5883lValidateOutputRate(val); err != nil { 163 panic(err) 164 } 165 d.outputRate = uint32(val) 166 } else if hmc5883lDebug { 167 log.Printf("Trying to set data output rate for non-HMC5883LDriver %v", c) 168 } 169 } 170 } 171 172 // WithHMC5883LApplyBias option sets to apply a measurement bias. 173 // Valid settings are -1 (negative bias), 0 (normal), 1 (positive bias). 174 func WithHMC5883LApplyBias(val int) func(Config) { 175 return func(c Config) { 176 d, ok := c.(*HMC5883LDriver) 177 if ok { 178 if err := hmc5883lValidateApplyBias(val); err != nil { 179 panic(err) 180 } 181 d.applyBias = int8(val) 182 } else if hmc5883lDebug { 183 log.Printf("Trying to set measurement flow for non-HMC5883LDriver %v", c) 184 } 185 } 186 } 187 188 // WithHMC5883LGain option sets the gain. 189 // Valid settings are 1370, 1090, 820, 660, 440, 390, 330 230 in 1/Gauss. 190 func WithHMC5883LGain(val int) func(Config) { 191 return func(c Config) { 192 d, ok := c.(*HMC5883LDriver) 193 if ok { 194 if err := hmc5883lValidateGain(val); err != nil { 195 panic(err) 196 } 197 d.gain = float64(val) 198 } else if hmc5883lDebug { 199 log.Printf("Trying to set gain for non-HMC5883LDriver %v", c) 200 } 201 } 202 } 203 204 // Read reads the values X, Y, Z in Gauss 205 func (h *HMC5883LDriver) Read() (x float64, y float64, z float64, err error) { 206 h.mutex.Lock() 207 defer h.mutex.Unlock() 208 209 xr, yr, zr, err := h.readRawData() 210 if err != nil { 211 return 212 } 213 return float64(xr) / h.gain, float64(yr) / h.gain, float64(zr) / h.gain, nil 214 } 215 216 // Heading returns the current heading in radians 217 func (h *HMC5883LDriver) Heading() (heading float64, err error) { 218 h.mutex.Lock() 219 defer h.mutex.Unlock() 220 221 var x, y int16 222 x, y, _, err = h.readRawData() 223 if err != nil { 224 return 225 } 226 heading = math.Atan2(float64(y), float64(x)) 227 if heading > 2*math.Pi { 228 heading -= 2 * math.Pi 229 } 230 if heading < 0 { 231 heading += 2 * math.Pi 232 } 233 return 234 } 235 236 // readRawData reads the raw values from the X, Y, and Z registers 237 func (h *HMC5883LDriver) readRawData() (x int16, y int16, z int16, err error) { 238 // read the data, starting from the initial register 239 data := make([]byte, 6) 240 if err = h.connection.ReadBlockData(hmc5883lAxisX, data); err != nil { 241 return 242 } 243 244 unsignedX := (uint16(data[0]) << 8) | uint16(data[1]) 245 unsignedZ := (uint16(data[2]) << 8) | uint16(data[3]) 246 unsignedY := (uint16(data[4]) << 8) | uint16(data[5]) 247 248 return twosComplement16Bit(unsignedX), twosComplement16Bit(unsignedY), twosComplement16Bit(unsignedZ), nil 249 } 250 251 func (h *HMC5883LDriver) initialize() (err error) { 252 regA := hmc5883lMeasurementFlowBits[h.applyBias] 253 regA |= hmc5883lOutputRateBits[h.outputRate] << 2 254 regA |= hmc5883lSamplesAvgBits[h.samplesAvg] << 5 255 if err := h.connection.WriteByteData(hmc5883lRegA, uint8(regA)); err != nil { 256 return err 257 } 258 regB := hmc5883lGainBits[h.gain] << 5 259 if err := h.connection.WriteByteData(hmc5883lRegB, uint8(regB)); err != nil { 260 return err 261 } 262 if err := h.connection.WriteByteData(hmc5883lRegMode, uint8(h.measurementMode)); err != nil { 263 return err 264 } 265 return 266 } 267 268 func hmc5883lValidateSamplesAveraged(samplesAvg int) (err error) { 269 if _, ok := hmc5883lSamplesAvgBits[uint8(samplesAvg)]; ok { 270 return 271 } 272 273 keys := []int{} 274 for k := range hmc5883lSamplesAvgBits { 275 keys = append(keys, int(k)) 276 } 277 sort.Ints(keys) 278 err = fmt.Errorf("Samples averaged must be one of: %d", keys) 279 return 280 } 281 282 func hmc5883lValidateOutputRate(outputRate int) (err error) { 283 if _, ok := hmc5883lOutputRateBits[uint32(outputRate)]; ok { 284 return 285 } 286 287 keys := []int{} 288 for k := range hmc5883lOutputRateBits { 289 keys = append(keys, int(k)) 290 } 291 sort.Ints(keys) 292 err = fmt.Errorf("Data output rate must be one of: %d", keys) 293 return 294 } 295 296 func hmc5883lValidateApplyBias(applyBias int) (err error) { 297 if _, ok := hmc5883lMeasurementFlowBits[int8(applyBias)]; ok { 298 return 299 } 300 301 keys := []int{} 302 for k := range hmc5883lMeasurementFlowBits { 303 keys = append(keys, int(k)) 304 } 305 sort.Ints(keys) 306 err = fmt.Errorf("Apply measurement bias must be one of: %d", keys) 307 return 308 } 309 310 func hmc5883lValidateGain(gain int) (err error) { 311 if _, ok := hmc5883lGainBits[float64(gain)]; ok { 312 return 313 } 314 315 keys := []int{} 316 for k := range hmc5883lGainBits { 317 keys = append(keys, int(k)) 318 } 319 sort.Ints(keys) 320 err = fmt.Errorf("Gain must be one of: %d", keys) 321 return 322 }