Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
Diff: app/iio_ad4696.c
- Revision:
- 1:8792acb5a039
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/iio_ad4696.c Thu Sep 30 11:01:05 2021 +0530 @@ -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); + } +}