Mahesh Phalke / AD717x-AD411x
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ad717x.c Source File

ad717x.c

00001 /***************************************************************************//**
00002 *   @file    AD717X.c
00003 *   @brief   AD717X implementation file.
00004 *            Devices: AD7172-2, AD7172-4, AD7173-8, AD7175-2, AD7175-8, AD7176-2
00005 *            AD7177-2, AD4111, AD4112, AD4114, AD4115
00006 *   @author  acozma (andrei.cozma@analog.com)
00007 *            dnechita (dan.nechita@analog.com)
00008 *
00009 ********************************************************************************
00010 * Copyright 2015(c) Analog Devices, Inc.
00011 *
00012 * All rights reserved.
00013 *
00014 * Redistribution and use in source and binary forms, with or without modification,
00015 * are permitted provided that the following conditions are met:
00016 *  - Redistributions of source code must retain the above copyright
00017 *    notice, this list of conditions and the following disclaimer.
00018 *  - Redistributions in binary form must reproduce the above copyright
00019 *    notice, this list of conditions and the following disclaimer in
00020 *    the documentation and/or other materials provided with the
00021 *    distribution.
00022 *  - Neither the name of Analog Devices, Inc. nor the names of its
00023 *    contributors may be used to endorse or promote products derived
00024 *    from this software without specific prior written permission.
00025 *  - The use of this software may or may not infringe the patent rights
00026 *    of one or more patent holders.  This license does not release you
00027 *    from the requirement that you obtain separate licenses from these
00028 *    patent holders to use this software.
00029 *  - Use of the software either in source or binary form, must be run
00030 *    on or directly connected to an Analog Devices Inc. component.
00031 *
00032 * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
00033 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
00034 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00035 * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00036 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00037 * INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00038 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00039 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00040 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00041 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042 *******************************************************************************/
00043 
00044 /******************************************************************************/
00045 /***************************** Include Files **********************************/
00046 /******************************************************************************/
00047 #include <stdlib.h>
00048 #include "ad717x.h"
00049 
00050 /* Error codes */
00051 #define INVALID_VAL -1 /* Invalid argument */
00052 #define COMM_ERR    -2 /* Communication error on receive */
00053 #define TIMEOUT     -3 /* A timeout has occured */
00054 
00055 /***************************************************************************//**
00056 * @brief  Searches through the list of registers of the driver instance and
00057 *         retrieves a pointer to the register that matches the given address.
00058 *
00059 * @param device - The handler of the instance of the driver.
00060 * @param reg_address - The address to be used to find the register.
00061 *
00062 * @return A pointer to the register if found or 0.
00063 *******************************************************************************/
00064 ad717x_st_reg  *AD717X_GetReg(ad717x_dev *device,
00065                  uint8_t reg_address)
00066 {
00067     uint8_t i;
00068     ad717x_st_reg  *reg = 0;
00069 
00070     if (!device || !device->regs)
00071         return 0;
00072 
00073     for (i = 0; i < device->num_regs; i++) {
00074         if (device->regs[i].addr == reg_address) {
00075             reg = &device->regs[i];
00076             break;
00077         }
00078     }
00079 
00080     return reg;
00081 }
00082 
00083 /***************************************************************************//**
00084 * @brief Reads the value of the specified register.
00085 *
00086 * @param device - The handler of the instance of the driver.
00087 * @param addr - The address of the register to be read. The value will be stored
00088 *         inside the register structure that holds info about this register.
00089 *
00090 * @return Returns 0 for success or negative error code.
00091 *******************************************************************************/
00092 int32_t AD717X_ReadRegister(ad717x_dev *device,
00093                 uint8_t addr)
00094 {
00095     int32_t ret       = 0;
00096     uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
00097     uint8_t i         = 0;
00098     uint8_t check8    = 0;
00099     uint8_t msgBuf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
00100     ad717x_st_reg  *pReg;
00101 
00102     if(!device)
00103         return INVALID_VAL;
00104 
00105     pReg = AD717X_GetReg(device, addr);
00106     if (!pReg)
00107         return INVALID_VAL;
00108 
00109     /* Build the Command word */
00110     buffer[0] = AD717X_COMM_REG_WEN | AD717X_COMM_REG_RD |
00111             AD717X_COMM_REG_RA(pReg->addr);
00112 
00113     /* Read data from the device */
00114     ret = spi_write_and_read(device->spi_desc,
00115                  buffer,
00116                  ((device->useCRC != AD717X_DISABLE) ? pReg->size + 1
00117                   : pReg->size) + 1);
00118     if(ret < 0)
00119         return ret;
00120 
00121     /* Check the CRC */
00122     if(device->useCRC == AD717X_USE_CRC) {
00123         msgBuf[0] = AD717X_COMM_REG_WEN | AD717X_COMM_REG_RD |
00124                 AD717X_COMM_REG_RA(pReg->addr);
00125         for(i = 1; i < pReg->size + 2; ++i) {
00126             msgBuf[i] = buffer[i];
00127         }
00128         check8 = AD717X_ComputeCRC8(msgBuf, pReg->size + 2);
00129     }
00130     if(device->useCRC == AD717X_USE_XOR) {
00131         msgBuf[0] = AD717X_COMM_REG_WEN | AD717X_COMM_REG_RD |
00132                 AD717X_COMM_REG_RA(pReg->addr);
00133         for(i = 1; i < pReg->size + 2; ++i) {
00134             msgBuf[i] = buffer[i];
00135         }
00136         check8 = AD717X_ComputeXOR8(msgBuf, pReg->size + 2);
00137     }
00138 
00139     if(check8 != 0) {
00140         /* ReadRegister checksum failed. */
00141         return COMM_ERR;
00142     }
00143 
00144     /* Build the result */
00145     pReg->value = 0;
00146     for(i = 1; i < pReg->size + 1; i++) {
00147         pReg->value <<= 8;
00148         pReg->value += buffer[i];
00149     }
00150 
00151     return ret;
00152 }
00153 
00154 /***************************************************************************//**
00155 * @brief Writes the value of the specified register.
00156 *
00157 * @param device - The handler of the instance of the driver.
00158 * @param addr   - The address of the register to be written with the value stored
00159 *               inside the register structure that holds info about this
00160 *               register.
00161 *
00162 * @return Returns 0 for success or negative error code.
00163 *******************************************************************************/
00164 int32_t AD717X_WriteRegister(ad717x_dev *device,
00165                  uint8_t addr)
00166 {
00167     int32_t ret      = 0;
00168     int32_t regValue = 0;
00169     uint8_t wrBuf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
00170     uint8_t i        = 0;
00171     uint8_t crc8     = 0;
00172     ad717x_st_reg  *preg;
00173 
00174     if(!device)
00175         return INVALID_VAL;
00176 
00177     preg = AD717X_GetReg(device, addr);
00178     if (!preg)
00179         return INVALID_VAL;
00180 
00181     /* Build the Command word */
00182     wrBuf[0] = AD717X_COMM_REG_WEN | AD717X_COMM_REG_WR |
00183            AD717X_COMM_REG_RA(preg->addr);
00184 
00185     /* Fill the write buffer */
00186     regValue = preg->value;
00187     for(i = 0; i < preg->size; i++) {
00188         wrBuf[preg->size - i] = regValue & 0xFF;
00189         regValue >>= 8;
00190     }
00191 
00192     /* Compute the CRC */
00193     if(device->useCRC != AD717X_DISABLE) {
00194         crc8 = AD717X_ComputeCRC8(wrBuf, preg->size + 1);
00195         wrBuf[preg->size + 1] = crc8;
00196     }
00197 
00198     /* Write data to the device */
00199     ret = spi_write_and_read(device->spi_desc,
00200                  wrBuf,
00201                  (device->useCRC != AD717X_DISABLE) ?
00202                  preg->size + 2 : preg->size + 1);
00203 
00204     return ret;
00205 }
00206 
00207 /***************************************************************************//**
00208 * @brief Resets the device.
00209 *
00210 * @param device - The handler of the instance of the driver.
00211 *
00212 * @return Returns 0 for success or negative error code.
00213 *******************************************************************************/
00214 int32_t AD717X_Reset(ad717x_dev *device)
00215 {
00216     int32_t ret = 0;
00217     uint8_t wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
00218 
00219     if(!device)
00220         return INVALID_VAL;
00221 
00222     ret = spi_write_and_read(device->spi_desc,
00223                  wrBuf,
00224                  8);
00225 
00226     return ret;
00227 }
00228 
00229 /***************************************************************************//**
00230 * @brief Waits until a new conversion result is available.
00231 *
00232 * @param device  - The handler of the instance of the driver.
00233 * @param timeout - Count representing the number of polls to be done until the
00234 *                  function returns if no new data is available.
00235 *
00236 * @return Returns 0 for success or negative error code.
00237 *******************************************************************************/
00238 int32_t AD717X_WaitForReady(ad717x_dev *device,
00239                 uint32_t timeout)
00240 {
00241     ad717x_st_reg  *statusReg;
00242     int32_t ret;
00243     int8_t ready = 0;
00244 
00245     if(!device || !device->regs)
00246         return INVALID_VAL;
00247 
00248     statusReg = AD717X_GetReg(device, AD717X_STATUS_REG);
00249     if (!statusReg)
00250         return INVALID_VAL;
00251 
00252     while(!ready && --timeout) {
00253         /* Read the value of the Status Register */
00254         ret = AD717X_ReadRegister(device, AD717X_STATUS_REG);
00255         if(ret < 0)
00256             return ret;
00257 
00258         /* Check the RDY bit in the Status Register */
00259         ready = (statusReg->value & AD717X_STATUS_REG_RDY) == 0;
00260     }
00261 
00262     return timeout ? 0 : TIMEOUT;
00263 }
00264 
00265 /***************************************************************************//**
00266 * @brief Reads the conversion result from the device.
00267 *
00268 * @param device - The handler of the instance of the driver.
00269 * @param pData  - Pointer to store the read data.
00270 *
00271 * @return Returns 0 for success or negative error code.
00272 *******************************************************************************/
00273 int32_t AD717X_ReadData(ad717x_dev *device,
00274             int32_t* pData)
00275 {
00276     ad717x_st_reg  *dataReg;
00277     int32_t ret;
00278 
00279     if(!device || !device->regs)
00280         return INVALID_VAL;
00281 
00282     dataReg = AD717X_GetReg(device, AD717X_DATA_REG);
00283     if (!dataReg)
00284         return INVALID_VAL;
00285 
00286     /* Update the data register length with respect to device and options */
00287     ret = AD717X_ComputeDataregSize(device);
00288 
00289     /* Read the value of the Status Register */
00290     ret |= AD717X_ReadRegister(device, AD717X_DATA_REG);
00291 
00292     /* Get the read result */
00293     *pData = dataReg->value;
00294 
00295     return ret;
00296 }
00297 
00298 /***************************************************************************//**
00299 * @brief Computes data register read size to account for bit number and status
00300 *        read.
00301 *
00302 * @param device - The handler of the instance of the driver.
00303 *
00304 * @return 0in case of success or negative code in case of failure.
00305 *******************************************************************************/
00306 int32_t AD717X_ComputeDataregSize(ad717x_dev *device)
00307 {
00308     ad717x_st_reg  *reg_ptr;
00309     ad717x_st_reg  *datareg_ptr;
00310     uint16_t case_var;
00311 
00312     /* Get interface mode register pointer */
00313     reg_ptr = AD717X_GetReg(device, AD717X_IFMODE_REG);
00314     /* Get data register pointer */
00315     datareg_ptr = AD717X_GetReg(device, AD717X_DATA_REG);
00316     case_var = reg_ptr->value & (AD717X_IFMODE_REG_DATA_STAT |
00317                      AD717X_IFMODE_REG_DATA_WL16);
00318 
00319     /* Compute data register size */
00320     datareg_ptr->size = 3;
00321     if ((case_var & AD717X_IFMODE_REG_DATA_WL16) == AD717X_IFMODE_REG_DATA_WL16)
00322         datareg_ptr->size--;
00323     if ((case_var & AD717X_IFMODE_REG_DATA_STAT) == AD717X_IFMODE_REG_DATA_STAT)
00324         datareg_ptr->size++;
00325 
00326     /* Get ID register pointer */
00327     reg_ptr = AD717X_GetReg(device, AD717X_ID_REG);
00328 
00329     /* If the part is 32/24 bit wide add a byte to the read */
00330     if((reg_ptr->value & AD717X_ID_REG_MASK) == AD7177_2_ID_REG_VALUE)
00331         datareg_ptr->size++;
00332 
00333     return 0;
00334 }
00335 
00336 /***************************************************************************//**
00337 * @brief Computes the CRC checksum for a data buffer.
00338 *
00339 * @param pBuf    - Data buffer
00340 * @param bufSize - Data buffer size in bytes
00341 *
00342 * @return Returns the computed CRC checksum.
00343 *******************************************************************************/
00344 uint8_t AD717X_ComputeCRC8(uint8_t * pBuf,
00345                uint8_t bufSize)
00346 {
00347     uint8_t i   = 0;
00348     uint8_t crc = 0;
00349 
00350     while(bufSize) {
00351         for(i = 0x80; i != 0; i >>= 1) {
00352             if(((crc & 0x80) != 0) != ((*pBuf & i) !=
00353                            0)) { /* MSB of CRC register XOR input Bit from Data */
00354                 crc <<= 1;
00355                 crc ^= AD717X_CRC8_POLYNOMIAL_REPRESENTATION;
00356             } else {
00357                 crc <<= 1;
00358             }
00359         }
00360         pBuf++;
00361         bufSize--;
00362     }
00363     return crc;
00364 }
00365 
00366 /***************************************************************************//**
00367 * @brief Computes the XOR checksum for a data buffer.
00368 *
00369 * @param pBuf    - Data buffer
00370 * @param bufSize - Data buffer size in bytes
00371 *
00372 * @return Returns the computed XOR checksum.
00373 *******************************************************************************/
00374 uint8_t AD717X_ComputeXOR8(uint8_t * pBuf,
00375                uint8_t bufSize)
00376 {
00377     uint8_t xor = 0;
00378 
00379     while(bufSize) {
00380         xor ^= *pBuf;
00381         pBuf++;
00382         bufSize--;
00383     }
00384     return xor;
00385 }
00386 
00387 /***************************************************************************//**
00388 * @brief Updates the CRC settings.
00389 *
00390 * @param device - The handler of the instance of the driver.
00391 *
00392 * @return Returns 0 for success or negative error code.
00393 *******************************************************************************/
00394 int32_t AD717X_UpdateCRCSetting(ad717x_dev *device)
00395 {
00396     ad717x_st_reg  *interfaceReg;
00397 
00398     if(!device || !device->regs)
00399         return INVALID_VAL;
00400 
00401     interfaceReg = AD717X_GetReg(device, AD717X_IFMODE_REG);
00402     if (!interfaceReg)
00403         return INVALID_VAL;
00404 
00405     /* Get CRC State. */
00406     if(AD717X_IFMODE_REG_CRC_STAT(interfaceReg->value)) {
00407         device->useCRC = AD717X_USE_CRC;
00408     } else if(AD717X_IFMODE_REG_XOR_STAT(interfaceReg->value)) {
00409         device->useCRC = AD717X_USE_XOR;
00410     } else {
00411         device->useCRC = AD717X_DISABLE;
00412     }
00413 
00414     return 0;
00415 }
00416 
00417 /***************************************************************************//**
00418 * @brief Initializes the AD717X.
00419 *
00420 * @param device     - The device structure.
00421 * @param init_param - The structure that contains the device initial
00422 *              parameters.
00423 *
00424 * @return Returns 0 for success or negative error code.
00425 *******************************************************************************/
00426 int32_t AD717X_Init(ad717x_dev **device,
00427             ad717x_init_param init_param)
00428 {
00429     ad717x_dev *dev;
00430     int32_t ret;
00431     ad717x_st_reg  *preg;
00432 
00433     dev = (ad717x_dev *)malloc(sizeof(*dev));
00434     if (!dev)
00435         return -1;
00436 
00437     dev->regs = init_param.regs;
00438     dev->num_regs = init_param.num_regs;
00439 
00440     /* Initialize the SPI communication. */
00441     ret = spi_init(&dev->spi_desc, &init_param.spi_init);
00442     if (ret < 0)
00443         return ret;
00444 
00445     /*  Reset the device interface.*/
00446     ret = AD717X_Reset(dev);
00447     if (ret < 0)
00448         return ret;
00449 
00450     /* Initialize ADC mode register. */
00451     ret = AD717X_WriteRegister(dev, AD717X_ADCMODE_REG);
00452     if(ret < 0)
00453         return ret;
00454 
00455     /* Initialize Interface mode register. */
00456     ret = AD717X_WriteRegister(dev, AD717X_IFMODE_REG);
00457     if(ret < 0)
00458         return ret;
00459 
00460     /* Get CRC State */
00461     ret = AD717X_UpdateCRCSetting(dev);
00462     if(ret < 0)
00463         return ret;
00464 
00465     /* Initialize registers AD717X_GPIOCON_REG through AD717X_OFFSET0_REG */
00466     preg = AD717X_GetReg(dev, AD717X_GPIOCON_REG);
00467     if (!preg)
00468         return INVALID_VAL;
00469 
00470     while (preg && preg->addr != AD717X_OFFSET0_REG) {
00471         if (preg->addr == AD717X_ID_REG) {
00472             preg ++;
00473             continue;
00474         }
00475 
00476         ret = AD717X_WriteRegister(dev, preg->addr);
00477         if (ret < 0)
00478             break;
00479         preg ++;
00480     }
00481 
00482     /* Read ID register to identify the part */
00483     ret = AD717X_ReadRegister(dev, AD717X_ID_REG);
00484     if(ret < 0)
00485         return ret;
00486 
00487     *device = dev;
00488 
00489     return ret;
00490 }
00491 
00492 /***************************************************************************//**
00493  * @brief Free the resources allocated by AD717X_Init().
00494  * @param dev - The device structure.
00495  * @return SUCCESS in case of success, negative error code otherwise.
00496 *******************************************************************************/
00497 int32_t AD717X_remove(ad717x_dev *dev)
00498 {
00499     int32_t ret;
00500 
00501     ret = spi_remove(dev->spi_desc);
00502 
00503     free(dev);
00504 
00505     return ret;
00506 }