dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_hmc5983.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)
35 
36 #include "pios_semaphore.h"
37 #include "pios_thread.h"
38 #include "pios_queue.h"
39 
40 /* Private constants */
41 #define HMC5983_TASK_PRIORITY PIOS_THREAD_PRIO_HIGHEST
42 #define HMC5983_TASK_STACK_BYTES 512
43 #define PIOS_HMC5983_MAX_DOWNSAMPLE 1
44 
45 /* Global Variables */
46 
47 /* Local Types */
48 enum pios_hmc5983_dev_magic {
49  PIOS_HMC5983_DEV_MAGIC = 0x3e8f18ac,
50 };
51 
52 struct hmc5983_dev {
53  pios_spi_t spi_id;
54  uint32_t slave_num;
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 };
61 
62 /* Local Variables */
63 static int32_t PIOS_HMC5983_Config(const struct pios_hmc5983_cfg *cfg);
64 static int32_t PIOS_HMC5983_ClaimBus(void);
65 static int32_t PIOS_HMC5983_ReleaseBus(void);
66 static int32_t PIOS_HMC5983_Read(uint8_t address, uint8_t *buffer, uint8_t len);
67 static int32_t PIOS_HMC5983_Write(uint8_t address, uint8_t buffer);
68 static void PIOS_HMC5983_Task(void *parameters);
69 
70 
71 static struct hmc5983_dev *dev;
72 
76 static struct hmc5983_dev *PIOS_HMC5983_alloc(void) {
77  struct hmc5983_dev *hmc5983_dev;
78 
79  hmc5983_dev = (struct hmc5983_dev *)PIOS_malloc(sizeof(*hmc5983_dev));
80  if (!hmc5983_dev) return (NULL);
81 
82  hmc5983_dev->magic = PIOS_HMC5983_DEV_MAGIC;
83 
84  hmc5983_dev->queue = PIOS_Queue_Create(PIOS_HMC5983_MAX_DOWNSAMPLE, sizeof(struct pios_sensor_mag_data));
85  if (hmc5983_dev->queue == NULL) {
86  PIOS_free(hmc5983_dev);
87  return NULL;
88  }
89 
90  hmc5983_dev->data_ready_sema = PIOS_Semaphore_Create();
91  if (hmc5983_dev->data_ready_sema == NULL) {
92  PIOS_free(hmc5983_dev);
93  return NULL;
94  }
95 
96  return hmc5983_dev;
97 }
98 
103 static int32_t PIOS_HMC5983_Validate(struct hmc5983_dev *dev)
104 {
105  if (dev == NULL)
106  return -1;
107  if (dev->magic != PIOS_HMC5983_DEV_MAGIC)
108  return -2;
109  if (dev->spi_id == 0)
110  return -3;
111  return 0;
112 }
113 
118 int32_t PIOS_HMC5983_Init(pios_spi_t spi_id, uint32_t slave_num, const struct pios_hmc5983_cfg *cfg)
119 {
120  dev = (struct hmc5983_dev *)PIOS_HMC5983_alloc();
121  if (dev == NULL)
122  return -1;
123 
124  dev->cfg = cfg;
125  dev->spi_id = spi_id;
126  dev->slave_num = slave_num;
127 
128 #ifdef PIOS_HMC5983_HAS_GPIOS
129  PIOS_EXTI_Init(cfg->exti_cfg);
130 #endif
131 
132  if (PIOS_HMC5983_Config(cfg) != 0)
133  return -2;
134 
136 
137  dev->task = PIOS_Thread_Create(PIOS_HMC5983_Task, "pios_hmc5983", HMC5983_TASK_STACK_BYTES, NULL, HMC5983_TASK_PRIORITY);
138 
139  PIOS_Assert(dev->task != NULL);
140 
141  return 0;
142 }
143 
218 static uint8_t CTRLB = 0x00;
219 static int32_t PIOS_HMC5983_Config(const struct pios_hmc5983_cfg *cfg)
220 {
221  uint8_t CTRLA = 0x00;
222  uint8_t MODE = 0x00;
223  CTRLB = 0;
224 
225  CTRLA |= (uint8_t)(PIOS_HMC5983_ENABLE_TEMP_SENSOR | cfg->Averaging | cfg->M_ODR | cfg->Meas_Conf);
226  CTRLB |= (uint8_t)(cfg->Gain);
227  MODE |= (uint8_t)(cfg->Mode);
228 
229  // CTRL_REGA
230  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_A, CTRLA) != 0)
231  return -1;
232 
233  // CTRL_REGB
234  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_B, CTRLB) != 0)
235  return -1;
236 
237  // Mode register
238  if (PIOS_HMC5983_Write(PIOS_HMC5983_MODE_REG, MODE) != 0)
239  return -1;
240 
241  return 0;
242 }
243 
249 static int32_t PIOS_HMC5983_ReadMag(struct pios_sensor_mag_data *mag_data)
250 {
251  if (PIOS_HMC5983_Validate(dev) != 0)
252  return -1;
253 
254  uint8_t buffer[6];
255  int32_t sensitivity;
256 
257  if (PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_XMSB_REG, buffer, 6) != 0)
258  return -1;
259 
260  switch (CTRLB & 0xE0) {
261  case 0x00:
262  sensitivity = PIOS_HMC5983_Sensitivity_0_88Ga;
263  break;
264  case 0x20:
265  sensitivity = PIOS_HMC5983_Sensitivity_1_3Ga;
266  break;
267  case 0x40:
268  sensitivity = PIOS_HMC5983_Sensitivity_1_9Ga;
269  break;
270  case 0x60:
271  sensitivity = PIOS_HMC5983_Sensitivity_2_5Ga;
272  break;
273  case 0x80:
274  sensitivity = PIOS_HMC5983_Sensitivity_4_0Ga;
275  break;
276  case 0xA0:
277  sensitivity = PIOS_HMC5983_Sensitivity_4_7Ga;
278  break;
279  case 0xC0:
280  sensitivity = PIOS_HMC5983_Sensitivity_5_6Ga;
281  break;
282  case 0xE0:
283  sensitivity = PIOS_HMC5983_Sensitivity_8_1Ga;
284  break;
285  default:
286  PIOS_Assert(0);
287  }
288 
289  int16_t mag_x, mag_y, mag_z;
290  mag_x = ((int16_t)((uint16_t) buffer[0] << 8) + buffer[1]) * 1000 / sensitivity;
291  mag_z = ((int16_t)((uint16_t) buffer[2] << 8) + buffer[3]) * 1000 / sensitivity;
292  mag_y = ((int16_t)((uint16_t) buffer[4] << 8) + buffer[5]) * 1000 / sensitivity;
293 
294  // Define "0" when the fiducial is in the front left of the board
295  switch (dev->cfg->Orientation) {
297  mag_data->x = -mag_x;
298  mag_data->y = mag_y;
299  mag_data->z = -mag_z;
300  break;
302  mag_data->x = -mag_y;
303  mag_data->y = -mag_x;
304  mag_data->z = -mag_z;
305  break;
307  mag_data->x = mag_x;
308  mag_data->y = -mag_y;
309  mag_data->z = -mag_z;
310  break;
312  mag_data->x = mag_y;
313  mag_data->y = mag_x;
314  mag_data->z = -mag_z;
315  break;
317  mag_data->x = -mag_x;
318  mag_data->y = -mag_y;
319  mag_data->z = mag_z;
320  break;
322  mag_data->x = mag_y;
323  mag_data->y = -mag_x;
324  mag_data->z = mag_z;
325  break;
327  mag_data->x = mag_x;
328  mag_data->y = mag_y;
329  mag_data->z = mag_z;
330  break;
332  mag_data->x = -mag_y;
333  mag_data->y = mag_x;
334  mag_data->z = mag_z;
335  break;
336  }
337 
338 #if PIOS_HMC5983_READ_TEMPERATURE
339  uint8_t temperature[2];
340  float mag_temperature;
341  if (PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_TEMPMSB_REG, temperature, 2) == 0)
342  mag_temperature = (((uint16_t)temperature[0] << 8) + temperature[1]) / 128 + 25;
343 #endif
344 
345  // This should not be necessary but for some reason it is coming out of continuous conversion mode
347 
348  return 0;
349 }
350 
356 static uint8_t PIOS_HMC5983_ReadID(uint8_t out[4])
357 {
358  uint8_t retval = PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_IDA_REG, out, 3);
359  out[3] = '\0';
360  return retval;
361 }
362 
367 static int32_t PIOS_HMC5983_ClaimBus(void)
368 {
369  if (PIOS_HMC5983_Validate(dev) != 0)
370  return -1;
371 
372  if (PIOS_SPI_ClaimBus(dev->spi_id) != 0)
373  return -2;
374 
375  PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0);
376  return 0;
377 }
378 
383 static int32_t PIOS_HMC5983_ReleaseBus(void)
384 {
385  if (PIOS_HMC5983_Validate(dev) != 0)
386  return -1;
387 
388  PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1);
389 
390  return PIOS_SPI_ReleaseBus(dev->spi_id);
391 }
392 
402 static int32_t PIOS_HMC5983_Read(uint8_t address, uint8_t *buffer, uint8_t len)
403 {
404  if (PIOS_HMC5983_ClaimBus() != 0)
405  return -1;
406 
407  PIOS_SPI_TransferByte(dev->spi_id, PIOS_HMC5983_READ_MODE | address);
408  if (PIOS_SPI_TransferBlock(dev->spi_id, NULL, buffer, len) < 0) {
409  PIOS_HMC5983_ReleaseBus();
410  return -2;
411  }
412 
413  return PIOS_HMC5983_ReleaseBus();
414 }
415 
424 static int32_t PIOS_HMC5983_Write(uint8_t address, uint8_t buffer)
425 {
426  if (PIOS_HMC5983_ClaimBus() != 0)
427  return -1;
428 
429  PIOS_SPI_TransferByte(dev->spi_id, 0x3F & address);
430  PIOS_SPI_TransferByte(dev->spi_id, buffer);
431 
432  return PIOS_HMC5983_ReleaseBus();
433 }
434 
439 int32_t PIOS_HMC5983_Test(void)
440 {
441  int32_t failed = 0;
442  uint8_t registers[3] = { 0, 0, 0 };
443  uint8_t status;
444  uint8_t ctrl_a_read;
445  uint8_t ctrl_b_read;
446  uint8_t mode_read;
448 
449  /* Verify that ID matches (HMC5983 ID is null-terminated ASCII string "H43") */
450  char id[4];
451  PIOS_HMC5983_ReadID((uint8_t *)id);
452  if ((id[0] != 'H') || (id[1] != '4') || (id[2] != '3')) // Expect H43
453  return -1;
454 
455  /* Backup existing configuration */
456  if (PIOS_HMC5983_Read(PIOS_HMC5983_CONFIG_REG_A, registers, 3) != 0)
457  return -1;
458 
459  /* Stop the device and read out last value */
460  PIOS_DELAY_WaitmS(10);
461  if (PIOS_HMC5983_Write(PIOS_HMC5983_MODE_REG, PIOS_HMC5983_MODE_IDLE) != 0)
462  return -1;
463  if (PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_STATUS_REG, &status, 1) != 0)
464  return -1;
465  if (PIOS_HMC5983_ReadMag(&values) != 0)
466  return -1;
467 
468  /*
469  * Put HMC5983 into self test mode
470  * This is done by placing measurement config into positive (0x01) or negative (0x10) bias
471  * and then placing the mode register into single-measurement mode. This causes the HMC5983
472  * to create an artificial magnetic field of ~1.1 Gauss.
473  *
474  * If gain were PIOS_HMC5983_GAIN_2_5, for example, X and Y will read around +766 LSB
475  * (1.16 Ga * 660 LSB/Ga) and Z would read around +713 LSB (1.08 Ga * 660 LSB/Ga)
476  *
477  * Changing measurement config back to PIOS_HMC5983_MEASCONF_NORMAL will leave self-test mode.
478  */
479  PIOS_DELAY_WaitmS(10);
481  return -1;
482  PIOS_DELAY_WaitmS(10);
483  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_B, PIOS_HMC5983_GAIN_8_1) != 0)
484  return -1;
485  PIOS_DELAY_WaitmS(10);
486  if (PIOS_HMC5983_Write(PIOS_HMC5983_MODE_REG, PIOS_HMC5983_MODE_SINGLE) != 0)
487  return -1;
488 
489  /* Must wait for value to be updated */
490  PIOS_DELAY_WaitmS(200);
491 
492  if (PIOS_HMC5983_ReadMag(&values) != 0)
493  return -1;
494 
495  PIOS_HMC5983_Read(PIOS_HMC5983_CONFIG_REG_A, &ctrl_a_read, 1);
496  PIOS_HMC5983_Read(PIOS_HMC5983_CONFIG_REG_B, &ctrl_b_read, 1);
497  PIOS_HMC5983_Read(PIOS_HMC5983_MODE_REG, &mode_read, 1);
498  PIOS_HMC5983_Read(PIOS_HMC5983_DATAOUT_STATUS_REG, &status, 1);
499 
500  /* Restore backup configuration */
501  PIOS_DELAY_WaitmS(10);
502  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_A, registers[0]) != 0)
503  return -1;
504  PIOS_DELAY_WaitmS(10);
505  if (PIOS_HMC5983_Write(PIOS_HMC5983_CONFIG_REG_B, registers[1]) != 0)
506  return -1;
507  PIOS_DELAY_WaitmS(10);
508  if (PIOS_HMC5983_Write(PIOS_HMC5983_MODE_REG, registers[2]) != 0)
509  return -1;
510 
511  return failed;
512 }
513 
517 bool PIOS_HMC5983_IRQHandler(void)
518 {
519  if (PIOS_HMC5983_Validate(dev) != 0)
520  return false;
521 
522  bool woken = false;
523  PIOS_Semaphore_Give_FromISR(dev->data_ready_sema, &woken);
524 
525  return woken;
526 }
527 
531 static void PIOS_HMC5983_Task(void *parameters)
532 {
533  while (1) {
534  if (PIOS_HMC5983_Validate(dev) != 0) {
535  PIOS_Thread_Sleep(100);
536  continue;
537  }
538 
539  if (PIOS_Semaphore_Take(dev->data_ready_sema, PIOS_SEMAPHORE_TIMEOUT_MAX) != true) {
540  PIOS_Thread_Sleep(100);
541  continue;
542  }
543 
544  struct pios_sensor_mag_data mag_data;
545  if (PIOS_HMC5983_ReadMag(&mag_data) == 0)
546  PIOS_Queue_Send(dev->queue, &mag_data, 0);
547  }
548 }
549 
550 #endif /* PIOS_INCLUDE_HMC5983 */
551 
#define PIOS_HMC5983_MEASCONF_BIAS_POS
Definition: pios_hmc5983.h:68
#define PIOS_HMC5983_Sensitivity_4_7Ga
Definition: pios_hmc5983.h:93
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 PIOS_HMC5983_ENABLE_TEMP_SENSOR
Definition: pios_hmc5983.h:103
#define PIOS_HMC5983_READ_MODE
Definition: pios_hmc5983.h:102
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
int32_t PIOS_EXTI_Init(const struct pios_exti_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
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
#define PIOS_HMC5983_DATAOUT_STATUS_REG
Definition: pios_hmc5983.h:49
#define PIOS_HMC5983_Sensitivity_5_6Ga
Definition: pios_hmc5983.h:94
#define PIOS_HMC5983_MODE_REG
Definition: pios_hmc5983.h:42
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int16_t status
Definition: main.c:61
#define PIOS_HMC5983_Sensitivity_1_3Ga
Definition: pios_hmc5983.h:89
#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_MODE_CONTINUOUS
Definition: pios_hmc5983.h:82
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
bool PIOS_HMC5983_IRQHandler(void)
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
#define PIOS_HMC5983_MODE_SINGLE
Definition: pios_hmc5983.h:83
#define PIOS_HMC5983_Sensitivity_0_88Ga
Definition: pios_hmc5983.h:88
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_Sensitivity_2_5Ga
Definition: pios_hmc5983.h:91
#define PIOS_HMC5983_DATAOUT_IDA_REG
Definition: pios_hmc5983.h:50
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
static struct pios_queue * queue
Definition: actuator.c:82
uint16_t values[FPPROTO_MAX_SERVOS]
#define PIOS_HMC5983_DATAOUT_TEMPMSB_REG
Definition: pios_hmc5983.h:53
#define PIOS_HMC5983_CONFIG_REG_A
Definition: pios_hmc5983.h:40
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
Definition: pios_delay.c:140
#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_MODE_IDLE
Definition: pios_hmc5983.h:84
#define PIOS_HMC5983_ODR_15
Definition: pios_hmc5983.h:61
int32_t PIOS_HMC5983_Init(pios_spi_t spi_id, uint32_t slave_num, const struct pios_hmc5983_cfg *cfg)
#define PIOS_HMC5983_CONFIG_REG_B
Definition: pios_hmc5983.h:41