PX4 Firmware
PX4 Autopilot Software http://px4.io
ms5611_i2c.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013 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 /**
35  * @file ms5611_i2c.cpp
36  *
37  * I2C interface for MS5611
38  */
39 
40 #include "ms5611.h"
41 
42 #define MS5611_ADDRESS_1 0x76 /* address select pins pulled high (PX4FMU series v1.6+) */
43 #define MS5611_ADDRESS_2 0x77 /* address select pins pulled low (PX4FMU prototypes) */
44 
45 
46 
48 
49 class MS5611_I2C : public device::I2C
50 {
51 public:
52  MS5611_I2C(uint8_t bus, ms5611::prom_u &prom_buf);
53  virtual ~MS5611_I2C() = default;
54 
55  virtual int read(unsigned offset, void *data, unsigned count);
56  virtual int ioctl(unsigned operation, unsigned &arg);
57 
58 protected:
59  virtual int probe();
60 
61 private:
63 
64  int _probe_address(uint8_t address);
65 
66  /**
67  * Send a reset command to the MS5611.
68  *
69  * This is required after any bus reset.
70  */
71  int _reset();
72 
73  /**
74  * Send a measure command to the MS5611.
75  *
76  * @param addr Which address to use for the measure operation.
77  */
78  int _measure(unsigned addr);
79 
80  /**
81  * Read the MS5611 PROM
82  *
83  * @return PX4_OK if the PROM reads successfully.
84  */
85  int _read_prom();
86 
87 };
88 
90 MS5611_i2c_interface(ms5611::prom_u &prom_buf, uint8_t busnum)
91 {
92  return new MS5611_I2C(busnum, prom_buf);
93 }
94 
96  I2C("MS5611_I2C", nullptr, bus, 0, 400000),
97  _prom(prom)
98 {
99 }
100 
101 int
102 MS5611_I2C::read(unsigned offset, void *data, unsigned count)
103 {
104  union _cvt {
105  uint8_t b[4];
106  uint32_t w;
107  } *cvt = (_cvt *)data;
108  uint8_t buf[3];
109 
110  /* read the most recent measurement */
111  uint8_t cmd = 0;
112  int ret = transfer(&cmd, 1, &buf[0], 3);
113 
114  if (ret == PX4_OK) {
115  /* fetch the raw value */
116  cvt->b[0] = buf[2];
117  cvt->b[1] = buf[1];
118  cvt->b[2] = buf[0];
119  cvt->b[3] = 0;
120  }
121 
122  return ret;
123 }
124 
125 int
126 MS5611_I2C::ioctl(unsigned operation, unsigned &arg)
127 {
128  int ret;
129 
130  switch (operation) {
131  case IOCTL_RESET:
132  ret = _reset();
133  break;
134 
135  case IOCTL_MEASURE:
136  ret = _measure(arg);
137  break;
138 
139  default:
140  ret = EINVAL;
141  }
142 
143  return ret;
144 }
145 
146 int
148 {
149  _retries = 10;
150 
151  if ((PX4_OK == _probe_address(MS5611_ADDRESS_1)) ||
152  (PX4_OK == _probe_address(MS5611_ADDRESS_2))) {
153  /*
154  * Disable retries; we may enable them selectively in some cases,
155  * but the device gets confused if we retry some of the commands.
156  */
157  _retries = 0;
158  return PX4_OK;
159  }
160 
161  return -EIO;
162 }
163 
164 int
166 {
167  /* select the address we are going to try */
168  set_device_address(address);
169 
170  /* send reset command */
171  if (PX4_OK != _reset()) {
172  return -EIO;
173  }
174 
175  /* read PROM */
176  if (PX4_OK != _read_prom()) {
177  return -EIO;
178  }
179 
180  return PX4_OK;
181 }
182 
183 int
185 {
186  unsigned old_retrycount = _retries;
187  uint8_t cmd = ADDR_RESET_CMD;
188  int result;
189 
190  /* bump the retry count */
191  _retries = 10;
192  result = transfer(&cmd, 1, nullptr, 0);
193  _retries = old_retrycount;
194 
195  return result;
196 }
197 
198 int
199 MS5611_I2C::_measure(unsigned addr)
200 {
201  /*
202  * Disable retries on this command; we can't know whether failure
203  * means the device did or did not see the command.
204  */
205  _retries = 0;
206 
207  uint8_t cmd = addr;
208  return transfer(&cmd, 1, nullptr, 0);
209 }
210 
211 int
213 {
214  uint8_t prom_buf[2];
215  union {
216  uint8_t b[2];
217  uint16_t w;
218  } cvt;
219 
220  /*
221  * Wait for PROM contents to be in the device (2.8 ms) in the case we are
222  * called immediately after reset.
223  */
224  px4_usleep(3000);
225 
226  uint8_t last_val = 0;
227  bool bits_stuck = true;
228 
229  /* read and convert PROM words */
230  for (int i = 0; i < 8; i++) {
231  uint8_t cmd = ADDR_PROM_SETUP + (i * 2);
232 
233  if (PX4_OK != transfer(&cmd, 1, &prom_buf[0], 2)) {
234  break;
235  }
236 
237  /* check if all bytes are zero */
238  if (i == 0) {
239  /* initialize to first byte read */
240  last_val = prom_buf[0];
241  }
242 
243  if (prom_buf[0] != last_val || prom_buf[1] != last_val) {
244  bits_stuck = false;
245  }
246 
247  /* assemble 16 bit value and convert from big endian (sensor) to little endian (MCU) */
248  cvt.b[0] = prom_buf[1];
249  cvt.b[1] = prom_buf[0];
250  _prom.c[i] = cvt.w;
251  }
252 
253  /* calculate CRC and return success/failure accordingly */
254  return (ms5611::crc4(&_prom.c[0]) && !bits_stuck) ? PX4_OK : -EIO;
255 }
int _read_prom()
Read the MS5611 PROM.
Definition: ms5611_i2c.cpp:212
int _reset()
Send a reset command to the MS5611.
Definition: ms5611_i2c.cpp:184
bool crc4(uint16_t *n_prom)
MS5611 crc4 cribbed from the datasheet.
Definition: ms5611.cpp:608
#define ADDR_PROM_SETUP
Definition: ms5611.h:59
virtual int probe()
Definition: ms5611_i2c.cpp:147
MS5611_I2C(uint8_t bus, ms5611::prom_u &prom_buf)
Definition: ms5611_i2c.cpp:95
virtual int read(unsigned offset, void *data, unsigned count)
Definition: ms5611_i2c.cpp:102
virtual ~MS5611_I2C()=default
Shared defines for the ms5611 driver.
uint8_t * data
Definition: dataman.cpp:149
#define MS5611_ADDRESS_2
Definition: ms5611_i2c.cpp:43
int _measure(unsigned addr)
Send a measure command to the MS5611.
Definition: ms5611_i2c.cpp:199
#define MS5611_ADDRESS_1
Definition: ms5611_i2c.cpp:42
ms5611::prom_u & _prom
Definition: ms5611_i2c.cpp:62
#define ADDR_RESET_CMD
Definition: ms5611.h:58
uint16_t c[8]
Definition: ms5611.h:87
#define IOCTL_MEASURE
Definition: mpl3115a2.h:93
virtual int ioctl(unsigned operation, unsigned &arg)
Definition: ms5611_i2c.cpp:126
Grody hack for crc4()
Definition: ms5611.h:86
Fundamental base class for all physical drivers (I2C, SPI).
Definition: Device.hpp:65
device::Device * MS5611_i2c_interface(ms5611::prom_u &prom_buf)
int _probe_address(uint8_t address)
Definition: ms5611_i2c.cpp:165
#define IOCTL_RESET
Definition: mpl3115a2.h:92