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;
}