Forked repository for pushing changes to EVAL-AD4696

Dependencies:   platform_drivers

Revision:
1:8792acb5a039
--- /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