From 50e19250285c8ae06104d04a74e89d0a2c62e93a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 12 Feb 2015 12:18:43 -0600 Subject: Add driver for the Feescale MPL115A baramoter. From Alan Carvalho de Assis --- nuttx/drivers/sensors/mpl115a.c | 396 ++++++++++++++++++++++++++++++++++ nuttx/include/nuttx/sensors/mpl115a.h | 120 +++++++++++ 2 files changed, 516 insertions(+) create mode 100644 nuttx/drivers/sensors/mpl115a.c create mode 100644 nuttx/include/nuttx/sensors/mpl115a.h diff --git a/nuttx/drivers/sensors/mpl115a.c b/nuttx/drivers/sensors/mpl115a.c new file mode 100644 index 000000000..b507b3343 --- /dev/null +++ b/nuttx/drivers/sensors/mpl115a.c @@ -0,0 +1,396 @@ +/**************************************************************************** + * drivers/sensors/mpl115a.c + * Character driver for the Freescale MPL115A1 Barometer Sensor + * + * Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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_SPI) && defined(CONFIG_MPL115A) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private + ****************************************************************************/ + +struct mpl115a_dev_s +{ + FAR struct spi_dev_s *spi; /* SPI interface */ + int16_t mpl115a_cal_a0; + int16_t mpl115a_cal_b1; + int16_t mpl115a_cal_b2; + int16_t mpl115a_cal_c12; + uint16_t mpl115a_temperature; + uint16_t mpl115a_pressure; +}; + + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline void mpl115a_configspi(FAR struct spi_dev_s *spi); +static uint8_t mpl115a_getreg8(FAR struct mpl115a_dev_s *priv, uint8_t regaddr); +static void mpl115a_updatecaldata(FAR struct mpl115a_dev_s *priv); +static void mpl115a_read_press_temp(FAR struct mpl115a_dev_s *priv); +static int mpl115a_getpressure(FAR struct mpl115a_dev_s *priv); + +/* Character driver methods */ + +static int mpl115a_open(FAR struct file *filep); +static int mpl115a_close(FAR struct file *filep); +static ssize_t mpl115a_read(FAR struct file *, FAR char *, size_t); +static ssize_t mpl115a_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_mpl115afops = +{ + mpl115a_open, + mpl115a_close, + mpl115a_read, + mpl115a_write, + 0, + 0 +#ifndef CONFIG_DISABLE_POLL + , 0 +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifndef CONFIG_SPI_OWNBUS +static inline void mpl115a_configspi(FAR struct spi_dev_s *spi) +{ + /* Configure SPI for the MPL115A */ + + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETBITS(spi, 8); + SPI_SETFREQUENCY(spi, MPL115A_SPI_MAXFREQUENCY); +} +#endif + +/**************************************************************************** + * Name: mpl115a_getreg8 + * + * Description: + * Read from an 8-bit MPL115A register + * + ****************************************************************************/ + +static uint8_t mpl115a_getreg8(FAR struct mpl115a_dev_s *priv, uint8_t regaddr) +{ + uint8_t regval; + + /* If SPI bus is shared then lock and configure it */ + +#ifndef CONFIG_SPI_OWNBUS + (void)SPI_LOCK(priv->spi, true); + mpl115a_configspi(priv->spi); +#endif + + /* Select the MPL115A */ + + SPI_SELECT(priv->spi, SPIDEV_BAROMETER, true); + + /* Send register to read and get the next byte */ + + (void)SPI_SEND(priv->spi, regaddr); + SPI_RECVBLOCK(priv->spi, ®val, 1); + + /* Deselect the MPL115A */ + + SPI_SELECT(priv->spi, SPIDEV_BAROMETER, false); + + /* Unlock bus */ + +#ifndef CONFIG_SPI_OWNBUS + (void)SPI_LOCK(priv->spi, false); +#endif + +#ifdef CONFIG_MPL115A_REGDEBUG + dbg("%02x->%02x\n", regaddr, regval); +#endif + return regval; +} + +/**************************************************************************** + * Name: mpl115a_updatecaldata + * + * Description: + * Update Calibration Coefficient Data + * + ****************************************************************************/ + +static void mpl115a_updatecaldata(FAR struct mpl115a_dev_s *priv) +{ + /* Get a0 coefficient */ + priv->mpl115a_cal_a0 = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_A0_MSB << 1)) << 8; + priv->mpl115a_cal_a0 |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_A0_LSB << 1)); + sndbg("a0 = %d\n", priv->mpl115a_cal_a0); + + /* Get b1 coefficient */ + priv->mpl115a_cal_b1 = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_B1_MSB << 1)) << 8; + priv->mpl115a_cal_b1 |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_B1_LSB << 1)); + sndbg("b1 = %d\n", priv->mpl115a_cal_b1); + + /* Get b2 coefficient */ + priv->mpl115a_cal_b2 = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_B2_MSB << 1)) << 8; + priv->mpl115a_cal_b2 |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_B2_LSB << 1)); + sndbg("b2 = %d\n", priv->mpl115a_cal_b2); + + /* Get c12 coefficient */ + priv->mpl115a_cal_c12 = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_C12_MSB << 1)) << 8; + priv->mpl115a_cal_c12 |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_C12_LSB << 1)); + sndbg("c12 = %d\n", priv->mpl115a_cal_c12); + + return; +} + +/**************************************************************************** + * Name: mpl115a_read_press_temp + * + * Description: + * Read raw pressure and temperature from MPL115A and store it in the + * mpl115a_dev_s structure. + */ +static void mpl115a_read_press_temp(FAR struct mpl115a_dev_s *priv) +{ + uint16_t pressure; + + /* Start a new convertion */ + mpl115a_getreg8(priv, (MPL115A_CONVERT << 1)); + + /* Delay 5ms */ + usleep(5000); + + priv->mpl115a_pressure = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_PADC_MSB << 1)) << 8; + priv->mpl115a_pressure |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_PADC_LSB << 1)); + priv->mpl115a_pressure >>= 6; /* Padc is 10bit unsigned */ + + sndbg("Pressure = %d\n", priv->mpl115a_pressure); + + priv->mpl115a_temperature = mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_TADC_MSB << 1)) << 8; + priv->mpl115a_temperature |= mpl115a_getreg8(priv, MPL115A_BASE_CMD | (MPL115A_TADC_LSB << 1)); + priv->mpl115a_temperature >>= 6; /* Tadc is 10bit unsigned */ + + sndbg("Temperature = %d\n", priv->mpl115a_temperature); +} + +/**************************************************************************** + * Name: mpl115a_getpressure + * + * Description: + * Calculate the Barometrc Pressure using the temperature compensated + * See Freescale AN3785 and MPL115A1 datasheet for details + * + ****************************************************************************/ + +static int mpl115a_getpressure(FAR struct mpl115a_dev_s *priv) +{ + int32_t c12x2, a1, a1x1, y1, a2x2, pcomp; + uint16_t padc, tadc, pressure; + + /* Check if coefficient data were read correctly */ + if ( (priv->mpl115a_cal_a0 == 0) || (priv->mpl115a_cal_b1 == 0) || + (priv->mpl115a_cal_b2 == 0) || (priv->mpl115a_cal_c12 == 0) ) + { + mpl115a_updatecaldata(priv); + } + + /* Read temperature and pressure */ + mpl115a_read_press_temp(priv); + padc = priv->mpl115a_pressure; + tadc = priv->mpl115a_temperature; + + /* These code are from Freescale AN3785 */ + c12x2 = ((int32_t)priv->mpl115a_cal_c12 * tadc) >> 11; + a1 = (int32_t) (priv->mpl115a_cal_b1 + c12x2); + a1x1 = a1 * padc; + y1 = (((int32_t)priv->mpl115a_cal_a0) << 10) + a1x1; + a2x2 = (((int32_t)priv->mpl115a_cal_b2) * tadc) >> 1; + pcomp = (y1 + a2x2) >> 9; + + /* Calculate the pressure in 1/16 kPa from compensated */ + pressure = (((((int32_t)pcomp) * 1041) >> 14) + 800); + + /* Note that the final pressure value is reported with 4 bit fractional + * This may be eliminated by right shifting the result 4 bits. + */ + sndbg("Final Pressure = %d\n", pressure >> 4); + return pressure; +} + +/**************************************************************************** + * Name: mpl115a_open + * + * Description: + * This function is called whenever the MPL115A1 device is opened. + * + ****************************************************************************/ + +static int mpl115a_open(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: mpl115a_close + * + * Description: + * This routine is called when the LM-75 device is closed. + * + ****************************************************************************/ + +static int mpl115a_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: mpl115a_read + ****************************************************************************/ + +static ssize_t mpl115a_read(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct mpl115a_dev_s *priv = inode->i_private; + FAR uint16_t *press = (FAR uint16_t *) buffer; + + if (!buffer) + { + sndbg("Buffer is null\n"); + return -1; + } + + if ( buflen != 2) + { + sndbg("You can't read something other than 16 bits (2 bytes)\n"); + return -1; + } + + /* Get the pressure compensated */ + *press = mpl115a_getpressure(priv); + + /* Return size of uint16_t (2 bytes) */ + return 2; +} + +/**************************************************************************** + * Name: mpl115a_write + ****************************************************************************/ + +static ssize_t mpl115a_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpl115a_register + * + * Description: + * Register the MPL115A character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/temp0" + * i2c - An instance of the I2C interface to use to communicate with MPL115A + * addr - The I2C address of the LM-75. The base I2C address of the MPL115A + * is 0x48. Bits 0-3 can be controlled to get 8 unique addresses from 0x48 + * through 0x4f. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int mpl115a_register(FAR const char *devpath, FAR struct spi_dev_s *spi) +{ + FAR struct mpl115a_dev_s *priv; + int ret; + + /* Initialize the MPL115A device structure */ + + priv = (FAR struct mpl115a_dev_s *)kmm_malloc(sizeof(struct mpl115a_dev_s)); + if (!priv) + { + sndbg("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->spi = spi; + priv->mpl115a_cal_a0 = 0; + priv->mpl115a_cal_b1 = 0; + priv->mpl115a_cal_b2 = 0; + priv->mpl115a_cal_c12 = 0; + + /* Read the coefficient value */ + mpl115a_updatecaldata(priv); + + /* Register the character driver */ + + ret = register_driver(devpath, &g_mpl115afops, 0666, priv); + if (ret < 0) + { + sndbg("Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + return ret; +} +#endif /* CONFIG_SPI && CONFIG_MPL115A */ diff --git a/nuttx/include/nuttx/sensors/mpl115a.h b/nuttx/include/nuttx/sensors/mpl115a.h new file mode 100644 index 000000000..c1f01ba70 --- /dev/null +++ b/nuttx/include/nuttx/sensors/mpl115a.h @@ -0,0 +1,120 @@ +/******************************************************************************************** + * drivers/sensors/mpl115a.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_MPL115A_H +#define __DRIVERS_SENSORS_MPL115A_H + +#if defined(CONFIG_MPL115A) + +/******************************************************************************************** + * Pre-Processor Definitions + ********************************************************************************************/ +/* Configuration ****************************************************************************/ +/* Prerequisites: + * + * CONFIG_SENSORS_MPL115A + * Enables support for the MPL115A driver + * CONFIG_MPL115A_REGDEBUG + * Enable very low register-level debug output. Requires CONFIG_DEBUG. + */ + +/* There are two types of MPL115A chips. The MPL115A1 communicates with the target CPU + * via a SPI interface. The MPL115A2 communicates via I2C interface. + * Note: This driver only supports MPL115A1 (SPI Interface). + */ + +/* SPI **************************************************************************************/ +/* The device always operates in mode 0 */ + +#define MPL115A_SPI_MODE SPIDEV_MODE0 /* Mode 0 */ + +/* SPI frequency */ + +#define MPL115A_SPI_MAXFREQUENCY 800000 /* 8MHz */ + +/* MPL115A Registers ************************************************************************/ +/* Register Addresses */ + +#define MPL115A_BASE_CMD 0x80 +#define MPL115A_PADC_MSB 0x00 /* 10-bit Pressure ADC output value MSB */ +#define MPL115A_PADC_LSB 0x01 /* 10-bit Pressure ADC output value LSB */ +#define MPL115A_TADC_MSB 0x02 /* 10-bit Temperature ADC output value MSB */ +#define MPL115A_TADC_LSB 0x03 /* 10-bit Temperature ADC output value LSB */ +#define MPL115A_A0_MSB 0x04 /* a0 coefficient MSB */ +#define MPL115A_A0_LSB 0x05 /* a0 coefficient LSB */ +#define MPL115A_B1_MSB 0x06 /* b1 coefficient MSB */ +#define MPL115A_B1_LSB 0x07 /* b1 coefficient LSB */ +#define MPL115A_B2_MSB 0x08 /* b2 coefficient MSB */ +#define MPL115A_B2_LSB 0x09 /* b2 coefficient LSB */ +#define MPL115A_C12_MSB 0x0A /* c12 coefficient MSB */ +#define MPL115A_C12_LSB 0x0B /* c12 coefficient LSB */ + /* 0x0C - 0x11 are reserved */ +#define MPL115A_CONVERT 0x12 /* Start Pressure and Temperature Conversion */ + +/******************************************************************************************** + * Public Function Prototypes + ********************************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mpl115a_register + * + * Description: + * Register the MPL115A character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/temp0" + * spi - An instance of the SPI interface to use to communicate with MPL115A + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +EXTERN int mpl115a_register(FAR const char *devpath, FAR struct spi_dev_s *spi); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_SENSORS_MPL115A */ +#endif /* __DRIVERS_SENSORS_MPL115A_H */ -- cgit v1.2.3