AD7715 barely working with SPI

Hey guys, I would like to ask for help in a project.
I use the AD7715 AD converter to read voltage values, but I get inconsistent results. I looked through a lot of forum posts with this ADC, and after many tries, I got this code, that samewhat works. There are 2 problems:

  1. The calibration of the ADC doesn't end as expected. When I check the setup register value, it's 0 or 255 most of the time. When it gives the correct value (40), it continues the code, but then I get the 2nd problem.
  2. The read values are 128 / 0 (the 2 bytes of the read data) at 0V analog input, and 255 / 255 at 2,5V and above. The values between these two voltages scale up good, it gives linear scale, which is good, but the range below 128 / 0 is not usable this way.

I use an Arduino Uno with a 9V adapter, this provides the power to the circuit through the 5V pin. The AD7715-5 ADC has a 2,4576 MHz crystal as internal clock, and an AD780 reference IC provides the reference voltage. The SPI-specific wires connect as the Arduino reference provides (MOSI / Din: pin 11, MISO / Dout: pin 12, SCLK: pin 13).
The circuit is exactly the same as the datasheet provided (including the capacitors). The drawing is attached.

Here is the code currently:

#include<SPI.h>

int DRDY = 8;
int read1 = 0;
int read2 = 0;
int busy = 1;
int result = 0;

void setup() {

  pinMode(DRDY, INPUT);
  
  SPI.begin();
  SPI.beginTransaction(SPISettings(60, MSBFIRST, SPI_MODE3));

  Serial.begin(115200);
  
  while(read1 != 40) {
    calibrate();
  }

}

void loop() {

  while(busy == 1) {        // wairing for an avaliable result
    busy = digitalRead(DRDY);
    Serial.println("busy");
    }
    
  SPI.transfer(0x38);
  read1 = SPI.transfer(0);
  read2 = SPI.transfer(0);

  conversion(read1, read2);
  delay(1000);
}

void calibrate() {

  busy = 1;
  while(busy == 1) {
    busy = digitalRead(DRDY);
    Serial.println("busy");
   }

  delay(50);

  SPI.transfer(16);   // 0 0 0 1 0 0 0 0 -> request to write to setup register
  SPI.transfer(104);   // 0 1 1 0 1 0 0 0 -> start self-calibration

  delay(1000);

  busy = 1;
  while(busy == 1) {   // waiting for calibration to finish
    buys = digitalRead(DRDY);
    Serial.println("busy");
   }

  SPI.transfer(24);   // 0 0 0 1 1 0 0 0 -> request to read from setup

  read1 = SPI.transfer(0);
  Serial.print("Setup register value: ");
  Serial.println(read1);
  
  delay(1000);
}

void conversion(int read1, int read2) {          // convert to decimal
  result = (read1 * 256) + read2;
  Serial.println(result);
}

Can this be an syncronization error, or maybe the calibration is not running correctly? Can somebody help me?

AD7715.png

AD7715.png

Just my humble opinion, but I would not tie /CS to GND. I would drive it accordingly when communicating with the chip.
The same goes for /RESET, especially when you are playing with it using an Arduino UNO (or any Arduino really). The chip would not reset when you load a new sketch. If you drive /RESET from a pin, then you can guarantee a known starting position.

Thank you so much, markd833! Manually controling the /RESET and /CS pins solved the first problem, now I get the correct register value every time.
The other problem stayed the same, the output value is 127 / 222 even if give 0V.

This is the code right now:

#include<SPI.h>

int DRDY = 8;
int read1 = 0;
int read2 = 0;
int busy = 1;
int result = 0;
int reset_pin = 9;
int CS = 7;

void setup() {

  pinMode(DRDY, INPUT);
  pinMode(reset_pin, OUTPUT);
  pinMode(CS, OUTPUT);

  digitalWrite(reset_pin, LOW);
  digitalWrite(CS, HIGH);
  delay(100); 

  SPI.begin();
  SPI.beginTransaction(SPISettings(60, MSBFIRST, SPI_MODE3));

  Serial.begin(115200);
  
  while(read1 != 40) {
    digitalWrite(reset_pin, LOW);
    calibrate();
  }

}

void loop() {

  digitalWrite(CS, LOW);

  while(busy == 1) {        // wairing for an avaliable result
    busy = digitalRead(DRDY);
    Serial.println("busy");
    }
    
  SPI.transfer(0x38);
  read1 = SPI.transfer(0);
  read2 = SPI.transfer(0);

  conversion(read1, read2);
  digitalWrite(CS, HIGH);
  delay(1000);
}

void calibrate() {

  delay(100);
  digitalWrite(reset_pin, HIGH);
  digitalWrite(CS, LOW);

  busy = 1;
  while(busy == 1) {
    busy = digitalRead(DRDY);
    Serial.println("busy");
   }

  delay(50);

  SPI.transfer(16);   // 0 0 0 1 0 0 0 0 -> request to write to setup register
  SPI.transfer(104);   // 0 1 1 0 1 0 0 0 -> start self-calibration

  delay(1000);

  busy = 1;
  while(busy == 1) {   // waiting for calibration to finish
    buys = digitalRead(DRDY);
    Serial.println("busy");
   }

  SPI.transfer(24);   // 0 0 0 1 1 0 0 0 -> request to read from setup

  read1 = SPI.transfer(0);
  Serial.print("Setup register value: ");
  Serial.println(read1);
  
  digitalWrite(CS, HIGH);
}

void conversion(int read1, int read2) {          // convert to decimal
  result = (read1 * 256) + read2;
  Serial.println(result);
}

One more question: what frequency should I give for the SPISetting? The internal clock of the ADC (2,4576 MHz), or the output rate (60 Hz)?

I'm looking at the datasheet on my phone so this may be wrong! I think it says that minimum clock cycle time is 200ns which is 5MHz. I would pick something slower to get started just to ensure that you are definitely within spec, say 100 or 200KHz. You can always wind the clock speed up once you've got it working.

I'm guessing that the 60hz is the maximum conversion rate. You can talk to the chip at a much faster rate than that when reading/writing the registers.