From ee5bea89c258d29dd628e366940569dd9795b1a9 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 7 Feb 2016 16:48:22 +0100 Subject: hdc1008 sensor --- os/various/bswap.h | 138 ++++++++++++ os/various/devices_lib/sensors/hdc1000/bswap.h | 138 ++++++++++++ os/various/devices_lib/sensors/hdc1000/hdc1000.c | 255 ++++++++++++++++++++++ os/various/devices_lib/sensors/hdc1000/hdc1000.h | 233 ++++++++++++++++++++ os/various/i2c_helpers.h | 267 +++++++++++++++++++++++ 5 files changed, 1031 insertions(+) create mode 100644 os/various/bswap.h create mode 100644 os/various/devices_lib/sensors/hdc1000/bswap.h create mode 100644 os/various/devices_lib/sensors/hdc1000/hdc1000.c create mode 100644 os/various/devices_lib/sensors/hdc1000/hdc1000.h create mode 100644 os/various/i2c_helpers.h diff --git a/os/various/bswap.h b/os/various/bswap.h new file mode 100644 index 0000000..624e4ba --- /dev/null +++ b/os/various/bswap.h @@ -0,0 +1,138 @@ +#ifndef BSWAP_H +#define BSWAP_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) +#if YOTTA_CFG_CONFIG_ARCH_LITTLE_ENDIAN +#define ARCH_LITTLE_ENDIAN +#endif +#if YOTTA_CFG_CONFIG_ARCH_BIG_ENDIAN +#define ARCH_BIG_ENDIAN +#endif +#endif + +#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) +#error "ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set." +#endif + +#if defined(ARCH_BIG_ENDIAN) && defined(ARCH_LITTLE_ENDIAN) +#error "ARCH_BIG_ENDIAN and ARCH_LITTLE_ENDIAN are both set." +#endif + + +#define BSWAP_16(x) \ + (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) +#define BSWAP_32(x) \ + (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | \ + (((x) & 0x00FF0000UL) >> 8UL) | \ + (((x) & 0x0000FF00UL) << 8UL) | \ + (((x) & 0x000000FFUL) << 24UL)) + + +#if defined(ARCH_BIG_ENDIAN) +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define be16_to_cpu(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +#define LE16_TO_CPU(x) BSWAP_16(x) +#define LE32_TO_CPU(x) BSWAP_32(x) +#define BE16_TO_CPU(x) (x) +#define BE32_TO_CPU(x) (x) +#define CPU_TO_LE16(x) BSWAP_16(x) +#define CPU_TO_LE32(x) BSWAP_32(x) +#define CPU_TO_BE16(x) (x) +#define CPU_TO_BE32(x) (x) +#endif + + +#if defined(ARCH_LITTLE_ENDIAN) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define be16_to_cpu(x) bswap_16(x) +#define be32_to_cpu(x) bswap_32(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_be16(x) bswap_16(x) +#define cpu_to_be32(x) bswap_32(x) +#define LE16_TO_CPU(x) (x) +#define LE32_TO_CPU(x) (x) +#define BE16_TO_CPU(x) BSWAP_16(x) +#define BE32_TO_CPU(x) BSWAP_32(x) +#define CPU_TO_LE16(x) (x) +#define CPU_TO_LE32(x) (x) +#define CPU_TO_BE16(x) BSWAP_16(x) +#define CPU_TO_BE32(x) BSWAP_32(x) +#endif + + +static inline uint16_t bswap_16(const uint16_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + +static inline uint16_t bswap_16(const uint16_t x) { + if (__builtin_constant_p(x)) + return BSWAP_16(x); + + uint8_t tmp; + union { uint16_t x; uint8_t b[2]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[1]; + data.b[1] = tmp; + + return data.x; +} + +static inline uint32_t bswap_32(const uint32_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + + +static inline uint32_t bswap_32(const uint32_t x) { + if (__builtin_constant_p(x)) + return BSWAP_32(x); + + uint8_t tmp; + union { uint32_t x; uint8_t b[4]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[3]; + data.b[3] = tmp; + tmp = data.b[1]; + data.b[1] = data.b[2]; + data.b[2] = tmp; + + return data.x; +} + +static inline void bswap_n(void* const data, uint8_t len) + __attribute__ ((nonnull (1))); + +static inline void bswap_n(void* const data, uint8_t len) { + uint8_t* ptr = (uint8_t*)data; + + for ( ; len > 1 ; ptr++, len -= 2 ) { + uint8_t tmp = *ptr; + *ptr = *(ptr + len - 1); + *(ptr + len - 1) = tmp; + } +} + +#if defined(__cplusplus) +} +#endif + +#endif + + diff --git a/os/various/devices_lib/sensors/hdc1000/bswap.h b/os/various/devices_lib/sensors/hdc1000/bswap.h new file mode 100644 index 0000000..624e4ba --- /dev/null +++ b/os/various/devices_lib/sensors/hdc1000/bswap.h @@ -0,0 +1,138 @@ +#ifndef BSWAP_H +#define BSWAP_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) +#if YOTTA_CFG_CONFIG_ARCH_LITTLE_ENDIAN +#define ARCH_LITTLE_ENDIAN +#endif +#if YOTTA_CFG_CONFIG_ARCH_BIG_ENDIAN +#define ARCH_BIG_ENDIAN +#endif +#endif + +#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) +#error "ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set." +#endif + +#if defined(ARCH_BIG_ENDIAN) && defined(ARCH_LITTLE_ENDIAN) +#error "ARCH_BIG_ENDIAN and ARCH_LITTLE_ENDIAN are both set." +#endif + + +#define BSWAP_16(x) \ + (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) +#define BSWAP_32(x) \ + (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | \ + (((x) & 0x00FF0000UL) >> 8UL) | \ + (((x) & 0x0000FF00UL) << 8UL) | \ + (((x) & 0x000000FFUL) << 24UL)) + + +#if defined(ARCH_BIG_ENDIAN) +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define be16_to_cpu(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +#define LE16_TO_CPU(x) BSWAP_16(x) +#define LE32_TO_CPU(x) BSWAP_32(x) +#define BE16_TO_CPU(x) (x) +#define BE32_TO_CPU(x) (x) +#define CPU_TO_LE16(x) BSWAP_16(x) +#define CPU_TO_LE32(x) BSWAP_32(x) +#define CPU_TO_BE16(x) (x) +#define CPU_TO_BE32(x) (x) +#endif + + +#if defined(ARCH_LITTLE_ENDIAN) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define be16_to_cpu(x) bswap_16(x) +#define be32_to_cpu(x) bswap_32(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_be16(x) bswap_16(x) +#define cpu_to_be32(x) bswap_32(x) +#define LE16_TO_CPU(x) (x) +#define LE32_TO_CPU(x) (x) +#define BE16_TO_CPU(x) BSWAP_16(x) +#define BE32_TO_CPU(x) BSWAP_32(x) +#define CPU_TO_LE16(x) (x) +#define CPU_TO_LE32(x) (x) +#define CPU_TO_BE16(x) BSWAP_16(x) +#define CPU_TO_BE32(x) BSWAP_32(x) +#endif + + +static inline uint16_t bswap_16(const uint16_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + +static inline uint16_t bswap_16(const uint16_t x) { + if (__builtin_constant_p(x)) + return BSWAP_16(x); + + uint8_t tmp; + union { uint16_t x; uint8_t b[2]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[1]; + data.b[1] = tmp; + + return data.x; +} + +static inline uint32_t bswap_32(const uint32_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + + +static inline uint32_t bswap_32(const uint32_t x) { + if (__builtin_constant_p(x)) + return BSWAP_32(x); + + uint8_t tmp; + union { uint32_t x; uint8_t b[4]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[3]; + data.b[3] = tmp; + tmp = data.b[1]; + data.b[1] = data.b[2]; + data.b[2] = tmp; + + return data.x; +} + +static inline void bswap_n(void* const data, uint8_t len) + __attribute__ ((nonnull (1))); + +static inline void bswap_n(void* const data, uint8_t len) { + uint8_t* ptr = (uint8_t*)data; + + for ( ; len > 1 ; ptr++, len -= 2 ) { + uint8_t tmp = *ptr; + *ptr = *(ptr + len - 1); + *(ptr + len - 1) = tmp; + } +} + +#if defined(__cplusplus) +} +#endif + +#endif + + diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.c b/os/various/devices_lib/sensors/hdc1000/hdc1000.c new file mode 100644 index 0000000..ac8160c --- /dev/null +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.c @@ -0,0 +1,255 @@ +/* + HDC1008 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +/** + * @file HDC1000.c + * @brief HDC1000 interface module code. + * + * @addtogroup hdc1000 + * @{ + */ + +#define I2C_HELPERS_AUTOMATIC_DRV TRUE + +#include "hal.h" +#include "i2c_helpers.h" +#include "hdc1000.h" + +/* DOC: http://www.ti.com/lit/ds/symlink/hdc1008.pdf + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* I2C Register */ +#define HDC1000_REG_TEMP_HUMID 0x00 +#define HDC1000_REG_TEMP 0x00 +#define HDC1000_REG_HUMID 0x01 +#define HDC1000_REG_CONFIG 0x02 +#define HDC1000_REG_SERIAL 0xFB +#define HDC1000_REG_SERIAL_1 0xFB +#define HDC1000_REG_SERIAL_2 0xFC +#define HDC1000_REG_SERIAL_3 0xFD +#define HDC1000_REG_MANUF_ID 0xFE +#define HDC1000_REG_DEVICE_ID 0xFF + +/* Configuration */ +#define HDC1000_CONFIG_RST (1 << 15) +#define HDC1000_CONFIG_HEATER (1 << 13) +#define HDC1000_CONFIG_MODE_ONE (0 << 12) +#define HDC1000_CONFIG_MODE_BOTH (1 << 12) +#define HDC1000_CONFIG_BATT (1 << 11) +#define HDC1000_CONFIG_TRES_14 (0) +#define HDC1000_CONFIG_TRES_11 (1 << 10) +#define HDC1000_CONFIG_HRES_14 (0) +#define HDC1000_CONFIG_HRES_11 (1 << 8) +#define HDC1000_CONFIG_HRES_8 (1 << 9) + +/* Value */ +#define HDC1000_MANUF_ID 0x5449 +#define HDC1000_DEVICE_ID 0x1000 + +/* Delay in micro seconds */ +#define HDC1000_DELAY_ACQUIRE_SAFETY 1000 +#define HDC1000_DELAY_ACQUIRE_TRES_14 6350 +#define HDC1000_DELAY_ACQUIRE_TRES_11 3650 +#define HDC1000_DELAY_ACQUIRE_HRES_14 6500 +#define HDC1000_DELAY_ACQUIRE_HRES_11 3850 +#define HDC1000_DELAY_ACQUIRE_HRES_8 2500 +#define HDC1000_DELAY_STARTUP 15000 + +// Deefault config (high res) +#define HDC1000_CONFIG_RES (HDC1000_CONFIG_TRES_14 | \ + HDC1000_CONFIG_HRES_14) +#define HDC1000_DELAY_ACQUIRE (HDC1000_DELAY_ACQUIRE_TRES_14 + \ + HDC1000_DELAY_ACQUIRE_HRES_14) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +inline msg_t +_apply_config(HDC1000_drv *drv) { + struct __attribute__((packed)) { + uint8_t reg; + uint16_t conf; + } tx = { HDC1000_REG_CONFIG, cpu_to_be16(drv->cfg) }; + + return i2c_send((uint8_t*)&tx, sizeof(tx)); +} + +inline msg_t +_decode_measure(HDC1000_drv *drv, + uint32_t val, float *temperature, float *humidity) { + (void)drv; + + /* Temperature */ + if (temperature) { + float temp = (val >> 16); + temp /= 65536; + temp *= 165; + temp -= 40; + *temperature = temp; + } + + /* Humidiy */ + if (humidity) { + float hum = (val & 0xFFFF); + hum /= 65535; + hum *= 100; + *humidity = hum; + } + + return MSG_OK; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void +HDC1000_init(HDC1000_drv *drv, HDC1000_config *config) { + drv->config = config; + drv->cfg = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE_BOTH | + HDC1000_CONFIG_RES; + drv->delay = (HDC1000_DELAY_ACQUIRE + + HDC1000_DELAY_ACQUIRE_SAFETY) / 1000; + drv->state = HDC1000_INIT; +} + +msg_t +HDC1000_check(HDC1000_drv *drv) { + msg_t msg = -10; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(HDC1000_REG_MANUF_ID, &val)) < 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; + + return MSG_OK; +} + + +msg_t +HDC1000_start(HDC1000_drv *drv) { + osalDbgAssert((drv->state == HDC1000_INIT ) || + (drv->state == HDC1000_ERROR ) || + (drv->state == HDC1000_STOPPED), + "invalid state"); + msg_t msg; + if ((msg = _apply_config(drv)) < MSG_OK) { + drv->state = HDC1000_ERROR; + return msg; + } + drv->state = HDC1000_STARTED; + return MSG_OK; +} + +msg_t +HDC1000_stop(HDC1000_drv *drv) { + drv->state = HDC1000_STOPPED; + return MSG_OK; +} + +msg_t +HDC1000_setHeater(HDC1000_drv *drv, bool on) { + if (on) { drv->cfg |= HDC1000_CONFIG_HEATER; } + else { drv->cfg &= ~HDC1000_CONFIG_HEATER; } + + msg_t msg; + if ((msg = _apply_config(drv)) < MSG_OK) { + drv->state = HDC1000_ERROR; + return msg; + } + return MSG_OK; +} + +msg_t +HDC1000_startMeasure(HDC1000_drv *drv) { + msg_t msg; + osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) + return msg; + drv->state = HDC1000_MEASURING; + return MSG_OK; +} + + +msg_t +HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial) { + msg_t msg; + osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + + if (((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_1, + (uint16_t*)&serial[0])) < MSG_OK) || + ((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_2, + (uint16_t*)&serial[2])) < MSG_OK) || + ((msg = i2c_reg_recv8 (HDC1000_REG_SERIAL_3, + (uint8_t*) &serial[4])) < MSG_OK)) + return msg; + return MSG_OK; +} + + +msg_t +HDC1000_readMeasure(HDC1000_drv *drv, + float *temperature, float *humidity) { + msg_t msg; + uint32_t val; + + osalDbgAssert((drv->state == HDC1000_MEASURING) || + (drv->state == HDC1000_READY ), + "invalid state"); + + if ((msg = i2c_recv32_be(&val)) < MSG_OK) { + drv->state = HDC1000_ERROR; + return msg; + } + + drv->state = HDC1000_STARTED; + + return _decode_measure(drv, val, temperature, humidity); +} + +msg_t +HDC1000_readTemperatureHumidity(HDC1000_drv *drv, + float *temperature, float *humidity) { + msg_t msg; + uint32_t val; + + osalDbgAssert(drv->state == HDC1000_STARTED, "invalid state"); + + /* Request value */ + if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) + return msg; + + /* Wait */ + osalThreadSleepMilliseconds(drv->delay); + + /* Get value */ + if ((msg = i2c_recv32_be(&val)) < MSG_OK) { + drv->state = HDC1000_ERROR; + return msg; + } + + return _decode_measure(drv, val, temperature, humidity); +} + + +/** @} */ diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.h b/os/various/devices_lib/sensors/hdc1000/hdc1000.h new file mode 100644 index 0000000..43090d9 --- /dev/null +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.h @@ -0,0 +1,233 @@ +/* + HDC1000 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +/** + * @file hdc1000.h + * @brief HDC1000 Temperature/Humidiry sensor interface module header. + * + * @{ + */ + +#ifndef _SENSOR_HDC1000_H_ +#define _SENSOR_HDC1000_H_ + +#include +#include +#include "i2c_helpers.h" + +// I2C address +#define HDC1000_I2CADDR_1 0x40 +#define HDC1000_I2CADDR_2 0x41 +#define HDC1000_I2CADDR_3 0x42 +#define HDC1000_I2CADDR_4 0x43 + +#ifndef HDC1000_I2CADDR +#define HDC1000_I2CADDR HDC1000_I2CADDR_1 +#endif + +// Size of serial (40 bits) +#define HDC1000_SERIAL_SIZE 5 + +#define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE + + +/** + * 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. + */ + + +/** + * @brief HDC1000 configuration structure. + */ +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; + unsigned int delay; + uint16_t cfg; +} HDC1000_drv; + +/** + * @brief Initialize the sensor driver + */ +void +HDC1000_init(HDC1000_drv *drv, + HDC1000_config *config); + +/** + * @brief Start the sensor + */ +msg_t +HDC1000_start(HDC1000_drv *drv); + +/** + * @brief Stop the sensor + * + * @details If the sensor support it, it will be put in low energy mode. + */ +msg_t +HDC1000_stop(HDC1000_drv *drv); + +/** + * @brief Check that the sensor is really present + */ +msg_t +HDC1000_check(HDC1000_drv *drv); + + +msg_t +HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial); + +/** + * @brief Control the HD1000 heater. + */ +msg_t +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 + * + * @returns + * unsigned int time in millis-seconds + */ +static inline unsigned int +HDC1000_getAcquisitionTime(HDC1000_drv *drv) { + return drv->delay; +} + +/** + * @brief Trigger a mesure acquisition + */ +msg_t +HDC1000_startMeasure(HDC1000_drv *drv); + +/** + * @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 +HDC1000_readMeasure(HDC1000_drv *drv, + float *temperature, float *humidity); + + +/** + * @brief Read temperature and humidity + * + * @details According to the sensor specification/configuration + * (see #HDC1000_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 +HDC1000_readTemperatureHumidity(HDC1000_drv *drv, + float *temperature, float *humidity); + +/** + * @brief Return the humidity value in percent. + * + * @details Use readTemperatureHumidity() for returning the humidity value. + * + * @note Prefere readTemperatureHumidity(), if you need both temperature + * and humidity, or if you need better error handling. + * + * @returns + * float humidity percent + * NAN on failure + */ +static inline float +HDC1000_getHumidity(HDC1000_drv *drv) { + float humidity = NAN; + HDC1000_readTemperatureHumidity(drv, NULL, &humidity); + return humidity; +} + +/** + * @brief Return the temperature value in °C. + * + * @details Use readTemperatureHumidity() for returning the humidity value. + * + * @note Prefere readTemperatureHumidity(), if you need both temperature + * and humidity, or if you need better error handling. + * + * @returns + * float humidity percent + * NAN on failure + */ +static inline float +HDC1000_getTemperature(HDC1000_drv *drv) { + float temperature = NAN; + HDC1000_readTemperatureHumidity(drv, &temperature, NULL); + return temperature; +} + + +#endif + diff --git a/os/various/i2c_helpers.h b/os/various/i2c_helpers.h new file mode 100644 index 0000000..56f9be6 --- /dev/null +++ b/os/various/i2c_helpers.h @@ -0,0 +1,267 @@ +#ifndef I2C_HELPERS_H +#define I2C_HELPERS_H + +#include "hal.h" +#include "bswap.h" + + +typedef struct { + /** + * @brief Pointer to the I2C driver. + */ + I2CDriver *driver; + /** + * @brief I2C address. + */ + i2caddr_t addr; +} I2CHelper; + + + +#if !defined(I2C_HELPERS_AUTOMATIC_DRV) || (I2C_HELPERS_AUTOMATIC_DRV == FALSE) + +#define i2c_send(i2c, txbuf, txbytes) \ + _i2c_send(i2c, txbuf, txbytes) +#define i2c_transmit(i2c, txbuf, txbytes, rxbuf, rxbytes) \ + _i2c_transmit(i2c, txbuf, txbytes, rxbuf, rxbytes) +#define i2c_receive(i2, rxbuf, rxbytes) \ + _i2c_receive(i2c, rxbuf, rxbytes) + +#define i2c_send_timeout(i2c, txbuf, txbytes) \ + _i2c_send(i2c, txbuf, txbytes) +#define i2c_transmit_timeout(i2c, txbuf, txbytes, rxbuf, rxbytes) \ + _i2c_transmit(i2c, txbuf, txbytes, rxbuf, rxbytes) +#define i2c_receive_timeout(i2, rxbuf, rxbytes) \ + _i2c_receive(i2c, rxbuf, rxbytes) + +#define i2c_reg(i2c, reg) \ + _i2c_reg(i2c, reg) + +#define i2c_reg_recv8(i2c, reg, val) \ + _i2c_reg_recv8(i2c, reg, val) +#define i2c_reg_recv16(i2c, reg, val) \ + _i2c_reg_recv16(i2c, reg, val) +#define i2c_reg_recv16_le(i2c, reg, val) \ + _i2c_reg_recv16_le(i2c, reg, val) +#define i2c_reg_recv16_be(i2c, reg, val) \ + _i2c_reg_recv16_be(i2c, reg, val) +#define i2c_reg_recv32(i2c, reg, val) \ + _i2c_reg_recv32(i2c, reg, val) +#define i2c_reg_recv32_le(i2c, reg, val) \ + _i2c_reg_recv32_le(i2c, reg, val) +#define i2c_reg_recv32_be(i2c, reg, val) \ + _i2c_reg_recv32_be(i2c, reg, val) + +#define i2c_recv8(i2c, val) \ + _i2c_recv8(i2c, val) +#define i2c_recv16(i2c, val) \ + _i2c_recv16(i2c, val) +#define i2c_recv16_le(i2c, val) \ + _i2c_recv16_le(i2c, val) +#define i2c_recv16_be(i2c, val) \ + _i2c_recv16_be(i2c, val) +#define i2c_recv32(i2c, val) \ + _i2c_recv32(i2c, val) +#define i2c_recv32_le(i2c, val) \ + _i2c_recv32_le(i2c, val) +#define i2c_recv32_be(i2c, val) \ + _i2c_recv32_be(i2c, val) + +#else + +#define i2c_send(txbuf, txbytes) \ + _i2c_send(&drv->config->i2c, txbuf, txbytes) +#define i2c_transmit(txbuf, txbytes, rxbuf, rxbytes) \ + _i2c_transmit(&drv->config->i2c, txbuf, txbytes, rxbuf, rxbytes) +#define i2c_receive(rxbuf, rxbytes) \ + _i2c_receive(&drv->config->i2c, rxbuf, rxbytes) + +#define i2c_send_timeout(txbuf, txbytes) \ + _i2c_send(&drv->config->i2c, txbuf, txbytes) +#define i2c_transmit_timeout(txbuf, txbytes, rxbuf, rxbytes) \ + _i2c_transmit(&drv->config->i2c, txbuf, txbytes, rxbuf, rxbytes) +#define i2c_receive_timeout(rxbuf, rxbytes) \ + _i2c_receive(&drv->config->i2c, rxbuf, rxbytes) + + +#define i2c_reg(reg) \ + _i2c_reg(&drv->config->i2c, reg) + +#define i2c_reg_recv8(reg, val) \ + _i2c_reg_recv8(&drv->config->i2c, reg, val) +#define i2c_reg_recv16(reg, val) \ + _i2c_reg_recv16(&drv->config->i2c, reg, val) +#define i2c_reg_recv16_le(reg, val) \ + _i2c_reg_recv16_le(&drv->config->i2c, reg, val) +#define i2c_reg_recv16_be(reg, val) \ + _i2c_reg_recv16_be(&drv->config->i2c, reg, val) +#define i2c_reg_recv32(reg, val) \ + _i2c_reg_recv32(&drv->config->i2c, reg, val) +#define i2c_reg_recv32_le(reg, val) \ + _i2c_reg_recv32_le(&drv->config->i2c, reg, val) +#define i2c_reg_recv32_be(reg, val) \ + _i2c_reg_recv32_be(&drv->config->i2c, reg, val) + +#define i2c_recv8(val) \ + _i2c_recv8(&drv->config->i2c, val) +#define i2c_recv16(val) \ + _i2c_recv16(&drv->config->i2c, val) +#define i2c_recv16_le(val) \ + _i2c_recv16_le(&drv->config->i2c, val) +#define i2c_recv16_be(val) \ + _i2c_recv16_be(&drv->config->i2c, val) +#define i2c_recv32(val) \ + _i2c_recv32(&drv->config->i2c, val) +#define i2c_recv32_le(val) \ + _i2c_recv32_le(&drv->config->i2c, val) +#define i2c_recv32_be(val) \ + _i2c_recv32_be(&drv->config->i2c, val) + +#endif + + + + + +static inline msg_t +_i2c_send(I2CHelper *i2c, const uint8_t *txbuf, size_t txbytes) { + return i2cMasterTransmitTimeout(i2c->driver, i2c->addr, + txbuf, txbytes, NULL, 0, TIME_INFINITE); +}; + +static inline msg_t +_i2c_transmit(I2CHelper *i2c, const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes) { + return i2cMasterTransmitTimeout(i2c->driver, i2c->addr, + txbuf, txbytes, rxbuf, rxbytes, TIME_INFINITE); +} + +static inline msg_t +_i2c_receive(I2CHelper *i2c, uint8_t *rxbuf, size_t rxbytes) { + return i2cMasterReceiveTimeout(i2c->driver, i2c->addr, + rxbuf, rxbytes, TIME_INFINITE); +}; + + + +static inline msg_t +_i2c_send_timeout(I2CHelper *i2c, const uint8_t *txbuf, size_t txbytes, + systime_t timeout) { + return i2cMasterTransmitTimeout(i2c->driver, i2c->addr, + txbuf, txbytes, NULL, 0, timeout); +}; + +static inline msg_t +_i2c_transmit_timeout(I2CHelper *i2c, const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { + return i2cMasterTransmitTimeout(i2c->driver, i2c->addr, + txbuf, txbytes, rxbuf, rxbytes, timeout); +} + +static inline msg_t +_i2c_receive_timeout(I2CHelper *i2c, uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { + return i2cMasterReceiveTimeout(i2c->driver, i2c->addr, + rxbuf, rxbytes, timeout); +}; + + +/*======================================================================*/ + + +static inline msg_t +_i2c_reg(I2CHelper *i2c, uint8_t reg) { + return _i2c_transmit(i2c, ®, sizeof(reg), NULL, 0); +}; + +/*======================================================================*/ + +static inline msg_t +_i2c_reg_recv8(I2CHelper *i2c, uint8_t reg, uint8_t *val) { + return _i2c_transmit(i2c, ®, sizeof(reg), (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_reg_recv16(I2CHelper *i2c, uint8_t reg, uint16_t *val) { + return _i2c_transmit(i2c, ®, sizeof(reg), (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_reg_recv16_le(I2CHelper *i2c, uint8_t reg, uint16_t *val) { + int msg = _i2c_reg_recv16(i2c, reg, val); + if (msg >= 0) *val = le16_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_reg_recv16_be(I2CHelper *i2c, uint8_t reg, uint16_t *val) { + int msg = _i2c_reg_recv16(i2c, reg, val); + if (msg >= 0) *val = be16_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_reg_recv32(I2CHelper *i2c, uint8_t reg, uint32_t *val) { + return _i2c_transmit(i2c, ®, sizeof(reg), (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_reg_recv32_le(I2CHelper *i2c, uint8_t reg, uint32_t *val) { + int msg = _i2c_reg_recv32(i2c, reg, val); + if (msg >= 0) *val = le32_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_reg_recv32_be(I2CHelper *i2c, uint8_t reg, uint32_t *val) { + int msg = _i2c_reg_recv32(i2c, reg, val); + if (msg >= 0) *val = be32_to_cpu(*val); + return msg; +}; + + +/*======================================================================*/ + +static inline msg_t +_i2c_recv8(I2CHelper *i2c, uint8_t *val) { + return _i2c_receive(i2c, (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_recv16(I2CHelper *i2c, uint16_t *val) { + return _i2c_receive(i2c, (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_recv16_le(I2CHelper *i2c, uint16_t *val) { + int msg = _i2c_recv16(i2c, val); + if (msg >= 0) *val = le16_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_recv16_be(I2CHelper *i2c, uint16_t *val) { + int msg = _i2c_recv16(i2c, val); + if (msg >= 0) *val = be16_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_recv32(I2CHelper *i2c, uint32_t *val) { + return _i2c_receive(i2c, (uint8_t*)val, sizeof(val)); +}; + +static inline msg_t +_i2c_recv32_le(I2CHelper *i2c, uint32_t *val) { + int msg = _i2c_recv32(i2c, val); + if (msg >= 0) *val = le32_to_cpu(*val); + return msg; +}; + +static inline msg_t +_i2c_recv32_be(I2CHelper *i2c, uint32_t *val) { + int msg = _i2c_recv32(i2c, val); + if (msg >= 0) *val = be32_to_cpu(*val); + return msg; +}; + +#endif -- cgit v1.2.3 From 12992db45cf71b0b729644452e2eb1966eb7a575 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 7 Feb 2016 17:05:10 +0100 Subject: fixed comments, set default i2c address --- os/various/devices_lib/sensors/hdc1000/hdc1000.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.h b/os/various/devices_lib/sensors/hdc1000/hdc1000.h index 43090d9..8522ecb 100644 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.h +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.h @@ -16,17 +16,16 @@ #include #include "i2c_helpers.h" -// I2C address +/* I2C address */ #define HDC1000_I2CADDR_1 0x40 #define HDC1000_I2CADDR_2 0x41 #define HDC1000_I2CADDR_3 0x42 #define HDC1000_I2CADDR_4 0x43 -#ifndef HDC1000_I2CADDR -#define HDC1000_I2CADDR HDC1000_I2CADDR_1 -#endif +#define HDC1000_I2CADDR_DEFAULT HDC1000_I2CADDR_1 + -// Size of serial (40 bits) +/* Size of serial (40 bits) */ #define HDC1000_SERIAL_SIZE 5 #define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE -- cgit v1.2.3 From 7ecdfd4386abe1bd27a92da87a5a487a946c1165 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 7 Feb 2016 18:54:54 +0100 Subject: mcp9808 temperature sensor --- os/various/devices_lib/sensors/mcp9808/mcp9808.c | 200 +++++++++++++++++++++++ os/various/devices_lib/sensors/mcp9808/mcp9808.h | 196 ++++++++++++++++++++++ 2 files changed, 396 insertions(+) create mode 100644 os/various/devices_lib/sensors/mcp9808/mcp9808.c create mode 100644 os/various/devices_lib/sensors/mcp9808/mcp9808.h diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.c b/os/various/devices_lib/sensors/mcp9808/mcp9808.c new file mode 100644 index 0000000..df4d440 --- /dev/null +++ b/os/various/devices_lib/sensors/mcp9808/mcp9808.c @@ -0,0 +1,200 @@ + +#define I2C_HELPERS_AUTOMATIC_DRV TRUE + +#include "hal.h" +#include "i2c_helpers.h" +#include "mcp9808.h" + +// http://www.mouser.com/ds/2/268/25095A-15487.pdf +// http://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf + + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* I2C Register */ +#define MCP9808_REG_CONFIG 0x01 +#define MCP9808_REG_UPPER_TEMP 0x02 +#define MCP9808_REG_LOWER_TEMP 0x03 +#define MCP9808_REG_CRIT_TEMP 0x04 +#define MCP9808_REG_AMBIENT_TEMP 0x05 +#define MCP9808_REG_MANUF_ID 0x06 +#define MCP9808_REG_DEVICE_ID 0x07 +#define MCP9808_REG_RESOLUTION 0x08 + +/* Config */ +#define MCP9808_REG_CONFIG_SHUTDOWN 0x0100 +#define MCP9808_REG_CONFIG_CRITLOCKED 0x0080 +#define MCP9808_REG_CONFIG_WINLOCKED 0x0040 +#define MCP9808_REG_CONFIG_INTCLR 0x0020 +#define MCP9808_REG_CONFIG_ALERTSTAT 0x0010 +#define MCP9808_REG_CONFIG_ALERTCTRL 0x0008 +#define MCP9808_REG_CONFIG_ALERTSEL 0x0002 +#define MCP9808_REG_CONFIG_ALERTPOL 0x0002 +#define MCP9808_REG_CONFIG_ALERTMODE 0x0001 + +/* Device Id */ +#define MCP9808_MANUF_ID 0x0054 +#define MCP9808_DEVICE_ID 0x0400 + +/* Resolution */ +#define MCP9808_RES_2 0x00 /* 1/2 = 0.5 */ +#define MCP9808_RES_4 0x01 /* 1/4 = 0.25 */ +#define MCP9808_RES_8 0x10 /* 1/8 = 0.125 */ +#define MCP9808_RES_16 0x11 /* 1/16 = 0.0625 */ + +/* Time in milli-seconds */ +#define MCP9808_DELAY_ACQUIRE_RES_2 30 +#define MCP9808_DELAY_ACQUIRE_RES_4 65 +#define MCP9808_DELAY_ACQUIRE_RES_8 130 +#define MCP9808_DELAY_ACQUIRE_RES_16 250 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline msg_t +_decode_measure(MCP9808_drv *drv, + uint16_t val, float *temperature) { + + /* Temperature */ + if (temperature) { + float temp = val & 0x0fff; + if (val & 0x1000) temp -= 0x1000; + + float factor = 16.0F; + switch(drv->resolution) { + case RES_2 : factor = 2.0F; break; + case RES_4 : factor = 4.0F; break; + case RES_8 : factor = 8.0F; break; + case RES_16: factor = 16.0F; break; + } + + *temperature = temp / factor; + } + + /* Ok */ + return MSG_OK; +} + + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void +MCP9808_init(MCP9808_drv *drv, MCP9808_config *config) { + drv->config = config; + drv->cfg = 0; + drv->resolution = RES_16; + drv->state = MCP9808_INIT; +} + +msg_t +MCP9808_check(MCP9808_drv *drv) { + msg_t msg = -10; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(MCP9808_REG_MANUF_ID, &val)) < 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; + + return MSG_OK; +} + +msg_t +MCP9808_setResolution(MCP9808_drv *drv, MCP9808_resolution_t res) { + struct __attribute__((packed)) { + uint8_t reg; + uint8_t resolution; + } tx = { MCP9808_REG_RESOLUTION, res }; + + msg_t msg; + if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK) + return msg; + + drv->resolution = 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; +} + +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; +} + + + +unsigned int +MCP9808_getAcquisitionTime(MCP9808_drv *drv) { + switch(drv->resolution) { + case RES_2 : return MCP9808_DELAY_ACQUIRE_RES_2; + case RES_4 : return MCP9808_DELAY_ACQUIRE_RES_4; + case RES_8 : return MCP9808_DELAY_ACQUIRE_RES_8; + case RES_16: return MCP9808_DELAY_ACQUIRE_RES_16; + } + osalDbgAssert(false, "programming error"); + return -1; +} + +msg_t +MCP9808_readMeasure(MCP9808_drv *drv, + float *temperature) { + + msg_t msg; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) + return msg; + + return _decode_measure(drv, val, temperature); +} + + +msg_t +MCP9808_readTemperature(MCP9808_drv *drv, + float *temperature) { + osalDbgAssert(drv->state == MCP9808_STARTED, "invalid state"); + + msg_t msg; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) + return msg; + + return _decode_measure(drv, val, temperature); +} diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.h b/os/various/devices_lib/sensors/mcp9808/mcp9808.h new file mode 100644 index 0000000..74540b4 --- /dev/null +++ b/os/various/devices_lib/sensors/mcp9808/mcp9808.h @@ -0,0 +1,196 @@ +/* + MCP9808 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +#ifndef _SENSOR_MCP9808_H_ +#define _SENSOR_MCP9808_H_ + +#include +#include +#include "i2c_helpers.h" + + +#define MCP9808_I2CADDR_DEFAULT 0x18 + +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_CONTINUOUS_ACQUISITION_SUPPORTED TRUE + +/** + * @brief MCP9808 configuration structure. + */ +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; + MCP9808_resolution_t resolution; + uint16_t cfg; +} MCP9808_drv; + +/** + * @brief Initialize the sensor driver + */ +void +MCP9808_init(MCP9808_drv *drv, + MCP9808_config *config); + +/** + * @brief Check that the sensor is really present + */ +msg_t +MCP9808_check(MCP9808_drv *drv); + +/** + * @brief Start the sensor + */ +msg_t +MCP9808_start(MCP9808_drv *drv); + +/** + * @brief Stop the sensor + * + * @details If the sensor support it, it will be put in low energy mode. + */ +msg_t +MCP9808_stop(MCP9808_drv *drv); + + + +/** + * @brief Control the MCP9809 resolution. + */ +msg_t +MCP9808_setResolution(MCP9808_drv *drv, + MCP9808_resolution_t res); + + +/** + * @brief Time necessary for the sensor to boot + * + * @returns + * unsigned int time in millis-seconds + */ + +static inline unsigned int +MCP9808_getBootupTime(MCP9808_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 +MCP9808_getStartupTime(MCP9808_drv *drv) { + (void)drv; + return 0; +}; + +/** + * @brief Time in milli-seconds necessary for acquiring a naw measure + * + * @returns + * unsigned int time in millis-seconds + */ +unsigned int +MCP9808_getAcquisitionTime(MCP9808_drv *drv); + +/** + * @brief Trigger a mesure acquisition + */ +static inline msg_t +MCP9808_startMeasure(MCP9808_drv *drv) { +} + +/** + * @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 +MCP9808_readMeasure(MCP9808_drv *drv, + float *temperature); + + +/** + * @brief Read temperature and humidity + * + * @details According to the sensor specification/configuration + * (see #MCP9808_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 +MCP9808_readTemperature(MCP9808_drv *drv, + float *temperature); + +/** + * @brief Return the temperature value in °C. + * + * @details Use readTemperatureHumidity() for returning the humidity value. + * + * @note Prefere readTemperatureHumidity(), if you need both temperature + * and humidity, or if you need better error handling. + * + * @returns + * float humidity percent + * NAN on failure + */ +static inline float +MCP9808_getTemperature(MCP9808_drv *drv) { + float temperature = NAN; + MCP9808_readTemperature(drv, &temperature); + return temperature; +} + + + + + + +#endif + -- cgit v1.2.3 From bd884d47577f398dfef251011ec82c81de9a84d7 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 7 Feb 2016 18:55:45 +0100 Subject: cleanup --- os/various/devices_lib/sensors/hdc1000/bswap.h | 138 ----------------------- os/various/devices_lib/sensors/hdc1000/hdc1000.c | 5 +- os/various/devices_lib/sensors/hdc1000/hdc1000.h | 1 - 3 files changed, 3 insertions(+), 141 deletions(-) delete mode 100644 os/various/devices_lib/sensors/hdc1000/bswap.h diff --git a/os/various/devices_lib/sensors/hdc1000/bswap.h b/os/various/devices_lib/sensors/hdc1000/bswap.h deleted file mode 100644 index 624e4ba..0000000 --- a/os/various/devices_lib/sensors/hdc1000/bswap.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef BSWAP_H -#define BSWAP_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) -#if YOTTA_CFG_CONFIG_ARCH_LITTLE_ENDIAN -#define ARCH_LITTLE_ENDIAN -#endif -#if YOTTA_CFG_CONFIG_ARCH_BIG_ENDIAN -#define ARCH_BIG_ENDIAN -#endif -#endif - -#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) -#error "ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set." -#endif - -#if defined(ARCH_BIG_ENDIAN) && defined(ARCH_LITTLE_ENDIAN) -#error "ARCH_BIG_ENDIAN and ARCH_LITTLE_ENDIAN are both set." -#endif - - -#define BSWAP_16(x) \ - (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) -#define BSWAP_32(x) \ - (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | \ - (((x) & 0x00FF0000UL) >> 8UL) | \ - (((x) & 0x0000FF00UL) << 8UL) | \ - (((x) & 0x000000FFUL) << 24UL)) - - -#if defined(ARCH_BIG_ENDIAN) -#define le16_to_cpu(x) bswap_16(x) -#define le32_to_cpu(x) bswap_32(x) -#define be16_to_cpu(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_le16(x) bswap_16(x) -#define cpu_to_le32(x) bswap_32(x) -#define cpu_to_be16(x) (x) -#define cpu_to_be32(x) (x) -#define LE16_TO_CPU(x) BSWAP_16(x) -#define LE32_TO_CPU(x) BSWAP_32(x) -#define BE16_TO_CPU(x) (x) -#define BE32_TO_CPU(x) (x) -#define CPU_TO_LE16(x) BSWAP_16(x) -#define CPU_TO_LE32(x) BSWAP_32(x) -#define CPU_TO_BE16(x) (x) -#define CPU_TO_BE32(x) (x) -#endif - - -#if defined(ARCH_LITTLE_ENDIAN) -#define le16_to_cpu(x) (x) -#define le32_to_cpu(x) (x) -#define be16_to_cpu(x) bswap_16(x) -#define be32_to_cpu(x) bswap_32(x) -#define cpu_to_le16(x) (x) -#define cpu_to_le32(x) (x) -#define cpu_to_be16(x) bswap_16(x) -#define cpu_to_be32(x) bswap_32(x) -#define LE16_TO_CPU(x) (x) -#define LE32_TO_CPU(x) (x) -#define BE16_TO_CPU(x) BSWAP_16(x) -#define BE32_TO_CPU(x) BSWAP_32(x) -#define CPU_TO_LE16(x) (x) -#define CPU_TO_LE32(x) (x) -#define CPU_TO_BE16(x) BSWAP_16(x) -#define CPU_TO_BE32(x) BSWAP_32(x) -#endif - - -static inline uint16_t bswap_16(const uint16_t x) - __attribute__ ((warn_unused_result)) - __attribute__ ((const)) - __attribute__ ((always_inline)); - -static inline uint16_t bswap_16(const uint16_t x) { - if (__builtin_constant_p(x)) - return BSWAP_16(x); - - uint8_t tmp; - union { uint16_t x; uint8_t b[2]; } data; - - data.x = x; - tmp = data.b[0]; - data.b[0] = data.b[1]; - data.b[1] = tmp; - - return data.x; -} - -static inline uint32_t bswap_32(const uint32_t x) - __attribute__ ((warn_unused_result)) - __attribute__ ((const)) - __attribute__ ((always_inline)); - - -static inline uint32_t bswap_32(const uint32_t x) { - if (__builtin_constant_p(x)) - return BSWAP_32(x); - - uint8_t tmp; - union { uint32_t x; uint8_t b[4]; } data; - - data.x = x; - tmp = data.b[0]; - data.b[0] = data.b[3]; - data.b[3] = tmp; - tmp = data.b[1]; - data.b[1] = data.b[2]; - data.b[2] = tmp; - - return data.x; -} - -static inline void bswap_n(void* const data, uint8_t len) - __attribute__ ((nonnull (1))); - -static inline void bswap_n(void* const data, uint8_t len) { - uint8_t* ptr = (uint8_t*)data; - - for ( ; len > 1 ; ptr++, len -= 2 ) { - uint8_t tmp = *ptr; - *ptr = *(ptr + len - 1); - *(ptr + len - 1) = tmp; - } -} - -#if defined(__cplusplus) -} -#endif - -#endif - - diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.c b/os/various/devices_lib/sensors/hdc1000/hdc1000.c index ac8160c..47e0e5a 100644 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.c +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.c @@ -78,7 +78,7 @@ /* Driver local functions. */ /*===========================================================================*/ -inline msg_t +static inline msg_t _apply_config(HDC1000_drv *drv) { struct __attribute__((packed)) { uint8_t reg; @@ -88,7 +88,7 @@ _apply_config(HDC1000_drv *drv) { return i2c_send((uint8_t*)&tx, sizeof(tx)); } -inline msg_t +static inline msg_t _decode_measure(HDC1000_drv *drv, uint32_t val, float *temperature, float *humidity) { (void)drv; @@ -110,6 +110,7 @@ _decode_measure(HDC1000_drv *drv, *humidity = hum; } + /* ok */ return MSG_OK; } diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.h b/os/various/devices_lib/sensors/hdc1000/hdc1000.h index 8522ecb..902b17b 100644 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.h +++ b/os/various/devices_lib/sensors/hdc1000/hdc1000.h @@ -62,7 +62,6 @@ typedef enum __attribute__ ((__packed__)) { } HDC1000_state_t; - /** * @brief HDC1000 configuration structure. */ -- cgit v1.2.3 From de87b64728ef28264b622b3583442038a231c90f Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 7 Feb 2016 19:26:02 +0100 Subject: small fix --- os/various/devices_lib/sensors/mcp9808/mcp9808.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.h b/os/various/devices_lib/sensors/mcp9808/mcp9808.h index 74540b4..6a8725d 100644 --- a/os/various/devices_lib/sensors/mcp9808/mcp9808.h +++ b/os/various/devices_lib/sensors/mcp9808/mcp9808.h @@ -44,7 +44,6 @@ typedef enum __attribute__ ((__packed__)) { MCP9808_ERROR = 6, /**< Error. */ } MCP9808_state_t; - /** * @brief MCP9808 configuration structure. */ @@ -55,6 +54,13 @@ typedef struct { uint16_t cfg; } MCP9808_drv; +/** + * @brief MCP9808 measure reading + */ +typedef struct { + float temperature; +} MCP9808_measure; + /** * @brief Initialize the sensor driver */ @@ -102,7 +108,7 @@ MCP9808_setResolution(MCP9808_drv *drv, static inline unsigned int MCP9808_getBootupTime(MCP9808_drv *drv) { (void)drv; - return 15; + return 0; /* no info found */ }; /** @@ -114,7 +120,7 @@ MCP9808_getBootupTime(MCP9808_drv *drv) { static inline unsigned int MCP9808_getStartupTime(MCP9808_drv *drv) { (void)drv; - return 0; + return 0; /* no info found */ }; /** @@ -131,6 +137,7 @@ MCP9808_getAcquisitionTime(MCP9808_drv *drv); */ static inline msg_t MCP9808_startMeasure(MCP9808_drv *drv) { + return MSG_OK; } /** -- cgit v1.2.3 From d124d1144fc6e8234a8579a09fac314ed35074e6 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 8 Feb 2016 09:37:26 +0100 Subject: added TSL2561 Light sesnor --- os/various/devices_lib/sensors/hdc1000/hdc1000.c | 49 ++- os/various/devices_lib/sensors/hdc1000/hdc1000.h | 101 +++--- os/various/devices_lib/sensors/mcp9808/mcp9808.c | 54 ++-- os/various/devices_lib/sensors/mcp9808/mcp9808.h | 83 ++--- os/various/devices_lib/sensors/tsl2561/tsl2561.c | 375 +++++++++++++++++++++++ os/various/devices_lib/sensors/tsl2561/tsl2561.h | 211 +++++++++++++ os/various/sensor.h | 25 ++ 7 files changed, 750 insertions(+), 148 deletions(-) create mode 100644 os/various/devices_lib/sensors/tsl2561/tsl2561.c create mode 100644 os/various/devices_lib/sensors/tsl2561/tsl2561.h create mode 100644 os/various/sensor.h 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 #include #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 @@ -62,6 +62,16 @@ /* Driver local functions. */ /*===========================================================================*/ +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 -#include #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 +#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 + + -- cgit v1.2.3 From 08fa41749ed577e71f04854e5176ae61fd7c036b Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 8 Feb 2016 12:13:15 +0100 Subject: changed file layout, move startup/bootup time to #define --- os/various/devices_lib/sensors/hdc1000.c | 253 +++++++++++++++ os/various/devices_lib/sensors/hdc1000.h | 228 ++++++++++++++ os/various/devices_lib/sensors/hdc1000/hdc1000.c | 253 --------------- os/various/devices_lib/sensors/hdc1000/hdc1000.h | 228 -------------- os/various/devices_lib/sensors/mcp9808.c | 192 ++++++++++++ os/various/devices_lib/sensors/mcp9808.h | 192 ++++++++++++ os/various/devices_lib/sensors/mcp9808/mcp9808.c | 192 ------------ os/various/devices_lib/sensors/mcp9808/mcp9808.h | 208 ------------- os/various/devices_lib/sensors/sensor.h | 66 ++++ os/various/devices_lib/sensors/tsl2561.c | 372 ++++++++++++++++++++++ os/various/devices_lib/sensors/tsl2561.h | 221 +++++++++++++ os/various/devices_lib/sensors/tsl2561/tsl2561.c | 375 ----------------------- os/various/devices_lib/sensors/tsl2561/tsl2561.h | 211 ------------- os/various/sensor.h | 25 -- 14 files changed, 1524 insertions(+), 1492 deletions(-) create mode 100644 os/various/devices_lib/sensors/hdc1000.c create mode 100644 os/various/devices_lib/sensors/hdc1000.h delete mode 100644 os/various/devices_lib/sensors/hdc1000/hdc1000.c delete mode 100644 os/various/devices_lib/sensors/hdc1000/hdc1000.h create mode 100644 os/various/devices_lib/sensors/mcp9808.c create mode 100644 os/various/devices_lib/sensors/mcp9808.h delete mode 100644 os/various/devices_lib/sensors/mcp9808/mcp9808.c delete mode 100644 os/various/devices_lib/sensors/mcp9808/mcp9808.h create mode 100644 os/various/devices_lib/sensors/sensor.h create mode 100644 os/various/devices_lib/sensors/tsl2561.c create mode 100644 os/various/devices_lib/sensors/tsl2561.h delete mode 100644 os/various/devices_lib/sensors/tsl2561/tsl2561.c delete mode 100644 os/various/devices_lib/sensors/tsl2561/tsl2561.h delete mode 100644 os/various/sensor.h diff --git a/os/various/devices_lib/sensors/hdc1000.c b/os/various/devices_lib/sensors/hdc1000.c new file mode 100644 index 0000000..218450d --- /dev/null +++ b/os/various/devices_lib/sensors/hdc1000.c @@ -0,0 +1,253 @@ +/* + HDC1008 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +/** + * @file HDC1000.c + * @brief HDC1000 interface module code. + * + * @addtogroup hdc1000 + * @{ + */ + +#define I2C_HELPERS_AUTOMATIC_DRV TRUE + +#include "hal.h" +#include "i2c_helpers.h" +#include "hdc1000.h" + +/* DOC: http://www.ti.com/lit/ds/symlink/hdc1008.pdf + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* I2C Register */ +#define HDC1000_REG_TEMP_HUMID 0x00 +#define HDC1000_REG_TEMP 0x00 +#define HDC1000_REG_HUMID 0x01 +#define HDC1000_REG_CONFIG 0x02 +#define HDC1000_REG_SERIAL 0xFB +#define HDC1000_REG_SERIAL_1 0xFB +#define HDC1000_REG_SERIAL_2 0xFC +#define HDC1000_REG_SERIAL_3 0xFD +#define HDC1000_REG_MANUF_ID 0xFE +#define HDC1000_REG_DEVICE_ID 0xFF + +/* Configuration */ +#define HDC1000_CONFIG_RST (1 << 15) +#define HDC1000_CONFIG_HEATER (1 << 13) +#define HDC1000_CONFIG_MODE_ONE (0 << 12) +#define HDC1000_CONFIG_MODE_BOTH (1 << 12) +#define HDC1000_CONFIG_BATT (1 << 11) +#define HDC1000_CONFIG_TRES_14 (0) +#define HDC1000_CONFIG_TRES_11 (1 << 10) +#define HDC1000_CONFIG_HRES_14 (0) +#define HDC1000_CONFIG_HRES_11 (1 << 8) +#define HDC1000_CONFIG_HRES_8 (1 << 9) + +/* Value */ +#define HDC1000_MANUF_ID 0x5449 +#define HDC1000_DEVICE_ID 0x1000 + +/* Delay in micro seconds */ +#define HDC1000_DELAY_ACQUIRE_SAFETY 1000 +#define HDC1000_DELAY_ACQUIRE_TRES_14 6350 +#define HDC1000_DELAY_ACQUIRE_TRES_11 3650 +#define HDC1000_DELAY_ACQUIRE_HRES_14 6500 +#define HDC1000_DELAY_ACQUIRE_HRES_11 3850 +#define HDC1000_DELAY_ACQUIRE_HRES_8 2500 +#define HDC1000_DELAY_STARTUP 15000 + +// Deefault config (high res) +#define HDC1000_CONFIG_RES (HDC1000_CONFIG_TRES_14 | \ + HDC1000_CONFIG_HRES_14) +#define HDC1000_DELAY_ACQUIRE (HDC1000_DELAY_ACQUIRE_TRES_14 + \ + HDC1000_DELAY_ACQUIRE_HRES_14) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline msg_t +_apply_config(HDC1000_drv *drv) { + struct __attribute__((packed)) { + uint8_t reg; + uint16_t conf; + } tx = { HDC1000_REG_CONFIG, cpu_to_be16(drv->cfg) }; + + return i2c_send((uint8_t*)&tx, sizeof(tx)); +} + +static inline msg_t +_decode_measure(HDC1000_drv *drv, + uint32_t val, float *temperature, float *humidity) { + (void)drv; + + /* Temperature */ + if (temperature) { + float temp = (val >> 16); + temp /= 65536; + temp *= 165; + temp -= 40; + *temperature = temp; + } + + /* Humidiy */ + if (humidity) { + float hum = (val & 0xFFFF); + hum /= 65535; + hum *= 100; + *humidity = hum; + } + + /* ok */ + return MSG_OK; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void +HDC1000_init(HDC1000_drv *drv, HDC1000_config *config) { + drv->config = config; + drv->cfg = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE_BOTH | + HDC1000_CONFIG_RES; + drv->delay = (HDC1000_DELAY_ACQUIRE + + HDC1000_DELAY_ACQUIRE_SAFETY) / 1000; + drv->state = SENSOR_INIT; +} + +msg_t +HDC1000_check(HDC1000_drv *drv) { + uint16_t manuf, device; + + 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 ((manuf != HDC1000_MANUF_ID) || (device != HDC1000_DEVICE_ID)) + return SENSOR_NOTFOUND; + + return MSG_OK; +} + + +msg_t +HDC1000_start(HDC1000_drv *drv) { + 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 = SENSOR_ERROR; + return msg; + } + drv->state = SENSOR_STARTED; + return MSG_OK; +} + +msg_t +HDC1000_stop(HDC1000_drv *drv) { + drv->state = SENSOR_STOPPED; + return MSG_OK; +} + +msg_t +HDC1000_setHeater(HDC1000_drv *drv, bool on) { + if (on) { drv->cfg |= HDC1000_CONFIG_HEATER; } + else { drv->cfg &= ~HDC1000_CONFIG_HEATER; } + + msg_t msg; + if ((msg = _apply_config(drv)) < MSG_OK) { + drv->state = SENSOR_ERROR; + return msg; + } + return MSG_OK; +} + +msg_t +HDC1000_startMeasure(HDC1000_drv *drv) { + msg_t msg; + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); + if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) + return msg; + drv->state = SENSOR_MEASURING; + return MSG_OK; +} + + +msg_t +HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial) { + msg_t msg; + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); + + if (((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_1, + (uint16_t*)&serial[0])) < MSG_OK) || + ((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_2, + (uint16_t*)&serial[2])) < MSG_OK) || + ((msg = i2c_reg_recv8 (HDC1000_REG_SERIAL_3, + (uint8_t*) &serial[4])) < MSG_OK)) + return msg; + return MSG_OK; +} + + +msg_t +HDC1000_readMeasure(HDC1000_drv *drv, + float *temperature, float *humidity) { + msg_t msg; + uint32_t val; + + osalDbgAssert((drv->state == SENSOR_MEASURING) || + (drv->state == SENSOR_READY ), + "invalid state"); + + if ((msg = i2c_recv32_be(&val)) < MSG_OK) { + drv->state = SENSOR_ERROR; + return msg; + } + + drv->state = SENSOR_STARTED; + + return _decode_measure(drv, val, temperature, humidity); +} + +msg_t +HDC1000_readTemperatureHumidity(HDC1000_drv *drv, + float *temperature, float *humidity) { + msg_t msg; + uint32_t val; + + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); + + /* Request value */ + if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) + return msg; + + /* Wait */ + osalThreadSleepMilliseconds(drv->delay); + + /* Get value */ + if ((msg = i2c_recv32_be(&val)) < MSG_OK) { + drv->state = SENSOR_ERROR; + return msg; + } + + return _decode_measure(drv, val, temperature, humidity); +} + + +/** @} */ diff --git a/os/various/devices_lib/sensors/hdc1000.h b/os/various/devices_lib/sensors/hdc1000.h new file mode 100644 index 0000000..9533060 --- /dev/null +++ b/os/various/devices_lib/sensors/hdc1000.h @@ -0,0 +1,228 @@ +/* + HDC1000 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +/** + * @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. + * + * @{ + */ + +#ifndef _SENSOR_HDC1000_H_ +#define _SENSOR_HDC1000_H_ + +#include +#include +#include "i2c_helpers.h" +#include "sensor.h" + + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE + +/* I2C address */ +#define HDC1000_I2CADDR_1 0x40 +#define HDC1000_I2CADDR_2 0x41 +#define HDC1000_I2CADDR_3 0x42 +#define HDC1000_I2CADDR_4 0x43 + +#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 + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#define HDC1000_I2CADDR_DEFAULT HDC1000_I2CADDR_1 + + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief HDC1000 configuration structure. + */ +typedef struct { + I2CHelper i2c; /* keep it first */ +} HDC1000_config; + +/** + * @brief HDC1000 configuration structure. + */ +typedef struct { + HDC1000_config *config; + sensor_state_t state; + unsigned int delay; + uint16_t cfg; +} HDC1000_drv; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/** + * @brief Initialize the sensor driver + */ +void +HDC1000_init(HDC1000_drv *drv, + HDC1000_config *config); + +/** + * @brief Start the sensor + */ +msg_t +HDC1000_start(HDC1000_drv *drv); + +/** + * @brief Stop the sensor + * + * @details If the sensor support it, it will be put in low energy mode. + */ +msg_t +HDC1000_stop(HDC1000_drv *drv); + +/** + * @brief Check that the sensor is really present + */ +msg_t +HDC1000_check(HDC1000_drv *drv); + + +msg_t +HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial); + +/** + * @brief Control the HD1000 heater. + */ +msg_t +HDC1000_setHeater(HDC1000_drv *drv, + bool on); + + + +/** + * @brief Time in milli-seconds necessary for acquiring a naw measure + * + * @returns + * unsigned int time in millis-seconds + */ +static inline unsigned int +HDC1000_getAcquisitionTime(HDC1000_drv *drv) { + return drv->delay; +} + +/** + * @brief Trigger a mesure acquisition + */ +msg_t +HDC1000_startMeasure(HDC1000_drv *drv); + +/** + * @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 +HDC1000_readMeasure(HDC1000_drv *drv, + float *temperature, float *humidity); + + +/** + * @brief Read temperature and humidity + * + * @details According to the sensor specification/configuration + * (see #HDC1000_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 #HDC1000_STARTUP_TIME + + * @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 +HDC1000_readTemperatureHumidity(HDC1000_drv *drv, + float *temperature, float *humidity); + +/** + * @brief Return the humidity value in percent. + * + * @details Use readTemperatureHumidity() for returning the humidity value. + * + * @note Prefere readTemperatureHumidity(), if you need both temperature + * and humidity, or if you need better error handling. + * + * @returns + * float humidity percent + * NAN on failure + */ +static inline float +HDC1000_getHumidity(HDC1000_drv *drv) { + float humidity = NAN; + HDC1000_readTemperatureHumidity(drv, NULL, &humidity); + return humidity; +} + +/** + * @brief Return the temperature value in °C. + * + * @details Use readTemperatureHumidity() for returning the humidity value. + * + * @note Prefere readTemperatureHumidity(), if you need both temperature + * and humidity, or if you need better error handling. + * + * @returns + * float humidity percent + * NAN on failure + */ +static inline float +HDC1000_getTemperature(HDC1000_drv *drv) { + float temperature = NAN; + HDC1000_readTemperatureHumidity(drv, &temperature, NULL); + return temperature; +} + + +#endif + +/** + * @} + */ diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.c b/os/various/devices_lib/sensors/hdc1000/hdc1000.c deleted file mode 100644 index 218450d..0000000 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - HDC1008 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu -*/ - -/** - * @file HDC1000.c - * @brief HDC1000 interface module code. - * - * @addtogroup hdc1000 - * @{ - */ - -#define I2C_HELPERS_AUTOMATIC_DRV TRUE - -#include "hal.h" -#include "i2c_helpers.h" -#include "hdc1000.h" - -/* DOC: http://www.ti.com/lit/ds/symlink/hdc1008.pdf - */ - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/* I2C Register */ -#define HDC1000_REG_TEMP_HUMID 0x00 -#define HDC1000_REG_TEMP 0x00 -#define HDC1000_REG_HUMID 0x01 -#define HDC1000_REG_CONFIG 0x02 -#define HDC1000_REG_SERIAL 0xFB -#define HDC1000_REG_SERIAL_1 0xFB -#define HDC1000_REG_SERIAL_2 0xFC -#define HDC1000_REG_SERIAL_3 0xFD -#define HDC1000_REG_MANUF_ID 0xFE -#define HDC1000_REG_DEVICE_ID 0xFF - -/* Configuration */ -#define HDC1000_CONFIG_RST (1 << 15) -#define HDC1000_CONFIG_HEATER (1 << 13) -#define HDC1000_CONFIG_MODE_ONE (0 << 12) -#define HDC1000_CONFIG_MODE_BOTH (1 << 12) -#define HDC1000_CONFIG_BATT (1 << 11) -#define HDC1000_CONFIG_TRES_14 (0) -#define HDC1000_CONFIG_TRES_11 (1 << 10) -#define HDC1000_CONFIG_HRES_14 (0) -#define HDC1000_CONFIG_HRES_11 (1 << 8) -#define HDC1000_CONFIG_HRES_8 (1 << 9) - -/* Value */ -#define HDC1000_MANUF_ID 0x5449 -#define HDC1000_DEVICE_ID 0x1000 - -/* Delay in micro seconds */ -#define HDC1000_DELAY_ACQUIRE_SAFETY 1000 -#define HDC1000_DELAY_ACQUIRE_TRES_14 6350 -#define HDC1000_DELAY_ACQUIRE_TRES_11 3650 -#define HDC1000_DELAY_ACQUIRE_HRES_14 6500 -#define HDC1000_DELAY_ACQUIRE_HRES_11 3850 -#define HDC1000_DELAY_ACQUIRE_HRES_8 2500 -#define HDC1000_DELAY_STARTUP 15000 - -// Deefault config (high res) -#define HDC1000_CONFIG_RES (HDC1000_CONFIG_TRES_14 | \ - HDC1000_CONFIG_HRES_14) -#define HDC1000_DELAY_ACQUIRE (HDC1000_DELAY_ACQUIRE_TRES_14 + \ - HDC1000_DELAY_ACQUIRE_HRES_14) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -static inline msg_t -_apply_config(HDC1000_drv *drv) { - struct __attribute__((packed)) { - uint8_t reg; - uint16_t conf; - } tx = { HDC1000_REG_CONFIG, cpu_to_be16(drv->cfg) }; - - return i2c_send((uint8_t*)&tx, sizeof(tx)); -} - -static inline msg_t -_decode_measure(HDC1000_drv *drv, - uint32_t val, float *temperature, float *humidity) { - (void)drv; - - /* Temperature */ - if (temperature) { - float temp = (val >> 16); - temp /= 65536; - temp *= 165; - temp -= 40; - *temperature = temp; - } - - /* Humidiy */ - if (humidity) { - float hum = (val & 0xFFFF); - hum /= 65535; - hum *= 100; - *humidity = hum; - } - - /* ok */ - return MSG_OK; -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -void -HDC1000_init(HDC1000_drv *drv, HDC1000_config *config) { - drv->config = config; - drv->cfg = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE_BOTH | - HDC1000_CONFIG_RES; - drv->delay = (HDC1000_DELAY_ACQUIRE + - HDC1000_DELAY_ACQUIRE_SAFETY) / 1000; - drv->state = SENSOR_INIT; -} - -msg_t -HDC1000_check(HDC1000_drv *drv) { - uint16_t manuf, device; - - 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 ((manuf != HDC1000_MANUF_ID) || (device != HDC1000_DEVICE_ID)) - return SENSOR_NOTFOUND; - - return MSG_OK; -} - - -msg_t -HDC1000_start(HDC1000_drv *drv) { - 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 = SENSOR_ERROR; - return msg; - } - drv->state = SENSOR_STARTED; - return MSG_OK; -} - -msg_t -HDC1000_stop(HDC1000_drv *drv) { - drv->state = SENSOR_STOPPED; - return MSG_OK; -} - -msg_t -HDC1000_setHeater(HDC1000_drv *drv, bool on) { - if (on) { drv->cfg |= HDC1000_CONFIG_HEATER; } - else { drv->cfg &= ~HDC1000_CONFIG_HEATER; } - - msg_t msg; - if ((msg = _apply_config(drv)) < MSG_OK) { - drv->state = SENSOR_ERROR; - return msg; - } - return MSG_OK; -} - -msg_t -HDC1000_startMeasure(HDC1000_drv *drv) { - msg_t msg; - osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); - if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) - return msg; - drv->state = SENSOR_MEASURING; - return MSG_OK; -} - - -msg_t -HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial) { - msg_t msg; - osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); - - if (((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_1, - (uint16_t*)&serial[0])) < MSG_OK) || - ((msg = i2c_reg_recv16(HDC1000_REG_SERIAL_2, - (uint16_t*)&serial[2])) < MSG_OK) || - ((msg = i2c_reg_recv8 (HDC1000_REG_SERIAL_3, - (uint8_t*) &serial[4])) < MSG_OK)) - return msg; - return MSG_OK; -} - - -msg_t -HDC1000_readMeasure(HDC1000_drv *drv, - float *temperature, float *humidity) { - msg_t msg; - uint32_t val; - - osalDbgAssert((drv->state == SENSOR_MEASURING) || - (drv->state == SENSOR_READY ), - "invalid state"); - - if ((msg = i2c_recv32_be(&val)) < MSG_OK) { - drv->state = SENSOR_ERROR; - return msg; - } - - drv->state = SENSOR_STARTED; - - return _decode_measure(drv, val, temperature, humidity); -} - -msg_t -HDC1000_readTemperatureHumidity(HDC1000_drv *drv, - float *temperature, float *humidity) { - msg_t msg; - uint32_t val; - - osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); - - /* Request value */ - if ((msg = i2c_reg(HDC1000_REG_TEMP_HUMID)) < MSG_OK) - return msg; - - /* Wait */ - osalThreadSleepMilliseconds(drv->delay); - - /* Get value */ - if ((msg = i2c_recv32_be(&val)) < MSG_OK) { - drv->state = SENSOR_ERROR; - return msg; - } - - return _decode_measure(drv, val, temperature, humidity); -} - - -/** @} */ diff --git a/os/various/devices_lib/sensors/hdc1000/hdc1000.h b/os/various/devices_lib/sensors/hdc1000/hdc1000.h deleted file mode 100644 index 9533060..0000000 --- a/os/various/devices_lib/sensors/hdc1000/hdc1000.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - HDC1000 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu -*/ - -/** - * @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. - * - * @{ - */ - -#ifndef _SENSOR_HDC1000_H_ -#define _SENSOR_HDC1000_H_ - -#include -#include -#include "i2c_helpers.h" -#include "sensor.h" - - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -#define HDC1000_CONTINUOUS_ACQUISITION_SUPPORTED FALSE - -/* I2C address */ -#define HDC1000_I2CADDR_1 0x40 -#define HDC1000_I2CADDR_2 0x41 -#define HDC1000_I2CADDR_3 0x42 -#define HDC1000_I2CADDR_4 0x43 - -#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 - - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#define HDC1000_I2CADDR_DEFAULT HDC1000_I2CADDR_1 - - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief HDC1000 configuration structure. - */ -typedef struct { - I2CHelper i2c; /* keep it first */ -} HDC1000_config; - -/** - * @brief HDC1000 configuration structure. - */ -typedef struct { - HDC1000_config *config; - sensor_state_t state; - unsigned int delay; - uint16_t cfg; -} HDC1000_drv; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -/** - * @brief Initialize the sensor driver - */ -void -HDC1000_init(HDC1000_drv *drv, - HDC1000_config *config); - -/** - * @brief Start the sensor - */ -msg_t -HDC1000_start(HDC1000_drv *drv); - -/** - * @brief Stop the sensor - * - * @details If the sensor support it, it will be put in low energy mode. - */ -msg_t -HDC1000_stop(HDC1000_drv *drv); - -/** - * @brief Check that the sensor is really present - */ -msg_t -HDC1000_check(HDC1000_drv *drv); - - -msg_t -HDC1000_readSerial(HDC1000_drv *drv, uint8_t *serial); - -/** - * @brief Control the HD1000 heater. - */ -msg_t -HDC1000_setHeater(HDC1000_drv *drv, - bool on); - - - -/** - * @brief Time in milli-seconds necessary for acquiring a naw measure - * - * @returns - * unsigned int time in millis-seconds - */ -static inline unsigned int -HDC1000_getAcquisitionTime(HDC1000_drv *drv) { - return drv->delay; -} - -/** - * @brief Trigger a mesure acquisition - */ -msg_t -HDC1000_startMeasure(HDC1000_drv *drv); - -/** - * @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 -HDC1000_readMeasure(HDC1000_drv *drv, - float *temperature, float *humidity); - - -/** - * @brief Read temperature and humidity - * - * @details According to the sensor specification/configuration - * (see #HDC1000_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 #HDC1000_STARTUP_TIME - - * @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 -HDC1000_readTemperatureHumidity(HDC1000_drv *drv, - float *temperature, float *humidity); - -/** - * @brief Return the humidity value in percent. - * - * @details Use readTemperatureHumidity() for returning the humidity value. - * - * @note Prefere readTemperatureHumidity(), if you need both temperature - * and humidity, or if you need better error handling. - * - * @returns - * float humidity percent - * NAN on failure - */ -static inline float -HDC1000_getHumidity(HDC1000_drv *drv) { - float humidity = NAN; - HDC1000_readTemperatureHumidity(drv, NULL, &humidity); - return humidity; -} - -/** - * @brief Return the temperature value in °C. - * - * @details Use readTemperatureHumidity() for returning the humidity value. - * - * @note Prefere readTemperatureHumidity(), if you need both temperature - * and humidity, or if you need better error handling. - * - * @returns - * float humidity percent - * NAN on failure - */ -static inline float -HDC1000_getTemperature(HDC1000_drv *drv) { - float temperature = NAN; - HDC1000_readTemperatureHumidity(drv, &temperature, NULL); - return temperature; -} - - -#endif - -/** - * @} - */ diff --git a/os/various/devices_lib/sensors/mcp9808.c b/os/various/devices_lib/sensors/mcp9808.c new file mode 100644 index 0000000..296c2f1 --- /dev/null +++ b/os/various/devices_lib/sensors/mcp9808.c @@ -0,0 +1,192 @@ + +#define I2C_HELPERS_AUTOMATIC_DRV TRUE + +#include "hal.h" +#include "i2c_helpers.h" +#include "mcp9808.h" + +// http://www.mouser.com/ds/2/268/25095A-15487.pdf +// http://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf + + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* I2C Register */ +#define MCP9808_REG_CONFIG 0x01 +#define MCP9808_REG_UPPER_TEMP 0x02 +#define MCP9808_REG_LOWER_TEMP 0x03 +#define MCP9808_REG_CRIT_TEMP 0x04 +#define MCP9808_REG_AMBIENT_TEMP 0x05 +#define MCP9808_REG_MANUF_ID 0x06 +#define MCP9808_REG_DEVICE_ID 0x07 +#define MCP9808_REG_RESOLUTION 0x08 + +/* Config */ +#define MCP9808_REG_CONFIG_SHUTDOWN 0x0100 +#define MCP9808_REG_CONFIG_CRITLOCKED 0x0080 +#define MCP9808_REG_CONFIG_WINLOCKED 0x0040 +#define MCP9808_REG_CONFIG_INTCLR 0x0020 +#define MCP9808_REG_CONFIG_ALERTSTAT 0x0010 +#define MCP9808_REG_CONFIG_ALERTCTRL 0x0008 +#define MCP9808_REG_CONFIG_ALERTSEL 0x0002 +#define MCP9808_REG_CONFIG_ALERTPOL 0x0002 +#define MCP9808_REG_CONFIG_ALERTMODE 0x0001 + +/* Device Id */ +#define MCP9808_MANUF_ID 0x0054 +#define MCP9808_DEVICE_ID 0x0400 + +/* Resolution */ +#define MCP9808_RES_2 0x00 /* 1/2 = 0.5 */ +#define MCP9808_RES_4 0x01 /* 1/4 = 0.25 */ +#define MCP9808_RES_8 0x10 /* 1/8 = 0.125 */ +#define MCP9808_RES_16 0x11 /* 1/16 = 0.0625 */ + +/* Time in milli-seconds */ +#define MCP9808_DELAY_ACQUIRE_RES_2 30 +#define MCP9808_DELAY_ACQUIRE_RES_4 65 +#define MCP9808_DELAY_ACQUIRE_RES_8 130 +#define MCP9808_DELAY_ACQUIRE_RES_16 250 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +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) { + + /* Temperature */ + if (temperature) { + float temp = val & 0x0fff; + if (val & 0x1000) temp -= 0x1000; + + float factor = 16.0F; + switch(drv->resolution) { + case RES_2 : factor = 2.0F; break; + case RES_4 : factor = 4.0F; break; + case RES_8 : factor = 8.0F; break; + case RES_16: factor = 16.0F; break; + } + + *temperature = temp / factor; + } + + /* Ok */ + return MSG_OK; +} + + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void +MCP9808_init(MCP9808_drv *drv, MCP9808_config *config) { + drv->config = config; + drv->cfg = 0; + drv->resolution = RES_16; /* power up default */ + drv->state = SENSOR_INIT; +} + +msg_t +MCP9808_check(MCP9808_drv *drv) { + uint16_t manuf, device; + + 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 ((manuf != MCP9808_MANUF_ID) || (device != MCP9808_DEVICE_ID)) + return SENSOR_NOTFOUND; + + return MSG_OK; +} + +msg_t +MCP9808_setResolution(MCP9808_drv *drv, MCP9808_resolution_t res) { + struct __attribute__((packed)) { + uint8_t reg; + uint8_t resolution; + } tx = { MCP9808_REG_RESOLUTION, res }; + + msg_t msg; + if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK) + return msg; + + drv->resolution = res; + return MSG_OK; +} + +msg_t +MCP9808_start(MCP9808_drv *drv) { + drv->cfg &= ~(MCP9808_REG_CONFIG_SHUTDOWN); + return _apply_config(drv); +} + +msg_t +MCP9808_stop(MCP9808_drv *drv) { + drv->cfg |= (MCP9808_REG_CONFIG_SHUTDOWN); + return _apply_config(drv); +} + +unsigned int +MCP9808_getAcquisitionTime(MCP9808_drv *drv) { + switch(drv->resolution) { + case RES_2 : return MCP9808_DELAY_ACQUIRE_RES_2; + case RES_4 : return MCP9808_DELAY_ACQUIRE_RES_4; + case RES_8 : return MCP9808_DELAY_ACQUIRE_RES_8; + case RES_16: return MCP9808_DELAY_ACQUIRE_RES_16; + } + osalDbgAssert(false, "OOPS"); + return 0; +} + +msg_t +MCP9808_readMeasure(MCP9808_drv *drv, + float *temperature) { + + msg_t msg; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) + return msg; + + return _decode_measure(drv, val, temperature); +} + + +msg_t +MCP9808_readTemperature(MCP9808_drv *drv, + float *temperature) { + osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); + + msg_t msg; + uint16_t val; + + if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) + return msg; + + return _decode_measure(drv, val, temperature); +} diff --git a/os/various/devices_lib/sensors/mcp9808.h b/os/various/devices_lib/sensors/mcp9808.h new file mode 100644 index 0000000..3bae5d2 --- /dev/null +++ b/os/various/devices_lib/sensors/mcp9808.h @@ -0,0 +1,192 @@ +/* + MCP9808 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu +*/ + +#ifndef _SENSOR_MCP9808_H_ +#define _SENSOR_MCP9808_H_ + +#include +#include "i2c_helpers.h" +#include "sensor.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define MCP9808_CONTINUOUS_ACQUISITION_SUPPORTED TRUE + + +#define MCP9808_I2CADDR_FIXED 0x18 + +/** + * @brief Time necessary for the sensor to boot + */ +#define MCP9808_BOOTUP_TIME 0 + +/** + * @brief Time necessary for the sensor to start + */ +#define MCP9808_STARTUP_TIME 0 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#define MCP9808_I2CADDR_DEFAULT MCP9808_I2CADDR_FIXED + +/*===========================================================================*/ +/* 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. + */ +typedef struct { + I2CHelper i2c; /* keep it first */ +} MCP9808_config; + +/** + * @brief MCP9808 configuration structure. + */ +typedef struct { + MCP9808_config *config; + sensor_state_t state; + MCP9808_resolution_t resolution; + uint16_t cfg; +} MCP9808_drv; + +/** + * @brief MCP9808 measure reading + */ +typedef struct { + float temperature; +} MCP9808_measure; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/** + * @brief Initialize the sensor driver + */ +void +MCP9808_init(MCP9808_drv *drv, + MCP9808_config *config); + +/** + * @brief Check that the sensor is really present + */ +msg_t +MCP9808_check(MCP9808_drv *drv); + +/** + * @brief Start the sensor + */ +msg_t +MCP9808_start(MCP9808_drv *drv); + +/** + * @brief Stop the sensor + * + * @details If the sensor support it, it will be put in low energy mode. + */ +msg_t +MCP9808_stop(MCP9808_drv *drv); + +/** + * @brief Control the MCP9809 resolution. + */ +msg_t +MCP9808_setResolution(MCP9808_drv *drv, + MCP9808_resolution_t res); + +/** + * @brief Time in milli-seconds necessary for acquiring a naw measure + * + * @returns + * unsigned int time in millis-seconds + */ +unsigned int +MCP9808_getAcquisitionTime(MCP9808_drv *drv); + +/** + * @brief Trigger a mesure acquisition + */ +static inline msg_t +MCP9808_startMeasure(MCP9808_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 +MCP9808_readMeasure(MCP9808_drv *drv, + float *temperature); + + +/** + * @brief Read temperature and humidity + * + * @details According to the sensor specification/configuration + * (see #MCP9808_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 +MCP9808_readTemperature(MCP9808_drv *drv, + float *temperature); + +/** + * @brief Return the temperature value in °C. + * + * @note Prefere readTemperature(), if you need better error handling. + * + * @return The temperature in °C + * @retval float humidity percent + * @retval NAN on failure + */ +static inline float +MCP9808_getTemperature(MCP9808_drv *drv) { + float temperature = NAN; + MCP9808_readTemperature(drv, &temperature); + return temperature; +} + +#endif + diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.c b/os/various/devices_lib/sensors/mcp9808/mcp9808.c deleted file mode 100644 index 296c2f1..0000000 --- a/os/various/devices_lib/sensors/mcp9808/mcp9808.c +++ /dev/null @@ -1,192 +0,0 @@ - -#define I2C_HELPERS_AUTOMATIC_DRV TRUE - -#include "hal.h" -#include "i2c_helpers.h" -#include "mcp9808.h" - -// http://www.mouser.com/ds/2/268/25095A-15487.pdf -// http://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf - - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/* I2C Register */ -#define MCP9808_REG_CONFIG 0x01 -#define MCP9808_REG_UPPER_TEMP 0x02 -#define MCP9808_REG_LOWER_TEMP 0x03 -#define MCP9808_REG_CRIT_TEMP 0x04 -#define MCP9808_REG_AMBIENT_TEMP 0x05 -#define MCP9808_REG_MANUF_ID 0x06 -#define MCP9808_REG_DEVICE_ID 0x07 -#define MCP9808_REG_RESOLUTION 0x08 - -/* Config */ -#define MCP9808_REG_CONFIG_SHUTDOWN 0x0100 -#define MCP9808_REG_CONFIG_CRITLOCKED 0x0080 -#define MCP9808_REG_CONFIG_WINLOCKED 0x0040 -#define MCP9808_REG_CONFIG_INTCLR 0x0020 -#define MCP9808_REG_CONFIG_ALERTSTAT 0x0010 -#define MCP9808_REG_CONFIG_ALERTCTRL 0x0008 -#define MCP9808_REG_CONFIG_ALERTSEL 0x0002 -#define MCP9808_REG_CONFIG_ALERTPOL 0x0002 -#define MCP9808_REG_CONFIG_ALERTMODE 0x0001 - -/* Device Id */ -#define MCP9808_MANUF_ID 0x0054 -#define MCP9808_DEVICE_ID 0x0400 - -/* Resolution */ -#define MCP9808_RES_2 0x00 /* 1/2 = 0.5 */ -#define MCP9808_RES_4 0x01 /* 1/4 = 0.25 */ -#define MCP9808_RES_8 0x10 /* 1/8 = 0.125 */ -#define MCP9808_RES_16 0x11 /* 1/16 = 0.0625 */ - -/* Time in milli-seconds */ -#define MCP9808_DELAY_ACQUIRE_RES_2 30 -#define MCP9808_DELAY_ACQUIRE_RES_4 65 -#define MCP9808_DELAY_ACQUIRE_RES_8 130 -#define MCP9808_DELAY_ACQUIRE_RES_16 250 - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -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) { - - /* Temperature */ - if (temperature) { - float temp = val & 0x0fff; - if (val & 0x1000) temp -= 0x1000; - - float factor = 16.0F; - switch(drv->resolution) { - case RES_2 : factor = 2.0F; break; - case RES_4 : factor = 4.0F; break; - case RES_8 : factor = 8.0F; break; - case RES_16: factor = 16.0F; break; - } - - *temperature = temp / factor; - } - - /* Ok */ - return MSG_OK; -} - - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -void -MCP9808_init(MCP9808_drv *drv, MCP9808_config *config) { - drv->config = config; - drv->cfg = 0; - drv->resolution = RES_16; /* power up default */ - drv->state = SENSOR_INIT; -} - -msg_t -MCP9808_check(MCP9808_drv *drv) { - uint16_t manuf, device; - - 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 ((manuf != MCP9808_MANUF_ID) || (device != MCP9808_DEVICE_ID)) - return SENSOR_NOTFOUND; - - return MSG_OK; -} - -msg_t -MCP9808_setResolution(MCP9808_drv *drv, MCP9808_resolution_t res) { - struct __attribute__((packed)) { - uint8_t reg; - uint8_t resolution; - } tx = { MCP9808_REG_RESOLUTION, res }; - - msg_t msg; - if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK) - return msg; - - drv->resolution = res; - return MSG_OK; -} - -msg_t -MCP9808_start(MCP9808_drv *drv) { - drv->cfg &= ~(MCP9808_REG_CONFIG_SHUTDOWN); - return _apply_config(drv); -} - -msg_t -MCP9808_stop(MCP9808_drv *drv) { - drv->cfg |= (MCP9808_REG_CONFIG_SHUTDOWN); - return _apply_config(drv); -} - -unsigned int -MCP9808_getAcquisitionTime(MCP9808_drv *drv) { - switch(drv->resolution) { - case RES_2 : return MCP9808_DELAY_ACQUIRE_RES_2; - case RES_4 : return MCP9808_DELAY_ACQUIRE_RES_4; - case RES_8 : return MCP9808_DELAY_ACQUIRE_RES_8; - case RES_16: return MCP9808_DELAY_ACQUIRE_RES_16; - } - osalDbgAssert(false, "OOPS"); - return 0; -} - -msg_t -MCP9808_readMeasure(MCP9808_drv *drv, - float *temperature) { - - msg_t msg; - uint16_t val; - - if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) - return msg; - - return _decode_measure(drv, val, temperature); -} - - -msg_t -MCP9808_readTemperature(MCP9808_drv *drv, - float *temperature) { - osalDbgAssert(drv->state == SENSOR_STARTED, "invalid state"); - - msg_t msg; - uint16_t val; - - if ((msg = i2c_reg_recv16_be(MCP9808_REG_AMBIENT_TEMP, &val)) < MSG_OK) - return msg; - - return _decode_measure(drv, val, temperature); -} diff --git a/os/various/devices_lib/sensors/mcp9808/mcp9808.h b/os/various/devices_lib/sensors/mcp9808/mcp9808.h deleted file mode 100644 index 2d488d7..0000000 --- a/os/various/devices_lib/sensors/mcp9808/mcp9808.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - MCP9808 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu -*/ - -#ifndef _SENSOR_MCP9808_H_ -#define _SENSOR_MCP9808_H_ - -#include -#include "i2c_helpers.h" -#include "sensor.h" - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -#define MCP9808_CONTINUOUS_ACQUISITION_SUPPORTED TRUE - - -#define MCP9808_I2CADDR 0x18 - - -/*===========================================================================*/ -/* 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. - */ -typedef struct { - I2CHelper i2c; /* keep it first */ -} MCP9808_config; - -/** - * @brief MCP9808 configuration structure. - */ -typedef struct { - MCP9808_config *config; - sensor_state_t state; - MCP9808_resolution_t resolution; - uint16_t cfg; -} MCP9808_drv; - -/** - * @brief MCP9808 measure reading - */ -typedef struct { - float temperature; -} MCP9808_measure; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -/** - * @brief Initialize the sensor driver - */ -void -MCP9808_init(MCP9808_drv *drv, - MCP9808_config *config); - -/** - * @brief Check that the sensor is really present - */ -msg_t -MCP9808_check(MCP9808_drv *drv); - -/** - * @brief Start the sensor - */ -msg_t -MCP9808_start(MCP9808_drv *drv); - -/** - * @brief Stop the sensor - * - * @details If the sensor support it, it will be put in low energy mode. - */ -msg_t -MCP9808_stop(MCP9808_drv *drv); - -/** - * @brief Control the MCP9809 resolution. - */ -msg_t -MCP9808_setResolution(MCP9808_drv *drv, - MCP9808_resolution_t res); - -/** - * @brief Time necessary for the sensor to boot - * - * @returns - * unsigned int time in millis-seconds - */ - -static inline unsigned int -MCP9808_getBootupTime(MCP9808_drv *drv) { - (void)drv; - return 0; /* no info found */ -}; - -/** - * @brief Time necessary the sensor to for starting - * - * @returns - * unsigned int time in millis-seconds - */ -static inline unsigned int -MCP9808_getStartupTime(MCP9808_drv *drv) { - (void)drv; - return 0; /* no info found */ -}; - -/** - * @brief Time in milli-seconds necessary for acquiring a naw measure - * - * @returns - * unsigned int time in millis-seconds - */ -unsigned int -MCP9808_getAcquisitionTime(MCP9808_drv *drv); - -/** - * @brief Trigger a mesure acquisition - */ -static inline msg_t -MCP9808_startMeasure(MCP9808_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 -MCP9808_readMeasure(MCP9808_drv *drv, - float *temperature); - - -/** - * @brief Read temperature and humidity - * - * @details According to the sensor specification/configuration - * (see #MCP9808_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 -MCP9808_readTemperature(MCP9808_drv *drv, - float *temperature); - -/** - * @brief Return the temperature value in °C. - * - * @note Prefere readTemperature(), if you need better error handling. - * - * @return The temperature in °C - * @retval float humidity percent - * @retval NAN on failure - */ -static inline float -MCP9808_getTemperature(MCP9808_drv *drv) { - float temperature = NAN; - MCP9808_readTemperature(drv, &temperature); - return temperature; -} - -#endif - diff --git a/os/various/devices_lib/sensors/sensor.h b/os/various/devices_lib/sensors/sensor.h new file mode 100644 index 0000000..6ffa5a4 --- /dev/null +++ b/os/various/devices_lib/sensors/sensor.h @@ -0,0 +1,66 @@ +/** + * + * Example of function calls. + * + * @code + * static SENSOR_config sensor_config = { + * }; + * static SENSOR_drv sensor_drv; + * @endcode + * + * + * @code + * osalThreadSleepMilliseconds(SENSOR_BOOTUP_TIME); + * SENSOR_init(&sensor_drv); + * @endcode + * + * @code + * SENSOR_start(&sensor_drv, &sensor_config); + * osalThreadSleepMilliseconds(SENSOR_STARTUP_TIME); + * @endcode + * + * If using SENSOR_startMeasure()/SENSOR_readMeasure() + * @code + * while(true) { + * SENSOR_startMeasure(&sensor_drv); + * osalThreadSleepMilliseconds(SENSOR_getAcquisitionTime()); + * SENSOR_readMeasure(&sensor_drv, ...); + * } + * @endcode + * + * If using SENSOR_readValue() or SENSOR_getValue() + * @code + * #if SENSOR_CONTINUOUS_ACQUISITION_SUPPORTED == TRUE + * osalThreadSleepMilliseconds(SENSOR_getAcquisitionTime()) + * #endif + * + * while(true) { + * SENSOR_readValue(&sensor_drv, ...); + * } + * @encode + */ +#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 + + diff --git a/os/various/devices_lib/sensors/tsl2561.c b/os/various/devices_lib/sensors/tsl2561.c new file mode 100644 index 0000000..f67823a --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2561.c @@ -0,0 +1,372 @@ +/* + 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; + 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.h b/os/various/devices_lib/sensors/tsl2561.h new file mode 100644 index 0000000..d91fb4a --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2561.h @@ -0,0 +1,221 @@ +/* + 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 +#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) + +/** + * @brief Time necessary for the sensor to boot + */ +#define TSL2561_BOOTUP_TIME 0 + +/** + * @brief Time necessary for the sensor to start + */ +#define TSL2561_STARTUP_TIME 0 + + + +/*===========================================================================*/ +/* 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/devices_lib/sensors/tsl2561/tsl2561.c b/os/various/devices_lib/sensors/tsl2561/tsl2561.c deleted file mode 100644 index e8372c0..0000000 --- a/os/various/devices_lib/sensors/tsl2561/tsl2561.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - 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 deleted file mode 100644 index 16e63d3..0000000 --- a/os/various/devices_lib/sensors/tsl2561/tsl2561.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - 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 -#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 deleted file mode 100644 index 7e77644..0000000 --- a/os/various/sensor.h +++ /dev/null @@ -1,25 +0,0 @@ -#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 - - -- cgit v1.2.3 From 23a4b895cee55079a9fd1821dc6c068e035e75cc Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Tue, 9 Feb 2016 18:31:31 +0100 Subject: updated license --- os/various/bswap.h | 13 ++----------- os/various/devices_lib/sensors/hdc1000.c | 14 +++++++++++++- os/various/devices_lib/sensors/hdc1000.h | 14 +++++++++++++- os/various/devices_lib/sensors/mcp9808.c | 15 +++++++++++++++ os/various/devices_lib/sensors/mcp9808.h | 12 ++++++++++++ os/various/devices_lib/sensors/sensor.h | 15 +++++++++++++++ os/various/devices_lib/sensors/tsl2561.c | 12 ++++++++++++ os/various/devices_lib/sensors/tsl2561.h | 12 ++++++++++++ 8 files changed, 94 insertions(+), 13 deletions(-) diff --git a/os/various/bswap.h b/os/various/bswap.h index 624e4ba..b99034e 100644 --- a/os/various/bswap.h +++ b/os/various/bswap.h @@ -5,15 +5,6 @@ extern "C" { #endif -#if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) -#if YOTTA_CFG_CONFIG_ARCH_LITTLE_ENDIAN -#define ARCH_LITTLE_ENDIAN -#endif -#if YOTTA_CFG_CONFIG_ARCH_BIG_ENDIAN -#define ARCH_BIG_ENDIAN -#endif -#endif - #if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) #error "ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set." #endif @@ -27,8 +18,8 @@ extern "C" { (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) #define BSWAP_32(x) \ (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | \ - (((x) & 0x00FF0000UL) >> 8UL) | \ - (((x) & 0x0000FF00UL) << 8UL) | \ + (((x) & 0x00FF0000UL) >> 8UL) | \ + (((x) & 0x0000FF00UL) << 8UL) | \ (((x) & 0x000000FFUL) << 24UL)) diff --git a/os/various/devices_lib/sensors/hdc1000.c b/os/various/devices_lib/sensors/hdc1000.c index 218450d..39e47ec 100644 --- a/os/various/devices_lib/sensors/hdc1000.c +++ b/os/various/devices_lib/sensors/hdc1000.c @@ -1,5 +1,17 @@ /* - HDC1008 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu + HDC100x 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. */ /** diff --git a/os/various/devices_lib/sensors/hdc1000.h b/os/various/devices_lib/sensors/hdc1000.h index 9533060..e4eae4c 100644 --- a/os/various/devices_lib/sensors/hdc1000.h +++ b/os/various/devices_lib/sensors/hdc1000.h @@ -1,5 +1,17 @@ /* - HDC1000 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu + HDC100x 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. */ /** diff --git a/os/various/devices_lib/sensors/mcp9808.c b/os/various/devices_lib/sensors/mcp9808.c index 296c2f1..4b22ea9 100644 --- a/os/various/devices_lib/sensors/mcp9808.c +++ b/os/various/devices_lib/sensors/mcp9808.c @@ -1,3 +1,18 @@ +/* + MCP9808 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. +*/ #define I2C_HELPERS_AUTOMATIC_DRV TRUE diff --git a/os/various/devices_lib/sensors/mcp9808.h b/os/various/devices_lib/sensors/mcp9808.h index 3bae5d2..857f2f9 100644 --- a/os/various/devices_lib/sensors/mcp9808.h +++ b/os/various/devices_lib/sensors/mcp9808.h @@ -1,5 +1,17 @@ /* MCP9808 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. */ #ifndef _SENSOR_MCP9808_H_ diff --git a/os/various/devices_lib/sensors/sensor.h b/os/various/devices_lib/sensors/sensor.h index 6ffa5a4..bd544b1 100644 --- a/os/various/devices_lib/sensors/sensor.h +++ b/os/various/devices_lib/sensors/sensor.h @@ -1,3 +1,18 @@ +/* + 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. +*/ + /** * * Example of function calls. diff --git a/os/various/devices_lib/sensors/tsl2561.c b/os/various/devices_lib/sensors/tsl2561.c index f67823a..954c098 100644 --- a/os/various/devices_lib/sensors/tsl2561.c +++ b/os/various/devices_lib/sensors/tsl2561.c @@ -1,5 +1,17 @@ /* TSL2561 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. */ #define I2C_HELPERS_AUTOMATIC_DRV TRUE diff --git a/os/various/devices_lib/sensors/tsl2561.h b/os/various/devices_lib/sensors/tsl2561.h index d91fb4a..94e1ede 100644 --- a/os/various/devices_lib/sensors/tsl2561.h +++ b/os/various/devices_lib/sensors/tsl2561.h @@ -1,5 +1,17 @@ /* TSL2561 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. */ /** -- cgit v1.2.3 From e34ef249e7c3c1b42df94693236bfd1b5e02c2d9 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Tue, 9 Feb 2016 23:52:11 +0100 Subject: fixed tsl2561, added tsl2591 --- os/various/devices_lib/sensors/tsl2561.c | 32 ++-- os/various/devices_lib/sensors/tsl2591.c | 253 +++++++++++++++++++++++++++++++ os/various/devices_lib/sensors/tsl2591.h | 240 +++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+), 14 deletions(-) create mode 100644 os/various/devices_lib/sensors/tsl2591.c create mode 100644 os/various/devices_lib/sensors/tsl2591.h diff --git a/os/various/devices_lib/sensors/tsl2561.c b/os/various/devices_lib/sensors/tsl2561.c index 954c098..3d7b910 100644 --- a/os/various/devices_lib/sensors/tsl2561.c +++ b/os/various/devices_lib/sensors/tsl2561.c @@ -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; } diff --git a/os/various/devices_lib/sensors/tsl2591.c b/os/various/devices_lib/sensors/tsl2591.c new file mode 100644 index 0000000..214b1ce --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2591.c @@ -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; +} + diff --git a/os/various/devices_lib/sensors/tsl2591.h b/os/various/devices_lib/sensors/tsl2591.h new file mode 100644 index 0000000..e6597bf --- /dev/null +++ b/os/various/devices_lib/sensors/tsl2591.h @@ -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 +#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 + -- cgit v1.2.3 From 260a9edc325b2083901aa591874aa50bd0e5be25 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 10 Feb 2016 00:56:51 +0100 Subject: correctly pack structure, remove unused fields --- os/various/devices_lib/sensors/tsl2561.c | 18 +++++++-------- os/various/devices_lib/sensors/tsl2561.h | 24 +++++++++++++------- os/various/devices_lib/sensors/tsl2591.c | 39 ++++++++++++++++++++++++-------- os/various/devices_lib/sensors/tsl2591.h | 4 +--- 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/os/various/devices_lib/sensors/tsl2561.c b/os/various/devices_lib/sensors/tsl2561.c index 3d7b910..a4ac8ec 100644 --- a/os/various/devices_lib/sensors/tsl2561.c +++ b/os/various/devices_lib/sensors/tsl2561.c @@ -15,7 +15,7 @@ */ /** - * + * Illuminance calculation code provided by www.taosinc.com * DOC: http://ams.com/eng/content/download/250096/975518/143687 */ #define I2C_HELPERS_AUTOMATIC_DRV TRUE @@ -131,10 +131,6 @@ #define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE - - -#define CEILING(x,y) (((x) + (y) - 1) / (y)) - /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -147,6 +143,8 @@ /* Driver local functions. */ /*===========================================================================*/ +#define CEILING(x,y) (((x) + (y) - 1) / (y)) + static inline unsigned int calculateIlluminance(TSL2561_integration_time_t integration_time, TSL2561_gain_t gain, @@ -276,7 +274,7 @@ void TSL2561_init(TSL2561_drv *drv, TSL2561_config *config) { drv->config = config; drv->gain = TSL2561_GAIN_1X; - drv->integration_time = TSL2561_INTEGRATIONTIME_SHORT; + drv->integration_time = TSL2561_INTEGRATIONTIME_LONG; drv->state = SENSOR_INIT; i2c_reg_recv8(TSL2561_COMMAND_BIT | TSL2561_REG_ID, @@ -297,7 +295,7 @@ TSL2561_check(TSL2561_drv *drv) { msg_t TSL2561_stop(TSL2561_drv *drv) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_CONTROL, @@ -308,7 +306,7 @@ TSL2561_stop(TSL2561_drv *drv) { msg_t TSL2561_start(TSL2561_drv *drv) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_CONTROL, @@ -320,7 +318,7 @@ TSL2561_start(TSL2561_drv *drv) { msg_t TSL2561_setIntegrationTime(TSL2561_drv *drv, TSL2561_integration_time_t time) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_TIMING, @@ -338,7 +336,7 @@ TSL2561_setIntegrationTime(TSL2561_drv *drv, msg_t TSL2561_setGain(TSL2561_drv *drv, TSL2561_gain_t gain) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2561_COMMAND_BIT | TSL2561_REG_TIMING, diff --git a/os/various/devices_lib/sensors/tsl2561.h b/os/various/devices_lib/sensors/tsl2561.h index 94e1ede..75e7c78 100644 --- a/os/various/devices_lib/sensors/tsl2561.h +++ b/os/various/devices_lib/sensors/tsl2561.h @@ -87,16 +87,26 @@ typedef struct { I2CHelper i2c; /* keep it first */ } TSL2561_config; - +/** + * @brief Available integration time + * + * @details Available integration time are: + * 13.7ms, 101ms, 402ms + */ typedef enum { - TSL2561_INTEGRATIONTIME_SHORT = 0x00, // 13.7ms - TSL2561_INTEGRATIONTIME_MEDIUM = 0x01, // 101ms - TSL2561_INTEGRATIONTIME_LONG = 0x02, // 402ms + TSL2561_INTEGRATIONTIME_SHORT = 0x00, /**< @brief 13.7ms */ + TSL2561_INTEGRATIONTIME_MEDIUM = 0x01, /**< @brief 101.0ms */ + TSL2561_INTEGRATIONTIME_LONG = 0x02, /**< @brief 402.0ms */ } TSL2561_integration_time_t; +/** + * @brief Available gain + * + * @details Available gain are 1x, 16x + */ typedef enum { - TSL2561_GAIN_1X = 0x00, // No gain - TSL2561_GAIN_16X = 0x10, // 16x gain + TSL2561_GAIN_1X = 0x00, /**< @brief 1x gain */ + TSL2561_GAIN_16X = 0x10, /**< @brief 16x gain */ } TSL2561_gain_t; /** @@ -105,8 +115,6 @@ typedef enum { 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 { diff --git a/os/various/devices_lib/sensors/tsl2591.c b/os/various/devices_lib/sensors/tsl2591.c index 214b1ce..c0bbee0 100644 --- a/os/various/devices_lib/sensors/tsl2591.c +++ b/os/various/devices_lib/sensors/tsl2591.c @@ -163,29 +163,48 @@ TSL2591_check(TSL2591_drv *drv) { msg_t TSL2591_start(TSL2591_drv *drv) { - struct PACKED { + struct __attribute__((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)); + } 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 PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; - } tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE, - TSL2591_ENABLE_POWEROFF }; + } tx_stop = { + TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE, + TSL2591_ENABLE_POWEROFF }; - return i2c_send((uint8_t*)&tx, sizeof(tx)); + return i2c_send((uint8_t*)&tx_stop, sizeof(tx_stop)); } msg_t TSL2591_setIntegrationTime(TSL2591_drv *drv, TSL2591_integration_time_t time) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG, @@ -203,7 +222,7 @@ TSL2591_setIntegrationTime(TSL2591_drv *drv, msg_t TSL2591_setGain(TSL2591_drv *drv, TSL2591_gain_t gain) { - struct PACKED { + struct __attribute__((packed)) { uint8_t reg; uint8_t conf; } tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG, diff --git a/os/various/devices_lib/sensors/tsl2591.h b/os/various/devices_lib/sensors/tsl2591.h index e6597bf..8320eb8 100644 --- a/os/various/devices_lib/sensors/tsl2591.h +++ b/os/various/devices_lib/sensors/tsl2591.h @@ -113,9 +113,7 @@ typedef enum { typedef struct { TSL2591_config *config; sensor_state_t state; - unsigned int delay; - uint16_t cfg; - TSL2591_gain_t gain; + TSL2591_gain_t gain; TSL2591_integration_time_t integration_time; } TSL2591_drv; -- cgit v1.2.3 From 7b5ddf1928e900fc0a0647e24cc0d4b8c49c1f42 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 15 Feb 2016 21:42:16 +0100 Subject: included copyright --- os/various/bswap.h | 29 +++++++++++++++++++++++------ os/various/i2c_helpers.h | 16 ++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/os/various/bswap.h b/os/various/bswap.h index b99034e..30ae1d6 100644 --- a/os/various/bswap.h +++ b/os/various/bswap.h @@ -1,3 +1,19 @@ +/* + 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. +*/ + #ifndef BSWAP_H #define BSWAP_H @@ -6,16 +22,17 @@ extern "C" { #endif #if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN)) -#error "ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set." +#error "Need to define one: ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN" #endif #if defined(ARCH_BIG_ENDIAN) && defined(ARCH_LITTLE_ENDIAN) -#error "ARCH_BIG_ENDIAN and ARCH_LITTLE_ENDIAN are both set." +#error "ARCH_BIG_ENDIAN and ARCH_LITTLE_ENDIAN are both set" #endif #define BSWAP_16(x) \ - (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) + (uint16_t)((((x) & 0xFF00) >> 8) | \ + (((x) & 0x00FF) << 8)) #define BSWAP_32(x) \ (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | \ (((x) & 0x00FF0000UL) >> 8UL) | \ @@ -61,7 +78,7 @@ extern "C" { #define CPU_TO_BE16(x) BSWAP_16(x) #define CPU_TO_BE32(x) BSWAP_32(x) #endif - + static inline uint16_t bswap_16(const uint16_t x) __attribute__ ((warn_unused_result)) @@ -114,8 +131,8 @@ static inline void bswap_n(void* const data, uint8_t len) { uint8_t* ptr = (uint8_t*)data; for ( ; len > 1 ; ptr++, len -= 2 ) { - uint8_t tmp = *ptr; - *ptr = *(ptr + len - 1); + uint8_t tmp = *ptr; + *ptr = *(ptr + len - 1); *(ptr + len - 1) = tmp; } } diff --git a/os/various/i2c_helpers.h b/os/various/i2c_helpers.h index 56f9be6..4b57174 100644 --- a/os/various/i2c_helpers.h +++ b/os/various/i2c_helpers.h @@ -1,3 +1,19 @@ +/* + 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. +*/ + #ifndef I2C_HELPERS_H #define I2C_HELPERS_H -- cgit v1.2.3