1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

drivers/tcs37727: initial commit for tcs37727 driver

The driver supports lux and ct calculation and autogain funktion.
This commit is contained in:
Johann F 2015-05-31 15:11:40 +02:00 committed by Johann Fischer
parent 71a3cc1779
commit c6cec830f9
5 changed files with 539 additions and 0 deletions

View File

@ -46,3 +46,6 @@ endif
ifneq (,$(filter encx24j600,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/encx24j600/include
endif
ifneq (,$(filter tcs37727,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tcs37727/include
endif

124
drivers/include/tcs37727.h Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2015 PHYTEC Messtechnik GmbH
*
* 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_tcs37727 TCS37727 Light-To-Digital Converter
*
* @ingroup drivers
* @brief Driver for the AMS TCS37727 Color Light-To-Digital Converter
*
*
* @{
*
* @file
* @brief Interface definition for the TCS37727 sensor driver.
*
* @author Felix Siebel <f.siebel@phytec.de>
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef TCS37727_H
#define TCS37727_H
#include <stdint.h>
#include <stdbool.h>
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef TCS37727_I2C_ADDRESS
#define TCS37727_I2C_ADDRESS 0x29 /**< Default Device Address */
#endif
#ifndef TCS37727_ATIME_DEFAULT
#define TCS37727_ATIME_DEFAULT 200000 /**< Default RGBC integration time */
#endif
/**
* @brief Struct for storing TCS37727 sensor data
*/
typedef struct {
uint32_t red; /**< IR compensated channels red */
uint32_t green; /**< IR compensated channels green */
uint32_t blue; /**< IR compensated channels blue */
uint32_t clear; /**< channels clear */
uint32_t lux; /**< Lux */
uint32_t ct; /**< Color temperature */
} tcs37727_data_t;
/**
* @brief Device descriptor for TCS37727 sensors.
*/
typedef struct {
i2c_t i2c; /**< I2C device the sensor is connected to */
uint8_t addr; /**< the sensor's slave address on the I2C bus */
bool initialized; /**< sensor status, true if sensor is initialized */
int atime_us; /**< atime value conveted to microseconds */
int again; /**< amount of gain */
} tcs37727_t;
/**
* @brief Initialise the TCS37727 sensor driver.
* Settings: Gain 4x, Proximity Detection off
*
* @param[out] dev device descriptor of sensor to initialize
* @param[in] i2c I2C bus the sensor is connected to
* @param[in] address sensor's I2C slave address
* @param[in] atime_us rgbc RGBC integration time in microseconds
*
* @return 0 on success
* @return -1 if initialization of I2C bus failed
* @return -2 if sensor test failed
* @return -3 if sensor configuration failed
*/
int tcs37727_init(tcs37727_t *dev, i2c_t i2c, uint8_t address, int atime_us);
/**
* @brief Set RGBC enable, this activates periodic RGBC measurements.
*
* @param[out] dev device descriptor of sensor
*
* @return 0 on success
* @return -1 on error
*/
int tcs37727_set_rgbc_active(tcs37727_t *dev);
/**
* @brief Set RGBC disable, this deactivates periodic RGBC measurements.
* Also turns off the sensor when proximity measurement is disabled.
*
* @param[in] dev device descriptor of sensor
*
* @return 0 on success
* @return -1 on error
*/
int tcs37727_set_rgbc_standby(tcs37727_t *dev);
/**
* @brief Read sensor's data.
* Besides an Autogain routine is called. If a maximum or minimum threshold
* value of the channel clear is reached, then the gain will be changed
* correspond to max or min threshold.
*
* @param[in] dev device descriptor of sensor
* @param[out] data device sensor data
*
* @return 0 on success
* @return -1 on error
*/
int tcs37727_read(tcs37727_t *dev, tcs37727_data_t *data);
#ifdef __cplusplus
}
#endif
#endif
/** @} */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2015 PHYTEC Messtechnik GmbH
*
* 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_tcs37727
* @{
*
* @file
* @brief Register definitions for the TCS37727 driver.
*
* @author Johann Fischer <j.fischer@phytec.de>
*
*/
#ifndef TCS37727_INTERNAL_H
#define TCS37727_INTERNAL_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef TCS37727_AG_THRESHOLD_LOW
#define TCS37727_AG_THRESHOLD_LOW 200
#endif
#ifndef TCS37727_AG_THRESHOLD_HIGH
#define TCS37727_AG_THRESHOLD_HIGH (65535 - TCS37727_AG_THRESHOLD_LOW)
#endif
/**
* @brief Register Map
*
* All setting register are defined for repeated byte protocol transaction.
*/
#define TCS37727_ENABLE 0x80 /* Enables states and interrupts */
#define TCS37727_ATIME 0x81 /* RGBC time */
#define TCS37727_PTIME 0x82 /* Proximity time */
#define TCS37727_WTIME 0x83 /* Wait time */
#define TCS37727_AILTL 0x04 /* Clear interrupt low threshold low byte */
#define TCS37727_AILTH 0x05 /* Clear interrupt low threshold high byte */
#define TCS37727_AIHTL 0x06 /* Clear interrupt high threshold low byte */
#define TCS37727_AIHTH 0x07 /* Clear interrupt high threshold high byte */
#define TCS37727_PILTL 0x08 /* Proximity interrupt low threshold low byte */
#define TCS37727_PILTH 0x09 /* Proximity interrupt low threshold high byte */
#define TCS37727_PIHTL 0x0A /* Proximity interrupt high threshold low byte */
#define TCS37727_PIHTH 0x0B /* Proximity interrupt high threshold high byte */
#define TCS37727_PERS 0x8C /* Interrupt persistence filters */
#define TCS37727_CONFIG 0x8D /* Configuration */
#define TCS37727_PPULSE 0x8E /* Proximity pulse count */
#define TCS37727_CONTROL 0x8F /* Gain control register */
#define TCS37727_ID 0x92 /* Device IDID */
#define TCS37727_STATUS 0x93 /* Device status */
#define TCS37727_CDATA 0x14 /* Clear ADC data low byte */
#define TCS37727_CDATAH 0x15 /* Clear ADC data high byte */
#define TCS37727_RDATA 0x16 /* Red ADC data low byte */
#define TCS37727_RDATAH 0x17 /* Red ADC data high byte */
#define TCS37727_GDATA 0x18 /* Green ADC data low byte */
#define TCS37727_GDATAH 0x19 /* Green ADC data high byte */
#define TCS37727_BDATA 0x1A /* Blue ADC data low byte */
#define TCS37727_BDATAH 0x1B /* Blue ADC data high byte */
#define TCS37727_PDATA 0x1C /* Proximity ADC data low byte */
#define TCS37727_PDATAH 0x1D /* Proximity ADC data high byte */
/**
* @brief Command Register
*/
#define TCS37727_BYTE_TRANS 0x80 /* Repeated byte protocol transaction */
#define TCS37727_INC_TRANS 0xA0 /* Auto-increment protocol transaction */
#define TCS37727_SF_PICLR 0xE5 /* Proximity interrupt clear */
#define TCS37727_SF_CICLR 0xE6 /* Clear channel interrupt clear */
#define TCS37727_SF_PCICLR 0xE7 /* Proximity and Clear channel interrupt clear */
/**
* @brief Enable Register
*/
#define TCS37727_ENABLE_PIEN (1 << 5) /* Proximity interrupt enable */
#define TCS37727_ENABLE_AIEN (1 << 4) /* Clear channel interrupt enable */
#define TCS37727_ENABLE_WEN (1 << 3) /* Wait enable, activates the wait feature */
#define TCS37727_ENABLE_PEN (1 << 2) /* Proximity enable, activates the proximity function */
#define TCS37727_ENABLE_AEN (1 << 1) /* RGBC enable, actives the two-channel ADC */
#define TCS37727_ENABLE_PON (1 << 0) /* Power ON */
/**
* @brief Control Register
*/
#define TCS37727_CONTROL_PDRIVE_100 0x00 /* 100 mA LED Drive Strength */
#define TCS37727_CONTROL_PDRIVE_50 0x04 /* 50 mA LED Drive Strength */
#define TCS37727_CONTROL_PDRIVE_25 0x08 /* 25 mA LED Drive Strength */
#define TCS37727_CONTROL_PDRIVE_12 0x0C /* 12.5 mA LED Drive Strength */
#define TCS37727_CONTROL_PDRIVE_MASK 0x0C /* PDRIVE Mask */
#define TCS37727_CONTROL_AGAIN_1 0x00 /* 1 × gain RGBC Gain Value */
#define TCS37727_CONTROL_AGAIN_4 0x01 /* 4 × gain RGBC Gain Value */
#define TCS37727_CONTROL_AGAIN_16 0x02 /* 16 × gain RGBC Gain Value */
#define TCS37727_CONTROL_AGAIN_60 0x03 /* 60 × gain RGBC Gain Value */
#define TCS37727_CONTROL_AGAIN_MASK 0x03 /* AGAIN Mask */
/**
* @brief Device ID
*/
#define TCS37727_ID_VALUE 0x49
/**
* @brief Predefined ATIME register values.
*/
#define TCS37727_ATIME_MIN 2400 /* 2.4ms integration time, max count 1024 */
#define TCS37727_ATIME_MAX 614000 /* 614ms integration time, max count 0xffff */
#define TCS37727_ATIME_TO_REG(val) (256 - (uint8_t)((val) / 2400))
#define TCS37727_ATIME_TO_US(reg) ((256 - (uint8_t)(reg)) * 2400)
/**
* @brief Coefficients for Lux and CT Equations (DN40)
*
* Coefficients in integer format, multiplied by 1000.
*/
#define DGF_IF 310
#define R_COEF_IF 136
#define G_COEF_IF 1000
#define B_COEF_IF -444
#define CT_COEF_IF 3810
#define CT_OFFSET_IF 1391
#ifdef __cplusplus
}
#endif
#endif
/** @} */

276
drivers/tcs37727/tcs37727.c Normal file
View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2015 PHYTEC Messtechnik GmbH
*
* 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_tcs37727
* @{
*
* @file
* @brief Driver for the AMS TCS37727 Color Light-To-Digital Converter
*
* @author Felix Siebel <f.siebel@phytec.de>
* @author Johann Fischer <j.fischer@phytec.de>
*
* @}
*/
#include <stdint.h>
#include <stdbool.h>
#include "periph/i2c.h"
#include "tcs37727.h"
#include "tcs37727-internal.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define I2C_SPEED I2C_SPEED_FAST
static int tcs37727_test(tcs37727_t *dev)
{
char id;
i2c_acquire(dev->i2c);
if (i2c_read_reg(dev->i2c, dev->addr, TCS37727_ID, &id) != 1) {
i2c_release(dev->i2c);
return -1;
}
i2c_release(dev->i2c);
if (id != TCS37727_ID_VALUE) {
return -1;
}
return 0;
}
int tcs37727_init(tcs37727_t *dev, i2c_t i2c, uint8_t address, int atime_us)
{
/* write device descriptor */
dev->i2c = i2c;
dev->addr = address;
dev->initialized = false;
i2c_acquire(dev->i2c);
/* initialize the I2C bus */
if (i2c_init_master(i2c, I2C_SPEED) < 0) {
i2c_release(dev->i2c);
return -1;
}
i2c_release(dev->i2c);
if (tcs37727_test(dev)) {
return -2;
}
i2c_acquire(dev->i2c);
if (i2c_write_reg(dev->i2c, dev->addr, TCS37727_CONTROL,
TCS37727_CONTROL_AGAIN_4) != 1) {
i2c_release(dev->i2c);
return -3;
}
dev->again = 4;
if (i2c_write_reg(dev->i2c, dev->addr,
TCS37727_ATIME_TO_REG(atime_us), 0) != 1) {
i2c_release(dev->i2c);
return -3;
}
dev->atime_us = atime_us;
dev->initialized = true;
i2c_release(dev->i2c);
return 0;
}
int tcs37727_set_rgbc_active(tcs37727_t *dev)
{
uint8_t reg;
if (dev->initialized == false) {
return -1;
}
i2c_acquire(dev->i2c);
if (i2c_read_regs(dev->i2c, dev->addr, TCS37727_ENABLE, (char *)&reg, 1) != 1) {
i2c_release(dev->i2c);
return -1;
}
reg |= (TCS37727_ENABLE_AEN | TCS37727_ENABLE_PON);
if (i2c_write_reg(dev->i2c, dev->addr, TCS37727_ENABLE, reg) != 1) {
i2c_release(dev->i2c);
return -1;
}
i2c_release(dev->i2c);
return 0;
}
int tcs37727_set_rgbc_standby(tcs37727_t *dev)
{
uint8_t reg;
if (dev->initialized == false) {
return -1;
}
i2c_acquire(dev->i2c);
if (i2c_read_regs(dev->i2c, dev->addr, TCS37727_ENABLE, (char *)&reg, 1) != 1) {
i2c_release(dev->i2c);
return -1;
}
reg &= ~TCS37727_ENABLE_AEN;
if (!(reg & TCS37727_ENABLE_PEN)) {
reg &= ~TCS37727_ENABLE_PON;
}
if (i2c_write_reg(dev->i2c, dev->addr, TCS37727_ENABLE, reg) != 1) {
i2c_release(dev->i2c);
return -1;
}
i2c_release(dev->i2c);
return 0;
}
static uint8_t tcs37727_trim_gain(tcs37727_t *dev, int rawc)
{
uint8_t reg_again = 0;
int val_again = dev->again;
if (dev->initialized == false) {
return -1;
}
if (rawc < TCS37727_AG_THRESHOLD_LOW) {
switch (val_again) {
case 1:
reg_again = TCS37727_CONTROL_AGAIN_4;
val_again = 4;
break;
case 4:
reg_again = TCS37727_CONTROL_AGAIN_16;
val_again = 16;
break;
case 16:
reg_again = TCS37727_CONTROL_AGAIN_60;
val_again = 60;
break;
case 60:
default:
return -1;
}
}
else if (rawc > TCS37727_AG_THRESHOLD_HIGH) {
switch (val_again) {
case 60:
reg_again = TCS37727_CONTROL_AGAIN_16;
val_again = 16;
break;
case 16:
reg_again = TCS37727_CONTROL_AGAIN_4;
val_again = 4;
break;
case 4:
reg_again = TCS37727_CONTROL_AGAIN_1;
val_again = 1;
break;
case 1:
default:
return -1;
}
}
else {
return 0;
}
i2c_acquire(dev->i2c);
uint8_t reg = 0;
if (i2c_read_reg(dev->i2c, dev->addr, TCS37727_CONTROL, (char *)&reg) != 1) {
i2c_release(dev->i2c);
return -2;
}
reg &= ~TCS37727_CONTROL_AGAIN_MASK;
reg |= reg_again;
if (i2c_write_reg(dev->i2c, dev->addr, TCS37727_CONTROL, reg) != 1) {
i2c_release(dev->i2c);
return -2;
}
i2c_release(dev->i2c);
dev->again = val_again;
return 0;
}
int tcs37727_read(tcs37727_t *dev, tcs37727_data_t *data)
{
char buf[8];
if (dev->initialized == false) {
return -1;
}
i2c_acquire(dev->i2c);
if (i2c_read_regs(dev->i2c, dev->addr,
(TCS37727_INC_TRANS | TCS37727_CDATA), buf, 8) != 8) {
i2c_release(dev->i2c);
return -1;
}
i2c_release(dev->i2c);
int32_t tmpc = ((uint16_t)buf[1] << 8) | buf[0];
int32_t tmpr = ((uint16_t)buf[3] << 8) | buf[2];
int32_t tmpg = ((uint16_t)buf[5] << 8) | buf[4];
int32_t tmpb = ((uint16_t)buf[7] << 8) | buf[6];
DEBUG("rawr: %"PRIi32" rawg %"PRIi32" rawb %"PRIi32" rawc %"PRIi32"\n",
tmpr, tmpg, tmpb, tmpc);
/* Remove IR component as described in the DN40. */
int32_t ir = (tmpr + tmpg + tmpb - tmpc) >> 1;
tmpr -= ir;
tmpg -= ir;
tmpb -= ir;
/* Color temperature calculation as described in the DN40. */
int32_t ct = (CT_COEF_IF * tmpb) / tmpr + CT_OFFSET_IF;
/* Lux calculation as described in the DN40. */
int32_t gi = R_COEF_IF * tmpr + G_COEF_IF * tmpg + B_COEF_IF * tmpb;
/* TODO: add Glass Attenuation Factor GA compensation */
int32_t cpl = (dev->atime_us * dev->again) / DGF_IF;
int32_t lux = gi / cpl;
/* Autogain */
tcs37727_trim_gain(dev, tmpc);
data->red = (tmpr < 0) ? 0 : (tmpr * 1000) / cpl;
data->green = (tmpg < 0) ? 0 : (tmpg * 1000) / cpl;
data->blue = (tmpb < 0) ? 0 : (tmpb * 1000) / cpl;
data->clear = (tmpb < 0) ? 0 : (tmpc * 1000) / cpl;
data->lux = (lux < 0) ? 0 : lux;
data->ct = (ct < 0) ? 0 : ct;
return 0;
}