1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #15383 from quangphhr/hsc_driver

drives/hsc: Add driver for Honeywell HSC series pressure and temperature sensor
This commit is contained in:
Marian Buschsieweke 2021-01-06 16:14:39 +01:00 committed by GitHub
commit 4bd448b949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 701 additions and 0 deletions

View File

@ -67,6 +67,7 @@ rsource "gp2y10xx/Kconfig"
rsource "hdc1000/Kconfig"
rsource "hih6130/Kconfig"
rsource "hmc5883l/Kconfig"
rsource "hsc/Kconfig"
rsource "hts221/Kconfig"
rsource "ina2xx/Kconfig"
rsource "ina3221/Kconfig"

41
drivers/hsc/Kconfig Normal file
View File

@ -0,0 +1,41 @@
# Copyright (c) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
#
# 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.
#
config MODULE_HSC
bool "Driver for Honeywell HSC series pressure and temperature sensor"
depends on HAS_PERIPH_I2C
depends on TEST_KCONFIG
select MODULE_PERIPH_I2C
help
This driver supports the Honeywell HSC series pressure and temperature
sensors that use an I2C interface.
menuconfig KCONFIG_USEMODULE_HSC
bool "Configure HSC pressure and temperature sensor driver"
depends on USEMODULE_HSC
help
Configure the hsc driver using Kconfig.
if KCONFIG_USEMODULE_HSC
config HSC_I2C_ADDRESS
hex "I2C address of the HSC pressure and temperature sensor"
range 0x28 0x98
default 0x28
help
The HSC sensors can have one of the following I2C addresses:
0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, and 0x98
config HSC_RANGE
int "Pressure range in millibar"
range 1 10000
default 40
help
The HSC sensors support a pressure range of 1.6 millibar to 10 bar,
depending on the model.
endif # KCONFIG_USEMODULE_HSC

1
drivers/hsc/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

1
drivers/hsc/Makefile.dep Normal file
View File

@ -0,0 +1 @@
FEATURES_REQUIRED += periph_i2c

View File

@ -0,0 +1,2 @@
USEMODULE_INCLUDES_hsc := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_hsc)

163
drivers/hsc/hsc.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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_hsc
* @{
*
* @file
* @brief Device driver implementation for the Honeywell HSC
* temperature and pressure sensor.
*
* @author Quang Pham <phhr_quang@live.com>
*
* @}
*/
#include "hsc.h"
#include "errno.h"
#include "hsc_internals.h"
#include "hsc_params.h"
#include "periph/i2c.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define DEV_I2C (dev->params.i2c_dev)
#define DEV_ADDR (dev->params.i2c_addr)
#define PRESS_RANGE (dev->params.hsc_range)
/* Internal function prototypes */
static int _read_ut(const hsc_t *dev, int32_t *ut);
static int _read_up(const hsc_t *dev, int32_t *up);
/*---------------------------------------------------------------------------*
* HSC Core API *
*---------------------------------------------------------------------------*/
int hsc_init(hsc_t *dev, const hsc_params_t *params)
{
dev->params = *params;
uint8_t buf[HSC_FULL_DATA_LENGTH];
/* Acquire exclusive access */
if (i2c_acquire(DEV_I2C)) {
return -ENODEV;
}
if (i2c_read_bytes(DEV_I2C, DEV_ADDR, buf, sizeof(buf), 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[hsc] read_bytes fails\n");
return -EIO;
}
i2c_release(DEV_I2C);
/* Check the status of the sensor */
uint8_t status = buf[0];
switch (status & HSC_STATUS_MASK) {
case HSC_STATUS_OK:
break;
case HSC_STATUS_STALE_DATA:
return -EAGAIN;
default:
return -EIO;
}
return 0;
}
int hsc_read_temperature(const hsc_t *dev, int16_t *dest)
{
int32_t ut = 0;
int retval;
/* Read uncompensated temperature value */
if ((retval = _read_ut(dev, &ut)) != 0) {
return retval;
}
/* Formular from section 4.0 in
* https://sensing.honeywell.com/i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-final-30may12.pdf */
*dest = ut * 2000 / 2047 - 500;
return 0;
}
int hsc_read_pressure(const hsc_t *dev, int32_t *dest)
{
int32_t up = 0;
int retval;
/* Read uncompensated pressure value */
if ((retval = _read_up(dev, &up)) != 0) {
return retval;
}
/* Formular from section 3.0 in
* https://sensing.honeywell.com/i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-final-30may12.pdf */
const int32_t output_max = 14745;
const int32_t output_min = 1636;
*dest = ((up - output_min) * 2000 * HSC_PARAM_RANGE / (output_max - output_min) - 1000 * HSC_PARAM_RANGE);
return 0;
}
/*---------------------------------------------------------------------------*
* Internal functions *
*---------------------------------------------------------------------------*/
static int _read_ut(const hsc_t *dev, int32_t *output)
{
/* Read UT (Uncompsensated Temperature value) */
uint8_t buf[HSC_FULL_DATA_LENGTH];
/* Acquire exclusive access */
if (i2c_acquire(DEV_I2C)) {
return -ENODEV;
}
if (i2c_read_bytes(DEV_I2C, DEV_ADDR, buf, sizeof(buf), 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[hsc] read_bytes fails\n");
return -EIO;
}
i2c_release(DEV_I2C);
*output = (((buf[2] << 8) | buf[3]) >> HSC_TEMPERATURE_SHIFT);
return 0;
}
static int _read_up(const hsc_t *dev, int32_t *output)
{
/* Read UP (Uncompsensated Pressure value) */
uint8_t buf[HSC_FULL_DATA_LENGTH];
/* Acquire exclusive access */
if (i2c_acquire(DEV_I2C)) {
return -ENODEV;
}
if (i2c_read_bytes(DEV_I2C, DEV_ADDR, buf, sizeof(buf), 0) < 0) {
i2c_release(DEV_I2C);
DEBUG("[hsc] read_bytes fails\n");
return -EIO;
}
i2c_release(DEV_I2C);
*output = ((buf[0] << 8) | buf[1]) & HSC_PRESSURE_MASK;
return 0;
}

56
drivers/hsc/hsc_saul.c Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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_hsc
* @{
*
* @file
* @brief SAUL adaption for HSC device
*
* @author Quang Pham <phhr_quang@live.com>
* @}
*/
#include <string.h>
#include "saul.h"
#include "hsc.h"
static int read_temperature(const void *dev, phydat_t *res)
{
if (hsc_read_temperature(dev, res->val) != 0) {
return 0;
}
res->unit = UNIT_TEMP_C;
res->scale = -1;
return 1;
}
static int read_pressure(const void *dev, phydat_t *res)
{
int32_t value;
if (hsc_read_pressure(dev, &value) != 0) {
return 0;
}
res->unit = UNIT_BAR;
res->scale = -6;
phydat_fit(res, &value, 1);
return 1;
}
const saul_driver_t hsc_temperature_saul_driver = {
.read = read_temperature,
.write = saul_notsup,
.type = SAUL_SENSE_TEMP
};
const saul_driver_t hsc_pressure_saul_driver = {
.read = read_pressure,
.write = saul_notsup,
.type = SAUL_SENSE_PRESS
};

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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_hsc
* @brief Internal addresses, constants for the HSC sensor.
* @{
*
* @file
* @brief Internal addresses, constants for the HSC sensor.
*
* @author Quang Pham <phhr_quang@live.com>
*/
#ifndef HSC_INTERNALS_H
#define HSC_INTERNALS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name HSC I2C Packet Readout
* @{
*/
#define HSC_PRESSURE_DATA_LENGTH (2) /**<
Pressure is stored in the first 2 bytes of data */
#define HSC_FULL_DATA_LENGTH (4) /**<
Pressure + temperature data is 4 bytes long */
#define HSC_STATUS_MASK (0xc0) /**<
Bit mask for the status bits in the first byte */
#define HSC_PRESSURE_MASK (0x3fff) /**<
Bit mask for the pressure data */
#define HSC_TEMPERATURE_SHIFT (5) /**<
Temperature data is left adjusted within the word */
/** @} */
/**
* @name Status and error return codes
* @{
*/
enum {
HSC_STATUS_OK = 0x00,
/**
* stale data: data that has already been fetched since the last measurement
* cycle, or data fetched before the first measurement has been completed.
*/
HSC_STATUS_STALE_DATA = 0x40,
HSC_STATUS_COMMAND_MODE = 0x80,
HSC_STATUS_DIAGNOSTIC = 0xc0,
};
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* HSC_INTERNALS_H */
/** @} */

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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_hsc
*
* @{
* @file
* @brief Default configuration for HSC
*
* @author Quang Pham <phhr_quang@live.com>
*/
#ifndef HSC_PARAMS_H
#define HSC_PARAMS_H
#include "board.h"
#include "hsc.h"
#include "hsc_internals.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the HSC
* @{
*/
#ifndef HSC_PARAM_I2C_DEV
#define HSC_PARAM_I2C_DEV I2C_DEV(0)
#endif
#ifndef HSC_PARAM_I2C_ADDR
#define HSC_PARAM_I2C_ADDR CONFIG_HSC_I2C_ADDR
#endif
#ifndef HSC_PARAM_RANGE
#define HSC_PARAM_RANGE CONFIG_HSC_RANGE
#endif
#ifndef HSC_PARAMS
#define HSC_PARAMS { .i2c_dev = HSC_PARAM_I2C_DEV, \
.i2c_addr = HSC_PARAM_I2C_ADDR, \
.hsc_range = HSC_PARAM_RANGE, }
#endif
#ifndef HSC_SAUL_INFO
#define HSC_SAUL_INFO { .name = "hsc" }
#endif
/**@}*/
/**
* @brief Configure HSC
*/
static const hsc_params_t hsc_params[] =
{
HSC_PARAMS
};
/**
* @brief Configure SAUL registry entries
*/
static const saul_reg_info_t hsc_saul_info[] =
{
HSC_SAUL_INFO
};
#ifdef __cplusplus
}
#endif
#endif /* HSC_PARAMS_H */
/** @} */

105
drivers/include/hsc.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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_hsc HSC temperature and pressure sensor
* @ingroup drivers_sensors
* @ingroup drivers_saul
* @brief Device driver interface for the HSC sensor
*
* This driver provides @ref drivers_saul capabilities.
* @{
*
* @file
* @brief Device driver interface for the HSC sensor.
*
* @author Quang Pham <phhr_quang@live.com>
*/
#ifndef HSC_H
#define HSC_H
#include "saul.h"
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Device initialization parameters
*/
typedef struct {
i2c_t i2c_dev; /**< I2C device which is used */
uint8_t i2c_addr; /**< I2C address */
uint8_t hsc_range; /**< Pressure range in mBar */
} hsc_params_t;
/**
* @brief Device descriptor for the HSC sensor
*/
typedef struct {
hsc_params_t params; /**< Device initialization parameters */
} hsc_t;
/**
* @brief Initialize the given HSC device
*
* @param[out] dev Initialized device descriptor of HSC device
* @param[in] params Initialization parameters
*
* @retval 0 Success
* @retval -ENXIO No HSC at given address
* @return -EIO An error occurred when reading calibration values
*/
int hsc_init(hsc_t *dev, const hsc_params_t *params);
/**
* @brief Read temperature value from the given HSC device, returned in 0.1°C
*
* @param[in] dev Device descriptor of HSC device to read from
* @param[out] dest Temperature in 0.1°C
*
* @retval 0 Success
* @retval -ENXIO No HSC at given address
* @return -EIO An error occurred when reading calibration values
*/
int hsc_read_temperature(const hsc_t *dev, int16_t *dest);
/**
* @brief Read pressure value from the given HSC device, returned in uBar
*
* @param[in] dev Device descriptor of HSC device to read from
* @param[out] dest Pressure in uBar
*
* @retval 0 Success
* @retval -ENXIO No HSC at given address
* @return -EIO An error occurred when reading calibration values
*/
int hsc_read_pressure(const hsc_t *dev, int32_t *dest);
/**
* @name Default configuration values
* @{
*/
#if !defined(CONFIG_HSC_I2C_ADDR) || defined(DOXYGEN)
#define CONFIG_HSC_I2C_ADDR (0x28) /**< Use address 0x28 by default */
#endif
#if !defined(CONFIG_HSC_RANGE) || defined(DOXYGEN)
#define CONFIG_HSC_RANGE (40U) /**< Default to 40 millibar range */
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* HSC_H */
/** @} */

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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 sys_auto_init_saul
* @{
*
* @file
* @brief Auto initialization of HSC driver.
*
* @author Quang Pham <phhr_quang@live.com>
*
* @}
*/
#ifdef MODULE_HSC
#include "assert.h"
#include "log.h"
#include "saul_reg.h"
#include "hsc.h"
#include "hsc_params.h"
/**
* @brief Define the number of configured sensors
*/
#define HSC_NUM ARRAY_SIZE(hsc_params)
/**
* @brief Allocation of memory for device descriptors
*/
static hsc_t hsc_devs[HSC_NUM];
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[HSC_NUM * 2];
/**
* @brief Define the number of saul info
*/
#define HSC_INFO_NUM ARRAY_SIZE(hsc_saul_info)
/**
* @name Reference the driver structs.
* @{
*/
extern const saul_driver_t hsc_temperature_saul_driver;
extern const saul_driver_t hsc_pressure_saul_driver;
/** @} */
void auto_init_hsc(void)
{
static_assert(HSC_INFO_NUM == HSC_NUM, "Number of descriptions and sensors must match");
LOG_DEBUG("[auto_init_saul] Number of HSC devices = %d\n", HSC_NUM);
for (unsigned i = 0; i < HSC_NUM; i++) {
LOG_DEBUG("[auto_init_saul] initializing hsc #%u\n", i);
if (hsc_init(&hsc_devs[i], &hsc_params[i]) != 0) {
LOG_ERROR("[auto_init_saul] error initializing hsc #%u\n", i);
continue;
}
/* temperature */
saul_entries[(i * 2)].dev = &(hsc_devs[i]);
saul_entries[(i * 2)].name = hsc_saul_info[i].name;
saul_entries[(i * 2)].driver = &hsc_temperature_saul_driver;
/* pressure */
saul_entries[(i * 2) + 1].dev = &(hsc_devs[i]);
saul_entries[(i * 2) + 1].name = hsc_saul_info[i].name;
saul_entries[(i * 2) + 1].driver = &hsc_pressure_saul_driver;
/* register to saul */
saul_reg_add(&(saul_entries[(i * 2)]));
saul_reg_add(&(saul_entries[(i * 2) + 1]));
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_HSC */

View File

@ -119,6 +119,10 @@ void saul_init_devs(void)
extern void auto_init_hdc1000(void);
auto_init_hdc1000();
}
if (IS_USED(MODULE_HSC)) {
extern void auto_init_hsc(void);
auto_init_hsc();
}
if (IS_USED(MODULE_HTS221)) {
extern void auto_init_hts221(void);
auto_init_hts221();

View File

@ -0,0 +1,6 @@
include ../Makefile.tests_common
USEMODULE += hsc
USEMODULE += xtimer
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,3 @@
BOARD_INSUFFICIENT_MEMORY := \
nucleo-l011k4 \
#

View File

@ -0,0 +1,10 @@
## About
This is a test application for the HSC Pressure and Temperature sensor.
## Usage
The application will continue trying to initiate the HSC sensor.
After initialization, every second, the application:
* reads the temperature (°C);
* reads the pressure (uBar);
* prints those values to STDOUT.

View File

@ -0,0 +1,2 @@
CONFIG_MODULE_HSC=y
CONFIG_MODULE_XTIMER=y

79
tests/driver_hsc/main.c Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2020 Deutsches Zentrum für Luft- und Raumfahrt e.V. (DLR)
*
* 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 HSC pressure and temperature sensor
*
* @author Quang Pham <phhr_quang@live.com>
*
* @}
*/
#include <stdlib.h>
#include <stdio.h>
#include "errno.h"
#include "string.h"
#include "hsc.h"
#include "hsc_params.h"
#include "xtimer.h"
#define SLEEP_USEC (1UL * US_PER_SEC)
int main(void)
{
hsc_t dev;
int retval;
xtimer_usleep(SLEEP_USEC);
puts("HSC test application\n");
printf("+------------Initializing------------+\n");
do {
retval = hsc_init(&dev, &hsc_params[0]);
if (retval < 0) {
if (IS_USED(MODULE_NEWLIB) || IS_USED(MODULE_PICOLIBC)) {
printf("Initialization error with code: %s\n", strerror(-retval));
}
else {
puts("Initialization failed");
}
}
xtimer_usleep(SLEEP_USEC);
} while (retval);
puts("Initialization successful\n");
printf("+--------Starting Measurements--------+\n");
while (1) {
/* Get temperature in degrees celsius */
int16_t temperature;
if ((retval = hsc_read_temperature(&dev, &temperature)) != 0) {
printf("Get temp fail with code %d\n", retval);
}
/* Get pressure in ubar */
int32_t pressure;
if ((retval = hsc_read_pressure(&dev, &pressure)) != 0) {
printf("Get press fail with code %d\n", retval);
}
printf("Measured pressure is %" PRId32 "ubar\n", pressure);
printf(" Measured temp is %d.%d °C\n", temperature/10, temperature%10);
xtimer_usleep(SLEEP_USEC);
}
return 0;
}