diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index bddc85e421b..c7137c3c124 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -3,6 +3,13 @@ # see the file kconfig-language.txt in the NuttX tools repository. # +config BMP180 + bool "Bosch BMP180 Barometer Sensor support" + default n + select I2C + ---help--- + Enable driver support for the Bosch BMP180 barometer sensor. + config LIS331DL bool "ST LIS331DL device support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index 4fc8e84cfca..ce887cdd1b0 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -53,6 +53,10 @@ ifeq ($(CONFIG_ADXL345_I2C),y) CSRCS += adxl345_i2c.c endif +ifeq ($(CONFIG_BMP180),y) + CSRCS += bmp180.c +endif + ifeq ($(CONFIG_I2C_LM75),y) CSRCS += lm75.c endif @@ -82,4 +86,4 @@ DEPPATH += --dep-path sensors VPATH += :sensors CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)sensors} -endif # CONFIG_SENSORS \ No newline at end of file +endif # CONFIG_SENSORS diff --git a/drivers/sensors/bmp180.c b/drivers/sensors/bmp180.c new file mode 100644 index 00000000000..32b1d4bc5e1 --- /dev/null +++ b/drivers/sensors/bmp180.c @@ -0,0 +1,621 @@ + +/**************************************************************************** + * drivers/sensors/bmp180.c + * Character driver for the Freescale BMP1801 Barometer Sensor + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015 Alan Carvalho de Assis + * Author: Alan Carvalho de Assis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_BMP180) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BMP180_ADDR 0x77 +#define BMP180_FREQ 100000 +#define DEVID 0x55 + +#define BMP180_AC1_MSB 0xaa +#define BMP180_AC1_LSB 0xab +#define BMP180_AC2_MSB 0xac +#define BMP180_AC2_LSB 0xad +#define BMP180_AC3_MSB 0xae +#define BMP180_AC3_LSB 0xaf +#define BMP180_AC4_MSB 0xb0 +#define BMP180_AC4_LSB 0xb1 +#define BMP180_AC5_MSB 0xb2 +#define BMP180_AC5_LSB 0xb3 +#define BMP180_AC6_MSB 0xb4 +#define BMP180_AC6_LSB 0xb5 +#define BMP180_B1_MSB 0xb6 +#define BMP180_B1_LSB 0xb7 +#define BMP180_B2_MSB 0xb8 +#define BMP180_B2_LSB 0xb9 +#define BMP180_MB_MSB 0xba +#define BMP180_MB_LSB 0xbb +#define BMP180_MC_MSB 0xbc +#define BMP180_MC_LSB 0xbd +#define BMP180_MD_MSB 0xbe +#define BMP180_MD_LSB 0xbf + +#define BMP180_DEVID 0xd0 +#define BMP180_SOFT_RESET 0xe0 +#define BMP180_CTRL_MEAS 0xf4 +#define BMP180_ADC_OUT_MSB 0xf6 +#define BMP180_ADC_OUT_LSB 0xf7 +#define BMP180_ADC_OUT_XLSB 0xf8 + +#define BMP180_READ_TEMP 0x2e +#define BMP180_READ_PRESS 0x34 + +#define BMP180_NOOVERSAMPLE 0x00 +#define BMP180_OVERSAMPLE2X 0x70 +#define BMP180_OVERSAMPLE4X 0xb0 +#define BMP180_OVERSAMPLE8X 0xc0 + +/* Current Oversampling */ + +#define CURRENT_OSS (BMP180_OVERSAMPLE8X) + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +struct bmp180_dev_s +{ + FAR struct i2c_dev_s *i2c; /* I2C interface */ + uint8_t addr; /* BMP180 I2C address */ + int freq; /* BMP180 Frequency <= 3.4MHz */ + int16_t bmp180_cal_ac1; /* Calibration coefficients */ + int16_t bmp180_cal_ac2; + int16_t bmp180_cal_ac3; + uint16_t bmp180_cal_ac4; + uint16_t bmp180_cal_ac5; + uint16_t bmp180_cal_ac6; + int16_t bmp180_cal_b1; + int16_t bmp180_cal_b2; + int16_t bmp180_cal_mb; + int16_t bmp180_cal_mc; + int16_t bmp180_cal_md; + int32_t bmp180_utemp; /* Uncompensated temperature read from BMP180 */ + int32_t bmp180_upress; /* Uncompensated pressure read from BMP180 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static uint8_t bmp180_getreg8(FAR struct bmp180_dev_s *priv, uint8_t regaddr); +static uint16_t bmp180_getreg16(FAR struct bmp180_dev_s *priv, uint8_t regaddr); +static void bmp180_putreg8(FAR struct bmp180_dev_s *priv, uint8_t regaddr, + uint8_t regval); +static void bmp180_updatecaldata(FAR struct bmp180_dev_s *priv); +static void bmp180_read_press_temp(FAR struct bmp180_dev_s *priv); +static int bmp180_getpressure(FAR struct bmp180_dev_s *priv); + +/* Character driver methods */ + +static int bmp180_open(FAR struct file *filep); +static int bmp180_close(FAR struct file *filep); +static ssize_t bmp180_read(FAR struct file *, FAR char *, size_t); +static ssize_t bmp180_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_bmp180fops = +{ + bmp180_open, /* open */ + bmp180_close, /* close */ + bmp180_read, /* read */ + bmp180_write, /* write */ + 0, /* seek */ + 0, /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + 0, /* poll */ +#endif + 0 /* unlink */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bmp180_getreg8 + * + * Description: + * Read from an 8-bit BMP180 register + * + ****************************************************************************/ + +static uint8_t bmp180_getreg8(FAR struct bmp180_dev_s *priv, uint8_t regaddr) +{ + int ret; + uint8_t regval = 0; + + /* Restart the register */ + + ret = I2C_WRITE(priv->i2c, ®addr, 1); + if (ret < 0) + { + sndbg("I2C_WRITE failed: %d\n", ret); + return ret; + } + + /* Restart the register */ + + ret = I2C_READ(priv->i2c, ®val, 1); + if (ret < 0) + { + sndbg("I2C_READ failed: %d\n", ret); + return ret; + } + + return regval; +} + +/**************************************************************************** + * Name: bmp180_getreg16 + * + * Description: + * Read two 8-bit from a BMP180 register + * + ****************************************************************************/ + +static uint16_t bmp180_getreg16(FAR struct bmp180_dev_s *priv, uint8_t regaddr) +{ + int ret; + uint16_t msb, lsb; + uint16_t regval = 0; + + /* Register to read */ + + ret = I2C_WRITE(priv->i2c, ®addr, 1); + if (ret < 0) + { + sndbg("I2C_WRITE failed: %d\n", ret); + return ret; + } + + /* Read register */ + + ret = I2C_READ(priv->i2c, (uint8_t *)®val, 2); + if (ret < 0) + { + sndbg("I2C_READ failed: %d\n", ret); + return ret; + } + + /* MSB and LSB are inverted */ + + msb = (regval & 0xFF); + lsb = (regval & 0xFF00) >> 8; + + regval = (msb << 8) | lsb; + + return regval; +} + +/**************************************************************************** + * Name: bmp180_putreg8 + * + * Description: + * Write to an 8-bit BMP180 register + * + ****************************************************************************/ + +static void bmp180_putreg8(FAR struct bmp180_dev_s *priv, uint8_t regaddr, + uint8_t regval) +{ + int ret; + uint8_t data[2]; + + data[0] = regaddr; + data[1] = regval; + + /* Restart the register */ + + ret = I2C_WRITE(priv->i2c, (uint8_t *) &data, 2); + if (ret < 0) + { + sndbg("I2C_WRITE failed: %d\n", ret); + return; + } + + return; +} + +/**************************************************************************** + * Name: bmp180_checkid + * + * Description: + * Read and verify the BMP180 chip ID + * + ****************************************************************************/ + +static int bmp180_checkid(FAR struct bmp180_dev_s *priv) +{ + uint8_t devid = 0; + + /* Read device ID */ + + devid = bmp180_getreg8(priv, BMP180_DEVID); + snvdbg("devid: 0x%02x\n", devid); + + if (devid != (uint16_t) DEVID) + { + /* ID is not Correct */ + + sndbg("Wrong Device ID!\n"); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: bmp180_updatecaldata + * + * Description: + * Update Calibration Coefficient Data + * + ****************************************************************************/ + +static void bmp180_updatecaldata(FAR struct bmp180_dev_s *priv) +{ + /* AC1 */ + + priv->bmp180_cal_ac1 = (int16_t) bmp180_getreg16(priv, BMP180_AC1_MSB); + + /* AC2 */ + + priv->bmp180_cal_ac2 = (int16_t) bmp180_getreg16(priv, BMP180_AC2_MSB); + + /* AC3 */ + + priv->bmp180_cal_ac3 = (int16_t) bmp180_getreg16(priv, BMP180_AC3_MSB); + + /* AC4 */ + + priv->bmp180_cal_ac4 = bmp180_getreg16(priv, BMP180_AC4_MSB); + + /* AC5 */ + + priv->bmp180_cal_ac5 = bmp180_getreg16(priv, BMP180_AC5_MSB); + + /* AC6 */ + + priv->bmp180_cal_ac6 = bmp180_getreg16(priv, BMP180_AC6_MSB); + + /* B1 */ + + priv->bmp180_cal_b1 = (int16_t) bmp180_getreg16(priv, BMP180_B1_MSB); + + /* B2 */ + + priv->bmp180_cal_b2 = (int16_t) bmp180_getreg16(priv, BMP180_B2_MSB); + + /* MB */ + + priv->bmp180_cal_mb = (int16_t) bmp180_getreg16(priv, BMP180_MB_MSB); + + /* MC */ + + priv->bmp180_cal_mc = (int16_t) bmp180_getreg16(priv, BMP180_MC_MSB); + + /* MD */ + + priv->bmp180_cal_md = (int16_t) bmp180_getreg16(priv, BMP180_MD_MSB); +} + +/**************************************************************************** + * Name: bmp180_read_press_temp + * + * Description: + * Read raw pressure and temperature from BMP180 and store it in the + * bmp180_dev_s structure. + * + ****************************************************************************/ + +static void bmp180_read_press_temp(FAR struct bmp180_dev_s *priv) +{ + uint8_t oss = CURRENT_OSS; + + /* Issue a read temperature command */ + + bmp180_putreg8(priv, BMP180_CTRL_MEAS, BMP180_READ_TEMP); + + /* Wait 5ms */ + + usleep(5000); + + /* Read temperature */ + + priv->bmp180_utemp = bmp180_getreg16(priv, BMP180_ADC_OUT_MSB); + + /* Issue a read pressure command */ + + bmp180_putreg8(priv, BMP180_CTRL_MEAS, (BMP180_READ_PRESS | oss)); + + /* Delay 25.5ms (to OverSampling 8X) */ + + usleep(25500); + + /* Read pressure */ + + priv->bmp180_upress = bmp180_getreg16(priv, BMP180_ADC_OUT_MSB) << 8; + priv->bmp180_upress |= bmp180_getreg8(priv, BMP180_ADC_OUT_XLSB); + priv->bmp180_upress = priv->bmp180_upress >> (8 - (oss >> 6)); + + snvdbg("Uncompensated temperature = %d\n", priv->bmp180_utemp); + snvdbg("Uncompensated pressure = %d\n", priv->bmp180_upress); +} + +/**************************************************************************** + * Name: bmp180_getpressure + * + * Description: + * Calculate the Barometric Pressure using the temperature compensated + * See Freescale AN3785 and BMP1801 data sheet for details + * + ****************************************************************************/ + +static int bmp180_getpressure(FAR struct bmp180_dev_s *priv) +{ + int32_t x1; + int32_t x2; + int32_t x3; + int32_t b3; + int32_t b5; + int32_t b6; + int32_t press; + int32_t temp; + uint32_t b4; + uint32_t b7; + uint8_t oss = (CURRENT_OSS >> 6); + + /* Check if coefficient data were read correctly */ + + if ((priv->bmp180_cal_ac1 == 0) || (priv->bmp180_cal_ac2 == 0) || + (priv->bmp180_cal_ac3 == 0) || (priv->bmp180_cal_ac4 == 0) || + (priv->bmp180_cal_ac5 == 0) || (priv->bmp180_cal_ac6 == 0) || + (priv->bmp180_cal_b1 == 0) || (priv->bmp180_cal_b2 == 0) || + (priv->bmp180_cal_mb == 0) || (priv->bmp180_cal_mc == 0) || + (priv->bmp180_cal_md == 0)) + { + bmp180_updatecaldata(priv); + } + + /* Read temperature and pressure */ + + bmp180_read_press_temp(priv); + + /* Calculate true temperature */ + + x1 = ((priv->bmp180_utemp - priv->bmp180_cal_ac6) * priv->bmp180_cal_ac5) >> 15; + x2 = (priv->bmp180_cal_mc << 11) / (x1 + priv->bmp180_cal_md); + b5 = x1 + x2; + temp = (b5 + 8) >> 4; + snvdbg("Compensated temperature = %d\n", temp); + + /* Calculate true pressure */ + + b6 = b5 - 4000; + x1 = (priv->bmp180_cal_b2 * ((b6 * b6) >> 12)) >> 11; + x2 = (priv->bmp180_cal_ac2 * b6) >> 11; + x3 = x1 + x2; + b3 = (((((int32_t) priv->bmp180_cal_ac1) * 4 + x3) << oss) + 2) >> 2; + x1 = (priv->bmp180_cal_ac3 * b6) >> 13; + x2 = (priv->bmp180_cal_b1 * ((b6 * b6) >> 12)) >> 16; + x3 = ((x1 + x2) + 2) >> 2; + b4 = (priv->bmp180_cal_ac4 * (uint32_t) (x3 + 32768)) >> 15; + b7 = ((uint32_t) (priv->bmp180_upress - b3) * (50000 >> oss)); + + if (b7 < 0x80000000) + { + press = (b7 << 1) / b4; + } + else + { + press = (b7 / b4) << 1; + } + + x1 = (press >> 8) * (press >> 8); + x1 = (x1 * 3038) >> 16; + x2 = (-7357 * press) >> 16; + + press = press + ((x1 + x2 + 3791) >> 4); + + snvdbg("Compressed pressure = %d\n", press); + return press; +} + +/**************************************************************************** + * Name: bmp180_open + * + * Description: + * This function is called whenever the BMP1801 device is opened. + * + ****************************************************************************/ + +static int bmp180_open(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: bmp180_close + * + * Description: + * This routine is called when the BMP180 device is closed. + * + ****************************************************************************/ + +static int bmp180_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: bmp180_read + ****************************************************************************/ + +static ssize_t bmp180_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bmp180_dev_s *priv = inode->i_private; + FAR uint32_t *press = (FAR uint32_t *) buffer; + + if (!buffer) + { + sndbg("Buffer is null\n"); + return -1; + } + + if ( buflen != 4) + { + sndbg("You can't read something other than 32 bits (4 bytes)\n"); + return -1; + } + + /* Get the pressure compensated */ + + *press = (int32_t) bmp180_getpressure(priv); + + /* Return size of uint32_t (4 bytes) */ + + return 4; +} + +/**************************************************************************** + * Name: bmp180_write + ****************************************************************************/ + +static ssize_t bmp180_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bmp180_register + * + * Description: + * Register the BMP180 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/press0" + * i2c - An instance of the I2C interface to use to communicate with + * BMP180 + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int bmp180_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c) +{ + FAR struct bmp180_dev_s *priv; + int ret; + + /* Initialize the BMP180 device structure */ + + priv = (FAR struct bmp180_dev_s *)kmm_malloc(sizeof(struct bmp180_dev_s)); + if (!priv) + { + sndbg("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = BMP180_ADDR; + priv->freq = BMP180_FREQ; + + /* Configure I2C before using it */ + + I2C_SETADDRESS(priv->i2c, priv->addr, 7); + I2C_SETFREQUENCY(priv->i2c, priv->freq); + + /* Check Device ID */ + + ret = bmp180_checkid(priv); + if (ret < 0) + { + sndbg("Failed to register driver: %d\n", ret); + kmm_free(priv); + return ret; + } + + /* Read the coefficient value */ + + bmp180_updatecaldata(priv); + + /* Register the character driver */ + + ret = register_driver(devpath, &g_bmp180fops, 0666, priv); + if (ret < 0) + { + sndbg("Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + snvdbg("BMP180 driver loaded successfully!\n"); + return ret; +} + +#endif /* CONFIG_I2C && CONFIG_BMP180 */ diff --git a/include/nuttx/sensors/bmp180.h b/include/nuttx/sensors/bmp180.h new file mode 100644 index 00000000000..668ce62815f --- /dev/null +++ b/include/nuttx/sensors/bmp180.h @@ -0,0 +1,92 @@ +/******************************************************************************************** + * drivers/sensors/bmp180.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Alan Carvalho de Assis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ********************************************************************************************/ + +#ifndef __DRIVERS_SENSORS_BMP180_H +#define __DRIVERS_SENSORS_BMP180_H + +#if defined(CONFIG_BMP180) + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ + +#define BMP180_I2C_PORTNO 1 + +/* Configuration ****************************************************************************/ +/* Prerequisites: + * + * CONFIG_BMP180 + * Enables support for the BMP180 driver + * CONFIG_BMP180_REGDEBUG + * Enable very low register-level debug output. Requires CONFIG_DEBUG. + */ + +/******************************************************************************************** + * Public Function Prototypes + ********************************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: bmp180_register + * + * Description: + * Register the BMP180 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/press0" + * i2c - An instance of the I2C interface to use to communicate with + * BMP180 + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int bmp180_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_BMP180 */ +#endif /* __DRIVERS_BMP180_H */