-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbarometer.cpp
More file actions
89 lines (79 loc) · 4.1 KB
/
Copy pathbarometer.cpp
File metadata and controls
89 lines (79 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "barometer.h"
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_DPS310.h>
static Adafruit_DPS310 dps;
// The part's operating range, from Adafruit_DPS310_Pressure::getSensor().
static const float DPS310_MIN_HPA = 300.0f;
static const float DPS310_MAX_HPA = 1200.0f;
// begin_I2C() leaves the DPS310 at 64 Hz / 64x oversampling and the part cannot
// actually run that. One conversion costs 20 + 16 * oversampling tenths of a
// millisecond - the datasheet formula, spelled out in Infineon's own driver as
// calcBusyTime() - so 64x is 104 ms, and continuous mode alternates pressure
// with temperature, which puts fresh pressure roughly 210 ms apart. Polled from
// a 20 ms control loop that is one poll in ten, and initSensors() averages one
// or two samples for its ground reference instead of the sixteen it asks for.
//
// 8x converts in 14.8 ms, so 32 Hz sits at about half the part's duty budget,
// and temperature only feeds the pressure compensation and barely moves, so it
// drops to 8 Hz at 1x. The cost is pressure noise, which sensors.cpp already
// low-passes; the gain is ~90 ms of lag out of a loop that differentiates
// altitude to get climb rate.
static const dps310_rate_t PRESSURE_RATE = DPS310_32HZ;
static const dps310_oversample_t PRESSURE_OVERSAMPLE = DPS310_8SAMPLES;
static const dps310_rate_t TEMPERATURE_RATE = DPS310_8HZ;
static const dps310_oversample_t TEMPERATURE_OVERSAMPLE = DPS310_1SAMPLE;
// There is deliberately no "wait for the first sample" loop in here. It looks
// like the obvious guard and it would be dead code: begin_I2C() cannot return
// true until _init()'s own wait has seen MEAS_CFG's PRS_RDY set, and none of the
// four calls after it read PRS_B2..B0, which is the only thing that clears the
// bit. A poll would exit on its first iteration on the flag left behind by the
// 64x conversion _init() already blocked for - it would report "the part
// converts" while proving nothing about the settings we just wrote.
//
// The case it looks like it catches - a chip that converts once and then quits -
// is caught a layer up instead, and caught properly: initSensors() averages
// sixteen reads for its ground reference and clears baroUp if none of them land
// (sensors.cpp), so a part that stopped gets about 320 ms to prove otherwise and
// the aircraft refuses to arm when it does not.
bool initBarometer() {
Wire.begin();
// Caveat on the no-hang rule: Adafruit_DPS310::_init() spins in its own
// unbounded `while (!temperatureAvailable() || !pressureAvailable())`, so
// begin_I2C() can still sit here forever. Bounding that would mean
// vendoring the library. Nothing this function adds can block.
if (!dps.begin_I2C()) {
Serial.println("DPS310 did not answer on I2C");
return false;
}
dps.setMode(DPS310_IDLE);
dps.configurePressure(PRESSURE_RATE, PRESSURE_OVERSAMPLE);
dps.configureTemperature(TEMPERATURE_RATE, TEMPERATURE_OVERSAMPLE);
dps.setMode(DPS310_CONT_PRESTEMP);
return true;
}
// Adafruit_DPS310::getEvents() ends in an unconditional `return true;` - it
// hands back whatever _read() last left in the object, so on its own it cannot
// tell a live chip from one that stopped answering. The two checks around it are
// what make a bad read detectable:
//
// pressureAvailable() is the MEAS_CFG "new pressure data" bit. The sensor
// converts at 32 Hz against a 50 Hz poll, so this is clear on roughly a third
// of calls in normal flight - a false return means "nothing new this cycle",
// not "the barometer is broken".
//
// The range is the DPS310's own operating span, 300..1200 hPa, straight out of
// the library's getSensor() bounds. Garbage off a dead I2C bus lands outside it.
bool readBarometer(float *pressure_hPa) {
if (!dps.pressureAvailable()) {
return false;
}
sensors_event_t temp_event, pressure_event;
dps.getEvents(&temp_event, &pressure_event);
float pressure = pressure_event.pressure;
if (!(pressure >= DPS310_MIN_HPA && pressure <= DPS310_MAX_HPA)) {
return false; // the >= form also rejects NaN
}
*pressure_hPa = pressure;
return true;
}