mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-17 10:33:49 +01:00
276 lines
9.8 KiB
C
276 lines
9.8 KiB
C
/*
|
|
* Copyright (C) 2025 David Picard
|
|
*
|
|
* 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_max31865 MAX31865 RTD-to-Digital converter driver
|
|
* @ingroup drivers_sensors
|
|
* @ingroup drivers_saul
|
|
* @brief Driver for the SPI RTD-to-Digital converter MAX31865.
|
|
*
|
|
* \section sec_max31865_ovrvw Overview
|
|
|
|
* The MAX31865 is a resistance-to-digital
|
|
* converter optimized for platinum resistance temperature
|
|
* detectors (RTDs). An external resistor sets the sensitivity
|
|
* for the RTD being used and a precision delta-sigma ADC
|
|
* converts the ratio of the RTD resistance to the reference
|
|
* resistance on the board, to a 15-bit word.
|
|
*
|
|
* - Compatible with 2-, 3-, and 4-Wire Sensor Connections
|
|
* - 15-Bit ADC resolution; resolution 0.03125°C
|
|
* - Total accuracy over all operating conditions: 0.5°C (0.05% FS) max
|
|
* - 21 ms max conversion time
|
|
*
|
|
* The RTD register and the threshold registers represent the ratio
|
|
* of the RTD resistance to the reference resistance.
|
|
*
|
|
* @note See the
|
|
* <a href="https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31865.pdf">
|
|
* datasheet</a> for more information.
|
|
*
|
|
* \section sec_max31865_lut Lookup table
|
|
*
|
|
* In order to convert the ADC code to temperature with a decent precision
|
|
* and low CPU usage by using fixed point computation, this driver uses a lookup table.
|
|
* The values of the lookup table depend on the type of RTD, the reference
|
|
* resistance on the board and the temperature range.
|
|
* A default lookup table for a Pt100 sensor, a reference resistance of 330Ω
|
|
* and a temperature range of -200..+650°C is provided.
|
|
* With this lookup table, the standard deviation of the computation
|
|
* error over the -200..+650°C range is 0.011°C and the maximum error
|
|
* is 0.039°C.
|
|
*
|
|
* If the default lookup doesn't fit the application, the user can generate
|
|
* a custom one with the Python script `drivers/max31865/dist/genlut.py`.
|
|
* Type `genlut.py -h` for help.
|
|
* Move the generated header file to the application project directory.
|
|
* In the application code, include `max31865_lut.h`.
|
|
* The header files must be included in the following order:
|
|
*
|
|
* @code
|
|
* #include "max31865.h"
|
|
* #include "max31865_lut.h"
|
|
* #include "max31865_params.h"
|
|
* @endcode
|
|
*
|
|
* The lookup table in the application directory will override the default one.
|
|
*
|
|
* \section sec_max31865_usage Usage
|
|
*
|
|
* The default configuration is set in \ref max31865_params.h as a
|
|
* \ref max31865_params_t structure.
|
|
* Most of them can be changed using the preprocessor definitions either
|
|
* in the board definition in `board.h` or in the Makefile of the application
|
|
* using the `CFLAGS` variable.
|
|
* In particular, let the SPI device and chip select pin fit the board.
|
|
*
|
|
* @code
|
|
* define MAX31865_PARAM_SPI (SPI_DEV(0))
|
|
* define MAX31865_PARAM_CS_PIN (GPIO_PIN(0, 5))
|
|
* @endcode
|
|
*
|
|
* The easiest way to read the temperature is to call #max31865_read().
|
|
* In critical applications, where a sensor failure may cause damage to the
|
|
* system, calling #max31865_read_raw(),
|
|
* #max31865_raw_to_data() and #max31865_detect_fault() independently
|
|
* provides a better control on fault detection.
|
|
*
|
|
* @{
|
|
*
|
|
* @file
|
|
*
|
|
* @author David Picard
|
|
*/
|
|
|
|
/* Add header includes here */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "periph/spi.h"
|
|
|
|
/**
|
|
* @brief Lookup table column indexes
|
|
*
|
|
* The lookup table is a 2D array.
|
|
* This enum defines the indexes of the columns of the table.
|
|
* The conversion from ADC code to temperature is done with a linear interpolation
|
|
* between two lines of the table.
|
|
* The coefficients at line n are valid for the temperature range between line n
|
|
* and line n+1.
|
|
*
|
|
* T = a<sub>0</sub> + a<sub>1</sub> × code
|
|
*/
|
|
typedef enum {
|
|
MAX31865_LUTCOL_CODE = 0, /**< ADC code column index */
|
|
MAX31865_LUTCOL_TEMP = 1, /**< Temperature column index (µ°C) */
|
|
MAX31865_LUTCOL_A0 = 2, /**< a<sub>0</sub> coefficient column index */
|
|
MAX31865_LUTCOL_A1 = 3, /**< a<sub>1</sub> coefficient column index */
|
|
MAX31865_LUTCOL_NUMOF /**< Number of columns in the lookup table */
|
|
} max31865_lutcols_t;
|
|
|
|
/**
|
|
* @brief Device initialization parameters
|
|
*
|
|
* - Use the bits defined in \ref drivers_max31865_constants_regcfg to build the
|
|
* configuration byte #max31865_params_t.cfg_byte.
|
|
* - The high and low thresholds must be set in units of 0.01 °C, e.g. `12000` for 120 °C.
|
|
* - #max31865_params_t.lut_numlines is defined in the header file generated
|
|
* by the Python script `drivers/max31865/dist/genlut.py`.
|
|
*/
|
|
typedef struct {
|
|
spi_t spi; /**< SPI device */
|
|
spi_cs_t cs_pin; /**< Chip select pin */
|
|
uint8_t cfg_byte; /**< Initial value of the configuration register */
|
|
int32_t temp_low_threshold; /**< Low threshold temperature (c°C) */
|
|
int32_t temp_high_threshold; /**< High threshold temperature (c°C) */
|
|
const int32_t (*lut)[][MAX31865_LUTCOL_NUMOF]; /**< Lookup table */
|
|
const int lut_numlines; /**< Number of lines in the lookup table */
|
|
} max31865_params_t;
|
|
|
|
/**
|
|
* @brief Device descriptor for the driver
|
|
*/
|
|
typedef struct {
|
|
const max31865_params_t *params; /**< device configuration */
|
|
} max31865_t;
|
|
|
|
/**
|
|
* @brief Fault status of the MAX31865
|
|
*/
|
|
typedef enum {
|
|
MAX31865_FAULT_NO_FAULT = 0, /**< No fault */
|
|
MAX31865_FAULT_RTD_HIGH = 1, /**< The RTD value is too high */
|
|
MAX31865_FAULT_RTD_LOW = 2, /**< The RTD value is too small */
|
|
MAX31865_FAULT_CIRCUIT = 3, /**< Open or shorted circuit */
|
|
MAX31865_FAULT_VOLTAGE = 4 /**< Overvoltage or undervoltage on the FORCE or RTD pin */
|
|
} max31865_fault_t;
|
|
|
|
/**
|
|
* @brief Initialize the given device
|
|
*
|
|
* @param[in,out] dev Device descriptor of the driver
|
|
* @param[in] params Initialization parameters
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -ENXIO invalid SPI device
|
|
* @retval -EINVAL invalid SPI CS pin/line
|
|
*/
|
|
int max31865_init(max31865_t *dev, const max31865_params_t *params);
|
|
|
|
/**
|
|
* @brief Clear the fault flag
|
|
*
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[out] config If not NULL, set to the value of the config register
|
|
*
|
|
* Call this function if after #max31865_read() or #max31865_detect_fault() if
|
|
* either of them reports a fault.
|
|
*/
|
|
void max31865_clear_fault(const max31865_t *dev, uint8_t *config);
|
|
|
|
/**
|
|
* @brief Read data from the MAX31865. This is a shortcut to read raw data
|
|
* and parse it to the data structure.
|
|
*
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[out] rtd_temperature_cdegc Temperature in centi-degrees Celsius (0.01°C)
|
|
*
|
|
* @pre \a dev and \a data must not be NULL
|
|
*
|
|
* This function does a minimal error check.
|
|
* To get more details on the fault, call
|
|
* #max31865_detect_fault().
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -EIO if an error was detected by the MAX31865
|
|
*/
|
|
int max31865_read(const max31865_t *dev, int32_t *rtd_temperature_cdegc);
|
|
|
|
/**
|
|
* @brief Read raw data from the MAX31865
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[out] raw_data Value of the RTD registers
|
|
*
|
|
* \a raw_data is a left-justified 15-bit word, representing the ratio
|
|
* of the RTD resistance to the reference resistance.
|
|
* Bit 0 is a status bit.
|
|
*
|
|
* @retval 0 on success.
|
|
* @retval -EIO if an error was detected by the MAX31865.
|
|
* In this case, the temperature is not valid.
|
|
* Call #max31865_detect_fault() for more details.
|
|
*/
|
|
int max31865_read_raw(const max31865_t *dev, uint16_t *raw_data);
|
|
|
|
/**
|
|
* @brief Convert the raw data from the MAX31865 temperature
|
|
*
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[in] raw_data Raw data from the MAX31865
|
|
* @param[out] rtd_temperature_cdegc Temperature in centi-degrees Celsius (0.01°C)
|
|
*
|
|
* @pre @p data must not be NULL
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -EINVAL on error
|
|
*/
|
|
int max31865_raw_to_data(const max31865_t *dev, uint16_t raw_data, int32_t *rtd_temperature_cdegc);
|
|
|
|
/**
|
|
* @brief Run an automatic fault-detection cycle
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[out] flt_code Fault code
|
|
*
|
|
* Run a full fault-detection cycle, in automatic mode.
|
|
* The automatic mode implies that the input filter of the ADC has
|
|
* a time constant smaller than 100µs.
|
|
* This is the case if the capacitor across the RTD has the
|
|
* value which is recommended in the datasheet.
|
|
*
|
|
* The execution time of this function is at least 100µs, until the
|
|
* fault-detection cycle completes.
|
|
* It polls the configuration register to check the completion of the cycle.
|
|
*
|
|
* @pre V<sub>BIAS</sub> must be on for at least 5 time constants.
|
|
*
|
|
* @retval 0 on success.
|
|
* @retval -EIO on error.
|
|
*/
|
|
int max31865_detect_fault(const max31865_t *dev, max31865_fault_t *flt_code);
|
|
|
|
/**
|
|
* @brief Switch V<sub>BIAS</sub> on or off
|
|
* @param[in] dev Device descriptor of the driver
|
|
* @param[in] enable Set to \c true to switch on, or to \c false to switch off V<sub>BIAS</sub>.
|
|
*
|
|
* The bias current of the RTD can be switched off to save power.
|
|
* After switching it on, wait for at least 10 time constants -- 10 × 100µs,
|
|
* if the capacitance across the RTD is as recommended in the datasheet --
|
|
* before measuring a valid temperature.
|
|
*/
|
|
void max31865_switch_vbias(const max31865_t *dev, bool enable);
|
|
|
|
/**
|
|
* @brief Start a one-shot conversion
|
|
* @param[in] dev Device descriptor of the driver
|
|
*
|
|
* The user must wait at least 52ms in 60Hz or 62.5ms in 50Hz filter mode
|
|
* for the conversion to complete, before reading the conversion result.
|
|
*/
|
|
void max31865_oneshot(const max31865_t *dev);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/** @} */
|