Class: Denko::Sensor::QMP6988
- Inherits:
-
Object
- Object
- Denko::Sensor::QMP6988
- Includes:
- Behaviors::Poller, I2C::Peripheral
- Defined in:
- lib/denko/sensor/qmp6988.rb
Constant Summary collapse
- UPDATE_TIME =
0.020
- RESET_REGISTER =
0xE0
- RESET_COMMAND =
0xE6
- CTRL_MEAS_REGISTER =
0xF4
- STANDBY_TIME_REGISTER =
0xF5
- IIR_REGISTER =
0xF1
- CONFIG_LENGTH =
5
- DATA_REGISTER =
0xF7
- DATA_LENGTH =
6
- CALIBRATION_REGISTER =
0xA0
- CALIBRATION_LENGTH =
25
- CHIP_ID_REGISTER =
0xD1
- CHIP_ID_LENGTH =
1
- FORCED_MODE =
0b01
- NORMAL_MODE =
0b11
- STANDBY_TIMES =
Standby Times for Normal (Continuous) Mode in milliseconds
{ 1 => 0b000, 5 => 0b001, 50 => 0b010, 250 => 0b011, 500 => 0b100, 1000 => 0b101, 2000 => 0b110, 4000 => 0b111, }
- OVERSAMPLE_FACTORS =
Oversample Setting Values Note: Each sensor has a separate oversample setting.
General formula:
2 ** (n-1), where n is the decimal value of the bits, up to 16x max oversampling.
{ # 0 => 0b000, # Sensor skipped. Value will be 0x800000. 1 => 0b001, 2 => 0b010, 4 => 0b011, 8 => 0b100, 16 => 0b101, 32 => 0b110, 64 => 0b111, }
- TEMPERATURE_SAMPLE_TIME =
Single sample times (in milliseconds) for each sensor, derived from datasheet examples.
0.9
- PRESSURE_SAMPLE_TIME =
0.85
- IIR_COEFFICIENTS =
IIR Filter Coefficients
{ 0 => 0b000, 2 => 0b001, 4 => 0b010, 8 => 0b011, 16 => 0b100, 32 => 0b101, # 0b110 and 0b111 are also valid for 16. }
- CONVERSION_FACTORS =
{ a1: { A: -6.3e-03, S: 4.3e-04 }, a2: { A: -1.9e-11, S: 1.2e-10 }, bt1: { A: 1.0e-01, S: 9.1e-02 }, bt2: { A: 1.2e-08, S: 1.2e-06 }, bp1: { A: 3.3e-02, S: 1.9e-02 }, b11: { A: 2.1e-07, S: 1.4e-07 }, bp2: { A: -6.3e-10, S: 3.5e-10 }, b12: { A: 2.9e-13, S: 7.6e-13 }, b21: { A: 2.1e-15, S: 1.2e-14 }, bp3: { A: 1.3e-16, S: 7.9e-17 }, a0: 16.0, b00: 16.0, }
Instance Attribute Summary collapse
-
#calibration_data_loaded ⇒ Object
readonly
Calibration.
-
#iir_coefficient ⇒ Object
Returns the value of attribute iir_coefficient.
-
#pressure_samples ⇒ Object
Returns the value of attribute pressure_samples.
-
#registers ⇒ Object
readonly
Returns the value of attribute registers.
-
#standby_time ⇒ Object
Returns the value of attribute standby_time.
-
#temperature_samples ⇒ Object
Returns the value of attribute temperature_samples.
Attributes included from Behaviors::Threaded
Attributes included from Behaviors::Callbacks
Attributes included from I2C::Peripheral
#i2c_frequency, #i2c_repeated_start
Attributes included from Behaviors::BusPeripheral
Attributes included from Behaviors::Component
Instance Method Summary collapse
-
#_read ⇒ Object
Reading & Processing.
- #after_initialize(options = {}) ⇒ Object
- #before_initialize(options = {}) ⇒ Object
- #calculate_measurement_time ⇒ Object
- #chip_id ⇒ Object
- #continuous_mode ⇒ Object
- #forced_mode ⇒ Object
- #get_calibration_data ⇒ Object
- #get_config_registers ⇒ Object
- #pre_callback_filter(bytes) ⇒ Object
- #process_calibration(bytes) ⇒ Object
- #process_config(bytes) ⇒ Object
- #process_reading(bytes) ⇒ Object
-
#reset ⇒ Object
Configuration Methods.
- #update_state(reading) ⇒ Object
Methods included from Behaviors::Poller
Methods included from Behaviors::Threaded
#enable_interrupts, included, #stop, #stop_thread, #threaded, #threaded_loop
Methods included from Behaviors::Reader
#read, #read_using, #wait_for_read
Methods included from Behaviors::Callbacks
#add_callback, #callbacks, #initialize, #remove_callback, #update
Methods included from Behaviors::State
Methods included from I2C::Peripheral
Methods included from Behaviors::BusPeripheral
Methods included from Behaviors::Component
Instance Attribute Details
#calibration_data_loaded ⇒ Object (readonly)
Calibration
245 246 247 |
# File 'lib/denko/sensor/qmp6988.rb', line 245 def calibration_data_loaded @calibration_data_loaded end |
#iir_coefficient ⇒ Object
Returns the value of attribute iir_coefficient.
111 112 113 |
# File 'lib/denko/sensor/qmp6988.rb', line 111 def iir_coefficient @iir_coefficient end |
#pressure_samples ⇒ Object
Returns the value of attribute pressure_samples.
140 141 142 |
# File 'lib/denko/sensor/qmp6988.rb', line 140 def pressure_samples @pressure_samples end |
#registers ⇒ Object (readonly)
Returns the value of attribute registers.
240 241 242 |
# File 'lib/denko/sensor/qmp6988.rb', line 240 def registers @registers end |
#standby_time ⇒ Object
Returns the value of attribute standby_time.
120 121 122 |
# File 'lib/denko/sensor/qmp6988.rb', line 120 def standby_time @standby_time end |
#temperature_samples ⇒ Object
Returns the value of attribute temperature_samples.
130 131 132 |
# File 'lib/denko/sensor/qmp6988.rb', line 130 def temperature_samples @temperature_samples end |
Instance Method Details
#_read ⇒ Object
Reading & Processing
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/denko/sensor/qmp6988.rb', line 173 def _read if @forced_mode # Write CTRL_MEAS register to trigger reading, then wait for measurement. i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register] sleep @measurement_time end # Read the data bytes. i2c_read(DATA_REGISTER, DATA_LENGTH) end |
#after_initialize(options = {}) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/denko/sensor/qmp6988.rb', line 72 def after_initialize(={}) super() # Avoid repeated memory allocation for callback data and state. @reading = { temperature: nil, pressure: nil } self.state = { temperature: nil, pressure: nil } reset # Get 5 config registers. Copy 0xF4 to modify it for control. get_config_registers @ctrl_meas_register = @registers[:f4].dup # Default settings self.iir_coefficient = 0 self.temperature_samples = 1 self.pressure_samples = 1 self.forced_mode # self.forced mode triggered an initial measurement so IIR works properly if enabled. # Wait for those values to enter the data registers, but don't read them back. sleep @measurement_time get_calibration_data end |
#before_initialize(options = {}) ⇒ Object
67 68 69 70 |
# File 'lib/denko/sensor/qmp6988.rb', line 67 def before_initialize(={}) @i2c_address = 0x70 super() end |
#calculate_measurement_time ⇒ Object
142 143 144 145 146 147 |
# File 'lib/denko/sensor/qmp6988.rb', line 142 def calculate_measurement_time @measurement_time = (@temperature_samples.to_i * TEMPERATURE_SAMPLE_TIME) + (@pressure_samples.to_i * PRESSURE_SAMPLE_TIME) # Add 5ms for safety and convert to seconds. @measurement_time = (@measurement_time + 5) * 0.001 end |
#chip_id ⇒ Object
163 164 165 166 167 168 |
# File 'lib/denko/sensor/qmp6988.rb', line 163 def chip_id return @chip_id if @chip_id i2c_read(CHIP_ID_REGISTER, 1) sleep 0.001 while !@chip_id @chip_id end |
#continuous_mode ⇒ Object
156 157 158 159 160 161 |
# File 'lib/denko/sensor/qmp6988.rb', line 156 def continuous_mode @ctrl_meas_register = (@ctrl_meas_register & 0b11111100) | NORMAL_MODE i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register] @forced_mode = false sleep UPDATE_TIME end |
#forced_mode ⇒ Object
149 150 151 152 153 154 |
# File 'lib/denko/sensor/qmp6988.rb', line 149 def forced_mode @ctrl_meas_register = (@ctrl_meas_register & 0b11111100) | FORCED_MODE i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register] @forced_mode = true sleep UPDATE_TIME end |
#get_calibration_data ⇒ Object
262 263 264 |
# File 'lib/denko/sensor/qmp6988.rb', line 262 def get_calibration_data i2c_read(CALIBRATION_REGISTER, CALIBRATION_LENGTH) end |
#get_config_registers ⇒ Object
230 231 232 233 234 235 |
# File 'lib/denko/sensor/qmp6988.rb', line 230 def get_config_registers @registers = {} i2c_read(IIR_REGISTER, CONFIG_LENGTH) sleep 0.001 while @registers.empty? @registers end |
#pre_callback_filter(bytes) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/denko/sensor/qmp6988.rb', line 184 def pre_callback_filter(bytes) if bytes.length == DATA_LENGTH return process_reading(bytes) elsif bytes.length == CONFIG_LENGTH process_config(bytes) elsif bytes.length == CALIBRATION_LENGTH process_calibration(bytes) elsif bytes.length == CHIP_ID_LENGTH @chip_id = bytes[0] end return nil end |
#process_calibration(bytes) ⇒ Object
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/denko/sensor/qmp6988.rb', line 266 def process_calibration(bytes) if bytes # These 2 values are 20-bit instead of 16-bit, so can't combine them with #pack. a0_unsigned = (bytes[18] << 12) + (bytes[19] << 4) + (bytes[24] & 0b00001111) b00_unsigned = (bytes[0] << 12) + (bytes[1] << 4) + ((bytes[24] & 0b11110000) >> 4) # Cast the raw bytes as big-endian signed. @calibration_raw = { # Shift these to 32-bit before converting to signed, then reverse the shift after. a0: [(a0_unsigned << 12)].pack('L>').unpack('l>')[0] >> 12, b00: [(b00_unsigned << 12)].pack('L>').unpack('l>')[0] >> 12, a1: bytes[20..21].pack('C*').unpack('s>')[0], a2: bytes[22..23].pack('C*').unpack('s>')[0], b11: bytes[8..9].pack('C*').unpack('s>')[0], b12: bytes[12..13].pack('C*').unpack('s>')[0], b21: bytes[14..15].pack('C*').unpack('s>')[0], bp1: bytes[6..7].pack('C*').unpack('s>')[0], bp2: bytes[10..11].pack('C*').unpack('s>')[0], bp3: bytes[16..17].pack('C*').unpack('s>')[0], bt1: bytes[2..3].pack('C*').unpack('s>')[0], bt2: bytes[4..5].pack('C*').unpack('s>')[0], } # Use conversion formulae to calculate compensation coefficients, all as floats. @calibration = {} @calibration_raw.keys.each do |key| if CONVERSION_FACTORS[key].class == Float @calibration[key] = @calibration_raw[key] / CONVERSION_FACTORS[key] else @calibration[key] = CONVERSION_FACTORS[key][:A] + (CONVERSION_FACTORS[key][:S] * @calibration_raw[key] / 32767.0) end end @calibration_data_loaded = true end end |
#process_config(bytes) ⇒ Object
237 238 239 |
# File 'lib/denko/sensor/qmp6988.rb', line 237 def process_config(bytes) @registers = { f1: bytes[0], f2: bytes[1], f3: bytes[2], f4: bytes[3], f5: bytes[4] } end |
#process_reading(bytes) ⇒ Object
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/denko/sensor/qmp6988.rb', line 197 def process_reading(bytes) # Temperature and pressure are 24-bits long each, and need 2^23 subtracted. dt = ((bytes[3] << 16) + (bytes[4] << 8) + bytes[5]) - (0b1 << 23) dp = ((bytes[0] << 16) + (bytes[1] << 8) + bytes[2]) - (0b1 << 23) # Compensated temperature calculated in 1/256 of a degree Celsius. tr = @calibration[:a0] + @calibration[:a1] * dt + @calibration[:a2] * (dt ** 2) @reading[:temperature] = tr / 256.0 # Compensated pressure calculated in Pascals. @reading[:pressure] = @calibration[:b00] + @calibration[:bt1] * tr + @calibration[:bp1] * dp + @calibration[:b11] * (tr * dp) + @calibration[:bt2] * (tr ** 2) + @calibration[:bp2] * (dp ** 2) + @calibration[:b12] * (dp * (tr ** 2)) + @calibration[:b21] * ((dp ** 2) * tr) + @calibration[:bp3] * (dp ** 3) # Return reading for callbacks. @reading end |
#reset ⇒ Object
Configuration Methods
101 102 103 104 |
# File 'lib/denko/sensor/qmp6988.rb', line 101 def reset i2c_write [RESET_REGISTER, RESET_COMMAND] sleep UPDATE_TIME end |
#update_state(reading) ⇒ Object
223 224 225 226 227 228 |
# File 'lib/denko/sensor/qmp6988.rb', line 223 def update_state(reading) @state_mutex.synchronize do @state[:temperature] = reading[:temperature] @state[:pressure] = reading[:pressure] end end |