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.
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.
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);
}
3 Answers 3
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:
Image source: AD7321 datasheet
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.
-
\$\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– Dom2020年06月01日 18:37:42 +00:00Commented Jun 1, 2020 at 18:37
There is a Extra Byte called Don't care If you shift right four instead of 3. It looks like you would have a correct result. Since the Dont Care bit is still in the number I think.
-
\$\begingroup\$ Is "There is a Extra Byte.." a typo, which should read "There is a Extra bit..."? \$\endgroup\$Chester Gillon– Chester Gillon2024年12月02日 23:43:48 +00:00Commented Dec 2, 2024 at 23:43
delayMicroseconds(x)
after the slave (de)selection, to meet the minimum required dead timet2
/t1
as shown in the timing diagram. Consult the datasheet for suitable values ofx
. \$\endgroup\$