Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
Diff: app/ad4696_data_capture.c
- Revision:
- 1:8792acb5a039
diff -r 721af8bb4b69 -r 8792acb5a039 app/ad4696_data_capture.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/ad4696_data_capture.c Thu Sep 30 11:01:05 2021 +0530 @@ -0,0 +1,428 @@ +/***************************************************************************//** + * @file ad4696_data_capture.c + * @brief Data capture interface for AD4696 IIO application + * @details This module handles the AD4696 data capturing for IIO client +******************************************************************************** + * Copyright (c) 2021 Analog Devices, Inc. + * All rights reserved. + * + * This software is proprietary to Analog Devices, Inc. and its licensors. + * By using this software you agree to the terms of the associated + * Analog Devices Software License Agreement. +*******************************************************************************/ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ + +#include <string.h> +#include <stdlib.h> + +#include "app_config.h" +#include "iio_ad4696.h" +#include "ad4696_data_capture.h" +#include "adc_data_capture.h" +#include "error.h" +#include "gpio.h" +#include "util.h" +#include "pwm.h" +#include "ad4696_support.h" + +/******************************************************************************/ +/********************** Macros and Constants Definition ***********************/ +/******************************************************************************/ +/* Note: Timeout is dependent upon MCU clock frequency and tested for SDP-K1 + * Mbed platform + * */ +#define BSY_CHECK_TIMEOUT 1000 + +/******************************************************************************/ +/********************** Variables and User Defined Data Types *****************/ +/******************************************************************************/ +/* Flag to mark the start of continuous read event */ +static volatile bool continuous_data_read = false; +/* Previously active channels */ +static uint32_t ad4696_prev_active_chns = 0; + +/******************************************************************************/ +/************************ Functions Declarations ******************************/ +/******************************************************************************/ + +/* Save the previous active channels value */ +static int32_t ad4696_save_prev_active_chns(void); +/* Restore (enable) the previous active channels */ +static int32_t ad4696_restore_prev_active_chns(void); +/* Enable ADC current (user input) channel */ +static int32_t ad4696_enable_curr_chn(uint8_t chn); +/* Enable ADC channels according to channel mask*/ +static int32_t ad4696_enable_channel_mask(uint32_t chn_msk); +/* Disable ADC current (user input) channel */ +static int32_t ad4696_disable_curr_chn(uint8_t chn); +/* Disable all ADC channels */ +static int32_t ad4696_disable_all_chns(void); +/* Enable conversion for single sample read */ +static int32_t ad4696_single_sample_read_start_ops(uint8_t input_chn); +/* Enable conversion for continuous sample read */ +static int32_t ad4696_enable_continuous_read_conversion(uint32_t ch_mask); +/* Disable conversion */ +static int32_t ad4696_continuous_sample_read_stop_ops(void); +/* Wait for conversion to finish on enabled channels and read conversion data */ +static int32_t ad4696_perform_conv_and_read_sample(uint32_t *adc_data); +/* Read ADC raw sample/data */ +static int32_t ad4696_read_converted_sample(uint32_t *adc_data); +/* Monitor end of conversion event */ +static int32_t ad4696_end_of_conversion_check(void); + +/* Define the variable for data_capture_ops structure */ +struct data_capture_ops data_capture_ops = { + /* Point ad7134 data capture functions to generic ADC data capture functions */ + .single_sample_read_start_ops = ad4696_single_sample_read_start_ops, + .perform_conv_and_read_sample = ad4696_perform_conv_and_read_sample, + .single_sample_read_stop_ops = ad4696_continuous_sample_read_stop_ops, + .continuous_sample_read_start_ops = ad4696_enable_continuous_read_conversion, + .read_converted_sample = ad4696_read_converted_sample, + .continuous_sample_read_stop_ops = ad4696_continuous_sample_read_stop_ops, + .trigger_next_conversion = NULL +}; + +/******************************************************************************/ +/************************ Functions Definitions *******************************/ +/******************************************************************************/ + +/*! + * @brief Save the previous active channels + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_save_prev_active_chns(void) +{ + uint8_t data; + /* Read the upper byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_read(p_ad4696_dev, AD469x_REG_SEQ_UB, &data) != SUCCESS) { + return FAILURE; + } + + /* The upper byte channel configuration is saved to the variable and is + * shifted by 8 bits to save the lower byte register configuration */ + ad4696_prev_active_chns = data; + ad4696_prev_active_chns <<= 8; + + /* Reads the lower byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_read(p_ad4696_dev, AD469x_REG_SEQ_LB, &data) != SUCCESS) { + return FAILURE; + } + ad4696_prev_active_chns |= data; + + return SUCCESS; +} + +/*! + * @brief Restore (re-enable) the previous active channels + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_restore_prev_active_chns(void) +{ + if (ad469x_exit_conversion_mode(p_ad4696_dev) != SUCCESS) + return FAILURE; + + /* Configure the lower byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_LB, + AD469x_SEQ_LB_CONFIG(ad4696_prev_active_chns)) != SUCCESS) { + return FAILURE; + } + + /* Configure the upper byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_UB, + AD469x_SEQ_UB_CONFIG(ad4696_prev_active_chns)) != SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +/*! + * @brief Disable all active channels + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_disable_all_chns(void) +{ + /* Reset the lower byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_LB, + AD469x_SEQ_CHANNELS_RESET) != SUCCESS) { + return FAILURE; + } + + /* Reset the upper byte of the standard sequencer configuration register*/ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_UB, + AD469x_SEQ_CHANNELS_RESET) != SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +/*! + * @brief Enable input channel + * @param chn[in] - Channel to enable + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_enable_curr_chn(uint8_t chn) +{ + /* If channel number is less than 8, then write to + * lower byte configuration register or else write + * to upper byte configuration register + * */ + if (chn < (NO_OF_CHANNELS / 2)) { + if (ad469x_spi_write_mask(p_ad4696_dev, + AD469x_REG_SEQ_LB, + AD469x_SEQ_CHANNELS_RESET, + AD469x_SINGLE_CHANNEL_EN(chn)) != SUCCESS) { + return FAILURE; + } + } + else { + if (ad469x_spi_write_mask(p_ad4696_dev, + AD469x_REG_SEQ_UB, + AD469x_SEQ_CHANNELS_RESET, + AD469x_SINGLE_CHANNEL_EN(chn - 8)) != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; +} + +/*! + * @brief Enable input channels according to the mask + * @param chn_msk[in] - Mask containing channels to be enabled + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_enable_channel_mask(uint32_t chn_msk) +{ + /* Write the lower byte of the channel mask to the lower byte + * of the standard sequencer configuration register + * */ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_LB, + AD469x_SEQ_LB_CONFIG(chn_msk)) != SUCCESS) { + return FAILURE; + } + + /* Write the upper byte of the channel mask to the upper byte + * of the standard sequencer configuration register + * */ + if (ad469x_spi_reg_write(p_ad4696_dev, + AD469x_REG_SEQ_UB, + AD469x_SEQ_UB_CONFIG(chn_msk)) != SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +/*! + * @brief Disable input channel + * @param chn[in] - Channel to disable + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_disable_curr_chn(uint8_t chn) +{ + /* If channel number is less than 8, then write + * to lower byte configuration register or else + * write to upper byte configuration register + * */ + if (chn < (NO_OF_CHANNELS/2)) { + if (ad469x_spi_write_mask(p_ad4696_dev, + AD469x_REG_SEQ_LB, + AD469x_SINGLE_CHANNEL_EN(chn), + AD469x_SEQ_CHANNEL_DI) != SUCCESS) { + return FAILURE; + } + } + else { + if (ad469x_spi_write_mask(p_ad4696_dev, + AD469x_REG_SEQ_UB, + AD469x_SINGLE_CHANNEL_EN(chn - 8), + AD469x_SEQ_CHANNEL_DI) != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; +} + +/*! + * @brief Enable conversion for single data read + * @param input_chn[in] - Channel to be enabled + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_single_sample_read_start_ops(uint8_t input_chn) +{ + do { + /* Save previously active channels */ + if (ad4696_save_prev_active_chns() != SUCCESS) { + break; + } + + /* Disable all channels */ + if (ad4696_disable_all_chns() != SUCCESS) { + break; + } + + /* Enable user input channel */ + if (ad4696_enable_curr_chn(input_chn) != SUCCESS) { + break; + } + + /* Enter into conversion mode */ + if (ad469x_enter_conversion_mode(p_ad4696_dev) != SUCCESS) { + break; + } + + return SUCCESS; + } while (0); + + return FAILURE; +} + +/*! + * @brief Enable conversion for continuous (sequencing) data read + * @param ch_mask[in] - Mask containing channels to be enabled + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_enable_continuous_read_conversion(uint32_t ch_mask) +{ + do { + /* Save previously active channels */ + if (ad4696_save_prev_active_chns() != SUCCESS) { + break; + } + + /* Disable all channels */ + if (ad4696_disable_all_chns() != SUCCESS) { + break; + } + + /* Enable user input channels */ + if (ad4696_enable_channel_mask(ch_mask) != SUCCESS) { + break; + } + + /* Start Generating PWM signal */ + if (pwm_enable(pwm_desc) != SUCCESS) { + break; + } + + continuous_data_read = true; + /* Enter into conversion mode */ + if (ad469x_enter_conversion_mode(p_ad4696_dev) != SUCCESS) { + break; + } + + return SUCCESS; + } while (0); + + return FAILURE; +} + +/*! + * @brief Disable ADC conversion + * @return SUCCESS in case of success, FAILURE otherwise + */ +static int32_t ad4696_continuous_sample_read_stop_ops(void) +{ + if (continuous_data_read) { + /* Stop Generating PWM signal */ + if (pwm_disable(pwm_desc) != SUCCESS) { + return FAILURE; + } + } + + /* Enter into register mode or exit from conversion mode */ + if (ad469x_exit_conversion_mode(p_ad4696_dev) != SUCCESS) { + return FAILURE; + } + + /* Enable back channels which were disabled prior to conversion start*/ + if (ad4696_restore_prev_active_chns() != SUCCESS) { + return FAILURE; + } + + continuous_data_read = false; + return SUCCESS; +} + +/*! + * @brief Read ADC raw data for recently sampled channel + * @param adc_raw[out] - Pointer to adc data read variable + * @return SUCCESS in case of success, FAILURE otherwise + * @note This function is intended to call from the conversion end trigger + * event. Therefore, this function should just read raw ADC data + * without further monitoring conversion end event + */ +static int32_t ad4696_read_converted_sample(uint32_t *adc_raw) +{ + /* Null Check */ + if (!adc_raw) { + return FAILURE; + } + + /* Read the converted ADC raw data and return the transaction result*/ + return ad469x_read_data(p_ad4696_dev, 0, adc_raw, 1); +} + +/*! + * @brief Read ADC single sample data + * @param read_adc_data[out] - Pointer to adc data read variable + * @return SUCCESS in case of success, FAILURE otherwise + * @details This function performs the sampling on previously active channels + * and then reads conversion result + */ +static int32_t ad4696_perform_conv_and_read_sample(uint32_t *read_adc_data) +{ + uint32_t adc_raw = 0; + + /* Read the converted ADC raw data */ + if (ad469x_read_data(p_ad4696_dev, 1, &adc_raw, 1) != SUCCESS) { + return FAILURE; + } + + *read_adc_data = adc_raw; + return SUCCESS; +} + +/*! + * @brief Check for the end of conversion event + * @return SUCCESS in case of success, FAILURE otherwise + * @details This function monitors the state line for BSY pin + * until timeout is reached + */ +static int32_t ad4696_end_of_conversion_check(void) +{ + uint16_t timeout = (uint16_t)BSY_CHECK_TIMEOUT; /* time out counter */ + uint8_t busy = GPIO_HIGH; /* GPIO initial state */ + + /* Check for BSY to go low */ + while (busy == GPIO_HIGH) { + gpio_get_value(((struct ad469x_dev *)p_ad4696_dev)->gpio_busy, &busy); + timeout--; + if (!timeout) { + return FAILURE; + } + } + + timeout = (uint16_t)BSY_CHECK_TIMEOUT; + /* Check for BSY pin to go high */ + while (busy == GPIO_LOW) { + gpio_get_value(((struct ad469x_dev *)p_ad4696_dev)->gpio_busy, &busy); + timeout--; + if (!timeout) { + return FAILURE; + } + } + + return SUCCESS; +} \ No newline at end of file