Post Go back to editing

AD7797 false read ADC value

Hi everyone,

I am working on AD7797, created a custom PCB with atmega328p chip(arduino uno) and also written firmware for this. I am able to communicate with AD7797 but while reading ADC value it false data. Same data repeats. Please help me i am attaching PCB schematic and arduino code. Kindly share some library or code for AD7797.

Regards

Suman

#include <SPI.h>    // include the SPI library:
#define cs 10
void setup()
{
  Serial.begin(9600);                    // initialize serial port
  pinMode(SCK, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT);
  pinMode(cs, OUTPUT);
  digitalWrite(cs, HIGH);

  SPI.begin();                           // wake up the SPI
  SPI.setDataMode(SPI_MODE3);            // datasheet p6-7
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32);  // datasheet p6

  Serial.println("AD7797 Test");

  initAD7797();


}

void initAD7797()
{
  beginAD7797();
  resetAD7797(); //reset device
  delay(2);
  if (!(getID() % 2))
  {
    Serial.println("ID : AD7796");
  }
  else
  {
    Serial.println("ID : AD7797");
  }
  Serial.print("Configuration : "); Serial.println(readCFG(), BIN);
}

void beginAD7797() //must be mode3
{
  //SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR0); //mode3, 1MHz
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA); //mode3, 4MHz
}

void resetAD7797() //p14
{
  digitalWrite(cs, LOW); //reset IC by sending out 32b of 1s
  transferAD7797(0xFF);
  transferAD7797(0xFF);
  transferAD7797(0xFF);
  transferAD7797(0xFF);
  digitalWrite(cs, HIGH);
}

uint8_t getID() //WORKS!
{
  uint8_t output = 0;
  digitalWrite(cs, LOW);
  transferAD7797(0x60); //01100000 0x60
  output = transferAD7797(0x00);
  digitalWrite(cs, HIGH);
  return output;
}

//read value from ADC,
long readAD7797()
{
  long value = 0; //uint16_t byte1, byte2, byte3;

  //selectCH(ch);
  selectMode();

  while (readST() > 127); //wait until !RDY

  digitalWrite(cs, LOW);
  transferAD7797(0x58); //select DATA register (01011000)(0x58) //one read  try (01011100)(0x5C) for CREAD

  value = (transferAD7797(0x00) << 16) & 0xFF0000;
  value += (transferAD7797(0x00) << 8) & 0xFF00; //grab top byte
  value += transferAD7797(0x00) & 0xFF; //grab bottom byte

  digitalWrite(cs, HIGH); //pull CS high to disengage

  return value; //return( ((byte1<<8) | byte2) & 0xFFFF);
}

uint16_t readCFG() //works!
{
  long output = 0;
  digitalWrite(cs, LOW);
  transferAD7797(0x50); //select CONFIGURATION register (01010000)(0x50)
  output = (transferAD7797(0x00) << 8) & 0xFF00; //grab top byte
  output += transferAD7797(0x00) & 0xFF; //grab bottom byte
  digitalWrite(cs, HIGH);
  return output;
}

uint8_t readST() //works!
{
  long output = 0;
  digitalWrite(cs, LOW);
  transferAD7797(0x40); //select STATUS register (01000000)(0x40)
  output = transferAD7797(0x00); //grab byte
  digitalWrite(cs, HIGH);
  return output;
}

//select adc channel
void selectCH(uint8_t ch)
{
  if (ch > 2)
    ch = 2;
  ch |= 0x90;

  digitalWrite(cs, LOW); //pull CS low to engage
  transferAD7797(0x10); //select configuration register 00010000 (0x10)

  transferAD7797(0x10); //Write 16 bits to CONFIGURATION register:
  //bias voltage: disabled 0 0
  //burnout current: disabled 0
  //bipolar operation: 0 or 1?
  //boost: disabled 1
  //gain: disabled 0 0 0
  //top 8b: 00011000 (0x18), disable boost yields 00010000 (0x10)

  transferAD7797(ch);   //internal reference 1
  //0 0
  //buffer 1
  //0
  //000 (CH1) 001(CH2) 010(CH3)
  //channel select = AIN1(+) - AIN1(-)
  //bottom 8b: 10010000 (0x90)  10010001 (0x91) read CH2  10010010 (0x92) read CH3
  digitalWrite(cs, HIGH); //pull CS high to disengage
}

void selectMode()
{

  digitalWrite(cs, LOW); //pull CS low to engage

  transferAD7797(0x08); //select MODE register (00001000)(0x08)
  //Write 16 bits to MODE register on page 16 Table 15
  transferAD7797(0x20); //0x00 for continuous
  //0x20 for single conversion  preferred
  //0x40 for idle
  //0x60 for power down
  //0x80 internal zero scale calibration
  //0xA0 internal full scale calibration
  //0xC0 system zero scale calibration
  //0xE0 system full scale calibration

  //update rate on page 16/17
  transferAD7797(0x0C); //0x00    X    X
  //0x01  470Hz 4mS
  //0x02  242Hz 8mS
  //0x03  123Hz 16mS
  //0x04   62Hz 32mS
  //0x05   50Hz 40mS
  //0x06   39Hz 48mS
  //0x07 33.2Hz 60mS
  //0x08 19.6Hz 101mS -90dB for 60Hz
  //0x09 16.7Hz 120mS -80dB for 50Hz
  //0x0A 16.7Hz 120mS -65dB for 50/60Hz
  //0x0B 12.5Hz 160mS -66dB for 50/60Hz
  //0x0C   10Hz 200mS -69dB for 50/60Hz
  //0x0D 8.33Hz 240mS -70dB for 50/60Hz
  //0x0E 6.25Hz 320mS -72dB for 50/60Hz
  //0x0F 4.17Hz 480mS -74dB for 50/60Hz
  digitalWrite(cs, HIGH);
}


uint8_t transferAD7797(uint8_t data)
{
  beginAD7797(); //set correct SPI settings for devices
  SPDR = data;
  while (!(SPSR & (1 << SPIF))); //wait until transfer is done
  return SPDR; //return received byte
}

void loop()
{
  delay(100);
  Serial.println(String("ADC Read : ") + readAD7797());
}

PCB Schematic

  • Hi,

    Do you have a scope shot of your digital interface upon reading the data register? Are you also monitoring the RDY bit or RDY pin upon reading the data register? May I know also what is your input range and so what data output are you getting from these input values?

    We have a software driver for the AD779x family. This can be also applicable for the AD7797. So you can use this as your reference code. Hope this will help. Kindly refer to the link. AD7793 IIO Low Power Sigma-Delta ADC Linux Driver [Analog Devices Wiki]

    Thanks,

    Jellenie

  • Hi thanks for the response. I read your solution on other related post accordingly i am trying, kindly can you check the above attached code. Also the reference code which you shared is bit complex and i am not expert in programming. If you tell me simple way it will be great help. Also please explain the sequence of data read write. 

    I followed figure 17 of datasheet (page 23) AD7797 for making PCB. I just want a simplest way to read ADC 24 bit value. Please provide some sample code written in C or C++ or Arduino

  • Hi,

    Apologies. I have attached the wrong link. You can use this link of AD779x generic driver for any microcontroller

     https://wiki.analog.com/resources/tools-software/uc-drivers/renesas/ad7793

    We do not usually provide support in terms of software, we only provide code to control and initialize the AD779x part but we don't provide any actual details for a specific communication protocol to the ADI driver but if you have any other issue regarding the driver provided on the link above you may ask directly to the Microcontroller no-OS Drivers  community to support you.

    Thanks,

    Jellenie

  • Hi Jellenie

    I tried everything but not getting the to read properly. Accordiing to your advice i wrote again a simple program. I can see data in and out on DSO, but not able to decode to meaningful data. Kindly help.

    here i am attaching DSO snapshots and new code please once you check it the sequence.

    Regards

    Suman

    Full stream of data comes once if i read data register

    #include <SPI.h>    // include the SPI library:
    
    char csPin = 10; //where chipselect pin connected
    //===================================================================================
    void setup()
    {
      Serial.begin(9600);
    
      // spi setup
      SPI.begin();                           // wake up the SPI
      SPI.setDataMode(SPI_MODE3);            // datasheet p6-7
      SPI.setBitOrder(MSBFIRST);
      SPI.setClockDivider(SPI_CLOCK_DIV32);  // datasheet p6
      delay(100);
      Serial.println("AD7797 Test");
    
      Serial.println("Reseting...");
      delay(2000);
      // adc setup
      adc_reset();
      Serial.println("Reset Done");
    
      if (!(getID() % 2))
      {
        Serial.println("ID : AD7796");
      }
      else
      {
        Serial.println("ID : AD7797");
      }
    
      adc_config();
    
      Serial.print("Ready");
      Serial.print("\n\n");
    }
    //===================================================================================
    
    void loop()
    {
      Serial.println("Waiting...");
      adc_config();
      Serial.println(String("Raw Data : ") + (adc_read(), BIN));
      delay(5000);
    }
    //===================================================================================
    
    void adc_reset() {
      unsigned char incomingByte = 0;
      digitalWrite(csPin, LOW);
      for (int i = 0; i < 4; i++) {        // send 0xFFFFFFFF
        incomingByte = SPI.transfer(0xFF);
      }
      digitalWrite(csPin, HIGH);
      delayMicroseconds(500);            // (datasheet --> p.23 ~p.19) wait 500us
    }
    //===================================================================================
    
    uint8_t getID() //WORKS!
    {
      uint8_t output = 0;
      digitalWrite(csPin, LOW);
      SPI.transfer(0x60); //01100000 0x60
      output = SPI.transfer(0x00);
      digitalWrite(csPin, HIGH);
      return output;
    }
    //===================================================================================
    
    uint8_t readST() //works!
    {
      long output = 0;
      digitalWrite(csPin, LOW);
      SPI.transfer(0x40); //select STATUS register (01000000)(0x40)
      output = SPI.transfer(0x00); //grab byte
      digitalWrite(csPin, HIGH);
      return output;
    }
    //===================================================================================
    // read from data register
    uint32_t adc_read()
    {
      uint32_t registerValue = 0;
      byte incomingByte;
    
      while (readST() > 127); //wait until !RDY
    
      digitalWrite(csPin, LOW);
    
      SPI.transfer(0x58); // read from data register
      for (int i = 0; i < 3; i++) {
        incomingByte = SPI.transfer(0x00);
        switch ( i ) {
          case 0:
            registerValue = incomingByte;
            break;
          case 1:
            registerValue <<= 8;
            registerValue |= incomingByte;
            break;
          case 2:
            registerValue <<= 8;
            registerValue |= incomingByte;
            break;
        }
      }
      digitalWrite(csPin, HIGH);
      return registerValue;
    }
    //===================================================================================
    
    void adc_config()
    {
      adc_cr_write(0x17, 0x10); // unipolar, channel 0
      adc_mode_write(0x20, 0x0c); //10Hz 200mS -69dB for 50/60Hz
    }
    //===================================================================================
    
    void adc_cr_write(char FirstByte, char SecondByte) {
      unsigned char incomingByte = 0;
      digitalWrite(csPin, LOW);
      incomingByte = SPI.transfer(0x10); // write in config register
      incomingByte = SPI.transfer(FirstByte); // data for write
      incomingByte = SPI.transfer(SecondByte); // data for write
      digitalWrite(csPin, HIGH);
    }
    //===================================================================================
    
    void adc_mode_write(char FirstByte, char SecondByte) {
      unsigned char incomingByte = 0;
      digitalWrite(csPin, LOW);
      incomingByte = SPI.transfer(0x08); //write in mode register
      incomingByte = SPI.transfer(FirstByte); // data for write
      incomingByte = SPI.transfer(SecondByte); // data for write
      digitalWrite(csPin, HIGH);
    }
    //===================================================================================

  • Hi Jellenie,

    I have written mode and config register as (mode = 0x200C and config = 0x1710) which you can see on the attached snapshot serial window. I tried reading mode and config register, it is exactly what i set.

    but now also when i am reading data resister the raw reading is max value like saturated.

    please check image and let me know what is the correct sequence of reading

  • Finally something good, able to read adc 24 bit data. Thank you

    Now need to calibrate. Can you tell how i can do this.

    Regards

    Suman

  • Hi, 

    Good to hear that you are now able to read the data. Regarding the calibration,  We have an AD779xFAQ document that covers all of the information needed for calibrations. This may help you on your queries. Usually, an internal calibrations is performed first followed by system calibrations. If the errors after performing internal calibrations does not change or has minimal effect then that's the time you can consider performing a system calibration to remove the errors internal to ADC as well as the errors associated in your analog front end circuitry. For internal calibrations, the respective zero input and full-scale input are automatically connected internally to the ADC input pins. A system calibration, however, expects the system zero-scale and system full-scale voltages to be applied to the ADC pins before the calibration mode is initiated. In this way, external ADC errors are removed.

    Thanks,

    Jellenie

  • Thanks i will go through the document.

    Can you check my pcb schematic is it correct? i followed datasheet for making.

    Both +Vref and AVDD are at 5V analog

    And -Vref abd AGND are analog ground.

    I am not understanding datasheet for calibrating zero scale or full system, what physical connection do i need to make with AN+ and AN- while calibrating different calibration steps.

    Please can you explain in details

    Regards

    Suman