ADC Read with Due and AD7683

Hey,

I am trying to read from an AD7683 it is a 16-bit adc from analog devices data sheet is found here http://www.analog.com/static/imported-files/data_sheets/AD7683.pdf

I am reading it with a Arduino Due using SPI protocol. I am pretty sure I am communicating with it just fine. The problem I am having is putting the 18 bits that I am reading into the proper order. I have tried flipping the bits and throwing away bits but it is not giving me the proper values.

I am using 3.3v to excite and I have a joystick(pot) going into the +IN and -IN is tied to ground. Proportionally I am getting the proper values but the bit values are either too high or too low.

Here is what comes out of my serial terminal.

// This is when the voltage across the pot is 3.3v
11 High
11111111 Mid
11111100 Low
111111111111111100
111111111111111100
	ADC Result = 262140
// This is when the voltage across the pot is 1.57
1 High
11101101 Mid
0 Low
1111011010
11110110100000000
	ADC Result = 126208

Here is the code I am running:

#include <SPI.h>

const int spiClockDivider = 42;
const int chipSelectPin = 4;

void setup()
{
  Serial.begin(19200);
  
  // start the SPI library:
  SPI.begin(4);
  
  // Set clock divider to 42
  SPI.setClockDivider(chipSelectPin, spiClockDivider);
}

void loop()
{ 
  //transfer 0x00 to the device on pin 4, store byte received in adcByteHigh, keep the chip selected
  byte adcByteHigh = SPI.transfer(4, 0x00, SPI_CONTINUE);
  //adcByteHigh &= 0b00000011;  // Tried excluding some bits but not sure which ones
  //transfer 0x00 to the device on pin 4, store byte received in adcByteMid, keep the chip selected
  byte adcByteMid = SPI.transfer(4, 0x00, SPI_CONTINUE);
  //transfer 0x00 to the device on pin 4, store byte received in adcByteLow, deselect the chip
  byte adcByteLow = SPI.transfer(4, 0x00);
  //adcByteHigh &= 0b11000000; // Tried excluding some bits but not sure which ones
  
  //combine the three parts into one 18-bit number:
  long ADCresult = ((adcByteHigh << 16) | (adcByteMid << 8) | adcByteLow );
  
  // display the ADC value:
  Serial.print(adcByteHigh, BIN);
  Serial.println(" High");
  Serial.print(adcByteMid, BIN);
  Serial.println(" Mid");
  Serial.print(adcByteLow, BIN);
  Serial.println(" Low");
  Serial.print(adcByteHigh, BIN);
  Serial.print(adcByteMid, BIN);
  Serial.println(adcByteLow, BIN);
  Serial.println(ADCresult, BIN);
  Serial.println("\tADC Result = " + String(ADCresult));
  delay(500);
}

Please help me combine the bits in the proper order Thanks.
-Ryman

Hey,

I think your results are only off by a factor of 4, so easy to fix :wink:

The way I understand the datasheet page 5 is that you do 3 times an 8 bit SPI transfer, like you do in your programm. Of the 24 bits you receive, the interesting ones are bits 7 to 22 (counting direction like in the datasheet assumed). So replacing the line in your code like this should do the job I guess:

long ADCresult = ((adcByteHigh << 14) | (adcByteMid << 6) | (adcByteLow>>2));

so you get rid of bits 23 and 24 on the right side using (adcByteLow>>2), and you fill accordingly up to bit 16. About the bits 1 to 6 you don't care as long as they are always zero.. did you verify this?
to be secure, you might add something like this before:

 adcByteHigh &= 0b00000011;

so you erase bits 1-6 and leave bits 7 and 8 unchanged of adcByteHigh

Let me know if it works! and thanks for posting the device name and datasheet link :wink:

Thank you schwingkopf,

That could not have been easier. I just changed that one line and then uncommented the other and it worked perfectly. Thank you very much. Now lets add 24 more of them...

-Ryman

I have another question about the same code except I added too it. I am trying to get a sense of the sampling rates that I can achieve so I made a "simulator" code with one ADC and polling it 24 times then writing it. This is working kind of but after the first read I get 3.30000 volts everytime ehich is not correct. I tried rezeroing all the channels but that doesn't work. Not sure what else to change. Am I filling up the memory with this method too, with a memory leak?

#include <SPI.h>


const int spiClockDivider = 42;
const int chipSelectPin = 4;
const int numChannels = 24;
long ADCresult[numChannels];
float ADCvolts[numChannels];

void setup()
{
  Serial.begin(115200);
  
  // start the SPI library:
  SPI.begin(4);
  
  // Set clock divider to 42
  SPI.setClockDivider(chipSelectPin, spiClockDivider);
  
  for (int makeChannel = 0; makeChannel < numChannels; makeChannel++)
  {
    ADCresult[makeChannel] = 0;
    ADCvolts[makeChannel] = 0;
  }
}
void loop()
{ 
  unsigned int time = 0;
  time = micros();
  
  for (int readChannel = 0; readChannel <= numChannels; readChannel++)
  {
    //transfer 0x00 to the device on pin 4, store byte received in adcByteHigh, keep the chip selected
    byte adcByteHigh = SPI.transfer(4, 0x00, SPI_CONTINUE);
    adcByteHigh &= 0b00000011;
    //transfer 0x00 to the device on pin 4, store byte received in adcByteMid, keep the chip selected
    byte adcByteMid = SPI.transfer(4, 0x00, SPI_CONTINUE);
    //transfer 0x00 to the device on pin 4, store byte received in adcByteLow, deselect the chip
    byte adcByteLow = SPI.transfer(4, 0x00);
  
    
    //combine the two parts into one 18-bit number:
    ADCresult[readChannel] = ((adcByteHigh << 14) | (adcByteMid << 6) | (adcByteLow >> 2));
    
    ADCvolts[readChannel] = 3.3 * ((float)ADCresult[readChannel]/65535);
    //delayMicroseconds(10);
    //delay(500);
  }
  time = micros() - time;
  
  // display the ADC value:
  //Serial.println(ADCresult, BIN);
  //Serial.print("Vertical joystick Voltage = ");
  for (int printChannel = 0; printChannel <= numChannels; printChannel++)
  {
    Serial.println(ADCvolts[printChannel], 6);
  }
  //Serial.println(" [Volts]");
  
  
  Serial.println(time, DEC);
  
  delay(1000);
}

From Serial Terminal the 3.300000 repeats.

1.588794
1.598462
1.582348
1.603296
1.585571
1.595239
1.595239
1.595239
1.601685
1.588794
1.595239
1.590405
1.601685
1.588794
1.588794
1.588794
1.598462
1.588794
1.590405
1.598462
1.590405
1.595239
1.588794
1.598462
1.598462
535
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
3.300000
186

Any help is appreciated. Thanks.
-Ryman

I don't know if this is the reason of your faults:

rymanvw:

  for (int readChannel = 0; readChannel <= numChannels; readChannel++)

{

there is an off-by-one bug, the condition should be < instead of <=

  for (int readChannel = 0; readChannel < numChannels; readChannel++)