PX4 Firmware
PX4 Autopilot Software http://px4.io
lis3mdl.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file lis3mdl.cpp
36  *
37  * Driver for the LIS3MDL magnetometer connected via I2C or SPI.
38  *
39  * Based on the hmc5883 driver.
40  */
41 
42 #include <px4_platform_common/time.h>
43 #include "lis3mdl.h"
44 
45 LIS3MDL::LIS3MDL(device::Device *interface, const char *path, enum Rotation rotation) :
46  CDev("LIS3MDL", path),
47  ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(interface->get_device_id())),
48  _interface(interface),
49  _reports(nullptr),
50  _scale{},
51  _last_report{},
52  _mag_topic(nullptr),
53  _comms_errors(perf_alloc(PC_COUNT, "lis3mdl_comms_errors")),
54  _conf_errors(perf_alloc(PC_COUNT, "lis3mdl_conf_errors")),
55  _range_errors(perf_alloc(PC_COUNT, "lis3mdl_range_errors")),
56  _sample_perf(perf_alloc(PC_ELAPSED, "lis3mdl_read")),
57  _calibrated(false),
58  _continuous_mode_set(false),
60  _rotation(rotation),
62  _class_instance(-1),
64  _range_ga(4.0f),
65  _range_scale(0), // default range scale from counts to gauss */
67  _cntl_reg1(
68  CNTL_REG1_DEFAULT), // 1 11 111 0 0 | temp-en, ultra high performance (XY), fast_odr disabled, self test disabled
69  _cntl_reg2(CNTL_REG2_DEFAULT), // 4 gauss FS range, reboot settings default
70  _cntl_reg3(CNTL_REG3_DEFAULT), // operating mode CONTINUOUS!
71  _cntl_reg4(CNTL_REG4_DEFAULT), // Z-axis ultra high performance mode
72  _cntl_reg5(CNTL_REG5_DEFAULT), // fast read disabled, continious update disabled (block data update)
73  _range_bits(0),
76 {
77  // set the device type from the interface
78  _device_id.devid_s.bus_type = _interface->get_device_bus_type();
79  _device_id.devid_s.bus = _interface->get_device_bus();
80  _device_id.devid_s.address = _interface->get_device_address();
81  _device_id.devid_s.devtype = DRV_MAG_DEVTYPE_LIS3MDL;
82 
83  // default scaling
84  _scale.x_offset = 0;
85  _scale.x_scale = 1.0f;
86  _scale.y_offset = 0;
87  _scale.y_scale = 1.0f;
88  _scale.z_offset = 0;
89  _scale.z_scale = 1.0f;
90 }
91 
93 {
94  /* make sure we are truly inactive */
95  stop();
96 
97  if (_mag_topic != nullptr) {
99  }
100 
101  if (_reports != nullptr) {
102  delete _reports;
103  }
104 
105  if (_class_instance != -1) {
107  }
108 
109  // free perf counters
114 }
115 
116 int
117 LIS3MDL::calibrate(struct file *file_pointer, unsigned enable)
118 {
119  struct mag_report report;
120  ssize_t sz;
121  int ret = 1;
122  uint8_t num_samples = 10;
123 
124  // XXX do something smarter here
125  int fd = (int)enable;
126 
127  float sum_excited[3] = {0.0f, 0.0f, 0.0f};
128  float sum_non_excited[3] = {0.0f, 0.0f, 0.0f};
129 
130  /* start the sensor polling at 50 Hz */
131  if (ioctl(file_pointer, SENSORIOCSPOLLRATE, 50) != OK) {
132  warn("FAILED: SENSORIOCSPOLLRATE 50Hz");
133  ret = 1;
134  goto out;
135  }
136 
137  /* Set to 12 Gauss */
138  if (ioctl(file_pointer, MAGIOCSRANGE, 12) != OK) {
139  PX4_WARN("FAILED: MAGIOCSRANGE 12 Ga");
140  ret = 1;
141  goto out;
142  }
143 
144  px4_usleep(20000);
145 
146  /* discard 10 samples to let the sensor settle */
147  for (uint8_t i = 0; i < num_samples; i++) {
148  struct pollfd fds;
149 
150  /* wait for data to be ready */
151  fds.fd = fd;
152  fds.events = POLLIN;
153  ret = ::poll(&fds, 1, 2000);
154 
155  if (ret != 1) {
156  warn("ERROR: TIMEOUT 1");
157  goto out;
158  }
159 
160  /* now go get it */
161  sz = ::read(fd, &report, sizeof(report));
162 
163  if (sz != sizeof(report)) {
164  warn("ERROR: READ 1");
165  ret = -EIO;
166  goto out;
167  }
168  }
169 
170  /* read the sensor up to 10x */
171  for (uint8_t i = 0; i < num_samples; i++) {
172  struct pollfd fds;
173 
174  /* wait for data to be ready */
175  fds.fd = fd;
176  fds.events = POLLIN;
177  ret = ::poll(&fds, 1, 2000);
178 
179  if (ret != 1) {
180  warn("ERROR: TIMEOUT 2");
181  goto out;
182  }
183 
184  /* now go get it */
185  sz = ::read(fd, &report, sizeof(report));
186 
187  if (sz != sizeof(report)) {
188  warn("ERROR: READ 2");
189  ret = -EIO;
190  goto out;
191  }
192 
193  sum_non_excited[0] += report.x;
194  sum_non_excited[1] += report.y;
195  sum_non_excited[2] += report.z;
196  }
197 
198  sum_non_excited[0] /= num_samples;
199  sum_non_excited[1] /= num_samples;
200  sum_non_excited[2] /= num_samples;
201 
202  /* excite strap and take measurements */
203  if (ioctl(file_pointer, MAGIOCEXSTRAP, 1) != OK) {
204  PX4_WARN("FAILED: MAGIOCEXSTRAP 1");
205  ret = 1;
206  goto out;
207  }
208 
209  px4_usleep(60000);
210 
211  /* discard 10 samples to let the sensor settle */
212  for (uint8_t i = 0; i < num_samples; i++) {
213  struct pollfd fds;
214 
215  /* wait for data to be ready */
216  fds.fd = fd;
217  fds.events = POLLIN;
218  ret = ::poll(&fds, 1, 2000);
219 
220  if (ret != 1) {
221  warn("ERROR: TIMEOUT 1");
222  goto out;
223  }
224 
225  /* now go get it */
226  sz = ::read(fd, &report, sizeof(report));
227 
228  if (sz != sizeof(report)) {
229  warn("ERROR: READ 1");
230  ret = -EIO;
231  goto out;
232  }
233  }
234 
235  /* read the sensor up to 10x */
236  for (uint8_t i = 0; i < 10; i++) {
237  struct pollfd fds;
238 
239  /* wait for data to be ready */
240  fds.fd = fd;
241  fds.events = POLLIN;
242  ret = ::poll(&fds, 1, 2000);
243 
244  if (ret != 1) {
245  warn("ERROR: TIMEOUT 2");
246  goto out;
247  }
248 
249  /* now go get it */
250  sz = ::read(fd, &report, sizeof(report));
251 
252  if (sz != sizeof(report)) {
253  warn("ERROR: READ 2");
254  ret = -EIO;
255  goto out;
256  }
257 
258  sum_excited[0] += report.x;
259  sum_excited[1] += report.y;
260  sum_excited[2] += report.z;
261  }
262 
263  sum_excited[0] /= num_samples;
264  sum_excited[1] /= num_samples;
265  sum_excited[2] /= num_samples;
266 
267  if (1.0f < fabsf(sum_excited[0] - sum_non_excited[0]) && fabsf(sum_excited[0] - sum_non_excited[0]) < 3.0f &&
268  1.0f < fabsf(sum_excited[1] - sum_non_excited[1]) && fabsf(sum_excited[1] - sum_non_excited[1]) < 3.0f &&
269  0.1f < fabsf(sum_excited[2] - sum_non_excited[2]) && fabsf(sum_excited[2] - sum_non_excited[2]) < 1.0f) {
270  ret = OK;
271 
272  } else {
273  ret = -EIO;
274  goto out;
275  }
276 
277 out:
278 
279  /* set back to normal mode */
280  set_range(4);
282 
283  px4_usleep(20000);
284 
285  return ret;
286 }
287 
288 int
290 {
291  bool offset_valid;
292 
293  if ((-2.0f * FLT_EPSILON < _scale.x_offset && _scale.x_offset < 2.0f * FLT_EPSILON) &&
294  (-2.0f * FLT_EPSILON < _scale.y_offset && _scale.y_offset < 2.0f * FLT_EPSILON) &&
295  (-2.0f * FLT_EPSILON < _scale.z_offset && _scale.z_offset < 2.0f * FLT_EPSILON)) {
296  /* offset is zero */
297  offset_valid = false;
298 
299  } else {
300  offset_valid = true;
301  }
302 
303  /* return 0 if calibrated, 1 else */
304  return !offset_valid;
305 }
306 
307 int
309 {
310  bool scale_valid;
311 
312  if ((-FLT_EPSILON + 1.0f < _scale.x_scale && _scale.x_scale < FLT_EPSILON + 1.0f) &&
313  (-FLT_EPSILON + 1.0f < _scale.y_scale && _scale.y_scale < FLT_EPSILON + 1.0f) &&
314  (-FLT_EPSILON + 1.0f < _scale.z_scale && _scale.z_scale < FLT_EPSILON + 1.0f)) {
315  /* scale is one */
316  scale_valid = false;
317 
318  } else {
319  scale_valid = true;
320  }
321 
322  /* return 0 if calibrated, 1 else */
323  return !scale_valid;
324 }
325 
326 int
328 {
329 #pragma pack(push, 1)
330  struct {
331  uint8_t x[2];
332  uint8_t y[2];
333  uint8_t z[2];
334  } lis_report;
335 
336  struct {
337  int16_t x;
338  int16_t y;
339  int16_t z;
340  int16_t t;
341  } report;
342 #pragma pack(pop)
343 
344  int ret = 0;
345  uint8_t buf_rx[2] = {0};
346 
347  float xraw_f;
348  float yraw_f;
349  float zraw_f;
350 
351  struct mag_report new_mag_report;
352  bool sensor_is_onboard = false;
353 
355 
356  new_mag_report.timestamp = hrt_absolute_time();
357  new_mag_report.error_count = perf_event_count(_comms_errors);
358  new_mag_report.scaling = _range_scale;
359  new_mag_report.device_id = _device_id.devid;
360 
361  ret = _interface->read(ADDR_OUT_X_L, (uint8_t *)&lis_report, sizeof(lis_report));
362 
363  /**
364  * Silicon Bug: the X axis will be read instead of the temperature registers if you do a sequential read through XYZ.
365  * The temperature registers must be addressed directly.
366  */
367  ret = _interface->read(ADDR_OUT_T_L, (uint8_t *)&buf_rx, sizeof(buf_rx));
368 
369  if (ret != OK) {
371  PX4_WARN("Register read error.");
372  return ret;
373  }
374 
375  report.x = (int16_t)((lis_report.x[1] << 8) | lis_report.x[0]);
376  report.y = (int16_t)((lis_report.y[1] << 8) | lis_report.y[0]);
377  report.z = (int16_t)((lis_report.z[1] << 8) | lis_report.z[0]);
378 
379  report.t = (int16_t)((buf_rx[1] << 8) | buf_rx[0]);
380 
381  float temperature = report.t;
382  new_mag_report.temperature = 25.0f + (temperature / 8.0f);
383 
384  // XXX revisit for SPI part, might require a bus type IOCTL
385 
386  unsigned dummy = 0;
387  sensor_is_onboard = !_interface->ioctl(MAGIOCGEXTERNAL, dummy);
388  new_mag_report.is_external = !sensor_is_onboard;
389 
390  /**
391  * RAW outputs
392  */
393  new_mag_report.x_raw = report.x;
394  new_mag_report.y_raw = report.y;
395  new_mag_report.z_raw = report.z;
396 
397  xraw_f = report.x;
398  yraw_f = report.y;
399  zraw_f = report.z;
400 
401  // apply user specified rotation
402  rotate_3f(_rotation, xraw_f, yraw_f, zraw_f);
403 
404  new_mag_report.x = ((xraw_f * _range_scale) - _scale.x_offset) * _scale.x_scale;
405  /* flip axes and negate value for y */
406  new_mag_report.y = ((yraw_f * _range_scale) - _scale.y_offset) * _scale.y_scale;
407  /* z remains z */
408  new_mag_report.z = ((zraw_f * _range_scale) - _scale.z_offset) * _scale.z_scale;
409 
410  if (!(_pub_blocked)) {
411 
412  if (_mag_topic != nullptr) {
413  /* publish it */
414  orb_publish(ORB_ID(sensor_mag), _mag_topic, &new_mag_report);
415 
416  } else {
417  _mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &new_mag_report,
418  &_orb_class_instance, (sensor_is_onboard) ? ORB_PRIO_HIGH : ORB_PRIO_MAX);
419 
420  if (_mag_topic == nullptr) {
421  DEVICE_DEBUG("ADVERT FAIL");
422  }
423  }
424  }
425 
426  _last_report = new_mag_report;
427 
428  /* post a report to the ring */
429  _reports->force(&new_mag_report);
430 
431  /* notify anyone waiting for data */
432  poll_notify(POLLIN);
433 
434  ret = OK;
435 
437  return ret;
438 }
439 
440 void
442 {
443  /* _measure_interval == 0 is used as _task_should_exit */
444  if (_measure_interval == 0) {
445  return;
446  }
447 
448  /* Collect last measurement at the start of every cycle */
449  if (collect() != OK) {
450  DEVICE_DEBUG("collection error");
451  /* restart the measurement state machine */
452  start();
453  return;
454  }
455 
456 
457  if (measure() != OK) {
458  DEVICE_DEBUG("measure error");
459  }
460 
461  if (_measure_interval > 0) {
462  /* schedule a fresh cycle call when the measurement is done */
463  ScheduleDelayed(LIS3MDL_CONVERSION_INTERVAL);
464  }
465 }
466 
467 int
469 {
470  int ret = PX4_ERROR;
471 
472  ret = CDev::init();
473 
474  if (ret != OK) {
475  DEVICE_DEBUG("CDev init failed");
476  return ret;
477  }
478 
479  /* allocate basic report buffers */
480  _reports = new ringbuffer::RingBuffer(2, sizeof(mag_report));
481 
482  if (_reports == nullptr) {
483  return PX4_ERROR;
484  }
485 
486  /* reset the device configuration */
487  reset();
488 
490 
491  return PX4_OK;
492 }
493 
494 int
495 LIS3MDL::ioctl(struct file *file_pointer, int cmd, unsigned long arg)
496 {
497  unsigned dummy = 0;
498 
499  switch (cmd) {
500  case SENSORIOCSPOLLRATE: {
501  switch (arg) {
502 
503  /* zero would be bad */
504  case 0:
505  return -EINVAL;
506 
508  /* do we need to start internal polling? */
509  bool not_started = (_measure_interval == 0);
510 
511  /* set interval for next measurement to minimum legal value */
513 
514  /* if we need to start the poll state machine, do it */
515  if (not_started) {
516  start();
517  }
518 
519  return PX4_OK;
520  }
521 
522  /* Uses arg (hz) for a custom poll rate */
523  default: {
524  /* do we need to start internal polling? */
525  bool not_started = (_measure_interval == 0);
526 
527  /* convert hz to tick interval via microseconds */
528  unsigned interval = (1000000 / arg);
529 
530  /* update interval for next measurement */
531  _measure_interval = interval;
532 
533  /* if we need to start the poll state machine, do it */
534  if (not_started) {
535  start();
536  }
537 
538  return PX4_OK;
539  }
540  }
541  }
542 
543  case SENSORIOCRESET:
544  return reset();
545 
546  case MAGIOCSRANGE:
547  return set_range(arg);
548 
549  case MAGIOCSSCALE:
550  /* set new scale factors */
551  memcpy(&_scale, (struct mag_calibration_s *)arg, sizeof(_scale));
552  return 0;
553 
554  case MAGIOCGSCALE:
555  /* copy out scale factors */
556  memcpy((struct mag_calibration_s *)arg, &_scale, sizeof(_scale));
557  return 0;
558 
559  case MAGIOCCALIBRATE:
560  return calibrate(file_pointer, arg);
561 
562  case MAGIOCEXSTRAP:
563  return set_excitement(arg);
564 
565  case MAGIOCGEXTERNAL:
566  DEVICE_DEBUG("MAGIOCGEXTERNAL in main driver");
567  return _interface->ioctl(cmd, dummy);
568 
569  case DEVIOCGDEVICEID:
570  return _interface->ioctl(cmd, dummy);
571 
572  default:
573  /* give it to the superclass */
574  return CDev::ioctl(file_pointer, cmd, arg);
575  }
576 }
577 
578 int
580 {
581  int ret = 0;
582 
583  /* Send the command to begin a measurement. */
584  if ((_mode == CONTINUOUS) && !_continuous_mode_set) {
586  _continuous_mode_set = true;
587 
588  } else if (_mode == SINGLE) {
590  _continuous_mode_set = false;
591  }
592 
593 
594  if (ret != OK) {
596  }
597 
598  return ret;
599 }
600 
601 void
603 {
606  PX4_INFO("poll interval: %u", _measure_interval);
607  print_message(_last_report);
608  _reports->print_info("report queue");
609 }
610 
611 int
613 {
614  int ret = 0;
615 
617 
618  if (ret != OK) {
619  return PX4_ERROR;
620  }
621 
622  ret = set_range(_range_ga);
623 
624  if (ret != OK) {
625  return PX4_ERROR;
626  }
627 
628  return PX4_OK;
629 }
630 
631 int
632 LIS3MDL::read(struct file *file_pointer, char *buffer, size_t buffer_len)
633 {
634  unsigned count = buffer_len / sizeof(struct mag_report);
635  struct mag_report *mag_buf = reinterpret_cast<struct mag_report *>(buffer);
636  int ret = 0;
637 
638  /* buffer must be large enough */
639  if (count < 1) {
640  return -ENOSPC;
641  }
642 
643  /* if automatic measurement is enabled */
644  if (_measure_interval > 0) {
645  /*
646  * While there is space in the caller's buffer, and reports, copy them.
647  * Note that we may be pre-empted by the workq thread while we are doing this;
648  * we are careful to avoid racing with them.
649  */
650  while (count--) {
651  if (_reports->get(mag_buf)) {
652  ret += sizeof(struct mag_report);
653  mag_buf++;
654  }
655  }
656 
657  /* if there was no data, warn the caller */
658  return ret ? ret : -EAGAIN;
659  }
660 
661  /* manual measurement - run one conversion */
662  /* XXX really it'd be nice to lock against other readers here */
663  do {
664  _reports->flush();
665 
666  /* trigger a measurement */
667  if (measure() != OK) {
668  ret = -EIO;
669  break;
670  }
671 
672  /* wait for it to complete */
673  px4_usleep(LIS3MDL_CONVERSION_INTERVAL);
674 
675  /* run the collection phase */
676  if (collect() != OK) {
677  ret = -EIO;
678  break;
679  }
680 
681  if (_reports->get(mag_buf)) {
682  ret = sizeof(struct mag_report);
683  }
684  } while (0);
685 
686  return ret;
687 }
688 
689 int
691 {
697 
698  return PX4_OK;
699 }
700 
701 int
702 LIS3MDL::set_excitement(unsigned enable)
703 {
704  int ret;
705  /* arm the excitement strap */
707 
708  if (ret != OK) {
710  }
711 
712  _cntl_reg1 &= ~0x01; // reset previous excitement mode
713 
714  if (enable > 0) {
715  _cntl_reg1 |= 0x01;
716  }
717 
718  ::printf("set_excitement enable=%d cntl1=0x%x\n", (int)enable, (unsigned)_cntl_reg1);
719 
720  ret = write_reg(ADDR_CTRL_REG1, _cntl_reg1);
721 
722  if (ret != OK) {
724  }
725 
726  uint8_t conf_reg_ret = 0;
727  read_reg(ADDR_CTRL_REG1, conf_reg_ret);
728 
729  //print_info();
730 
731  return !(_cntl_reg1 == conf_reg_ret);
732 }
733 
734 int
735 LIS3MDL::set_range(unsigned range)
736 {
737  if (range <= 4) {
738  _range_bits = 0x00;
739  _range_scale = 1.0f / 6842.0f;
740  _range_ga = 4.0f;
741 
742  } else if (range <= 8) {
743  _range_bits = 0x01;
744  _range_scale = 1.0f / 3421.0f;
745  _range_ga = 8.0f;
746 
747  } else if (range <= 12) {
748  _range_bits = 0x02;
749  _range_scale = 1.0f / 2281.0f;
750  _range_ga = 12.0f;
751 
752  } else {
753  _range_bits = 0x03;
754  _range_scale = 1.0f / 1711.0f;
755  _range_ga = 16.0f;
756  }
757 
758  int ret = 0;
759 
760  /*
761  * Send the command to set the range
762  */
763  ret = write_reg(ADDR_CTRL_REG2, (_range_bits << 5));
764 
765  if (ret != OK) {
767  }
768 
769  uint8_t range_bits_in = 0;
770  ret = read_reg(ADDR_CTRL_REG2, range_bits_in);
771 
772  if (ret != OK) {
774  }
775 
776  if (range_bits_in == (_range_bits << 5)) {
777  return PX4_OK;
778 
779  } else {
780  return PX4_ERROR;
781  }
782 }
783 
784 void
786 {
787  /* reset the report ring and state machine */
788  _reports->flush();
789 
791 
792  /* schedule a cycle to start things */
793  ScheduleNow();
794 }
795 
796 void
798 {
799  if (_measure_interval > 0) {
800  /* ensure no new items are queued while we cancel this one */
801  _measure_interval = 0;
802  ScheduleClear();
803  }
804 }
805 
806 int
807 LIS3MDL::read_reg(uint8_t reg, uint8_t &val)
808 {
809  uint8_t buf = val;
810  int ret = _interface->read(reg, &buf, 1);
811  val = buf;
812  return ret;
813 }
814 
815 int
816 LIS3MDL::write_reg(uint8_t reg, uint8_t val)
817 {
818  uint8_t buf = val;
819  return _interface->write(reg, &buf, 1);
820 }
#define MAGIOCGSCALE
copy the mag scaling constants to the structure pointed to by (arg)
Definition: drv_mag.h:76
void print_info()
Diagnostics - print some basic information about the driver.
Definition: lis3mdl.cpp:602
#define MAGIOCGEXTERNAL
determine if mag is external or onboard
Definition: drv_mag.h:88
uint8_t _cntl_reg5
Definition: lis3mdl.h:177
int reset()
Resets the device.
Definition: lis3mdl.cpp:612
virtual int read(struct file *file_pointer, char *buffer, size_t buffer_len)
Definition: lis3mdl.cpp:632
measure the time elapsed performing an event
Definition: perf_counter.h:56
int _class_instance
Definition: lis3mdl.h:166
int read_reg(uint8_t reg, uint8_t &val)
Reads a register.
Definition: lis3mdl.cpp:807
#define MAGIOCEXSTRAP
excite strap
Definition: drv_mag.h:85
uint8_t _range_bits
Definition: lis3mdl.h:178
uint8_t _cntl_reg3
Definition: lis3mdl.h:175
virtual int register_class_devname(const char *class_devname)
Register a class device name, automatically adding device class instance suffix if need be...
Definition: CDev.cpp:78
#define ADDR_CTRL_REG3
Definition: lps25h.cpp:56
#define ADDR_CTRL_REG2
Definition: lps25h.cpp:55
#define SENSOR_POLLRATE_DEFAULT
poll at driver normal rate
Definition: drv_sensor.h:136
__EXPORT void rotate_3f(enum Rotation rot, float &x, float &y, float &z)
rotate a 3 element float vector in-place
Definition: rotation.cpp:63
int write_reg(uint8_t reg, uint8_t val)
Writes a register.
Definition: lis3mdl.cpp:816
enum OPERATING_MODE _mode
Definition: lis3mdl.h:161
#define ADDR_OUT_X_L
Definition: l3gd20.cpp:97
used for info()
Definition: lis3mdl.h:148
mag scaling factors; Vout = (Vin * Vscale) + Voffset
Definition: drv_mag.h:56
Device * _interface
Definition: lis3mdl.h:140
perf_counter_t _sample_perf
Definition: lis3mdl.h:155
count the number of times an event occurs
Definition: perf_counter.h:55
bool _continuous_mode_set
Definition: lis3mdl.h:159
#define FLT_EPSILON
#define DRV_MAG_DEVTYPE_LIS3MDL
Definition: drv_sensor.h:59
#define CNTL_REG5_DEFAULT
Definition: lis3mdl.h:91
perf_counter_t _comms_errors
Definition: lis3mdl.h:152
uint8_t _cntl_reg4
Definition: lis3mdl.h:176
float _range_scale
Definition: lis3mdl.h:170
virtual void poll_notify(pollevent_t events)
Report new poll events.
Definition: CDev.cpp:330
#define MAGIOCSRANGE
set the measurement range to handle (at least) arg Gauss
Definition: drv_mag.h:79
#define ADDR_CTRL_REG5
Definition: l3gd20.cpp:93
void stop()
Stop the automatic measurement state machine.
Definition: lis3mdl.cpp:797
float x_offset
Definition: drv_mag.h:57
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
Definition: drv_sensor.h:134
virtual int ioctl(struct file *file_pointer, int cmd, unsigned long arg)
Definition: lis3mdl.cpp:495
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
#define MODE_REG_SINGLE_MODE
Definition: HMC5883.hpp:106
int set_excitement(unsigned enable)
Performs the on-sensor scale calibration routine.
Definition: lis3mdl.cpp:702
int measure()
Issue a measurement command.
Definition: lis3mdl.cpp:579
device identifier information
Definition: Device.hpp:240
void perf_count(perf_counter_t handle)
Count a performance event.
void Run() override
Performs a poll cycle; collect from the previous measurement and start a new one. ...
Definition: lis3mdl.cpp:441
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
Definition: drv_mag.h:73
#define MODE_REG_CONTINOUS_MODE
Definition: HMC5883.hpp:105
#define ADDR_CTRL_REG4
Definition: lps25h.cpp:57
void perf_free(perf_counter_t handle)
Free a counter.
#define MAG_BASE_DEVICE_PATH
Definition: drv_mag.h:47
void init()
Activates/configures the hardware registers.
#define MAGIOCCALIBRATE
perform self-calibration, update scale factors to canonical units
Definition: drv_mag.h:82
virtual int unregister_class_devname(const char *class_devname, unsigned class_instance)
Register a class device name, automatically adding device class instance suffix if need be...
Definition: CDev.cpp:109
#define perf_alloc(a, b)
Definition: px4io.h:59
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
perf_counter_t _range_errors
Definition: lis3mdl.h:154
#define LIS3MDL_CONVERSION_INTERVAL
LIS3MDL internal constants and data structures.
Definition: lis3mdl.h:61
uint8_t _temperature_counter
Definition: lis3mdl.h:179
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
struct mag_calibration_s _scale
Definition: lis3mdl.h:146
LIS3MDL(device::Device *interface, const char *path, enum Rotation rotation)
Definition: lis3mdl.cpp:45
perf_counter_t _conf_errors
Definition: lis3mdl.h:153
float y_offset
Definition: drv_mag.h:59
int check_offset()
Check the current offset calibration.
Definition: lis3mdl.cpp:289
enum Rotation _rotation
Definition: lis3mdl.h:162
int set_range(unsigned range)
Sets the sensor internal range to handle at least the argument in Gauss.
Definition: lis3mdl.cpp:735
void start()
Initialises the automatic measurement state machine and start it.
Definition: lis3mdl.cpp:785
#define CNTL_REG3_DEFAULT
Definition: lis3mdl.h:89
void perf_end(perf_counter_t handle)
End a performance event.
#define CNTL_REG1_DEFAULT
Definition: lis3mdl.h:87
Shared defines for the LIS3MDL driver.
int fd
Definition: dataman.cpp:146
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
orb_advert_t _mag_topic
Definition: lis3mdl.h:150
float _range_ga
Definition: lis3mdl.h:169
int _orb_class_instance
Definition: lis3mdl.h:167
float z_offset
Definition: drv_mag.h:61
int calibrate(struct file *file_pointer, unsigned enable)
Performs the on-sensor scale calibration routine.
Definition: lis3mdl.cpp:117
#define ADDR_CTRL_REG1
Definition: lps25h.cpp:54
virtual ~LIS3MDL()
Definition: lis3mdl.cpp:92
uint8_t _temperature_error_count
Definition: lis3mdl.h:180
int set_default_register_values()
Configures the device with default register values.
Definition: lis3mdl.cpp:690
uint8_t _cntl_reg1
Definition: lis3mdl.h:173
struct @83::@85::@87 file
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
#define SENSORIOCRESET
Reset the sensor to its default configuration.
Definition: drv_sensor.h:141
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
#define CNTL_REG4_DEFAULT
Definition: lis3mdl.h:90
int orb_unadvertise(orb_advert_t handle)
Definition: uORB.cpp:65
Fundamental base class for all physical drivers (I2C, SPI).
Definition: Device.hpp:65
Definition: bst.cpp:62
uint8_t _check_state_cnt
Definition: lis3mdl.h:172
#define ADDR_OUT_T_L
Definition: lis3mdl.h:81
int collect()
Collect the result of the most recent measurement.
Definition: lis3mdl.cpp:327
bool _calibrated
the calibration is valid
Definition: lis3mdl.h:158
virtual int init()
Definition: lis3mdl.cpp:468
#define OK
Definition: uavcan_main.cpp:71
#define CNTL_REG2_DEFAULT
Definition: lis3mdl.h:88
bool _pub_blocked
true if publishing should be blocked
Definition: CDev.hpp:91
unsigned int _measure_interval
Definition: lis3mdl.h:164
uint8_t _cntl_reg2
Definition: lis3mdl.h:174
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
Definition: uORB.cpp:53
int check_scale()
Check the current scale calibration.
Definition: lis3mdl.cpp:308
#define warn(...)
Definition: err.h:94
void perf_begin(perf_counter_t handle)
Begin a performance event.
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
virtual int poll(file_t *filep, px4_pollfd_struct_t *fds, bool setup)
Perform a poll setup/teardown operation.
Definition: CDev.cpp:213
ringbuffer::RingBuffer * _reports
Definition: lis3mdl.h:144
#define mag_report
Definition: drv_mag.h:53