dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_hmc5983_i2c.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_HMC5983_I2C)
35 
36 #include "pios_semaphore.h"
37 #include "pios_thread.h"
38 #include "pios_queue.h"
39 #include "pios_hmc5983.h"
40 
41 /* Private constants */
42 #define HMC5983_TASK_PRIORITY PIOS_THREAD_PRIO_HIGHEST
43 #define HMC5983_TASK_STACK_BYTES 512
44 #define PIOS_HMC5983_MAX_DOWNSAMPLE 1
45 
46 /* Global Variables */
47 
48 /* Local Types */
49 enum pios_hmc5983_dev_magic {
50  PIOS_HMC5983_DEV_MAGIC = 0x3d8efeed,
51 };
52 
53 struct hmc5983_dev {
54  pios_i2c_t i2c_id;
55  const struct pios_hmc5983_cfg *cfg;
56  struct pios_queue *queue;
57  struct pios_thread *task;
58  struct pios_semaphore *data_ready_sema;
59  enum pios_hmc5983_dev_magic magic;
60  enum pios_hmc5983_orientation orientation;
61 };
62 
63 /* Local Variables */
64 static int32_t PIOS_HMC5983_Config(const struct pios_hmc5983_cfg * cfg);
65 static int32_t PIOS_HMC5983_Read(uint8_t address, uint8_t * buffer, uint8_t len);
66 static int32_t PIOS_HMC5983_Write(uint8_t address, uint8_t buffer);
67 static void PIOS_HMC5983_Task(void *parameters);
68 
69 static struct hmc5983_dev *dev;
70 
74 static struct hmc5983_dev * PIOS_HMC5983_alloc(void)
75 {
76  struct hmc5983_dev *hmc5983_dev;
77 
78  hmc5983_dev = (struct hmc5983_dev *)PIOS_malloc(sizeof(*hmc5983_dev));
79  if (!hmc5983_dev) return (NULL);
80 
81  hmc5983_dev->magic = PIOS_HMC5983_DEV_MAGIC;
82 
83  hmc5983_dev->queue = PIOS_Queue_Create(PIOS_HMC5983_MAX_DOWNSAMPLE, sizeof(struct pios_sensor_mag_data));
84  if (hmc5983_dev->queue == NULL) {
85  PIOS_free(hmc5983_dev);
86  return NULL;
87  }
88 
89  return hmc5983_dev;
90 }
91 
96 static int32_t PIOS_HMC5983_Validate(struct hmc5983_dev *dev)
97 {
98  if (dev == NULL)
99  return -1;
100  if (dev->magic != PIOS_HMC5983_DEV_MAGIC)
101  return -2;
102  if (dev->i2c_id == 0)
103  return -3;
104  return 0;
105 }
106 
111 int32_t PIOS_HMC5983_I2C_Init(pios_i2c_t i2c_id,
112  const struct pios_hmc5983_cfg *cfg)
113 {
114  dev = (struct hmc5983_dev *) PIOS_HMC5983_alloc();
115  if (dev == NULL)
116  return -1;
117 
118  dev->cfg = cfg;
119  dev->i2c_id = i2c_id;
120  dev->orientation = cfg->Orientation;
121 
122 #ifdef PIOS_HMC5983_HAS_GPIOS
123  /* check if we are using an irq line */
124  if (cfg->exti_cfg != NULL) {
125  PIOS_EXTI_Init(cfg->exti_cfg);
126 
127  dev->data_ready_sema = PIOS_Semaphore_Create();
128  PIOS_Assert(dev->data_ready_sema != NULL);
129  }
130  else {
131  dev->data_ready_sema = NULL;
132  }
133 #else
134  dev->data_ready_sema = NULL;
135 #endif /* PIOS_HMC5983_HAS_GPIOS */
136 
137  if (PIOS_HMC5983_Config(cfg) != 0)
138  return -2;
139 
141 
142  dev->task = PIOS_Thread_Create(PIOS_HMC5983_Task, "pios_hmc5983", HMC5983_TASK_STACK_BYTES, NULL, HMC5983_TASK_PRIORITY);
143 
144  PIOS_Assert(dev->task != NULL);
145 
146  return 0;
147 }
148 
153 int32_t PIOS_HMC5983_SetOrientation(enum pios_hmc5983_orientation orientation)
154 {
155  if (PIOS_HMC5983_Validate(dev) != 0)
156  return -1;
157 
158  dev->orientation = orientation;
159 
160  return 0;
161 }
162 
228 static int32_t PIOS_HMC5983_Config(const struct pios_hmc5983_cfg * cfg)
229 {
230  // CRTL_REGA
231  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_A, 0x80 | cfg->M_ODR | cfg->Meas_Conf) != 0)
232  return -1;
233 
234  // CRTL_REGB
235  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_B, cfg->Gain) != 0)
236  return -1;
237 
238  // Mode register
239  if (PIOS_HMC5983_Write(PIOS_HMC5983_MODE_REG, cfg->Mode) != 0)
240  return -1;
241 
242  return 0;
243 }
244 
249 static uint16_t PIOS_HMC5983_Config_GetSensitivity()
250 {
251  switch (dev->cfg->Gain) {
268  }
269 
270  return 0;
271 }
272 
278 static int32_t PIOS_HMC5983_ReadMag(struct pios_sensor_mag_data *mag_data, float * temperature)
279 {
280  uint8_t n_read;
281  if (PIOS_HMC5983_Validate(dev) != 0)
282  return -1;
283 
284  /* don't use PIOS_HMC5983_Read and PIOS_HMC5983_Write here because the task could be
285  * switched out of context in between which would give the sensor less time to capture
286  * the next sample.
287  */
288  uint8_t addr_read = PIOS_HMC5983_DATAOUT_XMSB_REG;
289  uint8_t buffer_read[8];
290 
291  if (temperature == NULL)
292  n_read = sizeof(buffer_read) - 2;
293  else
294  n_read = sizeof(buffer_read);
295 
296  // PIOS_HMC5983_MODE_CONTINUOUS: This should not be necessary but for some reason it is coming out of continuous conversion mode
297  // PIOS_HMC5983_MODE_SINGLE: This triggers the next measurement
298  uint8_t buffer_write[2] = {
300  dev->cfg->Mode
301  };
302 
303  const struct pios_i2c_txn txn_list[] = {
304  {
305  .info = __func__,
306  .addr = PIOS_HMC5983_I2C_ADDR,
307  .rw = PIOS_I2C_TXN_WRITE,
308  .len = sizeof(addr_read),
309  .buf = &addr_read,
310  },
311  {
312  .info = __func__,
313  .addr = PIOS_HMC5983_I2C_ADDR,
314  .rw = PIOS_I2C_TXN_READ,
315  .len = n_read,
316  .buf = buffer_read,
317  },
318  {
319  .info = __func__,
320  .addr = PIOS_HMC5983_I2C_ADDR,
321  .rw = PIOS_I2C_TXN_WRITE,
322  .len = sizeof(buffer_write),
323  .buf = buffer_write,
324  },
325  };
326 
327  if (PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list)) != 0)
328  return -1;
329 
330  int16_t mag_x, mag_y, mag_z;
331  uint16_t sensitivity = PIOS_HMC5983_Config_GetSensitivity();
332  mag_x = ((int16_t) ((uint16_t)buffer_read[0] << 8) + buffer_read[1]) * 1000 / sensitivity;
333  mag_z = ((int16_t) ((uint16_t)buffer_read[2] << 8) + buffer_read[3]) * 1000 / sensitivity;
334  mag_y = ((int16_t) ((uint16_t)buffer_read[4] << 8) + buffer_read[5]) * 1000 / sensitivity;
335 
336  // Define "0" when the fiducial is in the front left of the board
337  switch (dev->orientation) {
339  mag_data->x = -mag_x;
340  mag_data->y = mag_y;
341  mag_data->z = -mag_z;
342  break;
344  mag_data->x = -mag_y;
345  mag_data->y = -mag_x;
346  mag_data->z = -mag_z;
347  break;
349  mag_data->x = mag_x;
350  mag_data->y = -mag_y;
351  mag_data->z = -mag_z;
352  break;
354  mag_data->x = mag_y;
355  mag_data->y = mag_x;
356  mag_data->z = -mag_z;
357  break;
359  mag_data->x = -mag_x;
360  mag_data->y = -mag_y;
361  mag_data->z = mag_z;
362  break;
364  mag_data->x = mag_y;
365  mag_data->y = -mag_x;
366  mag_data->z = mag_z;
367  break;
369  mag_data->x = mag_x;
370  mag_data->y = mag_y;
371  mag_data->z = mag_z;
372  break;
374  mag_data->x = -mag_y;
375  mag_data->y = mag_x;
376  mag_data->z = mag_z;
377  break;
378  }
379 
380  // calculate the temperature
381  if (temperature != NULL) {
382  *temperature = (float)(((uint16_t)buffer_read[6] << 8) + buffer_read[7]) / 128.f + 25.f;
383  }
384 
385  return 0;
386 }
387 
393 static uint8_t PIOS_HMC5983_ReadID(uint8_t out[4])
394 {
395  uint8_t retval = PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_IDA_REG, out, 3);
396  out[3] = '\0';
397  return retval;
398 }
399 
400 
410 static int32_t PIOS_HMC5983_Read(uint8_t address, uint8_t * buffer, uint8_t len)
411 {
412  if(PIOS_HMC5983_Validate(dev) != 0)
413  return -1;
414 
415  uint8_t addr_buffer[] = {
416  address,
417  };
418 
419  const struct pios_i2c_txn txn_list[] = {
420  {
421  .info = __func__,
422  .addr = PIOS_HMC5983_I2C_ADDR,
423  .rw = PIOS_I2C_TXN_WRITE,
424  .len = sizeof(addr_buffer),
425  .buf = addr_buffer,
426  }
427  ,
428  {
429  .info = __func__,
430  .addr = PIOS_HMC5983_I2C_ADDR,
431  .rw = PIOS_I2C_TXN_READ,
432  .len = len,
433  .buf = buffer,
434  }
435  };
436 
437  return PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list));
438 }
439 
448 static int32_t PIOS_HMC5983_Write(uint8_t address, uint8_t buffer)
449 {
450  if(PIOS_HMC5983_Validate(dev) != 0)
451  return -1;
452 
453  uint8_t data[] = {
454  address,
455  buffer,
456  };
457 
458  const struct pios_i2c_txn txn_list[] = {
459  {
460  .info = __func__,
461  .addr = PIOS_HMC5983_I2C_ADDR,
462  .rw = PIOS_I2C_TXN_WRITE,
463  .len = sizeof(data),
464  .buf = data,
465  }
466  ,
467  };
468 
469  return PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list));
470 }
471 
476 int32_t PIOS_HMC5983_Test(void)
477 {
478  /* Verify that ID matches (HMC5983 ID is null-terminated ASCII string "H43") */
479  char id[4];
480  PIOS_HMC5983_ReadID((uint8_t *)id);
481  if((id[0] != 'H') || (id[1] != '4') || (id[2] != '3')) // Expect H43
482  return -1;
483 
484  return 0;
485 }
486 
490 bool PIOS_HMC5983_IRQHandler(void)
491 {
492  if (PIOS_HMC5983_Validate(dev) != 0)
493  return false;
494 
495  bool woken = false;
496  PIOS_Semaphore_Give_FromISR(dev->data_ready_sema, &woken);
497 
498  return woken;
499 }
500 
504 static void PIOS_HMC5983_Task(void *parameters)
505 {
506  while (PIOS_HMC5983_Validate(dev) != 0) {
507  PIOS_Thread_Sleep(100);
508  }
509 
510  uint32_t sample_delay;
511 
512  switch (dev->cfg->M_ODR) {
514  sample_delay = 1000 / 0.75f + 0.99999f;
515  break;
517  sample_delay = 1000 / 1.5f + 0.99999f;
518  break;
519  case PIOS_HMC5983_ODR_3:
520  sample_delay = 1000 / 3.0f + 0.99999f;
521  break;
523  sample_delay = 1000 / 7.5f + 0.99999f;
524  break;
525  case PIOS_HMC5983_ODR_15:
526  sample_delay = 1000 / 15.0f + 0.99999f;
527  break;
528  case PIOS_HMC5983_ODR_30:
529  sample_delay = 1000 / 30.0f + 0.99999f;
530  break;
531  case PIOS_HMC5983_ODR_75:
532  default:
533  sample_delay = 1000 / 75.0f + 0.99999f;
534  break;
535  }
536 
537  uint32_t now = PIOS_Thread_Systime();
538 
539  while (1) {
540  if ((dev->data_ready_sema != NULL) && (dev->cfg->Mode == PIOS_HMC5983_MODE_CONTINUOUS)) {
541  if (PIOS_Semaphore_Take(dev->data_ready_sema, PIOS_SEMAPHORE_TIMEOUT_MAX) != true) {
542  PIOS_Thread_Sleep(100);
543  continue;
544  }
545  } else {
546  PIOS_Thread_Sleep_Until(&now, sample_delay);
547  }
548 
549  struct pios_sensor_mag_data mag_data;
550  if (PIOS_HMC5983_ReadMag(&mag_data, NULL) == 0)
551  PIOS_Queue_Send(dev->queue, &mag_data, 0);
552  }
553 }
554 
555 #endif /* PIOS_INCLUDE_HMC5983_I2C */
556 
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
#define PIOS_HMC5983_Sensitivity_4_7Ga
Definition: pios_hmc5983.h:93
pios_hmc5983_orientation
Definition: pios_hmc5983.h:105
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
HMC5983 functions header.
int32_t PIOS_EXTI_Init(const struct pios_exti_cfg *cfg)
#define PIOS_HMC5983_I2C_ADDR
Definition: pios_hmc5983.h:37
#define PIOS_HMC5983_ODR_1_5
Definition: pios_hmc5983.h:58
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)
uint8_t * buf
Definition: pios_i2c.h:45
#define PIOS_HMC5983_GAIN_4_0
Definition: pios_hmc5983.h:76
#define PIOS_HMC5983_Sensitivity_5_6Ga
Definition: pios_hmc5983.h:94
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
#define PIOS_HMC5983_MODE_REG
Definition: pios_hmc5983.h:42
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
enum pios_hmc5983_orientation Orientation
Definition: pios_hmc5983.h:127
#define PIOS_HMC5983_Sensitivity_1_3Ga
Definition: pios_hmc5983.h:89
#define PIOS_HMC5983_GAIN_1_3
Definition: pios_hmc5983.h:73
#define PIOS_HMC5983_Sensitivity_8_1Ga
Definition: pios_hmc5983.h:95
const struct pios_exti_cfg * exti_cfg
Definition: pios_hmc5983.h:121
#define PIOS_HMC5983_GAIN_0_88
Definition: pios_hmc5983.h:72
#define PIOS_HMC5983_MODE_CONTINUOUS
Definition: pios_hmc5983.h:82
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
#define PIOS_HMC5983_ODR_3
Definition: pios_hmc5983.h:59
struct pios_i2c_adapter * pios_i2c_t
Definition: pios_i2c.h:48
bool PIOS_HMC5983_IRQHandler(void)
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
#define PIOS_HMC5983_ODR_75
Definition: pios_hmc5983.h:63
#define PIOS_HMC5983_ODR_0_75
Definition: pios_hmc5983.h:57
int32_t PIOS_I2C_Transfer(pios_i2c_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns)
#define PIOS_HMC5983_Sensitivity_0_88Ga
Definition: pios_hmc5983.h:88
#define PIOS_HMC5983_GAIN_1_9
Definition: pios_hmc5983.h:74
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
#define PIOS_HMC5983_GAIN_5_6
Definition: pios_hmc5983.h:78
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
Pios sensor structure for generic mag data.
Definition: pios_sensors.h:54
#define PIOS_HMC5983_Sensitivity_4_0Ga
Definition: pios_hmc5983.h:92
#define PIOS_HMC5983_DATAOUT_XMSB_REG
Definition: pios_hmc5983.h:43
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
#define PIOS_HMC5983_ODR_7_5
Definition: pios_hmc5983.h:60
#define PIOS_HMC5983_Sensitivity_2_5Ga
Definition: pios_hmc5983.h:91
#define PIOS_HMC5983_DATAOUT_IDA_REG
Definition: pios_hmc5983.h:50
const char * info
Definition: pios_i2c.h:41
static struct pios_queue * queue
Definition: actuator.c:82
uint32_t len
Definition: pios_i2c.h:44
#define PIOS_HMC5983_GAIN_2_5
Definition: pios_hmc5983.h:75
#define PIOS_HMC5983_CONFIG_REG_A
Definition: pios_hmc5983.h:40
#define PIOS_HMC5983_ODR_30
Definition: pios_hmc5983.h:62
#define PIOS_Assert(test)
Definition: pios_debug.h:52
#define PIOS_HMC5983_GAIN_4_7
Definition: pios_hmc5983.h:77
#define PIOS_HMC5983_GAIN_8_1
Definition: pios_hmc5983.h:79
#define PIOS_HMC5983_Sensitivity_1_9Ga
Definition: pios_hmc5983.h:90
#define PIOS_HMC5983_ODR_15
Definition: pios_hmc5983.h:61
#define PIOS_HMC5983_CONFIG_REG_B
Definition: pios_hmc5983.h:41