Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
airspeed_ms45xx_i2c.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
3  * 2014 Felix Ruess <felix.ruess@gmail.com>
4  *
5  * This file is part of paparazzi
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, write to
19  * the Free Software Foundation, 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
28 #include "std.h"
29 #include "mcu_periph/i2c.h"
32 #include "modules/core/abi.h"
33 
34 #include "mcu_periph/uart.h"
35 #include "pprzlink/messages.h"
37 
38 #if PERIODIC_TELEMETRY
40 #endif
41 
42 /* Enable ABI sending */
43 #ifndef AIRSPEED_MS45XX_SEND_ABI
44 #define AIRSPEED_MS45XX_SEND_ABI true
45 #endif
46 
49 #ifndef MS45XX_I2C_DEV
50 #define MS45XX_I2C_DEV i2c2
51 #endif
52 
55 #ifndef MS45XX_I2C_ADDR
56 #define MS45XX_I2C_ADDR 0x50
57 #endif
58 
62 #ifndef MS45XX_PRESSURE_OUTPUT_TYPE_InH2O
63 #define MS45XX_PRESSURE_OUTPUT_TYPE_InH2O 0
64 #endif
65 
70 #ifndef MS45XX_PRESSURE_RANGE
71 #define MS45XX_PRESSURE_RANGE 1
72 #endif
73 
76 #ifndef MS45XX_PRESSURE_TYPE
77 #define MS45XX_PRESSURE_TYPE 0
78 #endif
79 
82 #ifndef USE_AIRSPEED_LOWPASS_FILTER
83 #define USE_AIRSPEED_LOWPASS_FILTER TRUE
84 #endif
85 
90 #ifndef MS45XX_OUTPUT_TYPE
91 #define MS45XX_OUTPUT_TYPE 0
92 #endif
93 
95 #define InH2O_TO_PA 249.08891
96 
98 #define PSI_TO_PA 6894.75729
99 
100 #if MS45XX_PRESSURE_OUTPUT_TYPE_InH2O
101 #define OutputPressureToPa InH2O_TO_PA
102 #else
103 #define OutputPressureToPa PSI_TO_PA
104 #endif
105 
106 #if MS45XX_OUTPUT_TYPE == 0
107 /* Offset and scaling for OUTPUT TYPE A:
108  * p_raw = (0.8*16383)/ (Pmax - Pmin) * (pressure - Pmin) + 0.1*16383
109  * For differential sensors Pmax = MS45XX_PRESSURE_RANGE = -Pmin.
110  *
111  * p_diff = (p_raw - 0.1*16383) * 2*RANGE/(0.8*16383) - RANGE
112  * p_diff = p_raw * 2*RANGE/(0.8*16383) - (RANGE + (0.1 * 16383) * 2*RANGE/(0.8*16383)
113  * p_diff = p_raw * 2*RANGE/(0.8*16383) - (1.25 * RANGE)
114  * p_diff = (p_raw - offset) * scale
115  * then convert to Pascal
116  */
117 #ifndef MS45XX_PRESSURE_SCALE
118 #define MS45XX_PRESSURE_SCALE (2 * MS45XX_PRESSURE_RANGE / (0.8 * 16383) * OutputPressureToPa)
119 #endif
120 #ifndef MS45XX_PRESSURE_OFFSET
121 #define MS45XX_PRESSURE_OFFSET (16383 / 2)
122 #endif
123 #else /* Can still be improved using another if statment with MS45XX_PRESSURE_TYPE etc. */
124 /* Offset and scaling for OUTPUT TYPE B:
125  * p_raw = (0.9*16383)/ (Pmax - Pmin) * (pressure - Pmin) + 0.05*16383
126  */
127 #ifndef MS45XX_PRESSURE_SCALE
128 #define MS45XX_PRESSURE_SCALE (MS45XX_PRESSURE_RANGE/(0.9*16383)*OutputPressureToPa)
129 #endif
130 #ifndef MS45XX_PRESSURE_OFFSET
131 #define MS45XX_PRESSURE_OFFSET (0.05*16383)
132 #endif
133 #endif
134 
135 PRINT_CONFIG_VAR(MS45XX_OUTPUT_TYPE)
136 PRINT_CONFIG_VAR(MS45XX_PRESSURE_TYPE)
137 PRINT_CONFIG_VAR(MS45XX_PRESSURE_RANGE)
138 PRINT_CONFIG_VAR(MS45XX_PRESSURE_SCALE)
139 PRINT_CONFIG_VAR(MS45XX_PRESSURE_OFFSET)
140 
141 
142 
147 #ifdef MS45XX_AIRSPEED_SCALE
148 PRINT_CONFIG_MSG("MS45XX changed air density. PS: Use MS45XX_PRESSURE_SCALE to calibrate the MS45XX.");
149 #endif
150 
151 #define MS45XX_RHO_DIV_2 1.6327
152 
153 
157 #ifndef MS45XX_LOWPASS_TAU
158 #define MS45XX_LOWPASS_TAU 0.15
159 #endif
160 
161 struct AirspeedMs45xx ms45xx;
162 static struct i2c_transaction ms45xx_trans;
163 #ifdef USE_AIRSPEED_LOWPASS_FILTER
165 #endif
166 
167 #if PREFLIGHT_CHECKS
168 /* Preflight checks */
170 static struct preflight_check_t ms45xx_i2c_pfc;
171 
172 static void ms45xx_preflight(struct preflight_result_t *result) {
173  if(ms45xx.offset_set) {
174  preflight_success(result, "Airspeed sensor succesfully nulled (MS45XX)");
175  } else {
176  preflight_error(result, "Airspeed sensor not nulled (MS45XX)");
177  }
178 }
179 #endif // PREFLIGHT_CHECKS
180 
181 static void ms45xx_downlink(struct transport_tx *trans, struct link_device *dev)
182 {
183  uint8_t dev_id = MS45XX_SENDER_ID;
184  float temp = ((float)ms45xx.temperature) * 0.1f;
185  pprz_msg_send_AIRSPEED_RAW(trans,dev,AC_ID,
186  &dev_id,
187  &ms45xx.raw_p,
189  &ms45xx.pressure,
190  &temp,
191  &ms45xx.airspeed);
192 }
193 
194 void ms45xx_i2c_init(void)
195 {
196  ms45xx.pressure = 0.;
197  ms45xx.temperature = 0;
198  ms45xx.airspeed = 0.;
199  ms45xx.raw_p = 0;
203  ms45xx.offset_set = false;
204 
206  // setup low pass filter with time constant and 100Hz sampling freq
207 #ifdef USE_AIRSPEED_LOWPASS_FILTER
209  MS45XX_I2C_PERIODIC_PERIOD, 0);
210 #endif
211 
212 #if PERIODIC_TELEMETRY
213  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_AIRSPEED_RAW, ms45xx_downlink);
214 #endif
215 
216  /* Register preflight checks */
217 #if PREFLIGHT_CHECKS
218  preflight_check_register(&ms45xx_i2c_pfc, ms45xx_preflight);
219 #endif
220 }
221 
223 {
224  // Initiate next read
227  }
228 }
229 
230 #define AUTOSET_NB_MAX 20
231 
233 {
234  static int autoset_nb = 0;
235  static float autoset_offset = 0.f;
236 
237  /* Check if transaction is succesfull */
239 
240  /* 2 MSB of data are status bits, 0 = good data, 2 = already fetched, 3 = fault */
241  uint8_t status = (0xC0 & ms45xx_trans.buf[0]) >> 6;
242 
243  if (status == 0) {
244  /* 14bit raw pressure */
245  uint16_t p_raw = 0x3FFF & (((uint16_t)(ms45xx_trans.buf[0]) << 8) | (uint16_t)(ms45xx_trans.buf[1]));
246  ms45xx.raw_p = p_raw;
247 
248  /* 11bit raw temperature, 5 LSB bits not used */
249  uint16_t temp_raw = 0xFFE0 & (((uint16_t)(ms45xx_trans.buf[2]) << 8) |
250  (uint16_t)(ms45xx_trans.buf[3]));
251  temp_raw = temp_raw >> 5;
252 
253  /* Reject any values that are the absolute minimum or maximums these
254  can happen due to gnd lifts or communication errors on the bus */
255  if(p_raw == 0x3FFF || p_raw == 0 || temp_raw == 0x7FF || temp_raw == 0) {
257  return;
258  }
259 
260  /* For type Diff
261  * Output is proportional to the difference between Port 1 and Port 2. Output
262  * swings positive when Port 1> Port 2. Output is 50% of total counts
263  * when Port 1=Port 2.
264  * For type Gauge
265  * p_out = (p_raw - offset) * scale
266  */
267 
268  float p_out = (p_raw - ms45xx.pressure_offset) * ms45xx.pressure_scale;
269 
270  /* 0 = -50degC, 20147 = 150degC
271  * ms45xx_temperature in 0.1 deg Celcius
272  */
273  ms45xx.temperature = ((uint32_t)temp_raw * 2000) / 2047 - 500;
274 
275  // if(electrical.vboard != 0) {
276  // float volt_diff = electrical.vboard - 5.0f;
277  // Bound(volt_diff, -0.7f, 0.5f);
278 
279  // p_out -= 65.0f * volt_diff;
280  // ms45xx.temperature -= 8.87f * volt_diff;
281  // }
282 #ifdef USE_AIRSPEED_LOWPASS_FILTER
284 #else
285  ms45xx.pressure = p_out;
286 #endif
287 
288  if (ms45xx.autoset_offset) {
289  if (autoset_nb < AUTOSET_NB_MAX) {
290  autoset_offset += p_raw;
291  autoset_nb++;
292  } else {
293  ms45xx.pressure_offset = autoset_offset / (float)autoset_nb;
294  autoset_offset = 0.f;
295  autoset_nb = 0;
296  ms45xx.autoset_offset = false;
297  ms45xx.offset_set = true;
298  }
299  }
300 
301  // Send (differential) pressure via ABI
302  #if AIRSPEED_MS45XX_SEND_ABI
303  AbiSendMsgBARO_DIFF(MS45XX_SENDER_ID, ms45xx.pressure);
304 
305  // Send temperature as float in deg Celcius via ABI
306  float temp = ms45xx.temperature / 10.0f;
307 
308  AbiSendMsgTEMPERATURE(MS45XX_SENDER_ID, temp);
309  #endif
310 
311  // Compute airspeed
312  float sign = 1.0f;
313  if (ms45xx.pressure < 0.0f) {
314  sign = -1.0f;
315  }
317 
318  }
319 
320  // Set to done
322  } else if (ms45xx_trans.status == I2CTransFailed) {
323  // Just retry if failed
325  }
326 }
Main include for ABI (AirBorneInterface).
#define MS45XX_SENDER_ID
#define MS45XX_LOWPASS_TAU
Time constant for second order Butterworth low pass filter Default of 0.15 should give cut-off freq o...
#define MS45XX_RHO_DIV_2
Quadratic scale factor for indicated airspeed.
#define MS45XX_PRESSURE_RANGE
MS45xx pressure range in PSI or InH2O The sensor is available in many ranges, the datasheet of your p...
void ms45xx_i2c_event(void)
#define MS45XX_OUTPUT_TYPE
MS45xx output Type.
void ms45xx_i2c_periodic(void)
#define MS45XX_I2C_DEV
Default I2C device.
#define MS45XX_I2C_ADDR
Sensor I2C slave address (existing defaults 0x50, 0x6C and 0x8C)
struct AirspeedMs45xx ms45xx
static void ms45xx_downlink(struct transport_tx *trans, struct link_device *dev)
#define MS45XX_PRESSURE_TYPE
Pressure Type 0 = Differential, 1 = Gauge note there are theoretical more types than 2,...
#define MS45XX_PRESSURE_OFFSET
static struct i2c_transaction ms45xx_trans
static Butterworth2LowPass ms45xx_filter
#define AUTOSET_NB_MAX
#define MS45XX_PRESSURE_SCALE
void ms45xx_i2c_init(void)
Airspeed driver for the MS45xx pressure sensor via I2C.
float pressure_scale
Scaling factor from raw measurement to Pascal.
bool autoset_offset
Set offset value from current filtered value.
float pressure_offset
Offset in Pascal.
uint16_t raw_p
Raw pressure.
bool offset_set
Offset is set once.
bool pressure_type
Pressure type Differential of Gauge.
float pressure
(differential) pressure in Pascal
int16_t temperature
Temperature in 0.1 deg Celcius.
float airspeed
Airspeed in m/s estimated from (differential) pressure.
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
bool i2c_receive(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint16_t len)
Submit a read only transaction.
Definition: i2c.c:334
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
@ I2CTransDone
transaction set to done by user level
Definition: i2c.h:59
I2C transaction structure.
Definition: i2c.h:93
Architecture independent I2C (Inter-Integrated Circuit Bus) API.
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
Simple first order low pass filter with bilinear transform.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
Second order low pass filter structure.
static float sign(float x)
sign function
Definition: nav_fish.c:232
uint8_t status
void preflight_error(struct preflight_result_t *result, const char *fmt,...)
Register a preflight error used inside the preflight checking functions.
void preflight_success(struct preflight_result_t *result, const char *fmt,...)
Register a preflight success used inside the preflight checking functions.
void preflight_check_register(struct preflight_check_t *check, preflight_check_f func)
Register a preflight check and add it to the linked list.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98