From 75d6c4cee3297d99d4622f870609ef136e58b86a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 15 Jan 2016 07:25:58 -0600 Subject: [PATCH] drivers/sensors/mcp9844: Driver for the MCP9844 I2C digital temperature sensor with a selectable resolution --- ChangeLog | 3 + drivers/sensors/Kconfig | 7 + drivers/sensors/Make.defs | 4 + drivers/sensors/mcp9844.c | 352 ++++++++++++++++++++++++++++++++ include/nuttx/sensors/mcp9844.h | 128 ++++++++++++ 5 files changed, 494 insertions(+) create mode 100644 drivers/sensors/mcp9844.c create mode 100644 include/nuttx/sensors/mcp9844.h diff --git a/ChangeLog b/ChangeLog index 6dd11f68a3..1e9bbb3986 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11305,3 +11305,6 @@ (2016-01-10). * libc/netdb: Add support for the use of a DNS resolver file like /etc/resolv.conf (2016-01-14). + * drivers/sensors/mcp9844.c and include/nuttx/sensors/mcp9844.h: Driver + for the MCP9844 I2C digital temperature sensor with a selectable + resolution. From Entinger Alexander (2016-01-15). diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 80cdfcec0c..993cc41254 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -31,6 +31,13 @@ config MB7040 ---help--- Enable driver support for the MaxBotix MB7040 sonar. +config MCP9844 + bool "MCP9844 Temperature Sensor" + default n + select I2C + ---help--- + Enable driver support for the MCP9844 I2C Temperature sensor. + config MS58XX bool "MEAS MS58XX Altimeter support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index a1c5c69a54..e4d38ca075 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -73,6 +73,10 @@ ifeq ($(CONFIG_MB7040),y) CSRCS += mb7040.c endif +ifeq ($(CONFIG_MCP9844),y) + CSRCS += mcp9844.c +endif + ifeq ($(CONFIG_MS58XX),y) CSRCS += ms58xx.c endif diff --git a/drivers/sensors/mcp9844.c b/drivers/sensors/mcp9844.c new file mode 100644 index 0000000000..68a5091ce3 --- /dev/null +++ b/drivers/sensors/mcp9844.c @@ -0,0 +1,352 @@ +/**************************************************************************** + * drivers/sensors/mcp9844.c + * Character driver for the MCP9844 Temperature Sensor + * + * Copyright (C) 2015 DS-Automotion GmbH. All rights reserved. + * Author: Alexander Entinger + * + * 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 + +#if defined(CONFIG_I2C) && defined(CONFIG_MCP9844) + +/**************************************************************************** + * Private + ****************************************************************************/ + +struct mcp9844_dev_s +{ + FAR struct i2c_dev_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C helper functions */ + +static int mcp9844_read_u16(FAR struct mcp9844_dev_s *priv, + uint8_t const regaddr, FAR uint16_t *value); +static int mcp9844_write_u16(FAR struct mcp9844_dev_s *priv, + uint8_t const regaddr, uint16_t const regval); + +/* Character driver methods */ + +static int mcp9844_open(FAR struct file *filep); +static int mcp9844_close(FAR struct file *filep); +static ssize_t mcp9844_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t mcp9844_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int mcp9844_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_mcp9844_fops = +{ + mcp9844_open, + mcp9844_close, + mcp9844_read, + mcp9844_write, + NULL, + mcp9844_ioctl +#ifndef CONFIG_DISABLE_POLL + , NULL +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mcp9844_read_u16 + * + * Description: + * Read a 16 bit valie from the MCP9844 at the address regaddr. + * + ****************************************************************************/ + +static int mcp9844_read_u16(FAR struct mcp9844_dev_s *priv, + uint8_t const regaddr, FAR uint16_t *value) +{ + int ret = -1; + + /* Write the register address */ + + I2C_SETADDRESS(priv->i2c, priv->addr, 7); + + ret = I2C_WRITE(priv->i2c, ®addr, 1); + if (ret < 0) + { + sndbg ("I2C_WRITE failed: %d\n", ret); + return ret; + } + + /* Restart and read 16-bits from the register */ + + uint8_t const BUFFER_SIZE = 2; + uint8_t buffer[BUFFER_SIZE]; + ret = I2C_READ(priv->i2c, buffer, BUFFER_SIZE); + if (ret < 0) + { + sndbg ("I2C_READ failed: %d\n", ret); + return ret; + } + + /* Copy the content of the buffer to the location of the uint16_t pointer */ + + *value = (((uint16_t)(buffer[0]))<<8) + ((uint16_t)(buffer[1])); + + sndbg("addr: %02x value: %08x ret: %d\n", regaddr, *value, ret); + + return OK; +} + +/**************************************************************************** + * Name: mcp9844_write_u16 + * + * Description: + * Write to a 16-bit register of the MCP9844. + * + ****************************************************************************/ + +static int mcp9844_write_u16(FAR struct mcp9844_dev_s *priv, + uint8_t const regaddr, uint16_t const regval) +{ + sndbg("addr: %02x value: %08x\n", regaddr, regval); + + /* Set up a 3 byte message to send */ + + uint8_t const BUFFER_SIZE = 3; + uint8_t buffer[BUFFER_SIZE]; + + buffer[0] = regaddr; + buffer[1] = (uint8_t)(regval >> 8); + buffer[2] = (uint8_t)(regval); + + /* Write the register address followed by the data (no RESTART) */ + + I2C_SETADDRESS(priv->i2c, priv->addr, 7); + + return I2C_WRITE(priv->i2c, buffer, BUFFER_SIZE); +} + +/**************************************************************************** + * Name: mcp9844_open + * + * Description: + * This function is called whenever the MCP9844 device is opened. + * + ****************************************************************************/ + +static int mcp9844_open(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: mcp9844_close + * + * Description: + * This routine is called when the MCP9844 device is closed. + * + ****************************************************************************/ + +static int mcp9844_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: mcp9844_read + ****************************************************************************/ + +static ssize_t mcp9844_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: mcp9844_write + ****************************************************************************/ + +static ssize_t mcp9844_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lm75_ioctl + ****************************************************************************/ + +static int mcp9844_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct mcp9844_dev_s *priv = inode->i_private; + int ret = OK; + + switch (cmd) + { + /* Read from the ambient temperature register. Arg: uint16_t* pointer */ + + case SNIOC_READTEMP: + { + FAR struct mcp9844_temp_arg_s *temp_result = + (FAR struct mcp9844_temp_arg_s *)((uintptr_t)arg); + + DEBUGASSERT(temp_result != NULL); + + /* Read the ambient temperature value from the device */ + + uint16_t raw_temperature = 0; + ret = mcp9844_read_u16(priv, MCP9844_TEMP_REG, &raw_temperature); + + /* Convert from the proprietary sensor temperature data representation + * to a more user friendly version. + */ + + if (ret == OK) + { + /* BIT15 - 13 contain information if preset temperature values + * have been exceeded or undercut. BIT12 is now not any longer + * needed since we do have the sign information retrieved. + * We do not need them for the temperature so those bits + * need to be masked out. + */ + + raw_temperature &= 0x0FFF; /* 0x0FFF = 0b 0000 1111 1111 1111 */ + + /* The post comma temperature value is encoded in BIT3 to BIT0 */ + + temp_result->temp_post_comma = (uint8_t)(raw_temperature & 0x000F); + + /* The pre comma temperature value is encoded in BIT11 to BIT4 */ + + temp_result->temp_pre_comma = (int8_t)(raw_temperature >> 4); + } + else + { + sndbg("ioctl::SNIOC_READTEMP - mcp9844_read_u16 failed - no temperature retrieved\n"); + } + } + break; + + case SNIOC_SETRESOLUTION: + { + ret = mcp9844_write_u16(priv, MCP9844_RESO_REG, (uint16_t)(arg)); + if (ret != OK) + { + sndbg("ioctl::SNIOC_SETRESOLUTION - mcp9844_write_u16 failed - no resolution set\n"); + } + } + break; + + default: + sndbg("Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mcp9844_register + * + * Description: + * Register the MCP9844 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 MCP9844 + * addr - The I2C address of the MCP9844. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int mcp9844_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr) +{ + /* Sanity check */ + + DEBUGASSERT(i2c != NULL); + + /* Initialize the LM-75 device structure */ + + FAR struct mcp9844_dev_s *priv = + (FAR struct mcp9844_dev_s *)kmm_malloc(sizeof(struct mcp9844_dev_s)); + + if (priv == NULL) + { + sndbg("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + + /* Register the character driver */ + + int ret = register_driver(devpath, &g_mcp9844_fops, 0666, priv); + if (ret < 0) + { + sndbg("Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + return ret; +} +#endif /* CONFIG_I2C && CONFIG_I2C_LM75 */ diff --git a/include/nuttx/sensors/mcp9844.h b/include/nuttx/sensors/mcp9844.h new file mode 100644 index 0000000000..68276b8487 --- /dev/null +++ b/include/nuttx/sensors/mcp9844.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * include/nuttx/sensors/mcp9844.h + * + * Copyright (C) 2016, DS-Automotion GmbH. All rights reserved. + * Author: Alexander Entinger + * + * 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 __NUTTX_INCLUDE_NUTTX_SENSORS_MCP9844_H +#define __NUTTX_INCLUDE_NUTTX_SENSORS_MCP9844_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_MCP9844) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IOCTL Commands ***********************************************************/ + +#define SNIOC_READTEMP _SNIOC(0x0001) /* Arg: mcp9844_temp_arg_s* pointer */ +#define SNIOC_SETRESOLUTION _SNIOC(0x0002) /* Arg: uint16_t value */ + +/* MCP9844 Register Definitions *********************************************/ + +/* MCP9844 Registers addresses */ + +#define MCP9844_CAPA_REG (0x00) /* Sensor Capability Register */ +#define MCP9844_CONF_REG (0x01) /* Sensor Configuration Register */ +#define MCP9844_TEMP_REG (0x05) /* Sensor Temperature Register */ +#define MCP9844_RESO_REG (0x09) /* Register to control the resolution of the temperature sensor */ + +/* Resolution Register Bit definitions */ + +#define MCP9844_RESO_REG_BIT_0 (1<<0) +#define MCP9844_RESO_REG_BIT_1 (1<<1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct mcp9844_temp_arg_s +{ + int8_t temp_pre_comma; + uint8_t temp_post_comma; +}; + +enum mcp9844_resolution_e +{ + RES_0_5 = 0, + RES_0_25 = MCP9844_RESO_REG_BIT_0, + RES_0_125 = MCP9844_RESO_REG_BIT_1, + RES_0_0625 = MCP9844_RESO_REG_BIT_1 | MCP9844_RESO_REG_BIT_0 +}; + +struct i2c_dev_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mcp9844_register + * + * Description: + * Register the MCP9844 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 MCP9844 + * addr - The I2C address of the MCP9844. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int mcp9844_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_MCP9844 */ +#endif /* __NUTTX_INCLUDE_NUTTX_SENSORS_MCP9844_H */