Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_Baro/AP_Baro_LPS2XH.cpp
Views: 1798
/*1This program is free software: you can redistribute it and/or modify2it under the terms of the GNU General Public License as published by3the Free Software Foundation, either version 3 of the License, or4(at your option) any later version.56This program is distributed in the hope that it will be useful,7but WITHOUT ANY WARRANTY; without even the implied warranty of8MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9GNU General Public License for more details.1011You should have received a copy of the GNU General Public License12along with this program. If not, see <http://www.gnu.org/licenses/>.13*/14#include "AP_Baro_LPS2XH.h"1516#if AP_BARO_LPS2XH_ENABLED1718#include <utility>19#include <stdio.h>2021#include <AP_InertialSensor/AP_InertialSensor_Invensense_registers.h>2223extern const AP_HAL::HAL &hal;2425// WHOAMI values26#define LPS22HB_WHOAMI 0xB127#define LPS25HB_WHOAMI 0xBD2829#define REG_ID 0x0F3031#define LPS22H_ID 0xB132#define LPS22H_CTRL_REG1 0x1033#define LPS22H_CTRL_REG2 0x1134#define LPS22H_CTRL_REG3 0x123536#define LPS22H_CTRL_REG1_SIM (1 << 0)37#define LPS22H_CTRL_REG1_BDU (1 << 1)38#define LPS22H_CTRL_REG1_LPFP_CFG (1 << 2)39#define LPS22H_CTRL_REG1_EN_LPFP (1 << 3)40#define LPS22H_CTRL_REG1_PD (0 << 4)41#define LPS22H_CTRL_REG1_ODR_1H (1 << 4)42#define LPS22H_CTRL_REG1_ODR_10HZ (2 << 4)43#define LPS22H_CTRL_REG1_ODR_25HZ (3 << 4)44#define LPS22H_CTRL_REG1_ODR_50HZ (4 << 4)45#define LPS22H_CTRL_REG1_ODR_75HZ (5 << 4)4647#define LPS25H_CTRL_REG1_ADDR 0x2048#define LPS25H_CTRL_REG2_ADDR 0x2149#define LPS25H_CTRL_REG3_ADDR 0x2250#define LPS25H_CTRL_REG4_ADDR 0x2351#define LPS25H_FIFO_CTRL 0x2E52#define TEMP_OUT_ADDR 0x2B53#define PRESS_OUT_XL_ADDR 0x2854#define STATUS_ADDR 0x275556//putting 1 in the MSB of those two registers turns on Auto increment for faster reading.5758AP_Baro_LPS2XH::AP_Baro_LPS2XH(AP_Baro &baro, AP_HAL::OwnPtr<AP_HAL::Device> dev)59: AP_Baro_Backend(baro)60, _dev(std::move(dev))61{62}6364AP_Baro_Backend *AP_Baro_LPS2XH::probe(AP_Baro &baro,65AP_HAL::OwnPtr<AP_HAL::Device> dev)66{67if (!dev) {68return nullptr;69}7071AP_Baro_LPS2XH *sensor = NEW_NOTHROW AP_Baro_LPS2XH(baro, std::move(dev));72if (!sensor || !sensor->_init()) {73delete sensor;74return nullptr;75}7677return sensor;78}7980AP_Baro_Backend *AP_Baro_LPS2XH::probe_InvensenseIMU(AP_Baro &baro,81AP_HAL::OwnPtr<AP_HAL::Device> dev,82uint8_t imu_address)83{84if (!dev) {85return nullptr;86}8788AP_Baro_LPS2XH *sensor = NEW_NOTHROW AP_Baro_LPS2XH(baro, std::move(dev));89if (sensor) {90if (!sensor->_imu_i2c_init(imu_address)) {91delete sensor;92return nullptr;93}94}9596if (!sensor || !sensor->_init()) {97delete sensor;98return nullptr;99}100101return sensor;102}103104/*105setup invensense IMU to enable barometer, assuming both IMU and baro106on the same i2c bus107*/108bool AP_Baro_LPS2XH::_imu_i2c_init(uint8_t imu_address)109{110_dev->get_semaphore()->take_blocking();111112// as the baro device is already locked we need to re-use it,113// changing its address to match the IMU address114uint8_t old_address = _dev->get_bus_address();115_dev->set_address(imu_address);116117_dev->set_retries(4);118119uint8_t whoami=0;120_dev->read_registers(MPUREG_WHOAMI, &whoami, 1);121DEV_PRINTF("IMU: whoami 0x%02x old_address=%02x\n", whoami, old_address);122123_dev->write_register(MPUREG_FIFO_EN, 0x00);124_dev->write_register(MPUREG_PWR_MGMT_1, BIT_PWR_MGMT_1_CLK_XGYRO);125126// wait for sensor to settle127hal.scheduler->delay(10);128129_dev->write_register(MPUREG_INT_PIN_CFG, BIT_BYPASS_EN);130131_dev->set_address(old_address);132133_dev->get_semaphore()->give();134135return true;136}137138bool AP_Baro_LPS2XH::_init()139{140if (!_dev) {141return false;142}143_dev->get_semaphore()->take_blocking();144145_dev->set_speed(AP_HAL::Device::SPEED_HIGH);146147// top bit is for read on SPI148if (_dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {149_dev->set_read_flag(0x80);150}151152if (!_check_whoami()) {153_dev->get_semaphore()->give();154return false;155}156157//init control registers.158if (_lps2xh_type == BARO_LPS25H) {159_dev->write_register(LPS25H_CTRL_REG1_ADDR,0x00); // turn off for config160_dev->write_register(LPS25H_CTRL_REG2_ADDR,0x00); //FIFO Disabled161_dev->write_register(LPS25H_FIFO_CTRL, 0x01);162_dev->write_register(LPS25H_CTRL_REG1_ADDR,0xc0);163164// request 25Hz update (maximum refresh Rate according to datasheet)165CallTime = 40 * AP_USEC_PER_MSEC;166}167168if (_lps2xh_type == BARO_LPS22H) {169_dev->write_register(LPS22H_CTRL_REG1, 0x00); // turn off for config170_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);171if (_dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {172_dev->write_register(LPS22H_CTRL_REG2, 0x18); // disable i2c173} else {174_dev->write_register(LPS22H_CTRL_REG2, 0x10);175}176177// request 75Hz update178CallTime = 1000000/75;179}180181_instance = _frontend.register_sensor();182183_dev->set_device_type(DEVTYPE_BARO_LPS2XH);184set_bus_id(_instance, _dev->get_bus_id());185186_dev->get_semaphore()->give();187188_dev->register_periodic_callback(CallTime, FUNCTOR_BIND_MEMBER(&AP_Baro_LPS2XH::_timer, void));189190return true;191}192193//check ID194bool AP_Baro_LPS2XH::_check_whoami(void)195{196uint8_t whoami;197if (!_dev->read_registers(REG_ID, &whoami, 1)) {198return false;199}200DEV_PRINTF("LPS2XH whoami 0x%02x\n", whoami);201202switch(whoami){203case LPS22HB_WHOAMI:204_lps2xh_type = BARO_LPS22H;205return true;206case LPS25HB_WHOAMI:207_lps2xh_type = BARO_LPS25H;208return true;209}210211return false;212}213214// accumulate a new sensor reading215void AP_Baro_LPS2XH::_timer(void)216{217uint8_t status;218// use status to check if data is available219if (!_dev->read_registers(STATUS_ADDR, &status, 1)) {220return;221}222223if (status & 0x02) {224_update_temperature();225}226227if (status & 0x01) {228_update_pressure();229}230}231232// transfer data to the frontend233void AP_Baro_LPS2XH::update(void)234{235if (_pressure_count == 0) {236return;237}238239WITH_SEMAPHORE(_sem);240_copy_to_frontend(_instance, _pressure_sum/_pressure_count, _temperature);241_pressure_sum = 0;242_pressure_count = 0;243}244245// calculate temperature246void AP_Baro_LPS2XH::_update_temperature(void)247{248uint8_t pu8[2];249if (!_dev->read_registers(TEMP_OUT_ADDR, pu8, 2)) {250return;251}252int16_t Temp_Reg_s16 = (uint16_t)(pu8[1]<<8) | pu8[0];253254WITH_SEMAPHORE(_sem);255256if (_lps2xh_type == BARO_LPS25H) {257_temperature = (Temp_Reg_s16 * (1.0/480)) + 42.5;258}259260if (_lps2xh_type == BARO_LPS22H) {261_temperature = Temp_Reg_s16 * 0.01;262}263}264265// calculate pressure266void AP_Baro_LPS2XH::_update_pressure(void)267{268uint8_t pressure[3];269if (!_dev->read_registers(PRESS_OUT_XL_ADDR, pressure, 3)) {270return;271}272273int32_t Pressure_Reg_s32 = ((uint32_t)pressure[2]<<16)|((uint32_t)pressure[1]<<8)|(uint32_t)pressure[0];274int32_t Pressure_mb = Pressure_Reg_s32 * (100.0f / 4096); // scale for pa275276WITH_SEMAPHORE(_sem);277_pressure_sum += Pressure_mb;278_pressure_count++;279}280281#endif // AP_BARO_LPS2XH_ENABLED282283284