Mahesh Phalke / Mbed OS EVAL-AD7689

Dependencies:   sdp_k1_sdram

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ad7689_iio.c Source File

ad7689_iio.c

Go to the documentation of this file.
00001 /***************************************************************************//**
00002  *   @file    ad7689_iio.c
00003  *   @brief   Implementation of AD7689 IIO application interfaces
00004 ********************************************************************************
00005  * Copyright (c) 2021-22 Analog Devices, Inc.
00006  * All rights reserved.
00007  *
00008  * This software is proprietary to Analog Devices, Inc. and its licensors.
00009  * By using this software you agree to the terms of the associated
00010  * Analog Devices Software License Agreement.
00011 *******************************************************************************/
00012 
00013 /******************************************************************************/
00014 /***************************** Include Files **********************************/
00015 /******************************************************************************/
00016 
00017 #include <stdint.h>
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <errno.h>
00021 
00022 #include "ad7689_iio.h"
00023 #include "app_config.h"
00024 #include "ad7689_user_config.h"
00025 #include "ad7689_data_capture.h"
00026 #include "no_os_error.h"
00027 
00028 /******************************************************************************/
00029 /********************* Macros and Constants Definition ************************/
00030 /******************************************************************************/
00031 
00032 /* ADC Raw to Voltage conversion default scale factor for IIO client */
00033 #if defined(BIPOLAR)
00034 /* Device supports only pseudo-bipolar mode. INX- = Vref / 2 */
00035 #define ADC_DEFAULT_SCALE       (((ADC_DEFAULT_REF_VOLTAGE / 2) / ADC_MAX_COUNT_BIPOLAR) * 1000)
00036 #else
00037 #define ADC_DEFAULT_SCALE       ((ADC_DEFAULT_REF_VOLTAGE / ADC_MAX_COUNT_UNIPOLAR) * 1000)
00038 #endif
00039 
00040 /* The output of temperature sensor is always unipolar (streight-binary) */
00041 #define TEMPERATURE_SENSITIVITY     0.283   // 283mv
00042 #define ROOM_TEMPERATURE            25.0
00043 #define TEMPERATURE_CONV_SCALE      (ROOM_TEMPERATURE / TEMPERATURE_SENSITIVITY) * \
00044                                     ((ADC_DEFAULT_REF_VOLTAGE / ADC_MAX_COUNT_UNIPOLAR) * 1000)
00045 
00046 /* Bytes per sample. This count should divide the total 256 bytes into 'n' equivalent
00047  * ADC samples as IIO library requests only 256bytes of data at a time in a given
00048  * data read query.
00049  * For 1 to 8-bit ADC, bytes per sample = 1 (2^0)
00050  * For 9 to 16-bit ADC, bytes per sample = 2 (2^1)
00051  * For 17 to 32-bit ADC, bytes per sample = 4 (2^2)
00052  **/
00053 #define BYTES_PER_SAMPLE    sizeof(uint16_t)    // For ADC resolution of 16-bits
00054 
00055 /* Number of data storage bits (needed for IIO client to plot ADC data) */
00056 #define CHN_STORAGE_BITS    (BYTES_PER_SAMPLE * 8)
00057 
00058 /* Private IDs for IIO attributes */
00059 #define IIO_RAW_ATTR_ID         0
00060 #define IIO_SCALE_ATTR_ID       1
00061 #define IIO_OFFSET_ATTR_ID      2
00062 
00063 /******************************************************************************/
00064 /******************** Variables and User Defined Data Types *******************/
00065 /******************************************************************************/
00066 
00067 /* IIO interface descriptor */
00068 static struct iio_desc *p_ad7689_iio_desc;
00069 
00070 /* Device name */
00071 static const char dev_name[] = ACTIVE_DEVICE_NAME;
00072 
00073 /* Pointer to the struct representing the AD7689 IIO device */
00074 struct ad7689_dev *p_ad7689_dev_inst = NULL;
00075 
00076 /* Device attributes with default values */
00077 
00078 /* Scale attribute value per channel */
00079 static float attr_scale_val[ADC_CHN_COUNT] = {
00080     ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE,
00081 #if !defined(DEV_AD7682)
00082     ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE, ADC_DEFAULT_SCALE,
00083 #endif
00084     TEMPERATURE_CONV_SCALE
00085 };
00086 
00087 /* AD7689 current configuration */
00088 struct ad7689_config ad7689_current_config;
00089 
00090 /******************************************************************************/
00091 /************************** Functions Declarations ****************************/
00092 /******************************************************************************/
00093 
00094 /******************************************************************************/
00095 /************************ Functions Definitions *******************************/
00096 /******************************************************************************/
00097 
00098 /*!
00099  * @brief   Getter/Setter for the sampling frequency attribute value
00100  * @param   device- pointer to IIO device structure
00101  * @param   buf- pointer to buffer holding attribute value
00102  * @param   len- length of buffer string data
00103  * @param   channel- pointer to IIO channel structure
00104  * @param   id- Attribute ID (optional)
00105  * @return  Number of characters read/written
00106  * @Note    This attribute is used to define the timeout period in IIO
00107  *          client during data capture.
00108  *          Timeout = (number of requested samples * (1/sampling frequency)) + 1sec
00109  *          e.g. if sampling frequency = 60KSPS and requested samples = 400
00110  *          Timeout = (400 * (1/60000)) + 1 = 1.0067sec = ~1sec
00111  */
00112 static int get_sampling_frequency(void *device,
00113                   char *buf,
00114                   uint32_t len,
00115                   const struct iio_ch_info *channel,
00116                   intptr_t id)
00117 {
00118     return sprintf(buf, "%d", SAMPLING_RATE);
00119 }
00120 
00121 static int set_sampling_frequency(void *device,
00122                   char *buf,
00123                   uint32_t len,
00124                   const struct iio_ch_info *channel,
00125                   intptr_t id)
00126 {
00127     /* sampling frequency is read-only attribute */
00128     return len;
00129 }
00130 
00131 
00132 /*!
00133  * @brief   Getter/Setter for the raw, offset and scale attribute value
00134  * @param   device- pointer to IIO device structure
00135  * @param   buf- pointer to buffer holding attribute value
00136  * @param   len- length of buffer string data
00137  * @param   channel- pointer to IIO channel structure
00138  * @param   id- Attribute ID (optional)
00139  * @return  Number of characters read/written
00140  */
00141 static int get_adc_raw(void *device,
00142                char *buf,
00143                uint32_t len,
00144                const struct iio_ch_info *channel,
00145                intptr_t id)
00146 {
00147     static uint32_t adc_data_raw = 0;
00148     int32_t offset = 0;
00149     int32_t ret;
00150 
00151     switch (id) {
00152     case IIO_RAW_ATTR_ID:
00153         /* Capture the raw adc data */
00154         ret = read_single_sample((uint8_t)channel->ch_num, &adc_data_raw);
00155         if (ret) {
00156             return sprintf(buf, " %s", "Error");
00157         }
00158         return sprintf(buf, "%d", adc_data_raw);
00159 
00160     case IIO_SCALE_ATTR_ID:
00161         return sprintf(buf, "%g", attr_scale_val[channel->ch_num]);
00162 
00163     case IIO_OFFSET_ATTR_ID:
00164 #if defined(BIPOLAR)
00165         if (channel->ch_num == TEMPERATURE_CHN) {
00166             offset = 0;
00167         } else {
00168             if (adc_data_raw >= ADC_MAX_COUNT_BIPOLAR) {
00169                 offset = -ADC_MAX_COUNT_UNIPOLAR;
00170             } else {
00171                 offset = 0;
00172             }
00173         }
00174 #endif
00175         return sprintf(buf, "%d", offset);
00176 
00177     default:
00178         break;
00179     }
00180 
00181     return len;
00182 }
00183 
00184 static int set_adc_raw(void *device,
00185                char *buf,
00186                uint32_t len,
00187                const struct iio_ch_info *channel,
00188                intptr_t id)
00189 {
00190     /* ADC raw, offset and scale are read-only attributes */
00191     return len;
00192 }
00193 
00194 /**
00195  * @brief   Read buffer data corresponding to AD4170 IIO device
00196  * @param   iio_dev_data[in] - Pointer to IIO device data structure
00197  * @return  0 in case of success, negative error code otherwise
00198  */
00199 static int32_t iio_ad7689_submit_buffer(struct iio_device_data *iio_dev_data)
00200 {
00201     uint32_t ret;
00202 
00203     /* Read the samples counts equal to buffer size/block */
00204     ret = read_buffered_data(&iio_dev_data->buffer->buf->buff,
00205                  iio_dev_data->buffer->size);
00206 
00207     /* Increment the write spin count as buffer reads all 'n' samples
00208      * in one go which is also the size of buffer block for a given instance.
00209      * The read spin count is incremented from IIO library during buffer
00210      * write/offloading into transmit buffer */
00211     if (iio_dev_data->buffer->buf->write.spin_count >= UINT32_MAX) {
00212         iio_dev_data->buffer->buf->write.spin_count = 0;
00213     }
00214 
00215     iio_dev_data->buffer->buf->write.spin_count += 1;
00216 
00217     return ret;
00218 }
00219 
00220 /**
00221  * @brief   Transfer the device data into memory (optional)
00222  * @param   dev_instance[in] - IIO device instance
00223  * @param   ch_mask[in] - Channels select mask
00224  * @return  0 in case of success, negative error code otherwise
00225  */
00226 static int32_t iio_ad7689_prepare_transfer(void *dev_instance,
00227         uint32_t ch_mask)
00228 {
00229     return prepare_data_transfer(ch_mask, ADC_CHN_COUNT, BYTES_PER_SAMPLE);
00230 }
00231 
00232 /**
00233  * @brief   Perform tasks before end of current data transfer
00234  * @param   dev[in] - IIO device instance
00235  * @return  0 in case of success, negative error code otherwise
00236  */
00237 static int32_t iio_ad7689_end_transfer(void *dev)
00238 {
00239     return end_data_transfer();
00240 }
00241 
00242 /*********************************************************
00243  *               IIO Attributes and Structures
00244  ********************************************************/
00245 
00246 /* IIOD channels attributes list */
00247 struct iio_attribute channel_input_attributes[] = {
00248     {
00249         .name = "raw",
00250         .show = get_adc_raw,
00251         .store = set_adc_raw,
00252         .priv = IIO_RAW_ATTR_ID
00253     },
00254     {
00255         .name = "scale",
00256         .show = get_adc_raw,
00257         .store = set_adc_raw,
00258         .priv = IIO_SCALE_ATTR_ID
00259     },
00260     {
00261         .name = "offset",
00262         .show = get_adc_raw,
00263         .store = set_adc_raw,
00264         .priv = IIO_OFFSET_ATTR_ID
00265     },
00266 
00267     END_ATTRIBUTES_ARRAY
00268 };
00269 
00270 /* IIOD context attributes list */
00271 static struct iio_context_attribute iio_context_attributes[] = {
00272     {
00273         .name = "hw_mezzanine",
00274         .value = HW_MEZZANINE_NAME
00275     },
00276     {
00277         .name = "hw_carrier",
00278         .value = HW_CARRIER_NAME
00279     },
00280     {
00281         .name = "hw_name",
00282         .value = HW_NAME
00283     },
00284     END_ATTRIBUTES_ARRAY
00285 };
00286 
00287 /* IIOD device (global) attributes list */
00288 static struct iio_attribute global_attributes[] = {
00289     {
00290         .name = "sampling_frequency",
00291         .show = get_sampling_frequency,
00292         .store = set_sampling_frequency,
00293     },
00294 
00295     END_ATTRIBUTES_ARRAY
00296 };
00297 
00298 /* IIOD channels configurations */
00299 struct scan_type chn_scan = {
00300 #if defined(BIPOLAR)
00301     .sign = 's',
00302 #else
00303     .sign = 'u',
00304 #endif
00305     .realbits = CHN_STORAGE_BITS,
00306     .storagebits = CHN_STORAGE_BITS,
00307     .shift = 0,
00308     .is_big_endian = false
00309 };
00310 
00311 static struct iio_channel iio_ad7689_channels[] = {
00312     {
00313         .name = "voltage0",
00314         .ch_type = IIO_VOLTAGE,
00315         .channel = 0,
00316         .scan_index = 0,
00317         .scan_type = &chn_scan,
00318         .attributes = channel_input_attributes,
00319         .ch_out = false,
00320         .indexed = true,
00321     },
00322     {
00323         .name = "voltage1",
00324         .ch_type = IIO_VOLTAGE,
00325         .channel = 1,
00326         .scan_index = 1,
00327         .scan_type = &chn_scan,
00328         .attributes = channel_input_attributes,
00329         .ch_out = false,
00330         .indexed = true
00331     },
00332     {
00333         .name = "voltage2",
00334         .ch_type = IIO_VOLTAGE,
00335         .channel = 2,
00336         .scan_index = 2,
00337         .scan_type = &chn_scan,
00338         .attributes = channel_input_attributes,
00339         .ch_out = false,
00340         .indexed = true
00341     },
00342     {
00343         .name = "voltage3",
00344         .ch_type = IIO_VOLTAGE,
00345         .channel = 3,
00346         .scan_index = 3,
00347         .scan_type = &chn_scan,
00348         .attributes = channel_input_attributes,
00349         .ch_out = false,
00350         .indexed = true
00351     },
00352 #if !defined(DEV_AD7682)
00353     {
00354         .name = "voltage4",
00355         .ch_type = IIO_VOLTAGE,
00356         .channel = 4,
00357         .scan_index = 4,
00358         .scan_type = &chn_scan,
00359         .attributes = channel_input_attributes,
00360         .ch_out = false,
00361         .indexed = true
00362     },
00363     {
00364         .name = "voltage5",
00365         .ch_type = IIO_VOLTAGE,
00366         .channel = 5,
00367         .scan_index = 5,
00368         .scan_type = &chn_scan,
00369         .attributes = channel_input_attributes,
00370         .ch_out = false,
00371         .indexed = true
00372     },
00373     {
00374         .name = "voltage6",
00375         .ch_type = IIO_VOLTAGE,
00376         .channel = 6,
00377         .scan_index = 6,
00378         .scan_type = &chn_scan,
00379         .attributes = channel_input_attributes,
00380         .ch_out = false,
00381         .indexed = true
00382     },
00383     {
00384         .name = "voltage7",
00385         .ch_type = IIO_VOLTAGE,
00386         .channel = 7,
00387         .scan_index = 7,
00388         .scan_type = &chn_scan,
00389         .attributes = channel_input_attributes,
00390         .ch_out = false,
00391         .indexed = true
00392     },
00393 #endif
00394     {
00395         .name = "temperature",
00396         .ch_type = IIO_TEMP,
00397 #if !defined(DEV_AD7682)
00398         .channel = 8,
00399         .scan_index = 8,
00400 #else
00401         .channel = 4,
00402         .scan_index = 4,
00403 #endif
00404         .scan_type = &chn_scan,
00405         .attributes = channel_input_attributes,
00406         .ch_out = false,
00407         .indexed = true
00408     },
00409 };
00410 
00411 
00412 /**
00413  * @brief   Init for reading/writing and parameterization of a
00414  *          ad7689 IIO device
00415  * @param   desc[in,out] - IIO device descriptor
00416  * @return  0 in case of success, negative error code otherwise
00417  */
00418 static int32_t iio_ad7689_init(struct iio_device **desc)
00419 {
00420     struct iio_device *iio_ad7689_inst;
00421 
00422     iio_ad7689_inst = calloc(1, sizeof(struct iio_device));
00423     if (!iio_ad7689_inst) {
00424         return -EINVAL;
00425     }
00426 
00427     iio_ad7689_inst->num_ch = sizeof(iio_ad7689_channels) / sizeof(
00428                       iio_ad7689_channels[0]);
00429     iio_ad7689_inst->channels = iio_ad7689_channels;
00430     iio_ad7689_inst->attributes = global_attributes;
00431     iio_ad7689_inst->context_attributes = iio_context_attributes;
00432 
00433     iio_ad7689_inst->submit = iio_ad7689_submit_buffer;
00434     iio_ad7689_inst->pre_enable = iio_ad7689_prepare_transfer;
00435     iio_ad7689_inst->post_disable = iio_ad7689_end_transfer;
00436 
00437     iio_ad7689_inst->debug_reg_read = NULL;
00438     iio_ad7689_inst->debug_reg_write = NULL;
00439 
00440     *desc = iio_ad7689_inst;
00441 
00442     return 0;
00443 }
00444 
00445 /**
00446  * @brief   Initialize the IIO interface for AD7689 IIO device
00447  * @return  none
00448  * @return  0 in case of success, negative error code otherwise
00449  */
00450 int32_t ad7689_iio_initialize(void)
00451 {
00452     int32_t init_status;
00453 
00454     /* IIO device descriptor */
00455     struct iio_device *p_iio_ad7689_dev;
00456 
00457     /* IIO interface init parameters */
00458     struct iio_init_param iio_init_params = {
00459         .phy_type = USE_UART,
00460         .nb_devs = 1,
00461     };
00462 
00463     /* IIOD init parameters */
00464     struct iio_device_init iio_device_init_params = {
00465         .name = (char *)dev_name,
00466         .raw_buf = adc_data_buffer,
00467         .raw_buf_len = DATA_BUFFER_SIZE
00468     };
00469 
00470     /* Init the system peripherals */
00471     init_status = init_system();
00472     if (init_status) {
00473         return init_status;
00474     }
00475 
00476     /* Initialize AD7689 device and peripheral interface */
00477     init_status = ad7689_init(&p_ad7689_dev_inst, &ad7689_init_params);
00478     if (init_status) {
00479         return init_status;
00480     }
00481 
00482     /* Initialize the AD7689 IIO application interface */
00483     init_status = iio_ad7689_init(&p_iio_ad7689_dev);
00484     if (init_status) {
00485         return init_status;
00486     }
00487 
00488     /* Initialize the IIO interface */
00489     iio_init_params.uart_desc = uart_desc;
00490     iio_device_init_params.dev = p_ad7689_dev_inst;
00491     iio_device_init_params.dev_descriptor = p_iio_ad7689_dev;
00492     iio_init_params.devs = &iio_device_init_params;
00493     init_status = iio_init(&p_ad7689_iio_desc, &iio_init_params);
00494     if (init_status) {
00495         return init_status;
00496     }
00497 
00498     /* Load the init config into current configuration */
00499     memcpy(&ad7689_current_config, &ad7689_init_params.config,
00500            sizeof(ad7689_current_config));
00501 
00502     return 0;
00503 }
00504 
00505 /**
00506  * @brief   Run the AD7689 IIO event handler
00507  * @return  none
00508  * @details This function monitors the new IIO client event
00509  */
00510 void ad7689_iio_event_handler(void)
00511 {
00512     (void)iio_step(p_ad7689_iio_desc);
00513 }