diff --git a/boards/iot-lab_M3/include/board.h b/boards/iot-lab_M3/include/board.h index 15cf1f8062..9a42c811d9 100644 --- a/boards/iot-lab_M3/include/board.h +++ b/boards/iot-lab_M3/include/board.h @@ -30,7 +30,7 @@ #include "periph_conf.h" /** - * Define the nominal CPU core clock in this board + * @name Define the nominal CPU core clock in this board */ #define F_CPU CLOCK_CORECLOCK @@ -44,9 +44,11 @@ /** @} */ /** - * Assign the hardware timer + * @name Assign the hardware timer + * @{ */ #define HW_TIMER TIMER_0 +/** @} */ /** * @name Define the interface to the AT86RF231 radio @@ -59,6 +61,14 @@ #define AT86RF231_SLEEP GPIO_14 /** @} */ +/** + * @name Define the interface to the ISL29020 light sensor + * @{ + */ +#define ISL29020_I2C I2C_0 +#define ISL29020_ADDR 0x44 +/** @} */ + /** * @name LED pin definitions * @{ diff --git a/drivers/Makefile b/drivers/Makefile index c88c956ddc..344f25da2b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,5 +43,8 @@ endif ifneq (,$(filter netdev_base,$(USEMODULE))) DIRS += netdev/base endif +ifneq (,$(filter isl29020,$(USEMODULE))) + DIRS += isl29020 +endif include $(RIOTBASE)/Makefile.base diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 49e12e4ee6..7ffcd24fa8 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -10,3 +10,6 @@ endif ifneq (,$(filter at86rf231,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at86rf231/include endif +ifneq (,$(filter isl29020,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29020/include +endif diff --git a/drivers/include/isl29020.h b/drivers/include/isl29020.h new file mode 100644 index 0000000000..92ba76284b --- /dev/null +++ b/drivers/include/isl29020.h @@ -0,0 +1,105 @@ +/* + * 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_isl29020 ISL29020 light sensor + * @ingroup drivers + * @brief Device driver for the ISL29020 light sensor + * @{ + * + * @file + * @brief Device driver interface for the ISL29020 light sensor + * + * @author Hauke Petersen + */ + +#ifndef __ISL29020_H +#define __ISL29020_H + +#include +#include "periph/i2c.h" + + /** + * @brief The sensors default I2C address + */ +#define ISL29020_DEFAULT_ADDRESS 0x44 + +/** + * @brief Device descriptor for ISL29020 sensors + */ +typedef struct { + i2c_t i2c; /**< I2C device the sensor is connected to */ + uint8_t address; /**< I2C bus address of the sensor */ + float lux_fac; /**< factor to calculate actual LUX value */ +} isl29020_t; + +/** + * @brief Possible modes for the ISR29020 sensor + */ +typedef enum { + ISL29020_MODE_AMBIENT = 0, /**< set sensor to detect ambient light */ + ISL29020_MODE_IR = 1 /**< set sensor to detect infrared light */ +} isl29020_mode_t; + +/** + * @brief Possible range values for the ISR29020 sensor + */ +typedef enum { + ISL29020_RANGE_1K = 0, /**< set range to 0-1000 LUX */ + ISL29020_RANGE_4K = 1, /**< set range to 0-4000 LUX */ + ISL29020_RANGE_16K = 2, /**< set range to 0-16000 LUX */ + ISL29020_RANGE_64K = 3 /**< set range to 0-64000 LUX */ +} isl29020_range_t; + +/** + * @brief Initialize a new ISL29020 device + * + * @param[in] dev device descriptor of an ISL29020 device + * @param[in] i2c I2C device the sensor is connected to + * @param[in] address I2C address of the sensor + * @param[in] range measurement range + * @param[in] mode configure if sensor reacts to ambient or infrared light + * + * @return 0 on success + * @return -1 on error + */ +int isl29020_init(isl29020_t *dev, i2c_t i2c, uint8_t address, + isl29020_range_t range, isl29020_mode_t mode); + +/** + * @brief Read a lighting value from the sensor, the result is given in LUX + * + * @param[in] dev device descriptor of an ISL29020 device + * + * @return the measured brightness in LUX + * @return -1 on error + */ +int isl29020_read(isl29020_t *dev); + +/** + * @brief Enable the given sensor + * + * @param[in] dev device descriptor of an ISL29020 device + * + * @return 0 on success + * @return -1 on error + */ +int isl29020_enable(isl29020_t *dev); + +/** + * @brief Disable the given sensor + * + * @param[in] dev device descriptor of an ISL29020 device + * + * @return 0 on success + * @return -1 on error + */ +int isl29020_disable(isl29020_t *dev); + +#endif /* __ISL29020_H */ +/** @} */ diff --git a/drivers/isl29020/Makefile b/drivers/isl29020/Makefile new file mode 100644 index 0000000000..a885f8360a --- /dev/null +++ b/drivers/isl29020/Makefile @@ -0,0 +1,3 @@ +MODULE = isl29020 + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/isl29020/include/isl29020-internal.h b/drivers/isl29020/include/isl29020-internal.h new file mode 100644 index 0000000000..dc3cfa21a0 --- /dev/null +++ b/drivers/isl29020/include/isl29020-internal.h @@ -0,0 +1,65 @@ +/* + * 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_isl29020 + * @{ + * + * @file + * @brief Definitions for the ISL29020 light sensor + * + * @author Hauke Petersen + */ + +#ifndef __ISL29020_INTERNAL_H +#define __ISL29020_INTERNAL_H + +/** + * @name ISL29020 registers + * @{ + */ +#define ISL29020_REG_CMD 0x00 +#define ISL29020_REG_LDATA 0x01 +#define ISL29020_REG_HDATA 0x02 +/** @} */ + +/** + * @name Masks for the ISL29020 command register + * @{ + */ +#define ISL29020_CMD_EN 0x80 +#define ISL29020_CMD_MODE 0x40 +#define ISL29020_CMD_LIGHT 0x20 +#define ISL29020_CMD_RES 0x1c +#define ISL29020_CMD_RAGNE 0x03 +/** @} */ + +/** + * @name Resolution options + * @{ + */ +#define ISL29020_RES_INT_16 0x00 +#define ISL29020_RES_INT_12 0x04 +#define ISL29020_RES_INT_8 0x08 +#define ISL29020_RES_INT_4 0x0c +#define ISL29020_RES_EXT_ADC 0x10 +#define ISL29020_RES_EXT_TIM 0x14 +/** @} */ + +/** + * @name Range options + * @{ + */ +#define ISL29020_RANGE_1 0x00 +#define ISL29020_RANGE_2 0x01 +#define ISL29020_RANGE_3 0x02 +#define ISL29020_RANGE_4 0x03 +/** @} */ + +#endif /* __ISL29020_INTERNAL_H */ +/** @} */ diff --git a/drivers/isl29020/isl29020.c b/drivers/isl29020/isl29020.c new file mode 100644 index 0000000000..1ff16913a6 --- /dev/null +++ b/drivers/isl29020/isl29020.c @@ -0,0 +1,100 @@ +/* + * 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_isl29020 + * @{ + * + * @file + * @brief Device driver implementation for the ISL29020 light sensor + * + * @author Hauke Petersen + * + * @} + */ + +#include "isl29020.h" +#include "isl29020-internal.h" +#include "periph/i2c.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +int isl29020_init(isl29020_t *dev, i2c_t i2c, uint8_t address, + isl29020_range_t range, isl29020_mode_t mode) +{ + int res; + char tmp; + + /* initialize device descriptor */ + dev->i2c = i2c; + dev->address = address; + dev->lux_fac = (float)((1 << (10 + (2 * range))) - 1) / 0xffff; + + /* initialize the I2C bus */ + i2c_init_master(i2c, I2C_SPEED_NORMAL); + + /* configure and enable the sensor */ + tmp = ISL29020_CMD_EN | ISL29020_CMD_MODE | ISL29020_RES_INT_16 | range | (mode << 5); + res = i2c_write_reg(dev->i2c, address, ISL29020_REG_CMD, tmp); + if (res < 1) { + return -1; + } + return 0; +} + +int isl29020_read(isl29020_t *dev) +{ + char low, high; + uint16_t res; + + /* read lightning value */ + res = i2c_read_reg(dev->i2c, dev->address, ISL29020_REG_LDATA, &low); + res += i2c_read_reg(dev->i2c, dev->address, ISL29020_REG_HDATA, &high); + if (res < 2) { + return -1; + } + res = (high << 8) | low; + DEBUG("ISL29020: Raw value: %i - high: %i, low: %i\n", res, high, low); + /* calculate and return actually LUX value */ + return (int)(dev->lux_fac * res); +} + +int isl29020_enable(isl29020_t *dev) +{ + int res; + char tmp; + + res = i2c_read_reg(dev->i2c, dev->address, ISL29020_REG_CMD, &tmp); + if (res < 1) { + return -1; + } + tmp |= ISL29020_CMD_EN; + res = i2c_write_reg(dev->i2c, dev->address, ISL29020_REG_CMD, tmp); + if (res < 1) { + return -1; + } + return 0; +} + +int isl29020_disable(isl29020_t *dev) +{ + int res; + char tmp; + + res = i2c_read_reg(dev->i2c, dev->address, ISL29020_REG_CMD, &tmp); + if (res < 1) { + return -1; + } + tmp &= ~(ISL29020_CMD_EN); + res = i2c_write_reg(dev->i2c, dev->address, ISL29020_REG_CMD, tmp); + if (res < 1) { + return -1; + } + return 0; +} diff --git a/tests/driver_isl29020/Makefile b/tests/driver_isl29020/Makefile new file mode 100644 index 0000000000..2dd0aadc5f --- /dev/null +++ b/tests/driver_isl29020/Makefile @@ -0,0 +1,28 @@ +APPLICATION = driver_isl29020 +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_i2c + +# Define default pin mappings for some boards: +ifneq (,$(filter iot-lab_M3,$(BOARD))) + export TEST_ISL29020_ADDR = 68 + export TEST_ISL29020_I2C ?= I2C_0 +endif + +USEMODULE += isl29020 +USEMODULE += vtimer + +ifneq (,$(TEST_ISL29020_I2C)) + CFLAGS += -DTEST_ISL29020_I2C=$(TEST_ISL29020_I2C) +else + # set random default + CFLAGS += -DTEST_ISL29020_I2C=I2C_0 +endif +ifneq (,$(TEST_ISL29020_ADDR)) + CFLAGS += -DTEST_ISL29020_ADDR=$(TEST_ISL29020_ADDR) +else + # set random default + CFLAGS += -DTEST_ISL29020_ADDR=68 +endif + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_isl29020/README.md b/tests/driver_isl29020/README.md new file mode 100644 index 0000000000..ad4c7c79bb --- /dev/null +++ b/tests/driver_isl29020/README.md @@ -0,0 +1,12 @@ +# About +This is a manual test application for the ISL29020 light sensor driver. + +# Usage +This test application will initialize the list sensor with the following parameters: + - Mode: Ambient light measurement + - Range: 16000LUX + +After initialization, the sensor value is read every 250ms and printed to the STDOUT. + +To verify the seen value you can hold the sensor into a bright light or shield the sensor to +see the value changing. diff --git a/tests/driver_isl29020/main.c b/tests/driver_isl29020/main.c new file mode 100644 index 0000000000..6b0bcca2a7 --- /dev/null +++ b/tests/driver_isl29020/main.c @@ -0,0 +1,59 @@ +/* + * 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 ISL29020 light sensor + * + * @author Hauke Petersen + * + * @} + */ + +#ifndef TEST_ISL29020_I2C +#error "TEST_ISL29020_I2C not defined" +#endif +#ifndef TEST_ISL29020_ADDR +#error "TEST_ISL29020_ADDR not defined" +#endif + +#include + +#include "vtimer.h" +#include "isl29020.h" + +#define MODE ISL29020_MODE_AMBIENT +#define RANGE ISL29020_RANGE_16K +#define SLEEP (250 * 1000U) + +int main(void) +{ + isl29020_t dev; + int value; + + puts("ISL29020 light sensor test application\n"); + printf("Initializing ISL29020 sensor at I2C_%i... ", TEST_ISL29020_I2C); + if (isl29020_init(&dev, TEST_ISL29020_I2C, TEST_ISL29020_ADDR, RANGE, MODE) == 0) { + puts("[OK]\n"); + } + else { + puts("[Failed]"); + return 1; + } + + while (1) { + value = isl29020_read(&dev); + printf("Light value: %5i LUX\n", value); + vtimer_usleep(SLEEP); + } + + return 0; +}