Arduino UNO with AD7714 ADC

Hi, I am using an AD7714 ADC to conver the value from an FSG020WNPB load cell.

I have used the code from this post and modified it for myself: https://forum.arduino.cc/index.php?topic=334371.0

My code works however when there is no load, the ADC is stuck at exactly half the value however it does respond to changes from the load cell. Does anyone know why this might be?

I have attatched the Datasheets for the ADC, Load cell and my circuit diagram and the Serial O/P.

/* Reads value from load cell but only goes between half and full output*/
/* Hardware Connections Arduino <--> AD7714
  PIN 1 -> SCLK : external clock SPI Arduino
  PIN 2 -> MCLK IN : 2.4576 MHz by crystal (input)
  PIN 3 -> MCLK OUT : 2.4576 MHz (output)
  PIN 4 -> POL = 0: first transition of the serial clock in a data transfer operation is from a low to a high
  PIN 5 -> (SYNC) = 1 : synchronization of the digital filters and analog modulators
  PIN 6 -> (RESET) : Reset (PIN 2) Arduino
  PIN 7/8/9/10 -> AIN1/AIN2/AIN3/AIN4 : Analog Input Channel
  PIN 11 -> (STANDBY) = 1 : disable Standby
  PIN 12 -> AVdd = 5 V
  PIN 13 -> BUFFER = 0 : analog input is shorted out
  PIN 14 -> REF IN(-) = should be 0
  PIN 15 -> REF IN(+) = Should be 3.8V
  PIN 16/17 -> AIN5/AIN6 : Analog Input Channel  no connect
  PIN 18 -> AGND = GND
  PIN 19 -> (CS) : chip select SPI (PIN 3) Arduino
  PIN 20 -> (DRDY) : (PIN 4) logic input of the AD7714
  PIN 21 -> DOUT : serial data output, MISO SPI Arduino
  PIN 22 -> DIN : serial data input, MOSI SPI Arduino
  PIN 23 -> DVdd = 5 V
  PIN 24 -> DGND = GND
*/

#include <SPI.h>

/*ADC -> UNO Definitions*/
const int dataReady = 4;
const int CS = 3;
const int RESET = 2;

//Define Functions for R/W Registers
uint8_t writeSmallReg( uint8_t reg, uint8_t value);
uint8_t readByteRegister( uint8_t reg);
uint32_t readbigRegister( uint8_t reg);

//8 or 32 Bit Integers
uint32_t measure;
uint8_t readfilterlow;
uint8_t readfilterhigh;
uint8_t readmode;
int8_t readtest;

bool bits24 = true; //24 bit from data register

void setup() {
  Serial.begin(9600);

  //SPI Setup
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(210);  // Slow down SPI clock
  SPI.setDataMode(SPI_MODE2);

  pinMode(dataReady, INPUT);
  pinMode(CS, OUTPUT);
  pinMode(RESET, OUTPUT);

  digitalWrite(CS, HIGH);  //deselect ADC

  digitalWrite(RESET, LOW); //Reset ADC
  delay(100);
  digitalWrite (RESET, HIGH);

  Serial.println("Begin ADC Register Setup");
  delay(100);
  //Channel 4 Operation as Load Cell connected to AIN1 and AIN2
  writeSmallReg(2, 0x61);   //Filter High, bipolar, 24-bit, current boost on, CLCKDIS 0
  writeSmallReg(3, 0x80);   //Filter Low Register FS11-FS0=0001 1000 0000 Filter first notch = 50Hz -3dB = 13.1Hz
  writeSmallReg(1, 0x2C);   //Self calibration
  Serial.println("Setup END");
  while (!(digitalRead(dataReady) == 0)); //wait for calibration to finish
  ///////////////////////Make sure Registers are Loaded with Correct Values/////////////////
  readfilterlow = readByteRegister (3);
  readfilterhigh = readByteRegister (2);
  readmode = readByteRegister (1);
  readtest = readByteRegister (4);
  Serial.print("Filter Low Register =  ");    //expected value= 0x80
  Serial.println(readfilterlow, HEX);
  Serial.print("Filter High Register =  ");   //expected value= 0x61
  Serial.println(readfilterhigh, HEX);
  Serial.print("Mode Register =  ");          //expected value= 0x0C
  Serial.println(readmode, HEX);
  Serial.print("Test Register =  ");          //expected value=???
  Serial.println(readtest, HEX);
  /////////////////////////////////////////////////////////////////////////////////////////

  // while (digitalRead(dataReady)==1);   //wait for drdy to go low
}
void loop  () {
  int val = 0;
  /*
    measure=readbigRegister(5);
    while (!(digitalRead(dataReady)));
    while (digitalRead(dataReady));
    while (!(digitalRead(dataReady)));
    while (digitalRead(dataReady));
    Serial.print(measure, HEX);
    Serial.println("=" + String((float(measure) / 16777216.0) * 3.9) + "V");
  */
  while (!(digitalRead(dataReady))); //wait for drdy to go low
  measure = readbigRegister(5);   //read data
  Serial.print(measure, HEX);
  Serial.println("=" + String((float(measure) / 16777216.0) * 3.863) + "V");   //ref voltage = 3.863V

}



uint8_t writeSmallReg( uint8_t reg, uint8_t value) { // only valid for 8 bit registers 0..4
  uint8_t ain = 0x04;
  uint8_t result = 0;
  if (reg < 5) { // byte registers
    uint8_t cmd = 0; // a place to build the correct comm reg value.

    cmd = (reg << 4); // set the correct RS2..RS0 bits of COMM register

    if (reg == 0) // update global ain Value
      ain = value & 7;

    cmd = cmd | ain; // keep the analog mux what it was previously configured as.

    digitalWrite(CS, LOW); // select the ADC

    uint8_t stat = SPI.transfer(cmd); // actually send the cmd and read the current status

    if (reg != 0) { // actually send the value to reg

      uint8_t unk = SPI.transfer(value);
      if (reg == 2) bits24 = (value & 0x40) == 0x40; // if configured for 24bit data register

    }
    digitalWrite(CS, HIGH); // all done with device
    result = stat; // return value received, drdy is bit 7.
  }
  return result;
}

uint8_t readByteRegister( uint8_t reg) { // only valid for 8 bit registers 0..4

  uint8_t result = 0;
  if (reg < 5) { // byte registers
    uint8_t cmd = 0; // a place to build the correct comm reg value.

    cmd = (reg << 4); // set the correct RS2..RS0 bits of COMM register

    cmd = cmd | 0x04; // keep the analog mux to channel 4.

    cmd = cmd | 0x08; // read mode

    digitalWrite(CS, LOW); // select the ADC

    result = SPI.transfer(cmd); // actually send the cmd and read the current status

    if (reg != 0) { // actually read the value of reg

      result = SPI.transfer(0); // 0 is just a place holder, the ADC ignores it. because of read mode
    }
    digitalWrite(CS, HIGH); // all done with device
  }
  return result;
}

uint32_t readbigRegister( uint8_t reg) { // only valid for 16,24 bit registers 5..7

  uint8_t ain = 0x04;
  uint32_t result = 0;
  if ((reg > 4) && (reg < 8)) { // big registers
    uint8_t cmd = 0; // a place to build the correct comm reg value.

    cmd = (reg << 4); // set the correct RS2..RS0 bits of COMM register

    cmd = cmd | ain; // keep the analog mux what it was previously configured as.

    cmd = cmd | 0x08; // read mode

    digitalWrite(CS, LOW); // select the ADC

    uint8_t stat = SPI.transfer(cmd); // actually send the cmd and read the current status
    uint8_t b = SPI.transfer(0); // send out placeholder get back byte
    result = b;
    b = SPI.transfer(0); // send out placeholder get back bigger byte
    result = (result << 8) + b; // build up 16 bit value from bytes
    if (bits24 || (reg > 5)) { //do a 24bit transfer
      b = SPI.transfer(0); // send out placeholder get back bigger byte
      result = (result << 8) + b; // build up 24 bit value from bytes.
    }
    digitalWrite(CS, HIGH); // all done with device
  }
  return result;
}

EDIT - The solution to this problem was that the ADC was set for bipolar mode when the Load Cell would only ever give a positive output. Setting the MSB in the filter high register to 1 solved the problem.

Circuit Diagram.jpg

Circuit Diagram.jpg

ADC-AD7714.pdf (293 KB)

Load Cell.pdf (384 KB)

I did not check your code, but pin 10 should be output.
Read the "Note about Slave Select (SS) pin on AVR based boards" paragraph here: Arduino - SPI

I think that's just if the AVR is acting as a Slave

Using a divider from the 5V rail for your voltage reference;: provided that is also providing the excitation voltage for the load cell, changes would balance out.

the ADC is stuck at exactly half the value

what value?

Hi John, thanks for your reply I really appreciate it. The ADC was outputting around the same value of 7FAxxx where x was changing.

Since then, somehow despite not changing any of the circuit the ADC now outputs zero when no load is applied but outputs FFFFFF when only a small force is applied to the load cell. I have used a multimeter to verify the reference voltage going into Vref+ is indeed 3.8V so I am unsure as to why this is happening.

What exactly do you mean by changes balancing out? I could try connecting the load cell with 3.3v from the arduino and see if that makes a difference?

How are the other 2 wires on the load cell connected?

The load cell outputs a voltage that is a linear function of the load and the excitation voltage.
If the excitation voltage drops by 10% then the output drops by 10%; however the reference ALSO drops by 10% so the measurement works out the same.

I'd suggest you measure the voltage on each output from the load cell with respect to the 0V supply.
Then - can you read each ADC input seperately?

How are the other 2 wires on the load cell connected?

Pin 1 - 5V (Arduino)
Pin 2- AIN1
Pin 3 - GND (Arduino)
Pin 4 - AIN2

I'd suggest you measure the voltage on each output from the load cell with respect to the 0V supply.
Then - can you read each ADC input seperately?

I connected the COM of the multimter to the GND rail of the arduino and then measured the Outputs, these are the results:

Load Cell: Pin 1 - 4.95V
Pin 2 - 2.5V (Value increased to 2.54 with load)
Pin 3 - 0V
Pin 4 - 2.46V (Value decreased to 2.43 with load)

ADC: Vref: 3.81V (no change when load applied to load cell)
AIN1 2.48V (increase with load)
AIN2 2.5V (decrease slightly with load)
Thanks for you help once again!

Interestingly after rebuilding the circuit the exact same it is now back to outputting half the value

The voltages are exactly as they should be.

You will need to refer to the ADC datasheet to find out how to configure it to read a differential voltage on Ain1:Ain2

That looks to be a very complicated bit of code for what should be essentially a simple task.

Yes it is a bit complex but that's relly just the functions for writing to and reading from the registers.
I believe to set up a fully differential output on AIN1 and AIN 2 I have to set the 3 lower bits in the communications register as 100 which I have done so I am not sure what is happening :confused: Thanks for all your help though!

Can you read the "Note about Slave Select (SS) pin on AVR based boards" once more ?

Can you read the "Note about Slave Select (SS) pin on AVR based boards" once more ?

Hi, I am not using pin 10 as my Slave Select, I am using pin 3 which I have labelled CS, this has been set to output. Cheers.

Can you print that paragraph and put it under your pillow ? Maybe that will help :confused:

set pin 10 as output.png

I checked SPI.begin() and that function already sets the SS as output 8)

You can still use pin 10 for a led or so, but don't use it as a input and don't connect a switch to it.

I think this means that pin 10 is not the problem.

set pin 10 as output.png

Yes I saw that, however I have verified previosuly in my code that the SPI communication is working properly. Unsurprisingly when adding code in to set pin 10 as an output the result is not affected.

You have a potentially noisy reference voltage - Fig 2 indicates decoupling
it well.

Do you have good decoupling on the two power pins?

You'll need more than x8 gain eventually I think.

Anyway I'd have thought the HX711 was a simpler option?

Do you have good decoupling on the two power pins?

I don't, I've just connected the 5V out from the arduino to a breadboard and then any pin that needs 5V to that rail. Would you suggest adding some decoupling capacitors and if so where?

Anyway I'd have thought the HX711 was a simpler option?

It is, however I wanted to challenge myself as the HX711 seemed a bit too easy to use.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.