Electronic – arduino – Interfacing AD7811 ADC with Arduino over SPI

adcarduinospi

TL;DR: I am not getting the correct values back from the AD7811 ADC. I am giving the ADC an input from my benchtop PSU (Tenma 72-2540) into analog input 1, and getting various (and always wildly incorrect) results back (although there is some consistency to it, read on!). I have additional questions about the part that might be better suited to a separate post.

More detail on the problem

I wanted to quickly test the AD7811 ADC with my Arduino Mega 2560 as I plan to use the AD7811 for a hobby project, and it is slightly different to the only SPI ADC I’ve used before (no dedicated “slave select” per se on the AD7811, has a combination of Conversion Start, Receive Frame Start and Transmit Frame Start). By tying CONVST, RFS and TFS together, it seems that it should operate similar to the way Slave Select normally works for SPI devices. I won’t be using the Mega in my final project, it was just faster to get it up and running.

Circuit
Here is a diagram of my circuit, it is implementing the “Typical Connection Diagram” found on page 10 of the datasheet. (I’ve also included a screenshot of this underneath my circuit)

Schematic of Arduino connected to AD7811

Typical Connection Diagram from datasheet

Photographs of connections

Here are some shots showing how I’ve got everything connected.

Top down view of breadboard

Close up of ADC connections

Macro view

Code

    #include <SPI.h>

const int convst = 42;  // CONVST pin on AD7811 connected to Pin 42 on Arduino
uint16_t return_val = 0;

// value to transfer to the control register (see page 7 of the datasheet)
uint16_t control = 0B1011000011; 

void setup() {
  // start the SPI library:
  SPI.begin();
  SPI.beginTransaction(SPISettings(2000, MSBFIRST, SPI_MODE0));
  pinMode(convst, OUTPUT);
  digitalWrite(convst, HIGH);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(convst, LOW); // Initiate the conversion process. Since TFS is also brought low, MOSI data is latched into the ADC (page 16)
  SPI.transfer(control>>2); // Transfer first 8 MSB of control settings (page 7 datasheet) i.e. 0B10110000 
  SPI.transfer(control<<6); // Transfer last 2 bits of control settings i.e. 0B11000000

  delayMicroseconds(3);      // Conversion process takes at most 2.3us 
  digitalWrite(convst, HIGH);// Bring CONVST, RFS and TFS high. First sentence of page 16 indicates that this would cause the result to be put on the SPI bus
  delayMicroseconds(1);
  return_val = SPI.transfer16(0); //read the 10 bit result
  return_val = return_val >> 6;   //SPI.transfer16 stores our result as a 16 bit number, but ADC only has 10bit resolution. Rightshift by 6 to correct this error. 

  Serial.println("Return");
  Serial.println(return_val); //print the value that we got back
  delay(1000);
}

Returned values

As I said in the TL;DR, the values I get back are always “wrong” (perhaps “not what I expected” is better), but they’re not necessarily the same values each time. For instance, feeding in 1VDC to Input 1 of the ADC, I get values 617, 616, 105 and 104 as my return values that I am printing to serial out (this is after I bitshift by 6 to the right). There’s no real discernible pattern, however it’s always one of these 4 values. For 1VDC input, and with Vref at 5VDC, I would expect about 204 or 205 as the return value (1/5 * 1024). If I change to 2VDC input, I get 722, 721, 210, 209.

Scope captures

  1. Proof that the control register is being written to (MOSI line)

The control settings appear to be leaving the Arduino on the MOSI line. There’s a “glitch” (terminology?) that occurs when transferring 0 from SPI.transfer16(): see the shot below, there’s a short spike of ~300ns duration around the falling edge of the 8th clock cycle. I’m not sure why this is occurring, I’m telling the Arduino to write a 0 for this transaction. Blue is SLCK, Red is MOSI (pin 51 Arduino)

Write to the control register, as well as writing of 0 as part of the read process

Glitch in the write process

  1. MISO line

Naturally, I wanted to check the response from the ADC. Blue is SCLK, Red is MISO (pin 50 on Arduino)

MISO line

I’ve noticed that, occasionally, there is an exponential decay over the last 7 clock cycles (and then some). I’m not sure what to make of this, but it doesn’t look good.

MISO with exponential decay

  1. Chip selection

Red is CONVST, RFS and TFS (tied together). Once that goes low, serial clock starts ticking, and data is transferred (in the manner shown in the scope captures above). Blue is SLCK, Red is CONVST/RFS/TFS (pin 42)

Chip selection timing

  1. Checking analog input 1

The input to the ADC looks to be clean, I have bypassed with a 10nF capacitor to help clean up the input.

Capture of ADC input

I am still pretty new to doing my own digital designs, second time using SPI, so I’d really appreciate any pointers or advice! If there’s any information I’m missing that you need, I’ll get it for you. I’m keen to improve wherever I can, including my troubleshooting skills!

Best Answer

For instance, feeding in 1VDC to Input 1 of the ADC, I get values 617, 616, 105 and 104 as my return values that I am printing to serial out (this is after I bitshift by 6 to the right). There’s no real discernible pattern, however it’s always one of these 4 values. If I change to 2VDC input, I get 722, 721, 210, 209.

Note the differences between the values:

  • 617 - 105 = 512
  • 616 - 104 = 512
  • 722 - 210 = 512
  • 721 - 209 = 512

It's clear that you're having trouble reading the ninth bit of the value correctly — 29 = 512. Sometimes you're getting "1" and sometimes you're getting "0".

The one-count variation (617 vs. 616, etc.) is simply normal quantization error.


I’ve noticed that, occasionally, there is an exponential decay over the last 7 clock cycles (and then some). I’m not sure what to make of this, but it doesn’t look good.

Actually, that's perfectly normal. During a read cycle, the AD7811 only drives data for the first ten clock cycles, then it tristates its output. If the last data bit (the LSB of the reading) is 1, the signal voltage slowly decays when the driver is turned off. You're ignoring those last 6 bits anyway.


Overall, I'd say that the most suspicious thing that I see is the timing on your MOSI line. The AD7811 expects the data to be stable during the falling edge of the clock, but in your traces, that's when it seems to be changing. You may need to switch modes in your SPI master between writing and reading in order to get this right.

That's one of the worst things about the SPI "standard" — there are four different ways to configure how the clock is driven relative to the data (both reading and writing), and it is sometimes difficult to infer the required settings from a device's datasheet.