add driver for tmp006 thermopile sensor
parent
84f4f8dac1
commit
b545f4dfe6
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_tmp006 TMP006 Infrared Thermopile Sensor
|
||||
* @ingroup drivers
|
||||
* @brief Driver for the Texas Instruments TMP006 sensor.
|
||||
* The sensor measures the temperature of an object
|
||||
* without the need of direct contact with the object.
|
||||
* After initialization and set active the sensor
|
||||
* will make measurements at periodic times.
|
||||
* The conversion duration depends on oversample ratio.<br>
|
||||
* The oversample ratio can be determined
|
||||
* by sensor initialization.<br>
|
||||
* The target object temperature can be calculated as follows:<br><br>
|
||||
* Temperature of sensor's die (2 times right shifting and devide-by 32):
|
||||
* \f{eqnarray*}{
|
||||
* T_{\mathrm{DIE}} &=& \frac{T_{\mathrm{RAW}}}{128}
|
||||
* \f}
|
||||
* Difference Temperature in Kelvin:
|
||||
* \f{eqnarray*}{
|
||||
* T_{\mathrm{DIFF}} &=& T_{\mathrm{DIE}} - T_{\mathrm{REF}}
|
||||
* \f}
|
||||
* Sensitivity of the thermopile sensor,
|
||||
* with \f$S_{\mathrm{0}}\f$ as calibration factor:
|
||||
* \f{eqnarray*}{
|
||||
* S &=& S_{\mathrm{0}} \cdot ( 1 + a_1 \cdot T_{\mathrm{DIFF}}
|
||||
* + a_2 \cdot T_{\mathrm{DIFF}}^2 ) \\
|
||||
* \f}
|
||||
* Sensor's voltage (the LSB size is \f$ 156.25\,\mathrm{nV} \f$):
|
||||
* \f{eqnarray*}{
|
||||
* V_{\mathrm{OBJ}} &=& V_{\mathrm{RAW}} \cdot 156.25\,\mathrm{nV}
|
||||
* \f}
|
||||
* Offset voltage:
|
||||
* \f{eqnarray*}{
|
||||
* V_{OS} &=& b_0 + b_1 \cdot T_{\mathrm{DIFF}}
|
||||
* + b_2 \cdot T_{\mathrm{DIFF}}^2 \\
|
||||
* \f}
|
||||
* Seebeck coefficients of the thermopile:
|
||||
* \f{eqnarray*}{
|
||||
* f(V_{\mathrm{OBJ}}) &=& (V_{\mathrm{OBJ}} - V_{O\mathrm{S}})
|
||||
* + c_2 \cdot (V_{\mathrm{OBJ}} - V_{\mathrm{OS}})^2 \\
|
||||
* \f}
|
||||
* Temperature of the target object:
|
||||
* \f{eqnarray*}{
|
||||
* T_{\mathrm{OBJ}} &=& \sqrt[4]{T_{\mathrm{DIE}}^4
|
||||
* + \frac{f(V_{\mathrm{OBJ}})}{S}} \\
|
||||
* \f}
|
||||
* Constants:<br>
|
||||
* \f{eqnarray*}{
|
||||
* a_{\mathrm{1}} &=& 1.75 \cdot 10^{-3} \\
|
||||
* a_{\mathrm{2}} &=& -1.678 \cdot 10^{-5} \\
|
||||
* T_{\mathrm{REF}} &=& 298.15\,\mathrm{K} \\
|
||||
* b_{\mathrm{0}} &=& -2.94 \cdot 10^{-5} \\
|
||||
* b_{\mathrm{1}} &=& -5.7 \cdot 10^{-7} \\
|
||||
* b_{\mathrm{2}} &=& 4.63 \cdot 10^{-9} \\
|
||||
* c_{\mathrm{2}} &=& 13.4
|
||||
* \f}
|
||||
*
|
||||
* The calculation and constants are wrapped from TI TMP006 User's Guide SBOU107.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Interface definition for the TMP006 sensor driver.
|
||||
*
|
||||
* @author Johann Fischer <j.fischer@phytec.de>
|
||||
*/
|
||||
|
||||
#ifndef TMP006_H
|
||||
#define TMP006_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "periph/i2c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef TMP006_I2C_ADDRESS
|
||||
#define TMP006_I2C_ADDRESS 0x41 /**< TMP006 Sensor Default Address */
|
||||
#endif
|
||||
|
||||
#ifndef TMP006_CONVERSION_TIME
|
||||
#define TMP006_CONVERSION_TIME 1E6 /**< Default Conversion Time in us */
|
||||
#endif
|
||||
|
||||
#define TMP006_CONFIG_CR_AS1 0x00 /**< Conversion Time 0.25 s, AVG Samples: 1 */
|
||||
#define TMP006_CONFIG_CR_AS2 0x01 /**< Conversion Time 0.5 s, AVG Samples: 2 */
|
||||
#define TMP006_CONFIG_CR_AS4 0x02 /**< Conversion Time 1 s, AVG Samples: 4 */
|
||||
#define TMP006_CONFIG_CR_AS8 0x03 /**< Conversion Time 2 s, AVG Samples: 8 */
|
||||
#define TMP006_CONFIG_CR_AS16 0x04 /**< Conversion Time 4 s, AVG Samples: 16 */
|
||||
#define TMP006_CONFIG_CR_DEF TMP006_CONFIG_CR_AS4 /**< Default for Testing */
|
||||
|
||||
#ifndef TMP006_CCONST_S0
|
||||
#define TMP006_CCONST_S0 6.4E-14 /**< Calibration Factor */
|
||||
#endif
|
||||
|
||||
#define TMP006_CCONST_A1 1.75E-3 /**< Constant \f$a_{\mathrm{1}}\f$ */
|
||||
#define TMP006_CCONST_A2 -1.678E-5 /**< Constant \f$a_{\mathrm{2}}\f$ */
|
||||
#define TMP006_CCONST_TREF 298.15 /**< Constant \f$T_{\mathrm{REF}\f$ */
|
||||
#define TMP006_CCONST_B0 -2.94E-5 /**< Constant \f$b_{\mathrm{0}}\f$ */
|
||||
#define TMP006_CCONST_B1 -5.7E-7 /**< Constant \f$b_{\mathrm{1}}\f$ */
|
||||
#define TMP006_CCONST_B2 4.63E-9 /**< Constant \f$b_{\mathrm{2}}\f$ */
|
||||
#define TMP006_CCONST_C2 13.4 /**< Constant \f$c_{\mathrm{2}}\f$ */
|
||||
#define TMP006_CCONST_LSB_SIZE 156.25E-9 /**< Sensor Voltage Register LSB Size */
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for TMP006 sensors.
|
||||
*/
|
||||
typedef struct {
|
||||
i2c_t i2c; /**< I2C device, the sensor is connected to */
|
||||
uint8_t addr; /**< the sensor's slave address on the I2C bus */
|
||||
bool initialized; /**< sensor status, true if sensor is initialized */
|
||||
} tmp006_t;
|
||||
|
||||
/**
|
||||
* @brief TMP006 sensor test.
|
||||
* This function looks for Device ID of the TMP006 sensor.
|
||||
*
|
||||
* @param[in] dev device descriptor of sensor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int tmp006_test(tmp006_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initialize the TMP006 sensor driver.
|
||||
*
|
||||
* @param[out] dev device descriptor of sensor to initialize
|
||||
* @param[in] i2c I2C bus the sensor is connected to
|
||||
* @param[in] address sensor's I2C slave address
|
||||
* @param[in] conv_rate number of averaged samples
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 if conv_rate is wrong
|
||||
* @return -2 if initialization of I2C bus failed
|
||||
* @return -3 if sensor test failed
|
||||
* @return -4 if sensor configuration failed
|
||||
*/
|
||||
int tmp006_init(tmp006_t *dev, i2c_t i2c, uint8_t address, uint8_t conv_rate);
|
||||
|
||||
/**
|
||||
* @brief Reset the TMP006 sensor. After that, the sensor should be reinitialized.
|
||||
*
|
||||
* @param[out] dev device descriptor of sensor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int tmp006_reset(tmp006_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set active mode, this enables periodic measurements.
|
||||
*
|
||||
* @param[in] dev device descriptor of sensor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int tmp006_set_active(tmp006_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set standby mode.
|
||||
*
|
||||
* @param[in] dev device descriptor of sensor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int tmp006_set_standby(tmp006_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Read sensor's data.
|
||||
*
|
||||
* @param[in] dev device descriptor of sensor
|
||||
* @param[out] rawv object voltage value
|
||||
* @param[out] rawt raw die temperature
|
||||
* @param[out] drdy data ready, 0 if a conversion is in progress
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int tmp006_read(tmp006_t *dev, int16_t *rawv, int16_t *rawt, uint8_t *drdy);
|
||||
|
||||
/**
|
||||
* @brief Convert raw sensor values to temperature.
|
||||
*
|
||||
* @param[in] rawv object voltage value
|
||||
* @param[in] rawt raw die temperature value
|
||||
* @param[out] tamb converted ambient temperature
|
||||
* @param[out] tobj converted object temperature
|
||||
*/
|
||||
void tmp006_convert(int16_t rawv, int16_t rawt, float *tamb, float *tobj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/** @} */
|
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_tmp006
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Driver for the TI TMP006 Infrared Thermopile Sensor.
|
||||
*
|
||||
* @author Johann Fischer <j.fischer@phytec.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include "periph/i2c.h"
|
||||
#include "tmp006.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define TMP006_V_OBJECT 0x00 /**< Sensor Voltage Register */
|
||||
#define TMP006_T_AMBIENT 0x01 /**< Ambient Temperature Register */
|
||||
#define TMP006_CONFIG 0x02 /**< Configuration Register */
|
||||
#define TMP006_MANUFACTURER_ID 0xFE /**< Manufacturer ID Register */
|
||||
#define TMP006_DEVICE_ID 0xFF /**< Device ID Register */
|
||||
|
||||
#define TMP006_CONFIG_RST (1 << 15)
|
||||
|
||||
#define TMP006_CONFIG_MOD_SHIFT 12
|
||||
#define TMP006_CONFIG_MOD_MASK 0x7000
|
||||
#define TMP006_CONFIG_MOD(x) (((uint16_t)(((uint16_t)(x))<<TMP006_CONFIG_MOD_SHIFT))\
|
||||
&TMP006_CONFIG_MOD_MASK)
|
||||
#define TMP006_CONFIG_MOD_CC 0x07
|
||||
#define TMP006_CONFIG_MOD_OFF 0x00
|
||||
|
||||
#define TMP006_CONFIG_CR_SHIFT 9
|
||||
#define TMP006_CONFIG_CR_MASK 0x0E00
|
||||
#define TMP006_CONFIG_CR(x) (((uint16_t)(((uint16_t)(x))<<TMP006_CONFIG_CR_SHIFT))\
|
||||
&TMP006_CONFIG_CR_MASK)
|
||||
|
||||
#define TMP006_CONFIG_DRDY_PIN_EN (1 << 8)
|
||||
#define TMP006_CONFIG_DRDY (1 << 7)
|
||||
|
||||
#define TMP006_MID_VALUE 0x5449 /**< Manufacturer ID */
|
||||
#define TMP006_DID_VALUE 0x0067 /**< Device ID */
|
||||
|
||||
#define I2C_SPEED I2C_SPEED_FAST
|
||||
|
||||
int tmp006_test(tmp006_t *dev)
|
||||
{
|
||||
char reg[2];
|
||||
uint16_t tmp;
|
||||
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_DEVICE_ID, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = ((uint16_t)reg[0] << 8) | reg[1];
|
||||
|
||||
if (tmp != TMP006_DID_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tmp006_init(tmp006_t *dev, i2c_t i2c, uint8_t address, uint8_t conv_rate)
|
||||
{
|
||||
char reg[2];
|
||||
|
||||
/* write device descriptor */
|
||||
dev->i2c = i2c;
|
||||
dev->addr = address;
|
||||
dev->initialized = false;
|
||||
|
||||
if (conv_rate > TMP006_CONFIG_CR_AS16) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialize the I2C bus */
|
||||
if (i2c_init_master(i2c, I2C_SPEED) < 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (tmp006_test(dev)) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
uint16_t tmp = TMP006_CONFIG_CR(conv_rate);
|
||||
reg[0] = (uint8_t)(tmp >> 8);
|
||||
reg[1] = (uint8_t)tmp;
|
||||
|
||||
if (i2c_write_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
dev->initialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tmp006_reset(tmp006_t *dev)
|
||||
{
|
||||
char reg[2];
|
||||
uint16_t tmp = TMP006_CONFIG_RST;
|
||||
reg[0] = (uint8_t)(tmp >> 8);
|
||||
reg[1] = (uint8_t)tmp;
|
||||
dev->initialized = false;
|
||||
|
||||
if (i2c_write_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tmp006_set_active(tmp006_t *dev)
|
||||
{
|
||||
char reg[2];
|
||||
|
||||
if (dev->initialized == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg[0] |= (uint8_t)(TMP006_CONFIG_MOD(TMP006_CONFIG_MOD_CC) >> 8);
|
||||
|
||||
if (i2c_write_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tmp006_set_standby(tmp006_t *dev)
|
||||
{
|
||||
char reg[2];
|
||||
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg[0] &= ~(uint8_t)(TMP006_CONFIG_MOD(TMP006_CONFIG_MOD_CC) >> 8);
|
||||
|
||||
if (i2c_write_regs(dev->i2c, dev->addr, TMP006_CONFIG, reg, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tmp006_read(tmp006_t *dev, int16_t *rawv, int16_t *rawt, uint8_t *drdy)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
if (dev->initialized == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register bytes are sent MSB first. */
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_CONFIG, buf, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*drdy = buf[1] & (uint8_t)(TMP006_CONFIG_DRDY);
|
||||
|
||||
if (!(*drdy)) {
|
||||
/* conversion in progress */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_V_OBJECT, buf, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*rawv = ((uint16_t)buf[0] << 8) | buf[1];
|
||||
|
||||
if (i2c_read_regs(dev->i2c, dev->addr, TMP006_T_AMBIENT, buf, 2) != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*rawt = ((uint16_t)buf[0] << 8) | buf[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tmp006_convert(int16_t rawv, int16_t rawt, float *tamb, float *tobj)
|
||||
{
|
||||
/* calculate die temperature */
|
||||
*tamb = (double)rawt / 128.0;
|
||||
/* die temperature in Kelvin */
|
||||
double tdie_k = *tamb + 273.15;
|
||||
|
||||
/* calculate sensor voltage */
|
||||
double sens_v = (double)rawv * TMP006_CCONST_LSB_SIZE;
|
||||
|
||||
double tdiff = tdie_k - TMP006_CCONST_TREF;
|
||||
double tdiff_pow2 = pow(tdiff, 2);
|
||||
|
||||
double s = TMP006_CCONST_S0 * (1 + TMP006_CCONST_A1 * tdiff
|
||||
+ TMP006_CCONST_A2 * tdiff_pow2);
|
||||
|
||||
double v_os = TMP006_CCONST_B0 + TMP006_CCONST_B1 * tdiff
|
||||
+ TMP006_CCONST_B2 * tdiff_pow2;
|
||||
|
||||
double f_obj = (sens_v - v_os) + TMP006_CCONST_C2 * pow((sens_v - v_os), 2);
|
||||
|
||||
double t = pow(pow(tdie_k, 4) + (f_obj / s), 0.25);
|
||||
/* calculate object temperature in Celsius */
|
||||
*tobj = (t - 273.15);
|
||||
}
|
Loading…
Reference in New Issue