dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_ms5611.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 /* Project Includes */
32 #include "pios.h"
33 
34 #if defined(PIOS_INCLUDE_MS5611)
35 
36 #include "pios_ms5611_priv.h"
37 #include "pios_semaphore.h"
38 #include "pios_thread.h"
39 #include "pios_queue.h"
40 
41 /* Private constants */
42 #define PIOS_MS5611_OVERSAMPLING oversampling
43 #define MS5611_TASK_PRIORITY PIOS_THREAD_PRIO_HIGHEST
44 #define MS5611_TASK_STACK_BYTES 512
45 
46 /* MS5611 Addresses */
47 #define MS5611_I2C_ADDR_0x76 0x76
48 #define MS5611_I2C_ADDR_0x77 0x77
49 #define MS5611_RESET 0x1E
50 #define MS5611_CALIB_ADDR 0xA2 /* First sample is factory stuff */
51 #define MS5611_CALIB_LEN 16
52 #define MS5611_ADC_READ 0x00
53 #define MS5611_PRES_ADDR 0x40
54 #define MS5611_TEMP_ADDR 0x50
55 #define MS5611_ADC_MSB 0xF6
56 #define MS5611_P0 101.3250f
57 
58 /* Private Variables */
59 uint8_t ms5611_i2c_addr;
60 
61 /* Private methods */
62 static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t * buffer, uint8_t len);
63 static int32_t PIOS_MS5611_WriteCommand(uint8_t command);
64 static void PIOS_MS5611_Task(void *parameters);
65 
66 /* Private types */
67 
68 /* Local Types */
69 
70 enum pios_ms5611_dev_magic {
71  PIOS_MS5611_DEV_MAGIC = 0xefba8e1d,
72 };
73 
74 enum conversion_type {
75  PRESSURE_CONV,
76  TEMPERATURE_CONV
77 };
78 
79 struct ms5611_dev {
80  const struct pios_ms5611_cfg * cfg;
81  pios_i2c_t i2c_id;
82  struct pios_thread *task;
83  struct pios_queue *queue;
84 
85  int64_t pressure_unscaled;
86  int64_t temperature_unscaled;
87  uint16_t calibration[6];
88  enum conversion_type current_conversion_type;
89  enum pios_ms5611_dev_magic magic;
90 
91  struct pios_semaphore *busy;
92 };
93 
94 static struct ms5611_dev *dev;
95 
99 static struct ms5611_dev * PIOS_MS5611_alloc(void)
100 {
101  struct ms5611_dev *ms5611_dev;
102 
103  ms5611_dev = (struct ms5611_dev *)PIOS_malloc(sizeof(*ms5611_dev));
104  if (!ms5611_dev)
105  return (NULL);
106 
107  memset(ms5611_dev, 0, sizeof(*ms5611_dev));
108 
109  ms5611_dev->queue = PIOS_Queue_Create(1, sizeof(struct pios_sensor_baro_data));
110  if (ms5611_dev->queue == NULL) {
111  PIOS_free(ms5611_dev);
112  return NULL;
113  }
114 
115  ms5611_dev->magic = PIOS_MS5611_DEV_MAGIC;
116 
117  ms5611_dev->busy = PIOS_Semaphore_Create();
118  PIOS_Assert(ms5611_dev->busy != NULL);
119 
120  return ms5611_dev;
121 }
122 
127 static int32_t PIOS_MS5611_Validate(struct ms5611_dev *dev)
128 {
129  if (dev == NULL)
130  return -1;
131  if (dev->magic != PIOS_MS5611_DEV_MAGIC)
132  return -2;
133  if (dev->i2c_id == 0)
134  return -3;
135  return 0;
136 }
137 
141 int32_t PIOS_MS5611_Init(const struct pios_ms5611_cfg *cfg, pios_i2c_t i2c_device)
142 {
143  dev = (struct ms5611_dev *)PIOS_MS5611_alloc();
144  if (dev == NULL)
145  return -1;
146 
147  dev->i2c_id = i2c_device;
148  dev->cfg = cfg;
149 
150  /* Which I2C address is being used? */
151  if (dev->cfg->use_0x76_address == true)
152  ms5611_i2c_addr = MS5611_I2C_ADDR_0x76;
153  else
154  ms5611_i2c_addr = MS5611_I2C_ADDR_0x77;
155 
156  if (PIOS_MS5611_WriteCommand(MS5611_RESET) != 0)
157  return -2;
158 
159  PIOS_DELAY_WaitmS(20);
160 
161  uint8_t data[2];
162 
163  /* Calibration parameters */
164  for (int i = 0; i < NELEMENTS(dev->calibration); i++) {
165  PIOS_MS5611_Read(MS5611_CALIB_ADDR + i * 2, data, 2);
166  dev->calibration[i] = (data[0] << 8) | data[1];
167  }
168 
170 
171  dev->task = PIOS_Thread_Create(
172  PIOS_MS5611_Task, "pios_ms5611", MS5611_TASK_STACK_BYTES, NULL, MS5611_TASK_PRIORITY);
173  PIOS_Assert(dev->task != NULL);
174 
175  return 0;
176 }
177 
183 static int32_t PIOS_MS5611_ClaimDevice(void)
184 {
185  PIOS_Assert(PIOS_MS5611_Validate(dev) == 0);
186 
187  return PIOS_Semaphore_Take(dev->busy, PIOS_SEMAPHORE_TIMEOUT_MAX) == true ? 0 : 1;
188 }
189 
194 static int32_t PIOS_MS5611_ReleaseDevice(void)
195 {
196  PIOS_Assert(PIOS_MS5611_Validate(dev) == 0);
197 
198  return PIOS_Semaphore_Give(dev->busy) == true ? 0 : 1;
199 }
200 
206 static int32_t PIOS_MS5611_StartADC(enum conversion_type type)
207 {
208  if (PIOS_MS5611_Validate(dev) != 0)
209  return -1;
210 
211  /* Start the conversion */
212  switch (type) {
213  case TEMPERATURE_CONV:
214  while (PIOS_MS5611_WriteCommand(MS5611_TEMP_ADDR + dev->cfg->oversampling) != 0)
215  continue;
216  break;
217  case PRESSURE_CONV:
218  while (PIOS_MS5611_WriteCommand(MS5611_PRES_ADDR + dev->cfg->oversampling) != 0)
219  continue;
220  break;
221  default:
222  return -1;
223  }
224 
225  dev->current_conversion_type = type;
226 
227  return 0;
228 }
229 
233 static int32_t PIOS_MS5611_GetDelay()
234 {
235  if (PIOS_MS5611_Validate(dev) != 0)
236  return 100;
237 
238  switch(dev->cfg->oversampling) {
239  case MS5611_OSR_256:
240  return 2;
241  case MS5611_OSR_512:
242  return 2;
243  case MS5611_OSR_1024:
244  return 3;
245  case MS5611_OSR_2048:
246  return 5;
247  case MS5611_OSR_4096:
248  return 10;
249  default:
250  break;
251  }
252  return 10;
253 }
254 
259 static int32_t PIOS_MS5611_ReadADC(void)
260 {
261  if (PIOS_MS5611_Validate(dev) != 0)
262  return -1;
263 
264  uint8_t data[3];
265 
266  static int64_t delta_temp;
267  static int64_t temperature;
268 
269  /* Read and store the 16bit result */
270  if (dev->current_conversion_type == TEMPERATURE_CONV) {
271  uint32_t raw_temperature;
272  /* Read the temperature conversion */
273  if (PIOS_MS5611_Read(MS5611_ADC_READ, data, 3) != 0)
274  return -1;
275 
276  raw_temperature = (data[0] << 16) | (data[1] << 8) | data[2];
277 
278  delta_temp = (int32_t)raw_temperature - (dev->calibration[4] << 8);
279  temperature = 2000 + ((delta_temp * dev->calibration[5]) >> 23);
280  dev->temperature_unscaled = temperature;
281 
282  // second order temperature compensation
283  if (temperature < 2000)
284  dev->temperature_unscaled -= (delta_temp * delta_temp) >> 31;
285 
286  } else {
287  int64_t offset;
288  int64_t sens;
289  uint32_t raw_pressure;
290 
291  /* Read the pressure conversion */
292  if (PIOS_MS5611_Read(MS5611_ADC_READ, data, 3) != 0)
293  return -1;
294 
295  raw_pressure = (data[0] << 16) | (data[1] << 8) | (data[2] << 0);
296 
297  offset = ((int64_t)dev->calibration[1] << 16) + (((int64_t)dev->calibration[3] * delta_temp) >> 7);
298  sens = (int64_t)dev->calibration[0] << 15;
299  sens = sens + ((((int64_t) dev->calibration[2]) * delta_temp) >> 8);
300 
301  // second order temperature compensation
302  if (temperature < 2000) {
303  offset -= (5 * (temperature - 2000) * (temperature - 2000)) >> 1;
304  sens -= (5 * (temperature - 2000) * (temperature - 2000)) >> 2;
305 
306  if (dev->temperature_unscaled < -1500) {
307  offset -= 7 * (temperature + 1500) * (temperature + 1500);
308  sens -= (11 * (temperature + 1500) * (temperature + 1500)) >> 1;
309  }
310  }
311 
312  dev->pressure_unscaled = ((((int64_t)raw_pressure * sens) >> 21) - offset) >> 15;
313  }
314  return 0;
315 }
316 
326 static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len)
327 {
328  if (PIOS_MS5611_Validate(dev) != 0)
329  return -1;
330 
331  const struct pios_i2c_txn txn_list[] = {
332  {
333  .info = __func__,
334  .addr = ms5611_i2c_addr,
335  .rw = PIOS_I2C_TXN_WRITE,
336  .len = 1,
337  .buf = &address,
338  },
339  {
340  .info = __func__,
341  .addr = ms5611_i2c_addr,
342  .rw = PIOS_I2C_TXN_READ,
343  .len = len,
344  .buf = buffer,
345  }
346  };
347 
348  return PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list));
349 }
350 
359 static int32_t PIOS_MS5611_WriteCommand(uint8_t command)
360 {
361  if (PIOS_MS5611_Validate(dev) != 0)
362  return -1;
363 
364  const struct pios_i2c_txn txn_list[] = {
365  {
366  .info = __func__,
367  .addr = ms5611_i2c_addr,
368  .rw = PIOS_I2C_TXN_WRITE,
369  .len = 1,
370  .buf = &command,
371  },
372  };
373 
374  return PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list));
375 }
376 
381 int32_t PIOS_MS5611_Test()
382 {
383  if (PIOS_MS5611_Validate(dev) != 0)
384  return -1;
385 
386  PIOS_MS5611_ClaimDevice();
387  PIOS_MS5611_StartADC(TEMPERATURE_CONV);
388  PIOS_DELAY_WaitmS(PIOS_MS5611_GetDelay());
389  PIOS_MS5611_ReadADC();
390  PIOS_MS5611_ReleaseDevice();
391 
392  PIOS_MS5611_ClaimDevice();
393  PIOS_MS5611_StartADC(PRESSURE_CONV);
394  PIOS_DELAY_WaitmS(PIOS_MS5611_GetDelay());
395  PIOS_MS5611_ReadADC();
396  PIOS_MS5611_ReleaseDevice();
397 
398  // check range for sanity according to datasheet
399  if (dev->temperature_unscaled < -4000 ||
400  dev->temperature_unscaled > 8500 ||
401  dev->pressure_unscaled < 1000 ||
402  dev->pressure_unscaled > 120000)
403  return -1;
404 
405  return 0;
406 }
407 
408 static void PIOS_MS5611_Task(void *parameters)
409 {
410  // init this to 1 in order to force a temperature read on the first run
411  uint32_t temp_press_interleave_count = 1;
412  int32_t read_adc_result = 0;
413 
414  while (1) {
415 
416  --temp_press_interleave_count;
417 
418  if (temp_press_interleave_count == 0)
419  {
420  // Update the temperature data
421  PIOS_MS5611_ClaimDevice();
422  PIOS_MS5611_StartADC(TEMPERATURE_CONV);
423  PIOS_Thread_Sleep(PIOS_MS5611_GetDelay());
424  PIOS_MS5611_ReadADC();
425  PIOS_MS5611_ReleaseDevice();
426 
427  temp_press_interleave_count = dev->cfg->temperature_interleaving;
428  if (temp_press_interleave_count == 0)
429  temp_press_interleave_count = 1;
430  }
431 
432  // Update the pressure data
433  PIOS_MS5611_ClaimDevice();
434  PIOS_MS5611_StartADC(PRESSURE_CONV);
435  PIOS_Thread_Sleep(PIOS_MS5611_GetDelay());
436  read_adc_result = PIOS_MS5611_ReadADC();
437  PIOS_MS5611_ReleaseDevice();
438 
439  // Compute the altitude from the pressure and temperature and send it out
440  struct pios_sensor_baro_data data;
441  data.temperature = ((float) dev->temperature_unscaled) / 100.0f;
442  data.pressure = ((float) dev->pressure_unscaled) / 1000.0f;
443  data.altitude = 44330.0f * (1.0f - powf(data.pressure / MS5611_P0, (1.0f / 5.255f)));
444 
445  if (read_adc_result == 0) {
446  PIOS_Queue_Send(dev->queue, &data, 0);
447  }
448  }
449 }
450 
451 
452 #endif
453 
MS5611 functions header.
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
#define PIOS_SEMAPHORE_TIMEOUT_MAX
Main PiOS header to include all the compiled in PiOS options.
#define NELEMENTS(x)
Definition: pios.h:192
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_Queue_Send(struct pios_queue *queuep, const void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:141
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
Configuration structure for the MS5611 driver.
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
struct pios_i2c_adapter * pios_i2c_t
Definition: pios_i2c.h:48
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
int32_t PIOS_SENSORS_Register(enum pios_sensor_type type, struct pios_queue *queue)
Register a queue-based sensor with the PIOS_SENSORS interface.
Definition: pios_sensors.c:82
static TaskInfoRunningElem task
Pios sensor structure for generic baro data.
Definition: pios_sensors.h:78
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
int32_t PIOS_I2C_Transfer(pios_i2c_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns)
uint32_t magic
void PIOS_free(void *buf)
Definition: pios_heap.c:174
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
uint32_t offset
Definition: uavtalk_priv.h:51
uint8_t type
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
const char * info
Definition: pios_i2c.h:41
static struct pios_queue * queue
Definition: actuator.c:82
int32_t PIOS_MS5611_Init(const struct pios_ms5611_cfg *cfg, pios_i2c_t i2c_device)
uint32_t len
Definition: pios_i2c.h:44
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
Definition: pios_delay.c:140