1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-17 18:43:50 +01:00
Marian Buschsieweke cac44edec7
tree-wide: replace multiple empty lines with one
For each C source/header `$file`: `sed -e '/^$/N;/^\n$/D' -i $file`.
2025-05-21 22:51:04 +02:00

312 lines
10 KiB
C

/*
* Copyright (C) 2024 CNRS, France
*
* 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.
*/
#pragma once
/**
* @defgroup drivers_abp2 ABP2 series Honeywell pressure and temperature sensor driver
* @ingroup drivers_sensors
* @ingroup drivers_saul
* @brief SPI and I2C pressure and temperature sensor driver.
*
*
* ## Description
*
* The unit and the range depend on the part number of the sensor.
* The default parameters assume a 0..160 mbar model.
* It is the responsibility of the user to use homogeneous units, depending
* on the actual sensor being used.
* The pressure range is set when calling #abp2_init().
*
* This driver provides @ref drivers_saul capabilities.
* The functions return 0 on success or a negative value made from \c errno.h on error.
*
* ## Usage
*
* See `RIOT/tests/drivers/abp2` for an example application using this driver.
*
* Add the following modules to the application makefile:
* \code
* USEMODULE += abp2
* USEMODULE += abp2_spi
* \endcode
* When the I2C version is supported, `abp2_i2c` can be used for I2C sensors
* instead of `abp2_spi`.
*
* To use the SAUL interface, add also to the makefile:
* \code
* USEMODULE += saul_default
* \endcode
*
* Initialize the driver by calling #abp2_init().
*
* When a measurement is started on the sensor, its internal ADC converts
* both pressure and temperature.
* The conversion takes about 5ms.
* These two values are retrieved in a single bus transfer.
*
* There are three ways to use the driver:
* - blocking mode : call #abp2_read()
* - non-blocking mode : call #abp2_read_nb()
* - the SAUL interface
*
* The first one will block for about 5ms and return the latest data, while
* the second one will return almost immediately but will return data from
* the previous ADC conversion.
*
* ## Caveats
*
* This driver currently doesn't support the I2C flavor of these sensors.
*
* @{
*
* @file
* @brief Honeywell ABP2 series pressure and temperature
* sensor driver
*
* @author David Picard <david.picard@clermont.in2p3.fr>
*/
#include "saul.h"
#if defined(MODULE_ABP2_SPI)
#include "periph/spi.h"
#include "periph/gpio.h"
#elif defined(MODULE_ABP2_I2C)
#include "periph/i2c.h"
#else
#error "ABP2 driver >> Please add a valid module: either abp2_spi or abp2_i2c"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MODULE_ABP2_I2C)
/**
* @brief Default I2C slave address for ABP2 devices
*
* The sensor address cannot be changed.
* A different address can only be obtained upon special request to Honeywell.
*/
#define ABP2_ADDR_DEFAULT (0x28)
#endif
/**
* @defgroup abp2_statusbits Status bits
* @{
* Macro definitions to manipulate the bits of the status byte.
*
* Status byte explanation :
*
* Bit | Meaning | Comment |
* --- | --- | --- |
* 7 | always 0 | |
* 6 | 1 : device is powered | |
* 5 | 1 : device is busy | Wait longer between 2 commands. |
* 4 | always 0 | |
* 3 | always 0 | |
* 2 | 1 : integrity test failed | Checksum error at power-up. |
* 1 | always 0 | |
* 0 | 1 : internal math saturation | |
*/
#define ABP2_STATUS_BUSY 0x20 /**< Sensor is busy. */
#define ABP2_STATUS_MEMERR 0x04 /**< Memory integrity error. */
#define ABP2_STATUS_MATHSAT 0x01 /**< Math saturation error. */
/** A bitwise AND of the status byte with this mask will return true in case of error. */
#define ABP2_STATUS_MASK (ABP2_STATUS_BUSY | ABP2_STATUS_MEMERR | ABP2_STATUS_MATHSAT)
/** @} */ /* end of abp2_statusbits */
/**
* @brief Parameters for ABP2 sensors.
*
* The range must be set in thousandths of sensor unit.
* For example, if the sensor unit is mbar, set the \a rangeMin and \a rangeMax
* properties in µbar.
*/
typedef struct abp2_params {
#if defined(MODULE_ABP2_SPI)
spi_t spi; /**< SPI bus the sensor is connected to. */
spi_cs_t cs; /**< CS pin GPIO handle. */
spi_clk_t clk; /**< SPI bus clock speed. */
#else
i2c_t i2c; /**< I2C bus the device is connected to. */
#endif
int32_t rangeMin; /**< Minimum pressure range (thousandths of sensor unit). */
int32_t rangeMax; /**< Maximum pressure range (thousandths of sensor unit). */
} abp2_params_t;
/**
* @brief Device descriptor for ABP2 sensors.
*/
typedef struct abp2 {
const abp2_params_t *params; /**< Sensor parameters. */
} abp2_t;
/**
* @brief Raw values read from a ABP2 sensor.
*/
typedef struct abp2_raw {
uint32_t cntPress; /**< 24-bit digital pressure reading (counts). */
uint32_t cntTemp; /**< 24-bit digital temperature reading (counts). */
} abp2_raw_t;
/**
* @brief Initialize the ABP2 sensor.
*
*
* @param[in] dev Sensor device descriptor.
* @param[in] params Sensor parameters. \sa #abp2_params.
*
* Assign the parameters \a params to the device descriptor \a dev.
* Poll the device until the busy flag clears or the operation times out.
* On SPI version, init the chip select pin.
*
* @note The bus is expected to be initialized when calling this function.
* @note \a params sets the sensor range.
*
* @return 0 on success
* @return \a -EIO on bus error or \a -ETIMEDOUT on timeout.
*/
int abp2_init(abp2_t *dev, const abp2_params_t *params);
/**
* @brief Let the sensor make one measurement.
*
* @param[in] dev Sensor device descriptor.
*
* This function lets the sensor transition from standby to operation mode
* and make one measurement, after which it will automatically return to
* standby mode.
* Call #abp2_read_raw() to retrieve the data.
*
* @return 0 on success
* @return \a -ENODATA on sensor error.
*/
int abp2_measure(const abp2_t *dev);
/**
* @brief Measure pressure and temperature (blocking version).
*
* @param[in] dev Sensor device descriptor.
* @param[out] press Pressure value read from the sensor (thousandths of sensor unit).
* @param[out] temp Temperature read from the sensor (milli-degrees Celsius).
*
* This function is **blocking**.
* It starts a conversion on the sensor ADC for both pressure and temperature, waits until
* the busy flag clears or for a **10ms timeout**, reads the values from the sensor and converts
* them to physical quantities.
*
* \sa The non-blocking version: #abp2_read_nb().
*
* @return 0 on success
* @return \a -#ETIMEDOUT on timeout
* @return \a -#ENODATA on sensor error
*/
int abp2_read(const abp2_t *dev, int32_t *press, int32_t *temp);
/**
* @brief Measure pressure and temperature (non-blocking version).
*
* @param[in] dev Sensor device descriptor.
* @param[out] press Pressure value read from the sensor (thousandths of sensor unit).
* @param[out] temp Temperature read from the sensor (milli-degrees Celsius).
*
* This function starts a conversion on the sensor ADC and reads the values
* from the **previous conversion** in a single bus transfer and converts
* them to physical quantities.
*
* \sa The blocking version: #abp2_read().
*
* @return 0 on success
* @return \a -#ENODATA on sensor error
*/
int abp2_read_nb(const abp2_t *dev, int32_t *press, int32_t *temp);
/**
* @brief Read the status byte of the sensor.
*
* @param[in] dev Sensor device descriptor.
*
* \sa \ref abp2_statusbits
*
* @return The status byte.
*/
uint8_t abp2_getstatus(const abp2_t *dev);
/**
* @brief Read pressure and temperature raw values.
*
* @param[in] dev Sensor device descriptor.
* @param[out] raw_values Raw values read from the sensor.
*
* Read the raw values, i.e. ADC counts and populate \a raw_values.
* The raw values can be converted to physical quantities with
* #abp2_pressure() and #abp2_temperature().
*
* \pre A measurement must have been initiated by #abp2_measure()
* and have completed (ca. 5ms).
*
* @return 0 on success
* @return \a -ENODATA on sensor error.
*/
int abp2_read_raw(const abp2_t *dev, abp2_raw_t *raw_values);
/**
* @brief Start measurement and read previous pressure and temperature raw values.
*
* @param[in] dev Sensor device descriptor.
* @param[out] raw_values Raw values read from the sensor.
*
* Read the raw values, i.e. ADC counts that result from the previous
* measurement.
* Then, populate \a raw_values.
* The raw values can be converted to physical quantities with
* #abp2_pressure() and #abp2_temperature().
*
* \pre A measurement must have been initiated by #abp2_measure()
* or a previous call to this function, in order to retrieve valid data.
*
* @note This function leads to concise user code. However, in order
* to get valid data, it must be called periodically, and at short intervals.
* If the application favors power savings i.e. low frequency measurements, then
* #abp2_measure() and #abp2_read_raw() are a better option.
*
* @return 0 on success
* @return \a -ENODATA on sensor error.
*/
int abp2_measure_read(const abp2_t *dev, abp2_raw_t *raw_values);
/**
* @brief Convert ADC counts to pressure.
*
* @param[in] dev Sensor device descriptor.
* @param[in] raw_values Raw values read from the sensor.
*
* \sa #abp2_params to know how to set the sensor range.
* @return The pressure in thousandths of user units, as set in the parameters
* of #abp2_init().
*/
int32_t abp2_pressure(const abp2_t *dev, const abp2_raw_t *raw_values);
/**
* @brief Convert ADC counts to temperature .
*
* @param[in] dev Sensor device descriptor.
* @param[in] raw_values Raw values read from the sensor.
*
* @return The temperature in milli-degrees Celsius.
*/
int32_t abp2_temperature(const abp2_t *dev, const abp2_raw_t *raw_values);
#ifdef __cplusplus
}
#endif
/** @} */