-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10983 from skullbox305/driver_ph_oem
drivers/ph_oem: support for Atlas Scientific pH OEM sensor
- Loading branch information
Showing
17 changed files
with
1,499 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,362 @@ | ||
/* | ||
* Copyright (C) 2019 University of Applied Sciences Emden / Leer | ||
* | ||
* 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_ph_oem pH OEM sensor device driver | ||
* @ingroup drivers_sensors | ||
* @ingroup drivers_saul | ||
* @brief Device driver for Atlas Scientific pH OEM sensor with SMBus/I2C interface | ||
* | ||
* The Atlas Scientific pH OEM sensor can be used with or without the interrupt | ||
* pin. Per default this pin is mapped to @ref GPIO_UNDEF if not otherwise defined | ||
* in your makefile. | ||
* | ||
* If you use an electrical isolation for most accurate readings | ||
* e.g. with the ADM3260, keep in mind that its not recommended to use the | ||
* interrupt pin without also isolating it somehow. The preferred method, | ||
* if not using an isolation on the interrupt line, would be polling. In this case | ||
* leave the interrupt pin undefined. | ||
* | ||
* The Sensor has no integrated temperature sensor and for the highest possible | ||
* precision it requires another device to provide the temperature for error | ||
* compensation. | ||
* | ||
* Once the pH OEM is powered on it will be ready to receive commands and take | ||
* readings after 1ms. | ||
* | ||
* @note This driver provides @ref drivers_saul capabilities. | ||
* Reading (@ref saul_driver_t.read) from the device returns the current pH value. | ||
* Writing (@ref saul_driver_t.write) a temperature value in celsius to the | ||
* device sets the temperature compensation. A valid temperature range is | ||
* 1 - 20000 (0.01 °C to 200.0 °C) | ||
* | ||
* @note Communication is done using SMBus/I2C protocol at speeds | ||
* of 10-100 kHz. Set your board I2C speed to @ref I2C_SPEED_LOW or | ||
* @ref I2C_SPEED_NORMAL | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* @brief Device driver for Atlas Scientific pH OEM Sensor with SMBus/I2C interface | ||
* @author Igor Knippenberg <igor.knippenberg@gmail.com> | ||
*/ | ||
|
||
#ifndef PH_OEM_H | ||
#define PH_OEM_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" | ||
{ | ||
#endif | ||
|
||
#include "periph/i2c.h" | ||
#include "periph/gpio.h" | ||
|
||
/** | ||
* @brief Named return values | ||
*/ | ||
typedef enum { | ||
PH_OEM_OK = 0, /**< Everything was fine */ | ||
PH_OEM_NODEV = -1, /**< No device found on the bus */ | ||
PH_OEM_READ_ERR = -2, /**< Reading to device failed*/ | ||
PH_OEM_WRITE_ERR = -3, /**< Writing to device failed */ | ||
PH_OEM_NOT_PH = -4, /**< Not an Atlas Scientific pH OEM device */ | ||
PH_OEM_INTERRUPT_GPIO_UNDEF = -5, /**< Interrupt pin is @ref GPIO_UNDEF */ | ||
PH_OEM_GPIO_INIT_ERR = -6, /**< Error while initializing GPIO PIN */ | ||
PH_OEM_TEMP_OUT_OF_RANGE = -7 /**< Temperature is out of range */ | ||
} ph_oem_named_returns_t; | ||
|
||
/** | ||
* @brief LED state values | ||
*/ | ||
typedef enum { | ||
PH_OEM_LED_ON = 0x01, /**< LED on state */ | ||
PH_OEM_LED_OFF = 0x00, /**< LED off state */ | ||
} ph_oem_led_state_t; | ||
|
||
/** | ||
* @brief Device state values | ||
*/ | ||
typedef enum { | ||
PH_OEM_TAKE_READINGS = 0x01, /**< Device active state */ | ||
PH_OEM_STOP_READINGS = 0x00, /**< Device hibernate state */ | ||
} ph_oem_device_state_t; | ||
/** | ||
* @brief Interrupt pin option values | ||
*/ | ||
typedef enum { | ||
PH_OEM_IRQ_RISING = 0x02, /**< Pin high on new reading (manually reset) */ | ||
PH_OEM_IRQ_FALLING = 0x04, /**< Pin low on new reading (manually reset) */ | ||
PH_OEM_IRQ_BOTH = 0x08, /**< Invert state on new reading (automatically reset) */ | ||
} ph_oem_irq_option_t; | ||
|
||
/** | ||
* @brief Calibration option values | ||
*/ | ||
typedef enum { | ||
PH_OEM_CALIBRATE_LOW_POINT = 0x02, /**< Low point calibration option */ | ||
PH_OEM_CALIBRATE_MID_POINT = 0x03, /**< Mid point calibration option */ | ||
PH_OEM_CALIBRATE_HIGH_POINT = 0x04, /**< High point calibration option */ | ||
} ph_oem_calibration_option_t; | ||
|
||
/** | ||
* @brief pH OEM sensor params | ||
*/ | ||
typedef struct ph_oem_params { | ||
i2c_t i2c; /**< I2C device the sensor is connected to */ | ||
uint8_t addr; /**< the slave address of the sensor on the I2C bus */ | ||
gpio_t interrupt_pin; /**< interrupt pin (@ref GPIO_UNDEF if not defined) */ | ||
gpio_mode_t gpio_mode; /**< gpio mode of the interrupt pin */ | ||
ph_oem_irq_option_t irq_option; /**< behavior of the interrupt pin, disabled by default */ | ||
} ph_oem_params_t; | ||
|
||
/** | ||
* @brief pH OEM interrupt pin callback | ||
*/ | ||
typedef void (*ph_oem_interrupt_pin_cb_t)(void *); | ||
|
||
/** | ||
* @brief pH OEM device descriptor | ||
*/ | ||
typedef struct ph_oem { | ||
ph_oem_params_t params; /**< device driver configuration */ | ||
ph_oem_interrupt_pin_cb_t cb; /**< interrupt pin callback */ | ||
void *arg; /**< interrupt pin callback param */ | ||
} ph_oem_t; | ||
|
||
/** | ||
* @brief Initialize a pH OEM sensor | ||
* | ||
* @param[in,out] dev device descriptor | ||
* @param[in] params device configuration | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_NODEV if no device is found on the bus | ||
* @return @ref PH_OEM_NOT_PH if the device found at the address is not a pH OEM device | ||
* @return | ||
*/ | ||
int ph_oem_init(ph_oem_t *dev, const ph_oem_params_t *params); | ||
|
||
/** | ||
* @brief Sets a new address to the pH OEM device by unlocking the | ||
* @ref PH_OEM_REG_UNLOCK register and writing a new address to | ||
* the @ref PH_OEM_REG_ADDRESS register. | ||
* The device address will also be updated in the device descriptor so | ||
* it is still usable. | ||
* | ||
* Settings are retained in the sensor if the power is cut. | ||
* | ||
* The address in the device descriptor will reverse to the default | ||
* address you provided through PH_OEM_PARAM_ADDR after the | ||
* microcontroller restarts | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] addr new address for the device. Range: 0x01 - 0x7f | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
*/ | ||
int ph_oem_set_i2c_address(ph_oem_t *dev, uint8_t addr); | ||
|
||
/** | ||
* @brief Enable the pH OEM interrupt pin if @ref ph_oem_params_t.interrupt_pin | ||
* is defined. | ||
* @note @ref ph_oem_reset_interrupt_pin needs to be called in the | ||
* callback if you use @ref PH_OEM_IRQ_FALLING or @ref PH_OEM_IRQ_RISING | ||
* | ||
* @note Provide the PH_OEM_PARAM_INTERRUPT_OPTION flag in your | ||
* makefile. Valid options see: @ref ph_oem_irq_option_t. | ||
* The default is @ref PH_OEM_IRQ_BOTH. | ||
* | ||
* @note Also provide the @ref gpio_mode_t as a CFLAG in your makefile. | ||
* Most likely @ref GPIO_IN. If the pin is to sensitive use | ||
* @ref GPIO_IN_PU for @ref PH_OEM_IRQ_FALLING or | ||
* @ref GPIO_IN_PD for @ref PH_OEM_IRQ_RISING and | ||
* @ref PH_OEM_IRQ_BOTH. The default is @ref GPIO_IN_PD | ||
* | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] cb callback called when the pH OEM interrupt pin fires | ||
* @param[in] arg callback argument | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
* @return @ref PH_OEM_INTERRUPT_GPIO_UNDEF if the interrupt pin is undefined | ||
* @return @ref PH_OEM_GPIO_INIT_ERR if initializing the interrupt gpio pin failed | ||
*/ | ||
int ph_oem_enable_interrupt(ph_oem_t *dev, ph_oem_interrupt_pin_cb_t cb, | ||
void *arg); | ||
|
||
/** | ||
* @brief The interrupt pin will not auto reset on option @ref PH_OEM_IRQ_RISING | ||
* and @ref PH_OEM_IRQ_FALLING after interrupt fires, | ||
* so call this function again to reset the pin state. | ||
* | ||
* @note The interrupt settings are not retained if the power is cut, | ||
* so you have to call this function again after powering on the device. | ||
* | ||
* @param[in] dev device descriptor | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
*/ | ||
int ph_oem_reset_interrupt_pin(const ph_oem_t *dev); | ||
|
||
/** | ||
* @brief Set the LED state of the pH OEM sensor by writing to the | ||
* @ref PH_OEM_REG_LED register | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] state @ref ph_oem_led_state_t | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
*/ | ||
int ph_oem_set_led_state(const ph_oem_t *dev, ph_oem_led_state_t state); | ||
|
||
/** | ||
* @brief Sets the device state (active/hibernate) of the pH OEM sensor by | ||
* writing to the @ref PH_OEM_REG_HIBERNATE register. | ||
* | ||
* @note Once the device has been woken up it will continuously take | ||
* readings every 420ms. Waking the device is the only way to take a | ||
* reading. Hibernating the device is the only way to stop taking readings. | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] state @ref ph_oem_device_state_t | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
*/ | ||
int ph_oem_set_device_state(const ph_oem_t *dev, ph_oem_device_state_t state); | ||
|
||
/** | ||
* @brief Starts a new reading by setting the device state to | ||
* @ref PH_OEM_TAKE_READINGS. | ||
* | ||
* @note If the @ref ph_oem_params_t.interrupt_pin is @ref GPIO_UNDEF | ||
* this function will poll every 20ms till a reading is done (~420ms) | ||
* and stop the device from taking further readings | ||
* | ||
* @param[in] dev device descriptor | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_start_new_reading(const ph_oem_t *dev); | ||
|
||
/** | ||
* @brief Clears all calibrations previously done | ||
* | ||
* @param[in] dev device descriptor | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_clear_calibration(const ph_oem_t *dev); | ||
|
||
/** | ||
* @brief Sets the @ref PH_OEM_REG_CALIBRATION_BASE register to the | ||
* calibration_value which the pH OEM sensor will be | ||
* calibrated to. Multiply the floating point calibration value of your | ||
* solution by 1000 e.g. pH calibration solution => 7.002 * 1000 = 7002 = 0x00001B5A | ||
* | ||
* The calibration value will be saved based on the given | ||
* @ref ph_oem_calibration_option_t and retained after the power is cut. | ||
* | ||
* @note Calibrating with @ref PH_OEM_CALIBRATE_MID_POINT will reset the | ||
* previous calibrations. | ||
* Always start with @ref PH_OEM_CALIBRATE_MID_POINT if you doing | ||
* 2 or 3 point calibration | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] calibration_value pH value multiplied by 1000 e.g 7,002 * 1000 = 7002 | ||
* @param[in] option @ref ph_oem_calibration_option_t | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_set_calibration(const ph_oem_t *dev, uint16_t calibration_value, | ||
ph_oem_calibration_option_t option); | ||
|
||
/** | ||
* @brief Read the @ref PH_OEM_REG_CALIBRATION_CONFIRM register. | ||
* After a calibration event has been successfully carried out, the | ||
* calibration confirmation register will reflect what calibration has | ||
* been done, by setting bits 0 - 2. | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[out] calibration_state calibration state reflected by bits 0 - 2 <br> | ||
* (0 = low, 1 = mid, 2 = high) | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_read_calibration_state(const ph_oem_t *dev, uint16_t *calibration_state); | ||
|
||
/** | ||
* @brief Sets the @ref PH_OEM_REG_TEMP_COMPENSATION_BASE register to the | ||
* temperature_compensation value which the pH OEM sensor will use | ||
* to compensate the reading error. | ||
* Multiply the floating point temperature value by 100 | ||
* e.g. temperature in degree Celsius = 34.26 * 100 = 3426 | ||
* | ||
* @note The temperature compensation will not be retained if the power is cut. | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[in] temperature_compensation valid temperature range is | ||
* 1 - 20000 (0.01 °C to 200.0 °C) | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_WRITE_ERR if writing to the device failed | ||
* @return @ref PH_OEM_TEMP_OUT_OF_RANGE if the temperature_compensation is not in | ||
* the valid range | ||
*/ | ||
int ph_oem_set_compensation(const ph_oem_t *dev, | ||
uint16_t temperature_compensation); | ||
|
||
/** | ||
* @brief Reads the @ref PH_OEM_REG_TEMP_CONFIRMATION_BASE register to verify | ||
* the temperature compensation value that was used to take the pH | ||
* reading is set to the correct temperature. | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[out] temperature_compensation raw temperature compensation value. <br> | ||
* Divide by 100 for floating point <br> | ||
* e.g 3426 / 100 = 34.26 | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_read_compensation(const ph_oem_t *dev, | ||
uint16_t *temperature_compensation); | ||
|
||
/** | ||
* @brief Reads the @ref PH_OEM_REG_PH_READING_BASE register to get the current | ||
* pH reading. | ||
* | ||
* @param[in] dev device descriptor | ||
* @param[out] ph_value raw pH value <br> | ||
* divide by 1000 for floating point <br> | ||
* e.g 8347 / 1000 = 8.347 | ||
* | ||
* @return @ref PH_OEM_OK on success | ||
* @return @ref PH_OEM_READ_ERR if reading from the device failed | ||
*/ | ||
int ph_oem_read_ph(const ph_oem_t *dev, uint16_t *ph_value); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* PH_OEM_H */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
Oops, something went wrong.