PX4 Firmware
PX4 Autopilot Software http://px4.io
bmm150.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2014 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 bmm150.cpp
36  * Driver for the Bosch BMM 150 MEMS magnetometer connected via I2C.
37  */
38 
39 #include "bmm150.hpp"
40 #include <px4_platform_common/getopt.h>
41 
42 /** driver 'main' command */
43 extern "C" { __EXPORT int bmm150_main(int argc, char *argv[]); }
44 
45 
46 namespace bmm150
47 {
48 
51 
52 void start(bool, enum Rotation);
53 void test(bool);
54 void reset(bool);
55 void info(bool);
56 void regdump(bool external_bus);
57 void usage();
58 
59 
60 /**
61  * Start the driver.
62  *
63  * This function only returns if the driver is up and running
64  * or failed to detect the sensor.
65  */
66 void start(bool external_bus, enum Rotation rotation)
67 {
68  int fd;
69  BMM150 **g_dev_ptr = (external_bus ? &g_dev_ext : &g_dev_int);
70  const char *path = (external_bus ? BMM150_DEVICE_PATH_MAG_EXT : BMM150_DEVICE_PATH_MAG);
71 
72  if (*g_dev_ptr != nullptr)
73  /* if already started, the still command succeeded */
74  {
75  PX4_ERR("already started");
76  exit(0);
77  }
78 
79  /* create the driver */
80  if (external_bus) {
81 #if defined(PX4_I2C_BUS_EXPANSION)
82  *g_dev_ptr = new BMM150(PX4_I2C_BUS_EXPANSION, path, rotation);
83 #else
84  PX4_ERR("External I2C not available");
85  exit(0);
86 #endif
87 
88  } else {
89 #if defined(PX4_I2C_BUS_ONBOARD)
90  *g_dev_ptr = new BMM150(PX4_I2C_BUS_ONBOARD, path, rotation);
91 #else
92  PX4_ERR("Internal I2C not available");
93  exit(0);
94 #endif
95  }
96 
97  if (*g_dev_ptr == nullptr) {
98  goto fail;
99  }
100 
101 
102  if (OK != (*g_dev_ptr)->init()) {
103  goto fail;
104  }
105 
106  /* set the poll rate to default, starts automatic data collection */
107  fd = open(path, O_RDONLY);
108 
109 
110  if (fd < 0) {
111  goto fail;
112  }
113 
114  if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
115  goto fail;
116  }
117 
118  close(fd);
119 
120  exit(0);
121 fail:
122 
123  if (*g_dev_ptr != nullptr) {
124  delete (*g_dev_ptr);
125  *g_dev_ptr = nullptr;
126  }
127 
128  PX4_ERR("driver start failed");
129  exit(1);
130 
131 }
132 
133 
134 void test(bool external_bus)
135 {
136  int fd = -1;
137  const char *path = (external_bus ? BMM150_DEVICE_PATH_MAG_EXT : BMM150_DEVICE_PATH_MAG);
138  struct mag_report m_report;
139  ssize_t sz;
140 
141 
142  /* get the driver */
143  fd = open(path, O_RDONLY);
144 
145  if (fd < 0) {
146  PX4_ERR("%s open failed (try 'bmm150 start' if the driver is not running)", path);
147  exit(1);
148  }
149 
150  /* reset to default polling rate*/
151  if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
152  PX4_ERR("reset to Max polling rate");
153  exit(1);
154  }
155 
156  /* do a simple demand read */
157  sz = read(fd, &m_report, sizeof(m_report));
158 
159  if (sz != sizeof(m_report)) {
160  PX4_ERR("immediate mag read failed");
161  exit(1);
162  }
163 
164  PX4_WARN("single read");
165  PX4_WARN("time: %lld", m_report.timestamp);
166  PX4_WARN("mag x: \t%8.4f\t", (double)m_report.x);
167  PX4_WARN("mag y: \t%8.4f\t", (double)m_report.y);
168  PX4_WARN("mag z: \t%8.4f\t", (double)m_report.z);
169  PX4_WARN("mag x: \t%d\traw 0x%0x", (short)m_report.x_raw, (unsigned short)m_report.x_raw);
170  PX4_WARN("mag y: \t%d\traw 0x%0x", (short)m_report.y_raw, (unsigned short)m_report.y_raw);
171  PX4_WARN("mag z: \t%d\traw 0x%0x", (short)m_report.z_raw, (unsigned short)m_report.z_raw);
172 
173  PX4_ERR("PASS");
174  exit(0);
175 
176 }
177 
178 
179 void
180 reset(bool external_bus)
181 {
182  const char *path = external_bus ? BMM150_DEVICE_PATH_MAG_EXT : BMM150_DEVICE_PATH_MAG;
183  int fd = open(path, O_RDONLY);
184 
185  if (fd < 0) {
186  PX4_ERR("failed");
187  exit(1);
188  }
189 
190  if (ioctl(fd, SENSORIOCRESET, 0) < 0) {
191  PX4_ERR("driver reset failed");
192  exit(1);
193  }
194 
195  if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
196  PX4_ERR("driver poll restart failed");
197  exit(1);
198  }
199 
200  exit(0);
201 
202 }
203 
204 void
205 info(bool external_bus)
206 {
207  BMM150 **g_dev_ptr = external_bus ? &g_dev_ext : &g_dev_int;
208 
209  if (*g_dev_ptr == nullptr) {
210  PX4_ERR("driver not running");
211  exit(1);
212  }
213 
214  printf("state @ %p\n", *g_dev_ptr);
215  (*g_dev_ptr)->print_info();
216 
217  exit(0);
218 
219 }
220 
221 /**
222  * Dump the register information
223  */
224 void
225 regdump(bool external_bus)
226 {
227  BMM150 **g_dev_ptr = external_bus ? &g_dev_ext : &g_dev_int;
228 
229  if (*g_dev_ptr == nullptr) {
230  PX4_ERR("driver not running");
231  exit(1);
232  }
233 
234  printf("regdump @ %p\n", *g_dev_ptr);
235  (*g_dev_ptr)->print_registers();
236 
237  exit(0);
238 }
239 
240 void
242 {
243  PX4_WARN("missing command: try 'start', 'info', 'test', 'stop',\n'reset', 'regdump'");
244  PX4_WARN("options:");
245  PX4_WARN(" -X (external bus)");
246 
247 }
248 
249 } // namespace bmm150
250 
251 
252 BMM150::BMM150(int bus, const char *path, enum Rotation rotation) :
253  I2C("BMM150", path, bus, BMM150_SLAVE_ADDRESS, BMM150_BUS_SPEED),
254  ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id())),
255  _running(false),
256  _call_interval(0),
257  _reports(nullptr),
258  _collect_phase(false),
259  _scale{},
260  _range_scale(0.01), /* default range scale from from uT to gauss */
261  _topic(nullptr),
263  _class_instance(-1),
266  _calibrated(false),
267  dig_x1(0),
268  dig_y1(0),
269  dig_x2(0),
270  dig_y2(0),
271  dig_z1(0),
272  dig_z2(0),
273  dig_z3(0),
274  dig_z4(0),
275  dig_xy1(0),
276  dig_xy2(0),
277  dig_xyz1(0),
278  _sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
279  _bad_transfers(perf_alloc(PC_COUNT, MODULE_NAME": bad transfers")),
280  _good_transfers(perf_alloc(PC_COUNT, MODULE_NAME": good transfers")),
281  _measure_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": measure")),
282  _comms_errors(perf_alloc(PC_COUNT, MODULE_NAME": comms errors")),
283  _duplicates(perf_alloc(PC_COUNT, MODULE_NAME": duplicates")),
284  _rotation(rotation),
285  _got_duplicate(false)
286 {
287  _device_id.devid_s.devtype = DRV_MAG_DEVTYPE_BMM150;
288 
289  // default scaling
290  _scale.x_offset = 0;
291  _scale.x_scale = 1.0f;
292  _scale.y_offset = 0;
293  _scale.y_scale = 1.0f;
294  _scale.z_offset = 0;
295  _scale.z_scale = 1.0f;
296 }
297 
299 {
300  /* make sure we are truly inactive */
301  stop();
302 
303  /* free any existing reports */
304  if (_reports != nullptr) {
305  delete _reports;
306  }
307 
308 
309  if (_class_instance != -1) {
310  unregister_class_devname(MAG_BASE_DEVICE_PATH, _class_instance);
311  }
312 
313  if (_topic != nullptr) {
315  }
316 
317 
318  /* delete the perf counter */
325 }
326 
328 {
329  int ret = OK;
330 
331  /* do I2C init (and probe) first */
332  ret = I2C::init();
333 
334  /* if probe/setup failed, bail now */
335  if (ret != OK) {
336  DEVICE_DEBUG("I2C setup failed");
337  return ret;
338  }
339 
340  /* allocate basic report buffers */
341  _reports = new ringbuffer::RingBuffer(2, sizeof(mag_report));
342 
343  if (_reports == nullptr) {
344  goto out;
345  }
346 
347  /* Bring the device to sleep mode */
349  up_udelay(10000);
350 
351 
352  /* check id*/
354  PX4_WARN("id of magnetometer is not: 0x%02x", BMM150_CHIP_ID);
355  return -EIO;
356  }
357 
358  if (reset() != OK) {
359  goto out;
360  }
361 
363 
364  _class_instance = register_class_devname(MAG_BASE_DEVICE_PATH);
365 
366  if (measure()) {
367  return -EIO;
368  }
369 
370  up_udelay(10000);
371 
372  if (collect()) {
373  return -EIO;
374  }
375 
376  /* advertise sensor topic, measure manually to initialize valid report */
377  struct mag_report mrb;
378  _reports->get(&mrb);
379 
380  /* measurement will have generated a report, publish */
381  _topic = orb_advertise_multi(ORB_ID(sensor_mag), &mrb,
382  &_orb_class_instance, (external()) ? ORB_PRIO_HIGH : ORB_PRIO_MAX);
383 
384  if (_topic == nullptr) {
385  PX4_WARN("ADVERT FAIL");
386  }
387 
388 out:
389  return ret;
390 }
391 
392 int
394 {
395  /* During I2C Initialization, sensor is in suspend mode
396  * and chip Id will return 0x00, hence returning OK. After
397  * I2C initialization, sensor is brought to sleep mode
398  * and Chip Id is verified. In sleep mode, we can read
399  * chip id. */
400 
401  /* @Note: Please read BMM150 Datasheet for more details */
402  return OK;
403 }
404 
405 
406 void
408 {
409  /* reset the report ring and state machine */
410  _collect_phase = false;
411  _running = true;
412  _reports->flush();
413 
414  /* schedule a cycle to start things */
415  ScheduleNow();
416 }
417 
418 void
420 {
421  _running = false;
422  ScheduleClear();
423 }
424 
425 ssize_t
426 BMM150::read(struct file *filp, char *buffer, size_t buflen)
427 {
428  unsigned count = buflen / sizeof(mag_report);
429  struct mag_report *mag_buf = reinterpret_cast<struct mag_report *>(buffer);
430  int ret = 0;
431 
432  /* buffer must be large enough */
433  if (count < 1) {
434  return -ENOSPC;
435  }
436 
437  /* if automatic measurement is enabled */
438  if (_call_interval > 0) {
439  /*
440  * While there is space in the caller's buffer, and reports, copy them.
441  * Note that we may be pre-empted by the workq thread while we are doing this;
442  * we are careful to avoid racing with them.
443  */
444  while (count--) {
445  if (_reports->get(mag_buf)) {
446  ret += sizeof(struct mag_report);
447  mag_buf++;
448  }
449  }
450 
451  /* if there was no data, warn the caller */
452  return ret ? ret : -EAGAIN;
453  }
454 
455  /* manual measurement - run one conversion */
456  /* XXX really it'd be nice to lock against other readers here */
457  do {
458  _reports->flush();
459 
460  /* trigger a measurement */
461  if (OK != measure()) {
462  ret = -EIO;
463  break;
464  }
465 
466  /* wait for it to complete */
468 
469  /* run the collection phase */
470  if (OK != collect()) {
471  ret = -EIO;
472  break;
473  }
474 
475 
476  if (_reports->get(mag_buf)) {
477  ret = sizeof(struct mag_report);
478  }
479  } while (0);
480 
481  /* return the number of bytes transferred */
482  return ret;
483 
484 }
485 
486 void
488 {
489  if (_collect_phase) {
490  collect();
491  unsigned wait_gap = _call_interval - BMM150_CONVERSION_INTERVAL;
492 
493  if ((wait_gap != 0) && (_running)) {
494  // need to wait some time before new measurement
495  ScheduleDelayed(wait_gap);
496 
497  return;
498  }
499 
500  }
501 
502  measure();
503 
504  if ((_running)) {
505  /* schedule a fresh cycle call when the measurement is done */
506  ScheduleDelayed(BMM150_CONVERSION_INTERVAL);
507  }
508 
509 
510 }
511 
512 int
514 {
515  _collect_phase = true;
516 
518 
519  /* start measure */
521 
522  if (ret != OK) {
525  return -EIO;
526  }
527 
529 
530  return OK;
531 }
532 
533 
534 
535 int
537 {
538  _collect_phase = false;
539 
540  bool mag_notify = true;
541  uint8_t mag_data[8], status;
542  uint16_t resistance, lsb, msb, msblsb;
543  mag_report mrb;
544 
545 
546  /* start collecting data */
548 
549  status = read_reg(BMM150_R_LSB);
550 
551  /* Read Magnetometer data*/
552  if (OK != get_data(BMM150_DATA_X_LSB_REG, mag_data, sizeof(mag_data))) {
553  return -EIO;
554  }
555 
556  /* Array holding the mag XYZ and R data
557  mag_data[0] - X LSB
558  mag_data[1] - X MSB
559  mag_data[2] - Y LSB
560  mag_data[3] - Y MSB
561  mag_data[4] - Z LSB
562  mag_data[5] - Z MSB
563  mag_data[6] - R LSB
564  mag_data[7] - R MSB
565  */
566 
567  /* Extract X axis data */
568  lsb = ((mag_data[0] & 0xF8) >> 3);
569  msb = (((int8_t)mag_data[1]) << 5);
570  msblsb = (msb | lsb);
571  mrb.x_raw = (int16_t)msblsb;
572 
573 
574  /* Extract Y axis data */
575  lsb = ((mag_data[2] & 0xF8) >> 3);
576  msb = (((int8_t)mag_data[3]) << 5);
577  msblsb = (msb | lsb);
578  mrb.y_raw = (int16_t)msblsb;
579 
580  /* Extract Z axis data */
581  lsb = ((mag_data[4] & 0xFE) >> 1);
582  msb = (((int8_t)mag_data[5]) << 7);
583  msblsb = (msb | lsb);
584  mrb.z_raw = (int16_t)msblsb;
585 
586  /* Extract Resistance data */
587  lsb = ((mag_data[6] & 0xFC) >> 2);
588  msb = (mag_data[7] << 6);
589  msblsb = (msb | lsb);
590  resistance = (uint16_t)msblsb;
591 
592  /* Check whether data is new or old */
593  if (!(status & 0x01)) {
596  _got_duplicate = true;
597  return -EIO;
598  }
599 
600  _got_duplicate = false;
601 
602  if (mrb.x_raw == 0 &&
603  mrb.y_raw == 0 &&
604  mrb.z_raw == 0 &&
605  resistance == 0) {
606  // all zero data - probably a I2C bus error
610  return -EIO;
611  }
612 
614 
615  /* Compensation for X axis */
616  if (mrb.x_raw != BMM150_FLIP_OVERFLOW_ADCVAL) {
617  /* no overflow */
618  if ((resistance != 0) && (dig_xyz1 != 0)) {
619  mrb.x = ((dig_xyz1 * 16384.0 / resistance) - 16384.0);
620  mrb.x = (((mrb.x_raw * ((((dig_xy2 * ((float)(mrb.x * mrb.x / (float)268435456.0)) + mrb.x * dig_xy1 /
621  (float)16384.0)) + (float)256.0) * (dig_x2 + (float)160.0))) / (float)8192.0) + (dig_x1 * (float)8.0)) / (float)16.0;
622 
623  } else {
625  }
626 
627  } else {
629  }
630 
631  /* Compensation for Y axis */
632  if (mrb.y_raw != BMM150_FLIP_OVERFLOW_ADCVAL) {
633  /* no overflow */
634  if ((resistance != 0) && (dig_xyz1 != 0)) {
635 
636  mrb.y = ((((float)dig_xyz1) * (float)16384.0 / resistance) - (float)16384.0);
637  mrb.y = (((mrb.y_raw * ((((dig_xy2 * (mrb.y * mrb.y / (float)268435456.0) + mrb.y * dig_xy1 / (float)16384.0)) +
638  (float)256.0) * (dig_y2 + (float)160.0))) / (float)8192.0) + (dig_y1 * (float)8.0)) / (float)16.0;
639 
640 
641  } else {
643  }
644 
645  } else {
646  /* overflow, set output to 0.0f */
648  }
649 
650 
651  /* Compensation for Z axis */
652  if (mrb.z_raw != BMM150_HALL_OVERFLOW_ADCVAL) {
653  /* no overflow */
654  if ((dig_z2 != 0) && (dig_z1 != 0) && (dig_xyz1 != 0) && (resistance != 0)) {
655  mrb.z = ((((mrb.z_raw - dig_z4) * (float)131072.0) - (dig_z3 * (resistance - dig_xyz1))) / ((
656  dig_z2 + dig_z1 * resistance / (float)32768.0) * (float)4.0)) / (float)16.0;
657  }
658 
659  } else {
660  /* overflow, set output to 0.0f */
662  }
663 
664 
665  mrb.timestamp = hrt_absolute_time();
666  mrb.is_external = external();
667 
668  // report the error count as the number of bad transfers.
669  // This allows the higher level code to decide if it
670  // should use this sensor based on whether it has had failures
671  mrb.error_count = perf_event_count(_bad_transfers);
672 
673  // apply user specified rotation
674  rotate_3f(_rotation, mrb.x, mrb.y, mrb.z);
675 
676 
677  /* Scaling the data */
678  mrb.x = ((mrb.x * _range_scale) - _scale.x_offset) * _scale.x_scale;
679  mrb.y = ((mrb.y * _range_scale) - _scale.y_offset) * _scale.y_scale;
680  mrb.z = ((mrb.z * _range_scale) - _scale.z_offset) * _scale.z_scale;
681 
682  mrb.scaling = _range_scale;
683  mrb.device_id = _device_id.devid;
684 
685  _last_report.x = mrb.x;
686  _last_report.y = mrb.y;
687  _last_report.z = mrb.z;
688 
689  _reports->force(&mrb);
690 
691  /* notify anyone waiting for data */
692  if (mag_notify) {
693  poll_notify(POLLIN);
694  }
695 
696  if (mag_notify && !(_pub_blocked)) {
697  /* publish it */
698  orb_publish(ORB_ID(sensor_mag), _topic, &mrb);
699  }
700 
702  return OK;
703 
704 }
705 
706 int
707 BMM150::ioctl(struct file *filp, int cmd, unsigned long arg)
708 {
709 
710  switch (cmd) {
711  case SENSORIOCSPOLLRATE: {
712  switch (arg) {
713 
714  /* zero would be bad */
715  case 0:
716  return -EINVAL;
717 
718  /* set default polling rate */
721 
722  /* adjust to a legal polling interval in Hz */
723  default: {
724  /* do we need to start internal polling? */
725  bool want_start = (_call_interval == 0);
726 
727  /* convert hz to tick interval via microseconds */
728  unsigned interval = (1000000 / arg);
729 
730  /* check against maximum rate */
731  if (interval < BMM150_CONVERSION_INTERVAL) {
732  return -EINVAL;
733  }
734 
735  /* update interval for next measurement */
736  _call_interval = interval;
737 
738  /* if we need to start the poll state machine, do it */
739  if (want_start) {
740  start();
741  }
742 
743  return OK;
744  }
745  }
746  }
747 
748  case SENSORIOCRESET:
749  return reset();
750 
751  case MAGIOCSSCALE:
752  return OK;
753 
754  case MAGIOCGSCALE:
755  return OK;
756 
757  case MAGIOCCALIBRATE:
758  return OK;
759 
760  case MAGIOCEXSTRAP:
761  return OK;
762 
763  default:
764  /* give it to the superclass */
765  return I2C::ioctl(filp, cmd, arg);
766  }
767 }
768 
769 
771 {
772  int ret = OK;
773 
774  /* Soft-reset */
776  up_udelay(5000);
777 
778  /* Enable Magnetometer in normal mode */
780  up_udelay(1000);
781 
782  /* Set the data rate to default */
784 
785  /* set the preset mode as regular*/
787 
788  return OK;
789 }
790 
791 
792 int
794 {
795  if (perf_event_count(_sample_perf) == 0) {
796  collect();
797  }
798 
799  /* return 0 on success, 1 else */
800  return (perf_event_count(_sample_perf) > 0) ? 0 : 1;
801 }
802 
803 uint8_t
804 BMM150::read_reg(uint8_t reg)
805 {
806  const uint8_t cmd = reg;
807  uint8_t ret;
808 
809  transfer(&cmd, 1, &ret, 1);
810 
811  return ret;
812 }
813 
814 int
815 BMM150::write_reg(uint8_t reg, uint8_t value)
816 {
817  const uint8_t cmd[2] = { reg, value};
818 
819  return transfer(cmd, 2, nullptr, 0);
820 }
821 
822 int
823 BMM150::get_data(uint8_t reg, uint8_t *data, unsigned len)
824 {
825  const uint8_t cmd = reg;
826 
827  return transfer(&cmd, 1, data, len);
828 
829 }
830 
831 void
832 BMM150::modify_reg(unsigned reg, uint8_t clearbits, uint8_t setbits)
833 {
834  uint8_t val;
835 
836  val = read_reg(reg);
837  val &= ~clearbits;
838  val |= setbits;
839  write_reg(reg, val);
840 }
841 
842 
843 
844 int BMM150 :: set_power_mode(uint8_t power_mode)
845 {
846  uint8_t setbits = 0;
847  uint8_t clearbits = BMM150_POWER_MASK;
848 
849  switch (power_mode) {
850  case BMM150_NORMAL_MODE:
851  _power = 0;
852  break;
853 
854  case BMM150_FORCED_MODE:
855  _power = 1;
856  break;
857 
858  case BMM150_SLEEP_MODE:
859  _power = 3;
860  break;
861 
862  default:
863  return -EINVAL;
864  }
865 
866  setbits |= power_mode;
867  modify_reg(BMM150_CTRL_REG, clearbits, setbits);
868 
869  return OK;
870 
871 }
872 
873 int BMM150 :: set_data_rate(uint8_t data_rate)
874 {
875  uint8_t setbits = 0;
876  uint8_t clearbits = BMM150_OUTPUT_DATA_RATE_MASK;
877 
878  switch (data_rate) {
880  _output_data_rate = 10;
881  break;
882 
884  _output_data_rate = 2;
885  break;
886 
888  _output_data_rate = 6;
889  break;
890 
892  _output_data_rate = 8;
893  break;
894 
896  _output_data_rate = 15;
897  break;
898 
900  _output_data_rate = 20;
901  break;
902 
904  _output_data_rate = 25;
905  break;
906 
908  _output_data_rate = 30;
909  break;
910 
911  default:
912  return -EINVAL;
913  }
914 
915  setbits |= data_rate;
916  modify_reg(BMM150_CTRL_REG, clearbits, setbits);
917 
918  return OK;
919 
920 }
921 
922 
924 {
925  int ret = OK;
926  uint8_t data[2] = {0};
927  uint16_t msb, lsb, msblsb;
928 
935 
936  ret += get_data(BMM150_DIG_Z1_LSB, data, 2);
937  lsb = data[0];
938  msb = (data[1] << 8);
939  msblsb = (msb | lsb);
940  dig_z1 = (uint16_t)msblsb;
941 
942  ret += get_data(BMM150_DIG_Z2_LSB, data, 2);
943  lsb = data[0];
944  msb = ((int8_t)data[1] << 8);
945  msblsb = (msb | lsb);
946  dig_z2 = (int16_t)msblsb;
947 
948  ret += get_data(BMM150_DIG_Z3_LSB, data, 2);
949  lsb = data[0];
950  msb = ((int8_t)data[1] << 8);
951  msblsb = (msb | lsb);
952  dig_z3 = (int16_t)msblsb;
953 
954  ret += get_data(BMM150_DIG_Z4_LSB, data, 2);
955  lsb = data[0];
956  msb = ((int8_t)data[1] << 8);
957  msblsb = (msb | lsb);
958  dig_z4 = (int16_t)msblsb;
959 
960  ret += get_data(BMM150_DIG_XYZ1_LSB, data, 2);
961  lsb = data[0];
962  msb = ((data[1] & 0x7F) << 8);
963  msblsb = (msb | lsb);
964  dig_xyz1 = (uint16_t)msblsb;
965 
966  return ret;
967 
968 }
969 
970 int BMM150::set_rep_xy(uint8_t rep_xy)
971 {
972  uint8_t cmd[2] = {BMM150_XY_REP_CTRL_REG, rep_xy};
973 
974  return transfer((const uint8_t *)cmd, sizeof(cmd), nullptr, 0);
975 
976 }
977 
978 int BMM150::set_rep_z(uint8_t rep_z)
979 {
980  uint8_t cmd[2] = {BMM150_Z_REP_CTRL_REG, rep_z};
981 
982  return transfer((const uint8_t *)cmd, sizeof(cmd), nullptr, 0);
983 
984 }
985 
986 
987 int BMM150::set_presetmode(uint8_t presetmode)
988 {
989  int ret = OK;
990  uint8_t data_rate, rep_xy, rep_z;
991 
992  if (presetmode == 1) {
993  data_rate = BMM150_LOWPOWER_DR;
994  rep_xy = BMM150_LOWPOWER_REPXY;
995  rep_z = BMM150_LOWPOWER_REPZ;
996 
997  } else if (presetmode == 2) {
998  data_rate = BMM150_REGULAR_DR;
999  rep_xy = BMM150_REGULAR_REPXY;
1000  rep_z = BMM150_REGULAR_REPZ;
1001 
1002  } else if (presetmode == 3) {
1003  data_rate = BMM150_HIGHACCURACY_DR;
1004  rep_xy = BMM150_HIGHACCURACY_REPXY;
1005  rep_z = BMM150_HIGHACCURACY_REPZ;
1006 
1007  } else if (presetmode == 4) {
1008  data_rate = BMM150_ENHANCED_DR;
1009  rep_xy = BMM150_ENHANCED_REPXY;
1010  rep_z = BMM150_ENHANCED_REPZ;
1011 
1012  } else {
1013  return -EINVAL;
1014  }
1015 
1016  ret = set_data_rate(data_rate);
1017 
1018  ret += set_rep_xy(rep_xy);
1019  ret += set_rep_z(rep_z);
1020 
1021  return ret;
1022 
1023 }
1024 
1025 void
1027 {
1031  _reports->print_info("mag queue");
1032 
1033  printf("output (%.2f %.2f %.2f)\n", (double)_last_report.x, (double)_last_report.y, (double)_last_report.z);
1034  printf("offsets (%.2f %.2f %.2f)\n", (double)_scale.x_offset, (double)_scale.y_offset, (double)_scale.z_offset);
1035  printf("scaling (%.2f %.2f %.2f) 1/range_scale %.2f ",
1036  (double)_scale.x_scale, (double)_scale.y_scale, (double)_scale.z_scale,
1037  (double)(1.0f / _range_scale));
1038  printf("\n");
1039 
1040 }
1041 
1042 void
1044 {
1045  printf("BMM150 registers\n");
1046 
1047  uint8_t reg = BMM150_CHIP_ID_REG;
1048  uint8_t v = read_reg(reg);
1049  printf("Chip Id: %02x:%02x ", (unsigned)reg, (unsigned)v);
1050  printf("\n");
1051 
1053  v = read_reg(reg);
1054  printf("Int sett Ctrl reg: %02x:%02x ", (unsigned)reg, (unsigned)v);
1055  printf("\n");
1056 
1058  v = read_reg(reg);
1059  printf("Axes En Ctrl reg: %02x:%02x ", (unsigned)reg, (unsigned)v);
1060  printf("\n");
1061 
1062 }
1063 
1064 int
1065 bmm150_main(int argc, char *argv[])
1066 {
1067  int myoptind = 1;
1068  int ch;
1069  const char *myoptarg = nullptr;
1070  bool external_bus = false;
1071  enum Rotation rotation = ROTATION_NONE;
1072 
1073  while ((ch = px4_getopt(argc, argv, "XR:", &myoptind, &myoptarg)) != EOF) {
1074  switch (ch) {
1075  case 'X':
1076  external_bus = true;
1077  break;
1078 
1079  case 'R':
1080  rotation = (enum Rotation)atoi(myoptarg);
1081  break;
1082 
1083  default:
1084  bmm150::usage();
1085  return 0;
1086  }
1087  }
1088 
1089  if (myoptind >= argc) {
1090  bmm150::usage();
1091  return -1;
1092  }
1093 
1094  const char *verb = argv[myoptind];
1095 
1096  /*
1097  * Start/load the driver.
1098  */
1099  if (!strcmp(verb, "start")) {
1100  bmm150::start(external_bus, rotation);
1101  }
1102 
1103 
1104  /*
1105  * Test the driver/device.
1106  */
1107  if (!strcmp(verb, "test")) {
1108  bmm150::test(external_bus);
1109  }
1110 
1111  /*
1112  * Reset the driver.
1113  */
1114  if (!strcmp(verb, "reset")) {
1115  bmm150::reset(external_bus);
1116  }
1117 
1118  /*
1119  * Print driver information.
1120  */
1121  if (!strcmp(verb, "info")) {
1122  bmm150::info(external_bus);
1123  }
1124 
1125  /*
1126  * Print register information.
1127  */
1128  if (!strcmp(verb, "regdump")) {
1129  bmm150::regdump(external_bus);
1130  }
1131 
1132 
1133  bmm150::usage();
1134  return -1;
1135 }
#define BMM150_CONVERSION_INTERVAL
Definition: bmm150.hpp:183
void reset(bool)
Definition: bmm150.cpp:180
#define MAGIOCGSCALE
copy the mag scaling constants to the structure pointed to by (arg)
Definition: drv_mag.h:76
#define BMM150_ENHANCED_DR
Definition: bmm150.hpp:132
#define BMM150_HIGHACCURACY_REPXY
Definition: bmm150.hpp:119
int8_t dig_x2
trim x2 data
Definition: bmm150.hpp:245
#define BMM150_REGULAR_DR
Definition: bmm150.hpp:130
void print_registers()
Definition: bmm150.cpp:1043
#define BMM150_BUS_SPEED
Definition: bmm150.hpp:46
void test(bool)
Definition: bmm150.cpp:134
static struct vehicle_status_s status
Definition: Commander.cpp:138
#define BMM150_SOFT_RESET_MASK
Definition: bmm150.hpp:180
int _orb_class_instance
Definition: bmm150.hpp:236
#define BMM150_DIG_XYZ1_LSB
Definition: bmm150.hpp:163
void info(bool)
Definition: bmm150.cpp:205
int reset()
Resets the chip.
Definition: bmm150.cpp:770
measure the time elapsed performing an event
Definition: perf_counter.h:56
BMM150 * g_dev_int
Definition: bmm150.cpp:50
#define BMM150_REGULAR_REPXY
Definition: bmm150.hpp:118
#define BMM150_DIG_Y1
Definition: bmm150.hpp:154
uint16_t dig_xyz1
trim xyz1 data
Definition: bmm150.hpp:256
#define BMM150_ENHANCED_REPXY
Definition: bmm150.hpp:120
#define BMM150_DATA_X_LSB_REG
Definition: bmm150.hpp:55
perf_counter_t _comms_errors
Definition: bmm150.hpp:262
#define MAGIOCEXSTRAP
excite strap
Definition: drv_mag.h:85
#define BMM150_DATA_RATE_25HZ
Definition: bmm150.hpp:93
#define DRV_MAG_DEVTYPE_BMM150
Definition: drv_sensor.h:94
#define BMM150_HIGHACCURACY_REPZ
Definition: bmm150.hpp:125
#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
#define BMM150_DIG_Z2_LSB
Definition: bmm150.hpp:159
virtual ~BMM150()
Definition: bmm150.cpp:298
#define BMM150_INT_SETT_CTRL_REG
Definition: bmm150.hpp:70
#define BMM150_HIGHACCURACY_DR
Definition: bmm150.hpp:131
Definition: I2C.hpp:51
#define BMM150_LOWPOWER_REPZ
Definition: bmm150.hpp:123
#define BMM150_DATA_RATE_06HZ
Definition: bmm150.hpp:89
#define BMM150_DIG_X2
Definition: bmm150.hpp:157
int set_rep_xy(uint8_t rep_xy)
Definition: bmm150.cpp:970
int measure()
Definition: bmm150.cpp:513
#define BMM150_DATA_RATE_15HZ
Definition: bmm150.hpp:91
#define BMM150_CHIP_ID_REG
Definition: bmm150.hpp:52
#define BMM150_POWER_CTRL_REG
Definition: bmm150.hpp:68
#define BMM150_DEFAULT_POWER_MODE
Definition: bmm150.hpp:141
int init_trim_registers(void)
Definition: bmm150.cpp:923
#define BMM150_DIG_Y2
Definition: bmm150.hpp:158
int8_t dig_y2
trim y2 data
Definition: bmm150.hpp:246
count the number of times an event occurs
Definition: perf_counter.h:55
#define BMM150_XY_REP_CTRL_REG
Definition: bmm150.hpp:76
#define BMM150_LOWPOWER_REPXY
Definition: bmm150.hpp:117
bool _got_duplicate
Definition: bmm150.hpp:266
#define BMM150_CTRL_REG
Definition: bmm150.hpp:69
unsigned _call_interval
Definition: bmm150.hpp:224
float _range_scale
Definition: bmm150.hpp:233
enum Rotation _rotation
Definition: bmm150.hpp:265
virtual int ioctl(struct file *filp, int cmd, unsigned long arg)
Definition: bmm150.cpp:707
uint8_t read_reg(uint8_t reg)
Read a register from the BMM150.
Definition: bmm150.cpp:804
#define BMM150_ENHANCED_REPZ
Definition: bmm150.hpp:126
ringbuffer::RingBuffer * _reports
Definition: bmm150.hpp:228
perf_counter_t _duplicates
Definition: bmm150.hpp:263
int write_reg(uint8_t reg, uint8_t value)
Write a register in the BMM150.
Definition: bmm150.cpp:815
int8_t dig_y1
trim y1 data
Definition: bmm150.hpp:243
uint8_t _power
Definition: bmm150.hpp:238
float x_offset
Definition: drv_mag.h:57
#define BMM150_DIG_XY1
Definition: bmm150.hpp:168
static void read(bootloader_app_shared_t *pshared)
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
Definition: drv_sensor.h:134
#define BMM150_AXES_EN_CTRL_REG
Definition: bmm150.hpp:71
int set_power_mode(uint8_t power)
Definition: bmm150.cpp:844
#define BMM150_DIG_XY2
Definition: bmm150.hpp:167
uint16_t dig_z1
trim z1 data
Definition: bmm150.hpp:248
void print_info()
Diagnostics - print some basic information about the driver.
Definition: bmm150.cpp:1026
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
void perf_count(perf_counter_t handle)
Count a performance event.
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen)
Definition: bmm150.cpp:426
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
Definition: drv_mag.h:73
uint8_t dig_xy1
trim xy1 data
Definition: bmm150.hpp:253
#define BMM150_FORCED_MODE
Definition: bmm150.hpp:137
int8_t dig_x1
trim x1 data
Definition: bmm150.hpp:242
#define BMM150_DEFAULT_ODR
Definition: bmm150.hpp:144
#define BMM150_Z_REP_CTRL_REG
Definition: bmm150.hpp:77
bool _running
Definition: bmm150.hpp:221
void regdump(bool external_bus)
Dump the register information.
Definition: bmm150.cpp:225
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
#define BMM150_SLAVE_ADDRESS
Definition: bmm150.hpp:44
virtual int init()
Definition: bmm150.cpp:327
#define perf_alloc(a, b)
Definition: px4io.h:59
int get_data(uint8_t reg, uint8_t *data, unsigned len)
Read the specified number of bytes from BMM150.
Definition: bmm150.cpp:823
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
uint8_t * data
Definition: dataman.cpp:149
void modify_reg(unsigned reg, uint8_t clearbits, uint8_t setbits)
Modify a register in the BMM150.
Definition: bmm150.cpp:832
#define BMM150_DATA_RATE_08HZ
Definition: bmm150.hpp:90
int set_presetmode(uint8_t presetmode)
Definition: bmm150.cpp:987
perf_counter_t _good_transfers
Definition: bmm150.hpp:260
int16_t dig_z4
trim z4 data
Definition: bmm150.hpp:251
#define BMM150_DEVICE_PATH_MAG_EXT
Definition: bmm150.hpp:42
float y_offset
Definition: drv_mag.h:59
virtual int probe()
Definition: bmm150.cpp:393
perf_counter_t _measure_perf
Definition: bmm150.hpp:261
void perf_end(perf_counter_t handle)
End a performance event.
#define BMM150_DIG_Z1_LSB
Definition: bmm150.hpp:161
BMM150(int bus, const char *path, enum Rotation rotation)
Definition: bmm150.cpp:252
#define BMM150_OUTPUT_DATA_RATE_MASK
Definition: bmm150.hpp:175
void usage()
Prints info about the driver argument usage.
Definition: bmm150.cpp:241
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
float z_offset
Definition: drv_mag.h:61
#define BMM150_SLEEP_MODE
Definition: bmm150.hpp:138
perf_counter_t _bad_transfers
Definition: bmm150.hpp:259
int16_t dig_z2
trim z2 data
Definition: bmm150.hpp:249
__EXPORT int bmm150_main(int argc, char *argv[])
driver &#39;main&#39; command
Definition: bmm150.cpp:1065
#define BMM150_LOWPOWER_DR
Definition: bmm150.hpp:129
#define BMM150_DIG_Z4_LSB
Definition: bmm150.hpp:155
#define BMM150_REGULAR_REPZ
Definition: bmm150.hpp:124
uint8_t _output_data_rate
Definition: bmm150.hpp:239
#define BMM150_SOFT_RESET_VALUE
Definition: bmm150.hpp:177
void stop()
Stop automatic measurement.
Definition: bmm150.cpp:419
mag_report _last_report
used for info()
Definition: bmm150.hpp:268
struct @83::@85::@87 file
int set_rep_z(uint8_t rep_z)
Definition: bmm150.cpp:978
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.
int orb_unadvertise(orb_advert_t handle)
Definition: uORB.cpp:65
void Run() override
Definition: bmm150.cpp:487
Definition: bst.cpp:62
void perf_cancel(perf_counter_t handle)
Cancel a performance event.
#define BMM150_DIG_Z3_LSB
Definition: bmm150.hpp:165
#define BMM150_DEVICE_PATH_MAG
Definition: bmm150.hpp:40
int16_t dig_z3
trim z3 data
Definition: bmm150.hpp:250
#define BMM150_CHIP_ID
Definition: bmm150.hpp:49
#define OK
Definition: uavcan_main.cpp:71
int set_data_rate(uint8_t data_rate)
Definition: bmm150.cpp:873
#define BMM150_R_LSB
Definition: bmm150.hpp:61
#define BMM150_MAX_DATA_RATE
Definition: bmm150.hpp:147
int self_test()
Measurement self test.
Definition: bmm150.cpp:793
#define BMM150_NORMAL_MODE
Definition: bmm150.hpp:136
#define BMM150_PRESETMODE_REGULAR
Definition: bmm150.hpp:81
int _class_instance
Definition: bmm150.hpp:237
#define BMM150_OVERFLOW_OUTPUT_FLOAT
Definition: bmm150.hpp:111
#define BMM150_DATA_RATE_02HZ
Definition: bmm150.hpp:88
void start(bool, enum Rotation)
Start the driver.
Definition: bmm150.cpp:66
BMM150 * g_dev_ext
Definition: bmm150.cpp:49
orb_advert_t _topic
Definition: bmm150.hpp:235
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
Definition: uORB.cpp:53
perf_counter_t _sample_perf
Definition: bmm150.hpp:258
#define BMM150_DATA_RATE_10HZ
Definition: bmm150.hpp:87
bool _calibrated
the calibration is valid
Definition: bmm150.hpp:240
void start()
Start automatic measurement.
Definition: bmm150.cpp:407
void perf_begin(perf_counter_t handle)
Begin a performance event.
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
#define BMM150_DATA_RATE_20HZ
Definition: bmm150.hpp:92
#define BMM150_HALL_OVERFLOW_ADCVAL
Definition: bmm150.hpp:113
int collect()
Definition: bmm150.cpp:536
int8_t dig_xy2
trim xy2 data
Definition: bmm150.hpp:254
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
#define BMM150_FLIP_OVERFLOW_ADCVAL
Definition: bmm150.hpp:112
#define BMM150_DIG_X1
Definition: bmm150.hpp:153
bool _collect_phase
Definition: bmm150.hpp:230
#define BMM150_DATA_RATE_30HZ
Definition: bmm150.hpp:94
struct mag_calibration_s _scale
Definition: bmm150.hpp:232
#define BMM150_POWER_MASK
Definition: bmm150.hpp:172
#define mag_report
Definition: drv_mag.h:53