Controls2 Developer / AD7730
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AD7730.cpp Source File

AD7730.cpp

00001 #include "AD7730.h"
00002 
00003 /************************************************************************************************************************/
00004 //default constructor requires pin names for spi and ready pin
00005 /************************************************************************************************************************/
00006 AD7730::AD7730(PinName mosi, PinName miso, PinName sclk, PinName ready, PinName cs) : _spi(mosi, miso, sclk), _cs(cs), _readyDig(ready), _LED3(LED3){
00007     
00008     _readyPin = ready;
00009       
00010     //setup default parameters for spi
00011     _spi.format(8, 1);  //8bits with polarity 0 (clock idle low), phase 1 (write on falling edge, read on rising edge)
00012     _spi.frequency(1000000); //2Mhz
00013     
00014     //set default setup
00015     _minWeight = 1;
00016     _maxWeight = 5;
00017     _fullScaleWeight = 11.023; //5kgs
00018     
00019     //reset the device
00020     reset(true);
00021     
00022     //get default registry values
00023     _mode = readRegistry(MODE_REG);
00024     _filter = readRegistry(FILTER_REG);
00025     _dac = readRegistry(DAC_REG);
00026     _offset = readRegistry(OFFSET_REG);
00027     _gain = readRegistry(GAIN_REG);
00028     
00029     //set chip select high
00030     _cs = 1; 
00031     
00032     //run internal calibration
00033     internalFullCal();
00034     internalZeroCal(); 
00035     
00036     //turn off LED3
00037     _LED3 = false; 
00038     
00039 
00040     _continous = false;
00041     _bufferCount = 0;
00042     memset(_readBuffer, 0, 100);
00043       
00044 }
00045 
00046 /************************************************************************************************************************/
00047 // default destructor
00048 /************************************************************************************************************************/
00049 AD7730::~AD7730(void){}
00050 
00051 
00052 
00053 
00054 /************************************************************************************************************************/
00055 //function to read the specified registry value
00056 /************************************************************************************************************************/
00057 int AD7730::readRegistry(int registry){
00058 
00059     int readReg = 0;
00060     int bytes = 0;
00061     
00062     switch(registry){
00063     
00064         case STATUS_REG: //status registry
00065         {   
00066             readReg = 0x10;
00067             bytes = 1;
00068             break;
00069         }
00070         case DATA_REG: //data registry
00071         {
00072             _LED3 = _readyDig ? true : false;
00073             readReg = 0x11;
00074             bytes = 3;
00075             break;
00076         }
00077         case MODE_REG: //mode registry
00078         {
00079             readReg = 0x12;
00080             bytes = 2;
00081             break;
00082         }
00083         case FILTER_REG: //filter registry
00084         {
00085             readReg = 0x13;
00086             bytes = 3;
00087             break;
00088         }
00089         case DAC_REG: //dac registry
00090         {
00091             readReg = 0x14;
00092             bytes = 1;
00093             break;
00094         }
00095         case OFFSET_REG: //offset registry
00096         {
00097             readReg = 0x15;
00098             bytes = 3;
00099             break;
00100         }
00101         case GAIN_REG: //gain registry
00102         {
00103             readReg = 0x16;
00104             bytes = 3;
00105             break;
00106         }
00107         case TEST_REG: //test registry
00108         {
00109             readReg = 0x17;
00110             bytes = 3;
00111             break;
00112         }
00113         default: //default to status registry
00114         {
00115             readReg = 0x10;
00116             bytes = 1;
00117             break;
00118         }
00119     } // end of switch statement
00120     
00121     //send command to read the registry
00122     _cs = 0; 
00123     wait_us(5);
00124     _spi.write(readReg);
00125     
00126     int value = 0;
00127     //loop through bytes of returned data
00128     for(int i=0; i<bytes; i++){
00129         value = (value << 8) | _spi.write(EMPTY_SPI); //shift previous return value up by 8 bits to make room for new data
00130     }
00131     wait_us(5);
00132     _cs = 1;
00133     
00134     return value;
00135 }
00136 
00137 /************************************************************************************************************************/
00138 //function to write to the specified registry
00139 /************************************************************************************************************************/
00140 int AD7730::writeRegistry(int registry, int value){
00141 
00142     int writeReg = 0;
00143     int bytes = 0;
00144     
00145     switch(registry){
00146     
00147         case MODE_REG: //mode registry
00148         {
00149             writeReg = 0x02;
00150             bytes = 2;
00151             _mode = value;
00152             //check if continous converstion is being stopped or started
00153             _continous = ((value & 0x2000) > 0)? true : false;
00154             break;
00155         }
00156         case FILTER_REG: //filter registry
00157         {
00158             writeReg = 0x03;
00159             bytes = 3;
00160             _filter = value;
00161             break;
00162         }
00163         case DAC_REG: //dac registry
00164         {
00165             writeReg = 0x04;
00166             bytes = 1;
00167             _dac = value;
00168             break;
00169         }
00170         case OFFSET_REG: //offset registry
00171         {
00172             writeReg = 0x05;
00173             bytes = 3;
00174             _offset = value;
00175             break;
00176         }
00177         case GAIN_REG: //gain registry
00178         {
00179             writeReg = 0x06;
00180             bytes = 3;
00181             _gain = value;
00182             break;
00183         }
00184         default: //default to communications register
00185         {
00186             writeReg = 0x00;
00187             bytes = 0;
00188             break;
00189         }
00190     } // end of switch statement
00191     
00192     //send command to write to a the registry
00193     _cs = 0;
00194     wait_us(5);
00195     _spi.write(writeReg);
00196     
00197     //send data
00198     switch(bytes)
00199     {
00200         case 3:
00201             _spi.write(((value >> 16) & 255));
00202         case 2:
00203             _spi.write(((value >> 8) & 255));
00204         case 1:
00205             _spi.write((value & 255));
00206             break;
00207         default:
00208             break;
00209     }
00210     wait_us(5);
00211     _cs = 1;
00212     
00213     return value;
00214 }
00215 
00216 
00217 /************************************************************************************************************************/
00218 //function to initiate an internal full-scale calibration
00219 /************************************************************************************************************************/
00220 int AD7730::internalFullCal(void){
00221     
00222     //reset execution timer
00223     _exeTmr.reset();
00224 
00225     //1011000100110000 (0xB130) Internal Full-Scale Calibration, unipolar, long data, low reference, 0-80mv, channel 0
00226     writeRegistry(MODE_REG, 0xB130);
00227     wait_us(1); //give time for ready line to go high
00228     
00229     //wait for ready pin to go low indicating calibration complete with timeout of 2000ms
00230     int time = 0;
00231     while(_readyDig && time < 2000){
00232         wait_ms(2);
00233         time += 2;
00234     }
00235     
00236     //update execution time
00237     _exeTime = _exeTmr.read_us();
00238     
00239     //check if timeout occurred
00240     if(time >= 2000){
00241         _exeError = 56;
00242         return 1;
00243     }
00244     else {
00245         _exeError = 0;
00246         return 0;
00247     } 
00248 }
00249 
00250 
00251 /************************************************************************************************************************/
00252 //function to initiate an internal zero-scale calibration
00253 /************************************************************************************************************************/
00254 int AD7730::internalZeroCal(void){
00255     
00256     //reset execution timer
00257     _exeTmr.reset();
00258 
00259     //1001000100110000 (0x9100) Internal Zero-Scale Calibration, unipolar, long data, low reference, 0-10mv, channel 0
00260     writeRegistry(MODE_REG, 0x9100);
00261     wait_us(1); //give time for ready line to go high
00262     
00263     //wait for ready pin to go low indicating calibration complete with timeout of 2000ms
00264     int time = 0;
00265     while(_readyDig && time < 2000){
00266         wait_ms(2);
00267         time += 2;
00268     }
00269     
00270     //update execution time
00271     _exeTime = _exeTmr.read_us();
00272     
00273     //check if timeout occurred
00274     if(time >= 2000){
00275         _exeError = 56;
00276         return 1;
00277     }
00278     else {
00279         _exeError = 0;
00280         return 0;
00281     } 
00282 }
00283 
00284 
00285 
00286 /************************************************************************************************************************/
00287 //function to initialize the chip settings to default values after power up and to run internal calibration
00288 /************************************************************************************************************************/
00289 int AD7730::initialize(void){
00290 
00291     //reset device
00292     reset(true); //initate a full reset
00293     
00294     systemLowCal(_minWeight);
00295     
00296     //set the Offset
00297     writeRegistry(OFFSET_REG, _offset);
00298     
00299     //set the Gain
00300     writeRegistry(GAIN_REG, _gain);
00301     
00302     //set the DAC
00303     writeRegistry(DAC_REG, _dac); 
00304     
00305     return 0;   
00306      
00307 }
00308 
00309 
00310 /************************************************************************************************************************/
00311 //function to initiate a system zero-scale calibration
00312 /************************************************************************************************************************/
00313 int AD7730::systemLowCal(double wgt){
00314     
00315     //set minimum weight for low calibration
00316     _minWeight = wgt;
00317     
00318     
00319     //1101000100000000 (0xD100) System Zero-Scale Calibration, unipolar, long data, low reference, 0-10mv, channel 0
00320     int mode = 0xD100;
00321     
00322     writeRegistry(MODE_REG, mode);
00323     
00324     wait_us(1);  //give time for ready pin to go high
00325     int time = 0;
00326     while(_readyDig && time < 2000){
00327         time += 2;
00328         wait_ms(2);
00329     }//wait for ready pin to go low     
00330     
00331     if(_readyDig){
00332         //printf("External Zero Failed\r\n");
00333     }
00334     
00335     return (time >= 2000) ? 1 : 0;
00336     
00337 }
00338 
00339 
00340 /************************************************************************************************************************/
00341 //function to initiate a system high calibration
00342 /************************************************************************************************************************/
00343 int AD7730::systemHighCal(double max, double fullScale){
00344     
00345     //get the current offset value
00346     int offset = readRegistry(OFFSET_REG);
00347     int fullScaleAdjust = ((double)offset - 8388608) + 16777215;
00348     fullScaleAdjust /= 2;
00349     //double calFactor = fullScale / (fullScaleAdjust / 2); //dual load cells splits the weight in half
00350     
00351     //set maximum weight for high calibration
00352     _maxWeight = max;
00353     //calculate the expected value for the maximum weight based on the full scale of the load cell
00354     double expected = ((fullScaleAdjust * max) / fullScale);
00355     
00356     //take some samples
00357     double avg = 0;
00358     double value = 0;
00359     for(int i=0; i<20; i++){
00360         value = (double)read();
00361         avg += value;  
00362     }
00363     
00364     avg = avg / 20;
00365     
00366     //get current gain setting
00367     double gain = (double)readRegistry(GAIN_REG);
00368     
00369     //calculate new gain value
00370     double adjustedGain = gain * (expected / avg);
00371     
00372     printf("Expected: %.3f\r\nActual: %.3f\r\n", expected, avg);
00373     
00374     int err = 0;
00375     if(adjustedGain > 16777215){
00376         //printf("Exceeded Maximum Gain Value\r\n");
00377         err = 1;
00378     }
00379     
00380     //update gain registry
00381     writeRegistry(GAIN_REG, (int)adjustedGain);
00382     
00383     return err;
00384 }
00385 
00386 
00387 
00388 /************************************************************************************************************************/
00389 //function to initiate the conversion of a sample
00390 /************************************************************************************************************************/
00391 int AD7730::startConversion(bool wait){
00392     
00393     //set the mode to do a single conversion
00394     //0101000100000000 (0x5000)  Single Conversion, unipolar, short data, low reference, 0-10mv, channel 0
00395     int mode = 0x5100;
00396 
00397     writeRegistry(MODE_REG, mode);
00398     
00399     if(wait){
00400         //wait for conversion to complete
00401          
00402         wait_us(1); //give time for ready to go high*/
00403     
00404         int time = 0;
00405         while(_readyDig && time < 2000000){
00406             time += 2;
00407             wait_us(2);
00408         }//wait for ready pin to go low.*/
00409         
00410         if(time >= 2000000){
00411             //printf("Convert Timeout\r\n");
00412             _exeError = 56;
00413             return 1;
00414         }
00415     }
00416     
00417     return 0;
00418 }
00419 
00420 /************************************************************************************************************************/
00421 //function to do a single read with conversion
00422 /************************************************************************************************************************/
00423 int AD7730::read(){
00424 
00425     if(_continous){
00426         //chip is running in continous conversion mode
00427         return _lastValue;
00428     }
00429     else {
00430         //a new conversion must be started
00431         startConversion(true);
00432         return readRegistry(DATA_REG);
00433     }              
00434 }
00435 
00436 
00437 /************************************************************************************************************************/
00438 //function to set the filter settings
00439 /************************************************************************************************************************/
00440 void AD7730::setFilter(int SF, bool chop, int filter2){
00441     
00442     SF = SF << 12; //slide SF settings up 12 bits
00443     
00444     switch(filter2){
00445         case 2:
00446             SF = SF | 512;  //turn on bit 10 for skip mode
00447             break;
00448         case 1:
00449             SF = SF | 256; //turn on bit 09 for fast mode
00450             break;
00451         default:
00452             break; //leave bits 9 & 10 off so secondary filter is fully enabled
00453     }
00454     
00455     if(chop){
00456         SF = SF | 16; //turn on bit 5 to enable chop mode
00457     }
00458     
00459     writeRegistry(FILTER_REG,SF);
00460     
00461 }
00462 
00463 /************************************************************************************************************************/
00464 //function to reset the chip
00465 /************************************************************************************************************************/
00466 void AD7730::reset(bool fullReset){
00467     
00468     _cs = 0;
00469     wait_us(5);
00470     _spi.write(0xFF);
00471     _spi.write(0xFF);
00472     _spi.write(0xFF);
00473     _spi.write(0xFF);
00474     _spi.write(0xFF);
00475     wait_us(5);
00476     _cs = 1;
00477     
00478     //if not a full reset, then reload registry settings
00479     if(!fullReset){
00480         writeRegistry(MODE_REG, _mode);
00481         writeRegistry(FILTER_REG, _filter);
00482         writeRegistry(DAC_REG, _dac);
00483         writeRegistry(OFFSET_REG, _offset);
00484         writeRegistry(GAIN_REG, _gain);
00485     }
00486     else {
00487         //reinitiate internal calibration
00488         internalFullCal();
00489         wait_ms(100);
00490         internalZeroCal();
00491         wait_ms(100);
00492     }
00493 }
00494 
00495 /************************************************************************************************************************/
00496 //function to adjust the DAC
00497 /************************************************************************************************************************/
00498 int AD7730::adjustDAC(int direction){
00499 
00500     int DAC = readRegistry(DAC_REG);
00501     int sign = DAC & 32; //get the sign bit
00502     DAC &= 31; //remove sign bit 
00503  
00504     
00505     if(direction > 0){
00506         //increment DAC
00507         if((sign > 0) && (DAC == 1)){ //sign bit is set and DAC is already at 1 change to 0;
00508             DAC = 0;
00509             sign = 0;
00510         }
00511         else if((sign == 0) && (DAC >= 0)){  //sign bit is not set increment DAC
00512             DAC++;
00513         }
00514         else if ((sign > 0) && (DAC > 0)){  //sign bit is set decrement DAC because it is negative
00515             DAC--;
00516         }
00517         
00518     }
00519     
00520    else if(direction < 0){
00521         //decrement DAC
00522         if((sign == 0) && (DAC == 0)){ //sign bit is not set and DAC is already at 0
00523             DAC = 1;
00524             sign = 1;
00525         }
00526         else if((sign == 0) && (DAC > 0)){  //sign bit is not set increment DAC
00527             DAC--;
00528         }
00529         else if ((sign > 0) && (DAC >= 0)){  //sign bit is set decrement DAC because it is negative
00530             DAC++;
00531         }
00532         
00533     }    
00534 
00535     else{
00536         //no change in direction
00537         //do nothing
00538         return DAC;
00539     }
00540     
00541     if(DAC > 31){
00542         DAC = 31;  //limit DAC to maximum value of 31 (5 bits)
00543     }
00544     
00545     if(sign > 0){
00546         DAC |= 32; //set the sign bit of DAC
00547     }
00548     
00549     //update DAC
00550     writeRegistry(DAC_REG, DAC);
00551     
00552     return DAC;
00553 }
00554 
00555 /************************************************************************************************************************/
00556 //function to set the filtering SF setting
00557 /************************************************************************************************************************/
00558 void AD7730::setFilterSF(int sf){
00559 
00560     //get current filter setting
00561     int filter = readRegistry(FILTER_REG);
00562     
00563     //clear sf bits 
00564     filter &= 0xFFF;
00565     
00566     //bitshift sf up by 12 bits
00567     sf = sf << 12;
00568     
00569     //or sf bits with filter bits
00570     filter = filter | sf;
00571     
00572     //apply new filter setting
00573     writeRegistry(FILTER_REG, filter);
00574 }
00575 
00576 /************************************************************************************************************************/
00577 //function to set the filtering chop mode
00578 /************************************************************************************************************************/
00579 void AD7730::setFilterChop(int enabled){
00580 
00581     //get current filter setting
00582     int filter = readRegistry(FILTER_REG);
00583     
00584     //clear bit 5 
00585     filter &= ~0x10;
00586     
00587     //apply chop setting
00588     if(enabled)
00589         filter |= 0x10;
00590     
00591     //apply new filter setting
00592     writeRegistry(FILTER_REG, filter);
00593 }
00594 
00595 /************************************************************************************************************************/
00596 //function to set the mode of the second filter
00597 /************************************************************************************************************************/
00598 void AD7730::setFilterMode(int mode){
00599 
00600     //get current filter setting
00601     int filter = readRegistry(FILTER_REG);
00602     
00603     //clear bits 9 & 10 
00604     filter &= ~0x300;
00605     
00606     //apply mode setting
00607     if(mode == 1){
00608         filter |= 0x100; //apply fast mode
00609     }
00610     else if(mode == 2){
00611         filter |= 0x200; //apply skip mode
00612     }
00613     else {
00614         //leave both bits unset
00615     }
00616     
00617     
00618     //apply new filter setting
00619     writeRegistry(FILTER_REG, filter);
00620 }
00621 
00622 /************************************************************************************************************************/
00623 //function to set the chip to continous conversion
00624 /************************************************************************************************************************/
00625 void AD7730::start(void){
00626     
00627     writeRegistry(MODE_REG, 0x3100); //set to continous conversion mode
00628     _interruptReady = new InterruptIn(_readyPin);
00629     _tmr.start();
00630     _frequency = 0;
00631     _interruptReady->fall(this, &AD7730::interruptRead);  
00632 }
00633 
00634 /************************************************************************************************************************/
00635 //function to stop the chip running in continous conversion mode
00636 /************************************************************************************************************************/
00637 void AD7730::stop(void){
00638     
00639     writeRegistry(MODE_REG, 0x1100); //set to idle mode
00640     
00641     _interruptReady = NULL;
00642   
00643 }
00644 
00645 /************************************************************************************************************************/
00646 //function to check if the ready digital line is low
00647 /************************************************************************************************************************/
00648 bool AD7730::isReady(void){
00649      
00650     //if digital line is high, return not ready  
00651     return (_readyDig)? false : true;
00652     
00653 }
00654 
00655 /************************************************************************************************************************/
00656 //function to read data on falling edge of ready pin when running in continous conversion mode
00657 /************************************************************************************************************************/
00658 void AD7730::interruptRead(void){
00659 
00660     _continous = true; //set flag indicating that chip is running in continous mode
00661     
00662     _lastValue = readRegistry(DATA_REG);
00663     
00664     //store data in circular buffer
00665     _readBuffer[_bufferCount] = _lastValue;
00666     if(_bufferCount < 99){
00667         _bufferCount++;
00668     }
00669     else {
00670         _bufferCount = 0;
00671     }
00672     
00673     //update conversion speed frequency
00674     _frequency = _tmr.read_us();
00675     _tmr.reset();
00676 }
00677 
00678 /************************************************************************************************************************/
00679 //function to return the hertz of the data conversion 
00680 /************************************************************************************************************************/
00681 double AD7730::getHz(void){
00682 
00683     return (1000000 / (double)_frequency);
00684 }