Analog Devices / Mbed OS EVAL-AD7689

Dependencies:   sdp_k1_sdram

Revision:
2:007533849deb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/ad7689_iio.c	Thu Jul 21 16:45:24 2022 +0530
@@ -0,0 +1,513 @@
+/***************************************************************************//**
+ *   @file    ad7689_iio.c
+ *   @brief   Implementation of AD7689 IIO application interfaces
+********************************************************************************
+ * Copyright (c) 2021-22 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "ad7689_iio.h"
+#include "app_config.h"
+#include "ad7689_user_config.h"
+#include "ad7689_data_capture.h"
+#include "no_os_error.h"
+
+/******************************************************************************/
+/********************* Macros and Constants Definition ************************/
+/******************************************************************************/
+
+/* ADC Raw to Voltage conversion default scale factor for IIO client */
+#if defined(BIPOLAR)
+/* Device supports only pseudo-bipolar mode. INX- = Vref / 2 */
+#define ADC_DEFAULT_SCALE		(((ADC_DEFAULT_REF_VOLTAGE / 2) / ADC_MAX_COUNT_BIPOLAR) * 1000)
+#else
+#define ADC_DEFAULT_SCALE		((ADC_DEFAULT_REF_VOLTAGE / ADC_MAX_COUNT_UNIPOLAR) * 1000)
+#endif
+
+/* The output of temperature sensor is always unipolar (streight-binary) */
+#define TEMPERATURE_SENSITIVITY		0.283	// 283mv
+#define ROOM_TEMPERATURE			25.0
+#define TEMPERATURE_CONV_SCALE		(ROOM_TEMPERATURE / TEMPERATURE_SENSITIVITY) * \
+									((ADC_DEFAULT_REF_VOLTAGE / ADC_MAX_COUNT_UNIPOLAR) * 1000)
+
+/* 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
+
+/******************************************************************************/
+/******************** Variables and User Defined Data Types *******************/
+/******************************************************************************/
+
+/* IIO interface descriptor */
+static struct iio_desc *p_ad7689_iio_desc;
+
+/* Device name */
+static const char dev_name[] = ACTIVE_DEVICE_NAME;
+
+/* Pointer to the struct representing the AD7689 IIO device */
+struct ad7689_dev *p_ad7689_dev_inst = NULL;
+
+/* Device attributes with default values */
+
+/* Scale attribute value per channel */
+static float attr_scale_val[ADC_CHN_COUNT] = {
+	ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE,
+#if !defined(DEV_AD7682)
+	ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE,
+#endif
+	TEMPERATURE_CONV_SCALE
+};
+
+/* AD7689 current configuration */
+struct ad7689_config ad7689_current_config;
+
+/******************************************************************************/
+/************************** Functions Declarations ****************************/
+/******************************************************************************/
+
+/******************************************************************************/
+/************************ Functions Definitions *******************************/
+/******************************************************************************/
+
+/*!
+ * @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
+ * @param	id- Attribute ID (optional)
+ * @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 = 60KSPS and requested samples = 400
+ *			Timeout = (400 * (1/60000)) + 1 = 1.0067sec = ~1sec
+ */
+static int get_sampling_frequency(void *device,
+				  char *buf,
+				  uint32_t len,
+				  const struct iio_ch_info *channel,
+				  intptr_t id)
+{
+	return sprintf(buf, "%d", SAMPLING_RATE);
+}
+
+static int set_sampling_frequency(void *device,
+				  char *buf,
+				  uint32_t len,
+				  const struct iio_ch_info *channel,
+				  intptr_t id)
+{
+	/* sampling frequency is read-only attribute */
+	return len;
+}
+
+
+/*!
+ * @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 (optional)
+ * @return	Number of characters read/written
+ */
+static int get_adc_raw(void *device,
+		       char *buf,
+		       uint32_t len,
+		       const struct iio_ch_info *channel,
+		       intptr_t id)
+{
+	static uint32_t adc_data_raw = 0;
+	int32_t offset = 0;
+	int32_t ret;
+
+	switch (id) {
+	case IIO_RAW_ATTR_ID:
+		/* Capture the raw adc data */
+		ret = read_single_sample((uint8_t)channel->ch_num, &adc_data_raw);
+		if (ret) {
+			return sprintf(buf, " %s", "Error");
+		}
+		return sprintf(buf, "%d", adc_data_raw);
+
+	case IIO_SCALE_ATTR_ID:
+		return sprintf(buf, "%g", attr_scale_val[channel->ch_num]);
+
+	case IIO_OFFSET_ATTR_ID:
+#if defined(BIPOLAR)
+		if (channel->ch_num == TEMPERATURE_CHN) {
+			offset = 0;
+		} else {
+			if (adc_data_raw >= ADC_MAX_COUNT_BIPOLAR) {
+				offset = -ADC_MAX_COUNT_UNIPOLAR;
+			} else {
+				offset = 0;
+			}
+		}
+#endif
+		return sprintf(buf, "%d", offset);
+
+	default:
+		break;
+	}
+
+	return len;
+}
+
+static int set_adc_raw(void *device,
+		       char *buf,
+		       uint32_t len,
+		       const struct iio_ch_info *channel,
+		       intptr_t id)
+{
+	/* ADC raw, offset and scale are read-only attributes */
+	return len;
+}
+
+/**
+ * @brief	Read buffer data corresponding to AD4170 IIO device
+ * @param	iio_dev_data[in] - Pointer to IIO device data structure
+ * @return	0 in case of success, negative error code otherwise
+ */
+static int32_t iio_ad7689_submit_buffer(struct iio_device_data *iio_dev_data)
+{
+	uint32_t ret;
+
+	/* Read the samples counts equal to buffer size/block */
+	ret = read_buffered_data(&iio_dev_data->buffer->buf->buff,
+				 iio_dev_data->buffer->size);
+
+	/* Increment the write spin count as buffer reads all 'n' samples
+	 * in one go which is also the size of buffer block for a given instance.
+	 * The read spin count is incremented from IIO library during buffer
+	 * write/offloading into transmit buffer */
+	if (iio_dev_data->buffer->buf->write.spin_count >= UINT32_MAX) {
+		iio_dev_data->buffer->buf->write.spin_count = 0;
+	}
+
+	iio_dev_data->buffer->buf->write.spin_count += 1;
+
+	return ret;
+}
+
+/**
+ * @brief	Transfer the device data into memory (optional)
+ * @param	dev_instance[in] - IIO device instance
+ * @param	ch_mask[in] - Channels select mask
+ * @return	0 in case of success, negative error code otherwise
+ */
+static int32_t iio_ad7689_prepare_transfer(void *dev_instance,
+		uint32_t ch_mask)
+{
+	return prepare_data_transfer(ch_mask, ADC_CHN_COUNT, BYTES_PER_SAMPLE);
+}
+
+/**
+ * @brief	Perform tasks before end of current data transfer
+ * @param	dev[in] - IIO device instance
+ * @return	0 in case of success, negative error code otherwise
+ */
+static int32_t iio_ad7689_end_transfer(void *dev)
+{
+	return end_data_transfer();
+}
+
+/*********************************************************
+ *               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 context attributes list */
+static struct iio_context_attribute iio_context_attributes[] = {
+	{
+		.name = "hw_mezzanine",
+		.value = HW_MEZZANINE_NAME
+	},
+	{
+		.name = "hw_carrier",
+		.value = HW_CARRIER_NAME
+	},
+	{
+		.name = "hw_name",
+		.value = HW_NAME
+	},
+	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 channels configurations */
+struct scan_type chn_scan = {
+#if defined(BIPOLAR)
+	.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_ad7689_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
+	},
+#if !defined(DEV_AD7682)
+	{
+		.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
+	},
+#endif
+	{
+		.name = "temperature",
+		.ch_type = IIO_TEMP,
+#if !defined(DEV_AD7682)
+		.channel = 8,
+		.scan_index = 8,
+#else
+		.channel = 4,
+		.scan_index = 4,
+#endif
+		.scan_type = &chn_scan,
+		.attributes = channel_input_attributes,
+		.ch_out = false,
+		.indexed = true
+	},
+};
+
+
+/**
+ * @brief	Init for reading/writing and parameterization of a
+ * 			ad7689 IIO device
+ * @param 	desc[in,out] - IIO device descriptor
+ * @return	0 in case of success, negative error code otherwise
+ */
+static int32_t iio_ad7689_init(struct iio_device **desc)
+{
+	struct iio_device *iio_ad7689_inst;
+
+	iio_ad7689_inst = calloc(1, sizeof(struct iio_device));
+	if (!iio_ad7689_inst) {
+		return -EINVAL;
+	}
+
+	iio_ad7689_inst->num_ch = sizeof(iio_ad7689_channels) / sizeof(
+					  iio_ad7689_channels[0]);
+	iio_ad7689_inst->channels = iio_ad7689_channels;
+	iio_ad7689_inst->attributes = global_attributes;
+	iio_ad7689_inst->context_attributes = iio_context_attributes;
+
+	iio_ad7689_inst->submit = iio_ad7689_submit_buffer;
+	iio_ad7689_inst->pre_enable = iio_ad7689_prepare_transfer;
+	iio_ad7689_inst->post_disable = iio_ad7689_end_transfer;
+
+	iio_ad7689_inst->debug_reg_read = NULL;
+	iio_ad7689_inst->debug_reg_write = NULL;
+
+	*desc = iio_ad7689_inst;
+
+	return 0;
+}
+
+/**
+ * @brief	Initialize the IIO interface for AD7689 IIO device
+ * @return	none
+ * @return	0 in case of success, negative error code otherwise
+ */
+int32_t ad7689_iio_initialize(void)
+{
+	int32_t init_status;
+
+	/* IIO device descriptor */
+	struct iio_device *p_iio_ad7689_dev;
+
+	/* IIO interface init parameters */
+	struct iio_init_param iio_init_params = {
+		.phy_type = USE_UART,
+		.nb_devs = 1,
+	};
+
+	/* IIOD init parameters */
+	struct iio_device_init iio_device_init_params = {
+		.name = (char *)dev_name,
+		.raw_buf = adc_data_buffer,
+		.raw_buf_len = DATA_BUFFER_SIZE
+	};
+
+	/* Init the system peripherals */
+	init_status = init_system();
+	if (init_status) {
+		return init_status;
+	}
+
+	/* Initialize AD7689 device and peripheral interface */
+	init_status = ad7689_init(&p_ad7689_dev_inst, &ad7689_init_params);
+	if (init_status) {
+		return init_status;
+	}
+
+	/* Initialize the AD7689 IIO application interface */
+	init_status = iio_ad7689_init(&p_iio_ad7689_dev);
+	if (init_status) {
+		return init_status;
+	}
+
+	/* Initialize the IIO interface */
+	iio_init_params.uart_desc = uart_desc;
+	iio_device_init_params.dev = p_ad7689_dev_inst;
+	iio_device_init_params.dev_descriptor = p_iio_ad7689_dev;
+	iio_init_params.devs = &iio_device_init_params;
+	init_status = iio_init(&p_ad7689_iio_desc, &iio_init_params);
+	if (init_status) {
+		return init_status;
+	}
+
+	/* Load the init config into current configuration */
+	memcpy(&ad7689_current_config, &ad7689_init_params.config,
+	       sizeof(ad7689_current_config));
+
+	return 0;
+}
+
+/**
+ * @brief 	Run the AD7689 IIO event handler
+ * @return	none
+ * @details	This function monitors the new IIO client event
+ */
+void ad7689_iio_event_handler(void)
+{
+	(void)iio_step(p_ad7689_iio_desc);
+}