Example program for EVAL-AD4130

Dependencies:   tempsensors sdp_k1_sdram

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ad4130_support.c Source File

ad4130_support.c

Go to the documentation of this file.
00001 /*************************************************************************//**
00002  *   @file   ad4130_support.c
00003  *   @brief  AD4130 device No-OS driver supports
00004 ******************************************************************************
00005 * Copyright (c) 2020, 2022 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 
00019 #include "app_config.h"
00020 #include "ad4130_support.h"
00021 #include "no_os_error.h"
00022 
00023 /******************************************************************************/
00024 /********************** Macros and Constants Definition ***********************/
00025 /******************************************************************************/
00026 
00027 /* AD4130 FIFO size and readback command size in bytes */
00028 #define AD4130_FIFO_MAX_SIZE        (256)
00029 #define AD4130_FIFO_READ_CMD_BYTES  (2)
00030 
00031 #define BYTE_SIZE                   (8)
00032 
00033 /* Timeout to monitor CON monitor GPIO. The timeout count is dependent upon the
00034  * MCU clock frequency. This timeout is tested for SDP-K1 Mbed controller platform */
00035 #define CONV_MON_GPIO_TIMEOUT   (10000)
00036 
00037 /* Select between GPIO Or STATUS register to monitor the end
00038  * of conversion in single conversion mode */
00039 //#define CONV_MON_USING_RDY_STATUS     // Uncomment to use STATUS reg
00040 
00041 /* FIFO busy time as per specifications (in usec)
00042  * Note : This time is stringent in FIFO readback.The minimum time period
00043  * as per specifications is 20usec
00044  */
00045 #define FIFO_BUSY_TIME      (20)
00046 
00047 /******************************************************************************/
00048 /********************** Variables and User Defined Data Types *****************/
00049 /******************************************************************************/
00050 
00051 /* AD4130 FIFO readback buffer.
00052  * Size for 24-bit ADC = (256 * 3) + 2 = 770 bytes
00053  * Size for 16-bit ADC = (256 * 2) + 2 = 514 bytes
00054  * */
00055 static uint8_t fifo_buf[(AD4130_FIFO_MAX_SIZE * (ADC_RESOLUTION / BYTE_SIZE)) +
00056                                           AD4130_FIFO_READ_CMD_BYTES];
00057 
00058 /******************************************************************************/
00059 /************************ Functions Definitions *******************************/
00060 /******************************************************************************/
00061 
00062 /*!
00063  * @brief   Get reference voltage based on the reference source
00064  * @param   dev[in] - Device instance
00065  * @param   chn[in] - ADC channel
00066  * @return  Reference voltage
00067  */
00068 float ad4130_get_reference_voltage(struct ad413x_dev *dev, uint8_t chn)
00069 {
00070     float ref_voltage;
00071     uint8_t preset = dev->ch[chn].preset;
00072     enum ad413x_ref_sel ref = dev->preset[preset].ref_sel;
00073     enum ad413x_int_ref int_ref = dev->int_ref;
00074 
00075     switch (ref) {
00076     case AD413X_REFIN1:
00077         ref_voltage = AD4130_REFIN1_VOLTAGE;
00078         break;
00079 
00080     case AD413X_REFIN2:
00081         ref_voltage = AD4130_REFIN2_VOLTAGE;
00082         break;
00083 
00084     case AD413X_AVDD_AVSS:
00085         ref_voltage = AD4130_AVDD_VOLTAGE;
00086         break;
00087 
00088     case AD413X_REFOUT_AVSS:
00089         if (int_ref == AD413X_INTREF_1_25V) {
00090             ref_voltage = AD4170_1_25V_INT_REF_VOLTAGE;
00091         } else {
00092             ref_voltage = AD4170_2_5V_INT_REF_VOLTAGE;
00093         }
00094         break;
00095 
00096     default:
00097         ref_voltage = AD4170_2_5V_INT_REF_VOLTAGE;
00098         break;
00099     }
00100 
00101     return ref_voltage;
00102 }
00103 
00104 /*!
00105  * @brief   Perform the sign conversion for handling negative voltages in
00106  *          bipolar mode
00107  * @param   dev[in] - Device instance
00108  * @param   adc_raw_data[in] - ADC raw value
00109  * @param   chn[in] - ADC Channel
00110  * @return  ADC data after signed conversion
00111  */
00112 int32_t perform_sign_conversion(struct ad413x_dev *dev, uint32_t adc_raw_data,
00113                 uint8_t chn)
00114 {
00115     int32_t adc_data;
00116     bool bipolar = dev->bipolar;
00117 
00118     /* Bipolar ADC Range:  (-FS) <-> 0 <-> (+FS) : 0 <-> 2^(ADC_RES-1)-1 <-> 2^(ADC_RES-1)
00119        Unipolar ADC Range: 0 <-> (+FS) : 0 <-> 2^ADC_RES
00120      **/
00121     if (bipolar) {
00122         /* Data output format is offset binary for bipolar mode */
00123         adc_data = adc_raw_data - ADC_MAX_COUNT_BIPOLAR;
00124     } else {
00125         /* Data output format is straight binary for unipolar mode */
00126         adc_data = adc_raw_data;
00127     }
00128 
00129     return adc_data;
00130 }
00131 
00132 /*!
00133  * @brief   Convert the ADC raw value into equivalent voltage
00134  * @param   dev[in] - Device instance
00135  * @param   adc_raw[in]- ADC raw data
00136  * @param   chn[in] - ADC channel
00137  * @return  ADC voltage value
00138  */
00139 float convert_adc_sample_into_voltage(void *dev, uint32_t adc_raw,
00140                       uint8_t chn)
00141 {
00142     enum ad413x_gain pga;
00143     float vref;
00144     int32_t adc_data;
00145     uint8_t preset = ((struct ad413x_dev *)dev)->ch[chn].preset;
00146     bool bipolar = ((struct ad413x_dev *)dev)->bipolar;
00147 
00148     pga = ((struct ad413x_dev *)dev)->preset[preset].gain;
00149     vref = ad4130_get_reference_voltage(dev, chn);
00150     adc_data = perform_sign_conversion(dev, adc_raw, chn);
00151 
00152     if (bipolar) {
00153         return (adc_data * (vref / (ADC_MAX_COUNT_BIPOLAR * (1 << pga))));
00154     } else {
00155         return (adc_data * (vref / (ADC_MAX_COUNT_UNIPOLAR * (1 << pga))));
00156     }
00157 }
00158 
00159 /*!
00160  * @brief   Convert the ADC raw value into equivalent RTD resistance
00161  * @param   dev[in] - Device instance
00162  * @param   adc_raw[in] - ADC raw sample
00163  * @param   rtd_ref[in] - RTD reference resistance in ohms
00164  * @param   chn[in] - ADC channel
00165  * @return  RTD resistance value
00166  * @note    RTD is biased with constant excitation current. Below formula
00167  *          is based on ratiometric measurement, where fixed value of RTD RREF
00168  *          (reference resistor) and gain is taken into account
00169  */
00170 float convert_adc_raw_into_rtd_resistance(void *dev, uint32_t adc_raw,
00171         float rtd_ref, uint8_t chn)
00172 {
00173     enum ad413x_gain pga;
00174     int32_t adc_data;
00175     uint8_t preset = ((struct ad413x_dev *)dev)->ch[chn].preset;
00176     bool bipolar = ((struct ad413x_dev *)dev)->bipolar;
00177 
00178     pga = ((struct ad413x_dev *)dev)->preset[preset].gain;
00179     adc_data = perform_sign_conversion(dev, adc_raw, chn);
00180 
00181     if (bipolar) {
00182         return (((float)adc_data * rtd_ref) / (ADC_MAX_COUNT_BIPOLAR * (1 << pga)));
00183     } else {
00184         return (((float)adc_data * rtd_ref) / (ADC_MAX_COUNT_UNIPOLAR * (1 << pga)));
00185     }
00186 }
00187 
00188 /*!
00189  * @brief   Function to monitor end of conversion and read
00190  *          conversion result
00191  * @param   dev[in] - Device instance
00192  * @param   raw_data[in, out]- ADC raw data
00193  * @return  0 in case of success, negative error code otherwise
00194  */
00195 int32_t ad413x_mon_conv_and_read_data(struct ad413x_dev *dev,
00196                       uint32_t *raw_data)
00197 {
00198     int32_t ret;
00199     uint8_t conv_mon = 0;
00200     uint32_t timeout = CONV_MON_GPIO_TIMEOUT;
00201 
00202     if (!dev || !raw_data) {
00203         return -EINVAL;
00204     }
00205 
00206     /* Wait for conversion */
00207 #if defined(CONV_MON_USING_RDY_STATUS)
00208     while (!conv_mon && timeout--) {
00209         /* Read the value of the Status Register */
00210         ret = ad413x_reg_read(dev, AD413X_REG_STATUS, raw_data);
00211         if (ret) {
00212             return ret;
00213         }
00214 
00215         /* Check the RDY bit in the Status Register */
00216         conv_mon = (*raw_data & AD413X_ADC_DATA_STATUS);
00217     }
00218 
00219     if (!timeout) {
00220         return -EIO;
00221     }
00222 
00223     /* Read the conversion result */
00224     ret = ad413x_reg_read(dev, AD413X_REG_DATA, raw_data);
00225     if (ret) {
00226         return ret;
00227     }
00228 #else
00229     conv_mon = NO_OS_GPIO_HIGH;
00230     while (conv_mon == NO_OS_GPIO_HIGH && timeout--) {
00231         ret = no_os_gpio_get_value(conv_mon_gpio_desc, &conv_mon);
00232         if (ret) {
00233             return ret;
00234         }
00235     }
00236 
00237     if (!timeout) {
00238         return -EIO;
00239     }
00240 
00241     /* Read the conversion result */
00242     ret = ad413x_reg_read(dev, AD413X_REG_DATA, raw_data);
00243     if (ret) {
00244         return ret;
00245     }
00246 
00247     conv_mon = NO_OS_GPIO_LOW;
00248     timeout = CONV_MON_GPIO_TIMEOUT;
00249     while (conv_mon == NO_OS_GPIO_LOW && timeout--) {
00250         ret = no_os_gpio_get_value(conv_mon_gpio_desc, &conv_mon);
00251         if (ret) {
00252             return ret;
00253         }
00254     }
00255 
00256     if (!timeout) {
00257         return -EIO;
00258     }
00259 #endif
00260 
00261     return 0;
00262 }
00263 
00264 /*!
00265  * @brief   Read the data from FIFO
00266  * @param   dev[in] - device instance
00267  * @param   data[in] - Buffer to store FIFO data
00268  * @param   adc_samples[in] - Number of ADC samples to read
00269  * @return  0 in case of success, negative error code otherwise
00270  * @note    This function doesn't consider the FIFO status and header information
00271  *          during data readback. It is assumed data user is intending to read
00272  *          only the data from FIFO.
00273  */
00274 int32_t ad4130_read_fifo(struct ad413x_dev *dev, uint32_t *data,
00275              uint32_t adc_samples)
00276 {
00277     int32_t ret;
00278     uint32_t loop_cntr;
00279     uint32_t buf_indx = 0;
00280     uint32_t bytes;
00281 
00282     if (!dev || !data) {
00283         return -EINVAL;
00284     }
00285 
00286     /* Watermark count of 0 implies full FIFO readback */
00287     if ((adc_samples == 0) || (adc_samples > AD4130_FIFO_MAX_SIZE)) {
00288         adc_samples = AD4130_FIFO_MAX_SIZE;
00289     }
00290 
00291     /* Delay b/w interrupt trigger and FIFO readback start */
00292     no_os_udelay(FIFO_BUSY_TIME);
00293 
00294     /* MOSI pin outputs 0x00 during FIFO data readback */
00295     memset(fifo_buf, 0, sizeof(fifo_buf));
00296 
00297     /* Enter into FIFO read mode by issuing dummy read command. Command consists of first byte as
00298      * address of FIFO data register and 2nd byte as number of samples to read from FIFO */
00299     fifo_buf[0] = AD413X_COMM_REG_RD | AD413X_ADDR(AD413X_REG_FIFO_DATA);
00300     fifo_buf[1] = adc_samples;
00301 
00302     /* Bytes to read = (samples * data size) + fifo data reg address + sample_cnt */
00303     bytes = (adc_samples * (ADC_RESOLUTION / BYTE_SIZE)) +
00304         AD4130_FIFO_READ_CMD_BYTES;
00305 
00306     /* Read all bytes over SPI */
00307     ret = no_os_spi_write_and_read(dev->spi_dev, fifo_buf, bytes);
00308     if (ret) {
00309         return ret;
00310     }
00311 
00312     /* Extract the data from buffer (data doesn't contain header/status info) */
00313     for (loop_cntr = AD4130_FIFO_READ_CMD_BYTES; loop_cntr < bytes;
00314          loop_cntr += (ADC_RESOLUTION / BYTE_SIZE)) {
00315 #if (ADC_RESOLUTION == 24)
00316         data[buf_indx++] = ((int32_t)fifo_buf[loop_cntr] << 16) |
00317                    ((int32_t)fifo_buf[loop_cntr + 1] << 8) |
00318                    (int32_t)fifo_buf[loop_cntr + 2];
00319 #else
00320         /* For 16-bit resolution */
00321         data[buf_indx++] = ((int32_t)fifo_buf[loop_cntr] << 8) |
00322                    (int32_t)fifo_buf[loop_cntr + 1];
00323 #endif
00324     }
00325 
00326     return 0;
00327 }
00328 
00329 /*!
00330  * @brief   Set interrupt conversion source (GPIO)
00331  * @param   dev[in] - Device instance
00332  * @param   conv_int_source[in]- Interrupt source
00333  * @return  0 in case of success, negative error code otherwise
00334  */
00335 int32_t ad413x_set_int_source(struct ad413x_dev *dev,
00336                   adc_conv_int_source_e conv_int_source)
00337 {
00338     int32_t ret;
00339 
00340     if (!dev) {
00341         return -EINVAL;
00342     }
00343 
00344     ret = ad413x_reg_write_msk(dev,
00345                    AD413X_REG_IO_CTRL,
00346                    AD413X_INT_PIN_SEL(conv_int_source),
00347                    AD4130_INT_SRC_SEL_MSK);
00348     if (ret) {
00349         return ret;
00350     }
00351 
00352     return 0;
00353 }
00354 
00355 /*!
00356  * @brief   Set filter FS value
00357  * @param   dev[in] - Device instance
00358  * @param   fs[in]- FS value
00359  * @param   preset[in] - Channel setup
00360  * @return  0 in case of success, negative error code otherwise
00361  */
00362 int32_t ad413x_set_filter_fs(struct ad413x_dev *dev, uint32_t fs,
00363                  uint8_t preset)
00364 {
00365     int32_t ret;
00366 
00367     if (!dev) {
00368         return -EINVAL;
00369     }
00370 
00371     ret = ad413x_reg_write_msk(dev,
00372                    AD413X_REG_FILTER(preset),
00373                    AD413X_FS_N(fs),
00374                    AD4130_FILTER_FS_MSK);
00375     if (ret) {
00376         return ret;
00377     }
00378 
00379     return 0;
00380 }