1
\$\begingroup\$

I'm trying to interface an AD7321 ADC with the Arduino Uno/Mega or Raspberry Pi for data acquisition of signals from my breadboard to computer.

I am able to communicate with the ADC through SPI with an Arduino Uno by sending the required 16 initialization bits, however the output of the ADC does not correctly represent the analog value when observed with an oscilloscope.

The image below is a snippet from the datasheet of the expected I/O for the SPI pins.

Datasheet

Since this is a 13bit (12+sign) ADC, I would expect a digital range from 0-4096 excluding the sign, however the images attached show otherwise.

This is a graph showing the ADC output at 5V DC.
ADC Graph 5V

This is a graph showing the ADC output at 0V DC.
ADC Graph 0V

The 2 return bytes given by the ADC in 0V DC graph

00001100 00010100 (Flat line) Which is when converted into decimal is 3092.

From the first image of the datasheet, the first 3 bits can be ignored when finding the absolute value of the desired signal.

I am trying to use this ADC to sample my signal (+-10V) at 100ksps which this ADC is capable of, however I cannot get an accurate reading from it.

Could someone who is more familiar with the AD732x chip shed some light on the behaviour of this chip?


EDIT: Thanks for the comments, I have amended the post to ensure the information is available.

This is the schematic, there are a few decoupling capacitors from Vdrive/Vcc to ground and both analog and digital grounds are connected at a star junction to reduce wire inductance noise.

The graphs above have Vdd = 5V and Vss = 0V, however I have also tried Vdd = 10V, 7V and Vss = -10V, -7V and -5V, but encounter the same issues.

ADC Schematic

In terms of code I have attached them below. The initial bits sent to the ADC are currently configured to read at +-5V single ended mode, no sequencing, binary code from channel 0.

#include <SPI.h>
#define CS_PIN 10 //Pin 10 defined as the CS Pin.
void setup()
{
  Serial.begin(115200); //Initalise port to print in serial terminal
  pinMode(CS_PIN,OUTPUT); //Pin 10 as CS
  digitalWrite(CS_PIN,HIGH);
  SPI.begin();  //Intialise SPI PORT
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV4);
  initialise();
}

void loop()
{
  uint16_t adcOut;
  float value;
  initialise();
  adcOut = readADC(0);

  adcOut = (adcOut<<3); // Bitshift to take last 13bits
  value = (adcOut>>3);
  Serial.println(value);
  delayMicroseconds(1); //Delay
}

uint16_t readADC(int channel)
{
  uint16_t output;
  digitalWrite(CS_PIN,LOW);
  byte msb = SPI.transfer(0x00);
  byte lsb = SPI.transfer(0x00);
  digitalWrite(CS_PIN,HIGH); // Deselect slave by pulling CS_PIN HIGH.
  output = (msb << 8 | lsb); //Combine MSB with LSB to form the 16 Bit Analog read  Value.
  return output; //Output Value
}

void initialise() 
{
  digitalWrite(CS_PIN, LOW); //Select the connected chip by pulling CS_PIN LOW.
  SPI.transfer(0b10111001);  //Defines range register -> | Write (1) | 0 | Register Select (1) | Vin0A | Vin0B | 0 | 0 | Vin1A |
  SPI.transfer(0b10000000);  // | Vin1B | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
  digitalWrite(CS_PIN, HIGH);
  delayMicroseconds(1);
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(0b10000000);  //Defines control register -> | Write (1) | 0 | Register Select (0) | 0 | 0 | ADD0 | Mode1 | Mode0 |
  SPI.transfer(0b00110000);  // | PM1 | PM0 | Coding | Ref | Seq1 | Seq2 | 0 | 0 |
  digitalWrite(CS_PIN, HIGH);
  delayMicroseconds(1);
}
\$\endgroup\$
6
  • 3
    \$\begingroup\$ Hi Dom. Please add a schematic or connection diagram. This will help troubleshoot issues not related to the data transfer itself. As a general tip: if you haven't already, please read the AD7321 Datasheet. \$\endgroup\$
    – pgvoorhees
    Jun 1, 2020 at 12:07
  • 1
    \$\begingroup\$ You'll probably need to post some code. \$\endgroup\$ Jun 1, 2020 at 12:29
  • \$\begingroup\$ Thanks for the comments, I have amended the post to ensure the information is available. I believe I am reading from channel 0, and have grounded the other channel. It should be converting in single ended mode, at +-5V but have tried other settings with similar issues. \$\endgroup\$
    – Dom
    Jun 1, 2020 at 14:22
  • \$\begingroup\$ My guess is, this is caused by corrupted communication. I suggest to add a delayMicroseconds(x) after the slave (de)selection, to meet the minimum required dead time t2/t1 as shown in the timing diagram. Consult the datasheet for suitable values of x. \$\endgroup\$
    – Sim Son
    Jun 1, 2020 at 14:39
  • \$\begingroup\$ why to you call the initialization in the loop? I guess, is not intended \$\endgroup\$
    – Sim Son
    Jun 1, 2020 at 14:42

2 Answers 2

1
\$\begingroup\$

It may be worth looking more closely at your power supply rails and how they are all interconnected and whether they are properly decoupled from their respective grounds at all, there are a few instances in the documentation pointing this out. The other thing that jumps out is that you don't appear to drive your reference voltage, either with the 680nF decoupling capacitor or one of the suggested external references:

ref/in

Image source: AD7321 datasheet

\$\endgroup\$
0
\$\begingroup\$

You did a good job asking your question here. Its always encouraging to see a well formed Q where research has already been done.

In my first comment I suggested reading the datasheet, I should have added "carefully" because ICs are usually complex and can easily "getcha".

The ADC is capable of producing codes in 2 different formats:

  • Straight counts
  • 2s Complement

Take note of how the output codes change with each mode, depicted here:
output code graphs

In Straight Binary case, the counts will map to voltages: -FS/2 -> 0, 0V -> ~4096, +FS/2 -> 8191

In 2's complement case, the counts will map to voltages: -FS/2 -> -4096, 0V ->~0, +FS/2 -> 4095

Which coding the ADC uses depends on the value set in the CONTROL REGISTER. You've selected the straight coding format.

  digitalWrite(CS_PIN, LOW);
  SPI.transfer(0b10000000);  //Defines control register -> | Write (1) | 0 | Register Select (0) | 0 | 0 | ADD0 | Mode1 | Mode0 |
  SPI.transfer(0b00110000);  // | PM1 | PM0 | **Coding** | Ref | Seq1 | Seq2 | 0 | 0 |
  digitalWrite(CS_PIN, HIGH);

Your code selects the "straight count" method, meaning it will map 0V to approximately 4096 counts, which it is. Try the other configuration and see how that works for you.

\$\endgroup\$
1
  • \$\begingroup\$ Hi pgvoorhees, Thank you so much for spending the time to respond to my post. I have looked into the coding and have found that both coding types do not provide an accurate sample of the analog signal. 0V with binary shows ~3000, 0V with 2s complement shows ~7000. I have two of these chips, although one of them is more noisy they both seem to read 3092 when Ch0 and Ch1 are in 0V but reads ~4000 when Ch0 is at 5V and Ch1 at 0V. Could it be an issue with my bitshifting, or wiring that could affect the value? \$\endgroup\$
    – Dom
    Jun 1, 2020 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.