Browse Source
This includes the Si7006, Si7013, Si7020 and Si7021 I2C sensors, including a test application.pr/gpio


6 changed files with 491 additions and 0 deletions
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Bas Stottelaar <basstottelaar@gmail.com> |
||||
* |
||||
* 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 driver_si70xx Si70xx |
||||
* @ingroup drivers |
||||
* @brief Driver for the Si7006/13/20/21 temperature and humidity sensor. |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface definition of the Si70xx driver. |
||||
* |
||||
* @author Bas Stottelaar <basstottelaar@gmail.com> |
||||
*/ |
||||
|
||||
#ifndef SI70XX_H_ |
||||
#define SI70XX_H_ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "periph/i2c.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @name Si70xx chip addresses. |
||||
*/ |
||||
#define SI70XX_ADDRESS_SI7006 (0x80) |
||||
#define SI70XX_ADDRESS_SI7013 (0x80) |
||||
#define SI70XX_ADDRESS_SI7013_ALT (0x81) |
||||
#define SI70XX_ADDRESS_SI7020 (0x80) |
||||
#define SI70XX_ADDRESS_SI7021 (0x80) |
||||
|
||||
/**
|
||||
* @name Si70xx device commands |
||||
* @{ |
||||
*/ |
||||
#define SI70XX_MEASURE_RH_HOLD (0xE5) |
||||
#define SI70XX_MEASURE_RH (0xF5) |
||||
#define SI70XX_MEASURE_TEMP_HOLD (0xE3) |
||||
#define SI70XX_MEASURE_TEMP (0xF3) |
||||
#define SI70XX_MEASURE_TEMP_PREV (0xE0) |
||||
#define SI70XX_RESET (0xFE) |
||||
#define SI70XX_WRITE_USER_REG (0xE6) |
||||
#define SI70XX_READ_USER_REG (0xE7) |
||||
#define SI70XX_WRITE_HEATER_REG (0x51) |
||||
#define SI70XX_READ_HEATER_REG (0x11) |
||||
#define SI70XX_READ_ID_FIRST_A (0xFA) |
||||
#define SI70XX_READ_ID_FIRST_B (0x0F) |
||||
#define SI70XX_READ_ID_SECOND_A (0xFC) |
||||
#define SI70XX_READ_ID_SECOND_B (0xC9) |
||||
#define SI70XX_READ_REVISION_A (0x84) |
||||
#define SI70XX_READ_REVISION_B (0xB8) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @name Si70xx register values |
||||
* @{ |
||||
*/ |
||||
#define SI70XX_ID_SI7006 (0x06) |
||||
#define SI70XX_ID_SI7013 (0x0D) |
||||
#define SI70XX_ID_SI7020 (0x14) |
||||
#define SI70XX_ID_SI7021 (0x15) |
||||
|
||||
#define SI70XX_REVISION_1 (0xFF) |
||||
#define SI70XX_REVISION_2 (0x20) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @brief Si70xx device descriptor |
||||
*/ |
||||
typedef struct { |
||||
i2c_t i2c_dev; /**< I2C bus the sensors is connected to */ |
||||
uint8_t address; /**< sensor address */ |
||||
} si70xx_t; |
||||
|
||||
/**
|
||||
* @brief Test if the device id and revision number are as expected. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return zero on succesful test |
||||
* @return non-zero on unsuccesfull test. |
||||
*/ |
||||
int si70xx_test(si70xx_t *dev); |
||||
|
||||
/**
|
||||
* @brief Initialize and reset the sensor. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @param[in] i2c_dev i2c device to use |
||||
* @param[in] address device address (depends on the chip) |
||||
* @return zero on succesful initialization. |
||||
* @return non-zero on error |
||||
*/ |
||||
int si70xx_init(si70xx_t *dev, i2c_t i2c_dev, uint8_t address); |
||||
|
||||
/**
|
||||
* @brief Read the relative humidity from the sensor. Uses clock streching. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return relative humidity in centi-percent (times 100) |
||||
*/ |
||||
uint16_t si70xx_get_relative_humidity(si70xx_t *dev); |
||||
|
||||
/**
|
||||
* @brief Read the current temperature from the sensor. Uses clock streching. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return current temperature in centi-degrees Celsius |
||||
* (times 100) |
||||
*/ |
||||
int16_t si70xx_get_temperature(si70xx_t *dev); |
||||
|
||||
/**
|
||||
* @brief Read the relative humidity and temperature from the sensor. Uses |
||||
* clock stretching. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @param[out] humidity pointer to relative humidity (in centi-percent) |
||||
* @param[out] temperature pointer to temperature (in centi-degrees Celsius) |
||||
*/ |
||||
void si70xx_get_both(si70xx_t *dev, uint16_t *humidity, int16_t *temperature); |
||||
|
||||
/**
|
||||
* @brief Read the sensor serial number. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return sensor serial number |
||||
*/ |
||||
uint64_t si70xx_get_serial(si70xx_t *dev); |
||||
|
||||
/**
|
||||
* @brief Read the sensor id, to identifier the sensor variant. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return device id |
||||
*/ |
||||
uint8_t si70xx_get_id(si70xx_t *dev); |
||||
|
||||
/**
|
||||
* @brief Read the firmware revision of the sensor. |
||||
* |
||||
* @param[in] dev device descriptor |
||||
* @return sensor firmware revision number |
||||
*/ |
||||
uint8_t si70xx_get_revision(si70xx_t *dev); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* SI70XX_H_ */ |
||||
/** @} */ |
@ -0,0 +1,3 @@
|
||||
MODULE = si70xx
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Bas Stottelaar <basstottelaar@gmail.com> |
||||
* |
||||
* 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 driver_si70xx |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Implementation of Si7006/13/20/21 sensor driver. |
||||
* |
||||
* @author Bas Stottelaar <basstottelaar@gmail.com> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
|
||||
#include "si70xx.h" |
||||
|
||||
#include "xtimer.h" |
||||
|
||||
/**
|
||||
* @brief Utility method to perform and reconstruct a measurement. |
||||
*/ |
||||
static uint32_t si70xx_measure(si70xx_t *dev, uint8_t command) |
||||
{ |
||||
uint8_t result[2]; |
||||
|
||||
i2c_acquire(dev->i2c_dev); |
||||
i2c_write_byte(dev->i2c_dev, dev->address, command); |
||||
i2c_read_bytes(dev->i2c_dev, dev->address, (char *) result, 2); |
||||
i2c_release(dev->i2c_dev); |
||||
|
||||
/* reconstruct raw result */ |
||||
return (result[0] << 8) + (result[1] & 0xfc); |
||||
} |
||||
|
||||
int si70xx_test(si70xx_t *dev) |
||||
{ |
||||
uint8_t revision = si70xx_get_revision(dev); |
||||
|
||||
if (revision != SI70XX_REVISION_1 && revision != SI70XX_REVISION_2) { |
||||
return -1; |
||||
} |
||||
|
||||
uint8_t id = si70xx_get_id(dev); |
||||
|
||||
if (id != SI70XX_ID_SI7006 && id != SI70XX_ID_SI7013 && |
||||
id != SI70XX_ID_SI7020 && id != SI70XX_ID_SI7021) { |
||||
return -2; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int si70xx_init(si70xx_t *dev, i2c_t i2c_dev, uint8_t address) |
||||
{ |
||||
dev->i2c_dev = i2c_dev; |
||||
dev->address = address; |
||||
|
||||
/* setup the i2c bus */ |
||||
i2c_acquire(dev->i2c_dev); |
||||
int result = i2c_init_master(dev->i2c_dev, I2C_SPEED_NORMAL); |
||||
|
||||
if (result != 0) { |
||||
i2c_release(dev->i2c_dev); |
||||
return result; |
||||
} |
||||
|
||||
/* initialize the peripheral */ |
||||
i2c_write_byte(dev->i2c_dev, dev->address, SI70XX_RESET); |
||||
|
||||
/* sensor is ready after at most 25 ms */ |
||||
xtimer_usleep(25 * MS_IN_USEC); |
||||
i2c_release(dev->i2c_dev); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
uint16_t si70xx_get_relative_humidity(si70xx_t *dev) |
||||
{ |
||||
uint32_t raw; |
||||
uint16_t humidity; |
||||
|
||||
/* perform measurement */ |
||||
raw = si70xx_measure(dev, SI70XX_MEASURE_RH_HOLD); |
||||
|
||||
humidity = ((12500 * raw) / 65536) - 600; |
||||
|
||||
/* according to datasheet, values may exceed bounds, but can be clipped */ |
||||
if (humidity < 0) { |
||||
return 0; |
||||
} |
||||
else if (humidity > 10000) { |
||||
return 10000; |
||||
} |
||||
else { |
||||
return humidity; |
||||
} |
||||
} |
||||
|
||||
int16_t si70xx_get_temperature(si70xx_t *dev) |
||||
{ |
||||
uint32_t raw; |
||||
|
||||
/* perform measurement */ |
||||
raw = si70xx_measure(dev, SI70XX_MEASURE_TEMP_HOLD); |
||||
|
||||
return ((17572 * raw) / 65536) - 4685; |
||||
} |
||||
|
||||
void si70xx_get_both(si70xx_t *dev, uint16_t *humidity, int16_t *temperature) |
||||
{ |
||||
uint32_t raw; |
||||
|
||||
/* read the humidity the normal way */ |
||||
*humidity = si70xx_get_relative_humidity(dev); |
||||
|
||||
/* read the temperature using the data from the previous measurement */ |
||||
raw = si70xx_measure(dev, SI70XX_MEASURE_TEMP_PREV); |
||||
|
||||
*temperature = ((17572 * raw) / 65536) - 4685; |
||||
} |
||||
|
||||
uint64_t si70xx_get_serial(si70xx_t *dev) |
||||
{ |
||||
uint8_t out[2]; |
||||
uint8_t in_first[8]; |
||||
uint8_t in_second[8]; |
||||
|
||||
/* read the lower bytes */ |
||||
out[0] = SI70XX_READ_ID_FIRST_A; |
||||
out[1] = SI70XX_READ_ID_FIRST_B; |
||||
|
||||
i2c_acquire(dev->i2c_dev); |
||||
i2c_write_bytes(dev->i2c_dev, dev->address, (char *) out, 2); |
||||
i2c_read_bytes(dev->i2c_dev, dev->address, (char *) in_first, 8); |
||||
|
||||
/* read the higher bytes */ |
||||
out[0] = SI70XX_READ_ID_SECOND_A; |
||||
out[1] = SI70XX_READ_ID_SECOND_B; |
||||
|
||||
i2c_write_bytes(dev->i2c_dev, dev->address, (char *) out, 2); |
||||
i2c_read_bytes(dev->i2c_dev, dev->address, (char *) in_second, 8); |
||||
i2c_release(dev->i2c_dev); |
||||
|
||||
/* calculate the ID */ |
||||
uint32_t id_first = (in_first[0] << 24) + (in_first[2] << 16) + |
||||
(in_first[4] << 8) + (in_first[6] << 0); |
||||
uint32_t id_second = (in_second[0] << 24) + (in_second[2] << 16) + |
||||
(in_second[4] << 8) + (in_second[6] << 0); |
||||
|
||||
return (((uint64_t) id_first) << 32) + id_second; |
||||
} |
||||
|
||||
uint8_t si70xx_get_id(si70xx_t *dev) |
||||
{ |
||||
return (si70xx_get_serial(dev) >> 24) & 0xff; |
||||
} |
||||
|
||||
uint8_t si70xx_get_revision(si70xx_t *dev) |
||||
{ |
||||
uint8_t out[2]; |
||||
uint8_t in; |
||||
|
||||
/* read the revision number */ |
||||
out[0] = SI70XX_READ_REVISION_A; |
||||
out[1] = SI70XX_READ_REVISION_B; |
||||
|
||||
i2c_acquire(dev->i2c_dev); |
||||
i2c_write_bytes(dev->i2c_dev, dev->address, (char *) out, 2); |
||||
i2c_read_byte(dev->i2c_dev, dev->address, (char *) &in); |
||||
i2c_release(dev->i2c_dev); |
||||
|
||||
return in; |
||||
} |
@ -0,0 +1,20 @@
|
||||
APPLICATION = driver_si70xx
|
||||
include ../Makefile.tests_common |
||||
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
|
||||
USEMODULE += si70xx
|
||||
USEMODULE += xtimer
|
||||
|
||||
# set default device parameters in case they are undefined
|
||||
TEST_I2C ?= 0
|
||||
TEST_I2C_ADDR ?= 128
|
||||
TEST_PIN_EN ?= 57
|
||||
|
||||
# export parameters
|
||||
CFLAGS += -DTEST_I2C=$(TEST_I2C)
|
||||
CFLAGS += -DTEST_I2C_ADDR=$(TEST_I2C_ADDR)
|
||||
CFLAGS += -DTEST_PIN_EN=$(TEST_PIN_EN)
|
||||
|
||||
include $(RIOTBASE)/Makefile.include |
@ -0,0 +1,14 @@
|
||||
# Si70xx Driver Test |
||||
|
||||
## Introduction |
||||
This test will test if the Si7006/13/20/21 temperature and humidity sensor is working. |
||||
|
||||
## Configuration |
||||
There are three parameters to configure: |
||||
|
||||
* `TEST_I2C` — I2C device to use. |
||||
* `TEST_I2C_ADDR` — The sensor address (usually 0x80 or 0x81). |
||||
* `TEST_PIN_EN` — If required, toggle the enable pin via this GPIO pin (see `GPIO_PIN` macro for your board). |
||||
|
||||
## Expected result |
||||
The sensor should continuously (every 1 sec) output the humidity and temperature. The precision should be two digits. |
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Bas Stottelaar <basstottelaar@gmail.com> |
||||
* |
||||
* 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 tests |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Test application for the Si7006/13/20/21 sensor driver |
||||
* |
||||
* @author Bas Stottelaar <basstottelaar@gmail.com> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#ifndef TEST_I2C |
||||
#error "TEST_I2C not defined" |
||||
#endif |
||||
|
||||
#ifndef TEST_I2C_ADDR |
||||
#error "TEST_I2C_ADDR not defined" |
||||
#endif |
||||
|
||||
#ifndef TEST_PIN_EN |
||||
#error "TEST_PIN_EN not defined" |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include "periph/gpio.h" |
||||
|
||||
#include "xtimer.h" |
||||
|
||||
#include "si70xx.h" |
||||
|
||||
int main(void) |
||||
{ |
||||
si70xx_t dev; |
||||
|
||||
puts("SI7021 temperature and humidity sensor test application\n"); |
||||
|
||||
/* enable the sensor if test pin given */ |
||||
if (TEST_PIN_EN != GPIO_UNDEF) { |
||||
printf("Toggling enable pin..."); |
||||
|
||||
if (gpio_init(TEST_PIN_EN, GPIO_DIR_OUT, GPIO_NOPULL) == 0) { |
||||
puts("[OK]\n"); |
||||
} |
||||
else { |
||||
puts("[Failed]\n"); |
||||
return 1; |
||||
} |
||||
|
||||
gpio_set(TEST_PIN_EN); |
||||
} |
||||
|
||||
/* initialize the sensor */ |
||||
printf("Initializing sensor..."); |
||||
|
||||
if (si70xx_init(&dev, TEST_I2C, TEST_I2C_ADDR) == 0) { |
||||
puts("[OK]\n"); |
||||
} |
||||
else { |
||||
puts("[Failed]"); |
||||
return 1; |
||||
} |
||||
|
||||
/* run sensor test */ |
||||
printf("Testing sensor communication..."); |
||||
|
||||
if (si70xx_test(&dev) == 0) { |
||||
puts("[OK]\n"); |
||||
} |
||||
else { |
||||
puts("[Failed]"); |
||||
return 1; |
||||
} |
||||
|
||||
/* print device id */ |
||||
printf("Identified sensor as the Si70%02i\n", si70xx_get_id(&dev)); |
||||
|
||||
/* read temperature and humidity every 1 seconds */ |
||||
bool both = false; |
||||
|
||||
int16_t temperature; |
||||
uint16_t humidity; |
||||
|
||||
while (1) { |
||||
/* rotate the way of getting the data */ |
||||
if (both) { |
||||
si70xx_get_both(&dev, &humidity, &temperature); |
||||
} |
||||
else { |
||||
temperature = si70xx_get_temperature(&dev); |
||||
humidity = si70xx_get_relative_humidity(&dev); |
||||
} |
||||
|
||||
both = !both; |
||||
|
||||
/* display results */ |
||||
printf("relative humidity: %d.%d\n", humidity / 100, humidity % 100); |
||||
printf("temperature: %d.%d C\n", temperature / 100, temperature % 100); |
||||
|
||||
/* sleep between measurements */ |
||||
xtimer_usleep(1000 * MS_IN_USEC); |
||||
} |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue