273 lines
8.6 KiB
C
273 lines
8.6 KiB
C
|
/*
|
||
|
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 __attribute__((packed)) {
|
||
|
uint8_t reg;
|
||
|
uint8_t conf;
|
||
|
} tx_config = {
|
||
|
TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG,
|
||
|
(uint8_t)(drv->integration_time | drv->gain) };
|
||
|
|
||
|
struct __attribute__((packed)) {
|
||
|
uint8_t reg;
|
||
|
uint8_t conf;
|
||
|
} tx_start = {
|
||
|
TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE,
|
||
|
TSL2591_ENABLE_POWERON };
|
||
|
|
||
|
msg_t msg;
|
||
|
|
||
|
if (((msg = i2c_send((uint8_t*)&tx_config, sizeof(tx_config))) < MSG_OK) ||
|
||
|
((msg = i2c_send((uint8_t*)&tx_start, sizeof(tx_start ))) < MSG_OK)) {
|
||
|
drv->state = SENSOR_ERROR;
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
drv->state = SENSOR_STARTED;
|
||
|
return MSG_OK;
|
||
|
}
|
||
|
|
||
|
msg_t
|
||
|
TSL2591_stop(TSL2591_drv *drv) {
|
||
|
struct __attribute__((packed)) {
|
||
|
uint8_t reg;
|
||
|
uint8_t conf;
|
||
|
} tx_stop = {
|
||
|
TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE,
|
||
|
TSL2591_ENABLE_POWEROFF };
|
||
|
|
||
|
return i2c_send((uint8_t*)&tx_stop, sizeof(tx_stop));
|
||
|
}
|
||
|
|
||
|
msg_t
|
||
|
TSL2591_setIntegrationTime(TSL2591_drv *drv,
|
||
|
TSL2591_integration_time_t time) {
|
||
|
struct __attribute__((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 __attribute__((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;
|
||
|
}
|
||
|
|