mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers/tsl4531x: Add power modes; redesign
Changes include: - Implementation of two power modes for the driver: low and high - Redesign and API change to the description in tsl4531x.h - Full documentation - Changing file structure and implementation to fit best practices as described in https://github.com/RIOT-OS/RIOT/wiki/Guide%3A-Writing-a-device-driver-in-RIOT - Including I2C addresses for the rest of the range
This commit is contained in:
parent
5604abcedc
commit
a1a834a726
@ -446,6 +446,11 @@ ifneq (,$(filter tsl2561,$(USEMODULE)))
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter tsl4531x,$(USEMODULE)))
|
||||||
|
FEATURES_REQUIRED += periph_i2c
|
||||||
|
USEMODULE += xtimer
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter uart_half_duplex,$(USEMODULE)))
|
ifneq (,$(filter uart_half_duplex,$(USEMODULE)))
|
||||||
FEATURES_REQUIRED += periph_gpio
|
FEATURES_REQUIRED += periph_gpio
|
||||||
FEATURES_REQUIRED += periph_uart
|
FEATURES_REQUIRED += periph_uart
|
||||||
@ -475,7 +480,3 @@ ifneq (,$(filter xbee,$(USEMODULE)))
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
USEMODULE += netif
|
USEMODULE += netif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter tsl4531x,$(USEMODULE)))
|
|
||||||
FEATURES_REQUIRED += periph_i2c
|
|
||||||
endif
|
|
||||||
|
@ -242,6 +242,10 @@ ifneq (,$(filter tsl2561,$(USEMODULE)))
|
|||||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tsl2561/include
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tsl2561/include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter tsl4531x,$(USEMODULE)))
|
||||||
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tsl4531x/include
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter uart_half_duplex,$(USEMODULE)))
|
ifneq (,$(filter uart_half_duplex,$(USEMODULE)))
|
||||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/uart_half_duplex/include
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/uart_half_duplex/include
|
||||||
endif
|
endif
|
||||||
|
@ -12,49 +12,184 @@
|
|||||||
* @brief Device driver for the AMS TSL4531 sensor
|
* @brief Device driver for the AMS TSL4531 sensor
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
|
* # Power modes
|
||||||
|
*
|
||||||
|
* This driver has two power modes: high and low. Its startup mode is configured
|
||||||
|
* in the initialization parameters, and it can also be changed during runtime.
|
||||||
|
*
|
||||||
|
* In high power mode, the user application can read from the device using the
|
||||||
|
* tsl4531x_simple_read function, and it will return immediately.
|
||||||
|
*
|
||||||
|
* In low power mode, the user application can interact with the driver in a
|
||||||
|
* synchronous or asynchronous manner. For synchronous operation, the application
|
||||||
|
* can call tsl4531x_simple_read, and the driver will block for the integration
|
||||||
|
* time defined in the initialization parameters (plus a small margin, to encompass
|
||||||
|
* the max times indicated in the datasheet). For asyncronous operation, the
|
||||||
|
* application needs to use the functions tsl4531x_start_sample,
|
||||||
|
* tsl4531x_time_until_sample_ready and tsl4531x_get_sample, as described in those
|
||||||
|
* functions' descriptions.
|
||||||
|
*
|
||||||
|
* Both modes will work through SAUL, with the low-power mode being synchronous.
|
||||||
|
*
|
||||||
* @file
|
* @file
|
||||||
* @brief Device driver for the AMS TSL4531 sensor
|
* @brief Device driver for the AMS TSL4531 sensor
|
||||||
*
|
*
|
||||||
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
||||||
|
* @author Daniel Petry <daniel.petry@fu-berlin.de>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TSL4531x_H
|
#ifndef TSL4531X_H
|
||||||
#define TSL4531x_H
|
#define TSL4531X_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "periph/i2c.h"
|
#include "periph/i2c.h"
|
||||||
|
|
||||||
static const uint16_t TSL4531x_INTEGRATE_400ms = 0; /* 0b00 */
|
#ifdef __cplusplus
|
||||||
static const uint16_t TSL4531x_INTEGRATE_200ms = 1; /* 0b01 */
|
extern "C" {
|
||||||
static const uint16_t TSL4531x_INTEGRATE_100ms = 2; /* 0b10 */
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents a single TSL4531x device.
|
* @brief Integration times
|
||||||
*/
|
*/
|
||||||
typedef struct tsl4531x {
|
typedef enum {
|
||||||
i2c_t i2c_dev;
|
TSL4531X_INTEGRATE_400MS = 0, /* 0b00 */
|
||||||
uint8_t integration_time;
|
TSL4531X_INTEGRATE_200MS = 1, /* 0b01 */
|
||||||
|
TSL4531X_INTEGRATE_100MS = 2, /* 0b10 */
|
||||||
|
}tsl4531x_intgn_time_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Fixed values for different members of the TSL4531x series
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @brief Part numbers
|
||||||
|
*/
|
||||||
|
#define TSL45311_PARTNO (0x8)
|
||||||
|
#define TSL45313_PARTNO (0x9)
|
||||||
|
#define TSL45315_PARTNO (0xA)
|
||||||
|
#define TSL45317_PARTNO (0xB)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TSL4531x I2C addresses
|
||||||
|
*/
|
||||||
|
#define TSL45311_ADDR (0x39)
|
||||||
|
#define TSL45313_ADDR (0x39)
|
||||||
|
#define TSL45315_ADDR (0x29)
|
||||||
|
#define TSL45317_ADDR (0x29)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
i2c_t i2c_dev; /**< I2C device which is used */
|
||||||
|
i2c_t i2c_addr; /**< I2C address of sensor */
|
||||||
|
tsl4531x_intgn_time_t integration_time; /**< integration time */
|
||||||
|
uint8_t low_power_mode : 1; /**< low power mode */
|
||||||
|
uint8_t part_number; /**< part number, according to variant */
|
||||||
|
} tsl4531x_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
i2c_t i2c_dev; /**< I2C device which is used */
|
||||||
|
i2c_t i2c_addr; /**< I2C address of sensor */
|
||||||
|
tsl4531x_intgn_time_t integration_time; /**< integration time */
|
||||||
|
uint8_t low_power_mode : 1; /**< low power mode */
|
||||||
|
uint8_t high_power_mode_started_up : 1; /**< high power mode started up flag */
|
||||||
|
uint32_t sample_start_time; /**< sample start time */
|
||||||
} tsl4531x_t;
|
} tsl4531x_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize TSL4513 device.
|
* Initialize the TSL4531x device.
|
||||||
*
|
*
|
||||||
* @param dev Device object.
|
* @param[out] dev Initialized device descriptor
|
||||||
* @param i2c_dev I2C interface to use.
|
* @param[in] params Device initialization parameters
|
||||||
* @param integration_time one of TSL4531x_INTEGRATE_400ms,
|
|
||||||
* TSL4531x_INTEGRATE_200ms, TSL4531x_INTEGRATE_100ms.
|
|
||||||
*
|
*
|
||||||
* @return Zero on success, negative on error.
|
* @return Zero on success
|
||||||
|
* @return -ENODEV if I2C bus can't be acquired
|
||||||
|
* @return -ENXIO if device can't be read or configured
|
||||||
|
* @return -ENOTSUP if ID, once read, is wrong
|
||||||
*/
|
*/
|
||||||
int tsl4531x_init(tsl4531x_t *dev, i2c_t i2c_dev, uint8_t integration_time);
|
int tsl4531x_init(tsl4531x_t *dev, const tsl4531x_params_t *params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the last measurements of illuminance, in lux.
|
* Set the low power mode of the driver on or off.
|
||||||
*
|
*
|
||||||
* @return 0 on sucess, negative on error. If there is an error, the value of
|
* @param dev Initialized device descriptor
|
||||||
* `*result_lux` is undefined.
|
* @param low_power_on Bool indicating whether low power mode is on or off
|
||||||
|
*
|
||||||
|
* @return Zero
|
||||||
*/
|
*/
|
||||||
int tsl4531x_read(const tsl4531x_t *dev, uint16_t *result_lux);
|
int tsl4531x_set_low_power_mode(tsl4531x_t *dev, uint8_t low_power_on);
|
||||||
|
|
||||||
#endif /* TSL4531x_H */
|
/**
|
||||||
|
* Start collecting sample in low power mode. This provides asynchronous operation
|
||||||
|
* along with tsl4531x_time_until_sample_ready and tsl4531x_get_sample. It does
|
||||||
|
* nothing in high power mode.
|
||||||
|
*
|
||||||
|
* @param dev Initialized device descriptor
|
||||||
|
*
|
||||||
|
* @return Zero
|
||||||
|
*/
|
||||||
|
int tsl4531x_start_sample(tsl4531x_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver time in microseconds until sample is ready, or zero if it is ready.
|
||||||
|
* In low power mode, this counts down from the point at which tsl4531x_start_sample
|
||||||
|
* is called, and along with that function and tsl4531x_get_sample, provides
|
||||||
|
* asynchronous operation. In high power mode, this counts down from the point
|
||||||
|
* at which the driver is switched into high power mode or started up, and
|
||||||
|
* indicates whether enough time has passed for a full sample to be collected.
|
||||||
|
*
|
||||||
|
* Note that for low power mode this rolls over and repeats its behaviour every
|
||||||
|
* 1.2 hours. The sample should have been collected well before this, however.
|
||||||
|
*
|
||||||
|
* The countdown time equals the integration time, which can be set in the
|
||||||
|
* device initialisation parameters, plus 5% margin to encompass the max times
|
||||||
|
* indicated in the datasheet.
|
||||||
|
*
|
||||||
|
* @param dev Initialized device descriptor
|
||||||
|
*
|
||||||
|
* @return Time in microseconds until sample is ready
|
||||||
|
*/
|
||||||
|
uint32_t tsl4531x_time_until_sample_ready(tsl4531x_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the sample from the device immediately. In high power mode, this does
|
||||||
|
* the same as tsl4531x_simple_read once the device has performed one
|
||||||
|
* integration cycle. In low power mode, this provides asynchronous operation
|
||||||
|
* along with tsl4531x_start_sample and tsl4531x_time_until_sample_ready which
|
||||||
|
* determine whether the device has performed an integration cycle.
|
||||||
|
*
|
||||||
|
* Note that this function will always return the value stored in the device's
|
||||||
|
* internal register, and this value will be sensible physically, representing
|
||||||
|
* the last time an integration cycle has been performed. However, in order for
|
||||||
|
* it to be accurate, the start_sample and time_until_sample_ready functions
|
||||||
|
* need to also be used, or alternatively the simple_read function can be used.
|
||||||
|
*
|
||||||
|
* @param dev Initialized device descriptor
|
||||||
|
*
|
||||||
|
* @return The sample value in Lux
|
||||||
|
*/
|
||||||
|
int tsl4531x_get_sample(const tsl4531x_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the sample from the device. In low power mode, or in high power mode
|
||||||
|
* just after startup, this starts collecting the sample, blocks until the
|
||||||
|
* sample is ready (400/200/100ms depending on the integration time set in the
|
||||||
|
* initialization parameters), and then reads and returns the sample.
|
||||||
|
*
|
||||||
|
* @param dev Initialized device descriptor
|
||||||
|
*
|
||||||
|
* @return The sample value in Lux
|
||||||
|
*/
|
||||||
|
int tsl4531x_simple_read(tsl4531x_t *dev);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TSL4531X_H */
|
||||||
|
/** @} */
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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>
|
|
||||||
*
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TSL4531x_SAUL_H
|
|
||||||
#define TSL4531x_SAUL_H
|
|
||||||
|
|
||||||
#include "saul.h"
|
|
||||||
|
|
||||||
/** SAUL-compatible structure for illuminance sensor
|
|
||||||
*/
|
|
||||||
const saul_driver_t tsl4531x_saul_driver;
|
|
||||||
|
|
||||||
#endif /* TSL4531x_SAUL_H */
|
|
||||||
|
|
105
drivers/tsl4531x/include/tsl4531x_internals.h
Normal file
105
drivers/tsl4531x/include/tsl4531x_internals.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Inria
|
||||||
|
* 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
|
||||||
|
* @brief Internal addresses, registers, constants for the TSL4531x sensor.
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Internal addresses, registers, constants for the TSL4531x sensor.
|
||||||
|
*
|
||||||
|
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||||
|
* @author Daniel Petry <danielpetry@cantab.net>
|
||||||
|
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* Derived from the internals.h file for the tsl2561 driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSL4531X_INTERNALS_H
|
||||||
|
#define TSL4531X_INTERNALS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name TSL4531x internal registers
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define TSL4531X_CONTROL_REG (0x0) /**< sets power mode */
|
||||||
|
#define TSL4531X_CONFIGURATION_REG (0x01) /**< sets power mode */
|
||||||
|
#define TSL4531X_ALSDATA1_REG (0x04) /**< contains DATALOW */
|
||||||
|
#define TSL4531X_ALSDATA2_REG (0x05) /**< contains DATAHIGH */
|
||||||
|
#define TSL4531X_ID_REG (0x0A) /**< contains part no above*/
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name TSL4531x power modes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define TSL4531X_MODE_POWER_DOWN (0x00)
|
||||||
|
#define TSL4531X_MODE_RESERVED (0x01)
|
||||||
|
#define TSL4531X_MODE_SINGLE_ADC_CYCLE (0x02) /**< Runs a single ADC cycle then
|
||||||
|
returns to power down. */
|
||||||
|
#define TSL4531X_MODE_NORMAL (0x03)
|
||||||
|
|
||||||
|
/* PowerSave saves some power in full power mode. PowerSave skip turns this off.
|
||||||
|
* Currently PowerSave skip is hard-coded to be on for simplicity, as it's just
|
||||||
|
* an intermediate between normal mode and low-power mode. */
|
||||||
|
#define TSL4531X_PSAVESKIP_OFF (0)
|
||||||
|
#define TSL4531X_PSAVESKIP_ON (1)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name TSL4531x macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Assemble the Command register */
|
||||||
|
#define TSL4531X_COMMAND(addr) ((1 << 7) | (addr))
|
||||||
|
|
||||||
|
/* Assemble the Configuration register */
|
||||||
|
#define TSL4531X_CONFIG(psaveskip, tcntrl) (((!!(psaveskip)) << 3) | (tcntrl))
|
||||||
|
|
||||||
|
/* Assemble the Control register */
|
||||||
|
#define TSL4531X_CONTROL(mode) (mode)
|
||||||
|
|
||||||
|
#define TSL4531X_GET_PARTNO(id_reg) ((id_reg) >> 4)
|
||||||
|
|
||||||
|
/* Data multiplier according to integration time.
|
||||||
|
*
|
||||||
|
* From the manual:
|
||||||
|
* MULTIPLIER = 1 for TCNTRL = 00 (Tint = 400 ms)
|
||||||
|
* MULTIPLIER = 2 for TCNTRL = 01 (Tint = 200 ms)
|
||||||
|
* MULTIPLIER = 4 for TCNTRL = 10 (Tint = 100 ms)
|
||||||
|
*/
|
||||||
|
#define MULTIPLY_DATA(data_raw, integration_time) ((data_raw) << (integration_time))
|
||||||
|
|
||||||
|
/* This allows either full power mode or power down mode. */
|
||||||
|
#define TSL4531X_POWER_MODE(mode) ((!mode) * (0x03))
|
||||||
|
|
||||||
|
/* The full integration time is a sum of:
|
||||||
|
* 1. A worst-case time for each of the integration times, which according to
|
||||||
|
* the datasheet is 5% more than the nominal time
|
||||||
|
* 2. 60, 30 or 15 ms, according to the integration time, if PowerSave is on;
|
||||||
|
* which is the power down period in between integration cycles in this mode.
|
||||||
|
* Note that in the current implementation, the "PowerSave skip" option is
|
||||||
|
* hard-coded to be on, as PowerSave only gives slightly less power
|
||||||
|
* consumption than normal mode.
|
||||||
|
*/
|
||||||
|
#define TSL4531X_GET_INTEGRATION_TIME_USEC(int_time_setting, psaveskip) \
|
||||||
|
(uint32_t)1000 * (((0x04 >> int_time_setting) * 105) + ((!psaveskip) * (60 >> int_time_setting)))
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TSL4531X_INTERNALS_H */
|
||||||
|
/** @} */
|
87
drivers/tsl4531x/include/tsl4531x_params.h
Normal file
87
drivers/tsl4531x/include/tsl4531x_params.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Inria
|
||||||
|
* 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 Default configuration for tsl4531x light sensor.
|
||||||
|
*
|
||||||
|
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||||
|
* @author Daniel Petry <danielpetry@cantab.net>
|
||||||
|
*
|
||||||
|
* Derived from the default configuration for the tsl2561 driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSL4531X_PARAMS_H
|
||||||
|
#define TSL4531X_PARAMS_H
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
#include "tsl4531x.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Set default configuration parameters for the TSL4531x
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef TSL4531X_PARAM_I2C_DEV
|
||||||
|
#define TSL4531X_PARAM_I2C_DEV I2C_DEV(0)
|
||||||
|
#endif
|
||||||
|
#ifndef TSL4531X_PARAM_I2C_ADDR
|
||||||
|
#define TSL4531X_PARAM_I2C_ADDR TSL45315_ADDR
|
||||||
|
#endif
|
||||||
|
#ifndef TSL4531X_PARAM_INTEGRATION
|
||||||
|
#define TSL4531X_PARAM_INTEGRATION TSL4531X_INTEGRATE_400MS
|
||||||
|
#endif
|
||||||
|
#ifndef TSL4531X_LOW_POWER_MODE
|
||||||
|
#define TSL4531X_LOW_POWER_MODE (false)
|
||||||
|
#endif
|
||||||
|
#ifndef TSL4531X_PARAM_PARTNO
|
||||||
|
#define TSL4531X_PARAM_PARTNO TSL45315_PARTNO
|
||||||
|
#endif
|
||||||
|
#ifndef TSL4531X_PARAMS
|
||||||
|
#define TSL4531X_PARAMS { .i2c_dev = TSL4531X_PARAM_I2C_DEV, \
|
||||||
|
.i2c_addr = TSL4531X_PARAM_I2C_ADDR, \
|
||||||
|
.integration_time = TSL4531X_PARAM_INTEGRATION, \
|
||||||
|
.low_power_mode = TSL4531X_LOW_POWER_MODE, \
|
||||||
|
.part_number = TSL4531X_PARAM_PARTNO }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TSL4531X_SAUL_INFO
|
||||||
|
#define TSL4531X_SAUL_INFO { .name = "tsl4531x" }
|
||||||
|
#endif
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure TSL4531x
|
||||||
|
*/
|
||||||
|
static const tsl4531x_params_t tsl4531x_params[] =
|
||||||
|
{
|
||||||
|
TSL4531X_PARAMS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate and configure entries to the SAUL registry
|
||||||
|
*/
|
||||||
|
saul_reg_info_t tsl4531x_saul_info[] =
|
||||||
|
{
|
||||||
|
TSL4531X_SAUL_INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TSL4531X_PARAMS_H */
|
||||||
|
/** @} */
|
@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2016 Inria
|
||||||
* Copyright (C) 2018 Freie Universität Berlin
|
* Copyright (C) 2018 Freie Universität Berlin
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
@ -11,15 +12,13 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file
|
* @file
|
||||||
* @brief Device driver for the TSL4531 Luminosity sensor.
|
* @brief Device driver for the TSL4531x Luminosity sensor.
|
||||||
*
|
*
|
||||||
|
* @author Daniel Petry <daniel.petry@fu-berlin.de>
|
||||||
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
||||||
|
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||||
*
|
*
|
||||||
* This driver was derived from the one for TSL2561.
|
* This driver was derived from the TSL2561 driver.
|
||||||
*
|
|
||||||
* @todo The i2c address is hardcoded
|
|
||||||
* @todo The only operating mode is "Normal Operation"
|
|
||||||
* @todo PowerSave is not supported
|
|
||||||
*
|
*
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
@ -28,113 +27,202 @@
|
|||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "tsl4531x.h"
|
#include "tsl4531x.h"
|
||||||
|
#include "tsl4531x_internals.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
static const uint16_t TSL4531_Addr = 0x29;
|
#define _DATALOW 0
|
||||||
static const uint16_t TSL4531_PARTNO = 0xA; /* 0b1010 */
|
#define _DATAHIGH 1
|
||||||
|
|
||||||
static const uint16_t Control_Reg = 0x0;
|
int tsl4531x_init(tsl4531x_t *dev, const tsl4531x_params_t *params)
|
||||||
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;
|
int r;
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
|
|
||||||
dev->i2c_dev = i2c_dev;
|
/* Initialise I2C bus */
|
||||||
dev->integration_time = integration_time;
|
if ((r = i2c_acquire(params->i2c_dev)) < 0) {
|
||||||
|
DEBUG("I2C_dev is: %d.", params->i2c_dev);
|
||||||
if ((r = i2c_acquire(dev->i2c_dev)) < 0) {
|
DEBUG("[Error] Cannot acquire device. I2C error: %d\n", r);
|
||||||
DEBUG("[Error] Cannot acquire device: %d\n", r);
|
return -ENODEV;
|
||||||
goto acquire_error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify sensor ID */
|
/* Test for connectivity - verify ID and compare against stored value */
|
||||||
if ((r = i2c_read_reg(dev->i2c_dev, TSL4531_Addr, TSL4531_COMMAND(ID_Reg),
|
if ((r = i2c_read_reg(params->i2c_dev,
|
||||||
|
params->i2c_addr,
|
||||||
|
TSL4531X_COMMAND(TSL4531X_ID_REG),
|
||||||
&id, 0)) < 0) {
|
&id, 0)) < 0) {
|
||||||
DEBUG("[Error] Cannot read ID register: %d\n", r);
|
DEBUG("[Error] Cannot read ID register. I2C error: %d\n", r);
|
||||||
goto init_error;
|
i2c_release(params->i2c_dev);
|
||||||
}
|
return -ENXIO;
|
||||||
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 */
|
DEBUG("[Info] tsl4531x sensor ID ? %d\n", id);
|
||||||
if (((r = i2c_write_reg(dev->i2c_dev , TSL4531_Addr, TSL4531_COMMAND(Control_Reg),
|
|
||||||
TSL4531_CONTROL(TSL4531x_MODE_Normal), 0)) < 0)
|
if (TSL4531X_GET_PARTNO(id) != params->part_number) {
|
||||||
||
|
DEBUG("[Error] not a TSL4531 sensor.\n");
|
||||||
((r = i2c_write_reg(dev->i2c_dev , TSL4531_Addr, TSL4531_COMMAND(Configuration_Reg),
|
i2c_release(params->i2c_dev);
|
||||||
TSL4531_CONFIG(1, integration_time), 0)) < 0)) {
|
return -ENOTSUP;
|
||||||
DEBUG("[Error] Cannot configure device %d\n", r);
|
|
||||||
goto init_error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init_error:
|
/* Configure device. In low power mode, we initially power the sensor down. */
|
||||||
/* ignore errors on device release */
|
if (((r = i2c_write_reg(params->i2c_dev,
|
||||||
i2c_release(dev->i2c_dev);
|
params->i2c_addr,
|
||||||
|
TSL4531X_COMMAND(TSL4531X_CONTROL_REG),
|
||||||
|
TSL4531X_CONTROL(TSL4531X_POWER_MODE(params->low_power_mode)),
|
||||||
|
0)) < 0)
|
||||||
|
||
|
||||||
|
((r = i2c_write_reg(params->i2c_dev,
|
||||||
|
params->i2c_addr,
|
||||||
|
TSL4531X_COMMAND(TSL4531X_CONFIGURATION_REG),
|
||||||
|
TSL4531X_CONFIG(TSL4531X_PSAVESKIP_ON, params->integration_time),
|
||||||
|
0)) < 0)) {
|
||||||
|
|
||||||
acquire_error:
|
DEBUG("[Error] Cannot configure device. I2C error: %d\n", r);
|
||||||
|
i2c_release(params->i2c_dev);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
/* If device was configured correctly, initialise the device descriptor */
|
||||||
|
dev->i2c_dev = params->i2c_dev;
|
||||||
|
dev->i2c_addr = params->i2c_addr;
|
||||||
|
dev->integration_time = params->integration_time;
|
||||||
|
dev->low_power_mode = params->low_power_mode;
|
||||||
|
dev->high_power_mode_started_up = false;
|
||||||
|
dev->sample_start_time = 0; /* Device assumed to start up at same time as
|
||||||
|
microcontroller - i.e. when it hits this line */
|
||||||
|
|
||||||
|
i2c_release(params->i2c_dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _DATALOW 0
|
int tsl4531x_set_low_power_mode(tsl4531x_t *dev, uint8_t low_power_mode)
|
||||||
#define _DATAHIGH 1
|
|
||||||
|
|
||||||
int tsl4531x_read(const tsl4531x_t *dev, uint16_t *result_lux)
|
|
||||||
{
|
{
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
dev->low_power_mode = low_power_mode;
|
||||||
|
|
||||||
|
if ((r = i2c_acquire(dev->i2c_dev)) < 0) {
|
||||||
|
DEBUG("[Error] Cannot acquire device. I2C error: %d\n", r);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = i2c_write_reg(dev->i2c_dev,
|
||||||
|
dev->i2c_addr,
|
||||||
|
TSL4531X_COMMAND(TSL4531X_CONTROL_REG),
|
||||||
|
TSL4531X_CONTROL(TSL4531X_POWER_MODE(low_power_mode)),
|
||||||
|
0)) < 0) {
|
||||||
|
DEBUG("[Error] Cannot write power mode. I2C error: %d\n", r);
|
||||||
|
i2c_release(dev->i2c_dev);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_release(dev->i2c_dev);
|
||||||
|
|
||||||
|
/* In high power mode only, we restart the sample ready timer, because only
|
||||||
|
in this mode it's used to indicate readiness after startup. */
|
||||||
|
if (!dev->low_power_mode) {
|
||||||
|
dev->sample_start_time = xtimer_now_usec();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsl4531x_start_sample(tsl4531x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
/* Don't change the mode to one-shot if the device is in high power mode. */
|
||||||
|
if (dev->low_power_mode) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((r = i2c_acquire(dev->i2c_dev)) < 0) {
|
||||||
|
DEBUG("[Error] Cannot acquire device. I2C error: %d\n", r);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = i2c_write_reg(dev->i2c_dev,
|
||||||
|
dev->i2c_addr,
|
||||||
|
TSL4531X_COMMAND(TSL4531X_CONTROL_REG),
|
||||||
|
TSL4531X_CONTROL(TSL4531X_MODE_SINGLE_ADC_CYCLE),
|
||||||
|
0)) < 0) {
|
||||||
|
DEBUG("[Error] Cannot write power mode. I2C error: %d\n", r);
|
||||||
|
i2c_release(dev->i2c_dev);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_release(dev->i2c_dev);
|
||||||
|
|
||||||
|
dev->sample_start_time = xtimer_now_usec();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tsl4531x_time_until_sample_ready(tsl4531x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
uint32_t t = TSL4531X_GET_INTEGRATION_TIME_USEC(dev->integration_time, TSL4531X_PSAVESKIP_ON) -
|
||||||
|
(xtimer_now_usec() - dev->sample_start_time);
|
||||||
|
|
||||||
|
/* Clamp t at zero */
|
||||||
|
t = (t <= TSL4531X_GET_INTEGRATION_TIME_USEC(dev->integration_time, TSL4531X_PSAVESKIP_ON) ?
|
||||||
|
t : 0);
|
||||||
|
|
||||||
|
if (!dev->low_power_mode) {
|
||||||
|
if (t == 0) {
|
||||||
|
dev->high_power_mode_started_up = true;
|
||||||
|
}
|
||||||
|
if (dev->high_power_mode_started_up) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsl4531x_get_sample(const tsl4531x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
uint8_t als_data[2]; /* = {[DATALOW], [DATAHIGH]} */
|
uint8_t als_data[2]; /* = {[DATALOW], [DATAHIGH]} */
|
||||||
|
|
||||||
if ((r = i2c_acquire(dev->i2c_dev)) < 0) {
|
if ((r = i2c_acquire(dev->i2c_dev)) < 0) {
|
||||||
DEBUG("[Error] Cannot acquire device: %d\n", r);
|
DEBUG("[Error] Cannot acquire device. I2C error: %d\n", r);
|
||||||
goto read_acquire_error;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((r = i2c_read_regs(dev->i2c_dev, TSL4531_Addr, TSL4531_COMMAND(ALSData1_Reg),
|
if ((r = i2c_read_regs(dev->i2c_dev,
|
||||||
als_data, 2, 0)) < 0) {
|
dev->i2c_addr,
|
||||||
(void)ALSData2_Reg; /* suppress warning */
|
TSL4531X_COMMAND(TSL4531X_ALSDATA1_REG),
|
||||||
DEBUG("[Error] Cannot read device: %d\n", r);
|
als_data, 2, 0)) < 0) {
|
||||||
goto read_error;
|
DEBUG("[Error] Cannot read data register. I2C error: %d\n", r);
|
||||||
|
i2c_release(dev->i2c_dev);
|
||||||
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
*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);
|
i2c_release(dev->i2c_dev);
|
||||||
|
|
||||||
read_acquire_error:
|
return MULTIPLY_DATA((((uint16_t)als_data[_DATAHIGH]) << 8)
|
||||||
return r;
|
+ als_data[_DATALOW], dev->integration_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tsl4531x_simple_read(tsl4531x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
if (dev->low_power_mode) {
|
||||||
|
tsl4531x_start_sample(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
xtimer_usleep(tsl4531x_time_until_sample_ready(dev));
|
||||||
|
|
||||||
|
return tsl4531x_get_sample(dev);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2016 Inria
|
||||||
* Copyright (C) 2018 Freie Universität Berlin
|
* Copyright (C) 2018 Freie Universität Berlin
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
@ -11,27 +12,25 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file
|
* @file
|
||||||
* @brief SAUL interface for TSL4531 Luminosity sensor.
|
* @brief SAUL interface for TSL4531x Luminosity sensor.
|
||||||
*
|
*
|
||||||
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
* @author Juan I Carrano <j.carrano@fu-berlin.de>
|
||||||
|
* @author Daniel Petry <daniel.petry@fu-berlin.de>
|
||||||
*
|
*
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "saul.h"
|
#include "saul.h"
|
||||||
#include "tsl4531x.h"
|
#include "tsl4531x.h"
|
||||||
|
|
||||||
static int _read(const void *dev, phydat_t *res)
|
static int _read(const void *dev, phydat_t *data)
|
||||||
{
|
{
|
||||||
int nvals;
|
memset(data, 0, sizeof(phydat_t));
|
||||||
uint16_t lux;
|
data->val[0] = tsl4531x_simple_read((const tsl4531x_t *)dev);
|
||||||
|
data->unit = UNIT_LUX;
|
||||||
nvals = (tsl4531x_read(dev, &lux) >= 0)? 1 : 0;
|
data->scale = 0;
|
||||||
|
return 1;
|
||||||
res->val[0] = lux;
|
|
||||||
res->unit = UNIT_LUX;
|
|
||||||
res->scale = 0;
|
|
||||||
return nvals;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const saul_driver_t tsl4531x_saul_driver = {
|
const saul_driver_t tsl4531x_saul_driver = {
|
||||||
|
Loading…
Reference in New Issue
Block a user