Analog Devices / AD7791

Dependents:   ad7791-helloworld CN0216

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AD7791.cpp Source File

AD7791.cpp

Go to the documentation of this file.
00001 /**
00002 *   @file     AD7791.cpp
00003 *   @brief    Source file for AD7791 ADC
00004 *   @author   Analog Devices Inc.
00005 *
00006 * For support please go to:
00007 * Github: https://github.com/analogdevicesinc/mbed-adi
00008 * Support: https://ez.analog.com/community/linux-device-drivers/microcontroller-no-os-drivers
00009 * Product: http://www.analog.com/ad7791
00010 * More: https://wiki.analog.com/resources/tools-software/mbed-drivers-all
00011 
00012 ********************************************************************************
00013 * Copyright 2016(c) Analog Devices, Inc.
00014 *
00015 * All rights reserved.
00016 *
00017 * Redistribution and use in source and binary forms, with or without
00018 * modification, are permitted provided that the following conditions are met:
00019 *  - Redistributions of source code must retain the above copyright
00020 *    notice, this list of conditions and the following disclaimer.
00021 *  - Redistributions in binary form must reproduce the above copyright
00022 *    notice, this list of conditions and the following disclaimer in
00023 *    the documentation and/or other materials provided with the
00024 *    distribution.
00025 *  - Neither the name of Analog Devices, Inc. nor the names of its
00026 *    contributors may be used to endorse or promote products derived
00027 *    from this software without specific prior written permission.
00028 *  - The use of this software may or may not infringe the patent rights
00029 *    of one or more patent holders.  This license does not release you
00030 *    from the requirement that you obtain separate licenses from these
00031 *    patent holders to use this software.
00032 *  - Use of the software either in source or binary form, must be run
00033 *    on or directly connected to an Analog Devices Inc. component.
00034 *
00035 * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
00036 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
00037 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00038 * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
00039 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00040 * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
00041 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00042 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00043 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00044 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045 *
00046 ********************************************************************************/
00047 
00048 #include <stdint.h>
00049 #include "mbed.h"
00050 #include "AD7791.h"
00051 
00052 /**
00053  * @brief AD7791 constructor, sets CS pin and SPI format
00054  * @param CS - (optional)chip select of the AD7791
00055  * @param MOSI - (optional)pin of the SPI interface
00056  * @param MISO - (optional)pin of the SPI interface
00057  * @param SCK  - (optional)pin of the SPI interface
00058  */
00059 AD7791::AD7791(float reference_voltage,
00060                PinName CS,
00061                PinName MOSI,
00062                PinName MISO,
00063                PinName SCK) :
00064     miso(MISO), ad7791(MOSI, MISO, SCK), cs(CS),  _vref(reference_voltage)
00065 {
00066     cs = true; // cs is active low
00067     ad7791.format(8, _SPI_MODE);
00068     _continous_conversion = true;
00069     _channel = DIFFERENTIAL;
00070 }
00071 
00072 /**
00073  * @brief Set AD7791 SPI frequency
00074  * @param hz - SPI bus frequency in hz
00075  * @return none
00076  */
00077 void AD7791::frequency(int hz)
00078 {
00079     ad7791.frequency(hz);
00080 }
00081 
00082 /**
00083  * @brief Resets the AD7791
00084  * @return none
00085  */
00086 void AD7791::reset()
00087 {
00088     ad7791.format(8, _SPI_MODE);
00089     cs = false;
00090     wait_us(_DELAY_TIMING);
00091     ad7791.write(_RESET);
00092     ad7791.write(_RESET);
00093     ad7791.write(_RESET);
00094     ad7791.write(_RESET);
00095     wait_us(_DELAY_TIMING);
00096     cs = true;
00097     _continous_conversion = true;
00098 }
00099 
00100 /**
00101  * Sets the mode register. Also sets continous mode and range based on the value
00102  * written in reg_val
00103  * @param reg_val
00104  */
00105 void AD7791::write_mode_reg(uint8_t reg_val)
00106 {
00107     write_reg(MODE_REG, reg_val);
00108     uint8_t continous_mode = (reg_val & 0xC0);
00109     if(continous_mode == 0x00) {
00110         _continous_conversion = true;
00111     } else {
00112         _continous_conversion = false;
00113     }
00114     /*  uint8_t range = (reg_val & 0x30);
00115         _PGA_gain = 1 << (range >> 4);*/
00116 
00117 }
00118 
00119 /**
00120  * Reads the mode register and returns its value
00121  * @return value of the mode register
00122  */
00123 uint8_t AD7791::read_mode_reg()
00124 {
00125     return read_reg(MODE_REG);
00126 }
00127 
00128 /**
00129  * Writes the filter register
00130  * @param regValue value to be written.
00131  */
00132 void AD7791::write_filter_reg(uint8_t reg_val)
00133 {
00134     write_reg(FILTER_REG, reg_val);
00135 }
00136 
00137 /**
00138  * Reads the filter register and returns its value
00139  * @return the value of the filter register
00140  */
00141 uint8_t AD7791::read_filter_reg()
00142 {
00143     return read_reg(FILTER_REG);
00144 }
00145 
00146 /**
00147  * Reads the data register and returns its value
00148  * @return value of the data register
00149  */
00150 uint32_t AD7791::read_data_reg()
00151 {
00152     uint32_t data_result;
00153     ad7791.format(8, _SPI_MODE);
00154     cs = false;
00155     ad7791.write(_DATA_READ | (static_cast<uint8_t>(_channel)));
00156     data_result  = ((ad7791.write(_DUMMY_BYTE)) << 16);
00157     data_result |= ((ad7791.write(_DUMMY_BYTE)) << 8 );
00158     data_result |=  (ad7791.write(_DUMMY_BYTE));
00159     cs = true;
00160     return data_result;
00161 }
00162 
00163 /**
00164  * Reads the status register of the ADC and returns its value
00165  * @return value of the status reg
00166  */
00167 uint8_t AD7791::read_status_reg()
00168 {
00169     return read_reg(STATUS_REG);
00170 }
00171 
00172 
00173 /**
00174  * @brief Enables/disables continous_conversion mode
00175  * In Single Conversion mode, read_u16 method will read the MODE register of the ADC,
00176  * then write the Start single conversion bit and wait for the DOUT/RDY pin to go low,
00177  * When the pin is driven low, data register is read back from the ADC.
00178  *
00179  * In Continous conversion mode, read_u16 method will poll the DOUT/RDY pin, if it is low,
00180  * the data register is read back from the ADC.
00181  *
00182  * @param mode
00183  * true - continous conversion mode enabled
00184  * false - single conversion mode enabled
00185  */
00186 void AD7791::set_conversion_mode(AD7791Mode_t mode)
00187 {
00188     uint8_t mode_reg_val;
00189     mode_reg_val = read_mode_reg() & 0x3F;
00190     mode_reg_val = mode_reg_val | (static_cast<uint8_t>(mode));
00191     write_mode_reg(mode);
00192 }
00193 
00194 /**
00195  *  - From mbed AnalogIn API -
00196  * @brief Read the input voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
00197  * Depending on the conversion mode, this method will have different behavior. Conversion mode is set using
00198  * set_continous_conversion_mode(bool).
00199  *
00200  * In Single Conversion mode, read_u16 method will read the MODE register of the ADC,
00201  * then write the Start single conversion bit and wait for the DOUT/RDY pin to go low,
00202  * When the pin is driven low, data register is read back from the ADC.
00203  *
00204  * In Continous conversion mode, read_u16 method will poll the DOUT/RDY pin, if it is low,
00205  * the data register is read back from the ADC.
00206  *
00207  * @return 16-bit unsigned short representing the current input voltage, normalised to a 16-bit value
00208  * returns -1 (0xFFFF) along with a debug message if conversion failed.
00209  */
00210 uint32_t AD7791::read_u32(void)
00211 {
00212     uint32_t data_result = 0;
00213     ad7791.format(8, _SPI_MODE);
00214     cs = false;
00215     uint16_t timeout_cnt = 0;
00216     if(_continous_conversion == false) {
00217 
00218         uint8_t mode_reg = read_mode_reg();
00219         wait_us(_DELAY_TIMING);
00220 
00221         cs = false;
00222         mode_reg = (mode_reg & 0x3F) | MD1; // mask single conversion bits
00223         ad7791.write((MODE_REG << 4) | (static_cast<uint8_t>(_channel))); // start single conversion
00224         ad7791.write(mode_reg);
00225         timeout_cnt = _SINGLE_CONVERSION_TIMEOUT; // starts timeout
00226     } else {
00227         timeout_cnt = _CONTINOUS_CONVERSION_TIMEOUT; // starts timeout
00228     }
00229     wait_us(1);
00230 
00231     while(miso) { // wait for the MISO pin to go low.
00232         if(timeout_cnt) {
00233             timeout_cnt--;
00234         } else {
00235             cs = true;
00236 #ifdef AD7791_DEBUG_MODE
00237             printf("timeout occurred reading the AD7791. "); // error, MISO line didn't toggle
00238 #endif
00239             return -1; // ERROR
00240         }
00241         wait_us(10);
00242     }
00243 
00244     ad7791.write(_DATA_READ | (static_cast<uint8_t>(_channel)));
00245     data_result  = ((ad7791.write(_DUMMY_BYTE)) << 16);
00246     data_result |= ((ad7791.write(_DUMMY_BYTE)) << 8 );
00247     data_result |=  (ad7791.write(_DUMMY_BYTE));
00248     cs = true;
00249     return data_result;
00250 }
00251 
00252 uint16_t AD7791::read_u16(void)
00253 {
00254     uint32_t data = read_u32();
00255     return static_cast<uint16_t>((data & 0xffff00) >> 8);
00256 }
00257 
00258 /**
00259  * @brief Reads a register of the AD7791
00260  * @param  address - address of the register
00261  * @return value of the register
00262  */
00263 uint16_t AD7791::read_reg(AD7791Register_t address)
00264 {
00265     uint16_t data = address << 12;
00266     data |= _DUMMY_BYTE;
00267     data |= _READ_FLAG;
00268     data |= (static_cast<uint8_t>(_channel) << 8);
00269     return  write_spi(data);
00270 }
00271 
00272 /**
00273  * @brief Writes a register of the AD7791
00274  * @param address - address of the register
00275  * @param reg_val - value to be written
00276  * @return none
00277  *
00278  */
00279 void AD7791::write_reg(AD7791Register_t address, uint8_t reg_val)
00280 {
00281     uint16_t spi_data = address << 12;
00282     spi_data |= reg_val;
00283     spi_data |= (static_cast<uint8_t>(_channel) << 8);
00284     write_spi(spi_data);
00285 }
00286 
00287 /**
00288  * @brief Writes 16bit data to the AD7791 SPI interface
00289  * @param reg_val to be written
00290  * @return data returned by the AD7791
00291  */
00292 uint16_t AD7791::write_spi(uint16_t reg_val)
00293 {
00294     uint16_t data_result;
00295     uint8_t upper_byte = (reg_val >> 8) & 0xFF;
00296     uint8_t lower_byte = reg_val & 0xFF;
00297     ad7791.format(8, _SPI_MODE);
00298     cs = false;
00299     data_result  =  (ad7791.write(upper_byte) << 8);
00300     data_result |=   ad7791.write(lower_byte);
00301     cs = true;
00302     return data_result;
00303 }
00304 
00305 /**
00306  * Sets the reference voltage of the AD7790
00307  * @param ref reference voltage to be set
00308  */
00309 void AD7791::set_reference_voltage(float ref)
00310 {
00311     _vref = ref;
00312 }
00313 
00314 /**
00315  * Gets the reference voltage of the AD7790
00316  * @return reference voltage
00317  */
00318 float AD7791::get_reference_voltage(void)
00319 {
00320     return _vref;
00321 }
00322 
00323 /**
00324  * Reads the data register of the ADC and converts the result to volts
00325  * Gain needs to be correctly set using set_gain in order to get accurate results
00326  * @return voltage of the ADC input
00327  */
00328 float AD7791::read_voltage(void)
00329 {
00330     return data_to_voltage(read_u32());
00331 }
00332 
00333 /**
00334  * Converts an uint16_t to voltage.
00335  * Gain needs to be correctly set using set_gain in order to get accurate results
00336  * @param data in uint16_t format
00337  * @return float value of voltage (in V)
00338  */
00339 float AD7791::data_to_voltage(uint32_t data)
00340 {
00341     return ((data / static_cast<float>(_RESOLUTION / 2)) - 1) * (_vref );
00342 }
00343 
00344 /**
00345  * Converts voltage to an uint16_t.
00346  * Gain needs to be correctly set using set_gain in order to get accurate results
00347  * @param voltage to be converted
00348  * @return data in uint16_t format
00349  */
00350 uint32_t AD7791::voltage_to_data(float voltage)
00351 {
00352     return (((voltage / _vref) + 1)   * static_cast<float>(_RESOLUTION / 2));
00353 }
00354 
00355 /**
00356  * Sets the conversion channel.
00357  * @param channel
00358  */
00359 void AD7791::set_channel(AD7791Channel_t channel)
00360 {
00361     _channel = channel;
00362 }
00363 
00364 /**
00365  *  - From mbed AnalogIn API -
00366  *  Read the input voltage, represented as a float in the range [0.0, 1.0] - uses the read_u16 method
00367  *  @returns A floating-point value representing the current input voltage, measured as a percentage
00368  *  returns 1.0 along with a debug message if the conversion failed
00369  */
00370 float AD7791::read(void)
00371 {
00372     float percent;
00373     uint32_t data;
00374     data = read_u32();
00375     percent = (data / static_cast<float>(_RESOLUTION) ); // translate bipolar conversion to [0.0, 1.0] domain
00376     return percent;
00377 }
00378 
00379 #ifdef MBED_OPERATORS
00380 
00381 /**
00382  *  - From mbed AnalogIn API -
00383  *  An operator shorthand for read()
00384  *  The float() operator can be used as a shorthand for read() to simplify common code sequences
00385  */
00386 AD7791::operator float()
00387 {
00388     return read();
00389 }
00390 
00391 #endif
00392 
00393 
00394