From 63dcc18c55b172c4312b88f3483f5bbb995f302a Mon Sep 17 00:00:00 2001 From: Juan Carrano <j.carrano@fu-berlin.de> Date: Mon, 10 Sep 2018 14:13:52 +0200 Subject: [PATCH] drivers/tsl4531x: Add driver for TSL45315 illuiminance sensor. Missing run modes and power saving configurations, but otherwise functional. --- drivers/Makefile.dep | 4 + drivers/include/tsl4531x.h | 60 +++++++++++++ drivers/tsl4531x/Makefile | 3 + drivers/tsl4531x/tsl4531x.c | 140 +++++++++++++++++++++++++++++++ drivers/tsl4531x/tsl4531x_saul.c | 41 +++++++++ 5 files changed, 248 insertions(+) create mode 100644 drivers/include/tsl4531x.h create mode 100644 drivers/tsl4531x/Makefile create mode 100644 drivers/tsl4531x/tsl4531x.c create mode 100644 drivers/tsl4531x/tsl4531x_saul.c diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 6a3de6c93d..12ff91b964 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -475,3 +475,7 @@ ifneq (,$(filter xbee,$(USEMODULE))) USEMODULE += xtimer USEMODULE += netif endif + +ifneq (,$(filter tsl4531x,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c +endif diff --git a/drivers/include/tsl4531x.h b/drivers/include/tsl4531x.h new file mode 100644 index 0000000000..2bcd4b6a42 --- /dev/null +++ b/drivers/include/tsl4531x.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 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 drivers_tsl4531x TSL4531x Illuminance sensor + * @ingroup drivers_sensors + * @brief Device driver for the AMS TSL4531 sensor + * @{ + * + * @file + * @brief Device driver for the AMS TSL4531 sensor + * + * @author Juan I Carrano <j.carrano@fu-berlin.de> + */ + +#ifndef TSL4531x_H +#define TSL4531x_H + +#include <stdint.h> + +#include "periph/i2c.h" + +static const uint16_t TSL4531x_INTEGRATE_400ms = 0; /* 0b00 */ +static const uint16_t TSL4531x_INTEGRATE_200ms = 1; /* 0b01 */ +static const uint16_t TSL4531x_INTEGRATE_100ms = 2; /* 0b10 */ + +/** + * @brief Represents a single TSL4531x device. + */ +typedef struct tsl4531x { + i2c_t i2c_dev; + uint8_t integration_time; +} tsl4531x_t; + +/** + * Initialize TSL4513 device. + * + * @param dev Device object. + * @param i2c_dev I2C interface to use. + * @param integration_time one of TSL4531x_INTEGRATE_400ms, + * TSL4531x_INTEGRATE_200ms, TSL4531x_INTEGRATE_100ms. + * + * @return Zero on success, negative on error. + */ +int tsl4531x_init(tsl4531x_t *dev, i2c_t i2c_dev, uint8_t integration_time); + +/** + * Get the last measurements of illuminance, in lux. + * + * @return 0 on sucess, negative on error. If there is an error, the value of + * `*result_lux` is undefined. + */ +int tsl4531x_read(const tsl4531x_t *dev, uint16_t *result_lux); + +#endif /* TSL4531x_H */ diff --git a/drivers/tsl4531x/Makefile b/drivers/tsl4531x/Makefile new file mode 100644 index 0000000000..2d6d86e78e --- /dev/null +++ b/drivers/tsl4531x/Makefile @@ -0,0 +1,3 @@ +MODULE = tsl4531x + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/tsl4531x/tsl4531x.c b/drivers/tsl4531x/tsl4531x.c new file mode 100644 index 0000000000..703982ad77 --- /dev/null +++ b/drivers/tsl4531x/tsl4531x.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2018 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 drivers_tsl4531x + * @{ + * + * @file + * @brief Device driver for the TSL4531 Luminosity sensor. + * + * @author Juan I Carrano <j.carrano@fu-berlin.de> + * + * This driver was derived from the one for TSL2561. + * + * @todo The i2c address is hardcoded + * @todo The only operating mode is "Normal Operation" + * @todo PowerSave is not supported + * + * @} + */ + +#include <errno.h> + +#include "log.h" +#include "tsl4531x.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static const uint16_t TSL4531_Addr = 0x29; +static const uint16_t TSL4531_PARTNO = 0xA; /* 0b1010 */ + +static const uint16_t Control_Reg = 0x0; +static const uint16_t Configuration_Reg = 0x01; +static const uint16_t ALSData1_Reg = 0x04; /* contains DATALOW */ +static const uint16_t ALSData2_Reg = 0x05; /* contains DATAHIGH */ +static const uint16_t ID_Reg = 0x0A; + +static const uint16_t TSL4531x_MODE_Normal = 0x03; /* 0b11 */ + +/* Assemble the Command register */ +#define TSL4531_COMMAND(addr) ((1<<7)|(addr)) + +/* Assemble the Configuration register */ +#define TSL4531_CONFIG(psaveskip, tcntrl) (((!!(psaveskip)) << 3) | (tcntrl)) + +/* Assemble the Control register */ +#define TSL4531_CONTROL(mode) (mode) + +#define TSL4531_GET_PARTNO(id_reg) ((id_reg) >> 4) + +/* Apply the multiplier corresponding to the active integration time */ +/* From the manual: + * MULTIPLIER = 1 for TCNTRL = 00 (Tint = 400 ms), + * MULTIPLIER = 2 for TCNTRL = 01 (Tint = 200 ms), and + * MULTIPLIER = 4 for TCNTRL = 10 (Tint = 100 ms), and + */ +#define MULTIPLY_DATA(data_raw, integration_time) ((data_raw) << (integration_time)) + +int tsl4531x_init(tsl4531x_t *dev, i2c_t i2c_dev, uint8_t integration_time) +{ + int r; + uint8_t id; + + dev->i2c_dev = i2c_dev; + dev->integration_time = integration_time; + + if ((r = i2c_acquire(dev->i2c_dev)) < 0) { + DEBUG("[Error] Cannot acquire device: %d\n", r); + goto acquire_error; + } + + /* Verify sensor ID */ + if ((r = i2c_read_reg(dev->i2c_dev, TSL4531_Addr, TSL4531_COMMAND(ID_Reg), + &id, 0)) < 0) { + DEBUG("[Error] Cannot read ID register: %d\n", r); + goto init_error; + } + DEBUG("[Info] ID ? %d\n", id); + if (TSL4531_GET_PARTNO(id) != TSL4531_PARTNO) { + DEBUG("[Error] not a TSL4531 sensor\n"); + r = -ENOTSUP; + goto init_error; + } + + /* configure device */ + if (((r = i2c_write_reg(dev->i2c_dev , TSL4531_Addr, TSL4531_COMMAND(Control_Reg), + TSL4531_CONTROL(TSL4531x_MODE_Normal), 0)) < 0) + || + ((r = i2c_write_reg(dev->i2c_dev , TSL4531_Addr, TSL4531_COMMAND(Configuration_Reg), + TSL4531_CONFIG(1, integration_time), 0)) < 0)) { + DEBUG("[Error] Cannot configure device %d\n", r); + goto init_error; + } + +init_error: + /* ignore errors on device release */ + i2c_release(dev->i2c_dev); + +acquire_error: + + return r; +} + +#define _DATALOW 0 +#define _DATAHIGH 1 + +int tsl4531x_read(const tsl4531x_t *dev, uint16_t *result_lux) +{ + int r; + uint8_t als_data[2]; /* = {[DATALOW], [DATAHIGH]} */ + + if ((r = i2c_acquire(dev->i2c_dev)) < 0) { + DEBUG("[Error] Cannot acquire device: %d\n", r); + goto read_acquire_error; + } + + if ((r = i2c_read_regs(dev->i2c_dev, TSL4531_Addr, TSL4531_COMMAND(ALSData1_Reg), + als_data, 2, 0)) < 0) { + (void)ALSData2_Reg; /* suppress warning */ + DEBUG("[Error] Cannot read device: %d\n", r); + goto read_error; + } + + *result_lux = MULTIPLY_DATA((((uint16_t)als_data[_DATAHIGH]) << 8) + + als_data[_DATALOW], dev->integration_time); + +read_error: + /* ignore errors on device release */ + i2c_release(dev->i2c_dev); + +read_acquire_error: + return r; +} + diff --git a/drivers/tsl4531x/tsl4531x_saul.c b/drivers/tsl4531x/tsl4531x_saul.c new file mode 100644 index 0000000000..f040beb25a --- /dev/null +++ b/drivers/tsl4531x/tsl4531x_saul.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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 drivers_tsl4531x + * @{ + * + * @file + * @brief SAUL interface for TSL4531 Luminosity sensor. + * + * @author Juan I Carrano <j.carrano@fu-berlin.de> + * + * @} + */ + +#include "saul.h" +#include "tsl4531x.h" + +static int _read(const void *dev, phydat_t *res) +{ + int nvals; + uint16_t lux; + + nvals = (tsl4531x_read(dev, &lux) >= 0)? 1 : 0; + + res->val[0] = lux; + res->unit = UNIT_LUX; + res->scale = 0; + return nvals; +} + +const saul_driver_t tsl2561_illuminance_saul_driver = { + .read = _read, + .write = saul_notsup, + .type = SAUL_SENSE_LIGHT +}; -- GitLab