IIO firmware for the AD4110
Dependencies: tempsensors sdp_k1_sdram
app/ad4110_iio.c
- Committer:
- Janani Sunil
- Date:
- 2022-08-01
- Revision:
- 1:a78dbaa4b05d
- Parent:
- 0:6ca37a8f8ba9
File content as of revision 1:a78dbaa4b05d:
/***************************************************************************//** * @file ad4110_iio.c * @brief Implementation of AD4110-1 IIO application interfaces ******************************************************************************** * Copyright (c) 2022 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 <stdlib.h> #include "ad4110_iio.h" #include "app_config.h" #include "ad4110.h" #include "no_os_error.h" #include "no_os_util.h" #include "ad4110_data_capture.h" #include "ad4110_temperature_sensor.h" /* Forward declaration of getter/setter functions */ static int ad4110_get_attribute(void *device, char *buf, uint32_t len, const struct iio_ch_info *channel, intptr_t priv); static int ad4110_set_attribute(void *device, char *buf, uint32_t len, const struct iio_ch_info *channel,intptr_t priv); /******************************************************************************/ /************************ Macros/Constants ************************************/ /******************************************************************************/ /* 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) /* Channel Attribute definition */ #define AD4110_CH_ATTR(_name, _idx) {\ .name = _name,\ .priv = _idx,\ .show = ad4110_get_attribute,\ .store = ad4110_set_attribute\ } /* Channel definition */ #define AD4110_CHANNEL(_name, _idx) {\ .name = _name # _idx, \ .ch_type = IIO_CHANNEL_TYPE,\ .ch_out = false,\ .indexed = true,\ .channel = _idx,\ .scan_index = _idx,\ .scan_type = &ad4110_scan_type,\ .attributes = ad4110_channel_attributes\ } #if (REGISTER_READ_SEL == AD4110_ADC) #define REGISTER_MAX_VAL AD4110_ADC_GAIN3 #else // AD4110_AFE #define REGISTER_MAX_VAL AD4110_REG_AFE_NO_PWR_DEFAULT_STATUS #endif /* SCale value for voltage and current mode configuration */ #define AD4110_BIPOLAR_SCALE ((AD4110_REF_VOLTAGE / (ADC_MAX_COUNT_BIPOLAR)) * 1000) /AD4110_DEFAULT_PGA #define AD4110_UNIPOLAR_SCALE ((AD4110_REF_VOLTAGE / (ADC_MAX_COUNT_UNIPOLAR)) * 1000) /AD4110_DEFAULT_PGA /* IIO Channel type for each demo mode config */ #if (ACTIVE_DEMO_MODE_CONFIG == VOLTAGE_MODE_CONFIG) #define IIO_CHANNEL_TYPE IIO_VOLTAGE #elif (ACTIVE_DEMO_MODE_CONFIG == CURRENT_MODE_CONFIG) #define IIO_CHANNEL_TYPE IIO_CURRENT #elif (ACTIVE_DEMO_MODE_CONFIG == FIELD_POWER_SUPPLY_CONFIG) #define IIO_CHANNEL_TYPE IIO_CURRENT #elif (ACTIVE_DEMO_MODE_CONFIG == THERMOCOUPLE_CONFIG) #define IIO_CHANNEL_TYPE IIO_TEMP #elif (ACTIVE_DEMO_MODE_CONFIG == RTD_CONFIG) #define IIO_CHANNEL_TYPE IIO_TEMP #endif /******************************************************************************/ /*************************** Types Declarations *******************************/ /******************************************************************************/ /* IIO interface descriptor */ static struct iio_desc *ad4110_iio_desc; /* AD4110-1 Device Descriptor */ struct ad4110_dev *ad4110_dev_inst; /* IIO Device name */ static const char *dev_name = ACTIVE_DEVICE; /* Channel Attribute ID */ enum ad4110_attribute_id { RAW_ATTR_ID, SCALE_ATTR_ID, OFFSET_ATTR_ID, SAMPLING_FREQ_ATTR_ID, DEMO_CONFIG_ATTR_ID }; struct scan_type ad4110_scan_type = { .storagebits = CHN_STORAGE_BITS, .shift = 0, .is_big_endian = false }; /* Global attributes */ static struct iio_attribute ad4110_global_attributes[] = { AD4110_CH_ATTR("sampling_frequency", SAMPLING_FREQ_ATTR_ID), AD4110_CH_ATTR("demo_config", DEMO_CONFIG_ATTR_ID), END_ATTRIBUTES_ARRAY }; /* Channel attributes */ static struct iio_attribute ad4110_channel_attributes[] = { AD4110_CH_ATTR("raw", RAW_ATTR_ID), AD4110_CH_ATTR("scale", SCALE_ATTR_ID), AD4110_CH_ATTR("offset", OFFSET_ATTR_ID), END_ATTRIBUTES_ARRAY }; /* IIOD channels configurations for AD4110-1 */ static struct iio_channel ad4110_iio_channels[] = { AD4110_CHANNEL("Chn", 0), AD4110_CHANNEL("Chn", 1), AD4110_CHANNEL("Chn", 2), AD4110_CHANNEL("Chn", 3) }; /* IIO context attributes list */ static struct iio_context_attribute ad4110_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 }; /* Scale attribute value per channel */ float attr_scale_val[AD4110_NUM_CHANNELS]; /******************************************************************************/ /************************ Functions Definitions *******************************/ /******************************************************************************/ /*! * @brief Calculate the scale value * @param chan_id[in] - ADC input channel * @param adc_raw[in] - Raw ADC Data * @return 0 in case of success, negative error code otherwise. */ static int32_t ad4110_get_scale(uint8_t chan_id, int32_t adc_raw) { float temperature = 0; uint32_t cjc_raw_data; float cjc_temp; int32_t ret; #if (ACTIVE_DEMO_MODE_CONFIG == RTD_CONFIG) temperature = get_rtd_temperature(adc_raw); attr_scale_val[chan_id] = (temperature / adc_raw) * 1000.0; #elif (ACTIVE_DEMO_MODE_CONFIG == THERMOCOUPLE_CONFIG) /* Sample the CJC Channel. TC is already sampled through the get_adc_attribute() function */ if (chan_id != CJC_CHANNEL) { /* Disable the requested channel chan_id */ ret = ad4110_set_channel_status(ad4110_dev_inst, chan_id, false); if (ret) { return ret; } /* Enable the channel on which CJC has been incorporated */ ret = ad4110_set_channel_status(ad4110_dev_inst, CJC_CHANNEL, true); if (ret) { return ret; } /* Read the CJC raw data */ if (ad4110_do_single_read(ad4110_dev_inst, &cjc_raw_data)) { return ret; } /* Disable the CJC channel */ ret = ad4110_set_channel_status(ad4110_dev_inst, CJC_CHANNEL, false); if (ret) { return ret; } } else { /* For calculating CJC value, TC raw value does not matter */ chan_id = 0; cjc_raw_data = adc_raw; adc_raw = 0; } /* Calculate the TC and CJC temperature and update scale factor */ temperature = get_tc_temperature(adc_raw, HV_CHANNEL, cjc_raw_data, CJC_CHANNEL, &cjc_temp); attr_scale_val[chan_id] = (temperature / adc_raw) * 1000; attr_scale_val[CJC_CHANNEL] = (cjc_temp / cjc_raw_data) * 1000; #endif return 0; } /*! * @brief Getter/Setter function for ADC attributes * @param device[in]- Pointer to IIO device instance * @param buf[in]- IIO input data buffer * @param len[in]- Number of input bytes * @param channel[in] - ADC input channel * @param priv[in] - Attribute private ID * @return len in case of success, negative error code otherwise */ static int ad4110_get_attribute(void *device, char *buf, uint32_t len, const struct iio_ch_info *channel, intptr_t priv) { int ret; uint32_t raw_data_read = 0 ; int32_t offset = 0; uint8_t ch_id; float scale; switch (priv) { case RAW_ATTR_ID: /* Enable the requested channel, disable the rest */ for (ch_id = 0; ch_id < AD4110_NUM_CHANNELS; ch_id++) { if (ch_id == channel->ch_num) { ret = ad4110_set_channel_status(device, ch_id, true); } else { ret = ad4110_set_channel_status(device, ch_id, false); } if (ret) { return ret; } } /* Perform single conversion */ ret = ad4110_do_single_read(device, &raw_data_read); if (ret) { return ret; } /* Update scale factor depending on the channel requested */ ret = ad4110_get_scale(channel->ch_num, raw_data_read); if (ret) { return ret; } return sprintf(buf, "%d", raw_data_read); case SCALE_ATTR_ID: return sprintf(buf, "%g", attr_scale_val[channel->ch_num]); case OFFSET_ATTR_ID: #if (ACTIVE_DEMO_MODE_CONFIG == VOLTAGE_MODE_CONFIG ||\ ACTIVE_DEMO_MODE_CONFIG == CURRENT_MODE_CONFIG ||\ ACTIVE_DEMO_MODE_CONFIG == FIELD_POWER_SUPPLY_CONFIG) /* Offset values for other demo modes are incorporated as a part of the ad4110_get_scale() function */ if (ad4110_dev_inst->bipolar) { offset = -ADC_MAX_COUNT_BIPOLAR; } else { offset = 0; } #endif return sprintf(buf, "%ld", offset); case SAMPLING_FREQ_ATTR_ID: return sprintf(buf, "%d", AD4110_SAMPLING_RATE); case DEMO_CONFIG_ATTR_ID: #if (ACTIVE_DEMO_MODE_CONFIG == VOLTAGE_MODE_CONFIG) return sprintf(buf, "%s", "Voltage"); #elif (ACTIVE_DEMO_MODE_CONFIG == CURRENT_MODE_CONFIG) return sprintf(buf, "%s", "Current"); #elif (ACTIVE_DEMO_MODE_CONFIG == RTD_CONFIG) return sprintf(buf, "%s", "RTD"); #elif (ACTIVE_DEMO_MODE_CONFIG == FIELD_POWER_SUPPLY_CONFIG) return sprintf(buf, "%s", "Field Power Supply"); #elif (ACTIVE_DEMO_MODE_CONFIG == THERMOCOUPLE_CONFIG) return sprintf(buf, "%s", "Thermocouple"); #endif } return -EINVAL; } static int ad4110_set_attribute(void *device, char *buf, uint32_t len, const struct iio_ch_info *channel, intptr_t priv) { switch (priv) { case RAW_ATTR_ID: case SCALE_ATTR_ID: case SAMPLING_FREQ_ATTR_ID: case DEMO_CONFIG_ATTR_ID: default: break; } return len; } /** * @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_ad4110_pre_enable(void *dev_instance, uint32_t chn_mask) { return prepare_data_transfer(chn_mask, AD4110_NUM_CHANNELS, BYTES_PER_SAMPLE); } /** * @brief Read buffer data corresponding to AD4110 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_ad4110_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_ad4110_post_disable(void *dev) { return end_data_transfer(); } /*! * @brief Read the device register value * @param dev[in]- Pointer to IIO device instance * @param reg[in]- Register address to read from * @param readval[out]- Pointer to variable to read data into * @return 0 in case of success, negative error code otherwise */ static int32_t ad4110_read_register(void *dev, uint32_t reg, uint32_t *readval) { int ret; if (reg > REGISTER_MAX_VAL) { return -EINVAL; } ret = ad4110_spi_int_reg_read(dev, REGISTER_READ_SEL, reg, readval); if (ret < 0) { return ret; } return 0; } /*! * @brief Write into the device register * @param dev[in] - Pointer to IIO device instance * @param reg[in] - Register address to write into * @param writeval[in] - Register value to write * @return 0 in case of success, negative error code otherwise */ static int32_t ad4110_write_register(void *dev, uint32_t reg, uint32_t writeval) { int ret; if (reg > REGISTER_MAX_VAL) { return -EINVAL; } ret = ad4110_spi_int_reg_write(dev, REGISTER_READ_SEL, reg, writeval); if (ret < 0) { return ret; } return 0; } /** * @brief Init for reading/writing and parameterization of a AD4110-1 IIO device * @param desc[in,out] - IIO device descriptor * @return 0 in case of success, negative error code otherwise */ int32_t ad4110_iio_init(struct iio_device **desc) { struct iio_device *ad4110_iio_device; ad4110_iio_device = (struct iio_device *)calloc(1, sizeof(*ad4110_iio_device)); if (!ad4110_iio_device) { return -ENOMEM; } ad4110_iio_device->num_ch = NO_OS_ARRAY_SIZE(ad4110_iio_channels); ad4110_iio_device->channels = ad4110_iio_channels; ad4110_iio_device->attributes = ad4110_global_attributes; ad4110_iio_device->context_attributes = ad4110_iio_context_attributes; ad4110_iio_device->pre_enable = iio_ad4110_pre_enable; ad4110_iio_device->post_disable = iio_ad4110_post_disable; ad4110_iio_device->submit = iio_ad4110_submit_buffer; ad4110_iio_device->debug_reg_read = ad4110_read_register; ad4110_iio_device->debug_reg_write = ad4110_write_register; *desc = ad4110_iio_device; return 0; } /** * @brief Update channel attribute structure * @param dev[in] - AD4110 device descriptor * @return None */ static void update_channel_scan_parameters(struct ad4110_dev *dev) { uint8_t channel_id; if (dev->bipolar) { ad4110_scan_type.sign = 's'; ad4110_scan_type.realbits = CHN_STORAGE_BITS; /* Update scale value in case of voltage or current mode */ for (channel_id = 0; channel_id < AD4110_NUM_CHANNELS; channel_id++) { #if (ACTIVE_DEMO_MODE_CONFIG == VOLTAGE_MODE_CONFIG) attr_scale_val[channel_id] = AD4110_BIPOLAR_SCALE; #elif (ACTIVE_DEMO_MODE_CONFIG == CURRENT_MODE_CONFIG) ||\ (ACTIVE_DEMO_MODE_CONFIG == FIELD_POWER_SUPPLY_CONFIG) attr_scale_val[channel_id] = AD4110_BIPOLAR_SCALE/AD4110_R_SENSE; #endif } } else { ad4110_scan_type.sign = 'u'; ad4110_scan_type.realbits = AD4110_RESOLUTION; for (channel_id = 0; channel_id < AD4110_NUM_CHANNELS; channel_id++) { #if (ACTIVE_DEMO_MODE_CONFIG == VOLTAGE_MODE_CONFIG) attr_scale_val[channel_id] = AD4110_UNIPOLAR_SCALE; #elif (ACTIVE_DEMO_MODE_CONFIG == CURRENT_MODE_CONFIG) ||\ (ACTIVE_DEMO_MODE_CONFIG == FIELD_POWER_SUPPLY_CONFIG) attr_scale_val[channel_id] = AD4110_UNIPOLAR_SCALE / AD4110_R_SENSE; #endif } } } /** * @brief Initialize the AD4110-1 IIO application * @return 0 in case of success, negative error code otherwise */ int32_t ad4110_iio_initialize(void) { int32_t ret_status; /* IIO Device Descriptor */ struct iio_device *ad4110_iio_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 }; /* Initialize the system peripherals */ ret_status = init_system(); if (ret_status) { return ret_status; } /* Initialize the AD4110 Device */ ret_status = ad4110_setup(&ad4110_dev_inst, ad4110_init_params); if (ret_status) { return ret_status; } /* Update channel scan attribute parameters */ update_channel_scan_parameters(ad4110_dev_inst); /* Initialize the AD4110-1 IIO application interface */ ret_status = ad4110_iio_init(&ad4110_iio_dev); if (ret_status) { return ret_status; } /* Update iio interface and IIOD init params */ iio_init_params.uart_desc = uart_desc; iio_device_init_params.dev = ad4110_dev_inst; iio_device_init_params.dev_descriptor = ad4110_iio_dev; iio_init_params.devs = &iio_device_init_params; /* Initialize the IIO interface */ ret_status = iio_init(&ad4110_iio_desc, &iio_init_params); if (ret_status) { return ret_status; } return 0; } /** * @brief Run the AD4110-1 IIO event handler * @return None */ void ad4110_iio_event_handler(void) { (void)iio_step(ad4110_iio_desc); }