Post Go back to editing

AD7731 via Arduino SPI

We're using an Arduino to control an AD7731.  We think the SPI interface is working in that we can 1) trigger a reset by writing four 0xFF bytes and see the RESET pin go low via our logic analyzer and 2) After the reset, we read the Mode register and get back 0x174 as per the data sheet.  Our problem is that when we try to do a continuous conversion read operation, fully differential, AIN1(+) and AIN2(-), 0 - 1.28 V, Mode bytes as follows (MSB first)   00110001  01110100, we can't ever get the RDY pin to go low.  Is there a way to check the operation of the chip so see if conversions are being made and put in the data register at all?  I don't think we fried the chip, but we don't have a way to check.  Also, we are using the AD780 2.5V reference.  We could send you code if that would help.

Thanks,

George

  • Hi George,

    Firstly, check your code against the "Pseudo-Code for Looping AD7731 Through Three Fully-Differential Channels", on page 36 of the AD7731 datasheet rev A.

    Confirm the mode register is programmed correctly by reading the register contents back. In Continuous Conversion Mode, the AD7731 is continuously processing data and providing conversion results to the Data Register at the programmed output update rate (as determined by the Filter Register).

     

    Kind Regards, Brendan.


  • Brendan,

         We tried your suggestion with mixed success. We still don't see the RDY pin go low. I've attached our Arduino code and a screenshot of one section of the output of our logic analyzer. We were able to:

    1. Do a reset by writing 32 1's to the ADC.

    2. Read the mode register and get the default/power-up value (0x174)

    3. Write new mode bytes for continuous read, etc. (see comments in code)

    4. Read back the mode bytes and confirm that the write was accomplished

    successfully.

    Can you see our error or perhaps suggest another test that might be helpful?

    Thanks,  George

    /*Arduino sketch for AD7731 ADC

    This sketch assumes the usual SPI pin assignments found at https://www.arduino.cc/en/Reference/SPI

    for the Mega2560:

    MOSI = 51

    MISO = 50

    SCK = 52

    SS = 53

    */

    #include <SPI.h>

    //Set any handy constants and do variable declarations

    const  int  adcRDY = 30;  //Monitor pin 30 to see when data is ready for reading

    byte mode1, mode2, modedata1, modedata2;        //For mode register bits, mode1 is MSB

    void  setup()  {

      pinMode(adcRDY,INPUT);

      pinMode(MISO,INPUT);

      pinMode(MOSI,OUTPUT);

      pinMode(SCK,OUTPUT);

      pinMode(SS,OUTPUT);                   //this is the chip select line, set low to select chip

      pinMode(40,OUTPUT); digitalWrite(40,LOW);    //We're using pin 40 as a trigger for the logic analyzer

      SPI.begin();

      SPI.setBitOrder(MSBFIRST);

      SPI.setDataMode(SPI_MODE3);    //CPOL = 1, CPHA = 0, POL pin on ADC should be HIGH

      SPI.setClockDivider(SPI_CLOCK_DIV16);  //Serial clock frequency is now 1 MHz

      Serial.begin(9600);  //connection to serial monitor for output and debugging

      Serial.println("past setup");

    }

     

    void  loop()  {

      digitalWrite(40,HIGH);  //Start the logic analyzer

      digitalWrite(SS,HIGH);  //Set SS HIGH in case it matters

      digitalWrite(SS,LOW);  //Set SS LOW to select chip

      SPI.transfer(0xFF); //hardware reset with 4, 8 byte sets of 1's

      SPI.transfer(0xFF);

      SPI.transfer(0xFF);

      SPI.transfer(0xFF);

      delayMicroseconds(100);  //just in case the chip needs time to settle out

      SPI.transfer(0x12);  //Tell comm register that next operation is read from mode register

      modedata1 = SPI.transfer(0x00);  // Read first byte from the mode register

      modedata2 = SPI.transfer(0x00);  // Read second byte from the mode register

      Serial.println("Default mode register bytes are...");

      Serial.println(modedata1,BIN);  //print out mode data bytes to serial monitor

      Serial.println(modedata2,BIN);  //print out mode data bytes to serial monitor

      mode1=0b00110001;    //MSB   Continuous conversion, unipolar, no digital ports, 24 bit data,

      mode2=0b01110100;    //LSB  Vref=2.5V, 0 - 1.28 V scale, no burnout, fully differential, AIN1(-) AIN2(+)

      SPI.transfer(0x02);  //Tells communications register that next operation is write to mode register.

      SPI.transfer(mode1);  //Tell it to take the reading as described by mode's bits

      SPI.transfer(mode2); 

      Serial.println("New mode register bytes are...");

      SPI.transfer(0x12);  //Tell comm register that next operation is read from mode register

      modedata1 = SPI.transfer(0x00);  // Read first byte from the mode register

      modedata2 = SPI.transfer(0x00);  // Read second byte from the mode register

      Serial.println(modedata1,BIN);  //print out mode data bytes to serial monitor

      Serial.println(modedata2,BIN);  //print out mode data bytes to serial monitor

      delay(1000);  //sit here a while to see if RDY ever goes low

      SPI.transfer(0x30);  //stop continuous conversion

      digitalWrite(40,LOW);  //reset level of logic analyzer trigger to get ready for next sweep

      digitalWrite(SS,HIGH); //deselect chip 

      delay(5000);  //wait 5 s before looping

    }

     

    319866a4116221178feca71c97ce4d1b.tiff

  • Sorry, but I think there was an error in the comments in the code:  We have CPOL = 1 and CPHA = 1, which does indeed correspond to SPI_MODE3.

  • Hi George,

    Don't see any problem with your code. Can you send me a schematic diagram. How are you driving pin 2 the MCLK IN? And how is the filter register programmed?

    One thing to try. Once the part is programmed to operate in continuous conversion mode, stop the code there and check the RDY pin with an oscilloscope, it should be toggling at the filter register programmed output data rate.

    Regards,  Brendan.


  • Brendan,

         I've attached a diagram showing our connections to the AD7731.  We are pretty much following Figure 21 on p. 39 of the datasheet.  We're using the AD780 to supply the VREF and a 4.9152 MHz crystal across the MCLK pins, with 33 pF caps to ground from each.  On a scope, the MCLK out signal (wrt ground) is a quasi-sine wave with 1 V amplitude with a +2V offset from ground (goes between 1 V and 3 V).  We don't use optoisolators between the Arduino and the AD7731.  The filter register is unchanged from its power up values, which the data sheet says should give an update rate of 600 Hz if my calculations are correct (I haven't yet had the code do a read of the filter register).  I see nothing on the scope or on the logic analyzer to indicate that the /RDY pin is going low at any time in the process.  If I use a DMM to monitor /RDY, I do see a quick few mV drop that seems to be cyclical (remember, the Arduino code continuously loops), but that could be crosstalk from some other line (like the /CS).

    We are using a powered breadboard, which isn't the most quiet of electronic environments, but I hesitate to solder up a board with ground planes and everything if we can't make it work at all under these conditions.

    2441fa37fe78dfa939b5c82be308f798.tiff

    Thanks,

    George

  • Brendan,

        More tests:  I've now read the filter register (I get the default 0x2002) and I followed the pseudocode in Table XIX on p. 36 to do a self calibration.  Still can't see the RDY pin go low with either the logic analyzer or a scope, even after waiting a full second after each calibration (full scale and zero).  I do see some AC noise on the RDY line, maybe 200 mV p-p, lasting about 0.5 s (don't know what event in the cycle triggers the noise).  The logic analyzer is set for 24MHz operation -- is the /RDY pulse so short that we might miss it?  I had earlier tried setting up an interrupt on the /RDY line with one of the Arduino pins (since I think that would react fairly fast), but I saw nothing.  It was done quickly, however, and might need to be done more carefully.  Running out of ideas here....got any more?

    Thanks,

    George

  • Hi George,

    You need to connect the /SYNC, /RESET and /STANDBY to a logic high, DVDD, +5V in your case. A floating digital input can float around or go down to GND. This is known as an "indeterminate logic state". So in your case, the part is most likely in a reset state. There will be no ADC conversion operation but the register SPI read/writes will still work. The most common way to tie digital inputs to DVDD is with a 10K pull-up resistor, as this allows you to tap a GND wire to the pin when required to activate that function, (that is for logic low active functions denoted by the "\" symbol.

    Let me know how it goes,

    Regards, Brendan.

  • Brendan,

          Thanks.  I was hoping it was something simple (in my case, stupid) like that.  It might be humbling, but we can now make progress.  A quick test shows that at least now the RDY pin is going low when it should be.  I'll let you know how further progress goes.

    Thanks,

    George

  • Brendan,

          Things seem to be working much better now, although I think my previous efforts at calibration (since all those pins were flopping) gave us some bad calibration register settings.  When we do an internal zero or calibration, do we need to make sure that the pins (AIN1 and AIN2) don't have anything connected to them, or does the chip do something internally to isolate those pins during the calibration?  We're getting data now, but the value is incorrect because of the bad calibration settings, so we need to do a zero and then an internal full scale calibration.

    Thanks,

    George

  • Brendan,

         Any guidance on our last question?  We assumed that we could do internal calibrations with external voltages connected to the input pins, and we do see the offset and gain registers change, but we're still getting the wrong voltage value.  We're feeding in 0.628 V and we're getting 0.141 V from our reading.  We'll keep checking things, but some more experienced advice would be helpful.

    Thanks,

    George