fixed tsl2561, added tsl2591

This commit is contained in:
Stephane D'Alu 2016-02-09 23:52:11 +01:00
parent 526d92aa62
commit e34ef249e7
3 changed files with 511 additions and 14 deletions

View File

@ -14,6 +14,10 @@
limitations under the License.
*/
/**
*
* DOC: http://ams.com/eng/content/download/250096/975518/143687
*/
#define I2C_HELPERS_AUTOMATIC_DRV TRUE
#include "hal.h"
@ -48,17 +52,17 @@
// I2C Register
#define TSL2561_REG_CONTROL 0x00
#define TSL2561_REG_TIMING 0x01
#define TSL2561_REG_THRESHHOLDL_LOW 0x02
#define TSL2561_REG_THRESHHOLDL_HIGH 0x03
#define TSL2561_REG_THRESHHOLDH_LOW 0x04
#define TSL2561_REG_THRESHHOLDH_HIGH 0x05
#define TSL2561_REG_THRESHHOLDLLOW 0x02
#define TSL2561_REG_THRESHHOLDLHIGH 0x03
#define TSL2561_REG_THRESHHOLDHLOW 0x04
#define TSL2561_REG_THRESHHOLDHHIGH 0x05
#define TSL2561_REG_INTERRUPT 0x06
#define TSL2561_REG_CRC 0x08
#define TSL2561_REG_ID 0x0A
#define TSL2561_REG_CHAN0_LOW 0x0C
#define TSL2561_REG_CHAN0_HIGH 0x0D
#define TSL2561_REG_CHAN1_LOW 0x0E
#define TSL2561_REG_CHAN1_HIGH 0x0F
#define TSL2561_REG_DATA0LOW 0x0C
#define TSL2561_REG_DATA0HIGH 0x0D
#define TSL2561_REG_DATA1LOW 0x0E
#define TSL2561_REG_DATA1HIGH 0x0F
// Auto-gain thresholds
@ -254,12 +258,12 @@ calculateIlluminance(TSL2561_integration_time_t integration_time,
static inline msg_t
_readChannel(TSL2561_drv *drv, uint16_t *broadband, uint16_t *ir) {
msg_t msg;
if (((msg = i2c_reg_recv16_le(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT |
TSL2561_REG_CHAN0_LOW,
broadband)) < MSG_OK) ||
((msg = i2c_reg_recv16_le(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT |
TSL2561_REG_CHAN1_LOW,
ir )) < MSG_OK))
if (((msg = i2c_reg_recv16_le(
TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REG_DATA0LOW,
broadband)) < MSG_OK) ||
((msg = i2c_reg_recv16_le(
TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REG_DATA1LOW,
ir )) < MSG_OK))
return msg;
return MSG_OK;
}

View File

@ -0,0 +1,253 @@
/*
TSL2591 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
*
* DOC: http://ams.com/eng/content/download/389383/1251117/221235
*/
#define I2C_HELPERS_AUTOMATIC_DRV TRUE
#include "hal.h"
#include "i2c_helpers.h"
#include "tsl2591.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define TSL2591_LUX_DF (408.0F)
#define TSL2591_LUX_COEFB (1.64F) // CH0 coefficient
#define TSL2591_LUX_COEFC (0.59F) // CH1 coefficient A
#define TSL2591_LUX_COEFD (0.86F) // CH2 coefficient B
/* I2C registers */
#define TSL2591_REG_ENABLE 0x00
#define TSL2591_REG_CONFIG 0x01 /**< @brief gain and integration */
#define TSL2591_REG_AILTL 0x04
#define TSL2591_REG_AILTH 0x05
#define TSL2591_REG_AIHTL 0x06
#define TSL2591_REG_AIHTH 0x07
#define TSL2591_REG_NPAILTL 0x08
#define TSL2591_REG_NPAILTH 0x09
#define TSL2591_REG_NPAIHTL 0x0A
#define TSL2591_REG_NPAIHTH 0x0B
#define TSL2591_REG_PERSIST 0x0C
#define TSL2591_REG_PID 0x11 /**< @brief Package ID */
#define TSL2591_REG_ID 0x12 /**< @brief Device ID */
#define TSL2591_REG_STATUS 0x13 /**< @brief Device status */
#define TSL2591_REG_C0DATAL 0x14 /**< @brief CH0 ADC low data byte */
#define TSL2591_REG_C0DATAH 0x15 /**< @brief CH0 ADC high data byte */
#define TSL2591_REG_C1DATAL 0x16 /**< @brief CH1 ADC low data byte */
#define TSL2591_REG_C1DATAH 0x17 /**< @brief CH1 ADC high data byte */
#define TSL2591_REG_COMMAND 0x80 /**< @brief Select command register */
#define TSL2591_REG_NORMAL 0x20 /**< @brief Normal opearation */
#define TSL2591_REG_SPECIAL 0x60 /**< @brief Special function */
#define TSL2591_ID_TSL2591 0x50
#define TSL2591_VISIBLE (2) // channel 0 - channel 1
#define TSL2591_INFRARED (1) // channel 1
#define TSL2591_FULLSPECTRUM (0) // channel 0
#define TSL2591_ENABLE_POWERON (0x01)
#define TSL2591_ENABLE_POWEROFF (0x00)
#define TSL2591_ENABLE_AEN (0x02)
#define TSL2591_ENABLE_AIEN (0x10)
#define TSL2591_CONTROL_RESET (0x80)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static inline uint32_t
calculateIlluminance(TSL2591_integration_time_t integration_time,
TSL2591_gain_t gain,
uint16_t broadband, uint16_t ir) {
uint16_t atime, again;
/* Check for overflow conditions first */
if ((broadband == 0xFFFF) | (ir == 0xFFFF)) {
return 0xFFFFFFFF; /* Signal overflow */
}
switch (integration_time) {
case TSL2591_INTEGRATIONTIME_100MS : atime = 100; break;
case TSL2591_INTEGRATIONTIME_200MS : atime = 200; break;
case TSL2591_INTEGRATIONTIME_300MS : atime = 300; break;
case TSL2591_INTEGRATIONTIME_400MS : atime = 400; break;
case TSL2591_INTEGRATIONTIME_500MS : atime = 500; break;
case TSL2591_INTEGRATIONTIME_600MS : atime = 600; break;
}
switch (gain) {
case TSL2591_GAIN_1X : again = 1; break;
case TSL2591_GAIN_25X : again = 25; break;
case TSL2591_GAIN_415X : again = 415; break;
case TSL2591_GAIN_10000X : again = 10000; break;
}
// cpl = (ATIME * AGAIN) / DF
float cpl = ((float)(atime * again)) / ((float)TSL2591_LUX_DF);
float lux1 = ( ((float)broadband) - (TSL2591_LUX_COEFB * (float)ir) ) / cpl;
float lux2 = ( (TSL2591_LUX_COEFC * (float)broadband) -
(TSL2591_LUX_COEFD * (float)ir ) ) / cpl;
return (uint32_t) (lux1 > lux2 ? lux1 : lux2);
}
static inline msg_t
_readChannel(TSL2591_drv *drv, uint16_t *broadband, uint16_t *ir) {
msg_t msg;
if (((msg = i2c_reg_recv16_le(
TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_C0DATAL,
broadband)) < MSG_OK) ||
((msg = i2c_reg_recv16_le(
TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_C1DATAL,
ir )) < MSG_OK))
return msg;
return MSG_OK;
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
void
TSL2591_init(TSL2591_drv *drv, TSL2591_config *config) {
drv->config = config;
drv->gain = TSL2591_GAIN_1X;
drv->integration_time = TSL2591_INTEGRATIONTIME_100MS;
drv->state = SENSOR_INIT;
}
msg_t
TSL2591_check(TSL2591_drv *drv) {
uint8_t id;
msg_t msg;
if ((msg = i2c_reg_recv8(TSL2591_REG_COMMAND | TSL2591_REG_NORMAL |
TSL2591_REG_ID, &id)) < MSG_OK)
return msg;
if (id != TSL2591_ID_TSL2591)
return SENSOR_NOTFOUND;
return MSG_OK;
}
msg_t
TSL2591_start(TSL2591_drv *drv) {
struct PACKED {
uint8_t reg;
uint8_t conf;
} tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE,
TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN | TSL2591_ENABLE_AIEN };
return i2c_send((uint8_t*)&tx, sizeof(tx));
}
msg_t
TSL2591_stop(TSL2591_drv *drv) {
struct PACKED {
uint8_t reg;
uint8_t conf;
} tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE,
TSL2591_ENABLE_POWEROFF };
return i2c_send((uint8_t*)&tx, sizeof(tx));
}
msg_t
TSL2591_setIntegrationTime(TSL2591_drv *drv,
TSL2591_integration_time_t time) {
struct PACKED {
uint8_t reg;
uint8_t conf;
} tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG,
(uint8_t)(time | drv->gain) };
msg_t msg;
if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK)
return msg;
drv->integration_time = time;
return MSG_OK;
}
msg_t
TSL2591_setGain(TSL2591_drv *drv,
TSL2591_gain_t gain) {
struct PACKED {
uint8_t reg;
uint8_t conf;
} tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG,
(uint8_t)(drv->integration_time | gain) };
msg_t msg;
if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK)
return msg;
drv->gain = gain;
return MSG_OK;
}
unsigned int
TSL2591_getAcquisitionTime(TSL2591_drv *drv) {
switch (drv->integration_time) {
case TSL2591_INTEGRATIONTIME_100MS : return 100;
case TSL2591_INTEGRATIONTIME_200MS : return 200;
case TSL2591_INTEGRATIONTIME_300MS : return 300;
case TSL2591_INTEGRATIONTIME_400MS : return 400;
case TSL2591_INTEGRATIONTIME_500MS : return 500;
case TSL2591_INTEGRATIONTIME_600MS : return 600;
}
return -1;
}
msg_t
TSL2591_readIlluminance(TSL2591_drv *drv,
unsigned int *illuminance) {
uint16_t broadband;
uint16_t ir;
/* Read channels */
msg_t msg;
if ((msg = _readChannel(drv, &broadband, &ir)) < MSG_OK)
return msg;
/* Calculate illuminance */
*illuminance =
calculateIlluminance(drv->integration_time, drv->gain,
broadband, ir);
/* Ok */
return SENSOR_OK;
}

View File

@ -0,0 +1,240 @@
/*
TSL2591 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file tsl2591.h
* @brief TSL2591 Light sensor interface module header.
*
* @{
*/
#ifndef _SENSOR_TSL2591_H_
#define _SENSOR_TSL2591_H_
#include <math.h>
#include "i2c_helpers.h"
#include "sensor.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Device sensor continuous acquisition support.
*/
#define TSL2591_CONTINUOUS_ACQUISITION_SUPPORTED TRUE
/**
* @brief I2C address.
*/
#define TSL2591_I2CADDR_FIXED 0x29
/**
* @brief Time necessary for the sensor to boot
*/
#define TSL2591_BOOTUP_TIME 0
/**
* @brief Time necessary for the sensor to start
*/
#define TSL2591_STARTUP_TIME 0
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/**
* @brief Default I2C address (when pin unconfigured)
*/
#define TSL2591_I2CADDR_DEFAULT TSL2591_I2CADDR_FIXED
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief TSL2591 configuration structure.
*/
typedef struct {
I2CHelper i2c; /* keep it first */
} TSL2591_config;
/**
* @brief Available integration time
*
* @details Available integration time are:
* 100ms, 200ms, 300ms, 400ms, 500ms and 600ms
*/
typedef enum {
TSL2591_INTEGRATIONTIME_100MS = 0x00, /**< @brief 100ms */
TSL2591_INTEGRATIONTIME_200MS = 0x01, /**< @brief 200ms */
TSL2591_INTEGRATIONTIME_300MS = 0x02, /**< @brief 300ms */
TSL2591_INTEGRATIONTIME_400MS = 0x03, /**< @brief 400ms */
TSL2591_INTEGRATIONTIME_500MS = 0x04, /**< @brief 500ms */
TSL2591_INTEGRATIONTIME_600MS = 0x05, /**< @brief 600ms */
} TSL2591_integration_time_t;
/**
* @brief Available gain
*
* @details Available gain are 1x, 25x, 415x, 10000x
*/
typedef enum {
TSL2591_GAIN_1X = 0x00, /**< @brief 1x gain */
TSL2591_GAIN_25X = 0x10, /**< @brief 25x gain */
TSL2591_GAIN_415X = 0x20, /**< @brief 415x gain */
TSL2591_GAIN_10000X = 0x30, /**< @brief 10000x gain */
} TSL2591_gain_t;
/**
* @brief TSL2591 configuration structure.
*/
typedef struct {
TSL2591_config *config;
sensor_state_t state;
unsigned int delay;
uint16_t cfg;
TSL2591_gain_t gain;
TSL2591_integration_time_t integration_time;
} TSL2591_drv;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/**
* @brief Initialize the sensor driver
*/
void
TSL2591_init(TSL2591_drv *drv,
TSL2591_config *config);
/**
* @brief Start the sensor
*/
msg_t
TSL2591_start(TSL2591_drv *drv);
/**
* @brief Stop the sensor
*
* @details If the sensor support it, it will be put in low energy mode.
*/
msg_t
TSL2591_stop(TSL2591_drv *drv);
/**
* @brief Check that the sensor is really present
*/
msg_t
TSL2591_check(TSL2591_drv *drv);
/**
* @brief Time in milli-seconds necessary for acquiring a naw measure
*
* @returns
* unsigned int time in millis-seconds
*/
unsigned int
TSL2591_getAcquisitionTime(TSL2591_drv *drv);
/**
* @brief Trigger a mesure acquisition
*/
static inline msg_t
TSL2591_startMeasure(TSL2591_drv *drv) {
(void)drv;
return MSG_OK;
};
msg_t
TSL2591_setGain(TSL2591_drv *drv,
TSL2591_gain_t gain);
msg_t
TSL2591_setIntegrationTime(TSL2591_drv *drv,
TSL2591_integration_time_t time);
/**
* @brief Read the newly acquiered measure
*
* @note According the the sensor design the measure read
* can be any value acquired after the acquisition time
* and the call to readMeasure.
*/
msg_t
TSL2591_readMeasure(TSL2591_drv *drv,
unsigned int illuminance);
/**
* @brief Read temperature and humidity
*
* @details According to the sensor specification/configuration
* (see #TSL2591_CONTINUOUS_ACQUISITION_SUPPORTED),
* if the sensor is doing continuous measurement
* it's value will be requested and returned immediately.
* Otherwise a measure is started, the necessary amount of
* time for acquiring the value is spend sleeping (not spinning),
* and finally the measure is read.
*
* @note In continuous measurement mode, if you just started
* the sensor, you will need to wait getAcquisitionTime()
* in addition to the usual getStartupTime()
* @note If using several sensors, it is better to start all the
* measure together, wait for the sensor having the longuest
* aquisition time, and finally read all the values
*/
msg_t
TSL2591_readIlluminance(TSL2591_drv *drv,
unsigned int *illuminance);
/**
* @brief Return the illuminance value in Lux
*
* @details Use readIlluminance() for returning the humidity value.
*
* @note Prefere readIlluminance()if you need better error handling.
*
* @return Illuminance in Lux
* @retval unsigned int illuminace value
* @retval -1 on failure
*/
static inline unsigned int
TSL2591_getIlluminance(TSL2591_drv *drv) {
unsigned int illuminance = -1;
TSL2591_readIlluminance(drv, &illuminance);
return illuminance;
}
#endif