Mitchell Wright / AD7124_no_OS
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ad7124.cpp Source File

ad7124.cpp

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