Example program for EVAL-AD4696.

Dependencies:   platform_drivers

Revision:
1:edd760d6380f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/iio_ad4696.c	Thu Sep 30 11:58:20 2021 +0100
@@ -0,0 +1,633 @@
+/***************************************************************************//**
+ *   @file    iio_ad4696.c
+ *   @brief   Implementation of AD4696 IIO application interfaces
+ *   @details This module acts as an interface for AD4696 IIO application
+********************************************************************************
+ * Copyright (c) 2021 Analog Devices, Inc.
+ *
+ * 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 <inttypes.h>
+#include <string.h>
+#include <math.h>
+
+#include "app_config.h"
+#include "tinyiiod.h"
+#include "iio_ad4696.h"
+#include "adc_data_capture.h"
+#include "ad4696_support.h"
+#include "ad4696_user_config.h"
+#include "error.h"
+
+/******************************************************************************/
+/************************ Macros/Constants ************************************/
+/******************************************************************************/
+
+/* ADC Raw to Voltage conversion default scale factor for IIO client */
+#if defined(PSEUDO_BIPOLAR_MODE)
+/* Device supports pseudo-bipolar mode only with INX- = Vref / 2 */
+#define DEFAULT_SCALE		(((DEFAULT_VREF  / 2) / ADC_MAX_COUNT_BIPOLAR) * 1000)
+#else
+#define DEFAULT_SCALE		((DEFAULT_VREF / ADC_MAX_COUNT_UNIPOLAR) * 1000)
+#endif
+
+/* Bytes per sample. This count should divide the total 256 bytes into 'n' equivalent
+ * ADC samples as IIO library requests only 256bytes of data at a time in a given
+ * data read query.
+ * For 1 to 8-bit ADC, bytes per sample = 1 (2^0)
+ * For 9 to 16-bit ADC, bytes per sample = 2 (2^1)
+ * For 17 to 32-bit ADC, bytes per sample = 4 (2^2)
+ **/
+#define	BYTES_PER_SAMPLE	sizeof(uint16_t)	// For ADC resolution of 16-bits
+
+/* Number of data storage bits (needed for IIO client to plot ADC data) */
+#define CHN_STORAGE_BITS	(BYTES_PER_SAMPLE * 8)
+
+/* Private IDs for IIO attributes */
+#define	IIO_RAW_ATTR_ID			0
+#define	IIO_SCALE_ATTR_ID		1
+#define	IIO_OFFSET_ATTR_ID		2
+
+/******************************************************************************/
+/*************************** Types Declarations *******************************/
+/******************************************************************************/
+
+/* Pointer to the struct representing the AD4696 IIO device */
+struct ad469x_dev *p_ad4696_dev = NULL;
+
+/* IIO interface descriptor */
+static struct iio_desc *p_ad4696_iio_desc;
+
+/* Device name */
+static const char dev_name [] = ACTIVE_DEVICE_NAME;
+
+/* Scale value per channel */
+static float attr_scale_val[NO_OF_CHANNELS] = {
+	DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
+	DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
+	DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
+	DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE
+};
+
+/* Flag to trigger new data capture */
+static bool adc_data_capture_started = false;
+
+/******************************************************************************/
+/************************ Functions Definitions *******************************/
+/******************************************************************************/
+
+/*!
+ * @brief	Getter/Setter for the raw, offset and scale attribute value
+ * @param	device- pointer to IIO device structure
+ * @param	buf- pointer to buffer holding attribute value
+ * @param	len- length of buffer string data
+ * @param	channel- pointer to IIO channel structure
+ * @param	id- Attribute ID
+ * @return	Number of characters read/written
+ */
+static ssize_t get_adc_raw(void *device,
+					char *buf,
+					size_t len,
+					const struct iio_ch_info *channel,
+					intptr_t id)
+{
+	static uint32_t adc_data_raw = 0;
+	int32_t offset = 0;
+
+	switch (id) {
+	case IIO_RAW_ATTR_ID:
+		/* Capture the raw adc data */
+		if (read_single_sample((uint32_t)channel->ch_num, &adc_data_raw) != FAILURE) {
+			return (ssize_t) sprintf(buf, "%d", adc_data_raw);
+		}
+		break;
+		
+	case IIO_SCALE_ATTR_ID:
+		return (ssize_t) sprintf(buf, "%f", attr_scale_val[channel->ch_num]);
+		break;
+		
+	case IIO_OFFSET_ATTR_ID:
+#if defined(PSEUDO_BIPOLAR_MODE)
+		if (adc_data_raw >= ADC_MAX_COUNT_BIPOLAR) {
+			offset = -ADC_MAX_COUNT_UNIPOLAR ;
+		}
+		else {
+			offset = 0;
+		}
+#endif
+		return (ssize_t) sprintf(buf, "%d", offset);
+		break;
+			
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static ssize_t set_adc_raw(void *device,
+					char *buf,
+					size_t len,
+					const struct iio_ch_info *channel,
+					intptr_t id)
+{
+	/* ADC raw value, offset factor and scale factor are fixed for given configurations set
+	 * in the firmware */
+	return len;
+}
+
+/*!
+ * @brief	Getter/Setter for the sampling frequency attribute value
+ * @param	device- pointer to IIO device structure
+ * @param	buf- pointer to buffer holding attribute value
+ * @param	len- length of buffer string data
+ * @param	channel- pointer to IIO channel structure
+ * @return	Number of characters read/written
+ * @Note	This attribute is used to define the timeout period in IIO
+ *			client during data capture.
+ *			Timeout = (number of requested samples * (1/sampling frequency)) + 1sec
+ *			e.g. if sampling frequency = 50SPS and requested samples = 400
+ *			Timeout = (400 * 0.02) + 1 = 9sec
+ */
+ssize_t get_sampling_frequency(void *device,
+			       char *buf,
+			       size_t len,
+			       const struct iio_ch_info *channel,
+			       intptr_t id)
+{
+	return (ssize_t) sprintf(buf, "%d", SAMPLING_RATE);
+}
+
+ssize_t set_sampling_frequency(void *device,
+			       char *buf,
+			       size_t len,
+			       const struct iio_ch_info *channel,
+			       intptr_t id)
+{
+	/* Sampling frequency determines the IIO client timeout. It is defined in the
+	* software and not allowed to change externally */
+	return -EINVAL;
+}
+
+/*!
+ * @brief	Read the debug register value
+ * @param	dev- Pointer to IIO device instance
+ * @param	reg- Register address to read from
+ * @param	readval- Pointer to variable to read data into
+ * @return	SUCCESS in case of success, negative value otherwise
+ */
+int32_t debug_reg_read(void *dev, uint32_t reg, uint8_t *readval)
+{
+	/* Read the data from device */
+	if (reg <= NUM_OF_REGISTERS) {
+		if (ad469x_spi_reg_read(dev, reg, readval) == SUCCESS) {
+			return SUCCESS;
+		}
+	}
+
+	return FAILURE;
+}
+
+/*!
+ * @brief	Write into the debug register
+ * @param	dev- Pointer to IIO device instance
+ * @param	reg- Register address to write into
+ * @param	writeval- Register value to write
+ * @return	SUCCESS in case of success, negative value otherwise
+ */
+int32_t debug_reg_write(void *dev, uint32_t reg, uint32_t writeval)
+{
+	if (reg <= NUM_OF_REGISTERS) {
+		if (ad469x_spi_reg_write(dev, reg, writeval) == SUCCESS) {
+			return SUCCESS;
+		}
+	}
+
+	return FAILURE;
+}
+
+/**
+ * @brief	Read buffer data corresponding to AD4696 IIO device
+ * @param	dev_instance[in] - IIO device instance
+ * @param	pbuf[out] - Pointer to output data buffer
+ * @param	offset[in] - Data buffer offset
+ * @param	bytes_count[in] - Number of bytes to read
+ * @param	ch_mask[in] - Channels select mask
+ * @return	SUCCESS in case of success or negative value otherwise
+ */
+static ssize_t iio_ad4696_read_data(void *dev_instance,
+				    char *pbuf,
+				    size_t offset,
+				    size_t bytes_count,
+				    uint32_t ch_mask)
+{
+	if (adc_data_capture_started == false) {
+		start_data_capture(ch_mask, AD469x_CHANNEL_NO);
+		adc_data_capture_started = true;
+	}
+
+	/* Read the buffered data */
+	return (ssize_t)read_buffered_data(pbuf, bytes_count, offset, ch_mask,
+		BYTES_PER_SAMPLE);
+
+}
+
+/**
+ * @brief	Transfer the device data into memory (optional)
+ * @param	dev_instance[in] - IIO device instance
+ * @param	bytes_count[in] - Number of bytes to read
+ * @param	ch_mask[in] - Channels select mask
+ * @return	SUCCESS in case of success or negative value otherwise
+ */
+static ssize_t iio_ad4696_transfer_dev_data(void *dev_instance,
+		size_t bytes_count, uint32_t ch_mask)
+{
+	store_requested_samples_count(bytes_count, BYTES_PER_SAMPLE);
+	return SUCCESS;
+}
+
+/**
+ * @brief	Perform tasks before new data transfer
+ * @param	dev_instance[in] - IIO device instance
+ * @param	ch_mask[in] - Channels select mask
+ * @return	SUCCESS in case of success or negative value otherwise
+ */
+static int32_t iio_ad4696_start_transfer(void *dev_instance, uint32_t ch_mask)
+{
+	return SUCCESS;
+}
+
+
+/**
+ * @brief	Perform tasks before end of current data transfer
+ * @param	dev_instance[in] - IIO device instance
+ * @return	SUCCESS in case of success or negative value otherwise
+ */
+static int32_t iio_ad4696_stop_transfer(void *dev)
+{
+	adc_data_capture_started = false;
+	stop_data_capture();
+
+	return SUCCESS;
+}
+
+/*********************************************************
+ *               IIO Attributes and Structures
+ ********************************************************/
+
+/* IIOD channels attributes list */
+struct iio_attribute channel_input_attributes[] = {
+	{
+		.name = "raw",
+		.show = get_adc_raw,
+		.store = set_adc_raw,
+		.priv = IIO_RAW_ATTR_ID
+	},
+	{
+		.name = "scale",
+		.show = get_adc_raw,
+		.store = set_adc_raw,
+		.priv = IIO_SCALE_ATTR_ID
+	},
+	{
+		.name = "offset",
+		.show = get_adc_raw,
+		.store = set_adc_raw,
+		.priv = IIO_OFFSET_ATTR_ID
+	},
+
+	END_ATTRIBUTES_ARRAY
+};
+
+/* IIOD device (global) attributes list */
+static struct iio_attribute global_attributes[] = {
+	{
+		.name = "sampling_frequency",
+		.show = get_sampling_frequency,
+		.store = set_sampling_frequency,
+	},
+
+	END_ATTRIBUTES_ARRAY
+};
+
+/* IIOD debug attributes list */
+static struct iio_attribute debug_attributes[] = {
+	{
+		.name = "direct_reg_access",
+		.show = NULL,
+		.store = NULL,
+	},
+
+	END_ATTRIBUTES_ARRAY
+};
+
+/* IIOD channels configurations */
+struct scan_type chn_scan = {
+#if defined(PSEUDO_BIPOLAR_MODE)
+	.sign = 's',
+#else
+	.sign = 'u',
+#endif
+	.realbits = CHN_STORAGE_BITS,
+	.storagebits = CHN_STORAGE_BITS,
+	.shift = 0,
+	.is_big_endian = false
+};
+static struct iio_channel iio_ad4696_channels[] = {
+	{
+		.name = "voltage0",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 0,
+		.scan_index = 0,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true,
+	},
+	{
+		.name = "voltage1",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 1,
+		.scan_index = 1,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage2",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 2,
+		.scan_index = 2,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage3",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 3,
+		.scan_index = 3,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage4",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 4,
+		.scan_index = 4,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage5",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 5,
+		.scan_index = 5,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage6",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 6,
+		.scan_index = 6,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage7",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 7,
+		.scan_index = 7,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage8",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 8,
+		.scan_index = 8,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true,
+	},
+	{
+		.name = "voltage9",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 9,
+		.scan_index = 9,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage10",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 10,
+		.scan_index = 10,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage11",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 11,
+		.scan_index = 11,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage12",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 12,
+		.scan_index = 12,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage13",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 13,
+		.scan_index = 13,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage14",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 14,
+		.scan_index = 14,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+	{
+		.name = "voltage15",
+		.ch_type = IIO_VOLTAGE,
+		.channel = 15,
+		.scan_index = 15,
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+};
+
+/**
+ * @brief	Init for reading/writing and parameterization of a
+ * 			ad4696 IIO device
+ * @param 	desc[in,out] - IIO device descriptor
+ * @return	SUCCESS in case of success, FAILURE otherwise
+ */
+static int32_t iio_ad4696_init(struct iio_device **desc)
+{
+	struct iio_device *iio_ad4696_inst;
+
+	iio_ad4696_inst = calloc(1, sizeof(struct iio_device));
+	if (!iio_ad4696_inst) {
+		return FAILURE;
+	}
+
+	iio_ad4696_inst->num_ch = sizeof(iio_ad4696_channels) / sizeof(
+					  iio_ad4696_channels[0]);
+	iio_ad4696_inst->channels = iio_ad4696_channels;
+	iio_ad4696_inst->attributes = global_attributes;
+	iio_ad4696_inst->debug_attributes = debug_attributes;
+
+	iio_ad4696_inst->transfer_dev_to_mem = iio_ad4696_transfer_dev_data;
+	iio_ad4696_inst->transfer_mem_to_dev = NULL;
+	iio_ad4696_inst->read_data = iio_ad4696_read_data;
+	iio_ad4696_inst->write_data = NULL;
+	iio_ad4696_inst->prepare_transfer = iio_ad4696_start_transfer;
+	iio_ad4696_inst->end_transfer = iio_ad4696_stop_transfer;
+	iio_ad4696_inst->debug_reg_read = debug_reg_read;
+	iio_ad4696_inst->debug_reg_write = debug_reg_write;
+
+	*desc = iio_ad4696_inst;
+
+	return SUCCESS;
+}
+
+/**
+ * @brief Release resources allocated for IIO device
+ * @param desc[in] - IIO device descriptor
+ * @return SUCCESS in case of success, FAILURE otherwise
+ */
+static int32_t iio_ad4696_remove(struct iio_desc *desc)
+{
+	int32_t status;
+
+	if (!desc) {
+		return FAILURE;
+	}
+
+	status = iio_unregister(desc, (char *)dev_name);
+	if (status != SUCCESS) {
+		return FAILURE;
+	}
+
+	return SUCCESS;
+}
+
+
+/**
+ * @brief	Initialize the IIO interface for AD4696 IIO device
+ * @return	SUCCESS in case of success, FAILURE otherwise
+ */
+int32_t ad4696_iio_initialize(void)
+{
+	int32_t init_status;
+
+	/* IIO device descriptor */
+	struct iio_device *p_iio_ad4696_dev;
+
+	/* IIO interface init parameter */
+	struct iio_init_param iio_init_params = {
+		.phy_type = USE_UART,
+		{
+			&uart_init_params
+		}
+	};
+
+	/* Initialize AD4696 device and peripheral interface */
+	init_status = ad469x_init(&p_ad4696_dev, &ad4696_init_str);
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+
+	/* Initialize the IIO interface */
+	init_status = iio_init(&p_ad4696_iio_desc, &iio_init_params);
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+
+	/* Register and initialize the AD4696 device into IIO interface */
+	init_status = iio_ad4696_init(&p_iio_ad4696_dev);
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+
+	/* Register AD4696 IIO interface */
+	init_status = iio_register(p_ad4696_iio_desc, p_iio_ad4696_dev,
+				   (char *)dev_name, p_ad4696_dev, NULL,
+				   NULL);
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+
+	/* Init the system peripherals */
+	init_status = init_system();
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+
+	/* To enable manual trigger mode for operation */ 
+	init_status = ad4696_enable_manual_trigger_mode(p_ad4696_dev);
+	if (init_status != SUCCESS) {
+		return init_status;
+	}
+	
+	return SUCCESS;
+}
+
+/**
+ * @brief 	Run the AD4696 IIO event handler
+ * @return	none
+ * @details	This function monitors the new IIO client event
+ */
+void ad4696_iio_event_handler(void)
+{
+	while(1) {
+		(void)iio_step(p_ad4696_iio_desc);
+	}
+}