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);
}