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
diff -r 000000000000 -r c584a588c24f AD7730.cpp
--- /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
diff -r 000000000000 -r c584a588c24f AD7730.h
--- /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