dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_ms5611_spi.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_SPI)
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_RESET 0x1E
48 #define MS5611_CALIB_ADDR 0xA2 /* First sample is factory stuff */
49 #define MS5611_CALIB_LEN 16
50 #define MS5611_ADC_READ 0x00
51 #define MS5611_PRES_ADDR 0x40
52 #define MS5611_TEMP_ADDR 0x50
53 #define MS5611_ADC_MSB 0xF6
54 #define MS5611_P0 101.3250f
55 
56 /* Private methods */
57 static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t * buffer, uint8_t len);
58 static int32_t PIOS_MS5611_WriteCommand(uint8_t command);
59 static void PIOS_MS5611_Task(void *parameters);
60 
61 /* Private types */
62 
63 /* Local Types */
64 
65 enum pios_ms5611_dev_magic {
66  PIOS_MS5611_DEV_MAGIC = 0xefba8e10,
67 };
68 
69 enum conversion_type {
70  PRESSURE_CONV,
71  TEMPERATURE_CONV
72 };
73 
74 struct ms5611_dev {
75  const struct pios_ms5611_cfg *cfg;
76  pios_spi_t spi_id;
77  uint32_t slave_num;
78  struct pios_thread *task;
79  struct pios_queue *queue;
80 
81  int64_t pressure_unscaled;
82  int64_t temperature_unscaled;
83  uint16_t calibration[6];
84  enum conversion_type current_conversion_type;
85  enum pios_ms5611_dev_magic magic;
86 
87  struct pios_semaphore *busy;
88 };
89 
90 static struct ms5611_dev *dev;
91 
95 static struct ms5611_dev * PIOS_MS5611_alloc(void)
96 {
97  struct ms5611_dev *ms5611_dev;
98 
99  ms5611_dev = (struct ms5611_dev *)PIOS_malloc(sizeof(*ms5611_dev));
100  if (!ms5611_dev)
101  return (NULL);
102 
103  memset(ms5611_dev, 0, sizeof(*ms5611_dev));
104 
105  ms5611_dev->queue = PIOS_Queue_Create(1, sizeof(struct pios_sensor_baro_data));
106  if (ms5611_dev->queue == NULL) {
107  PIOS_free(ms5611_dev);
108  return NULL;
109  }
110 
111  ms5611_dev->magic = PIOS_MS5611_DEV_MAGIC;
112 
113  ms5611_dev->busy = PIOS_Semaphore_Create();
114  PIOS_Assert(ms5611_dev->busy != NULL);
115 
116  return ms5611_dev;
117 }
118 
123 static int32_t PIOS_MS5611_Validate(struct ms5611_dev *dev)
124 {
125  if (dev == NULL)
126  return -1;
127  if (dev->magic != PIOS_MS5611_DEV_MAGIC)
128  return -2;
129  if (dev->spi_id == 0)
130  return -3;
131  return 0;
132 }
133 
137 int32_t PIOS_MS5611_SPI_Init(pios_spi_t spi_id, uint32_t slave_num,
138  const struct pios_ms5611_cfg *cfg)
139 {
140  dev = (struct ms5611_dev *)PIOS_MS5611_alloc();
141  if (dev == NULL)
142  return -1;
143 
144  dev->spi_id = spi_id;
145  dev->slave_num = slave_num;
146 
147  dev->cfg = cfg;
148 
149  if (PIOS_MS5611_WriteCommand(MS5611_RESET) != 0)
150  return -2;
151 
152  PIOS_DELAY_WaitmS(20);
153 
154  uint8_t data[2];
155 
156  /* Calibration parameters */
157  for (int i = 0; i < NELEMENTS(dev->calibration); i++) {
158  PIOS_MS5611_Read(MS5611_CALIB_ADDR + i * 2, data, 2);
159  dev->calibration[i] = (data[0] << 8) | data[1];
160  }
161 
163 
164  dev->task = PIOS_Thread_Create(
165  PIOS_MS5611_Task, "pios_ms5611", MS5611_TASK_STACK_BYTES, NULL, MS5611_TASK_PRIORITY);
166  PIOS_Assert(dev->task != NULL);
167 
168  return 0;
169 }
170 
176 static int32_t PIOS_MS5611_ClaimDevice(void)
177 {
178  PIOS_Assert(PIOS_MS5611_Validate(dev) == 0);
179 
180  return PIOS_Semaphore_Take(dev->busy, PIOS_SEMAPHORE_TIMEOUT_MAX) == true ? 0 : 1;
181 }
182 
187 static int32_t PIOS_MS5611_ReleaseDevice(void)
188 {
189  PIOS_Assert(PIOS_MS5611_Validate(dev) == 0);
190 
191  return PIOS_Semaphore_Give(dev->busy) == true ? 0 : 1;
192 }
193 
198 static int32_t PIOS_MS5611_ClaimBus(void)
199 {
200  if (PIOS_MS5611_Validate(dev) != 0)
201  return -1;
202 
203  if (PIOS_SPI_ClaimBus(dev->spi_id) != 0)
204  return -2;
205 
206  PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0);
207 
208  return 0;
209 }
210 
215 static int32_t PIOS_MS5611_ReleaseBus(void)
216 {
217  if (PIOS_MS5611_Validate(dev) != 0)
218  return -1;
219 
220  PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1);
221 
222  return PIOS_SPI_ReleaseBus(dev->spi_id);
223 }
224 
230 static int32_t PIOS_MS5611_StartADC(enum conversion_type type)
231 {
232  if (PIOS_MS5611_Validate(dev) != 0)
233  return -1;
234 
235  /* Start the conversion */
236  switch (type) {
237  case TEMPERATURE_CONV:
238  while (PIOS_MS5611_WriteCommand(MS5611_TEMP_ADDR + dev->cfg->oversampling) != 0)
239  continue;
240  break;
241  case PRESSURE_CONV:
242  while (PIOS_MS5611_WriteCommand(MS5611_PRES_ADDR + dev->cfg->oversampling) != 0)
243  continue;
244  break;
245  default:
246  return -1;
247  }
248 
249  dev->current_conversion_type = type;
250 
251  return 0;
252 }
253 
257 static int32_t PIOS_MS5611_GetDelay()
258 {
259  if (PIOS_MS5611_Validate(dev) != 0)
260  return 100;
261 
262  switch(dev->cfg->oversampling) {
263  case MS5611_OSR_256:
264  return 2;
265  case MS5611_OSR_512:
266  return 2;
267  case MS5611_OSR_1024:
268  return 3;
269  case MS5611_OSR_2048:
270  return 5;
271  case MS5611_OSR_4096:
272  return 10;
273  default:
274  break;
275  }
276  return 10;
277 }
278 
283 static int32_t PIOS_MS5611_ReadADC(void)
284 {
285  if (PIOS_MS5611_Validate(dev) != 0)
286  return -1;
287 
288  uint8_t data[3];
289 
290  static int64_t delta_temp;
291  static int64_t temperature;
292 
293  /* Read and store the 16bit result */
294  if (dev->current_conversion_type == TEMPERATURE_CONV) {
295  uint32_t raw_temperature;
296  /* Read the temperature conversion */
297  if (PIOS_MS5611_Read(MS5611_ADC_READ, data, 3) != 0)
298  return -1;
299 
300  raw_temperature = (data[0] << 16) | (data[1] << 8) | data[2];
301 
302  delta_temp = (int32_t)raw_temperature - (dev->calibration[4] << 8);
303  temperature = 2000 + ((delta_temp * dev->calibration[5]) >> 23);
304  dev->temperature_unscaled = temperature;
305 
306  // second order temperature compensation
307  if (temperature < 2000)
308  dev->temperature_unscaled -= (delta_temp * delta_temp) >> 31;
309 
310  } else {
311  int64_t offset;
312  int64_t sens;
313  uint32_t raw_pressure;
314 
315  /* Read the pressure conversion */
316  if (PIOS_MS5611_Read(MS5611_ADC_READ, data, 3) != 0)
317  return -1;
318 
319  raw_pressure = (data[0] << 16) | (data[1] << 8) | (data[2] << 0);
320 
321  offset = ((int64_t)dev->calibration[1] << 16) + (((int64_t)dev->calibration[3] * delta_temp) >> 7);
322  sens = (int64_t)dev->calibration[0] << 15;
323  sens = sens + ((((int64_t) dev->calibration[2]) * delta_temp) >> 8);
324 
325  // second order temperature compensation
326  if (temperature < 2000) {
327  offset -= (5 * (temperature - 2000) * (temperature - 2000)) >> 1;
328  sens -= (5 * (temperature - 2000) * (temperature - 2000)) >> 2;
329 
330  if (dev->temperature_unscaled < -1500) {
331  offset -= 7 * (temperature + 1500) * (temperature + 1500);
332  sens -= (11 * (temperature + 1500) * (temperature + 1500)) >> 1;
333  }
334  }
335 
336  dev->pressure_unscaled = ((((int64_t)raw_pressure * sens) >> 21) - offset) >> 15;
337  }
338  return 0;
339 }
340 
351 static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len)
352 {
353  if (PIOS_MS5611_Validate(dev) != 0)
354  return -1;
355 
356  if (PIOS_MS5611_ClaimBus() != 0)
357  return -2;
358 
359  int32_t rc;
360 
361  PIOS_SPI_TransferByte(dev->spi_id, address);
362 
363  if (PIOS_SPI_TransferBlock(dev->spi_id, NULL, buffer, len) < 0) {
364  rc = -3;
365  goto out;
366  }
367 
368  rc = 0;
369 
370 out:
371  PIOS_MS5611_ReleaseBus();
372 
373  return rc;
374 }
375 
385 static int32_t PIOS_MS5611_WriteCommand(uint8_t command)
386 {
387  if (PIOS_MS5611_Validate(dev) != 0)
388  return -1;
389 
390  if (PIOS_MS5611_ClaimBus() != 0)
391  return -2;
392 
393  PIOS_SPI_TransferByte(dev->spi_id, command);
394 
395  PIOS_MS5611_ReleaseBus();
396 
397  return 0;
398 }
399 
404 int32_t PIOS_MS5611_SPI_Test()
405 {
406  if (PIOS_MS5611_Validate(dev) != 0)
407  return -1;
408 
409 
410  PIOS_MS5611_ClaimDevice();
411  PIOS_MS5611_StartADC(TEMPERATURE_CONV);
412  PIOS_DELAY_WaitmS(PIOS_MS5611_GetDelay());
413  PIOS_MS5611_ReadADC();
414  PIOS_MS5611_ReleaseDevice();
415 
416  PIOS_MS5611_ClaimDevice();
417  PIOS_MS5611_StartADC(PRESSURE_CONV);
418  PIOS_DELAY_WaitmS(PIOS_MS5611_GetDelay());
419  PIOS_MS5611_ReadADC();
420  PIOS_MS5611_ReleaseDevice();
421 
422 
423  // check range for sanity according to datasheet
424  if (dev->temperature_unscaled < -4000 ||
425  dev->temperature_unscaled > 8500 ||
426  dev->pressure_unscaled < 1000 ||
427  dev->pressure_unscaled > 120000)
428  return -1;
429 
430  return 0;
431 }
432 
433 static void PIOS_MS5611_Task(void *parameters)
434 {
435  // init this to 1 in order to force a temperature read on the first run
436  uint32_t temp_press_interleave_count = 1;
437  int32_t read_adc_result = 0;
438 
439  while (1) {
440 
441  --temp_press_interleave_count;
442 
443  if (temp_press_interleave_count == 0)
444  {
445  // Update the temperature data
446  PIOS_MS5611_ClaimDevice();
447  PIOS_MS5611_StartADC(TEMPERATURE_CONV);
448  PIOS_Thread_Sleep(PIOS_MS5611_GetDelay());
449  PIOS_MS5611_ReadADC();
450  PIOS_MS5611_ReleaseDevice();
451 
452  temp_press_interleave_count = dev->cfg->temperature_interleaving;
453  if (temp_press_interleave_count == 0)
454  temp_press_interleave_count = 1;
455  }
456 
457  // Update the pressure data
458  PIOS_MS5611_ClaimDevice();
459  PIOS_MS5611_StartADC(PRESSURE_CONV);
460  PIOS_Thread_Sleep(PIOS_MS5611_GetDelay());
461  read_adc_result = PIOS_MS5611_ReadADC();
462  PIOS_MS5611_ReleaseDevice();
463 
464  // Compute the altitude from the pressure and temperature and send it out
465  struct pios_sensor_baro_data data;
466  data.temperature = ((float) dev->temperature_unscaled) / 100.0f;
467  data.pressure = ((float) dev->pressure_unscaled) / 1000.0f;
468  data.altitude = 44330.0f * (1.0f - powf(data.pressure / MS5611_P0, (1.0f / 5.255f)));
469 
470 
471  if (read_adc_result == 0) {
472  PIOS_Queue_Send(dev->queue, &data, 0);
473  }
474  }
475 }
476 
477 
478 #endif
479 
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.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
#define NELEMENTS(x)
Definition: pios.h:192
int32_t PIOS_MS5611_SPI_Init(pios_spi_t spi_id, uint32_t slave_num, const struct pios_ms5611_cfg *cfg)
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
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.
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
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.
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.
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
static struct pios_queue * queue
Definition: actuator.c:82
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
Definition: pios_delay.c:140