Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
app/ad4696_data_capture.c
- Committer:
- pmallick
- Date:
- 2021-09-30
- Revision:
- 1:8792acb5a039
File content as of revision 1:8792acb5a039:
/***************************************************************************//** * @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; }