Class for using AD7730 chip

Files at this revision

API Documentation at this revision

Comitter:
cfscontrols2
Date:
Fri Dec 16 20:31:01 2011 +0000
Commit message:

Changed in this revision

AD7730.cpp Show annotated file Show diff for this revision Revisions of this file
AD7730.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AD7730.cpp	Fri Dec 16 20:31:01 2011 +0000
@@ -0,0 +1,684 @@
+#include "AD7730.h"
+
+/************************************************************************************************************************/
+//default constructor requires pin names for spi and ready pin
+/************************************************************************************************************************/
+AD7730::AD7730(PinName mosi, PinName miso, PinName sclk, PinName ready, PinName cs) : _spi(mosi, miso, sclk), _cs(cs), _readyDig(ready), _LED3(LED3){
+    
+    _readyPin = ready;
+      
+    //setup default parameters for spi
+    _spi.format(8, 1);  //8bits with polarity 0 (clock idle low), phase 1 (write on falling edge, read on rising edge)
+    _spi.frequency(1000000); //2Mhz
+    
+    //set default setup
+    _minWeight = 1;
+    _maxWeight = 5;
+    _fullScaleWeight = 11.023; //5kgs
+    
+    //reset the device
+    reset(true);
+    
+    //get default registry values
+    _mode = readRegistry(MODE_REG);
+    _filter = readRegistry(FILTER_REG);
+    _dac = readRegistry(DAC_REG);
+    _offset = readRegistry(OFFSET_REG);
+    _gain = readRegistry(GAIN_REG);
+    
+    //set chip select high
+    _cs = 1; 
+    
+    //run internal calibration
+    internalFullCal();
+    internalZeroCal(); 
+    
+    //turn off LED3
+    _LED3 = false; 
+    
+
+    _continous = false;
+    _bufferCount = 0;
+    memset(_readBuffer, 0, 100);
+      
+}
+
+/************************************************************************************************************************/
+// default destructor
+/************************************************************************************************************************/
+AD7730::~AD7730(void){}
+
+
+
+
+/************************************************************************************************************************/
+//function to read the specified registry value
+/************************************************************************************************************************/
+int AD7730::readRegistry(int registry){
+
+    int readReg = 0;
+    int bytes = 0;
+    
+    switch(registry){
+    
+        case STATUS_REG: //status registry
+        {   
+            readReg = 0x10;
+            bytes = 1;
+            break;
+        }
+        case DATA_REG: //data registry
+        {
+            _LED3 = _readyDig ? true : false;
+            readReg = 0x11;
+            bytes = 3;
+            break;
+        }
+        case MODE_REG: //mode registry
+        {
+            readReg = 0x12;
+            bytes = 2;
+            break;
+        }
+        case FILTER_REG: //filter registry
+        {
+            readReg = 0x13;
+            bytes = 3;
+            break;
+        }
+        case DAC_REG: //dac registry
+        {
+            readReg = 0x14;
+            bytes = 1;
+            break;
+        }
+        case OFFSET_REG: //offset registry
+        {
+            readReg = 0x15;
+            bytes = 3;
+            break;
+        }
+        case GAIN_REG: //gain registry
+        {
+            readReg = 0x16;
+            bytes = 3;
+            break;
+        }
+        case TEST_REG: //test registry
+        {
+            readReg = 0x17;
+            bytes = 3;
+            break;
+        }
+        default: //default to status registry
+        {
+            readReg = 0x10;
+            bytes = 1;
+            break;
+        }
+    } // end of switch statement
+    
+    //send command to read the registry
+    _cs = 0; 
+    wait_us(5);
+    _spi.write(readReg);
+    
+    int value = 0;
+    //loop through bytes of returned data
+    for(int i=0; i<bytes; i++){
+        value = (value << 8) | _spi.write(EMPTY_SPI); //shift previous return value up by 8 bits to make room for new data
+    }
+    wait_us(5);
+    _cs = 1;
+    
+    return value;
+}
+
+/************************************************************************************************************************/
+//function to write to the specified registry
+/************************************************************************************************************************/
+int AD7730::writeRegistry(int registry, int value){
+
+    int writeReg = 0;
+    int bytes = 0;
+    
+    switch(registry){
+    
+        case MODE_REG: //mode registry
+        {
+            writeReg = 0x02;
+            bytes = 2;
+            _mode = value;
+            //check if continous converstion is being stopped or started
+            _continous = ((value & 0x2000) > 0)? true : false;
+            break;
+        }
+        case FILTER_REG: //filter registry
+        {
+            writeReg = 0x03;
+            bytes = 3;
+            _filter = value;
+            break;
+        }
+        case DAC_REG: //dac registry
+        {
+            writeReg = 0x04;
+            bytes = 1;
+            _dac = value;
+            break;
+        }
+        case OFFSET_REG: //offset registry
+        {
+            writeReg = 0x05;
+            bytes = 3;
+            _offset = value;
+            break;
+        }
+        case GAIN_REG: //gain registry
+        {
+            writeReg = 0x06;
+            bytes = 3;
+            _gain = value;
+            break;
+        }
+        default: //default to communications register
+        {
+            writeReg = 0x00;
+            bytes = 0;
+            break;
+        }
+    } // end of switch statement
+    
+    //send command to write to a the registry
+    _cs = 0;
+    wait_us(5);
+    _spi.write(writeReg);
+    
+    //send data
+    switch(bytes)
+    {
+        case 3:
+            _spi.write(((value >> 16) & 255));
+        case 2:
+            _spi.write(((value >> 8) & 255));
+        case 1:
+            _spi.write((value & 255));
+            break;
+        default:
+            break;
+    }
+    wait_us(5);
+    _cs = 1;
+    
+    return value;
+}
+
+
+/************************************************************************************************************************/
+//function to initiate an internal full-scale calibration
+/************************************************************************************************************************/
+int AD7730::internalFullCal(void){
+    
+    //reset execution timer
+    _exeTmr.reset();
+
+    //1011000100110000 (0xB130) Internal Full-Scale Calibration, unipolar, long data, low reference, 0-80mv, channel 0
+    writeRegistry(MODE_REG, 0xB130);
+    wait_us(1); //give time for ready line to go high
+    
+    //wait for ready pin to go low indicating calibration complete with timeout of 2000ms
+    int time = 0;
+    while(_readyDig && time < 2000){
+        wait_ms(2);
+        time += 2;
+    }
+    
+    //update execution time
+    _exeTime = _exeTmr.read_us();
+    
+    //check if timeout occurred
+    if(time >= 2000){
+        _exeError = 56;
+        return 1;
+    }
+    else {
+        _exeError = 0;
+        return 0;
+    } 
+}
+
+
+/************************************************************************************************************************/
+//function to initiate an internal zero-scale calibration
+/************************************************************************************************************************/
+int AD7730::internalZeroCal(void){
+    
+    //reset execution timer
+    _exeTmr.reset();
+
+    //1001000100110000 (0x9100) Internal Zero-Scale Calibration, unipolar, long data, low reference, 0-10mv, channel 0
+    writeRegistry(MODE_REG, 0x9100);
+    wait_us(1); //give time for ready line to go high
+    
+    //wait for ready pin to go low indicating calibration complete with timeout of 2000ms
+    int time = 0;
+    while(_readyDig && time < 2000){
+        wait_ms(2);
+        time += 2;
+    }
+    
+    //update execution time
+    _exeTime = _exeTmr.read_us();
+    
+    //check if timeout occurred
+    if(time >= 2000){
+        _exeError = 56;
+        return 1;
+    }
+    else {
+        _exeError = 0;
+        return 0;
+    } 
+}
+
+
+
+/************************************************************************************************************************/
+//function to initialize the chip settings to default values after power up and to run internal calibration
+/************************************************************************************************************************/
+int AD7730::initialize(void){
+
+    //reset device
+    reset(true); //initate a full reset
+    
+    systemLowCal(_minWeight);
+    
+    //set the Offset
+    writeRegistry(OFFSET_REG, _offset);
+    
+    //set the Gain
+    writeRegistry(GAIN_REG, _gain);
+    
+    //set the DAC
+    writeRegistry(DAC_REG, _dac); 
+    
+    return 0;   
+     
+}
+
+
+/************************************************************************************************************************/
+//function to initiate a system zero-scale calibration
+/************************************************************************************************************************/
+int AD7730::systemLowCal(double wgt){
+    
+    //set minimum weight for low calibration
+    _minWeight = wgt;
+    
+    
+    //1101000100000000 (0xD100) System Zero-Scale Calibration, unipolar, long data, low reference, 0-10mv, channel 0
+    int mode = 0xD100;
+    
+    writeRegistry(MODE_REG, mode);
+    
+    wait_us(1);  //give time for ready pin to go high
+    int time = 0;
+    while(_readyDig && time < 2000){
+        time += 2;
+        wait_ms(2);
+    }//wait for ready pin to go low     
+    
+    if(_readyDig){
+        //printf("External Zero Failed\r\n");
+    }
+    
+    return (time >= 2000) ? 1 : 0;
+    
+}
+
+
+/************************************************************************************************************************/
+//function to initiate a system high calibration
+/************************************************************************************************************************/
+int AD7730::systemHighCal(double max, double fullScale){
+    
+    //get the current offset value
+    int offset = readRegistry(OFFSET_REG);
+    int fullScaleAdjust = ((double)offset - 8388608) + 16777215;
+    fullScaleAdjust /= 2;
+    //double calFactor = fullScale / (fullScaleAdjust / 2); //dual load cells splits the weight in half
+    
+    //set maximum weight for high calibration
+    _maxWeight = max;
+    //calculate the expected value for the maximum weight based on the full scale of the load cell
+    double expected = ((fullScaleAdjust * max) / fullScale);
+    
+    //take some samples
+    double avg = 0;
+    double value = 0;
+    for(int i=0; i<20; i++){
+        value = (double)read();
+        avg += value;  
+    }
+    
+    avg = avg / 20;
+    
+    //get current gain setting
+    double gain = (double)readRegistry(GAIN_REG);
+    
+    //calculate new gain value
+    double adjustedGain = gain * (expected / avg);
+    
+    printf("Expected: %.3f\r\nActual: %.3f\r\n", expected, avg);
+    
+    int err = 0;
+    if(adjustedGain > 16777215){
+        //printf("Exceeded Maximum Gain Value\r\n");
+        err = 1;
+    }
+    
+    //update gain registry
+    writeRegistry(GAIN_REG, (int)adjustedGain);
+    
+    return err;
+}
+
+
+
+/************************************************************************************************************************/
+//function to initiate the conversion of a sample
+/************************************************************************************************************************/
+int AD7730::startConversion(bool wait){
+    
+    //set the mode to do a single conversion
+    //0101000100000000 (0x5000)  Single Conversion, unipolar, short data, low reference, 0-10mv, channel 0
+    int mode = 0x5100;
+
+    writeRegistry(MODE_REG, mode);
+    
+    if(wait){
+        //wait for conversion to complete
+         
+        wait_us(1); //give time for ready to go high*/
+    
+        int time = 0;
+        while(_readyDig && time < 2000000){
+            time += 2;
+            wait_us(2);
+        }//wait for ready pin to go low.*/
+        
+        if(time >= 2000000){
+            //printf("Convert Timeout\r\n");
+            _exeError = 56;
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+/************************************************************************************************************************/
+//function to do a single read with conversion
+/************************************************************************************************************************/
+int AD7730::read(){
+
+    if(_continous){
+        //chip is running in continous conversion mode
+        return _lastValue;
+    }
+    else {
+        //a new conversion must be started
+        startConversion(true);
+        return readRegistry(DATA_REG);
+    }              
+}
+
+
+/************************************************************************************************************************/
+//function to set the filter settings
+/************************************************************************************************************************/
+void AD7730::setFilter(int SF, bool chop, int filter2){
+    
+    SF = SF << 12; //slide SF settings up 12 bits
+    
+    switch(filter2){
+        case 2:
+            SF = SF | 512;  //turn on bit 10 for skip mode
+            break;
+        case 1:
+            SF = SF | 256; //turn on bit 09 for fast mode
+            break;
+        default:
+            break; //leave bits 9 & 10 off so secondary filter is fully enabled
+    }
+    
+    if(chop){
+        SF = SF | 16; //turn on bit 5 to enable chop mode
+    }
+    
+    writeRegistry(FILTER_REG,SF);
+    
+}
+
+/************************************************************************************************************************/
+//function to reset the chip
+/************************************************************************************************************************/
+void AD7730::reset(bool fullReset){
+    
+    _cs = 0;
+    wait_us(5);
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    wait_us(5);
+    _cs = 1;
+    
+    //if not a full reset, then reload registry settings
+    if(!fullReset){
+        writeRegistry(MODE_REG, _mode);
+        writeRegistry(FILTER_REG, _filter);
+        writeRegistry(DAC_REG, _dac);
+        writeRegistry(OFFSET_REG, _offset);
+        writeRegistry(GAIN_REG, _gain);
+    }
+    else {
+        //reinitiate internal calibration
+        internalFullCal();
+        wait_ms(100);
+        internalZeroCal();
+        wait_ms(100);
+    }
+}
+
+/************************************************************************************************************************/
+//function to adjust the DAC
+/************************************************************************************************************************/
+int AD7730::adjustDAC(int direction){
+
+    int DAC = readRegistry(DAC_REG);
+    int sign = DAC & 32; //get the sign bit
+    DAC &= 31; //remove sign bit 
+ 
+    
+    if(direction > 0){
+        //increment DAC
+        if((sign > 0) && (DAC == 1)){ //sign bit is set and DAC is already at 1 change to 0;
+            DAC = 0;
+            sign = 0;
+        }
+        else if((sign == 0) && (DAC >= 0)){  //sign bit is not set increment DAC
+            DAC++;
+        }
+        else if ((sign > 0) && (DAC > 0)){  //sign bit is set decrement DAC because it is negative
+            DAC--;
+        }
+        
+    }
+    
+   else if(direction < 0){
+        //decrement DAC
+        if((sign == 0) && (DAC == 0)){ //sign bit is not set and DAC is already at 0
+            DAC = 1;
+            sign = 1;
+        }
+        else if((sign == 0) && (DAC > 0)){  //sign bit is not set increment DAC
+            DAC--;
+        }
+        else if ((sign > 0) && (DAC >= 0)){  //sign bit is set decrement DAC because it is negative
+            DAC++;
+        }
+        
+    }    
+
+    else{
+        //no change in direction
+        //do nothing
+        return DAC;
+    }
+    
+    if(DAC > 31){
+        DAC = 31;  //limit DAC to maximum value of 31 (5 bits)
+    }
+    
+    if(sign > 0){
+        DAC |= 32; //set the sign bit of DAC
+    }
+    
+    //update DAC
+    writeRegistry(DAC_REG, DAC);
+    
+    return DAC;
+}
+
+/************************************************************************************************************************/
+//function to set the filtering SF setting
+/************************************************************************************************************************/
+void AD7730::setFilterSF(int sf){
+
+    //get current filter setting
+    int filter = readRegistry(FILTER_REG);
+    
+    //clear sf bits 
+    filter &= 0xFFF;
+    
+    //bitshift sf up by 12 bits
+    sf = sf << 12;
+    
+    //or sf bits with filter bits
+    filter = filter | sf;
+    
+    //apply new filter setting
+    writeRegistry(FILTER_REG, filter);
+}
+
+/************************************************************************************************************************/
+//function to set the filtering chop mode
+/************************************************************************************************************************/
+void AD7730::setFilterChop(int enabled){
+
+    //get current filter setting
+    int filter = readRegistry(FILTER_REG);
+    
+    //clear bit 5 
+    filter &= ~0x10;
+    
+    //apply chop setting
+    if(enabled)
+        filter |= 0x10;
+    
+    //apply new filter setting
+    writeRegistry(FILTER_REG, filter);
+}
+
+/************************************************************************************************************************/
+//function to set the mode of the second filter
+/************************************************************************************************************************/
+void AD7730::setFilterMode(int mode){
+
+    //get current filter setting
+    int filter = readRegistry(FILTER_REG);
+    
+    //clear bits 9 & 10 
+    filter &= ~0x300;
+    
+    //apply mode setting
+    if(mode == 1){
+        filter |= 0x100; //apply fast mode
+    }
+    else if(mode == 2){
+        filter |= 0x200; //apply skip mode
+    }
+    else {
+        //leave both bits unset
+    }
+    
+    
+    //apply new filter setting
+    writeRegistry(FILTER_REG, filter);
+}
+
+/************************************************************************************************************************/
+//function to set the chip to continous conversion
+/************************************************************************************************************************/
+void AD7730::start(void){
+    
+    writeRegistry(MODE_REG, 0x3100); //set to continous conversion mode
+    _interruptReady = new InterruptIn(_readyPin);
+    _tmr.start();
+    _frequency = 0;
+    _interruptReady->fall(this, &AD7730::interruptRead);  
+}
+
+/************************************************************************************************************************/
+//function to stop the chip running in continous conversion mode
+/************************************************************************************************************************/
+void AD7730::stop(void){
+    
+    writeRegistry(MODE_REG, 0x1100); //set to idle mode
+    
+    _interruptReady = NULL;
+  
+}
+
+/************************************************************************************************************************/
+//function to check if the ready digital line is low
+/************************************************************************************************************************/
+bool AD7730::isReady(void){
+     
+    //if digital line is high, return not ready  
+    return (_readyDig)? false : true;
+    
+}
+
+/************************************************************************************************************************/
+//function to read data on falling edge of ready pin when running in continous conversion mode
+/************************************************************************************************************************/
+void AD7730::interruptRead(void){
+
+    _continous = true; //set flag indicating that chip is running in continous mode
+    
+    _lastValue = readRegistry(DATA_REG);
+    
+    //store data in circular buffer
+    _readBuffer[_bufferCount] = _lastValue;
+    if(_bufferCount < 99){
+        _bufferCount++;
+    }
+    else {
+        _bufferCount = 0;
+    }
+    
+    //update conversion speed frequency
+    _frequency = _tmr.read_us();
+    _tmr.reset();
+}
+
+/************************************************************************************************************************/
+//function to return the hertz of the data conversion 
+/************************************************************************************************************************/
+double AD7730::getHz(void){
+
+    return (1000000 / (double)_frequency);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AD7730.h	Fri Dec 16 20:31:01 2011 +0000
@@ -0,0 +1,85 @@
+#ifndef AD7730_H
+#define AD7730_H
+
+#include "mbed.h"
+
+class AD7730{
+
+    public:
+        AD7730(PinName mosi, PinName miso, PinName sclk, PinName ready, PinName cs);
+        ~AD7730(void);
+        
+        int readRegistry(int registry);
+        int writeRegistry(int registry, int value);
+        int initialize(void);
+        int systemLowCal(double wgt);
+        int systemHighCal(double wgt, double fullScale);
+        int read();
+        int startConversion(bool wait); 
+        void setFilter(int SF, bool chop, int filter2);
+        void setFilterSF(int SF);
+        void setFilterMode(int mode);
+        void setFilterChop(int enabled);
+        void reset(bool fullReset);
+        int adjustDAC(int direction);
+        void start(void);
+        void stop(void);
+        bool isReady(void);
+        double getHz(void);
+
+    
+    private:
+    
+        SPI _spi;
+        DigitalOut _cs;
+        DigitalIn _readyDig;
+        DigitalOut _LED3;
+        InterruptIn *_interruptReady;
+        PinName  _readyPin;
+        double _fullScaleWeight;
+        double _minWeight;
+        double _maxWeight;
+        int _readBuffer[100];
+        int _bufferCount;
+        int _lastValue;
+        bool _continous;
+        int _frequency;
+        Timer _tmr;
+        
+        //Registry value constants
+        static const int STATUS_REG = 0;
+        static const int DATA_REG = 1;
+        static const int MODE_REG = 2;
+        static const int FILTER_REG = 3;
+        static const int DAC_REG = 4;
+        static const int OFFSET_REG = 5;
+        static const int GAIN_REG = 6;
+        static const int TEST_REG = 7;
+        
+        //define empty spi command
+        static const int EMPTY_SPI = 0xFF;
+        
+        //internal registries
+        int _mode;
+        int _filter;
+        int _dac;
+        int _offset;
+        int _gain;
+        
+        
+        //timing variables
+        Timer _exeTmr;
+        int _exeTime;
+        
+        //error variables
+        int _exeError;
+        
+        //private functions
+        int internalZeroCal(void);
+        int internalFullCal(void); 
+        void interruptRead(void);       
+        
+        
+};
+
+#endif