Analog Devices / Mbed OS EVAL-AD4696

Dependencies:   platform_drivers

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers iio_ad4696.c Source File

iio_ad4696.c

Go to the documentation of this file.
00001 /***************************************************************************//**
00002  *   @file    iio_ad4696.c
00003  *   @brief   Implementation of AD4696 IIO application interfaces
00004  *   @details This module acts as an interface for AD4696 IIO application
00005 ********************************************************************************
00006  * Copyright (c) 2021 Analog Devices, Inc.
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 <inttypes.h>
00018 #include <string.h>
00019 #include <math.h>
00020 
00021 #include "app_config.h"
00022 #include "tinyiiod.h"
00023 #include "iio_ad4696.h"
00024 #include "adc_data_capture.h"
00025 #include "ad4696_support.h"
00026 #include "ad4696_user_config.h"
00027 #include "error.h"
00028 
00029 /******************************************************************************/
00030 /************************ Macros/Constants ************************************/
00031 /******************************************************************************/
00032 
00033 /* ADC Raw to Voltage conversion default scale factor for IIO client */
00034 #if defined(PSEUDO_BIPOLAR_MODE)
00035 /* Device supports pseudo-bipolar mode only with INX- = Vref / 2 */
00036 #define DEFAULT_SCALE       (((DEFAULT_VREF  / 2) / ADC_MAX_COUNT_BIPOLAR) * 1000)
00037 #else
00038 #define DEFAULT_SCALE       ((DEFAULT_VREF / ADC_MAX_COUNT_UNIPOLAR) * 1000)
00039 #endif
00040 
00041 /* Bytes per sample. This count should divide the total 256 bytes into 'n' equivalent
00042  * ADC samples as IIO library requests only 256bytes of data at a time in a given
00043  * data read query.
00044  * For 1 to 8-bit ADC, bytes per sample = 1 (2^0)
00045  * For 9 to 16-bit ADC, bytes per sample = 2 (2^1)
00046  * For 17 to 32-bit ADC, bytes per sample = 4 (2^2)
00047  **/
00048 #define BYTES_PER_SAMPLE    sizeof(uint16_t)    // For ADC resolution of 16-bits
00049 
00050 /* Number of data storage bits (needed for IIO client to plot ADC data) */
00051 #define CHN_STORAGE_BITS    (BYTES_PER_SAMPLE * 8)
00052 
00053 /* Private IDs for IIO attributes */
00054 #define IIO_RAW_ATTR_ID         0
00055 #define IIO_SCALE_ATTR_ID       1
00056 #define IIO_OFFSET_ATTR_ID      2
00057 
00058 /******************************************************************************/
00059 /*************************** Types Declarations *******************************/
00060 /******************************************************************************/
00061 
00062 /* Pointer to the struct representing the AD4696 IIO device */
00063 struct ad469x_dev *p_ad4696_dev = NULL;
00064 
00065 /* IIO interface descriptor */
00066 static struct iio_desc *p_ad4696_iio_desc;
00067 
00068 /* Device name */
00069 static const char dev_name [] = ACTIVE_DEVICE_NAME;
00070 
00071 /* Scale value per channel */
00072 static float attr_scale_val[NO_OF_CHANNELS] = {
00073     DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
00074     DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
00075     DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE,
00076     DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE, DEFAULT_SCALE
00077 };
00078 
00079 /* Flag to trigger new data capture */
00080 static bool adc_data_capture_started = false;
00081 
00082 /******************************************************************************/
00083 /************************ Functions Definitions *******************************/
00084 /******************************************************************************/
00085 
00086 /*!
00087  * @brief   Getter/Setter for the raw, offset and scale attribute value
00088  * @param   device- pointer to IIO device structure
00089  * @param   buf- pointer to buffer holding attribute value
00090  * @param   len- length of buffer string data
00091  * @param   channel- pointer to IIO channel structure
00092  * @param   id- Attribute ID
00093  * @return  Number of characters read/written
00094  */
00095 static ssize_t get_adc_raw(void *device,
00096                     char *buf,
00097                     size_t len,
00098                     const struct iio_ch_info *channel,
00099                     intptr_t id)
00100 {
00101     static uint32_t adc_data_raw = 0;
00102     int32_t offset = 0;
00103 
00104     switch (id) {
00105     case IIO_RAW_ATTR_ID:
00106         /* Capture the raw adc data */
00107         if (read_single_sample((uint32_t)channel->ch_num, &adc_data_raw) != FAILURE) {
00108             return (ssize_t) sprintf(buf, "%d", adc_data_raw);
00109         }
00110         break;
00111         
00112     case IIO_SCALE_ATTR_ID:
00113         return (ssize_t) sprintf(buf, "%f", attr_scale_val[channel->ch_num]);
00114         break;
00115         
00116     case IIO_OFFSET_ATTR_ID:
00117 #if defined(PSEUDO_BIPOLAR_MODE)
00118         if (adc_data_raw >= ADC_MAX_COUNT_BIPOLAR) {
00119             offset = -ADC_MAX_COUNT_UNIPOLAR ;
00120         }
00121         else {
00122             offset = 0;
00123         }
00124 #endif
00125         return (ssize_t) sprintf(buf, "%d", offset);
00126         break;
00127             
00128     default:
00129         break;
00130     }
00131 
00132     return -EINVAL;
00133 }
00134 
00135 static ssize_t set_adc_raw(void *device,
00136                     char *buf,
00137                     size_t len,
00138                     const struct iio_ch_info *channel,
00139                     intptr_t id)
00140 {
00141     /* ADC raw value, offset factor and scale factor are fixed for given configurations set
00142      * in the firmware */
00143     return len;
00144 }
00145 
00146 /*!
00147  * @brief   Getter/Setter for the sampling frequency attribute value
00148  * @param   device- pointer to IIO device structure
00149  * @param   buf- pointer to buffer holding attribute value
00150  * @param   len- length of buffer string data
00151  * @param   channel- pointer to IIO channel structure
00152  * @return  Number of characters read/written
00153  * @Note    This attribute is used to define the timeout period in IIO
00154  *          client during data capture.
00155  *          Timeout = (number of requested samples * (1/sampling frequency)) + 1sec
00156  *          e.g. if sampling frequency = 50SPS and requested samples = 400
00157  *          Timeout = (400 * 0.02) + 1 = 9sec
00158  */
00159 ssize_t get_sampling_frequency(void *device,
00160                    char *buf,
00161                    size_t len,
00162                    const struct iio_ch_info *channel,
00163                    intptr_t id)
00164 {
00165     return (ssize_t) sprintf(buf, "%d", SAMPLING_RATE);
00166 }
00167 
00168 ssize_t set_sampling_frequency(void *device,
00169                    char *buf,
00170                    size_t len,
00171                    const struct iio_ch_info *channel,
00172                    intptr_t id)
00173 {
00174     /* Sampling frequency determines the IIO client timeout. It is defined in the
00175     * software and not allowed to change externally */
00176     return -EINVAL;
00177 }
00178 
00179 /*!
00180  * @brief   Read the debug register value
00181  * @param   dev- Pointer to IIO device instance
00182  * @param   reg- Register address to read from
00183  * @param   readval- Pointer to variable to read data into
00184  * @return  SUCCESS in case of success, negative value otherwise
00185  */
00186 int32_t debug_reg_read(void *dev, uint32_t reg, uint8_t *readval)
00187 {
00188     /* Read the data from device */
00189     if (reg <= NUM_OF_REGISTERS) {
00190         if (ad469x_spi_reg_read(dev, reg, readval) == SUCCESS) {
00191             return SUCCESS;
00192         }
00193     }
00194 
00195     return FAILURE;
00196 }
00197 
00198 /*!
00199  * @brief   Write into the debug register
00200  * @param   dev- Pointer to IIO device instance
00201  * @param   reg- Register address to write into
00202  * @param   writeval- Register value to write
00203  * @return  SUCCESS in case of success, negative value otherwise
00204  */
00205 int32_t debug_reg_write(void *dev, uint32_t reg, uint32_t writeval)
00206 {
00207     if (reg <= NUM_OF_REGISTERS) {
00208         if (ad469x_spi_reg_write(dev, reg, writeval) == SUCCESS) {
00209             return SUCCESS;
00210         }
00211     }
00212 
00213     return FAILURE;
00214 }
00215 
00216 /**
00217  * @brief   Read buffer data corresponding to AD4696 IIO device
00218  * @param   dev_instance[in] - IIO device instance
00219  * @param   pbuf[out] - Pointer to output data buffer
00220  * @param   offset[in] - Data buffer offset
00221  * @param   bytes_count[in] - Number of bytes to read
00222  * @param   ch_mask[in] - Channels select mask
00223  * @return  SUCCESS in case of success or negative value otherwise
00224  */
00225 static ssize_t iio_ad4696_read_data(void *dev_instance,
00226                     char *pbuf,
00227                     size_t offset,
00228                     size_t bytes_count,
00229                     uint32_t ch_mask)
00230 {
00231     if (adc_data_capture_started == false) {
00232         start_data_capture(ch_mask, AD469x_CHANNEL_NO);
00233         adc_data_capture_started = true;
00234     }
00235 
00236     /* Read the buffered data */
00237     return (ssize_t)read_buffered_data(pbuf, bytes_count, offset, ch_mask,
00238         BYTES_PER_SAMPLE);
00239 
00240 }
00241 
00242 /**
00243  * @brief   Transfer the device data into memory (optional)
00244  * @param   dev_instance[in] - IIO device instance
00245  * @param   bytes_count[in] - Number of bytes to read
00246  * @param   ch_mask[in] - Channels select mask
00247  * @return  SUCCESS in case of success or negative value otherwise
00248  */
00249 static ssize_t iio_ad4696_transfer_dev_data(void *dev_instance,
00250         size_t bytes_count, uint32_t ch_mask)
00251 {
00252     store_requested_samples_count(bytes_count, BYTES_PER_SAMPLE);
00253     return SUCCESS;
00254 }
00255 
00256 /**
00257  * @brief   Perform tasks before new data transfer
00258  * @param   dev_instance[in] - IIO device instance
00259  * @param   ch_mask[in] - Channels select mask
00260  * @return  SUCCESS in case of success or negative value otherwise
00261  */
00262 static int32_t iio_ad4696_start_transfer(void *dev_instance, uint32_t ch_mask)
00263 {
00264     return SUCCESS;
00265 }
00266 
00267 
00268 /**
00269  * @brief   Perform tasks before end of current data transfer
00270  * @param   dev_instance[in] - IIO device instance
00271  * @return  SUCCESS in case of success or negative value otherwise
00272  */
00273 static int32_t iio_ad4696_stop_transfer(void *dev)
00274 {
00275     adc_data_capture_started = false;
00276     stop_data_capture();
00277 
00278     return SUCCESS;
00279 }
00280 
00281 /*********************************************************
00282  *               IIO Attributes and Structures
00283  ********************************************************/
00284 
00285 /* IIOD channels attributes list */
00286 struct iio_attribute channel_input_attributes[] = {
00287     {
00288         .name = "raw",
00289         .show = get_adc_raw,
00290         .store = set_adc_raw,
00291         .priv = IIO_RAW_ATTR_ID
00292     },
00293     {
00294         .name = "scale",
00295         .show = get_adc_raw,
00296         .store = set_adc_raw,
00297         .priv = IIO_SCALE_ATTR_ID
00298     },
00299     {
00300         .name = "offset",
00301         .show = get_adc_raw,
00302         .store = set_adc_raw,
00303         .priv = IIO_OFFSET_ATTR_ID
00304     },
00305 
00306     END_ATTRIBUTES_ARRAY
00307 };
00308 
00309 /* IIOD device (global) attributes list */
00310 static struct iio_attribute global_attributes[] = {
00311     {
00312         .name = "sampling_frequency",
00313         .show = get_sampling_frequency,
00314         .store = set_sampling_frequency,
00315     },
00316 
00317     END_ATTRIBUTES_ARRAY
00318 };
00319 
00320 /* IIOD debug attributes list */
00321 static struct iio_attribute debug_attributes[] = {
00322     {
00323         .name = "direct_reg_access",
00324         .show = NULL,
00325         .store = NULL,
00326     },
00327 
00328     END_ATTRIBUTES_ARRAY
00329 };
00330 
00331 /* IIOD channels configurations */
00332 struct scan_type chn_scan = {
00333 #if defined(PSEUDO_BIPOLAR_MODE)
00334     .sign = 's',
00335 #else
00336     .sign = 'u',
00337 #endif
00338     .realbits = CHN_STORAGE_BITS,
00339     .storagebits = CHN_STORAGE_BITS,
00340     .shift = 0,
00341     .is_big_endian = false
00342 };
00343 static struct iio_channel iio_ad4696_channels[] = {
00344     {
00345         .name = "voltage0",
00346         .ch_type = IIO_VOLTAGE,
00347         .channel = 0,
00348         .scan_index = 0,
00349         .scan_type = &chn_scan,
00350         .attributes = channel_input_attributes,
00351         .ch_out = false,
00352         .indexed = true,
00353     },
00354     {
00355         .name = "voltage1",
00356         .ch_type = IIO_VOLTAGE,
00357         .channel = 1,
00358         .scan_index = 1,
00359         .scan_type = &chn_scan,
00360         .attributes = channel_input_attributes,
00361         .ch_out = false,
00362         .indexed = true
00363     },
00364     {
00365         .name = "voltage2",
00366         .ch_type = IIO_VOLTAGE,
00367         .channel = 2,
00368         .scan_index = 2,
00369         .scan_type = &chn_scan,
00370         .attributes = channel_input_attributes,
00371         .ch_out = false,
00372         .indexed = true
00373     },
00374     {
00375         .name = "voltage3",
00376         .ch_type = IIO_VOLTAGE,
00377         .channel = 3,
00378         .scan_index = 3,
00379         .scan_type = &chn_scan,
00380         .attributes = channel_input_attributes,
00381         .ch_out = false,
00382         .indexed = true
00383     },
00384     {
00385         .name = "voltage4",
00386         .ch_type = IIO_VOLTAGE,
00387         .channel = 4,
00388         .scan_index = 4,
00389         .scan_type = &chn_scan,
00390         .attributes = channel_input_attributes,
00391         .ch_out = false,
00392         .indexed = true
00393     },
00394     {
00395         .name = "voltage5",
00396         .ch_type = IIO_VOLTAGE,
00397         .channel = 5,
00398         .scan_index = 5,
00399         .scan_type = &chn_scan,
00400         .attributes = channel_input_attributes,
00401         .ch_out = false,
00402         .indexed = true
00403     },
00404     {
00405         .name = "voltage6",
00406         .ch_type = IIO_VOLTAGE,
00407         .channel = 6,
00408         .scan_index = 6,
00409         .scan_type = &chn_scan,
00410         .attributes = channel_input_attributes,
00411         .ch_out = false,
00412         .indexed = true
00413     },
00414     {
00415         .name = "voltage7",
00416         .ch_type = IIO_VOLTAGE,
00417         .channel = 7,
00418         .scan_index = 7,
00419         .scan_type = &chn_scan,
00420         .attributes = channel_input_attributes,
00421         .ch_out = false,
00422         .indexed = true
00423     },
00424     {
00425         .name = "voltage8",
00426         .ch_type = IIO_VOLTAGE,
00427         .channel = 8,
00428         .scan_index = 8,
00429         .scan_type = &chn_scan,
00430         .attributes = channel_input_attributes,
00431         .ch_out = false,
00432         .indexed = true,
00433     },
00434     {
00435         .name = "voltage9",
00436         .ch_type = IIO_VOLTAGE,
00437         .channel = 9,
00438         .scan_index = 9,
00439         .scan_type = &chn_scan,
00440         .attributes = channel_input_attributes,
00441         .ch_out = false,
00442         .indexed = true
00443     },
00444     {
00445         .name = "voltage10",
00446         .ch_type = IIO_VOLTAGE,
00447         .channel = 10,
00448         .scan_index = 10,
00449         .scan_type = &chn_scan,
00450         .attributes = channel_input_attributes,
00451         .ch_out = false,
00452         .indexed = true
00453     },
00454     {
00455         .name = "voltage11",
00456         .ch_type = IIO_VOLTAGE,
00457         .channel = 11,
00458         .scan_index = 11,
00459         .scan_type = &chn_scan,
00460         .attributes = channel_input_attributes,
00461         .ch_out = false,
00462         .indexed = true
00463     },
00464     {
00465         .name = "voltage12",
00466         .ch_type = IIO_VOLTAGE,
00467         .channel = 12,
00468         .scan_index = 12,
00469         .scan_type = &chn_scan,
00470         .attributes = channel_input_attributes,
00471         .ch_out = false,
00472         .indexed = true
00473     },
00474     {
00475         .name = "voltage13",
00476         .ch_type = IIO_VOLTAGE,
00477         .channel = 13,
00478         .scan_index = 13,
00479         .scan_type = &chn_scan,
00480         .attributes = channel_input_attributes,
00481         .ch_out = false,
00482         .indexed = true
00483     },
00484     {
00485         .name = "voltage14",
00486         .ch_type = IIO_VOLTAGE,
00487         .channel = 14,
00488         .scan_index = 14,
00489         .scan_type = &chn_scan,
00490         .attributes = channel_input_attributes,
00491         .ch_out = false,
00492         .indexed = true
00493     },
00494     {
00495         .name = "voltage15",
00496         .ch_type = IIO_VOLTAGE,
00497         .channel = 15,
00498         .scan_index = 15,
00499         .scan_type = &chn_scan,
00500         .attributes = channel_input_attributes,
00501         .ch_out = false,
00502         .indexed = true
00503     },
00504 };
00505 
00506 /**
00507  * @brief   Init for reading/writing and parameterization of a
00508  *          ad4696 IIO device
00509  * @param   desc[in,out] - IIO device descriptor
00510  * @return  SUCCESS in case of success, FAILURE otherwise
00511  */
00512 static int32_t iio_ad4696_init(struct iio_device **desc)
00513 {
00514     struct iio_device *iio_ad4696_inst;
00515 
00516     iio_ad4696_inst = calloc(1, sizeof(struct iio_device));
00517     if (!iio_ad4696_inst) {
00518         return FAILURE;
00519     }
00520 
00521     iio_ad4696_inst->num_ch = sizeof(iio_ad4696_channels) / sizeof(
00522                       iio_ad4696_channels[0]);
00523     iio_ad4696_inst->channels = iio_ad4696_channels;
00524     iio_ad4696_inst->attributes = global_attributes;
00525     iio_ad4696_inst->debug_attributes = debug_attributes;
00526 
00527     iio_ad4696_inst->transfer_dev_to_mem = iio_ad4696_transfer_dev_data;
00528     iio_ad4696_inst->transfer_mem_to_dev = NULL;
00529     iio_ad4696_inst->read_data = iio_ad4696_read_data;
00530     iio_ad4696_inst->write_data = NULL;
00531     iio_ad4696_inst->prepare_transfer = iio_ad4696_start_transfer;
00532     iio_ad4696_inst->end_transfer = iio_ad4696_stop_transfer;
00533     iio_ad4696_inst->debug_reg_read = debug_reg_read;
00534     iio_ad4696_inst->debug_reg_write = debug_reg_write;
00535 
00536     *desc = iio_ad4696_inst;
00537 
00538     return SUCCESS;
00539 }
00540 
00541 /**
00542  * @brief Release resources allocated for IIO device
00543  * @param desc[in] - IIO device descriptor
00544  * @return SUCCESS in case of success, FAILURE otherwise
00545  */
00546 static int32_t iio_ad4696_remove(struct iio_desc *desc)
00547 {
00548     int32_t status;
00549 
00550     if (!desc) {
00551         return FAILURE;
00552     }
00553 
00554     status = iio_unregister(desc, (char *)dev_name);
00555     if (status != SUCCESS) {
00556         return FAILURE;
00557     }
00558 
00559     return SUCCESS;
00560 }
00561 
00562 
00563 /**
00564  * @brief   Initialize the IIO interface for AD4696 IIO device
00565  * @return  SUCCESS in case of success, FAILURE otherwise
00566  */
00567 int32_t ad4696_iio_initialize(void)
00568 {
00569     int32_t init_status;
00570 
00571     /* IIO device descriptor */
00572     struct iio_device *p_iio_ad4696_dev;
00573 
00574     /* IIO interface init parameter */
00575     struct iio_init_param iio_init_params = {
00576         .phy_type = USE_UART,
00577         {
00578             &uart_init_params
00579         }
00580     };
00581 
00582     /* Initialize AD4696 device and peripheral interface */
00583     init_status = ad469x_init(&p_ad4696_dev, &ad4696_init_str);
00584     if (init_status != SUCCESS) {
00585         return init_status;
00586     }
00587 
00588     /* Initialize the IIO interface */
00589     init_status = iio_init(&p_ad4696_iio_desc, &iio_init_params);
00590     if (init_status != SUCCESS) {
00591         return init_status;
00592     }
00593 
00594     /* Register and initialize the AD4696 device into IIO interface */
00595     init_status = iio_ad4696_init(&p_iio_ad4696_dev);
00596     if (init_status != SUCCESS) {
00597         return init_status;
00598     }
00599 
00600     /* Register AD4696 IIO interface */
00601     init_status = iio_register(p_ad4696_iio_desc, p_iio_ad4696_dev,
00602                    (char *)dev_name, p_ad4696_dev, NULL,
00603                    NULL);
00604     if (init_status != SUCCESS) {
00605         return init_status;
00606     }
00607 
00608     /* Init the system peripherals */
00609     init_status = init_system();
00610     if (init_status != SUCCESS) {
00611         return init_status;
00612     }
00613 
00614     /* To enable manual trigger mode for operation */ 
00615     init_status = ad4696_enable_manual_trigger_mode(p_ad4696_dev);
00616     if (init_status != SUCCESS) {
00617         return init_status;
00618     }
00619     
00620     return SUCCESS;
00621 }
00622 
00623 /**
00624  * @brief   Run the AD4696 IIO event handler
00625  * @return  none
00626  * @details This function monitors the new IIO client event
00627  */
00628 void ad4696_iio_event_handler(void)
00629 {
00630     while(1) {
00631         (void)iio_step(p_ad4696_iio_desc);
00632     }
00633 }