CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_Baro/AP_Baro_DPS280.cpp
Views: 1798
1
/*
2
This program is free software: you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation, either version 3 of the License, or
5
(at your option) any later version.
6
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
11
12
You should have received a copy of the GNU General Public License
13
along with this program. If not, see <http://www.gnu.org/licenses/>.
14
*/
15
/*
16
DPS280 barometer driver
17
*/
18
19
#include "AP_Baro_DPS280.h"
20
21
#if AP_BARO_DPS280_ENABLED
22
23
#include <utility>
24
#include <stdio.h>
25
#include <AP_Math/definitions.h>
26
27
extern const AP_HAL::HAL &hal;
28
29
#define DPS280_REG_PRESS 0x00
30
#define DPS280_REG_TEMP 0x03
31
#define DPS280_REG_PCONF 0x06
32
#define DPS280_REG_TCONF 0x07
33
#define DPS280_REG_MCONF 0x08
34
#define DPS280_REG_CREG 0x09
35
#define DPS280_REG_ISTS 0x0A
36
#define DPS280_REG_FSTS 0x0B
37
#define DPS280_REG_RESET 0x0C
38
#define DPS280_REG_PID 0x0D
39
#define DPS280_REG_COEF 0x10
40
#define DPS280_REG_CSRC 0x28
41
42
#define DPS280_WHOAMI 0x10
43
44
#define TEMPERATURE_LIMIT_C 120
45
46
AP_Baro_DPS280::AP_Baro_DPS280(AP_Baro &baro, AP_HAL::OwnPtr<AP_HAL::Device> _dev)
47
: AP_Baro_Backend(baro)
48
, dev(std::move(_dev))
49
{
50
}
51
52
AP_Baro_Backend *AP_Baro_DPS280::probe(AP_Baro &baro,
53
AP_HAL::OwnPtr<AP_HAL::Device> _dev, bool _is_dps310)
54
{
55
if (!_dev) {
56
return nullptr;
57
}
58
59
AP_Baro_DPS280 *sensor = NEW_NOTHROW AP_Baro_DPS280(baro, std::move(_dev));
60
if (sensor) {
61
sensor->is_dps310 = _is_dps310;
62
}
63
if (!sensor || !sensor->init(_is_dps310)) {
64
delete sensor;
65
return nullptr;
66
}
67
return sensor;
68
}
69
70
AP_Baro_Backend *AP_Baro_DPS310::probe(AP_Baro &baro,
71
AP_HAL::OwnPtr<AP_HAL::Device> _dev)
72
{
73
// same as DPS280 but with is_dps310 set for temperature fix
74
return AP_Baro_DPS280::probe(baro, std::move(_dev), true);
75
}
76
77
/*
78
handle bit width for 16 bit config registers
79
*/
80
void AP_Baro_DPS280::fix_config_bits16(int16_t &v, uint8_t bits) const
81
{
82
if (v > int16_t((1U<<(bits-1))-1)) {
83
v = v - (1U<<bits);
84
}
85
}
86
87
/*
88
handle bit width for 32 bit config registers
89
*/
90
void AP_Baro_DPS280::fix_config_bits32(int32_t &v, uint8_t bits) const
91
{
92
if (v > int32_t((1U<<(bits-1))-1)) {
93
v = v - (1U<<bits);
94
}
95
}
96
97
/*
98
read calibration data
99
*/
100
bool AP_Baro_DPS280::read_calibration(void)
101
{
102
uint8_t buf[18];
103
104
if (!dev->read_registers(DPS280_REG_COEF, buf, 18)) {
105
return false;
106
}
107
108
calibration.C0 = (buf[0] << 4) + ((buf[1] >>4) & 0x0F);
109
calibration.C1 = (buf[2] + ((buf[1] & 0x0F)<<8));
110
calibration.C00 = ((buf[4]<<4) + (buf[3]<<12)) + ((buf[5]>>4) & 0x0F);
111
calibration.C10 = ((buf[5] & 0x0F)<<16) + buf[7] + (buf[6]<<8);
112
calibration.C01 = (buf[9] + (buf[8]<<8));
113
calibration.C11 = (buf[11] + (buf[10]<<8));
114
calibration.C20 = (buf[13] + (buf[12]<<8));
115
calibration.C21 = (buf[15] + (buf[14]<<8));
116
calibration.C30 = (buf[17] + (buf[16]<<8));
117
118
fix_config_bits16(calibration.C0, 12);
119
fix_config_bits16(calibration.C1, 12);
120
fix_config_bits32(calibration.C00, 20);
121
fix_config_bits32(calibration.C10, 20);
122
fix_config_bits16(calibration.C01, 16);
123
fix_config_bits16(calibration.C11, 16);
124
fix_config_bits16(calibration.C20, 16);
125
fix_config_bits16(calibration.C21, 16);
126
fix_config_bits16(calibration.C30, 16);
127
128
/* get calibration source */
129
if (!dev->read_registers(DPS280_REG_CSRC, &calibration.temp_source, 1)) {
130
return false;
131
}
132
calibration.temp_source &= 0x80;
133
134
return true;
135
}
136
137
void AP_Baro_DPS280::set_config_registers(void)
138
{
139
dev->write_register(DPS280_REG_CREG, 0x0C, true); // shift for 16x oversampling
140
dev->write_register(DPS280_REG_PCONF, 0x54, true); // 32 Hz, 16x oversample
141
dev->write_register(DPS280_REG_TCONF, 0x54 | calibration.temp_source, true); // 32 Hz, 16x oversample
142
dev->write_register(DPS280_REG_MCONF, 0x07); // continuous temp and pressure.
143
144
if (is_dps310) {
145
// work around broken temperature handling on some sensors
146
// using undocumented register writes
147
// see https://github.com/infineon/DPS310-Pressure-Sensor/blob/dps310/src/DpsClass.cpp#L442
148
dev->write_register(0x0E, 0xA5);
149
dev->write_register(0x0F, 0x96);
150
dev->write_register(0x62, 0x02);
151
dev->write_register(0x0E, 0x00);
152
dev->write_register(0x0F, 0x00);
153
}
154
}
155
156
bool AP_Baro_DPS280::init(bool _is_dps310)
157
{
158
if (!dev) {
159
return false;
160
}
161
dev->get_semaphore()->take_blocking();
162
163
// setup to allow reads on SPI
164
if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {
165
dev->set_read_flag(0x80);
166
}
167
168
dev->set_speed(AP_HAL::Device::SPEED_HIGH);
169
170
// the DPS310 can get into a state on boot where the whoami is not
171
// read correctly at startup. Toggling the CS line gets its out of
172
// this state
173
dev->set_chip_select(true);
174
dev->set_chip_select(false);
175
176
uint8_t whoami=0;
177
if (!dev->read_registers(DPS280_REG_PID, &whoami, 1) ||
178
whoami != DPS280_WHOAMI) {
179
dev->get_semaphore()->give();
180
return false;
181
}
182
183
if (!read_calibration()) {
184
dev->get_semaphore()->give();
185
return false;
186
}
187
188
dev->setup_checked_registers(4, 20);
189
190
set_config_registers();
191
192
instance = _frontend.register_sensor();
193
if(_is_dps310) {
194
dev->set_device_type(DEVTYPE_BARO_DPS310);
195
} else {
196
dev->set_device_type(DEVTYPE_BARO_DPS280);
197
}
198
set_bus_id(instance, dev->get_bus_id());
199
200
dev->get_semaphore()->give();
201
202
// request 64Hz update. New data will be available at 32Hz
203
dev->register_periodic_callback((1000 / 64) * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_DPS280::timer, void));
204
205
return true;
206
}
207
208
/*
209
calculate corrected pressure and temperature
210
*/
211
void AP_Baro_DPS280::calculate_PT(int32_t UT, int32_t UP, float &pressure, float &temperature)
212
{
213
const struct dps280_cal &cal = calibration;
214
// scaling for 16x oversampling
215
const float scaling_16 = 1.0f/253952;
216
217
float temp_scaled;
218
float press_scaled;
219
220
temp_scaled = float(UT) * scaling_16;
221
temperature = cal.C0 * 0.5f + cal.C1 * temp_scaled;
222
223
press_scaled = float(UP) * scaling_16;
224
225
pressure = cal.C00;
226
pressure += press_scaled * (cal.C10 + press_scaled * (cal.C20 + press_scaled * cal.C30));
227
pressure += temp_scaled * cal.C01;
228
pressure += temp_scaled * press_scaled * (cal.C11 + press_scaled * cal.C21);
229
}
230
231
/*
232
check health and possibly reset
233
*/
234
void AP_Baro_DPS280::check_health(void)
235
{
236
dev->check_next_register();
237
238
if (fabsf(last_temperature) > TEMPERATURE_LIMIT_C) {
239
err_count++;
240
}
241
if (err_count > 16) {
242
err_count = 0;
243
dev->write_register(DPS280_REG_RESET, 0x09);
244
set_config_registers();
245
pending_reset = true;
246
}
247
}
248
249
// accumulate a new sensor reading
250
void AP_Baro_DPS280::timer(void)
251
{
252
uint8_t buf[6];
253
uint8_t ready;
254
255
if (pending_reset) {
256
// reset registers after software reset from check_health()
257
pending_reset = false;
258
set_config_registers();
259
return;
260
}
261
262
if (!dev->read_registers(DPS280_REG_MCONF, &ready, 1) ||
263
!(ready & (1U<<4)) ||
264
!dev->read_registers(DPS280_REG_PRESS, buf, 3) ||
265
!dev->read_registers(DPS280_REG_TEMP, &buf[3], 3)) {
266
// data not ready
267
err_count++;
268
check_health();
269
return;
270
}
271
272
int32_t press = (buf[2]) + (buf[1]<<8) + (buf[0]<<16);
273
int32_t temp = (buf[5]) + (buf[4]<<8) + (buf[3]<<16);
274
fix_config_bits32(press, 24);
275
fix_config_bits32(temp, 24);
276
277
float pressure, temperature;
278
279
calculate_PT(temp, press, pressure, temperature);
280
281
last_temperature = temperature;
282
283
if (!pressure_ok(pressure)) {
284
return;
285
}
286
287
check_health();
288
289
if (fabsf(last_temperature) <= TEMPERATURE_LIMIT_C) {
290
err_count = 0;
291
}
292
293
WITH_SEMAPHORE(_sem);
294
295
pressure_sum += pressure;
296
temperature_sum += temperature;
297
count++;
298
}
299
300
// transfer data to the frontend
301
void AP_Baro_DPS280::update(void)
302
{
303
if (count == 0) {
304
return;
305
}
306
307
WITH_SEMAPHORE(_sem);
308
309
_copy_to_frontend(instance, pressure_sum/count, temperature_sum/count);
310
pressure_sum = 0;
311
temperature_sum = 0;
312
count=0;
313
}
314
315
#endif // AP_BARO_DPS280_ENABLED
316
317