Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
app/iio_ad4696.c
- Committer:
- pmallick
- Date:
- 2021-09-30
- Revision:
- 1:8792acb5a039
File content as of revision 1:8792acb5a039:
/***************************************************************************//** * @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); } }