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); }