A collection of Analog Devices drivers for the mbed platform

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AD7790.cpp Source File

AD7790.cpp

Go to the documentation of this file.
00001 /**
00002 *   @file     AD7790.cpp
00003 *   @brief    Source file for AD7790 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/ad7790
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 "AD7790.h"
00051 
00052 /**
00053  * @brief AD7790 constructor, sets CS pin and SPI format
00054  * @param CS - (optional)chip select of the AD7790
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 AD7790::AD7790(float reference_voltage,
00060                PinName CS,
00061                PinName MOSI,
00062                PinName MISO,
00063                PinName SCK) :
00064     miso(MISO), ad7790(MOSI, MISO, SCK), cs(CS), _vref(reference_voltage), _PGA_gain(1)
00065 {
00066     cs = true; // cs is active low
00067     ad7790.format(8, _SPI_MODE);
00068     _continous_conversion = true;
00069     _channel = DIFFERENTIAL;
00070 }
00071 
00072 /**
00073  * @brief Set AD7790 SPI frequency
00074  * @param hz - SPI bus frequency in hz
00075  * @return none
00076  */
00077 void AD7790::frequency(int hz)
00078 {
00079     ad7790.frequency(hz);
00080 }
00081 
00082 /**
00083  * @brief Resets the AD7790
00084  * @return none
00085  */
00086 void AD7790::reset()
00087 {
00088     ad7790.format(8, _SPI_MODE);
00089     cs = false;
00090     wait_us(_DELAY_TIMING);
00091     ad7790.write(_RESET);
00092     ad7790.write(_RESET);
00093     ad7790.write(_RESET);
00094     ad7790.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 AD7790::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  * Reads the mode register and returns its value
00120  * @return value of the mode register
00121  */
00122 uint8_t AD7790::read_mode_reg()
00123 {
00124     return read_reg(MODE_REG);
00125 }
00126 
00127 /**
00128  * Writes the filter register
00129  * @param regValue value to be written.
00130  */
00131 void AD7790::write_filter_reg(uint8_t reg_val)
00132 {
00133     write_reg(FILTER_REG, reg_val);
00134 }
00135 
00136 /**
00137  * Reads the filter register and returns its value
00138  * @return the value of the filter register
00139  */
00140 uint8_t AD7790::read_filter_reg()
00141 {
00142     return read_reg(FILTER_REG);
00143 }
00144 
00145 /**
00146  * Reads the data register and returns its value
00147  * @return value of the data register
00148  */
00149 uint16_t AD7790::read_data_reg()
00150 {
00151     uint16_t data_result;
00152     ad7790.format(8, _SPI_MODE);
00153     cs = false;
00154     ad7790.write(_DATA_READ | (static_cast<uint8_t>(_channel)));
00155     data_result  = ((ad7790.write(_DUMMY_BYTE)) << 8);
00156     data_result |=  (ad7790.write(_DUMMY_BYTE));
00157     cs = true;
00158     return data_result;
00159 }
00160 
00161 /**
00162  * Reads the status register of the ADC and returns its value
00163  * @return value of the status reg
00164  */
00165 uint8_t AD7790::read_status_reg()
00166 {
00167     return read_reg(STATUS_REG);
00168 }
00169 
00170 
00171 /**
00172  * @brief Enables/disables continous_conversion mode
00173  * In Single Conversion mode, read_u16 method will read the MODE register of the ADC,
00174  * then write the Start single conversion bit and wait for the DOUT/RDY pin to go low,
00175  * When the pin is driven low, data register is read back from the ADC.
00176  *
00177  * In Continous conversion mode, read_u16 method will poll the DOUT/RDY pin, if it is low,
00178  * the data register is read back from the ADC.
00179  *
00180  * @param mode
00181  * true - continous conversion mode enabled
00182  * false - single conversion mode enabled
00183  */
00184 void AD7790::set_conversion_mode(AD7790Mode_t mode)
00185 {
00186     uint8_t mode_reg_val;
00187     mode_reg_val = read_mode_reg() & 0x3F;
00188     mode_reg_val = mode_reg_val | (static_cast<uint8_t>(mode));
00189     write_mode_reg(mode);
00190 }
00191 
00192 /**
00193  *  - From mbed AnalogIn API -
00194  * @brief Read the input voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
00195  * Depending on the conversion mode, this method will have different behavior. Conversion mode is set using
00196  * set_continous_conversion_mode(bool).
00197  *
00198  * In Single Conversion mode, read_u16 method will read the MODE register of the ADC,
00199  * then write the Start single conversion bit and wait for the DOUT/RDY pin to go low,
00200  * When the pin is driven low, data register is read back from the ADC.
00201  *
00202  * In Continous conversion mode, read_u16 method will poll the DOUT/RDY pin, if it is low,
00203  * the data register is read back from the ADC.
00204  *
00205  * @return 16-bit unsigned short representing the current input voltage, normalised to a 16-bit value
00206  * returns -1 (0xFFFF) along with a debug message if conversion failed.
00207  */
00208 uint16_t AD7790::read_u16(void)
00209 {
00210     uint16_t data_result = 0;
00211     ad7790.format(8, _SPI_MODE);
00212     cs = false;
00213     uint16_t timeout_cnt = 0;
00214     if(_continous_conversion == false) {
00215 
00216         uint8_t mode_reg = read_mode_reg();
00217         wait_us(_DELAY_TIMING);
00218 
00219         cs = false;
00220         mode_reg = (mode_reg & 0x3F) | MD1; // mask single conversion bits
00221         ad7790.write((MODE_REG << 4) | (static_cast<uint8_t>(_channel))); // start single conversion
00222         ad7790.write(mode_reg);
00223         timeout_cnt = _SINGLE_CONVERSION_TIMEOUT; // starts timeout
00224     } else {
00225         timeout_cnt = _CONTINOUS_CONVERSION_TIMEOUT; // starts timeout
00226     }
00227     wait_us(1);
00228 
00229     while(miso) { // wait for the MISO pin to go low.
00230         if(timeout_cnt) {
00231             timeout_cnt--;
00232         } else {
00233             cs = true;
00234 #ifdef AD7790_DEBUG_MODE
00235             printf("timeout occurred reading the AD7790. "); // error, MISO line didn't toggle
00236 #endif
00237             return -1; // ERROR
00238         }
00239         wait_us(10);
00240     }
00241 
00242     ad7790.write(_DATA_READ |  (static_cast<uint8_t>(_channel)));
00243     data_result  = ((ad7790.write(_DUMMY_BYTE)) << 8);
00244     data_result |=  (ad7790.write(_DUMMY_BYTE));
00245     cs = true;
00246     return data_result;
00247 }
00248 
00249 /**
00250  * @brief Reads a register of the AD7790
00251  * @param  address - address of the register
00252  * @return value of the register
00253  */
00254 uint16_t AD7790::read_reg(AD7790Register_t address)
00255 {
00256     uint16_t data = address << 12;
00257     data |= _DUMMY_BYTE;
00258     data |= _READ_FLAG;
00259     data |= (static_cast<uint8_t>(_channel) << 8);
00260     return  write_spi(data);
00261 }
00262 
00263 /**
00264  * @brief Writes a register of the AD7790
00265  * @param address - address of the register
00266  * @param reg_val - value to be written
00267  * @return none
00268  *
00269  */
00270 void AD7790::write_reg(AD7790Register_t address, uint8_t reg_val)
00271 {
00272     uint16_t spi_data = address << 12;
00273     spi_data |= reg_val;
00274     spi_data |= (static_cast<uint8_t>(_channel) << 8);
00275     write_spi(spi_data);
00276 }
00277 
00278 /**
00279  * @brief Writes 16bit data to the AD7790 SPI interface
00280  * @param reg_val to be written
00281  * @return data returned by the AD7790
00282  */
00283 uint16_t AD7790::write_spi(uint16_t reg_val)
00284 {
00285     uint16_t data_result;
00286     uint8_t upper_byte = (reg_val >> 8) & 0xFF;
00287     uint8_t lower_byte = reg_val & 0xFF;
00288     ad7790.format(8, _SPI_MODE);
00289     cs = false;
00290     data_result  =  (ad7790.write(upper_byte) << 8);
00291     data_result |=   ad7790.write(lower_byte);
00292     cs = true;
00293     return data_result;
00294 }
00295 
00296 
00297 /**
00298  * Sets the AnalogInputRange to be used by the AD7790
00299  * @param range AnalogInputRange_t to be used in voltage computations
00300  */
00301 void AD7790::set_range(AnalogInputRange_t range)
00302 {
00303 
00304     uint8_t mode_reg_val;
00305     mode_reg_val = read_mode_reg() & 0xCF;
00306     mode_reg_val = mode_reg_val | (range << 4);
00307     write_mode_reg(mode_reg_val);
00308 }
00309 
00310 /**
00311  * Sets the reference voltage of the AD7790
00312  * @param ref reference voltage to be set
00313  */
00314 void AD7790::set_reference_voltage(float ref)
00315 {
00316     _vref = ref;
00317 }
00318 
00319 /**
00320  * Gets the reference voltage of the AD7790
00321  * @return reference voltage
00322  */
00323 float AD7790::get_reference_voltage(void)
00324 {
00325     return _vref;
00326 }
00327 
00328 /**
00329  * Reads the data register of the ADC and converts the result to volts
00330  * Gain needs to be correctly set using set_gain in order to get accurate results
00331  * @return voltage of the ADC input
00332  */
00333 float AD7790::read_voltage(void)
00334 {
00335     return data_to_voltage(read_u16());
00336 }
00337 
00338 /**
00339  * Converts an uint16_t to voltage.
00340  * Gain needs to be correctly set using set_gain in order to get accurate results
00341  * @param data in uint16_t format
00342  * @return float value of voltage (in V)
00343  */
00344 float AD7790::data_to_voltage(uint16_t data)
00345 {
00346     return ((data / static_cast<float>(_RESOLUTION / 2)) - 1) * (_vref / _PGA_gain);
00347 }
00348 
00349 /**
00350  * Converts voltage to an uint16_t.
00351  * Gain needs to be correctly set using set_gain in order to get accurate results
00352  * @param voltage to be converted
00353  * @return data in uint16_t format
00354  */
00355 uint16_t AD7790::voltage_to_data(float voltage)
00356 {
00357     return (((voltage * _PGA_gain / _vref) + 1)   * static_cast<float>(_RESOLUTION / 2));
00358 }
00359 
00360 /**
00361  * Sets the conversion channel.
00362  * @param channel
00363  */
00364 void AD7790::set_channel(AD7790Channel_t channel)
00365 {
00366     _channel = channel;
00367 }
00368 
00369 /**
00370  *  - From mbed AnalogIn API -
00371  *  Read the input voltage, represented as a float in the range [0.0, 1.0] - uses the read_u16 method
00372  *  @returns A floating-point value representing the current input voltage, measured as a percentage
00373  *  returns 1.0 along with a debug message if the conversion failed
00374  */
00375 float AD7790::read(void)
00376 {
00377     float percent;
00378     uint16_t data;
00379     data = read_u16();
00380     percent = (data / static_cast<float>(_RESOLUTION) ); // translate bipolar conversion to [0.0, 1.0] domain
00381     return percent;
00382 }
00383 
00384 #ifdef MBED_OPERATORS
00385 
00386 /**
00387  *  - From mbed AnalogIn API -
00388  *  An operator shorthand for read()
00389  *  The float() operator can be used as a shorthand for read() to simplify common code sequences
00390  */
00391 AD7790::operator float()
00392 {
00393     return read();
00394 }
00395 
00396 #endif
00397 
00398 
00399