From 7b666eb2a98ecd57c858c936ddc6517e10a84392 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Mon, 6 Oct 2014 19:11:09 +0200 Subject: [PATCH 1/3] drivers: added LPS331AP pressure sensor driver --- drivers/Makefile | 3 + drivers/Makefile.include | 3 + drivers/include/lps331ap.h | 112 ++++++++++++++++ drivers/lps331ap/Makefile | 3 + drivers/lps331ap/include/lps331ap-internal.h | 70 ++++++++++ drivers/lps331ap/lps331ap.c | 131 +++++++++++++++++++ 6 files changed, 322 insertions(+) create mode 100644 drivers/include/lps331ap.h create mode 100644 drivers/lps331ap/Makefile create mode 100644 drivers/lps331ap/include/lps331ap-internal.h create mode 100644 drivers/lps331ap/lps331ap.c diff --git a/drivers/Makefile b/drivers/Makefile index bb0312148d..d8d826a190 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -49,5 +49,8 @@ endif ifneq (,$(filter mq3,$(USEMODULE))) DIRS += mq3 endif +ifneq (,$(filter lps331ap,$(USEMODULE))) + DIRS += lps331ap +endif include $(RIOTBASE)/Makefile.base diff --git a/drivers/Makefile.include b/drivers/Makefile.include index f90e14c458..6dce21a4cb 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -13,3 +13,6 @@ endif ifneq (,$(filter isl29020,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29020/include endif +ifneq (,$(filter lps331ap,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lps331ap/include +endif diff --git a/drivers/include/lps331ap.h b/drivers/include/lps331ap.h new file mode 100644 index 0000000000..9ab54f09cb --- /dev/null +++ b/drivers/include/lps331ap.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * 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. + */ + +/** + * @defgroup driver_lps331ap LPS331AP Pressure Sensor Driver + * @ingroup drivers + * @brief Device driver for the LPS331AP pressure sensor + * @{ + * + * @file + * @brief Device driver interface for the LPS331AP pressure sensor + * + * @note This driver uses the sensors I2C interface + * + * @author Hauke Petersen + */ + +#ifndef __LPS331AP_H +#define __LPS331AP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "periph/i2c.h" + + /** + * @name The sensors default I2C address + */ +#define LPS331AP_DEFAULT_ADDRESS 0x5c + +/** + * @brief Device descriptor for LPS331AP sensors + */ +typedef struct { + i2c_t i2c; /**< I2C device the sensor is connected to */ + uint8_t address; /**< I2C bus address of the sensor */ +} lps331ap_t; + +/** + * @brief Possible sampling rates for LPS331AP sensors + */ +typedef enum { + LPS331AP_RATE_1HZ = 1, /**< sample with 1Hz */ + LPS331AP_RATE_7HZ = 5, /**< sample with 7Hz */ + LPS331AP_RATE_12HZ5 = 6, /**< sample with 12.5Hz */ + LPS331AP_RATE_25HZ = 7 /**< sample with 25Hz */ +} lps331ap_rate_t; + +/** + * @brief Initialize a given LPS331AP pressure sensor + * + * @param[out] dev device descriptor of the sensor + * @param[in] i2c I2C bus the sensor is connected to + * @param[in] address the sensor's address on the I2C bus + * @param[in] rate internal sampling rate of the sensor + * + * @return 0 on success + * @return -1 on error + */ +int lps331ap_init(lps331ap_t *dev, i2c_t i2c, uint8_t address, lps331ap_rate_t rate); + +/** + * @brief Read a temperature value from the given sensor, returned in m°C + * + * @param[in] dev device descriptor of sensor to read from + * + * @return temperature value in m°C + */ +int lps331ap_read_temp(lps331ap_t *dev); + +/** + * @brief Read a pressure value from the given sensor, returned in mbar + * + * @param[in] dev device descriptor of sensor to read from + * + * @return pressure value in mbar + */ +int lps331ap_read_pres(lps331ap_t *dev); + +/** + * @brief Enable the given sensor + * + * @param[in] dev device descriptor of sensor to enable + * + * @return 0 on success + * @return -1 on error + */ +int lps331ap_enable(lps331ap_t *dev); + +/** + * @brief Disable the given sensor + * + * @param[in] dev device descriptor of sensor to disable + * + * @return 0 on success + * @return -1 on error + */ +int lps331ap_disable(lps331ap_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __LPS331AP_H */ +/** @} */ diff --git a/drivers/lps331ap/Makefile b/drivers/lps331ap/Makefile new file mode 100644 index 0000000000..318d4ab0cf --- /dev/null +++ b/drivers/lps331ap/Makefile @@ -0,0 +1,3 @@ +MODULE = lps331ap + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/lps331ap/include/lps331ap-internal.h b/drivers/lps331ap/include/lps331ap-internal.h new file mode 100644 index 0000000000..ee109abf20 --- /dev/null +++ b/drivers/lps331ap/include/lps331ap-internal.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * 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 driver_lps331ap + * @{ + * + * @file + * @brief Definitions for the LPS331AP pressure sensor + * + * @author Hauke Petersen + */ + +#ifndef __LPS331AP_INTERNAL_H +#define __LPS331AP_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name LPS331AP registers + * @{ + */ +#define LPS331AP_AUTO_INC 0x80 +#define LPS331AP_REG_REF_P_XL 0x08 +#define LPS331AP_REG_REF_P_L 0x09 +#define LPS331AP_REG_REF_P_H 0x0a +#define LPS331AP_REG_WHO_AM_I 0x0f +#define LPS331AP_REG_RES_CONF 0x10 +#define LPS331AP_REG_CTRL_REG1 0x20 +#define LPS331AP_REG_CTRL_REG2 0x21 +#define LPS331AP_REG_CTRL_REG3 0x22 +#define LPS331AP_REG_INT_CFG_REG 0x23 +#define LPS331AP_REG_INT_SOURCE_REG 0x24 +#define LPS331AP_REG_THS_P_LOW_REG 0x25 +#define LPS331AP_REG_THS_P_HIGH_REG 0x26 +#define LPS331AP_REG_STATUS_REG 0x27 +#define LPS331AP_REG_PRESS_OUT_XL 0x28 +#define LPS331AP_REG_PRESS_OUT_L 0x29 +#define LPS331AP_REG_PRESS_OUT_H 0x2a +#define LPS331AP_REG_TEMP_OUT_L 0x2b +#define LPS331AP_REG_TEMP_OUT_H 0x2c +#define LPS331AP_REG_AMP_CTRL 0x30 +/** @} */ + +/** + * @name LPS331AP CTRL_REG1 bitfields + * @{ + */ +#define LPS331AP_CTRL_REG1_PD 0x80 +#define LPS331AP_CTRL_REG1_ODR 0x70 +#define LPS331AP_CTRL_REG1_ODR_POS 4 +#define LPS331AP_CTRL_REG1_DIFF_EN 0x08 +#define LPS331AP_CTRL_REG1_DBDU 0x04 +#define LPS331AP_CTRL_REG1_DELTA_EN 0x02 +#define LPS331AP_CTRL_REG1_SIM 0x01 +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LPS331AP_INTERNAL_H */ +/** @} */ diff --git a/drivers/lps331ap/lps331ap.c b/drivers/lps331ap/lps331ap.c new file mode 100644 index 0000000000..ad17c234a8 --- /dev/null +++ b/drivers/lps331ap/lps331ap.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * 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 driver_lps331ap + * @{ + * + * @file + * @brief Device driver implementation for the LPS331AP pressure sensor + * + * @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 + * + * @} + */ + +#include + +#include "periph/i2c.h" +#include "lps331ap.h" +#include "lps331ap-internal.h" + +/** + * @brief default I2C bus speed for this sensor + */ +#define BUS_SPEED I2C_SPEED_FAST + +/** + * @brief pressure divider for norming pressure output + */ +#define PRES_DIVIDER (4096U) + +/** + * @brief temperature base value and divider for norming temperature output + */ +#define TEMP_BASE (42.5f) +#define TEMP_DIVIDER (480U) + + +int lps331ap_init(lps331ap_t *dev, i2c_t i2c, uint8_t address, lps331ap_rate_t rate) +{ + char tmp; + + /* save device specifics */ + dev->i2c = i2c; + dev->address = address; + + /* initialize underlying I2C bus */ + if (i2c_init_master(dev->i2c, BUS_SPEED) < 0) { + return -1; + } + + /* configure device, for simple operation only CTRL_REG1 needs to be touched */ + tmp = LPS331AP_CTRL_REG1_DBDU | LPS331AP_CTRL_REG1_PD | + (rate << LPS331AP_CTRL_REG1_ODR_POS); + if (i2c_write_reg(dev->i2c, dev->address, LPS331AP_REG_CTRL_REG1, tmp) != 1) { + return -1; + } + + return 0; +} + +int lps331ap_read_temp(lps331ap_t *dev) +{ + char tmp; + int16_t val = 0; + float res = TEMP_BASE; /* reference value -> see datasheet */ + + i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_TEMP_OUT_L, &tmp); + val |= tmp; + i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_TEMP_OUT_H, &tmp); + val |= (tmp << 8); + + /* compute actual temperature value in °C */ + res += ((float)val) / TEMP_DIVIDER; + + /* return temperature in m°C */ + return (int)(res * 1000); +} + +int lps331ap_read_pres(lps331ap_t *dev) +{ + char tmp; + int32_t val = 0; + float res; + + i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_PRESS_OUT_XL, &tmp); + val |= tmp; + i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_PRESS_OUT_L, &tmp); + val |= (tmp << 8); + i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_PRESS_OUT_H, &tmp); + val |= (tmp << 16); + /* see if value is negative */ + if (tmp & 0x80) { + val |= (0xff << 24); + } + + /* compute actual pressure value in mbar */ + res = ((float)val) / PRES_DIVIDER; + + return (int)res; +} + + +int lps331ap_enable(lps331ap_t *dev) +{ + char tmp; + if (i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_CTRL_REG1, &tmp) != 1) { + return -1; + } + tmp |= (LPS331AP_CTRL_REG1_PD); + return i2c_write_reg(dev->i2c, dev->address, LPS331AP_REG_CTRL_REG1, tmp); +} + +int lps331ap_disable(lps331ap_t *dev) +{ + char tmp; + if (i2c_read_reg(dev->i2c, dev->address, LPS331AP_REG_CTRL_REG1, &tmp) != 1) { + return -1; + } + tmp &= ~(LPS331AP_CTRL_REG1_PD); + return i2c_write_reg(dev->i2c, dev->address, LPS331AP_REG_CTRL_REG1, tmp); +} From d31ed0f85b04776d5346be3c32d3671e2ada9926 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Wed, 15 Oct 2014 15:01:05 +0200 Subject: [PATCH 2/3] board/iot-lab_M3: added interface for LPS331AP --- boards/iot-lab_M3/include/board.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/boards/iot-lab_M3/include/board.h b/boards/iot-lab_M3/include/board.h index d85b6ab7dc..17fe1bb5c8 100644 --- a/boards/iot-lab_M3/include/board.h +++ b/boards/iot-lab_M3/include/board.h @@ -69,6 +69,14 @@ #define ISL29020_ADDR 0x44 /** @} */ +/** + * @name Define the interface to the LPS331AP pressure sensor + * @{ + */ +#define LPS331AP_I2C I2C_0 +#define LPS331AP_ADDR 0x5c +/** @} */ + /** * @name LED pin definitions * @{ From f06eeeaaefb3112f3d5821e506f2d0524e32594d Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Wed, 15 Oct 2014 16:14:37 +0200 Subject: [PATCH 3/3] tests: added test for LPS331AP sensor driver --- tests/driver_lps331ap/Makefile | 22 +++++++++++ tests/driver_lps331ap/README.md | 9 +++++ tests/driver_lps331ap/main.c | 68 +++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 tests/driver_lps331ap/Makefile create mode 100644 tests/driver_lps331ap/README.md create mode 100644 tests/driver_lps331ap/main.c diff --git a/tests/driver_lps331ap/Makefile b/tests/driver_lps331ap/Makefile new file mode 100644 index 0000000000..f5a4426a89 --- /dev/null +++ b/tests/driver_lps331ap/Makefile @@ -0,0 +1,22 @@ +APPLICATION = driver_lps331ap +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_i2c + +USEMODULE += lps331ap +USEMODULE += vtimer + +ifneq (,$(TEST_LPS331AP_I2C)) + CFLAGS += -DTEST_LPS331AP_I2C=$(TEST_LPS331AP_I2C) +else + # set random default + CFLAGS += -DTEST_LPS331AP_I2C=I2C_0 +endif +ifneq (,$(TEST_LPS331AP_ADDR)) + CFLAGS += -DTEST_LPS331AP_ADDR=$(TEST_LPS331AP_ADDR) +else + # set random default + CFLAGS += -DTEST_LPS331AP_ADDR=92 +endif + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_lps331ap/README.md b/tests/driver_lps331ap/README.md new file mode 100644 index 0000000000..96daac3736 --- /dev/null +++ b/tests/driver_lps331ap/README.md @@ -0,0 +1,9 @@ +# About +This is a manual test application for the LPS331AP pressure sensor driver. + +# Usage +This test application will initialize the pressure sensor with the following parameters: + - Sampling Rate: 7Hz + +After initialization, the sensor reads the pressure and temperature values every 250ms +and prints them to the STDOUT. diff --git a/tests/driver_lps331ap/main.c b/tests/driver_lps331ap/main.c new file mode 100644 index 0000000000..04f51d1bcb --- /dev/null +++ b/tests/driver_lps331ap/main.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * 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 tests + * @{ + * + * @file + * @brief Test application for the LPS331AP pressure sensor + * + * @author Hauke Petersen + * + * @} + */ + +#ifndef TEST_LPS331AP_I2C +#error "TEST_LPS331AP_I2C not defined" +#endif +#ifndef TEST_LPS331AP_ADDR +#error "TEST_LPS331AP_ADDR not defined" +#endif + +#include + +#include "vtimer.h" +#include "lps331ap.h" + +#define RATE LPS331AP_RATE_7HZ +#define SLEEP (250 * 1000U) + +int main(void) +{ + lps331ap_t dev; + int temp, pres; + int temp_abs, pres_abs; + + puts("LPS331AP pressure sensor test application\n"); + printf("Initializing LPS331AP sensor at I2C_%i... ", TEST_LPS331AP_I2C); + if (lps331ap_init(&dev, TEST_LPS331AP_I2C, TEST_LPS331AP_ADDR, RATE) == 0) { + puts("[OK]\n"); + } + else { + puts("[Failed]"); + return 1; + } + + while (1) { + pres = lps331ap_read_pres(&dev); + temp = lps331ap_read_temp(&dev); + + pres_abs = pres / 1000; + pres -= pres_abs * 1000; + temp_abs = temp / 1000; + temp -= temp_abs * 1000; + + printf("Pressure value: %2i.%03i bar - Temperature: %2i.%03i °C\n", + pres_abs, pres, temp_abs, temp); + + vtimer_usleep(SLEEP); + } + + return 0; +}