Path: blob/master/libraries/AP_Compass/AP_Compass_RM3100.cpp
9420 views
/*1* This file is free software: you can redistribute it and/or modify it2* under the terms of the GNU General Public License as published by the3* Free Software Foundation, either version 3 of the License, or4* (at your option) any later version.5*6* This file is distributed in the hope that it will be useful, but7* WITHOUT ANY WARRANTY; without even the implied warranty of8* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.9* See the GNU General Public License for more details.10*11* You should have received a copy of the GNU General Public License along12* with this program. If not, see <http://www.gnu.org/licenses/>.13*/14/*15Driver by Thomas Schumacher, Jan 201916Structure based on LIS3MDL driver1718*/19#include "AP_Compass_RM3100.h"2021#if AP_COMPASS_RM3100_ENABLED2223#include <AP_HAL/AP_HAL.h>24#include <utility>25#include <AP_Math/AP_Math.h>26#include <stdio.h>2728#define RM3100_POLL_REG 0x002930#define RM3100_CMM_REG 0x013132#define RM3100_CCX1_REG 0x0433#define RM3100_CCX0_REG 0x0534#define RM3100_CCY1_REG 0x0635#define RM3100_CCY0_REG 0x0736#define RM3100_CCZ1_REG 0x0837#define RM3100_CCZ0_REG 0x093839#define RM3100_TMRC_REG 0x0B4041#define RM3100_MX2_REG 0x2442#define RM3100_MX1_REG 0x2543#define RM3100_MX0_REG 0x2644#define RM3100_MY2_REG 0x2745#define RM3100_MY1_REG 0x2846#define RM3100_MY0_REG 0x2947#define RM3100_MZ2_REG 0x2A48#define RM3100_MZ1_REG 0x2B49#define RM3100_MZ0_REG 0x2C5051#define RM3100_BIST_REG 0x3352#define RM3100_STATUS_REG 0x3453#define RM3100_HSHAKE_REG 0x3454#define RM3100_REVID_REG 0x365556#define CCP0 0xC8 // Cycle Count values57#define CCP1 0x0058#define CCP0_DEFAULT 0xC8 // Default Cycle Count values (used as a whoami check)59#define CCP1_DEFAULT 0x0060#define GAIN_CC50 20.0f // LSB/uT61#define GAIN_CC100 38.0f62#define GAIN_CC200 75.0f6364#define TMRC 0x94 // Update rate 150Hz65#define CMM 0x71 // read 3 axes and set data ready if 3 axes are ready6667extern const AP_HAL::HAL &hal;6869AP_Compass_Backend *AP_Compass_RM3100::probe(AP_HAL::OwnPtr<AP_HAL::Device> dev,70bool force_external,71enum Rotation rotation)72{73if (!dev) {74return nullptr;75}76AP_Compass_RM3100 *sensor = NEW_NOTHROW AP_Compass_RM3100(std::move(dev), force_external, rotation);77if (!sensor || !sensor->init()) {78delete sensor;79return nullptr;80}8182return sensor;83}8485AP_Compass_RM3100::AP_Compass_RM3100(AP_HAL::OwnPtr<AP_HAL::Device> _dev,86bool _force_external,87enum Rotation _rotation)88: dev(std::move(_dev))89, force_external(_force_external)90, rotation(_rotation)91{92}9394bool AP_Compass_RM3100::init()95{96dev->get_semaphore()->take_blocking();9798if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {99// read has high bit set for SPI100dev->set_read_flag(0x80);101}102103// high retries for init104dev->set_retries(10);105106// use default cycle count values as a whoami test107uint8_t ccx0;108uint8_t ccx1;109uint8_t ccy0;110uint8_t ccy1;111uint8_t ccz0;112uint8_t ccz1;113if (!dev->read_registers(RM3100_CCX1_REG, &ccx1, 1) ||114!dev->read_registers(RM3100_CCX0_REG, &ccx0, 1) ||115!dev->read_registers(RM3100_CCY1_REG, &ccy1, 1) ||116!dev->read_registers(RM3100_CCY0_REG, &ccy0, 1) ||117!dev->read_registers(RM3100_CCZ1_REG, &ccz1, 1) ||118!dev->read_registers(RM3100_CCZ0_REG, &ccz0, 1) ||119ccx1 != CCP1_DEFAULT || ccx0 != CCP0_DEFAULT ||120ccy1 != CCP1_DEFAULT || ccy0 != CCP0_DEFAULT ||121ccz1 != CCP1_DEFAULT || ccz0 != CCP0_DEFAULT) {122// couldn't read one of the cycle count registers or didn't recognize the default cycle count values123dev->get_semaphore()->give();124return false;125}126127dev->setup_checked_registers(8);128129dev->write_register(RM3100_TMRC_REG, TMRC, true); // CMM data rate130dev->write_register(RM3100_CMM_REG, CMM, true); // CMM configuration131dev->write_register(RM3100_CCX1_REG, CCP1, true); // cycle count x132dev->write_register(RM3100_CCX0_REG, CCP0, true); // cycle count x133dev->write_register(RM3100_CCY1_REG, CCP1, true); // cycle count y134dev->write_register(RM3100_CCY0_REG, CCP0, true); // cycle count y135dev->write_register(RM3100_CCZ1_REG, CCP1, true); // cycle count z136dev->write_register(RM3100_CCZ0_REG, CCP0, true); // cycle count z137138_scaler = (1 / GAIN_CC200) * UTESLA_TO_MGAUSS; // has to be changed if using a different cycle count139140// lower retries for run141dev->set_retries(3);142143dev->get_semaphore()->give();144145/* register the compass instance in the frontend */146dev->set_device_type(DEVTYPE_RM3100);147if (!register_compass(dev->get_bus_id())) {148return false;149}150151DEV_PRINTF("RM3100: Found at address 0x%x as compass %u\n", dev->get_bus_address(), instance);152153set_rotation(rotation);154155if (force_external) {156set_external(true);157}158159// call timer() at 80Hz160dev->register_periodic_callback(1000000U/80U,161FUNCTOR_BIND_MEMBER(&AP_Compass_RM3100::timer, void));162163return true;164}165166void AP_Compass_RM3100::timer()167{168struct PACKED {169uint8_t magx_2;170uint8_t magx_1;171uint8_t magx_0;172uint8_t magy_2;173uint8_t magy_1;174uint8_t magy_0;175uint8_t magz_2;176uint8_t magz_1;177uint8_t magz_0;178} data;179180int32_t magx = 0;181int32_t magy = 0;182int32_t magz = 0;183184// check data ready on 3 axis185uint8_t status;186if (!dev->read_registers(RM3100_STATUS_REG, (uint8_t *)&status, 1)) {187goto check_registers;188}189190if (!(status & 0x80)) {191// data not available yet192goto check_registers;193}194195if (!dev->read_registers(RM3100_MX2_REG, (uint8_t *)&data, sizeof(data))) {196goto check_registers;197}198199// the 24 bits of data for each axis are in 2s complement representation200// each byte is shifted to its position in a 24-bit unsigned integer and from 8 more bits to be left-aligned in a 32-bit integer201magx = ((uint32_t)data.magx_2 << 24) | ((uint32_t)data.magx_1 << 16) | ((uint32_t)data.magx_0 << 8);202magy = ((uint32_t)data.magy_2 << 24) | ((uint32_t)data.magy_1 << 16) | ((uint32_t)data.magy_0 << 8);203magz = ((uint32_t)data.magz_2 << 24) | ((uint32_t)data.magz_1 << 16) | ((uint32_t)data.magz_0 << 8);204205// right-shift signed integer back to get correct measurement value206magx >>= 8;207magy >>= 8;208magz >>= 8;209210#ifdef AP_RM3100_REVERSAL_MASK211// some RM3100 builds get the polarity wrong on one or more of the212// elements. By setting AP_RM3100_REVERSAL_MASK in hwdef.dat you213// can fix it without modifying the hardware214if (AP_RM3100_REVERSAL_MASK & 1U) {215magx = -magx;216}217if (AP_RM3100_REVERSAL_MASK & 2U) {218magy = -magy;219}220if (AP_RM3100_REVERSAL_MASK & 4U) {221magz = -magz;222}223#endif224225{226// apply scaler and store in field vector227Vector3f field{228magx * _scaler,229magy * _scaler,230magz * _scaler231};232233accumulate_sample(field);234}235236check_registers:237dev->check_next_register();238}239240void AP_Compass_RM3100::read()241{242drain_accumulated_samples();243}244245#endif // AP_COMPASS_RM3100_ENABLED246247248