tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/bmp180/bmp180.go (about) 1 // Package bmp180 provides a driver for the BMP180 digital pressure sensor 2 // by Bosch. 3 // 4 // Datasheet: 5 // https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf 6 package bmp180 // import "tinygo.org/x/drivers/bmp180" 7 8 import ( 9 "math" 10 "time" 11 12 "tinygo.org/x/drivers" 13 "tinygo.org/x/drivers/internal/legacy" 14 ) 15 16 // OversamplingMode is the oversampling ratio of the pressure measurement. 17 type OversamplingMode uint 18 19 // calibrationCoefficients reads at startup and stores the calibration coefficients 20 type calibrationCoefficients struct { 21 ac1 int16 22 ac2 int16 23 ac3 int16 24 ac4 uint16 25 ac5 uint16 26 ac6 uint16 27 b1 int16 28 b2 int16 29 mb int16 30 mc int16 31 md int16 32 } 33 34 // Device wraps an I2C connection to a BMP180 device. 35 type Device struct { 36 bus drivers.I2C 37 Address uint16 38 mode OversamplingMode 39 calibrationCoefficients calibrationCoefficients 40 } 41 42 // New creates a new BMP180 connection. The I2C bus must already be 43 // configured. 44 // 45 // This function only creates the Device object, it does not initialize the device. 46 // You must call Configure() first in order to use the device itself. 47 func New(bus drivers.I2C) Device { 48 return Device{ 49 bus: bus, 50 Address: Address, 51 mode: ULTRAHIGHRESOLUTION, 52 } 53 } 54 55 // Connected returns whether a BMP180 has been found. 56 // It does a "who am I" request and checks the response. 57 func (d *Device) Connected() bool { 58 data := []byte{0} 59 legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data) 60 return data[0] == CHIP_ID 61 } 62 63 // Configure sets up the device for communication and 64 // read the calibration coefficients. 65 func (d *Device) Configure() { 66 data := make([]byte, 22) 67 err := legacy.ReadRegister(d.bus, uint8(d.Address), AC1_MSB, data) 68 if err != nil { 69 return 70 } 71 d.calibrationCoefficients.ac1 = readInt(data[0], data[1]) 72 d.calibrationCoefficients.ac2 = readInt(data[2], data[3]) 73 d.calibrationCoefficients.ac3 = readInt(data[4], data[5]) 74 d.calibrationCoefficients.ac4 = readUint(data[6], data[7]) 75 d.calibrationCoefficients.ac5 = readUint(data[8], data[9]) 76 d.calibrationCoefficients.ac6 = readUint(data[10], data[11]) 77 d.calibrationCoefficients.b1 = readInt(data[12], data[13]) 78 d.calibrationCoefficients.b2 = readInt(data[14], data[15]) 79 d.calibrationCoefficients.mb = readInt(data[16], data[17]) 80 d.calibrationCoefficients.mc = readInt(data[18], data[19]) 81 d.calibrationCoefficients.md = readInt(data[20], data[21]) 82 } 83 84 // ReadTemperature returns the temperature in celsius milli degrees (°C/1000). 85 func (d *Device) ReadTemperature() (temperature int32, err error) { 86 rawTemp, err := d.rawTemp() 87 if err != nil { 88 return 89 } 90 b5 := d.calculateB5(rawTemp) 91 t := (b5 + 8) >> 4 92 return 100 * t, nil 93 } 94 95 // ReadPressure returns the pressure in milli pascals (mPa). 96 func (d *Device) ReadPressure() (pressure int32, err error) { 97 rawTemp, err := d.rawTemp() 98 if err != nil { 99 return 100 } 101 rawPressure, err := d.rawPressure(d.mode) 102 if err != nil { 103 return 104 } 105 b5 := d.calculateB5(rawTemp) 106 b6 := b5 - 4000 107 x1 := (int32(d.calibrationCoefficients.b2) * (b6 * b6 >> 12)) >> 11 108 x2 := (int32(d.calibrationCoefficients.ac2) * b6) >> 11 109 x3 := x1 + x2 110 b3 := (((int32(d.calibrationCoefficients.ac1)*4 + x3) << uint(d.mode)) + 2) >> 2 111 x1 = (int32(d.calibrationCoefficients.ac3) * b6) >> 13 112 x2 = (int32(d.calibrationCoefficients.b1) * ((b6 * b6) >> 12)) >> 16 113 x3 = ((x1 + x2) + 2) >> 2 114 b4 := (uint32(d.calibrationCoefficients.ac4) * uint32(x3+32768)) >> 15 115 b7 := uint32(rawPressure-b3) * (50000 >> uint(d.mode)) 116 var p int32 117 if b7 < 0x80000000 { 118 p = int32((b7 << 1) / b4) 119 } else { 120 p = int32((b7 / b4) << 1) 121 } 122 x1 = (p >> 8) * (p >> 8) 123 x1 = (x1 * 3038) >> 16 124 x2 = (-7357 * p) >> 16 125 return 1000 * (p + ((x1 + x2 + 3791) >> 4)), nil 126 } 127 128 // ReadAltitude returns the current altitude in meters based on the 129 // current barometric pressure and estimated pressure at sea level. 130 // Calculation is based on code from Adafruit BME280 library 131 // 132 // https://github.com/adafruit/Adafruit_BME280_Library 133 func (d *Device) ReadAltitude() (int32, error) { 134 mPa, err := d.ReadPressure() 135 if err != nil { 136 return 0, err 137 } 138 atmP := float32(mPa) / 100000 139 140 return int32(44330.0 * (1.0 - math.Pow(float64(atmP/SEALEVEL_PRESSURE), 0.1903))), nil 141 } 142 143 // rawTemp returns the sensor's raw values of the temperature 144 func (d *Device) rawTemp() (int32, error) { 145 legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_TEMP}) 146 time.Sleep(5 * time.Millisecond) 147 data := make([]byte, 2) 148 err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_TEMP_MSB, data) 149 if err != nil { 150 return 0, err 151 } 152 return int32(uint16(data[0])<<8 | uint16(data[1])), nil 153 } 154 155 // calculateB5 calculates intermediate value B5 as per page 15 of datasheet 156 func (d *Device) calculateB5(rawTemp int32) int32 { 157 x1 := (rawTemp - int32(d.calibrationCoefficients.ac6)) * int32(d.calibrationCoefficients.ac5) >> 15 158 x2 := int32(d.calibrationCoefficients.mc) << 11 / (x1 + int32(d.calibrationCoefficients.md)) 159 return x1 + x2 160 } 161 162 // rawPressure returns the sensor's raw values of the pressure 163 func (d *Device) rawPressure(mode OversamplingMode) (int32, error) { 164 legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)}) 165 time.Sleep(pauseForReading(mode)) 166 data := make([]byte, 3) 167 err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_PRESSURE_MSB, data) 168 if err != nil { 169 return 0, err 170 } 171 rawPressure := int32((uint32(data[0])<<16 + uint32(data[1])<<8 + uint32(data[2])) >> (8 - uint(mode))) 172 return rawPressure, nil 173 } 174 175 // pauseForReading returns the pause duration depending on the sampling mode 176 func pauseForReading(mode OversamplingMode) time.Duration { 177 var d time.Duration 178 switch mode { 179 case ULTRALOWPOWER: 180 d = 5 * time.Millisecond 181 case STANDARD: 182 d = 8 * time.Millisecond 183 case HIGHRESOLUTION: 184 d = 14 * time.Millisecond 185 case ULTRAHIGHRESOLUTION: 186 d = 26 * time.Millisecond 187 } 188 return d 189 } 190 191 // readInt converts two bytes to int16 192 func readInt(msb byte, lsb byte) int16 { 193 return int16(uint16(msb)<<8 | uint16(lsb)) 194 } 195 196 // readUint converts two bytes to uint16 197 func readUint(msb byte, lsb byte) uint16 { 198 return (uint16(msb) << 8) | uint16(lsb) 199 }