PX4 Firmware
PX4 Autopilot Software http://px4.io
MS5525.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2017 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #include "MS5525.hpp"
35 
36 int
38 {
39  int ret = PX4_ERROR;
40 
41  if (_inited) {
42  // send the command to begin a conversion.
43  uint8_t cmd = _current_cmd;
44  ret = transfer(&cmd, 1, nullptr, 0);
45 
46  if (ret != PX4_OK) {
48  }
49 
50  } else {
51  _inited = init_ms5525();
52 
53  if (_inited) {
54  ret = PX4_OK;
55  }
56  }
57 
58  return ret;
59 }
60 
61 bool
63 {
64  // Step 1 - reset
65  uint8_t cmd = CMD_RESET;
66  int ret = transfer(&cmd, 1, nullptr, 0);
67 
68  if (ret != PX4_OK) {
70  return false;
71  }
72 
73  px4_usleep(3000);
74 
75  // Step 2 - read calibration coefficients from prom
76 
77  // prom layout
78  // 0 factory data and the setup
79  // 1-6 calibration coefficients
80  // 7 serial code and CRC
81  uint16_t prom[8];
82 
83  for (uint8_t i = 0; i < 8; i++) {
84  cmd = CMD_PROM_START + i * 2;
85 
86  // request PROM value
87  ret = transfer(&cmd, 1, nullptr, 0);
88 
89  if (ret != PX4_OK) {
91  return false;
92  }
93 
94  // read 2 byte value
95  uint8_t val[2];
96  ret = transfer(nullptr, 0, &val[0], 2);
97 
98  if (ret == PX4_OK) {
99  prom[i] = (val[0] << 8) | val[1];
100 
101  } else {
103  return false;
104  }
105  }
106 
107  // Step 3 - check CRC
108  const uint8_t crc = prom_crc4(prom);
109  const uint8_t onboard_crc = prom[7] & 0xF;
110 
111  if (crc == onboard_crc) {
112  // store valid calibration coefficients
113  C1 = prom[1];
114  C2 = prom[2];
115  C3 = prom[3];
116  C4 = prom[4];
117  C5 = prom[5];
118  C6 = prom[6];
119 
120  Tref = int64_t(C5) * (1UL << Q5);
121  _device_id.devid_s.devtype = DRV_DIFF_PRESS_DEVTYPE_MS5525;
122 
123  return true;
124 
125  } else {
126  PX4_ERR("CRC mismatch");
127  return false;
128  }
129 }
130 
131 uint8_t
132 MS5525::prom_crc4(uint16_t n_prom[]) const
133 {
134  // see Measurement Specialties AN520
135 
136  // crc remainder
137  unsigned int n_rem = 0x00;
138 
139  // original value of the crc
140  unsigned int crc_read = n_prom[7]; // save read CRC
141  n_prom[7] = (0xFF00 & (n_prom[7])); // CRC byte is replaced by 0
142 
143  // operation is performed on bytes
144  for (int cnt = 0; cnt < 16; cnt++) {
145  // choose LSB or MSB
146  if (cnt % 2 == 1) {
147  n_rem ^= (unsigned short)((n_prom[cnt >> 1]) & 0x00FF);
148 
149  } else {
150  n_rem ^= (unsigned short)(n_prom[cnt >> 1] >> 8);
151  }
152 
153  for (uint8_t n_bit = 8; n_bit > 0; n_bit--) {
154  if (n_rem & (0x8000)) {
155  n_rem = (n_rem << 1) ^ 0x3000;
156 
157  } else {
158  n_rem = (n_rem << 1);
159  }
160  }
161  }
162 
163  n_rem = (0x000F & (n_rem >> 12)); // final 4-bit reminder is CRC code
164  n_prom[7] = crc_read; // restore the crc_read to its original place
165 
166  return (n_rem ^ 0x00);
167 }
168 
169 int
171 {
173 
174  // read ADC
175  uint8_t cmd = CMD_ADC_READ;
176  int ret = transfer(&cmd, 1, nullptr, 0);
177 
178  if (ret != PX4_OK) {
180  return ret;
181  }
182 
183  // read 24 bits from the sensor
184  uint8_t val[3];
185  ret = transfer(nullptr, 0, &val[0], 3);
186 
187  if (ret != PX4_OK) {
189  return ret;
190  }
191 
192  uint32_t adc = (val[0] << 16) | (val[1] << 8) | val[2];
193 
194  // If the conversion is not executed before the ADC read command, or the ADC read command is repeated, it will give 0 as the output
195  // result. If the ADC read command is sent during conversion the result will be 0, the conversion will not stop and
196  // the final result will be wrong. Conversion sequence sent during the already started conversion process will yield
197  // incorrect result as well.
198  if (adc == 0) {
200  return EAGAIN;
201  }
202 
204  D1 = adc;
205  _pressure_count++;
206 
207  if (_pressure_count > 9) {
208  _pressure_count = 0;
210  }
211 
212  } else if (_current_cmd == CMD_CONVERT_TEMP) {
213  D2 = adc;
215 
216  // only calculate and publish after new pressure readings
217  return PX4_OK;
218  }
219 
220  // not ready yet
221  if (D1 == 0 || D2 == 0) {
222  return EAGAIN;
223  }
224 
225  // Difference between actual and reference temperature
226  // dT = D2 - Tref
227  const int64_t dT = D2 - Tref;
228 
229  // Measured temperature
230  // TEMP = 20°C + dT * TEMPSENS
231  const int64_t TEMP = 2000 + (dT * int64_t(C6)) / (1UL << Q6);
232 
233  // Offset at actual temperature
234  // OFF = OFF_T1 + TCO * dT
235  const int64_t OFF = int64_t(C2) * (1UL << Q2) + (int64_t(C4) * dT) / (1UL << Q4);
236 
237  // Sensitivity at actual temperature
238  // SENS = SENS_T1 + TCS * dT
239  const int64_t SENS = int64_t(C1) * (1UL << Q1) + (int64_t(C3) * dT) / (1UL << Q3);
240 
241  // Temperature Compensated Pressure (example 24996 = 2.4996 psi)
242  // P = D1 * SENS - OFF
243  const int64_t P = (D1 * SENS / (1UL << 21) - OFF) / (1UL << 15);
244 
245  const float diff_press_PSI = P * 0.0001f;
246 
247  // 1 PSI = 6894.76 Pascals
248  static constexpr float PSI_to_Pa = 6894.757f;
249  const float diff_press_pa_raw = diff_press_PSI * PSI_to_Pa;
250 
251  const float temperature_c = TEMP * 0.01f;
252 
253  differential_pressure_s diff_pressure = {
255  .error_count = perf_event_count(_comms_errors),
256  .differential_pressure_raw_pa = diff_press_pa_raw - _diff_pres_offset,
257  .differential_pressure_filtered_pa = _filter.apply(diff_press_pa_raw) - _diff_pres_offset,
258  .temperature = temperature_c,
259  .device_id = _device_id.devid
260  };
261 
262  if (_airspeed_pub != nullptr && !(_pub_blocked)) {
263  /* publish it */
264  orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &diff_pressure);
265  }
266 
267  ret = OK;
268 
270 
271  return ret;
272 }
273 
274 void
276 {
277  int ret = PX4_ERROR;
278 
279  // collection phase
280  if (_collect_phase) {
281  // perform collection
282  ret = collect();
283 
284  if (OK != ret) {
285  /* restart the measurement state machine */
286  start();
287  _sensor_ok = false;
288  return;
289  }
290 
291  // next phase is measurement
292  _collect_phase = false;
293 
294  // is there a collect->measure gap?
296 
297  // schedule a fresh cycle call when we are ready to measure again
298  ScheduleDelayed(_measure_interval - CONVERSION_INTERVAL);
299 
300  return;
301  }
302  }
303 
304  /* measurement phase */
305  ret = measure();
306 
307  if (OK != ret) {
308  DEVICE_DEBUG("measure error");
309  }
310 
311  _sensor_ok = (ret == OK);
312 
313  // next phase is collection
314  _collect_phase = true;
315 
316  // schedule a fresh cycle call when the measurement is done
317  ScheduleDelayed(CONVERSION_INTERVAL);
318 }
orb_advert_t _airspeed_pub
Definition: airspeed.h:81
uint16_t C5
Definition: MS5525.hpp:115
uint32_t D2
Definition: MS5525.hpp:122
uint16_t C6
Definition: MS5525.hpp:116
#define CONVERSION_INTERVAL
static constexpr uint8_t Q3
Definition: MS5525.hpp:105
uint16_t C4
Definition: MS5525.hpp:114
static constexpr uint8_t CMD_ADC_READ
Definition: MS5525.hpp:77
int collect() override
Definition: MS5525.cpp:170
math::LowPassFilter2p _filter
Definition: MS5525.hpp:74
static constexpr uint8_t Q5
Definition: MS5525.hpp:107
bool _inited
Definition: MS5525.hpp:125
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
static constexpr uint8_t CMD_CONVERT_TEMP
Definition: MS5525.hpp:95
static constexpr uint8_t CMD_PROM_START
Definition: MS5525.hpp:79
static constexpr uint8_t Q2
Definition: MS5525.hpp:104
void perf_count(perf_counter_t handle)
Count a performance event.
int measure() override
Definition: MS5525.cpp:37
void Run() override
Perform a poll cycle; collect from the previous measurement and start a new one.
Definition: MS5525.cpp:275
uint8_t prom_crc4(uint16_t n_prom[]) const
Definition: MS5525.cpp:132
static constexpr uint8_t CMD_RESET
Definition: MS5525.hpp:76
uint8_t _current_cmd
Definition: MS5525.hpp:97
unsigned _pressure_count
Definition: MS5525.hpp:99
perf_counter_t _sample_perf
Definition: airspeed.h:88
void perf_end(perf_counter_t handle)
End a performance event.
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
int _measure_interval
Definition: airspeed.h:77
#define DRV_DIFF_PRESS_DEVTYPE_MS5525
Definition: drv_sensor.h:98
bool init_ms5525()
Definition: MS5525.cpp:62
static constexpr uint8_t CMD_CONVERT_PRES
Definition: MS5525.hpp:87
float apply(float sample)
Add a new raw value to the filter.
static constexpr uint8_t Q6
Definition: MS5525.hpp:108
static constexpr uint8_t Q1
Definition: MS5525.hpp:103
float _diff_pres_offset
Definition: airspeed.h:79
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
int64_t Tref
Definition: MS5525.hpp:118
#define OK
Definition: uavcan_main.cpp:71
bool _collect_phase
Definition: airspeed.h:78
P[0][0]
Definition: quatCovMat.c:44
uint16_t C2
Definition: MS5525.hpp:112
bool _sensor_ok
Definition: airspeed.h:76
void perf_begin(perf_counter_t handle)
Begin a performance event.
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
perf_counter_t _comms_errors
Definition: airspeed.h:89
uint16_t C1
Definition: MS5525.hpp:111
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
static constexpr uint8_t Q4
Definition: MS5525.hpp:106
void start()
Initialise the automatic measurement state machine and start it.
Definition: airspeed.cpp:200
uint32_t D1
Definition: MS5525.hpp:121
uint16_t C3
Definition: MS5525.hpp:113