1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/lpsxxx/lpsxxx.c

261 lines
7.5 KiB
C

/*
* Copyright (C) 2014 Freie Universität Berlin
* 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_lpsxxx
* @{
*
* @file
* @brief Device driver implementation for the LPSXXX family of pressure sensors
*
* @note The current driver implementation is very basic and allows only for polling the
* devices temperature and pressure values. Threshold values and interrupts are not
* used.
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include <stdint.h>
#include "periph/i2c.h"
#include "lpsxxx.h"
#include "lpsxxx_internal.h"
#include "macros/math.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief pressure divider for norming pressure output
*/
#define PRES_DIVIDER (12U)
/**
* @brief temperature base value and divider for norming temperature output
*
* @details temperature base is given in centi-degree-celsius
*/
#if MODULE_LPS331AP || MODULE_LPS25HB
#define TEMP_BASE (4250U) /* = 42.5 C */
#define TEMP_DIVIDER (480U)
#else
#define TEMP_BASE (0U)
#define TEMP_DIVIDER (100U)
#endif
#define DEV_I2C (dev->params.i2c)
#define DEV_ADDR (dev->params.addr)
#define DEV_RATE (dev->params.rate)
int lpsxxx_init(lpsxxx_t *dev, const lpsxxx_params_t * params)
{
dev->params = *params;
/* Acquire exclusive access to the bus. */
i2c_acquire(DEV_I2C);
uint8_t id;
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_WHO_AM_I, &id, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] init: cannot read WHO_AM_I register\n");
return -LPSXXX_ERR_I2C;
}
if (id != LPSXXX_WHO_AM_I) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] init: not a valid device (got %02X, expected %02X)\n",
id, LPSXXX_WHO_AM_I);
return -LPSXXX_ERR_NODEV;
}
uint8_t tmp;
#if MODULE_LPS22HB
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG2, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] init: cannot read LPSXXX_REG_CTRL_REG2 register\n");
return -LPSXXX_ERR_I2C;
}
/* Disable automatic increment of register address during byte access
(recommended in datasheet (section 9.6 CTRL_REG2) */
tmp &= ~LPSXXX_CTRL_REG2_ID_ADD_INC;
DEBUG("[lpsxxx] init: update reg2, %02X\n", tmp);
if (i2c_write_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG2, tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] init: cannot write in CTRL_REG2 register\n");
return -LPSXXX_ERR_I2C;
}
#endif
/* configure device, for simple operation only CTRL_REG1 needs to be touched */
#if MODULE_LPS331AP
tmp = LPSXXX_CTRL_REG1_DBDU | LPSXXX_CTRL_REG1_PD |
(DEV_RATE << LPSXXX_CTRL_REG1_ODR_POS);
#elif MODULE_LPS25HB
tmp = LPSXXX_CTRL_REG1_BDU | LPSXXX_CTRL_REG1_PD |
(DEV_RATE << LPSXXX_CTRL_REG1_ODR_POS);
#elif MODULE_LPS22HB
tmp = LPSXXX_CTRL_REG1_EN_LPFP | /* Low-pass filter configuration: ODR/9 */
LPSXXX_CTRL_REG1_BDU | (DEV_RATE << LPSXXX_CTRL_REG1_ODR_POS);
#elif MODULE_LPS22HH || MODULE_LPS22CH
tmp = LPSXXX_CTRL_REG1_EN_LPFP | /* Low-pass filter configuration: ODR/9 */
LPSXXX_CTRL_REG1_BDU | (DEV_RATE << LPSXXX_CTRL_REG1_ODR_POS);
#endif
DEBUG("[lpsxxx] init: update reg1, value: %02X\n", tmp);
if (i2c_write_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG1, tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] init: cannot write in CTRL_REG1 register\n");
return -LPSXXX_ERR_I2C;
}
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] initialization successful\n");
return LPSXXX_OK;
}
int lpsxxx_read_temp(const lpsxxx_t *dev, int16_t *temp)
{
uint8_t tmp;
int16_t val;
uint16_t res = TEMP_BASE; /* reference value -> see datasheet */
i2c_acquire(DEV_I2C);
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_TEMP_OUT_L, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] read_temp: cannot read TEMP_OUT_L register\n");
return -LPSXXX_ERR_I2C;
}
val = tmp;
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_TEMP_OUT_H, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] read_temp: cannot read TEMP_OUT_H register\n");
return -LPSXXX_ERR_I2C;
}
i2c_release(DEV_I2C);
val |= ((uint16_t)tmp << 8);
DEBUG("[lpsxxx] read_temp: raw data %08" PRIx16 "\n", val);
/* compute actual temperature value in c°C */
res += DIV_ROUND((int32_t)val * 100, TEMP_DIVIDER);
*temp = res;
return LPSXXX_OK;
}
int lpsxxx_read_pres(const lpsxxx_t *dev, uint16_t *pres)
{
uint8_t tmp;
int32_t val = 0;
i2c_acquire(DEV_I2C);
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_PRESS_OUT_XL, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] read_pres: cannot read PRES_OUT_XL register\n");
return -LPSXXX_ERR_I2C;
}
val |= tmp;
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_PRESS_OUT_L, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] read_pres: cannot read PRES_OUT_L register\n");
return -LPSXXX_ERR_I2C;
}
val |= ((uint32_t)tmp << 8);
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_PRESS_OUT_H, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] read_pres: cannot read PRES_OUT_H register\n");
return -LPSXXX_ERR_I2C;
}
i2c_release(DEV_I2C);
val |= ((uint32_t)tmp << 16);
DEBUG("[lpsxxx] read_pres: raw data %08" PRIx32 "\n", (uint32_t)val);
/* see if value is negative */
if (tmp & 0x80) {
val |= ((uint32_t)0xff << 24);
}
/* compute actual pressure value in hPa */
*pres = (uint16_t)(val >> PRES_DIVIDER);
return LPSXXX_OK;
}
int lpsxxx_enable(const lpsxxx_t *dev)
{
uint8_t tmp;
i2c_acquire(DEV_I2C);
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG1, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] enable: cannot read CTRL_REG1 register\n");
return -LPSXXX_ERR_I2C;
}
#if MODULE_LPS331AP || MODULE_LPS25HB
tmp |= LPSXXX_CTRL_REG1_PD;
#else
tmp |= LPSXXX_CTRL_REG1_EN_LPFP | /* Low-pass filter configuration: ODR/9 */
LPSXXX_CTRL_REG1_BDU | (DEV_RATE << LPSXXX_CTRL_REG1_ODR_POS);
#endif
DEBUG("[lpsxxx] enable: update reg1 with %02X\n", tmp);
if (i2c_write_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG1, tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] enable: cannot write CTRL_REG1 register\n");
return -LPSXXX_ERR_I2C;
}
i2c_release(DEV_I2C);
return LPSXXX_OK;
}
int lpsxxx_disable(const lpsxxx_t *dev)
{
uint8_t tmp;
i2c_acquire(DEV_I2C);
if (i2c_read_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG1, &tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] disable: cannot read CTRL_REG1 register\n");
return -LPSXXX_ERR_I2C;
}
#if MODULE_LPS331AP || MODULE_LPS25HB
tmp &= ~LPSXXX_CTRL_REG1_PD;
#else
tmp &= ~(7 << LPSXXX_CTRL_REG1_ODR_POS);
#endif
DEBUG("[lpsxxx] disable: update reg1 with %02X\n", tmp);
if (i2c_write_reg(DEV_I2C, DEV_ADDR, LPSXXX_REG_CTRL_REG1, tmp, 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[lpsxxx] disable: cannot write CTRL_REG1 register\n");
return -LPSXXX_ERR_I2C;
}
i2c_release(DEV_I2C);
return LPSXXX_OK;
}