/* * Author: Jon Trulson * Copyright (c) 2015 Intel Corporation. * * This program and the accompanying materials are made available under the * terms of the The MIT License which is available at * https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: MIT */ #pragma once #include #include #include #include #define AK8975_I2C_BUS 0 #define AK8975_DEFAULT_I2C_ADDR 0x0c namespace upm { /** * @library mpu9150 * @sensor ak8975 * @comname 3-axis Magnetometer * @altname AK9875 * @type compass * @man seeed * @con i2c * @web http://www.akm.com/akm/en/file/datasheet/AK8975.pdf * * @brief API for the AK8975 magnetometer * * This is a 3-axis magnetometer, which can be used alone, or * coupled with another device (such as the mcu9150 9-axis motion * sensor). * * @snippet mpu9150-ak8975.cxx Interesting */ class AK8975: virtual public iMagnetometer { public: /** * AK8975 registers */ typedef enum { REG_WIA = 0x00, // device id REG_INFO = 0x01, // undocumented (AK proprietary data) REG_ST1 = 0x02, // status 1 REG_HXL = 0x03, // magnetometer data, X axis low byte REG_HXH = 0x04, // magnetometer data, X axis high byte REG_HYL = 0x05, REG_HYH = 0x06, REG_HZL = 0x07, REG_HZH = 0x08, REG_ST2 = 0x09, // status 2 REG_CNTL = 0x0a, // control // REG_RSV 0x0b reserved REG_ASTC = 0x0c, // self test (internal mag field) // REG_TS1, REG_TS2 0x0d, 0x0e reserved/factory test // REG_I2CDIS 0x0f, I2C disable. Not a good idea to use or support. // write a 0x1b to disable i2c. This requires a power cycle to undo. // These registers hold factory calibrated co-efficients needed to // properly compensate for production variations. They can only be // read when device is in fuse mode. They are used to adjust the // measured mag field values. REG_ASAX = 0x10, // X calibration REG_ASAY = 0x11, REG_ASAZ = 0x12 } AK8975_REG_T; /** * ST1 bits */ typedef enum { ST1_DRDY = 0x01 // data ready bit } ST1_BITS_T; /** * ST2 bits */ typedef enum { ST2_DERR = 0x04, // data error ST2_HOFL = 0x08 // measurement overflow } ST2_BITS_T; /** * CNTL register, operating mode values */ typedef enum { CNTL_PWRDWN = 0x00, // power down CNTL_MEASURE = 0x01, // single measurement CNTL_SELFTEST = 0x08, CNTL_FUSE_ACCESS = 0x0f // access fuse (coeff) registers } CNTL_MODES_T; /** * ASTC (self test control) bits */ typedef enum { ASTC_SELF = 0x40 // enable self test } ASTC_BITS_T; /** * ak8975 constructor * * @param bus i2c bus to use * @param address the address for this device */ AK8975(int bus=AK8975_I2C_BUS, uint8_t address=AK8975_DEFAULT_I2C_ADDR); /** * AK8975 Destructor */ ~AK8975(); /** * set up initial values and start operation * * @param dsr the data sampling rate: one of the DSR_BITS_T values * @return true if successful */ bool init(); /** * put the chip into a specific mode * * @param mode one of the CNTL_MODES_T values * @return true if successful */ bool setMode(CNTL_MODES_T mode); /** * check to see if the ST1_DRDY bit is set, indicating the device * can accept commands * * @return true if device is ready, false otherwise */ bool isReady(); /** * check to see if device is ready and sleep/retry if not. * Returns once device indicates it's ready. * * @return true if device is ready, false if retries exhausted */ bool waitforDeviceReady(); /** * take a measurement * * @param selfTest true if we are running a self test, false * (default) otherwise. * @return true if successful, false otherwise */ bool update(bool selfTest=false); /** * do a self test sequence. When self test is executed, the * device activates internal calibrated magnets, and measures * them, updating the measurement registers. Once complete, the * data can be read as usual (getMagnetometer()) and the returned * values compared against the following limits to determine * correctness: * * -100 < X < +100; -100 < Y < +100; -1000 < Z < -300 * * @return true if successful, false otherwise */ bool selfTest(); /** * return the compensated values for the x, y, and z axes. The * unit of measurement is in micro-teslas (uT). * * @param x pointer to returned X axis value * @param y pointer to returned Y axis value * @param z pointer to returned Z axis value */ void getMagnetometer(float *x, float *y, float *z); /** * Return magnetometer data in micro-Teslas (uT) in the form * of a floating point vector. update() must have been called * prior to calling this method. * * @return A floating point vector containing x, y, and z in * that order. */ std::vector getMagnetometer(); protected: /** * compute a compensated magnetometer axis value, based on the raw * axis value and a per-device, per-axis adjustment coefficient * that was read and stored at init() time. * * @param value the raw axis value to compensate * @param adj the adjustment coefficient * @return true if successful */ float adjustValue(float value, float adj); // compensation coefficients (factory set) for this device float m_xCoeff; float m_yCoeff; float m_zCoeff; // uncompensated magnetometer readings float m_xData; float m_yData; float m_zData; private: mraa::I2c m_i2c; uint8_t m_addr; }; }