dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_bmx055.c
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  *
26  * Additional note on redistribution: The copyright and license notices above
27  * must be maintained in each individual source file that is a derivative work
28  * of this source file; otherwise redistribution is prohibited.
29  */
30 
31 /* The PIOS_BMX055 contains several sensors integrated into one package.
32  * The accelerometer and gyro are supported here. The magnetomter is supported
33  * by the BMM150 driver, due to its different characteristics and the fac that
34  * you might want to skip it if you're using an external mag.
35  */
36 
37 #include "openpilot.h"
38 #include "pios.h"
39 
40 #if defined(PIOS_INCLUDE_BMX055)
41 
42 #include "pios_semaphore.h"
43 #include "pios_thread.h"
44 #include "pios_queue.h"
45 #include "physical_constants.h"
46 #include "taskmonitor.h"
47 
48 #include "pios_bmx055_priv.h"
49 
50 #define PIOS_BMX_TASK_PRIORITY PIOS_THREAD_PRIO_HIGHEST
51 #define PIOS_BMX_TASK_STACK 640
52 
53 #define PIOS_BMX_QUEUE_LEN 2
54 
55 #define PIOS_BMX_SPI_SPEED 10000000
56 
57 
62 enum pios_bmx055_dev_magic {
63  PIOS_BMX_DEV_MAGIC = 0x58786d42
64 };
65 
69 struct pios_bmx055_dev {
70  enum pios_bmx055_dev_magic magic;
71  const struct pios_bmx055_cfg *cfg;
72  pios_spi_t spi_id;
73  uint32_t spi_slave_gyro;
74  uint32_t spi_slave_accel;
75 
76  struct pios_queue *gyro_queue;
77  struct pios_queue *accel_queue;
78 
79  struct pios_thread *task_handle;
80  struct pios_semaphore *data_ready_sema;
81  volatile uint32_t interrupt_count;
82 };
83 
85 static struct pios_bmx055_dev *bmx_dev;
86 
88 
91 static struct pios_bmx055_dev *PIOS_BMX_Alloc(const struct pios_bmx055_cfg *cfg);
92 
97 static int32_t PIOS_BMX_Validate(struct pios_bmx055_dev *dev);
98 
99 static void PIOS_BMX_Task(void *parameters);
100 
105 static int32_t PIOS_BMX_ClaimBus(int slave);
106 
111 static int32_t PIOS_BMX_ReleaseBus(int slave);
112 
113 static int32_t PIOS_BMX_ReadReg(int slave, uint8_t address, uint8_t *buffer);
114 static int32_t PIOS_BMX_WriteReg(int slave, uint8_t address, uint8_t buffer);
115 
116 static struct pios_bmx055_dev *PIOS_BMX_Alloc(const struct pios_bmx055_cfg *cfg)
117 {
118  struct pios_bmx055_dev *dev;
119 
120  dev = (struct pios_bmx055_dev *)PIOS_malloc(sizeof(*bmx_dev));
121  if (!dev)
122  return NULL;
123 
124  dev->magic = PIOS_BMX_DEV_MAGIC;
125 
126  dev->accel_queue = PIOS_Queue_Create(PIOS_BMX_QUEUE_LEN, sizeof(struct pios_sensor_accel_data));
127  if (dev->accel_queue == NULL) {
128  PIOS_free(dev);
129  return NULL;
130  }
131 
132  dev->gyro_queue = PIOS_Queue_Create(PIOS_BMX_QUEUE_LEN, sizeof(struct pios_sensor_gyro_data));
133  if (dev->gyro_queue == NULL) {
134  PIOS_Queue_Delete(dev->accel_queue);
135  PIOS_free(dev);
136  return NULL;
137  }
138 
139  dev->data_ready_sema = PIOS_Semaphore_Create();
140  if (dev->data_ready_sema == NULL) {
141  PIOS_Queue_Delete(dev->accel_queue);
142  PIOS_Queue_Delete(dev->gyro_queue);
143  PIOS_free(dev);
144  return NULL;
145  }
146 
147  return dev;
148 }
149 
150 static int32_t PIOS_BMX_Validate(struct pios_bmx055_dev *dev)
151 {
152  if (dev == NULL)
153  return -1;
154  if (dev->magic != PIOS_BMX_DEV_MAGIC)
155  return -2;
156  if (dev->spi_id == 0)
157  return -3;
158  return 0;
159 }
160 
161 static int32_t AssertReg(int slave, uint8_t address, uint8_t expect) {
162  uint8_t c;
163 
164  int32_t ret = PIOS_BMX_ReadReg(slave, address, &c);
165 
166  if (ret) {
167  return ret;
168  }
169 
170  if (c != expect) {
171  DEBUG_PRINTF(2, "BMX: Assertion failed: *(%d:%02x) == %02x (expect %02x)\n",
172  slave, address, c, expect);
173  return -1;
174  }
175 
176  DEBUG_PRINTF(2, "BMX: Assertion passed: *(%d:%02x) == %02x\n", slave, address,
177  expect);
178 
179  return 0;
180 }
181 
183  uint32_t slave_gyro, uint32_t slave_accel,
184  const struct pios_bmx055_cfg *cfg)
185 {
186  DEBUG_PRINTF(2, "BMX: SPI_Init called\n");
187 
188  bmx_dev = PIOS_BMX_Alloc(cfg);
189  if (bmx_dev == NULL)
190  return -1;
191  *dev = bmx_dev;
192 
193  bmx_dev->spi_id = spi_id;
194  bmx_dev->spi_slave_gyro = slave_gyro;
195  bmx_dev->spi_slave_accel = slave_accel;
196  bmx_dev->cfg = cfg;
197 
198  int32_t ret;
199 
200  /* Verify presence/chip selects */
201  ret = AssertReg(bmx_dev->spi_slave_gyro, BMX055_REG_GYRO_CHIPID,
203 
204  if (ret) return ret;
205 
206  ret = AssertReg(bmx_dev->spi_slave_accel, BMX055_REG_ACC_CHIPID,
208 
209  if (ret) return ret;
210 
211  DEBUG_PRINTF(2, "BMX: Resetting sensors\n");
212 
213  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_gyro,
216 
217  if (ret) return ret;
218 
219  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_accel,
222 
223  if (ret) return ret;
224 
225  /* Gyro is very slow to wake up, so a big total delay here */
226  PIOS_DELAY_WaitmS(50);
227 
228  /* Verify presence/chip selects again */
229  ret = AssertReg(bmx_dev->spi_slave_gyro,
232 
233  if (ret) return ret;
234 
235  ret = AssertReg(bmx_dev->spi_slave_accel,
238 
239  if (ret) return ret;
240 
241  /* Program ODR, range, and bandwidth of accel */
242  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_accel,
245 
246  if (ret) return ret;
247 
248  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_accel,
251 
252  if (ret) return ret;
253 
254  /* Program ODR, range, and bandwidth of gyro */
255  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_gyro,
258 
259  if (ret) return ret;
260 
261  ret = PIOS_BMX_WriteReg(bmx_dev->spi_slave_gyro,
264 
265  if (ret) return ret;
266 
267 #if 0
268  /* Set up EXTI line */
269  PIOS_EXTI_Init(bmx_dev->cfg->exti_cfg);
270 
271  /* Wait 20 ms for data ready interrupt and make sure it happens twice */
272  if (!bmx_dev->cfg->skip_startup_irq_check) {
273  for (int i=0; i<2; i++) {
274  uint32_t ref_val = bmx_dev->interrupt_count;
275  uint32_t raw_start = PIOS_DELAY_GetRaw();
276 
277  while (bmx_dev->interrupt_count == ref_val) {
278  if (PIOS_DELAY_DiffuS(raw_start) > 20000) {
279  PIOS_EXTI_DeInit(bmx_dev->cfg->exti_cfg);
280  return -PIOS_BMX_ERROR_NOIRQ;
281  }
282  }
283  }
284  }
285 #endif
286 
287  bmx_dev->task_handle = PIOS_Thread_Create(
288  PIOS_BMX_Task, "pios_bmx", PIOS_BMX_TASK_STACK,
289  NULL, PIOS_BMX_TASK_PRIORITY);
290 
291  PIOS_Assert(bmx_dev->task_handle != NULL);
292  TaskMonitorAdd(TASKINFO_RUNNING_IMU, bmx_dev->task_handle);
293 
295 
298 
299  PIOS_SENSORS_Register(PIOS_SENSOR_ACCEL, bmx_dev->accel_queue);
300  PIOS_SENSORS_Register(PIOS_SENSOR_GYRO, bmx_dev->gyro_queue);
301 
302  return 0;
303 }
304 
305 static int32_t PIOS_BMX_ClaimBus(int slave)
306 {
307  if (PIOS_BMX_Validate(bmx_dev) != 0)
308  return -1;
309 
310  if (PIOS_SPI_ClaimBus(bmx_dev->spi_id) != 0)
311  return -2;
312 
313  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, slave, false);
314 
315  return 0;
316 }
317 
318 static int32_t PIOS_BMX_ReleaseBus(int slave)
319 {
320  if (PIOS_BMX_Validate(bmx_dev) != 0)
321  return -1;
322 
323  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, slave, true);
324 
325  PIOS_SPI_ReleaseBus(bmx_dev->spi_id);
326 
327  return 0;
328 }
329 
330 static int32_t PIOS_BMX_ReadReg(int slave, uint8_t address, uint8_t *buffer)
331 {
332  if (PIOS_BMX_ClaimBus(slave) != 0)
333  return -1;
334 
335  PIOS_SPI_TransferByte(bmx_dev->spi_id, 0x80 | address); // request byte
336  *buffer = PIOS_SPI_TransferByte(bmx_dev->spi_id, 0); // receive response
337 
338  PIOS_BMX_ReleaseBus(slave);
339 
340  return 0;
341 }
342 
343 static int32_t PIOS_BMX_WriteReg(int slave, uint8_t address, uint8_t buffer)
344 {
345  if (PIOS_BMX_ClaimBus(slave) != 0)
346  return -1;
347 
348  PIOS_SPI_TransferByte(bmx_dev->spi_id, 0x7f & address);
349  PIOS_SPI_TransferByte(bmx_dev->spi_id, buffer);
350 
351  PIOS_BMX_ReleaseBus(slave);
352 
353  return 0;
354 }
355 
356 #if 0
357 bool PIOS_BMX_IRQHandler(void)
358 {
359  if (PIOS_BMX_Validate(bmx_dev) != 0)
360  return false;
361 
362  bool woken = false;
363 
364  bmx_dev->interrupt_count++;
365 
366  PIOS_Semaphore_Give_FromISR(bmx_dev->data_ready_sema, &woken);
367 
368  return woken;
369 }
370 #endif
371 
372 static void PIOS_BMX_Task(void *parameters)
373 {
374  (void)parameters;
375 
376  while (true) {
377 #if 0
378  //Wait for data ready interrupt
379  if (PIOS_Semaphore_Take(bmx_dev->data_ready_sema, PIOS_SEMAPHORE_TIMEOUT_MAX) != true)
380  continue;
381 #endif
382  PIOS_Thread_Sleep(1); /* XXX */
383 
384  // claim bus in high speed mode
385  if (PIOS_SPI_ClaimBus(bmx_dev->spi_id) != 0)
386  continue;
387 
388  uint8_t acc_buf[BMX055_REG_ACC_TEMP - BMX055_REG_ACC_X_LSB + 1];
389  uint8_t gyro_buf[BMX055_REG_GYRO_Z_MSB - BMX055_REG_GYRO_X_LSB + 1];
390 
391  PIOS_SPI_SetClockSpeed(bmx_dev->spi_id, 10000000);
392 
393  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, bmx_dev->spi_slave_accel,
394  false);
395 
396  PIOS_SPI_TransferByte(bmx_dev->spi_id, 0x80 | BMX055_REG_ACC_X_LSB);
397 
398  if (PIOS_SPI_TransferBlock(bmx_dev->spi_id, NULL, acc_buf, sizeof(acc_buf)) < 0) {
399  PIOS_BMX_ReleaseBus(false);
400  continue;
401  }
402 
403  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, bmx_dev->spi_slave_accel,
404  true);
405  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, bmx_dev->spi_slave_gyro,
406  false);
407 
408  PIOS_SPI_TransferByte(bmx_dev->spi_id, 0x80 | BMX055_REG_GYRO_X_LSB);
409  if (PIOS_SPI_TransferBlock(bmx_dev->spi_id, NULL, gyro_buf, sizeof(gyro_buf)) < 0) {
410  PIOS_BMX_ReleaseBus(false);
411  continue;
412  }
413  PIOS_SPI_RC_PinSet(bmx_dev->spi_id, bmx_dev->spi_slave_gyro,
414  true);
415 
416  PIOS_SPI_ReleaseBus(bmx_dev->spi_id);
417 
418  struct pios_sensor_accel_data accel_data;
419  struct pios_sensor_gyro_data gyro_data;
420 
421 #define PACK_REG12_ADDR_OFFSET(b, reg, off) (int16_t) ( (b[reg-off] & 0xf0) | (b[reg-off+1] << 8) )
422 #define PACK_REG16_ADDR_OFFSET(b, reg, off) (int16_t) ( (b[reg-off]) | (b[reg-off+1] << 8) )
423  float accel_x = PACK_REG12_ADDR_OFFSET(acc_buf, BMX055_REG_ACC_X_LSB, BMX055_REG_ACC_X_LSB);
424  float accel_y = PACK_REG12_ADDR_OFFSET(acc_buf, BMX055_REG_ACC_Y_LSB, BMX055_REG_ACC_X_LSB);
425  float accel_z = PACK_REG12_ADDR_OFFSET(acc_buf, BMX055_REG_ACC_Z_LSB, BMX055_REG_ACC_X_LSB);
426  int accel_temp = ((int8_t) acc_buf[BMX055_REG_ACC_TEMP - BMX055_REG_ACC_X_LSB]) + BMX055_ACC_TEMP_OFFSET;
427 
428  float gyro_x = PACK_REG16_ADDR_OFFSET(gyro_buf, BMX055_REG_GYRO_X_LSB, BMX055_REG_GYRO_X_LSB);
429  float gyro_y = PACK_REG16_ADDR_OFFSET(gyro_buf, BMX055_REG_GYRO_Y_LSB, BMX055_REG_GYRO_X_LSB);
430  float gyro_z = PACK_REG16_ADDR_OFFSET(gyro_buf, BMX055_REG_GYRO_Z_LSB, BMX055_REG_GYRO_X_LSB);
431 
432  // Rotate the sensor to our convention. The datasheet defines X as towards the right
433  // and Y as forward. Our convention transposes this. Also the Z is defined negatively
434  // to our convention. This is true for accels and gyros. Magnetometer corresponds our convention.
435  switch (bmx_dev->cfg->orientation) {
436  case PIOS_BMX_TOP_0DEG:
437  accel_data.y = accel_x;
438  accel_data.x = accel_y;
439  accel_data.z = -accel_z;
440  gyro_data.y = gyro_x;
441  gyro_data.x = gyro_y;
442  gyro_data.z = -gyro_z;
443  break;
444  case PIOS_BMX_TOP_90DEG:
445  accel_data.y = -accel_y;
446  accel_data.x = accel_x;
447  accel_data.z = -accel_z;
448  gyro_data.y = -gyro_y;
449  gyro_data.x = gyro_x;
450  gyro_data.z = -gyro_z;
451  break;
452  case PIOS_BMX_TOP_180DEG:
453  accel_data.y = -accel_x;
454  accel_data.x = -accel_y;
455  accel_data.z = -accel_z;
456  gyro_data.y = -gyro_x;
457  gyro_data.x = -gyro_y;
458  gyro_data.z = -gyro_z;
459  break;
460  case PIOS_BMX_TOP_270DEG:
461  accel_data.y = accel_y;
462  accel_data.x = -accel_x;
463  accel_data.z = -accel_z;
464  gyro_data.y = gyro_y;
465  gyro_data.x = -gyro_x;
466  gyro_data.z = -gyro_z;
467  break;
469  accel_data.y = -accel_x;
470  accel_data.x = accel_y;
471  accel_data.z = accel_z;
472  gyro_data.y = -gyro_x;
473  gyro_data.x = gyro_y;
474  gyro_data.z = gyro_z;
475  break;
477  accel_data.y = accel_y;
478  accel_data.x = accel_x;
479  accel_data.z = accel_z;
480  gyro_data.y = gyro_y;
481  gyro_data.x = gyro_x;
482  gyro_data.z = gyro_z;
483  break;
485  accel_data.y = accel_x;
486  accel_data.x = -accel_y;
487  accel_data.z = accel_z;
488  gyro_data.y = gyro_x;
489  gyro_data.x = -gyro_y;
490  gyro_data.z = gyro_z;
491  break;
493  accel_data.y = -accel_y;
494  accel_data.x = -accel_x;
495  accel_data.z = accel_z;
496  gyro_data.y = -gyro_y;
497  gyro_data.x = -gyro_x;
498  gyro_data.z = gyro_z;
499  break;
500  }
501 
502  // Apply sensor scaling
503  // At 16G setting, BMX055 is 128 lsb/G.
504  // Plus there's 4 bits of left adjustment, so 2048 counts/g.
505  //
506  float accel_scale = GRAVITY/2048;
507  accel_data.x *= accel_scale;
508  accel_data.y *= accel_scale;
509  accel_data.z *= accel_scale;
510  accel_data.temperature = accel_temp;
511 
512  float gyro_scale = 2000.0f / 32768;
513  gyro_data.x *= gyro_scale;
514  gyro_data.y *= gyro_scale;
515  gyro_data.z *= gyro_scale;
516  gyro_data.temperature = accel_temp;
517 
518  PIOS_Queue_Send(bmx_dev->accel_queue, &accel_data, 0);
519  PIOS_Queue_Send(bmx_dev->gyro_queue, &gyro_data, 0);
520  }
521 }
522 
523 #endif // PIOS_INCLUDE_BMX055
524 
#define BMX055_REG_ACC_Y_LSB
uint32_t PIOS_DELAY_DiffuS(uint32_t raw)
Subtract raw time from now and convert to us.
Definition: pios_delay.c:159
#define BMX055_REG_ACC_X_LSB
#define BMX055_REG_ACC_Z_LSB
#define BMX055_REG_ACC_PMU_BW
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
#define PIOS_SEMAPHORE_TIMEOUT_MAX
#define BMX055_REG_GYRO_CHIPID
#define BMX055_REG_ACC_TEMP
void PIOS_SENSORS_SetMaxGyro(int32_t rate)
Set the maximum gyro rate in deg/s.
Definition: pios_sensors.c:162
Main PiOS header to include all the compiled in PiOS options.
int32_t PIOS_BMX055_SPI_Init(pios_bmx055_dev_t *dev, pios_spi_t spi_id, uint32_t slave_gyro, uint32_t slave_accel, const struct pios_bmx055_cfg *cfg)
Initialize the BMX-xxxx 6/9-axis sensor on SPI.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
#define BMX055_VAL_ACC_BGW_SOFTRESET_REQ
int32_t PIOS_EXTI_Init(const struct pios_exti_cfg *cfg)
#define BMX055_VAL_GYRO_CHIPID
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
#define BMX055_REG_GYRO_Z_LSB
#define BMX055_ACC_TEMP_OFFSET
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
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
#define BMX055_REG_GYRO_BGW_SOFTRESET
#define DEBUG_PRINTF(level,...)
Definition: pios_board.h:39
#define BMX055_REG_ACC_BGW_SOFTRESET
void PIOS_Queue_Delete(struct pios_queue *queuep)
Definition: pios_queue.c:89
Task monitoring library.
#define BMX055_VAL_ACC_PMU_RANGE_16G
void PIOS_EXTI_DeInit(const struct pios_exti_cfg *cfg)
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
#define BMX055_VAL_GYRO_BGW_SOFTRESET_REQ
static float gyro_scale[3]
Definition: sensors.c:116
#define BMX055_REG_ACC_CHIPID
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
#define BMX055_VAL_ACC_PMU_BW_500HZ
static float accel_scale[3]
Definition: sensors.c:115
Pios sensor structure for generic accel data.
Definition: pios_sensors.h:46
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t speed)
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
#define BMX055_REG_GYRO_Z_MSB
#define BMX055_REG_GYRO_X_LSB
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
uint8_t i
Definition: msp_messages.h:97
Pios sensor structure for generic gyro data.
Definition: pios_sensors.h:38
struct pios_bmx055_dev * pios_bmx055_dev_t
Definition: pios_bmx055.h:51
#define BMX055_REG_ACC_PMU_RANGE
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
#define BMX055_REG_GYRO_RANGE
#define BMX055_REG_GYRO_BW
void PIOS_SENSORS_SetSampleRate(enum pios_sensor_type type, uint32_t sample_rate)
Set the sample rate of a sensor (Hz)
Definition: pios_sensors.c:172
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
Includes PiOS and core architecture components.
#define BMX055_VAL_GYRO_RANGE_2000DPS
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
Definition: pios_delay.c:140
#define BMX055_REG_GYRO_Y_LSB
#define BMX055_VAL_GYRO_BW_116HZ
#define BMX055_VAL_ACC_CHIPID
uint32_t PIOS_DELAY_GetRaw()
Get the raw delay timer, useful for timing.
Definition: pios_delay.c:153