Class for using AD7730 chip
AD7730.cpp
- Committer:
- cfscontrols2
- Date:
- 2011-12-16
- Revision:
- 0:c584a588c24f
File content as of revision 0:c584a588c24f:
#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); }