From 88effef51ac3abcd6ce8e14e72d3baab14742e48 Mon Sep 17 00:00:00 2001 From: ljwang Date: Tue, 6 Feb 2018 21:39:55 +1100 Subject: [PATCH] AP_Baro: support mini-pix using LPS25H SPI barometer allow LPS22H and LPS25H to share a driver --- libraries/AP_Baro/AP_Baro.cpp | 7 +- libraries/AP_Baro/AP_Baro_LPS25H.cpp | 135 ------------- libraries/AP_Baro/AP_Baro_LPS2XH.cpp | 185 ++++++++++++++++++ .../{AP_Baro_LPS25H.h => AP_Baro_LPS2XH.h} | 21 +- 4 files changed, 209 insertions(+), 139 deletions(-) delete mode 100644 libraries/AP_Baro/AP_Baro_LPS25H.cpp create mode 100644 libraries/AP_Baro/AP_Baro_LPS2XH.cpp rename libraries/AP_Baro/{AP_Baro_LPS25H.h => AP_Baro_LPS2XH.h} (60%) diff --git a/libraries/AP_Baro/AP_Baro.cpp b/libraries/AP_Baro/AP_Baro.cpp index 25c392a62f..6155a09ade 100644 --- a/libraries/AP_Baro/AP_Baro.cpp +++ b/libraries/AP_Baro/AP_Baro.cpp @@ -34,8 +34,8 @@ #include "AP_Baro_HIL.h" #include "AP_Baro_KellerLD.h" #include "AP_Baro_MS5611.h" -#include "AP_Baro_LPS25H.h" #include "AP_Baro_ICM20789.h" +#include "AP_Baro_LPS2XH.h" #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT #include "AP_Baro_qflight.h" #endif @@ -519,7 +519,7 @@ void AP_Baro::init(void) drivers[0] = new AP_Baro_QURT(*this); _num_drivers = 1; #elif HAL_BARO_DEFAULT == HAL_BARO_LPS25H - ADD_BACKEND(AP_Baro_LPS25H::probe(*this, + ADD_BACKEND(AP_Baro_LPS2XH::probe(*this, std::move(hal.i2c_mgr->get_device(HAL_BARO_LPS25H_I2C_BUS, HAL_BARO_LPS25H_I2C_ADDR)))); #elif HAL_BARO_DEFAULT == HAL_BARO_20789_I2C_I2C ADD_BACKEND(AP_Baro_ICM20789::probe(*this, @@ -529,6 +529,9 @@ void AP_Baro::init(void) ADD_BACKEND(AP_Baro_ICM20789::probe(*this, std::move(hal.i2c_mgr->get_device(HAL_BARO_20789_I2C_BUS, HAL_BARO_20789_I2C_ADDR_PRESS)), std::move(hal.spi->get_device("icm20789")))); +#elif HAL_BARO_DEFAULT == HAL_BARO_LPS22H_SPI + ADD_BACKEND(AP_Baro_LPS2XH::probe(*this, + std::move(hal.spi->get_device(HAL_BARO_LPS22H_NAME)))); #endif // can optionally have baro on I2C too diff --git a/libraries/AP_Baro/AP_Baro_LPS25H.cpp b/libraries/AP_Baro/AP_Baro_LPS25H.cpp deleted file mode 100644 index 46bcf9c1db..0000000000 --- a/libraries/AP_Baro/AP_Baro_LPS25H.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -#include "AP_Baro_LPS25H.h" - -#include -#include -extern const AP_HAL::HAL &hal; - - -#define LPS25H_ID 0xBD -#define LPS25H_REG_ID 0x0F -#define LPS25H_CTRL_REG1_ADDR 0x20 -#define LPS25H_CTRL_REG2_ADDR 0x21 -#define LPS25H_CTRL_REG3_ADDR 0x22 -#define LPS25H_CTRL_REG4_ADDR 0x23 -#define LPS25H_FIFO_CTRL 0x2E -#define LPS25H_TEMP_OUT_ADDR 0xAB //Regsiter address is 0x2B in 2's compliment. -#define PRESS_OUT_XL_ADDR 0xA8 //Regsiter address is 0x28 in 2's compliment. -//putting 1 in the MSB of those two registers turns on Auto increment for faster reading. - -AP_Baro_LPS25H::AP_Baro_LPS25H(AP_Baro &baro, AP_HAL::OwnPtr dev) - : AP_Baro_Backend(baro) - , _dev(std::move(dev)) -{ -} - -AP_Baro_Backend *AP_Baro_LPS25H::probe(AP_Baro &baro, - AP_HAL::OwnPtr dev) -{ - if (!dev) { - return nullptr; - } - AP_Baro_LPS25H *sensor = new AP_Baro_LPS25H(baro, std::move(dev)); - if (!sensor || !sensor->_init()) { - delete sensor; - return nullptr; - } - return sensor; -} - -bool AP_Baro_LPS25H::_init() -{ - if (!_dev || !_dev->get_semaphore()->take(HAL_SEMAPHORE_BLOCK_FOREVER)) { - return false; - } - _has_sample = false; - - _dev->set_speed(AP_HAL::Device::SPEED_HIGH); - - uint8_t whoami; - if (!_dev->read_registers(LPS25H_REG_ID, &whoami, 1) || - whoami != LPS25H_ID) { - // not a LPS25H - _dev->get_semaphore()->give(); - return false; - } - - //init control registers. - _dev->write_register(LPS25H_CTRL_REG1_ADDR,0x00); // turn off for config - _dev->write_register(LPS25H_CTRL_REG2_ADDR,0x00); //FIFO Disabled - _dev->write_register(LPS25H_FIFO_CTRL, 0x01); - _dev->write_register(LPS25H_CTRL_REG1_ADDR,0xc0); - - _instance = _frontend.register_sensor(); - - _dev->get_semaphore()->give(); - - // request 25Hz update (maximum refresh Rate according to datasheet) - _dev->register_periodic_callback(40 * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_LPS25H::_timer, void)); - - return true; -} - - - -// acumulate a new sensor reading -void AP_Baro_LPS25H::_timer(void) -{ - _update_temperature(); - _update_pressure(); - _has_sample = true; -} - -// transfer data to the frontend -void AP_Baro_LPS25H::update(void) -{ - if (_sem->take_nonblocking()) { - if (!_has_sample) { - _sem->give(); - return; - } - - _copy_to_frontend(_instance, _pressure, _temperature); - _has_sample = false; - _sem->give(); - } -} - -// calculate temperature -void AP_Baro_LPS25H::_update_temperature(void) -{ - uint8_t pu8[2]; - _dev->read_registers(LPS25H_TEMP_OUT_ADDR, pu8, 2); - int16_t Temp_Reg_s16 = (uint16_t)(pu8[1]<<8) | pu8[0]; - if (_sem->take_nonblocking()) { - _temperature=((float)(Temp_Reg_s16/480)+42.5); - _sem->give(); - } - -} - -// calculate pressure -void AP_Baro_LPS25H::_update_pressure(void) -{ - uint8_t pressure[3]; - _dev->read_registers(PRESS_OUT_XL_ADDR, pressure, 3); - int32_t Pressure_Reg_s32 = ((uint32_t)pressure[2]<<16)|((uint32_t)pressure[1]<<8)|(uint32_t)pressure[0]; - int32_t Pressure_mb = Pressure_Reg_s32 / 4096; // scale - if (_sem->take_nonblocking()) { - _pressure=Pressure_mb; - _sem->give(); - } -} diff --git a/libraries/AP_Baro/AP_Baro_LPS2XH.cpp b/libraries/AP_Baro/AP_Baro_LPS2XH.cpp new file mode 100644 index 0000000000..4833265d54 --- /dev/null +++ b/libraries/AP_Baro/AP_Baro_LPS2XH.cpp @@ -0,0 +1,185 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include +#include + +#include "AP_Baro_LPS2XH.h" +extern const AP_HAL::HAL &hal; + +#define REG_ID 0x0F + +#define LPS22H_ID 0xB1 +#define LPS22H_CTRL_REG1 0x10 +#define LPS22H_CTRL_REG2 0x11 +#define LPS22H_CTRL_REG3 0x12 + +#define LPS22H_CTRL_REG1_SIM (1 << 0) +#define LPS22H_CTRL_REG1_BDU (1 << 1) +#define LPS22H_CTRL_REG1_LPFP_CFG (1 << 2) +#define LPS22H_CTRL_REG1_EN_LPFP (1 << 3) +#define LPS22H_CTRL_REG1_PD (0 << 4) +#define LPS22H_CTRL_REG1_ODR_1HZ (1 << 4) +#define LPS22H_CTRL_REG1_ODR_10HZ (2 << 4) +#define LPS22H_CTRL_REG1_ODR_25HZ (3 << 4) +#define LPS22H_CTRL_REG1_ODR_50HZ (4 << 4) +#define LPS22H_CTRL_REG1_ODR_75HZ (5 << 4) + + +#define LPS25H_CTRL_REG1_ADDR 0x20 +#define LPS25H_CTRL_REG2_ADDR 0x21 +#define LPS25H_CTRL_REG3_ADDR 0x22 +#define LPS25H_CTRL_REG4_ADDR 0x23 +#define LPS25H_FIFO_CTRL 0x2E +#define TEMP_OUT_ADDR 0x2B +#define PRESS_OUT_XL_ADDR 0x28 +//putting 1 in the MSB of those two registers turns on Auto increment for faster reading. + +AP_Baro_LPS2XH::AP_Baro_LPS2XH(AP_Baro &baro, AP_HAL::OwnPtr dev) + : AP_Baro_Backend(baro) + , _dev(std::move(dev)) +{ +} + +AP_Baro_Backend *AP_Baro_LPS2XH::probe(AP_Baro &baro, + AP_HAL::OwnPtr dev) +{ + if (!dev) { + return nullptr; + } + AP_Baro_LPS2XH *sensor = new AP_Baro_LPS2XH(baro, std::move(dev)); + if (!sensor || !sensor->_init()) { + delete sensor; + return nullptr; + } + return sensor; +} + +bool AP_Baro_LPS2XH::_init() +{ + if (!_dev || !_dev->get_semaphore()->take(HAL_SEMAPHORE_BLOCK_FOREVER)) { + return false; + } + _has_sample = false; + + _dev->set_speed(AP_HAL::Device::SPEED_HIGH); + + // top bit is for read on SPI + _dev->set_read_flag(0x80); + + if(!_check_whoami()){ + _dev->get_semaphore()->give(); + return false; + } + + //init control registers. + if(_lps2xh_type == BARO_LPS25H){ + _dev->write_register(LPS25H_CTRL_REG1_ADDR,0x00); // turn off for config + _dev->write_register(LPS25H_CTRL_REG2_ADDR,0x00); //FIFO Disabled + _dev->write_register(LPS25H_FIFO_CTRL, 0x01); + _dev->write_register(LPS25H_CTRL_REG1_ADDR,0xc0); + + // request 25Hz update (maximum refresh Rate according to datasheet) + CallTime = 40 * AP_USEC_PER_MSEC; + } + if(_lps2xh_type == BARO_LPS22H){ + _dev->write_register(LPS22H_CTRL_REG1,LPS22H_CTRL_REG1_ODR_75HZ|LPS22H_CTRL_REG1_BDU|LPS22H_CTRL_REG1_EN_LPFP|LPS22H_CTRL_REG1_LPFP_CFG); + _dev->write_register(LPS22H_CTRL_REG2,0x18); + + // request 75Hz update + CallTime = 1000000/75; + } + + _instance = _frontend.register_sensor(); + + _dev->get_semaphore()->give(); + + _dev->register_periodic_callback(CallTime, FUNCTOR_BIND_MEMBER(&AP_Baro_LPS2XH::_timer, void)); + + return true; +} + +//check ID +bool AP_Baro_LPS2XH::_check_whoami(void) +{ + uint8_t whoami; + if (! _dev->read_registers(REG_ID, &whoami, 1)) { + return false; + } + hal.console->printf("LPS2XH whoami 0x%02x\n", whoami); + + switch(whoami){ + case LPS22HB_WHOAMI: + _lps2xh_type = BARO_LPS22H; + return true; + case LPS25HB_WHOAMI: + _lps2xh_type = BARO_LPS25H; + return true; + } + return false; +} + + +// acumulate a new sensor reading +void AP_Baro_LPS2XH::_timer(void) +{ + _update_temperature(); + _update_pressure(); + _has_sample = true; +} + +// transfer data to the frontend +void AP_Baro_LPS2XH::update(void) +{ + if (_sem->take_nonblocking()) { + if (!_has_sample) { + _sem->give(); + return; + } + + _copy_to_frontend(_instance, _pressure, _temperature); + _has_sample = false; + _sem->give(); + } +} + +// calculate temperature +void AP_Baro_LPS2XH::_update_temperature(void) +{ + uint8_t pu8[2]; + _dev->read_registers(TEMP_OUT_ADDR, pu8, 2); + int16_t Temp_Reg_s16 = (uint16_t)(pu8[1]<<8) | pu8[0]; + if (_sem->take_nonblocking()) { + if(_lps2xh_type == BARO_LPS25H){ + _temperature=((float)(Temp_Reg_s16/480)+42.5); + } + if(_lps2xh_type == BARO_LPS22H){ + _temperature=(float)(Temp_Reg_s16/100); + } + _sem->give(); + } +} + +// calculate pressure +void AP_Baro_LPS2XH::_update_pressure(void) +{ + uint8_t pressure[3]; + _dev->read_registers(PRESS_OUT_XL_ADDR, pressure, 3); + int32_t Pressure_Reg_s32 = ((uint32_t)pressure[2]<<16)|((uint32_t)pressure[1]<<8)|(uint32_t)pressure[0]; + int32_t Pressure_mb = Pressure_Reg_s32 / 4096 *100; // scale for pa + if (_sem->take_nonblocking()) { + _pressure=Pressure_mb; + _sem->give(); + } +} diff --git a/libraries/AP_Baro/AP_Baro_LPS25H.h b/libraries/AP_Baro/AP_Baro_LPS2XH.h similarity index 60% rename from libraries/AP_Baro/AP_Baro_LPS25H.h rename to libraries/AP_Baro/AP_Baro_LPS2XH.h index 05daf0c97c..e4936afe1a 100644 --- a/libraries/AP_Baro/AP_Baro_LPS25H.h +++ b/libraries/AP_Baro/AP_Baro_LPS2XH.h @@ -10,27 +10,44 @@ #define HAL_BARO_LPS25H_I2C_ADDR 0x5D -class AP_Baro_LPS25H : public AP_Baro_Backend +class AP_Baro_LPS2XH : public AP_Baro_Backend { public: - AP_Baro_LPS25H(AP_Baro &baro, AP_HAL::OwnPtr dev); + enum LPS2XH_TYPE { + BARO_LPS22H = 0, + BARO_LPS25H = 1, + }; + + AP_Baro_LPS2XH(AP_Baro &baro, AP_HAL::OwnPtr dev); /* AP_Baro public interface: */ void update(); static AP_Baro_Backend *probe(AP_Baro &baro, AP_HAL::OwnPtr dev); + private: + virtual ~AP_Baro_LPS2XH(void) {}; bool _init(void); void _timer(void); void _update_temperature(void); void _update_pressure(void); + bool _check_whoami(void); + AP_HAL::OwnPtr _dev; bool _has_sample; uint8_t _instance; float _pressure; float _temperature; + + uint32_t CallTime = 0; + + enum LPS2XH_TYPE _lps2xh_type; + + // WHOAMI values +#define LPS22HB_WHOAMI 0xB1 +#define LPS25HB_WHOAMI 0xBD };