diff options
author | Stephane D'Alu <sdalu@sdalu.com> | 2016-02-08 09:37:26 +0100 |
---|---|---|
committer | Stephane D'Alu <sdalu@sdalu.com> | 2016-02-08 09:37:26 +0100 |
commit | d124d1144fc6e8234a8579a09fac314ed35074e6 (patch) | |
tree | 927a83af121c910aecf8d9d6f48e1768a86d598e | |
parent | de87b64728ef28264b622b3583442038a231c90f (diff) | |
download | ChibiOS-Contrib-d124d1144fc6e8234a8579a09fac314ed35074e6.tar.gz ChibiOS-Contrib-d124d1144fc6e8234a8579a09fac314ed35074e6.tar.bz2 ChibiOS-Contrib-d124d1144fc6e8234a8579a09fac314ed35074e6.zip |
added TSL2561 Light sesnor
-rw-r--r-- | os/various/devices_lib/sensors/hdc1000/hdc1000.c | 49 | ||||
-rw-r--r-- | os/various/devices_lib/sensors/hdc1000/hdc1000.h | 101 | ||||
-rw-r--r-- | os/various/devices_lib/sensors/mcp9808/mcp9808.c | 54 | ||||
-rw-r--r-- | os/various/devices_lib/sensors/mcp9808/mcp9808.h | 83 | ||||
-rw-r--r-- | os/various/devices_lib/sensors/tsl2561/tsl2561.c | 375 | ||||
-rw-r--r-- | os/various/devices_lib/sensors/tsl2561/tsl2561.h | 211 | ||||
-rw-r--r-- | os/various/sensor.h | 25 |
7 files changed, 750 insertions, 148 deletions
diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.c b/os/various/devices_lib/sensors/hdc1000/hdc1000.c index 47e0e5a..218450d 100644 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.c +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.c @@ -125,23 +125,20 @@ HDC1000_init(HDC1000_drv *drv, HDC1000_config *config) { HDC1000_CONFIG_RES; drv->delay = (HDC1000_DELAY_ACQUIRE + HDC1000_DELAY_ACQUIRE_SAFETY) / 1000; - drv->state = HDC1000_INIT; + drv->state = SENSOR_INIT; } msg_t HDC1000_check(HDC1000_drv *drv) { - msg_t msg = -10; - uint16_t val; + uint16_t manuf, device; - if ((msg = i2c_reg_recv16_be(HDC1000_REG_MANUF_ID, &val)) < MSG_OK) + msg_t msg; + if (((msg = i2c_reg_recv16_be(HDC1000_REG_MANUF_ID, &manuf )) < MSG_OK) || + ((msg = i2c_reg_recv16_be(HDC1000_REG_DEVICE_ID, &device)) < MSG_OK)) return msg; - if (val != HDC1000_MANUF_ID) - return -2; - if ((msg = i2c_reg_recv16_be(HDC1000_REG_DEVICE_ID, &val)) < MSG_OK) - return msg; - if (val != HDC1000_DEVICE_ID) - return -2; + if ((manuf != HDC1000_MANUF_ID) || (device != HDC1000_DEVICE_ID)) + return SENSOR_NOTFOUND; return MSG_OK; } @@ -149,22 +146,22 @@ HDC1000_check(HDC1000_drv *drv) { msg_t HDC1000_start(HDC1000_drv *drv) { - osalDbgAssert((drv->state == HDC1000_INIT ) || - (drv->state == HDC1000_ERROR ) || - (drv->state == HDC1000_STOPPED), + osalDbgAssert((drv->state == SENSOR_INIT ) || + (drv->state == SENSOR_ERROR ) || + (drv->state == SENSOR_STOPPED), "invalid state"); msg_t msg; if ((msg = _apply_config(drv)) < MSG_OK) { - drv->state = HDC1000_ERROR; + drv->state = SENSOR_ERROR; return msg; } - drv->state = HDC1000_STARTED; + drv->state = SENSOR_STARTED; return MSG_OK; } msg_t HDC1000_stop(HDC1000_drv *drv) { - drv->state = HDC1000_STOPPED; + drv->state = SENSOR_STOPPED; return MSG_OK; } @@ -175,7 +172,7 @@ HDC1000_setHeater(HDC1000_drv *drv, bool on) { msg_t msg; if ((msg = _apply_config(drv)) < MSG_OK) { - drv->state = HDC1000_ERROR; + drv->state = SENSOR_ERROR; return msg; } return MSG_OK; @@ -184,10 +181,10 @@ HDC1000_setHeater(HDC1000_drv *drv, bool on) { msg_t HDC1000_startMeasure(HDC1000_drv *drv) { msg_t msg; - osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) return msg; - drv->state = HDC1000_MEASURING; + drv->state = SENSOR_MEASURING; return MSG_OK; } @@ -195,7 +192,7 @@ HDC1000_startMeasure(HDC1000_drv *drv) { msg_t HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial) { msg_t msg; - osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); if (((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_1, (uint16_t*)&serial[0])) < MSG_OK) || @@ -214,16 +211,16 @@ HDC1000_readMeasure(HDC1000_drv *drv, msg_t msg; uint32_t val; - osalDbgAssert((drv->state == HDC1000_MEASURING) || - (drv->state == HDC1000_READY ), + osalDbgAssert((drv->state == SENSOR_MEASURING) || + (drv->state == SENSOR_READY ), "invalid state"); if ((msg = i2c_recv32_be(&val)) < MSG_OK) { - drv->state = HDC1000_ERROR; + drv->state = SENSOR_ERROR; return msg; } - drv->state = HDC1000_STARTED; + drv->state = SENSOR_STARTED; return _decode_measure(drv, val, temperature, humidity); } @@ -234,7 +231,7 @@ HDC1000_readTemperatureHumidity(HDC1000_drv *drv, msg_t msg; uint32_t val; - osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); /* Request value */ if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) @@ -245,7 +242,7 @@ HDC1000_readTemperatureHumidity(HDC1000_drv *drv, /* Get value */ if ((msg = i2c_recv32_be(&val)) < MSG_OK) { - drv->state = HDC1000_ERROR; + drv->state = SENSOR_ERROR; return msg; } diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.h b/os/various/devices_lib/sensors/hdc1000/hdc1000.h index 902b17b..9533060 100644 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.h +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.h @@ -6,6 +6,12 @@ * @file hdc1000.h * @brief HDC1000 Temperature/Humidiry sensor interface module header. * + * When changing sensor settings, you generally need to wait + * for 2 * getAquisitionTime(), as usually the first acquisition + * will be corrupted by the change of settings. + * + * No locking is done. + * * @{ */ @@ -15,6 +21,14 @@ #include <math.h> #include <stdbool.h> #include "i2c_helpers.h" +#include "sensor.h" + + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE /* I2C address */ #define HDC1000_I2CADDR_1 0x40 @@ -22,24 +36,34 @@ #define HDC1000_I2CADDR_3 0x42 #define HDC1000_I2CADDR_4 0x43 -#define HDC1000_I2CADDR_DEFAULT HDC1000_I2CADDR_1 +#define HDC1000_SERIAL_SIZE 5 /**< @brief Size of serial (40bits) */ + +/** + * @brief Time necessary for the sensor to boot + */ +#define HDC1000_BOOTUP_TIME 15 +/** + * @brief Time necessary for the sensor to start + */ +#define HDC1000_STARTUP_TIME 0 -/* Size of serial (40 bits) */ -#define HDC1000_SERIAL_SIZE 5 -#define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ -/** - * When changing sensor settings, you generally need to wait - * for 2 * getAquisitionTime(), as usually the first acquisition - * will be corrupted by the change of settings. - * - * No locking is done. - */ +#define HDC1000_I2CADDR_DEFAULT HDC1000_I2CADDR_1 +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + /** * @brief HDC1000 configuration structure. */ @@ -47,31 +71,25 @@ typedef struct { I2CHelper i2c; /* keep it first */ } HDC1000_config; - -/** - * @brief Driver state machine possible states. - */ -typedef enum __attribute__ ((__packed__)) { - HDC1000_UNINIT = 0, /**< Not initialized. */ - HDC1000_INIT = 1, /**< Initialized. */ - HDC1000_STARTED = 2, /**< Started. */ - HDC1000_MEASURING = 4, /**< Measuring. */ - HDC1000_READY = 3, /**< Ready. */ - HDC1000_STOPPED = 5, /**< Stopped. */ - HDC1000_ERROR = 6, /**< Error. */ -} HDC1000_state_t; - - /** * @brief HDC1000 configuration structure. */ typedef struct { HDC1000_config *config; - HDC1000_state_t state; + sensor_state_t state; unsigned int delay; uint16_t cfg; } HDC1000_drv; +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + /** * @brief Initialize the sensor driver */ @@ -111,30 +129,6 @@ HDC1000_setHeater(HDC1000_drv *drv, bool on); -/** - * @brief Time necessary for the sensor to boot - * - * @returns - * unsigned int time in millis-seconds - */ - -static inline unsigned int -HDC1000_getBootupTime(HDC1000_drv *drv) { - (void)drv; - return 15; -}; - -/** - * @brief Time necessary the sensor to for starting - * - * @returns - * unsigned int time in millis-seconds - */ -static inline unsigned int -HDC1000_getStartupTime(HDC1000_drv *drv) { - (void)drv; - return 0; -}; /** * @brief Time in milli-seconds necessary for acquiring a naw measure @@ -178,7 +172,7 @@ HDC1000_readMeasure(HDC1000_drv *drv, * * @note In continuous measurement mode, if you just started * the sensor, you will need to wait getAcquisitionTime() - * in addition to the usual getStartupTime() + * in addition to the usual #HDC1000_STARTUP_TIME * @note If using several sensors, it is better to start all the * measure together, wait for the sensor having the longuest @@ -229,3 +223,6 @@ HDC1000_getTemperature(HDC1000_drv *drv) { #endif +/** + * @} + */ diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.c b/os/various/devices_lib/sensors/mcp9808/mcp9808.c index df4d440..296c2f1 100644 --- a/os/various/devices_lib/sensors/mcp9808/mcp9808.c +++ b/os/various/devices_lib/sensors/mcp9808/mcp9808.c @@ -63,6 +63,16 @@ /*===========================================================================*/ static inline msg_t +_apply_config(MCP9808_drv *drv) { + struct __attribute__((packed)) { + uint8_t reg; + uint16_t conf; + } tx = { MCP9808_REG_CONFIG, cpu_to_be16(drv->cfg) }; + + return i2c_send((uint8_t*)&tx, sizeof(tx)); +} + +static inline msg_t _decode_measure(MCP9808_drv *drv, uint16_t val, float *temperature) { @@ -95,24 +105,21 @@ void MCP9808_init(MCP9808_drv *drv, MCP9808_config *config) { drv->config = config; drv->cfg = 0; - drv->resolution = RES_16; - drv->state = MCP9808_INIT; + drv->resolution = RES_16; /* power up default */ + drv->state = SENSOR_INIT; } msg_t MCP9808_check(MCP9808_drv *drv) { - msg_t msg = -10; - uint16_t val; + uint16_t manuf, device; - if ((msg = i2c_reg_recv16_be(MCP9808_REG_MANUF_ID, &val)) < MSG_OK) + msg_t msg; + if (((msg = i2c_reg_recv16_be(MCP9808_REG_MANUF_ID, &manuf )) < MSG_OK) || + ((msg = i2c_reg_recv16_be(MCP9808_REG_DEVICE_ID, &device)) < MSG_OK)) return msg; - if (val != MCP9808_MANUF_ID) - return -2; - if ((msg = i2c_reg_recv16_be(MCP9808_REG_DEVICE_ID, &val)) < MSG_OK) - return msg; - if (val != MCP9808_DEVICE_ID) - return -2; + if ((manuf != MCP9808_MANUF_ID) || (device != MCP9808_DEVICE_ID)) + return SENSOR_NOTFOUND; return MSG_OK; } @@ -132,33 +139,18 @@ MCP9808_setResolution(MCP9808_drv *drv, MCP9808_resolution_t res) { return MSG_OK; } - msg_t MCP9808_start(MCP9808_drv *drv) { drv->cfg &= ~(MCP9808_REG_CONFIG_SHUTDOWN); - - struct __attribute__((packed)) { - uint8_t reg; - uint16_t conf; - } tx = { MCP9808_REG_CONFIG, cpu_to_be16(drv->cfg) }; - - return i2c_send((uint8_t*)&tx, sizeof(tx)) >= 0; + return _apply_config(drv); } msg_t MCP9808_stop(MCP9808_drv *drv) { drv->cfg |= (MCP9808_REG_CONFIG_SHUTDOWN); - - struct __attribute__((packed)) { - uint8_t reg; - uint16_t conf; - } tx = { MCP9808_REG_CONFIG, cpu_to_be16(drv->cfg) }; - - return i2c_send((uint8_t*)&tx, sizeof(tx)) >= 0; + return _apply_config(drv); } - - unsigned int MCP9808_getAcquisitionTime(MCP9808_drv *drv) { switch(drv->resolution) { @@ -167,8 +159,8 @@ MCP9808_getAcquisitionTime(MCP9808_drv *drv) { case RES_8 : return MCP9808_DELAY_ACQUIRE_RES_8; case RES_16: return MCP9808_DELAY_ACQUIRE_RES_16; } - osalDbgAssert(false, "programming error"); - return -1; + osalDbgAssert(false, "OOPS"); + return 0; } msg_t @@ -188,7 +180,7 @@ MCP9808_readMeasure(MCP9808_drv *drv, msg_t MCP9808_readTemperature(MCP9808_drv *drv, float *temperature) { - osalDbgAssert(drv->state == MCP9808_STARTED, "invalid state"); + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); msg_t msg; uint16_t val; diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.h b/os/various/devices_lib/sensors/mcp9808/mcp9808.h index 6a8725d..2d488d7 100644 --- a/os/various/devices_lib/sensors/mcp9808/mcp9808.h +++ b/os/various/devices_lib/sensors/mcp9808/mcp9808.h @@ -6,22 +6,42 @@ #define _SENSOR_MCP9808_H_ #include <math.h> -#include <stdbool.h> #include "i2c_helpers.h" +#include "sensor.h" +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ -#define MCP9808_I2CADDR_DEFAULT 0x18 +#define MCP9808_CONTINUOUS_ACQUISITION_SUPPORTED TRUE -typedef enum { - RES_2 = 0x00, /* 1/2 = 0.5 */ - RES_4 = 0x01, /* 1/4 = 0.25 */ - RES_8 = 0x10, /* 1/8 = 0.125 */ - RES_16 = 0x11, /* 1/16 = 0.0625 */ -} MCP9808_resolution_t; +#define MCP9808_I2CADDR 0x18 -#define MCP9808_CONTINUOUS_ACQUISITION_SUPPORTED TRUE +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#define MCP9808_I2CADDR_DEFAULT MCP9808_I2CADDR + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Different possible resolution + */ +typedef enum { + RES_2 = 0x00, /**< @brief Resolution of 1/2 = 0.5 */ + RES_4 = 0x01, /**< @brief Resolution of 1/4 = 0.25 */ + RES_8 = 0x10, /**< @brief Resolution of 1/8 = 0.125 */ + RES_16 = 0x11, /**< @brief Resolution of 1/16 = 0.0625 */ +} MCP9808_resolution_t; /** * @brief MCP9808 configuration structure. @@ -30,26 +50,12 @@ typedef struct { I2CHelper i2c; /* keep it first */ } MCP9808_config; - -/** - * @brief Driver state machine possible states. - */ -typedef enum __attribute__ ((__packed__)) { - MCP9808_UNINIT = 0, /**< Not initialized. */ - MCP9808_INIT = 1, /**< Initialized. */ - MCP9808_STARTED = 2, /**< Started. */ - MCP9808_MEASURING = 4, /**< Measuring. */ - MCP9808_READY = 3, /**< Ready. */ - MCP9808_STOPPED = 5, /**< Stopped. */ - MCP9808_ERROR = 6, /**< Error. */ -} MCP9808_state_t; - /** * @brief MCP9808 configuration structure. */ typedef struct { MCP9808_config *config; - MCP9808_state_t state; + sensor_state_t state; MCP9808_resolution_t resolution; uint16_t cfg; } MCP9808_drv; @@ -61,6 +67,15 @@ typedef struct { float temperature; } MCP9808_measure; +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + /** * @brief Initialize the sensor driver */ @@ -88,8 +103,6 @@ MCP9808_start(MCP9808_drv *drv); msg_t MCP9808_stop(MCP9808_drv *drv); - - /** * @brief Control the MCP9809 resolution. */ @@ -97,7 +110,6 @@ msg_t MCP9808_setResolution(MCP9808_drv *drv, MCP9808_resolution_t res); - /** * @brief Time necessary for the sensor to boot * @@ -137,6 +149,7 @@ MCP9808_getAcquisitionTime(MCP9808_drv *drv); */ static inline msg_t MCP9808_startMeasure(MCP9808_drv *drv) { + (void)drv; return MSG_OK; } @@ -178,14 +191,11 @@ MCP9808_readTemperature(MCP9808_drv *drv, /** * @brief Return the temperature value in °C. * - * @details Use readTemperatureHumidity() for returning the humidity value. + * @note Prefere readTemperature(), if you need better error handling. * - * @note Prefere readTemperatureHumidity(), if you need both temperature - * and humidity, or if you need better error handling. - * - * @returns - * float humidity percent - * NAN on failure + * @return The temperature in °C + * @retval float humidity percent + * @retval NAN on failure */ static inline float MCP9808_getTemperature(MCP9808_drv *drv) { @@ -194,10 +204,5 @@ MCP9808_getTemperature(MCP9808_drv *drv) { return temperature; } - - - - - #endif diff --git a/os/various/devices_lib/sensors/tsl2561/tsl2561.c b/os/various/devices_lib/sensors/tsl2561/tsl2561.c new file mode 100644 index 0000000..e8372c0 --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2561/tsl2561.c @@ -0,0 +1,375 @@ +/* + TSL2561 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +#define I2C_HELPERS_AUTOMATIC_DRV TRUE + +#include "hal.h" +#include "i2c_helpers.h" +#include "tsl2561.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +// Integration time in µs +#define TSL2561_DELAY_INTTIME_SHORT 13700 // 13.7 ms +#define TSL2561_DELAY_INTTIME_MEDIUM 120000 // 120.0 ms +#define TSL2561_DELAY_INTTIME_LONG 450000 // 450.0 ms + + +#define TSL2561_COMMAND_BIT (0x80) +#define TSL2561_CLEAR_BIT (0x40) +#define TSL2561_WORD_BIT (0x20) +#define TSL2561_BLOCK_BIT (0x10) + +#define TSL2561_CONTROL_POWERON (0x03) +#define TSL2561_CONTROL_POWEROFF (0x00) + +#define TSL2561_LUX_LUXSCALE (14) +#define TSL2561_LUX_RATIOSCALE (9) +#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 +#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE +#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE + + +// 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_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 + + +// Auto-gain thresholds +#define TSL2561_AGC_THI_SHORT (4850) // Max value at Ti 13ms = 5047 +#define TSL2561_AGC_TLO_SHORT (100) +#define TSL2561_AGC_THI_MEDIUM (36000) // Max value at Ti 101ms = 37177 +#define TSL2561_AGC_TLO_MEDIUM (200) +#define TSL2561_AGC_THI_LONG (63000) // Max value at Ti 402ms = 65535 +#define TSL2561_AGC_TLO_LONG (500) + +// Clipping thresholds +#define TSL2561_CLIPPING_SHORT (4900) +#define TSL2561_CLIPPING_MEDIUM (37000) +#define TSL2561_CLIPPING_LONG (65000) + +// T, FN and CL package values +#define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE +#define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE +#define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE +#define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE +#define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE +#define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE +#define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE +#define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE +#define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE +#define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE +#define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE +#define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE +#define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE +#define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE +#define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE +#define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE +#define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE +#define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE +#define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE +#define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE + +// CS package values +#define TSL2561_LUX_K1C (0x0043) // 0.130 * 2^RATIO_SCALE +#define TSL2561_LUX_B1C (0x0204) // 0.0315 * 2^LUX_SCALE +#define TSL2561_LUX_M1C (0x01ad) // 0.0262 * 2^LUX_SCALE +#define TSL2561_LUX_K2C (0x0085) // 0.260 * 2^RATIO_SCALE +#define TSL2561_LUX_B2C (0x0228) // 0.0337 * 2^LUX_SCALE +#define TSL2561_LUX_M2C (0x02c1) // 0.0430 * 2^LUX_SCALE +#define TSL2561_LUX_K3C (0x00c8) // 0.390 * 2^RATIO_SCALE +#define TSL2561_LUX_B3C (0x0253) // 0.0363 * 2^LUX_SCALE +#define TSL2561_LUX_M3C (0x0363) // 0.0529 * 2^LUX_SCALE +#define TSL2561_LUX_K4C (0x010a) // 0.520 * 2^RATIO_SCALE +#define TSL2561_LUX_B4C (0x0282) // 0.0392 * 2^LUX_SCALE +#define TSL2561_LUX_M4C (0x03df) // 0.0605 * 2^LUX_SCALE +#define TSL2561_LUX_K5C (0x014d) // 0.65 * 2^RATIO_SCALE +#define TSL2561_LUX_B5C (0x0177) // 0.0229 * 2^LUX_SCALE +#define TSL2561_LUX_M5C (0x01dd) // 0.0291 * 2^LUX_SCALE +#define TSL2561_LUX_K6C (0x019a) // 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6C (0x0101) // 0.0157 * 2^LUX_SCALE +#define TSL2561_LUX_M6C (0x0127) // 0.0180 * 2^LUX_SCALE +#define TSL2561_LUX_K7C (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7C (0x0037) // 0.00338 * 2^LUX_SCALE +#define TSL2561_LUX_M7C (0x002b) // 0.00260 * 2^LUX_SCALE +#define TSL2561_LUX_K8C (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8C (0x0000) // 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE + + + + +#define CEILING(x,y) (((x) + (y) - 1) / (y)) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline unsigned int +calculateIlluminance(TSL2561_integration_time_t integration_time, + TSL2561_gain_t gain, + uint16_t broadband, uint16_t ir, + unsigned int partno) { + unsigned long channel_1; + unsigned long channel_0; + + /* Get value for channel scaling, and clipping */ + uint16_t clip_threshold = 0; + unsigned long channel_scale = 0; + switch (integration_time) { + case TSL2561_INTEGRATIONTIME_SHORT: + clip_threshold = TSL2561_CLIPPING_SHORT; + channel_scale = TSL2561_LUX_CHSCALE_TINT0; + break; + case TSL2561_INTEGRATIONTIME_MEDIUM: + clip_threshold = TSL2561_CLIPPING_MEDIUM; + channel_scale = TSL2561_LUX_CHSCALE_TINT1; + break; + case TSL2561_INTEGRATIONTIME_LONG: + clip_threshold = TSL2561_CLIPPING_LONG; + channel_scale = (1 << TSL2561_LUX_CHSCALE); + break; + default: + // assert failed + break; + } + + /* Check for saturated sensor (ie: clipping) */ + if ((broadband > clip_threshold) || (ir > clip_threshold)) { + return TSL2561_OVERLOADED; + } + + /* Scale for gain (1x or 16x) */ + if (gain == TSL2561_GAIN_1X) + channel_scale <<= 4; + + /* Scale the channel values */ + channel_0 = (broadband * channel_scale) >> TSL2561_LUX_CHSCALE; + channel_1 = (ir * channel_scale) >> TSL2561_LUX_CHSCALE; + + /* Find the ratio of the channel values (Channel_1/Channel_0) */ + unsigned long _ratio = 0; + if (channel_0 != 0) + _ratio = (channel_1 << (TSL2561_LUX_RATIOSCALE+1)) / channel_0; + unsigned long ratio = (_ratio + 1) >> 1; /* round the ratio value */ + + /* Find linear approximation */ + unsigned int b = 0; + unsigned int m = 0; + + switch (partno) { +#if TSL2561_WITH_CS + case 0x1: // 0001 = TSL2561 CS + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) + { b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C; } + else if (ratio <= TSL2561_LUX_K2C) + { b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C; } + else if (ratio <= TSL2561_LUX_K3C) + { b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C; } + else if (ratio <= TSL2561_LUX_K4C) + { b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C; } + else if (ratio <= TSL2561_LUX_K5C) + { b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C; } + else if (ratio <= TSL2561_LUX_K6C) + { b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C; } + else if (ratio <= TSL2561_LUX_K7C) + { b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C; } + else if (ratio > TSL2561_LUX_K8C) + { b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C; } + break; +#endif +#if TSL2561_WITH_T_FN_CL + case 0x5: // 0101 = TSL2561 T/FN/CL + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) + { b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T; } + else if (ratio <= TSL2561_LUX_K2T) + { b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T; } + else if (ratio <= TSL2561_LUX_K3T) + { b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T; } + else if (ratio <= TSL2561_LUX_K4T) + { b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T; } + else if (ratio <= TSL2561_LUX_K5T) + { b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T; } + else if (ratio <= TSL2561_LUX_K6T) + { b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T; } + else if (ratio <= TSL2561_LUX_K7T) + { b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T; } + else if (ratio > TSL2561_LUX_K8T) + { b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T; } + break; +#endif + default: + // assert failed + break; + } + + /* Compute illuminance */ + long ill = ((channel_0 * b) - (channel_1 * m)); + if (ill < 0) ill = 0; /* Do not allow negative lux value */ + ill += (1 << (TSL2561_LUX_LUXSCALE-1)); /* Round lsb (2^(LUX_SCALE-1)) */ + ill >>= TSL2561_LUX_LUXSCALE; /* Strip fractional part */ + + /* Signal I2C had no errors */ + return ill; +} + +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)) + return msg; + + + chprintf(&SD1, "CHANNELS : %x, %x\r\n", *broadband, *ir); + return MSG_OK; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void +TSL2561_init(TSL2561_drv *drv, TSL2561_config *config) { + drv->config = config; + drv->gain = TSL2561_GAIN_1X; + drv->integration_time = TSL2561_INTEGRATIONTIME_SHORT; + drv->state = SENSOR_INIT; + + i2c_reg_recv8(TSL2561_COMMAND_BIT | TSL2561_REG_ID, + (uint8_t*)&drv->id); +} + +msg_t +TSL2561_check(TSL2561_drv *drv) { + uint8_t rx; + + msg_t msg; + if ((msg = i2c_reg_recv8(TSL2561_REG_ID, &rx)) < MSG_OK) + return msg; + if (!(rx & 0x0A)) + return SENSOR_NOTFOUND; + return MSG_OK; +} + +msg_t +TSL2561_stop(TSL2561_drv *drv) { + struct PACKED { + uint8_t reg; + uint8_t conf; + } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_CONTROL, + TSL2561_CONTROL_POWEROFF }; + + return i2c_send((uint8_t*)&tx, sizeof(tx)); +} + +msg_t +TSL2561_start(TSL2561_drv *drv) { + struct PACKED { + uint8_t reg; + uint8_t conf; + } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_CONTROL, + TSL2561_CONTROL_POWERON }; + + return i2c_send((uint8_t*)&tx, sizeof(tx)); +} + +msg_t +TSL2561_setIntegrationTime(TSL2561_drv *drv, + TSL2561_integration_time_t time) { + struct PACKED { + uint8_t reg; + uint8_t conf; + } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_TIMING, + (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 +TSL2561_setGain(TSL2561_drv *drv, + TSL2561_gain_t gain) { + struct PACKED { + uint8_t reg; + uint8_t conf; + } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_TIMING, + (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 +TSL2561_getAcquisitionTime(TSL2561_drv *drv) { + switch (drv->integration_time) { + case TSL2561_INTEGRATIONTIME_SHORT: + return CEILING(TSL2561_DELAY_INTTIME_SHORT , 1000); + case TSL2561_INTEGRATIONTIME_MEDIUM: + return CEILING(TSL2561_DELAY_INTTIME_MEDIUM, 1000); + case TSL2561_INTEGRATIONTIME_LONG: + return CEILING(TSL2561_DELAY_INTTIME_LONG , 1000); + } + return -1; +} + + +msg_t +TSL2561_readIlluminance(TSL2561_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, drv->id.partno); + /* Ok */ + return SENSOR_OK; +} + diff --git a/os/various/devices_lib/sensors/tsl2561/tsl2561.h b/os/various/devices_lib/sensors/tsl2561/tsl2561.h new file mode 100644 index 0000000..16e63d3 --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2561/tsl2561.h @@ -0,0 +1,211 @@ +/* + TSL2561 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +/** + * @file tsl2561.h + * @brief TSL2561 Light sensor interface module header. + * + * @{ + */ + +#ifndef _SENSOR_TSL2561_H_ +#define _SENSOR_TSL2561_H_ + +#include <math.h> +#include "i2c_helpers.h" +#include "sensor.h" + + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define TSL2561_CONTINUOUS_ACQUISITION_SUPPORTED TRUE + +#define TSL2561_OVERLOADED (-1) + + +// I2C address +#define TSL2561_I2CADDR_LOW (0x29) +#define TSL2561_I2CADDR_FLOAT (0x39) +#define TSL2561_I2CADDR_HIGH (0x49) + + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +#ifndef TSL2561_WITH_CS +#define TSL2561_WITH_CS 0 +#endif + +#ifndef TSL2561_WITH_T_FN_CL +#define TSL2561_WITH_T_FN_CL 1 +#endif + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + + +#define TSL2561_I2CADDR_DEFAULT TSL2561_I2CADDR_FLOAT + + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief TSL2561 configuration structure. + */ +typedef struct { + I2CHelper i2c; /* keep it first */ +} TSL2561_config; + + +typedef enum { + TSL2561_INTEGRATIONTIME_SHORT = 0x00, // 13.7ms + TSL2561_INTEGRATIONTIME_MEDIUM = 0x01, // 101ms + TSL2561_INTEGRATIONTIME_LONG = 0x02, // 402ms +} TSL2561_integration_time_t; + +typedef enum { + TSL2561_GAIN_1X = 0x00, // No gain + TSL2561_GAIN_16X = 0x10, // 16x gain +} TSL2561_gain_t; + +/** + * @brief TSL2561 configuration structure. + */ +typedef struct { + TSL2561_config *config; + sensor_state_t state; + unsigned int delay; + uint16_t cfg; + TSL2561_gain_t gain; + TSL2561_integration_time_t integration_time; + struct PACKED { + uint8_t revno : 4; + uint8_t partno : 4; } id; +} TSL2561_drv; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/** + * @brief Initialize the sensor driver + */ +void +TSL2561_init(TSL2561_drv *drv, + TSL2561_config *config); + +/** + * @brief Start the sensor + */ +msg_t +TSL2561_start(TSL2561_drv *drv); + +/** + * @brief Stop the sensor + * + * @details If the sensor support it, it will be put in low energy mode. + */ +msg_t +TSL2561_stop(TSL2561_drv *drv); + +/** + * @brief Check that the sensor is really present + */ +msg_t +TSL2561_check(TSL2561_drv *drv); + +/** + * @brief Time in milli-seconds necessary for acquiring a naw measure + * + * @returns + * unsigned int time in millis-seconds + */ +unsigned int +TSL2561_getAcquisitionTime(TSL2561_drv *drv); + +/** + * @brief Trigger a mesure acquisition + */ +static inline msg_t +TSL2561_startMeasure(TSL2561_drv *drv) { + (void)drv; + return MSG_OK; +}; + +/** + * @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 +TSL2561_readMeasure(TSL2561_drv *drv, + unsigned int illuminance); + +msg_t +TSL2561_setGain(TSL2561_drv *drv, + TSL2561_gain_t gain); + +msg_t +TSL2561_setIntegrationTime(TSL2561_drv *drv, + TSL2561_integration_time_t time); + +/** + * @brief Read temperature and humidity + * + * @details According to the sensor specification/configuration + * (see #TSL2561_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 +TSL2561_readIlluminance(TSL2561_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 +TSL2561_getIlluminance(TSL2561_drv *drv) { + unsigned int illuminance = -1; + TSL2561_readIlluminance(drv, &illuminance); + return illuminance; +} + + +#endif + diff --git a/os/various/sensor.h b/os/various/sensor.h new file mode 100644 index 0000000..7e77644 --- /dev/null +++ b/os/various/sensor.h @@ -0,0 +1,25 @@ +#ifndef _SENSOR_H_ +#define _SENSOR_H_ + +#define SENSOR_OK MSG_OK /**< @brief Operation successful. */ +#define SENSOR_TIMEOUT MSG_TIMEOUT /**< @brief Communication timeout */ +#define SENSOR_RESET MSG_REST /**< @brief Communication error. */ +#define SENSOR_NOTFOUND (msg_t)-20 /**< @brief Sensor not found. */ + + +/** + * @brief Driver state machine possible states. + */ +typedef enum __attribute__ ((__packed__)) { + SENSOR_UNINIT = 0, /**< Not initialized. */ + SENSOR_INIT = 1, /**< Initialized. */ + SENSOR_STARTED = 2, /**< Started. */ + SENSOR_MEASURING = 4, /**< Measuring. */ + SENSOR_READY = 3, /**< Ready. */ + SENSOR_STOPPED = 5, /**< Stopped. */ + SENSOR_ERROR = 6, /**< Error. */ +} sensor_state_t; + +#endif + + |