IIO firmware for the AD717x and AD411x family of devices.

Dependencies:   sdp_k1_sdram

app/ad717x_iio.c

Committer:
Janani Sunil
Date:
22 months ago
Revision:
3:0dcba3253ec1
Parent:
0:5ad86d8d396a

File content as of revision 3:0dcba3253ec1:

/***************************************************************************//**
 * @file    ad717x_iio.c
 * @brief   Source file for the AD717x IIO Application
********************************************************************************
* 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 <stdio.h>
#include "ad717x_user_config.h"
#include "app_config.h"
#include "ad717x_iio.h"
#include "ad717x.h"
#include "iio.h"
#include "no_os_util.h"
#include "ad717x_data_capture.h"
#include "no_os_error.h"

/******************************************************************************/
/********************* Macros and Constants Definition ************************/
/******************************************************************************/

/* Define ADC Resolution in Bits */
#if defined (DEV_AD7177_2)
#define AD717x_RESOLUTION	32
#else
#define AD717x_RESOLUTION	24
#endif

/* ADC max count (full scale value) for unipolar inputs */
#define ADC_MAX_COUNT_UNIPOLAR	(uint32_t)((1 << AD717x_RESOLUTION) - 1)

/* ADC max count (full scale value) for bipolar inputs */
#define ADC_MAX_COUNT_BIPOLAR	(uint32_t)(1 << (AD717x_RESOLUTION-1))

/* Bytes per sample (*Note: 4 bytes needed per sample for data range
 * of 0 to 32-bit) */
#define	BYTES_PER_SAMPLE	sizeof(uint32_t)

/* Number of data storage bits (needed for IIO client) */
#define CHN_STORAGE_BITS	(BYTES_PER_SAMPLE * 8)

/* Private IDs for IIO attributes */
#define	AD717x_RAW_ATTR_ID		0
#define	AD717x_SCALE_ATTR_ID		1
#define	AD717x_OFFSET_ATTR_ID		2
#define AD717x_SAMPLING_FREQUENCY_ID	3

/* Data Buffer for burst mode data capture */
#define AD717x_DATA_BUFFER_SIZE		(8192)

/* Scan type definition */
#define AD717x_SCAN {\
	.sign = 'u',\
	.realbits = AD717x_RESOLUTION,\
	.storagebits = CHN_STORAGE_BITS,\
	.shift = 0,\
	.is_big_endian = false\
}

/* Channel attribute definition */
#define AD717x_CHANNEL(_name, _priv) {\
	.name = _name,\
	.priv = _priv,\
	.show = get_adc_attribute,\
	.store = set_adc_attribute\
}

/* AD717x Channel Definition */
#define IIO_AD717x_CHANNEL(_idx) {\
	.name = "ch" # _idx,\
	.ch_type = IIO_VOLTAGE,\
	.channel = _idx,\
	.scan_index = _idx,\
	.indexed = true,\
	.scan_type = &ad717x_scan_type[_idx],\
	.ch_out = false,\
	.attributes = ad717x_channel_attributes,\
}

/******************************************************************************/
/******************** Variables and User Defined Data Types *******************/
/******************************************************************************/

/* IIO interface descriptor */
static struct iio_desc *p_ad717x_iio_desc;

/* Pointer to the struct representing the AD717x IIO device */
ad717x_dev *p_ad717x_dev_inst = NULL;

/* Device Name */
static const char dev_name[] = ACTIVE_DEVICE_NAME;

/* Variable to hold the number of active channels*/
uint8_t num_active_channels = 0;

/* Channel scale values */
static float attr_scale_val[NUMBER_OF_CHANNELS];

/* Channel offset values */
static int attr_offset_val[NUMBER_OF_CHANNELS];

/* AD717x channel scan type */
static struct scan_type ad717x_scan_type[] = {
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
#if (NUMBER_OF_CHANNELS != 4)
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
#if (NUMBER_OF_CHANNELS != 4) && (NUMBER_OF_CHANNELS !=8 )
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN,
	AD717x_SCAN
#endif
#endif
};

/******************************************************************************/
/************************** Functions Declaration *****************************/
/******************************************************************************/

/******************************************************************************/
/************************** Functions Definition ******************************/
/******************************************************************************/

/*!
 * @brief	Getter/Setter for the attribute value
 * @param	device[in]- pointer to IIO device structure
 * @param	buf[in]- pointer to buffer holding attribute value
 * @param	len[in]- length of buffer string data
 * @param	channel[in]- pointer to IIO channel structure
 * @param	id[in]- Attribute ID
 * @return	Number of characters read/written in case of success, negative error code otherwise
 */
static int32_t get_adc_attribute(void *device,
				 char *buf,
				 uint32_t len,
				 const struct iio_ch_info *channel,
				 intptr_t id)
{
	int32_t adc_raw_data = 0;
	int32_t adc_offset = 0;

	switch (id) {
	case AD717x_RAW_ATTR_ID:
		if (ad717x_single_read(device, channel->ch_num, &adc_raw_data) < 0)
			return -EINVAL;

		return sprintf(buf, "%d", adc_raw_data);

	case AD717x_SCALE_ATTR_ID:
		return sprintf(buf, "%f", attr_scale_val[channel->ch_num]);

	case AD717x_OFFSET_ATTR_ID:
		return sprintf(buf, "%d", attr_offset_val[channel->ch_num]);

	case AD717x_SAMPLING_FREQUENCY_ID:
		return sprintf(buf, "%d", AD717x_SAMPLING_RATE/NUMBER_OF_CHANNELS);

	default:
		break;
	}

	return -EINVAL;
}


static int32_t set_adc_attribute(void *device,
				 char *buf,
				 uint32_t len,
				 const struct iio_ch_info *channel,
				 intptr_t id)
{
	switch (id) {

	/* ADC Raw, Scale, Offset factors are constant for the firmware configuration */
	case AD717x_RAW_ATTR_ID:
	case AD717x_SCALE_ATTR_ID:
	case AD717x_OFFSET_ATTR_ID:
	case AD717x_SAMPLING_FREQUENCY_ID:
	default:
		break;
	}

	return len;
}

/* AD717X Channel Attributes */
static struct iio_attribute ad717x_channel_attributes[] = {
	AD717x_CHANNEL("raw", AD717x_RAW_ATTR_ID),
	AD717x_CHANNEL("scale", AD717x_SCALE_ATTR_ID),
	AD717x_CHANNEL("offset", AD717x_OFFSET_ATTR_ID),
	END_ATTRIBUTES_ARRAY
};

/* AD717x Global Attributes */
static struct iio_attribute iio_ad717x_global_attributes[] = {
	AD717x_CHANNEL("sampling_frequency", AD717x_SAMPLING_FREQUENCY_ID),
	END_ATTRIBUTES_ARRAY
};

/* IIO Attributes */
static struct iio_channel iio_adc_channels[] = {
	IIO_AD717x_CHANNEL(0),
	IIO_AD717x_CHANNEL(1),
	IIO_AD717x_CHANNEL(2),
	IIO_AD717x_CHANNEL(3),
#if (NUMBER_OF_CHANNELS != 4)
	IIO_AD717x_CHANNEL(4),
	IIO_AD717x_CHANNEL(5),
	IIO_AD717x_CHANNEL(6),
	IIO_AD717x_CHANNEL(7),
#if (NUMBER_OF_CHANNELS != 4) && (NUMBER_OF_CHANNELS != 8)
	IIO_AD717x_CHANNEL(8),
	IIO_AD717x_CHANNEL(9),
	IIO_AD717x_CHANNEL(10),
	IIO_AD717x_CHANNEL(11),
	IIO_AD717x_CHANNEL(12),
	IIO_AD717x_CHANNEL(13),
	IIO_AD717x_CHANNEL(14),
	IIO_AD717x_CHANNEL(15)
#endif
#endif
};

/**
 * @brief Read the debug register value
 * @param desc[in,out] - Pointer to IIO device descriptor
 * @param reg[in]- Address of the register to be read
 * @param readval[out]- Pointer to the register data variable
 * @return 0 in case of success, negative error code
 */
static int32_t iio_ad717x_debug_reg_read(void *dev,
		uint32_t reg,
		uint32_t *readval)
{
	int32_t debug_read_status; // Status check variable

	/* Retrieve the pointer to the requested register */
	ad717x_st_reg *read_register =  AD717X_GetReg(p_ad717x_dev_inst, reg);
	if (!read_register) {
		return -EINVAL;
	}

	/* Read the register data, extract the value */
	debug_read_status = AD717X_ReadRegister(p_ad717x_dev_inst, reg);
	if (debug_read_status) {
		return debug_read_status;
	}
	*readval = read_register->value;

	return 0;
}


/**
 * @brief Write value to the debug register
 * @param desc[in,out] Pointer to IIO device descriptor
 * @param reg[in] Address of the register where the data is to be written
 * @param write_val[out] Pointer to the register data variable
 * @return 0 in case of success, negative error code otherwise
 */
static int32_t iio_ad717x_debug_reg_write(void *dev,
		uint32_t reg,
		uint32_t write_val)
{
	int32_t debug_write_status;	// Status check variable
	ad717x_st_reg *device_data_reg;  // Pointer to data register

	/* Retrieve the pointer to the requested registrer */
	device_data_reg = AD717X_GetReg(p_ad717x_dev_inst, reg);
	device_data_reg->value = write_val;

	/* Write value to the register */
	debug_write_status = AD717X_WriteRegister(p_ad717x_dev_inst, reg);
	if (debug_write_status) {
		return debug_write_status;
	}

	return 0;
}


/**
 * @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 or negative value otherwise
 */
static int32_t iio_ad717x_pre_enable(void *dev_instance, uint32_t chn_mask)
{
	return prepare_data_transfer(chn_mask, NUMBER_OF_CHANNELS, BYTES_PER_SAMPLE);
}


/**
 * @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 or negative value otherwise
 */
static int32_t iio_ad717x_submit_buffer(struct iio_device_data *iio_dev_data)
{
	int32_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 Perform tasks before end of current data transfer
 * @param dev[in] - IIO device instance
 * @return 0 in case of success or negative value otherwise
 */
static int32_t iio_ad717x_post_disable(void *dev)
{
	return end_data_transfer();
}


/**
 * @brief Init for reading/writing and parameterization of a AD717x IIO device
 * @param desc[in,out] IIO device descriptor
 * @return 0 in case of success, negative error code otherwise
 */
int32_t iio_ad717x_init(struct iio_device **desc)
{
	struct iio_device *iio_ad717x_inst;  // IIO Device Descriptor for AD717x

	iio_ad717x_inst = calloc(1, sizeof(struct iio_device));
	if (!iio_ad717x_inst) {
		return -EINVAL;
	}

	iio_ad717x_inst->num_ch = NO_OS_ARRAY_SIZE(iio_adc_channels);
	iio_ad717x_inst->channels = iio_adc_channels;
	iio_ad717x_inst->attributes = iio_ad717x_global_attributes;
	iio_ad717x_inst->buffer_attributes = NULL;
	iio_ad717x_inst->write_dev = NULL;
	iio_ad717x_inst->pre_enable = iio_ad717x_pre_enable;
	iio_ad717x_inst->post_disable = iio_ad717x_post_disable;
	iio_ad717x_inst->submit = iio_ad717x_submit_buffer;
	iio_ad717x_inst->debug_reg_read = iio_ad717x_debug_reg_read;
	iio_ad717x_inst->debug_reg_write = iio_ad717x_debug_reg_write;

	*desc = iio_ad717x_inst;

	return 0;
}


/**
 * @brief Function to update scale and offset values based on user selection
 * @param device[in] AD717x device descriptor
 * @return 0 in case of success, negative error code otherwise
 */
static int32_t ad717x_update_attr_parameters(ad717x_dev *device)
{
	float reference_value = 0; // Variable to hold the updated reference value
	uint8_t i;

	for (i = 0; i < NUMBER_OF_CHANNELS; i++) {
		/* Update reference value */
		switch (device->setups[device->chan_map[i].setup_sel].ref_source) {
		case INTERNAL_REF:
			reference_value = AD717X_INTERNAL_REFERENCE;
			break;
		case EXTERNAL_REF:
			reference_value = AD717x_EXTERNAL_REFERENCE;
			break;
		case AVDD_AVSS:
			reference_value = AD717X_AVDD_AVSS_REFERENCE;
			break;
		default:
			return -EINVAL;
		}

		/* Update channel attribute parameters */
		if (!(device->setups[device->chan_map[i].setup_sel].bi_unipolar)) {
			/* Settings for Unipolar mode */
			attr_scale_val[i] = ((reference_value / ADC_MAX_COUNT_UNIPOLAR) * 1000) /
					    SCALE_FACTOR_DR;
			attr_offset_val[i] = 0;
			ad717x_scan_type[i].sign = 'u';
			ad717x_scan_type[i].realbits = AD717x_RESOLUTION;
		} else {
			/* Settings for Bipolar mode */
			attr_scale_val[i] = ((reference_value / (ADC_MAX_COUNT_BIPOLAR)) * 1000) /
					    SCALE_FACTOR_DR;
			attr_offset_val[i] = -(1 << (AD717x_RESOLUTION - 1));
			ad717x_scan_type[i].sign = 's';
			ad717x_scan_type[i].realbits = CHN_STORAGE_BITS;
		}
	}

	return 0;
}


/**
 * @brief 	Initialize the AD717x IIO Interface
 * @return	0 in case of success, negative error code otherwise
 */
int32_t ad717x_iio_initialize(void)
{
	int32_t iio_init_status;		    // Status check variable
	struct iio_init_param iio_init_params;	    // IIO Init Parameters
	struct iio_device *ad717x_iio_desc;	    //  aD717x IIO Descriptor

	/* Init the system peripheral- UART */
	iio_init_status = init_system();
	if (iio_init_status) {
		return iio_init_status;
	}

	/* IIO Initialization Parameters */
	iio_init_params.phy_type = USE_UART;
	iio_init_params.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
	};

	/* Initialize AD717x device */
	iio_init_status = AD717X_Init(&p_ad717x_dev_inst, ad717x_init_params);
	if (iio_init_status) {
		return iio_init_status;
	}

	/* Update the ADC scale respective to the device settings */
	iio_init_status = ad717x_update_attr_parameters(p_ad717x_dev_inst);
	if (iio_init_status) {
		return iio_init_status;
	}

	/* Initialize the AD717x IIO Interface */
	iio_init_status = iio_ad717x_init(&ad717x_iio_desc);
	if (iio_init_status) {
		return iio_init_status;
	}

	/* Initialize the IIO Interface */
	iio_init_params.uart_desc = uart_desc;
	iio_device_init_params.dev = p_ad717x_dev_inst;
	iio_device_init_params.dev_descriptor = ad717x_iio_desc;
	iio_init_params.devs = &iio_device_init_params;
	iio_init_params.nb_trigs = 0;
	iio_init_status = iio_init(&p_ad717x_iio_desc, &iio_init_params);
	if (iio_init_status) {
		return iio_init_status;
	}

	return 0;
}


/**
 * @brief 	Run the AD717x IIO event handler
 * @return	None
 */
void ad717x_iio_event_handler(void)
{
	(void)iio_step(p_ad717x_iio_desc);
}