tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/lis2mdl/lis2mdl.go (about) 1 // Package lis2mdl implements a driver for the LIS2MDL, 2 // a magnetic sensor which is included on BBC micro:bit v1.5. 3 // 4 // Datasheet: https://www.st.com/resource/en/datasheet/lis2mdl.pdf 5 package lis2mdl // import "tinygo.org/x/drivers/lis2mdl" 6 7 import ( 8 "math" 9 "time" 10 11 "tinygo.org/x/drivers" 12 "tinygo.org/x/drivers/internal/legacy" 13 ) 14 15 // Device wraps an I2C connection to a LIS2MDL device. 16 type Device struct { 17 bus drivers.I2C 18 Address uint8 19 PowerMode uint8 20 SystemMode uint8 21 DataRate uint8 22 } 23 24 // Configuration for LIS2MDL device. 25 type Configuration struct { 26 PowerMode uint8 27 SystemMode uint8 28 DataRate uint8 29 } 30 31 // New creates a new LIS2MDL connection. The I2C bus must already be 32 // configured. 33 // 34 // This function only creates the Device object, it does not touch the device. 35 func New(bus drivers.I2C) Device { 36 return Device{bus: bus, Address: ADDRESS} 37 } 38 39 // Connected returns whether LIS2MDL sensor has been found. 40 func (d *Device) Connected() bool { 41 data := []byte{0} 42 legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data) 43 return data[0] == 0x40 44 } 45 46 // Configure sets up the LIS2MDL device for communication. 47 func (d *Device) Configure(cfg Configuration) { 48 if cfg.PowerMode != 0 { 49 d.PowerMode = cfg.PowerMode 50 } else { 51 d.PowerMode = POWER_NORMAL 52 } 53 54 if cfg.DataRate != 0 { 55 d.DataRate = cfg.DataRate 56 } else { 57 d.DataRate = DATARATE_100HZ 58 } 59 60 if cfg.SystemMode != 0 { 61 d.SystemMode = cfg.SystemMode 62 } else { 63 d.SystemMode = SYSTEM_CONTINUOUS 64 } 65 66 cmd := []byte{0} 67 68 // reset 69 cmd[0] = byte(1 << 5) 70 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd) 71 time.Sleep(100 * time.Millisecond) 72 73 // reboot 74 cmd[0] = byte(1 << 6) 75 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd) 76 time.Sleep(100 * time.Millisecond) 77 78 // bdu 79 cmd[0] = byte(1 << 4) 80 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_C, cmd) 81 82 // Temperature compensation is on for magnetic sensor (0x80) 83 cmd[0] = byte(0x80) 84 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd) 85 86 // speed 87 cmd[0] = byte(0x80 | d.DataRate) 88 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd) 89 } 90 91 // ReadMagneticField reads the current magnetic field from the device and returns 92 // it in mG (milligauss). 1 mG = 0.1 µT (microtesla). 93 func (d *Device) ReadMagneticField() (x int32, y int32, z int32) { 94 // turn back on read mode, even though it is supposed to be continuous? 95 cmd := []byte{0} 96 cmd[0] = byte(0x80 | d.PowerMode<<4 | d.DataRate<<2 | d.SystemMode) 97 legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd) 98 time.Sleep(10 * time.Millisecond) 99 100 data := make([]byte, 6) 101 legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_REG, data) 102 103 x = int32(int16((uint16(data[0]) << 8) | uint16(data[1]))) 104 y = int32(int16((uint16(data[2]) << 8) | uint16(data[3]))) 105 z = int32(int16((uint16(data[4]) << 8) | uint16(data[5]))) 106 107 return 108 } 109 110 // ReadCompass reads the current compass heading from the device and returns 111 // it in degrees. When the z axis is pointing straight to Earth and 112 // the y axis is pointing to North, the heading would be zero. 113 // 114 // However, the heading may be off due to electronic compasses would be effected 115 // by strong magnetic fields and require constant calibration. 116 func (d *Device) ReadCompass() (h int32) { 117 x, y, _ := d.ReadMagneticField() 118 xf, yf := float64(x)*0.15, float64(y)*0.15 119 120 rh := (math.Atan2(yf, xf) * 180) / math.Pi 121 if rh < 0 { 122 rh = 360 + rh 123 } 124 125 return int32(rh) 126 }