diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 25a18bd2c7..b7de874d66 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -19,6 +19,9 @@ endif ifneq (,$(filter isl29020,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29020/include endif +ifneq (,$(filter isl29125,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29125/include +endif ifneq (,$(filter lps331ap,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lps331ap/include endif diff --git a/drivers/include/isl29125.h b/drivers/include/isl29125.h new file mode 100644 index 0000000000..b4b2d40a2c --- /dev/null +++ b/drivers/include/isl29125.h @@ -0,0 +1,155 @@ +/* + * Copyright 2015 Ludwig Ortmann + * + * 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_isl29125 ISL29125 light sensor + * @ingroup drivers + * @brief Device driver for the ISL29125 RGB light sensor + * + * ## Description + * + * The device supports level conversion in 12, and 16 bit depth per + * channel. Selecting a higher precision results in a longer + * conversion time. + * + * The driver uses the @ref color_rgb_t color definition from @ref + * color.h for value representation. It does not depend on the color + * module however. + * + * ## Usage + * + * Examine `tests/driver_isr29125` for an exemplary application using + * this driver. + * + * ## Caveats + * + * A GPIO pin definition has been included in the interface for future + * compatibility only. + * - The driver does not support SYNC mode at the moment. + * - The driver supports polling only, i.e. interrupt mode is + * currently not supported. + * + * @{ + * + * @file + * @brief Device driver interface for the ISL29125 RGB light sensor + * + * @author Ludwig Ortmann + +#include "periph/i2c.h" +#include "periph/gpio.h" +#include "color.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief data type for storing lux RGB sensor readings + */ +typedef struct { + float red; /**< red lux value */ + float green; /**< green lux value */ + float blue; /**< blue lux value */ +} isl29125_rgb_t; + +/** + * @brief supported operation modes of the ISL29125 sensor's AD + * conversion + */ +typedef enum { + ISL29125_MODE_DOWN = 0x00, /**< ADC powered down */ + ISL29125_MODE_STANDBY = 0x04, /**< AD conversion not performed */ + ISL29125_MODE_RGB = 0x05, /**< RGB conversion */ + ISL29125_MODE_R = 0x02, /**< red conversion only */ + ISL29125_MODE_G = 0x01, /**< green conversion only */ + ISL29125_MODE_B = 0x03, /**< blue conversion only */ + ISL29125_MODE_RG = 0x06, /**< red and green conversion only */ + ISL29125_MODE_GB = 0x07 /**< green and blue conversion only */ +} isl29125_mode_t; + +/** + * @brief supported RGB sensing range values of the ISL29125 sensor + */ +typedef enum { + ISL29125_RANGE_375 = 0x00, /**< range: 5.7m - 375 lux */ + ISL29125_RANGE_10K = 0x08 /**< range: 0.152 - 10,000 lux */ +} isl29125_range_t; + +/** + * @brief supported color resolutions of the ISL29125 sensor's AD + * conversion + */ +typedef enum { + ISL29125_RESOLUTION_12 = 0x10, /**< resolution: 12 bit */ + ISL29125_RESOLUTION_16 = 0x00 /**< resolution: 16 bit */ +} isl29125_resolution_t; + +/** + * @brief Device descriptor for ISL29125 sensors + */ +typedef struct { + i2c_t i2c; /**< I2C device the sensor is connected to */ + gpio_t gpio; /**< GPIO pin for interrupt/sync mode */ + isl29125_range_t range; /**< sensor range */ + isl29125_resolution_t res; /**< sensor resolution */ +} isl29125_t; + +/** + * @brief initialize a new ISL29125 device + * + * @param[in] dev device descriptor of an ISL29125 device + * @param[in] i2c I2C device the sensor is connected to + * @param[in] gpio GPIO pin for interrupt/sync mode (currently unused) + * @param[in] mode operation mode + * @param[in] range measurement range + * @param[in] resolution AD conversion resolution + * + * @return 0 on success + * @return -1 on error + */ +int isl29125_init(isl29125_t *dev, i2c_t i2c, gpio_t gpio, + isl29125_mode_t mode, isl29125_range_t range, + isl29125_resolution_t resolution); + +/** + * @brief read RGB values from device + * + * @param[in] dev device descriptor of an ISL29125 device + * @param[in] dest pointer to lux RGB color object data is written to + */ +void isl29125_read_rgb_lux(isl29125_t *dev, isl29125_rgb_t *dest); + + /** + * @brief read color values from device + * + * @param[in] dev device descriptor of an ISL29125 device + * @param[in] dest pointer to RGB color object data is written to + */ +void isl29125_read_rgb_color(isl29125_t *dev, color_rgb_t *dest); + +/** + * @brief set the device's operation mode + * + * @param[in] dev device descriptor of an ISL29125 device + * @param[in] mode operation mode + */ +void isl29125_set_mode(isl29125_t *dev, isl29125_mode_t mode); + +#ifdef __cplusplus +} +#endif + +#endif /* ISL29125_H */ +/** @} */ diff --git a/drivers/isl29125/Makefile b/drivers/isl29125/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/isl29125/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/isl29125/include/isl29125-internal.h b/drivers/isl29125/include/isl29125-internal.h new file mode 100644 index 0000000000..b1c103ebf3 --- /dev/null +++ b/drivers/isl29125/include/isl29125-internal.h @@ -0,0 +1,93 @@ +/* + * Copyright 2015 Ludwig Ortmann + * + * 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_isl29125 + * @{ + * + * @file + * @brief Definitions for the ISL29125 RGB light sensor + * + * @author Ludwig Ortmann + */ + +#ifndef ISL29125_INTERNAL_H +#define ISL29125_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The sensors hard coded I2C address + */ +#define ISL29125_I2C_ADDRESS 0x44 + +/** + * @name ISL29125 constants + * @{ + */ +#define ISL29125_ID 0x7D +/** @} */ + +/** + * @name ISL29125 register map + * @{ + */ +/* main register */ +#define ISL29125_REG_ID 0x00 +#define ISL29125_REG_RESET 0x00 +/* configuration registers */ +#define ISL29125_REG_CONF1 0x01 +#define ISL29125_REG_CONF2 0x02 +#define ISL29125_REG_CONF3 0x03 +/* interrupt mode threshold registers */ +#define ISL29125_REG_LTHLB 0x04 +#define ISL29125_REG_LTHHB 0x05 +#define ISL29125_REG_HTHLB 0x06 +#define ISL29125_REG_HTHHB 0x07 +/* status register */ +#define ISL29125_REG_STATUS 0x08 +/* sensor readout registers (double buffered) */ +#define ISL29125_REG_GDLB 0x09 +#define ISL29125_REG_GDHB 0x0A +#define ISL29125_REG_RDLB 0x0B +#define ISL29125_REG_RDHB 0x0C +#define ISL29125_REG_BDLB 0x0D +#define ISL29125_REG_BDHB 0x0E +/** @} */ + +/** + * @name ISL29125 commands + * @{ + */ +#define ISL29125_CMD_RESET 0x46 +/** @} */ + +/** + * @name ISL29125 configuration masks and bits + * @{ + */ +/* ISL29125_REG_CONF1 B2:B0 */ +#define ISL29125_CON1_MASK_MODE 0x07 +/* ISL29125_REG_CONF1 B3 */ +#define ISL29125_CON1_MASK_RANGE 0x08 +/* ISL29125_REG_CONF1 B4 */ +#define ISL29125_CON1_MASK_RES 0x10 +/* ISL29125_REG_CONF1 B5 */ +#define ISL29125_CON1_MASK_SYNC 0x20 +#define ISL29125_CON1_SYNCOFF 0x00 +#define ISL29125_CON1_SYNCON 0x20 +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ISL29125_INTERNAL_H */ +/** @} */ diff --git a/drivers/isl29125/isl29125.c b/drivers/isl29125/isl29125.c new file mode 100644 index 0000000000..714b6a5508 --- /dev/null +++ b/drivers/isl29125/isl29125.c @@ -0,0 +1,155 @@ +/* + * Copyright 2015 Ludwig Ortmann + * + * 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_isl29125 + * @{ + * + * @file + * @brief Device driver implementation for the ISL29125 RGB light sensor + * + * @author Ludwig Ortmann + * + * @} + */ + +#include + +#include "isl29125.h" +#include "isl29125-internal.h" +#include "periph/i2c.h" +#include "periph/gpio.h" +#include "color.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/*********************************************************************** + * public API implementation + **********************************************************************/ + +int isl29125_init(isl29125_t *dev, i2c_t i2c, gpio_t gpio, + isl29125_mode_t mode, isl29125_range_t range, + isl29125_resolution_t resolution) +{ + DEBUG("isl29125_init\n"); + + /* initialize device descriptor */ + dev->i2c = i2c; + dev->res = resolution; + dev->range = range; + dev->gpio = gpio; + + /* configuration 1: operation mode, range, resolution */ + char conf1 = 0x00; + conf1 |= mode; + conf1 |= range; + conf1 |= resolution; + conf1 |= ISL29125_CON1_SYNCOFF; /* TODO: implement SYNC mode configuration */ + + /* TODO: implement configuration 2: infrared compensation configuration */ + + /* TODO: implement configuration 3: interrupt mode configuration */ + + /* acquire exclusive access to the bus */ + DEBUG("isl29125_init: i2c_acquire\n"); + (void) i2c_acquire(dev->i2c); + + /* initialize the I2C bus */ + DEBUG("isl29125_init: i2c_init_master\n"); + (void) i2c_init_master(i2c, I2C_SPEED_NORMAL); + + /* verify the device ID */ + DEBUG("isl29125_init: i2c_read_reg\n"); + char reg_id; + int ret = i2c_read_reg(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_ID, ®_id); + if ((reg_id == ISL29125_ID) && (ret == 1)) { + DEBUG("isl29125_init: ID successfully verified\n"); + } + else { + DEBUG("isl29125_init: ID could not be verified, ret: %i\n", ret); + (void) i2c_release(dev->i2c); + return -1; + } + + /* configure and enable the sensor */ + DEBUG("isl29125_init: i2c_write_reg(ISL29125_REG_RESET)\n"); + (void) i2c_write_reg(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_RESET, ISL29125_CMD_RESET); + + DEBUG("isl29125_init: i2c_write_reg(ISL29125_REG_CONF1)\n"); + (void) i2c_write_reg(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_CONF1, conf1); + + /* release the I2C bus */ + DEBUG("isl29125_init: i2c_release\n"); + (void) i2c_release(dev->i2c); + + DEBUG("isl29125_init: success\n"); + return 0; +} + +void isl29125_read_rgb_lux(isl29125_t *dev, isl29125_rgb_t *dest) +{ + /* acquire exclusive access to the bus */ + (void) i2c_acquire(dev->i2c); + + /* read values */ + char bytes[6]; + (void) i2c_read_regs(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_GDLB, bytes, 6); + + /* release the I2C bus */ + (void) i2c_release(dev->i2c); + + /* possibly shift by 4 to normalize 12 to 16 bit */ + int resfactor = (dev->res == ISL29125_RESOLUTION_12) ? 4 : 0; + /* parse and normalize readings */ + uint16_t green = (bytes[0] | (bytes[1] << 8)) << resfactor; + uint16_t red = (bytes[2] | (bytes[3] << 8)) << resfactor; + uint16_t blue = (bytes[4] | (bytes[5] << 8)) << resfactor; + + DEBUG("isl29125_read_rgb: adjusted, unconverted readings: (%5i / %5i / %5i) \n", red, green, blue); + + /* convert readings to lux */ + float luxfactor = (dev->range == ISL29125_RANGE_10K) ? 10000.0 / 65535.0 : 375.0 / 65535.0; + dest->red = red * luxfactor; + dest->green = green * luxfactor; + dest->blue = blue * luxfactor; +} + +void isl29125_read_rgb_color(isl29125_t *dev, color_rgb_t *dest) +{ + /* acquire exclusive access to the bus */ + (void) i2c_acquire(dev->i2c); + + /* read values */ + char bytes[6]; + (void) i2c_read_regs(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_GDLB, bytes, 6); + + /* release the I2C bus */ + (void) i2c_release(dev->i2c); + + /* factor normalize 12 or 16 bit to 8 bit */ + int normfactor = (dev->res == ISL29125_RESOLUTION_12) ? 4 : 8; + /* parse and normalize readings */ + dest->g = (bytes[0] | (bytes[1] << 8)) >> normfactor; + dest->r = (bytes[2] | (bytes[3] << 8)) >> normfactor; + dest->b = (bytes[4] | (bytes[5] << 8)) >> normfactor; +} + +void isl29125_set_mode(isl29125_t *dev, isl29125_mode_t mode) +{ + char conf1; + + (void) i2c_acquire(dev->i2c); + + (void) i2c_read_reg(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_CONF1, &conf1); + conf1 &= ~ISL29125_CON1_MASK_MODE; + conf1 |= mode; + (void) i2c_write_reg(dev->i2c, ISL29125_I2C_ADDRESS, ISL29125_REG_CONF1, conf1); + + (void) i2c_release(dev->i2c); +}