tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/bmp280/bmp280.go (about) 1 package bmp280 2 3 import ( 4 "time" 5 6 "tinygo.org/x/drivers" 7 "tinygo.org/x/drivers/internal/legacy" 8 ) 9 10 // OversamplingMode is the oversampling ratio of the temperature or pressure measurement. 11 type Oversampling uint 12 13 // Mode is the Power Mode. 14 type Mode uint 15 16 // Standby is the inactive period between the reads when the sensor is in normal power mode. 17 type Standby uint 18 19 // Filter unwanted changes in measurement caused by external (environmental) or internal changes (IC). 20 type Filter uint 21 22 // Device wraps an I2C connection to a BMP280 device. 23 type Device struct { 24 bus drivers.I2C 25 Address uint16 26 cali calibrationCoefficients 27 Temperature Oversampling 28 Pressure Oversampling 29 Mode Mode 30 Standby Standby 31 Filter Filter 32 } 33 34 type calibrationCoefficients struct { 35 // Temperature compensation 36 t1 uint16 37 t2 int16 38 t3 int16 39 40 // Pressure compensation 41 p1 uint16 42 p2 int16 43 p3 int16 44 p4 int16 45 p5 int16 46 p6 int16 47 p7 int16 48 p8 int16 49 p9 int16 50 } 51 52 // New creates a new BMP280 connection. The I2C bus must already be 53 // configured. 54 // 55 // This function only creates the Device object, it does not initialize the device. 56 // You must call Configure() first in order to use the device itself. 57 func New(bus drivers.I2C) Device { 58 return Device{ 59 bus: bus, 60 Address: Address, 61 } 62 } 63 64 // Connected returns whether a BMP280 has been found. 65 // It does a "who am I" request and checks the response. 66 func (d *Device) Connected() bool { 67 data := make([]byte, 1) 68 legacy.ReadRegister(d.bus, uint8(d.Address), REG_ID, data) 69 return data[0] == CHIP_ID 70 } 71 72 // Reset preforms complete power-on-reset procedure. 73 // It is required to call Configure afterwards. 74 func (d *Device) Reset() { 75 legacy.WriteRegister(d.bus, uint8(d.Address), REG_RESET, []byte{CMD_RESET}) 76 } 77 78 // Configure sets up the device for communication and 79 // read the calibration coefficients. 80 func (d *Device) Configure(standby Standby, filter Filter, temp Oversampling, pres Oversampling, mode Mode) { 81 d.Standby = standby 82 d.Filter = filter 83 d.Temperature = temp 84 d.Pressure = pres 85 d.Mode = mode 86 87 // Write the configuration (standby, filter, spi 3 wire) 88 config := uint(d.Standby<<5) | uint(d.Filter<<2) | 0x00 89 legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONFIG, []byte{byte(config)}) 90 91 // Write the control (temperature oversampling, pressure oversampling, 92 config = uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(d.Mode) 93 legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)}) 94 95 // Read Calibration data 96 data := make([]byte, 24) 97 err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALI, data) 98 if err != nil { 99 return 100 } 101 102 // Datasheet: 3.11.2 Trimming parameter readout 103 d.cali.t1 = readUintLE(data[0], data[1]) 104 d.cali.t2 = readIntLE(data[2], data[3]) 105 d.cali.t3 = readIntLE(data[4], data[5]) 106 107 d.cali.p1 = readUintLE(data[6], data[7]) 108 d.cali.p2 = readIntLE(data[8], data[9]) 109 d.cali.p3 = readIntLE(data[10], data[11]) 110 d.cali.p4 = readIntLE(data[12], data[13]) 111 d.cali.p5 = readIntLE(data[14], data[15]) 112 d.cali.p6 = readIntLE(data[16], data[17]) 113 d.cali.p7 = readIntLE(data[18], data[19]) 114 d.cali.p8 = readIntLE(data[20], data[21]) 115 d.cali.p9 = readIntLE(data[22], data[23]) 116 } 117 118 // PrintCali prints the Calibration information. 119 func (d *Device) PrintCali() { 120 println("T1:", d.cali.t1) 121 println("T2:", d.cali.t2) 122 println("T3:", d.cali.t3) 123 124 println("P1:", d.cali.p1) 125 println("P2:", d.cali.p2) 126 println("P3:", d.cali.p3) 127 println("P4:", d.cali.p4) 128 println("P5:", d.cali.p5) 129 println("P6:", d.cali.p6) 130 println("P7:", d.cali.p7) 131 println("P8:", d.cali.p8) 132 println("P9:", d.cali.p9, "\n") 133 } 134 135 // ReadTemperature returns the temperature in celsius milli degrees (°C/1000). 136 func (d *Device) ReadTemperature() (temperature int32, err error) { 137 data, err := d.readData(REG_TEMP, 3) 138 if err != nil { 139 return 140 } 141 142 rawTemp := convert3Bytes(data[0], data[1], data[2]) 143 144 // Datasheet: 8.2 Compensation formula in 32 bit fixed point 145 // Temperature compensation 146 var1 := ((rawTemp >> 3) - int32(d.cali.t1<<1)) * int32(d.cali.t2) >> 11 147 var2 := (((rawTemp >> 4) - int32(d.cali.t1)) * ((rawTemp >> 4) - int32(d.cali.t1)) >> 12) * 148 int32(d.cali.t3) >> 14 149 150 tFine := var1 + var2 151 152 // Convert from degrees to milli degrees by multiplying by 10. 153 // Will output 30250 milli degrees celsius for 30.25 degrees celsius 154 temperature = 10 * ((tFine*5 + 128) >> 8) 155 return 156 } 157 158 // ReadPressure returns the pressure in milli pascals (mPa). 159 func (d *Device) ReadPressure() (pressure int32, err error) { 160 // First 3 bytes are Pressure, last 3 bytes are Temperature 161 data, err := d.readData(REG_PRES, 6) 162 if err != nil { 163 return 164 } 165 166 rawTemp := convert3Bytes(data[3], data[4], data[5]) 167 168 // Datasheet: 8.2 Compensation formula in 32 bit fixed point 169 // Calculate tFine (temperature), used for the Pressure compensation 170 var1 := ((rawTemp >> 3) - int32(d.cali.t1<<1)) * int32(d.cali.t2) >> 11 171 var2 := (((rawTemp >> 4) - int32(d.cali.t1)) * ((rawTemp >> 4) - int32(d.cali.t1)) >> 12) * 172 int32(d.cali.t3) >> 14 173 174 tFine := var1 + var2 175 176 rawPres := convert3Bytes(data[0], data[1], data[2]) 177 178 // Datasheet: 8.2 Compensation formula in 32 bit fixed point 179 // Pressure compensation 180 var1 = (tFine >> 1) - 64000 181 var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * int32(d.cali.p6) 182 var2 = var2 + ((var1 * int32(d.cali.p5)) << 1) 183 var2 = (var2 >> 2) + (int32(d.cali.p4) << 16) 184 var1 = (((int32(d.cali.p3) * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + 185 ((int32(d.cali.p2) * var1) >> 1)) >> 18 186 var1 = ((32768 + var1) * int32(d.cali.p1)) >> 15 187 188 if var1 == 0 { 189 return 0, nil 190 } 191 192 p := uint32(((1048576 - rawPres) - (var2 >> 12)) * 3125) 193 if p < 0x80000000 { 194 p = (p << 1) / uint32(var1) 195 } else { 196 p = (p / uint32(var1)) * 2 197 } 198 199 var1 = (int32(d.cali.p9) * int32(((p>>3)*(p>>3))>>13)) >> 12 200 var2 = (int32(p>>2) * int32(d.cali.p8)) >> 13 201 202 return 1000 * (int32(p) + ((var1 + var2 + int32(d.cali.p7)) >> 4)), nil 203 } 204 205 // readData reads n number of bytes of the specified register 206 func (d *Device) readData(register int, n int) ([]byte, error) { 207 // If not in normal mode, set the mode to FORCED mode, to prevent incorrect measurements 208 // After the measurement in FORCED mode, the sensor will return to SLEEP mode 209 if d.Mode != MODE_NORMAL { 210 config := uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(MODE_FORCED) 211 legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)}) 212 } 213 214 // Check STATUS register, wait if data is not available yet 215 status := make([]byte, 1) 216 for legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]) { 217 time.Sleep(time.Millisecond) 218 } 219 220 // Read the requested register 221 data := make([]byte, n) 222 err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:]) 223 return data, err 224 } 225 226 // convert3Bytes converts three bytes to int32 227 func convert3Bytes(msb byte, b1 byte, lsb byte) int32 { 228 return int32(((((uint32(msb) << 8) | uint32(b1)) << 8) | uint32(lsb)) >> 4) 229 } 230 231 // readUint converts two bytes to uint16 232 func readUint(msb byte, lsb byte) uint16 { 233 return (uint16(msb) << 8) | uint16(lsb) 234 } 235 236 // readUintLE converts two little endian bytes to uint16 237 func readUintLE(msb byte, lsb byte) uint16 { 238 temp := readUint(msb, lsb) 239 return (temp >> 8) | (temp << 8) 240 } 241 242 // readIntLE converts two little endian bytes to int16 243 func readIntLE(msb byte, lsb byte) int16 { 244 return int16(readUintLE(msb, lsb)) 245 }