/** * @file * @brief ADC public API header file. */ /* * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2015 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_H_ #define ZEPHYR_INCLUDE_DRIVERS_ADC_H_ #include #ifdef __cplusplus extern "C" { #endif /** * @brief ADC driver APIs * @defgroup adc_interface ADC driver APIs * @ingroup io_interfaces * @{ */ /** @brief ADC channel gain factors. */ enum adc_gain { ADC_GAIN_1_6, /**< x 1/6. */ ADC_GAIN_1_5, /**< x 1/5. */ ADC_GAIN_1_4, /**< x 1/4. */ ADC_GAIN_1_3, /**< x 1/3. */ ADC_GAIN_1_2, /**< x 1/2. */ ADC_GAIN_2_3, /**< x 2/3. */ ADC_GAIN_1, /**< x 1. */ ADC_GAIN_2, /**< x 2. */ ADC_GAIN_3, /**< x 3. */ ADC_GAIN_4, /**< x 4. */ ADC_GAIN_8, /**< x 8. */ ADC_GAIN_16, /**< x 16. */ ADC_GAIN_32, /**< x 32. */ ADC_GAIN_64, /**< x 64. */ ADC_GAIN_128, /**< x 128. */ }; /** * @brief Invert the application of gain to a measurement value. * * For example, if the gain passed in is ADC_GAIN_1_6 and the * referenced value is 10, the value after the function returns is 60. * * @param gain the gain used to amplify the input signal. * * @param value a pointer to a value that initially has the effect of * the applied gain but has that effect removed when this function * successfully returns. If the gain cannot be reversed the value * remains unchanged. * * @retval 0 if the gain was successfully reversed * @retval -EINVAL if the gain could not be interpreted */ int adc_gain_invert(enum adc_gain gain, int32_t *value); /** @brief ADC references. */ enum adc_reference { ADC_REF_VDD_1, /**< VDD. */ ADC_REF_VDD_1_2, /**< VDD/2. */ ADC_REF_VDD_1_3, /**< VDD/3. */ ADC_REF_VDD_1_4, /**< VDD/4. */ ADC_REF_INTERNAL, /**< Internal. */ ADC_REF_EXTERNAL0, /**< External, input 0. */ ADC_REF_EXTERNAL1, /**< External, input 1. */ }; /** Acquisition time is expressed in microseconds. */ #define ADC_ACQ_TIME_MICROSECONDS (1u) /** Acquisition time is expressed in nanoseconds. */ #define ADC_ACQ_TIME_NANOSECONDS (2u) /** Acquisition time is expressed in ADC ticks. */ #define ADC_ACQ_TIME_TICKS (3u) /** Macro for composing the acquisition time value in given units. */ #define ADC_ACQ_TIME(unit, value) (((unit) << 14) | ((value) & BIT_MASK(14))) /** Value indicating that the default acquisition time should be used. */ #define ADC_ACQ_TIME_DEFAULT 0 #define ADC_ACQ_TIME_UNIT(time) (((time) >> 14) & BIT_MASK(2)) #define ADC_ACQ_TIME_VALUE(time) ((time) & BIT_MASK(14)) /** * @brief Structure for specifying the configuration of an ADC channel. */ struct adc_channel_cfg { /** Gain selection. */ enum adc_gain gain; /** Reference selection. */ enum adc_reference reference; /** * Acquisition time. * Use the ADC_ACQ_TIME macro to compose the value for this field or * pass ADC_ACQ_TIME_DEFAULT to use the default setting for a given * hardware (e.g. when the hardware does not allow to configure the * acquisition time). * Particular drivers do not necessarily support all the possible units. * Value range is 0-16383 for a given unit. */ uint16_t acquisition_time; /** * Channel identifier. * This value primarily identifies the channel within the ADC API - when * a read request is done, the corresponding bit in the "channels" field * of the "adc_sequence" structure must be set to include this channel * in the sampling. * For hardware that does not allow selection of analog inputs for given * channels, but rather have dedicated ones, this value also selects the * physical ADC input to be used in the sampling. Otherwise, when it is * needed to explicitly select an analog input for the channel, or two * inputs when the channel is a differential one, the selection is done * in "input_positive" and "input_negative" fields. * Particular drivers indicate which one of the above two cases they * support by selecting or not a special hidden Kconfig option named * ADC_CONFIGURABLE_INPUTS. If this option is not selected, the macro * CONFIG_ADC_CONFIGURABLE_INPUTS is not defined and consequently the * mentioned two fields are not present in this structure. * While this API allows identifiers from range 0-31, particular drivers * may support only a limited number of channel identifiers (dependent * on the underlying hardware capabilities or configured via a dedicated * Kconfig option). */ uint8_t channel_id : 5; /** Channel type: single-ended or differential. */ uint8_t differential : 1; #ifdef CONFIG_ADC_CONFIGURABLE_INPUTS /** * Positive ADC input. * This is a driver dependent value that identifies an ADC input to be * associated with the channel. */ uint8_t input_positive; /** * Negative ADC input (used only for differential channels). * This is a driver dependent value that identifies an ADC input to be * associated with the channel. */ uint8_t input_negative; #endif /* CONFIG_ADC_CONFIGURABLE_INPUTS */ }; /** * @brief Convert a raw ADC value to millivolts. * * This function performs the necessary conversion to transform a raw * ADC measurement to a voltage in millivolts. * * @param ref_mv the reference voltage used for the measurement, in * millivolts. This may be from adc_ref_internal() or a known * external reference. * * @param gain the ADC gain configuration used to sample the input * * @param resolution the number of bits in the absolute value of the * sample. For differential sampling this may be one less than the * resolution in struct adc_sequence. * * @param valp pointer to the raw measurement value on input, and the * corresponding millivolt value on successful conversion. If * conversion fails the stored value is left unchanged. * * @retval 0 on successful conversion * @retval -EINVAL if the gain is not reversible */ static inline int adc_raw_to_millivolts(int32_t ref_mv, enum adc_gain gain, uint8_t resolution, int32_t *valp) { int32_t adc_mv = *valp * ref_mv; int ret = adc_gain_invert(gain, &adc_mv); if (ret == 0) { *valp = (adc_mv >> resolution); } return ret; } /* Forward declaration of the adc_sequence structure. */ struct adc_sequence; /** * @brief Action to be performed after a sampling is done. */ enum adc_action { /** The sequence should be continued normally. */ ADC_ACTION_CONTINUE = 0, /** * The sampling should be repeated. New samples or sample should be * read from the ADC and written in the same place as the recent ones. */ ADC_ACTION_REPEAT, /** The sequence should be finished immediately. */ ADC_ACTION_FINISH, }; /** * @brief Type definition of the optional callback function to be called after * a requested sampling is done. * * @param dev Pointer to the device structure for the driver * instance. * @param sequence Pointer to the sequence structure that triggered the * sampling. * @param sampling_index Index (0-65535) of the sampling done. * * @returns Action to be performed by the driver. See @ref adc_action. */ typedef enum adc_action (*adc_sequence_callback)( struct device *dev, const struct adc_sequence *sequence, uint16_t sampling_index); /** * @brief Structure defining additional options for an ADC sampling sequence. */ struct adc_sequence_options { /** * Interval between consecutive samplings (in microseconds), 0 means * sample as fast as possible, without involving any timer. * The accuracy of this interval is dependent on the implementation of * a given driver. The default routine that handles the intervals uses * a kernel timer for this purpose, thus, it has the accuracy of the * kernel's system clock. Particular drivers may use some dedicated * hardware timers and achieve a better precision. */ uint32_t interval_us; /** * Callback function to be called after each sampling is done. * Optional - set to NULL if it is not needed. */ adc_sequence_callback callback; /** * Number of extra samplings to perform (the total number of samplings * is 1 + extra_samplings). */ uint16_t extra_samplings; }; /** * @brief Structure defining an ADC sampling sequence. */ struct adc_sequence { /** * Pointer to a structure defining additional options for the sequence. * If NULL, the sequence consists of a single sampling. */ const struct adc_sequence_options *options; /** * Bit-mask indicating the channels to be included in each sampling * of this sequence. * All selected channels must be configured with adc_channel_setup() * before they are used in a sequence. */ uint32_t channels; /** * Pointer to a buffer where the samples are to be written. Samples * from subsequent samplings are written sequentially in the buffer. * The number of samples written for each sampling is determined by * the number of channels selected in the "channels" field. * The buffer must be of an appropriate size, taking into account * the number of selected channels and the ADC resolution used, * as well as the number of samplings contained in the sequence. */ void *buffer; /** * Specifies the actual size of the buffer pointed by the "buffer" * field (in bytes). The driver must ensure that samples are not * written beyond the limit and it must return an error if the buffer * turns out to be not large enough to hold all the requested samples. */ size_t buffer_size; /** * ADC resolution. * For single-ended channels the sample values are from range: * 0 .. 2^resolution - 1, * for differential ones: * - 2^(resolution-1) .. 2^(resolution-1) - 1. */ uint8_t resolution; /** * Oversampling setting. * Each sample is averaged from 2^oversampling conversion results. * This feature may be unsupported by a given ADC hardware, or in * a specific mode (e.g. when sampling multiple channels). */ uint8_t oversampling; /** * Perform calibration before the reading is taken if requested. * * The impact of channel configuration on the calibration * process is specific to the underlying hardware. ADC * implementations that do not support calibration should * ignore this flag. */ bool calibrate; }; /** * @brief Type definition of ADC API function for configuring a channel. * See adc_channel_setup() for argument descriptions. */ typedef int (*adc_api_channel_setup)(struct device *dev, const struct adc_channel_cfg *channel_cfg); /** * @brief Type definition of ADC API function for setting a read request. * See adc_read() for argument descriptions. */ typedef int (*adc_api_read)(struct device *dev, const struct adc_sequence *sequence); #ifdef CONFIG_ADC_ASYNC /** * @brief Type definition of ADC API function for setting an asynchronous * read request. * See adc_read_async() for argument descriptions. */ typedef int (*adc_api_read_async)(struct device *dev, const struct adc_sequence *sequence, struct k_poll_signal *async); #endif /** * @brief ADC driver API * * This is the mandatory API any ADC driver needs to expose. */ __subsystem struct adc_driver_api { adc_api_channel_setup channel_setup; adc_api_read read; #ifdef CONFIG_ADC_ASYNC adc_api_read_async read_async; #endif uint16_t ref_internal; /* mV */ }; /** * @brief Configure an ADC channel. * * It is required to call this function and configure each channel before it is * selected for a read request. * * @param dev Pointer to the device structure for the driver instance. * @param channel_cfg Channel configuration. * * @retval 0 On success. * @retval -EINVAL If a parameter with an invalid value has been provided. */ __syscall int adc_channel_setup(struct device *dev, const struct adc_channel_cfg *channel_cfg); static inline int z_impl_adc_channel_setup(struct device *dev, const struct adc_channel_cfg *channel_cfg) { const struct adc_driver_api *api = (const struct adc_driver_api *)dev->driver_api; return api->channel_setup(dev, channel_cfg); } /** * @brief Set a read request. * * @param dev Pointer to the device structure for the driver instance. * @param sequence Structure specifying requested sequence of samplings. * * If invoked from user mode, any sequence struct options for callback must * be NULL. * * @retval 0 On success. * @retval -EINVAL If a parameter with an invalid value has been provided. * @retval -ENOMEM If the provided buffer is to small to hold the results * of all requested samplings. * @retval -ENOTSUP If the requested mode of operation is not supported. * @retval -EBUSY If another sampling was triggered while the previous one * was still in progress. This may occur only when samplings * are done with intervals, and it indicates that the selected * interval was too small. All requested samples are written * in the buffer, but at least some of them were taken with * an extra delay compared to what was scheduled. */ __syscall int adc_read(struct device *dev, const struct adc_sequence *sequence); static inline int z_impl_adc_read(struct device *dev, const struct adc_sequence *sequence) { const struct adc_driver_api *api = (const struct adc_driver_api *)dev->driver_api; return api->read(dev, sequence); } #ifdef CONFIG_ADC_ASYNC /** * @brief Set an asynchronous read request. * * If invoked from user mode, any sequence struct options for callback must * be NULL. * * @param dev Pointer to the device structure for the driver instance. * @param sequence Structure specifying requested sequence of samplings. * @param async Pointer to a valid and ready to be signaled struct * k_poll_signal. (Note: if NULL this function will not notify * the end of the transaction, and whether it went successfully * or not). * * @returns 0 on success, negative error code otherwise. * */ __syscall int adc_read_async(struct device *dev, const struct adc_sequence *sequence, struct k_poll_signal *async); static inline int z_impl_adc_read_async(struct device *dev, const struct adc_sequence *sequence, struct k_poll_signal *async) { const struct adc_driver_api *api = (const struct adc_driver_api *)dev->driver_api; return api->read_async(dev, sequence, async); } #endif /* CONFIG_ADC_ASYNC */ /** * @brief Get the internal reference voltage. * * Returns the voltage corresponding to @ref ADC_REF_INTERNAL, * measured in millivolts. * * @return a positive value is the reference voltage value. Returns * zero if reference voltage information is not available. */ static inline uint16_t adc_ref_internal(struct device *dev) { const struct adc_driver_api *api = (const struct adc_driver_api *)dev->driver_api; return api->ref_internal; } /** * @} */ #ifdef __cplusplus } #endif #include #endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_H_ */