Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
app/ad7689_iio.c
- Committer:
- MPhalke@MPHALKE-L02.ad.analog.com
- Date:
- 2022-07-15
- Revision:
- 2:8ce98fe471c7
File content as of revision 2:8ce98fe471c7:
/***************************************************************************//**
* @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);
}