A collection of Analog Devices drivers for the mbed platform

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