Class for using AD7730 chip
Revision 0:c584a588c24f, committed 2011-12-16
- 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