This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS131M04: Help with sample code

Part Number: ADS131M04
Other Parts Discussed in Thread: MSP432E401Y, ADS131M08, ADS1115

I'm trying to get the ADS131M04 working with a Raspberry Pi.  I have your sample code, and ported the hal.c to the pi environment.  Right now I'm just trying to see if I can read the ADC channels.  And nothing seems to be happening.  When I call the readData() function in ads131m0x.c, the structure returned is all zeros.  It could very well be that I'm doing something wrong...  Do you have any advice for troubleshooting?  Or do you have any sample code that actually does something?

My code is calling initADC() (with InitGPIO(), initSPI(), and adcStartup() in hal.c implemented In hal.c), then calls readData() in an attempt to get ADC data from the 131m04.  Is there anything else I'm supposed to do before reading data?

  • David,


    The example code was tested on an MSP432E401Y, but I'm not enough of a coder to really know the differences between that MCU and the raspberry pi. The readme file in the example code does have some limited hints as to what to alter for different controllers. Library references should be added in hal.h for any processor-specific library files. The function implementations go in hal.c, including the raspberry pi's SPI peripheral.

    Normally, I would check to see what's happening from the device side of things. I would use an oscilloscope or logic analyzer to see what clocks are making it to the device and what data is going into and out of the device and raspberry pi. I would also verify all my connections and ensure that the device and the controller have a common ground.

    Check the digital inputs and outputs with a scope or logic analyzer and post the results back here. I'd want to see the transmission of full SPI data frames, with enough resolution to see the data words going back and forth.


    Joseph Wu

  • I'm still struggling with this.  Unfortunately, I'm not set up to analyze the SPI communication with a logic analyzer.  But I need to see if communication is working.  So again, I'm trying to read data with the readData() function in ads1310x.c.  And I'm getting all zeros.  I have AIN0P connected to 3.3 volts, and AIN0N connected to ground.  I'm expecting to see a non zero value in the structure returned by readData().

    How can I verify that SPI communication is happening?  Is there some simple handshaking test I can do, like reading a register?  What should readData() return?  The example code doesn't seem to do any error checking on data returned via SPI, so it's hard to verify that the code works and that I have the correct connections.  The code actually seems to run fine with nothing at all connected to the controller via SPI.  Shouldn't there be some error checking?

  • David,

    You could certainly read a register. After the device is powered up, the registers would be populated with the default (reset) values. For example, a read of the MODE register (address=2h) should return a 510h as the default value. Note that this command takes two communication frames, as shown in Figure 45 in the datasheet.

    However, I highly recommend using a logic analyzer or oscilloscope to look at all the SPI lines. This is what I would think of as the error checking that you were referring to. You should be able to see the signals, verifying that the SCLK is clocking, and that the DIN and are clocking in the values on the falling edges. On top of checking the communication, you should also look at all the other lines, checking that AVDD and DVDD are at the proper voltage, and that the /RESET is set high.


    Joseph Wu

  • Ok, I've made a little progress.  It turns out that I indeed hadn't configured SPI correctly.  I am now able to send and receive data over SPI. Sort of.  The data I read is gobbledeygook.  I tried reading the mode register and it's 255 (0xFF).  When I read ADC data with the readData() function, the data is garbage.  And the CRC check fails.  Question - why was CRC checking commented out in the ads131m0x.c?  That's the kind of error checking I'm talking about.  The code has a compiler #define to enable/disable CRC checking on writes, but the CRC checking on reads isn't enabled with a compiler flag, it's permanently commented out.  Doesn't seem right to me...

    Anyway, I did have a logic analyzer available and I connected it to the SPI lines and I do see communication happening.  But I'm not able to read meaningful data.  Suggestions?  I'm using the startup sequence from the TI code in ads131m0x.c and hal.c, so the startup sequence is presumably correct...

  • David,


    First, there's a small problem in the example code for the CRC calculation. The ADS131M0x is capable of using the CCITT polynomial or the ANSI polynomial for CRC. I believe that the polynomials were swapped in the code. You should be able to check these polynomials and verify that you're using the correct one.

    Using the logic analyzer is very good debugging tool in determining errors in the SPI communication. Even if the data you're getting isn't making sense right now, you should be able to see the lines move with as a response to the SCLK and DIN.

    My first test would be to read a known register. For example if you read the MODE register, you would read 0510h as the default setting. In this debug, it's important to have a test for which you know the response. Once you're able to send this command can you please post the device response? It'll be important to see the frames where you write the RREG command and then the following frame get the proper response.


    Joseph Wu

  • Thanks again for all your help.  Can you elaborate on how I check the CRC calculation?  The code defines CRC_CCITT in ads131m0x.h.  So it's set to use the CCITT version of the code.  Are you saying that it should be using the ANSII version?  Or that the code for CCITT is wrong and it's doing the ANSII version when it "thinks" it is doing the CCITT?  Which is the default for the chip?  And again - why is the CRC code commented out?

    Also, you said the MODE register should be 510.  The code has a constant, DRDY_FMT_PULSE, defined.  This forces it to "or" the mode bits with MODE_DRDY_FMT_NEG_PULSE_FIXED_WIDTH, changing the mode bits to 511h.

    But I don't think either of these things would explain my problem, but please answer my questions above if you can...

    When I start up, I toggle the reset line, and then try to read the mode register, using the TI code.  It gets 255 (FFh) as a return value from the readSingleRegister() call.  If I then try to read the spi channel in a loop, waiting for it to not have anything in the buffer, the loop never ends.  It seems like the chip is pumping out data as fast or faster than I can read it.  And since I'm reading it from compiled C code, I wouldn't think that could happen...

    So does that answer your question?  Reading the mode register returns a response of FF.  Or are you asking me to send you screenshots of the oscilliscope output?  Not sure if I can do that but I could try...  To be honest, I'm not too familiar with my oscilliscope (MSO-19), and the documentation is terrible.

  • Ok, I was able to get a capture from my oscilliscope, for what it's worth.  Below are the translated SPI bytes according to the oscilliscope, and a screen capture of the oscilliscope screen.  I'm running with both the SPI clock and the data clock at 1MHZ.  If you could also answer my questions from my last post, I'd appreciate it.


  • More questions...

    What would the recommended values be for the ADC clock and SPI clock?  I'm confused about this.  The datasheet says the max sample rate is 32ksps.  But it says to use an ADC clock rate of 8.192 mhz.  Why isn't the ADC clock 32 khz?  And for the 32ksps rate, what would a good value be for sclk?

    Finally, unix on the rpi is not a realtime operating system.  My intent was to sit there and do reads continuously, but I can't be sure that my process won't get interrupted in the middle of a read.  So it seems like it will be hard to keep my ADC reads in sync with the sclk timing pulse.  So I'm thinking that I will need to poll the DRDY pin and do my ADC reads when DRDY goes low (or is it high?), and also will need to use the CRC checking on my reads.  Then if a CRC fails, reset the chip and start again.  Make sense?  


  • David,


    Sorry, but I've been busy with other support for the day.

    The CRC calculation is transposed from the CCITT to the ANSI version, what happened was that the polynomials were swapped in the code (it's written correctly in the datasheet. This was recently brought to our attention in this post:

    https://e2e.ti.com/support/data-converters/f/73/t/909157

    If you're using the code and want to use the CCITT CRC, then use the ANSI polynomial in the code. I'm not sure why the CRC section was commented out in the example code.
    However, I would start your code by disabling the CRC and then enabling it later. By disabling the CRC, you could verify writes and reads, without the device ignoring the commands.

    I didn't know about the MODE_DRDY_FMT_NEG_PULSE_FIXED_WIDTH setting, but regardless, you should be able to read the register and basically know what the register should say. You can use this as a starting point to try to figure out what is coming out of the device.

    Looking at your scope capture, I was hoping to see two complete SPI frames. The first would be the read register command similar to Figure 41 in the datasheet. If your word size is 24 bits, the RREG would start with B2 00 00 (for one register) and then the CRC word. At the same time DOUT would still clock out all frames as if there is data. This would be the response from the previous frame, then 8 channels of data followed by the CRC.

    The second frame would be the register data, and you would again clock DOUT all the way through. If you have the scope you can view the /DRDY and see that it returns high at the end of the read of Channel 7.

    The recommended master clock is 8.192MHz, this is because the ADC is repeatedly taking samples of the input voltage at 4.096MHz (master clock/2) and it takes many samples (given as OSR) to create one ADC conversion data. Ideally, you would want to clock out all of the data within one data period. You would need to easily need to clock out 24*10 bits for every 31us. Because of this you would need at least an 8MHz SCLK.

    However, this readout may be more complicated because your controller might read data, then go away and do something else, and then come back. Because the device has a two unit FIFO, there may be some reading problems as described in section 8.5.1.9.1. Generally you need to read out every available data or you may need to read the data twice to clear the FIFO.


    Joseph Wu

  • I was finally able to get this working yesterday.  My main problem was that I needed to use an SPI api that does the send/receive concurrently, rather than sequentially like the example code appears to do.

    Why don't you guys fix the sample code to do the correct CRC  calculation?  It's only a change to two lines of code.  I'd also strongly suggest putting the CRC code back in (uncommenting it out, and possibly adding some if statements to select it if enabled).  I  It's the default behavior for the chip, and is very useful to make sure that you're reading data correctly.

    The ADC values I'm getting are somewhat reasonable, but seem a bit off.  I will play with it some more and see if I can figure out the issues, and will post back if not.

    Thanks again for all the help!

  • David,

    I'm glad you were able to get the code working. I've already mentioned the fix for the CRC to the engineer that wrote the code, but he's currently working on other projects. We'll try to make the change soon.

    If the values of the measurement appear a bit off, there are plenty of ways to debug that too. Keep in mind that any reference error appears as a gain error. You can use a precision multimeter to measure both the input signal and the reference voltage to get a measurement of the true gain error. Also be aware that the input currents to the ADC may add errors if there are large series resistances or if the measurement source has a high output impedance.

    Joseph Wu

  • I am not getting the expected 32K sps.  I have a master clock frequency of 8.192 mhz, verified on my oscilliscope.  My SPI baud is 16.66mhz, also verified on an oscilliscope.  My code is a simiple loop, reading the status register (to get adc conversion data), over and over, and it counts each time the data ready bits go high.  Using this, I am getting 4ksps.  Shouldn't I be getting the full 32K?  I see many references in the datasheet to a 4ksps sample rate, but it appears that I should be getting 32Ksps with the 8.192mhz clock.  Am I missing something?  Is there a register to set the sample rate, that I need to set?

  • Joseph - I didn't see your last response until after I sent my post above.  So those questions still stand.  But regarding your last post - how do you measure the reference voltage?  I don't see a pin that shows that.

  • David,

    The data rate is variable depending on the OSR setting of the device. With the nominal master clock frequency of 8.192MHz, the fMOD frequency is 4.096MHz. After that the default OSR setting is 1024, which sets the data rate to 4kSPS. The data rate is described in Table 4 of the datasheet.

    I'd note that the device is set for High Resolution for the Power Mode.

    Joseph Wu

  • Thanks!  That did the trick.  I have to say, though, that the datasheet could be clearer.  The term "OSR" is mentioned several times before it is defined.  And it would be nice if it stated what the default setting was, in the various tables such as table 4 above.

    So I'm sure I will have more questions, but for now everything seems to be pretty much working.  The only thing I still wanted to know was how you measure the reference voltage, as you discussed above.  Is that available on one of the pins?

  • David,

    There are definitely times when the datasheet can be confusing. However, the part in itself is a complex device. It's not a simple process to get it working.

    For the internal reference, I think you can just measure the REFIN pin with respect to GND. If the internal reference is enabled and being used, I believe that the connection goes to the outside world. You can see it from the connection in the functional block diagram:

    Regardless, I hope you're able to work with this device. Let me know if you have any other questions.

    Joseph Wu

  • REFIN pin?  I see no such pin.  Are you talking about the ADS131m04?  I was thinking maybe the CAP pin, but I'm seeing 1.7 volts on that.

  • David,

    Sorry about that, I'd lost track that you were using the ADS131M04 and not the ADS131M08 which does have a REFIN pin.

    Joseph Wu

  • Joseph:

    I have a new problem that I'm hoping you can help me with.  The ADC readings I'm getting are not quite right.  The error is in the neighborhood of 2%.  For example, if I feed the ADC a constant voltage of .500v (as measured on my multimeter), the reading returned is 3,576,751.  If my math is correct, that translates to a voltage of .512v.

    (3576751 / 7FFFFFh) * 1.2 = .512

    I have the .500v voltage connected to pin 7, and pin 8 is connected to ground.  I have not changed any calibration or gain settings from the default.  Any idea why I'd be having this issue?

    Thanks.

  • David,


    There are a couple of things that could cause this type of error.

    First, are you using a precision multimeter? I'd make sure that the error of the meter isn't a big factor. If you're using a low-cost handheld, then the error might be in the 1% range.

    If you have series impedance on the front end, this may also cause a gain error. The input impedance of this ADC is about 330kOhms, and a 1kOhm resistor on one input would cause about a 0.3% gain error. However, this isn't is your problem, because this would make the measurement appear smaller, not larger. I just mentioned this just in case it comes up later.

    There may also be some offset in your measurement, this could be from some ground loop in your system, or a measurement where the source ground isn't directly connected to the ADC ground.

    If you have an adjustable source, you may want to make measurements with several different input voltages. You can use this to discern if this error is an offset error or a gain error.

    Can you share a schematic of your setup? I'd also like to know what you're using as the source voltage and how you have it connected to your board. More detail could help in debugging this problem.


    Joseph Wu

  • I'm using a Fluke 117 multimeter.  Should be accurate.  This project is an upgrade to an older project, using the ads131m04 to replace an ads1115 adc chip, with which I had no such errors.

    For the test voltage, I have a potentiometer against a 1 volt input going to the same ground that the adc is connected to.  I tested against many output voltages of the pot, and consistently get a 2-3% error, vs what the Fluke reports, both going to the same ground.

    I can try to put together a schematic of my setup, but it's basically the recommended circuit from the datasheet, with the caps, etc recommended.  My VCC is 3.3 volts from a Raspberry Pi.

  • David,

    What resistance is the poteniometer?


    Joseph Wu

  • The potentiometer is 10K ohms.  (10,170 ohms, to be exact)

  • David,

    Ok, that's fine. I was worried that it was up in the 100kOhm range and that represents a large series resistance that could cause problems with settling for the input sampling capacitors. 

    For now, I'd concentrate on two things. First get a schematic together with a description of the source you're using to generate the input voltage. Then why don't you measure input voltages from 0V to 1.1V in 0.1V increments. Make sure that you measure the input voltage back with the multimeter. If you can, try to get something better than a handheld meter. For 16 bit ADCs, I'm comfortable with the Agilent 34401A meter because of the accuracy and linearity, but for most precision measurements, we use the Agilent 3458A.

    Joseph Wu

  • Ok, thanks. I’ll do some more readings and send to you. I did do quite a few readings and consistently had erroneous values, but I’ll document the readings for voltages from 0 to 1.1 v.

    I’ll do the schematic too.

    But sorry, I’m not going to upgrade my multimeter. I don’t believe multimeter inaccuracy could explain what I’m seeing.

  • Edit: I posted some erroneous data earlier.  Below is what I'm seeing.

    Multimeter ADS131M04 Raw Converted Error %
    0.000 FFC1BA -0.00228  
    0.100 0AE559 0.10212 2.1%
    0.200 160F7B 0.20676 3.4%
    0.300 20CF2D 0.30756 2.5%
    0.400 2BB49B 0.40968 2.4%
    0.500 36475A 0.50892 1.8%
    0.600 40EED1 0.60876 1.5%
    0.700 4BB788 0.7098 1.4%
    0.800 566393 0.80988 1.2%
    0.900 60ECB5 0.90864 1.0%
    1.002 6AFC00 1.00296 0.1%

  • David,


    Sorry I haven't responded. I've been busy with several other customer support issues, and I haven't had a chance to circle back to yours.

    There are a couple of different things to try, but I'm not sure what it is that is causing the error. Part of the problem is that you're setup isn't the most precise. I would generally start with cleaning up what you have.

    First, do you have any kind of adjustable power supply? I'm not sure how clean your raspberry pi supply is. If this has some sort of noise, then perhaps this is coupling into the power supply so that the ADC and multimeter measurement are different. Additionally, this applies to the input signal too. The input signal is basically a voltage divider from the 3.3V supply, so any noise on that, will be on the inputs as well. It might be better to use a voltage divider from a battery instead. At least that would be better. Another issue is that the way you have the pot set up, it's output impedance varies with the input signal. That normally wouldn't be too much of a problem because the impedance isn't excessively large, and you also measure back the voltage.

    I'm guessing that your 5V supply comes from some sort of wall plug. That in itself might have some sort of line cycle noise that going through your system that might be picked up differently between the ADC and the multimeter.

    The data you provided looked like the multimeter was a lower measurement by anywhere from almost 0 to 3.4 percent, but there was more variation at the lowest two measurements which looks like some non-linearity. I would think this is from some meter auto-ranging, and the meter goes from one gain error to the next, but the gain errors are large. Again, this could be a problem with periodic noise being picked up differently by the ADC and the multimeter.

    At this point, this seems more like an input issue rather than something systemic like power. I would focus on getting a cleaner signal to measure. Again, a battery might be significantly better than a power supply.


    Joseph Wu

  • David,

    One other thing that I forgot to mention in the previous post was, try a long set of measurements. Try collecting about 100 or 1000 points and see what the noise performance is. Post the results in an excel spreadsheet. You might see periodic noise, and that might give a clue that the ADC and multimeter are reading something different.

    Joseph Wu

  • I am waiting to get a voltage regulator so I can try powering my circuit with a battery.  In the meantime, see the attached.  This is 100 samples where the input value is .200v.  One interesting thing is that the first sample is always much higher.  I collected the data multiple times and consistently see this.  Any idea why?

    noise.xlsx

  • David,

    Just so that anyone reading this post can see, here's a plot of the data:

    I'm not sure why it's starting off high, but there is some settling after starting to take a measurement. The ADS131M04 uses a sinc3 digital filter, which is basically a 3 unit moving average filter. Because of this, it takes 3 data periods for the ADC to settle. Also, the ADC does have it's own input impedance, so if you start taking data, there might be a small amount of input current that affects your divider.

    Joseph Wu

  • Ok, here's the spreadsheet with the circuit powered by a battery.  The error is better, but still high.  Any suggestions?

    1854.noise.xlsx

  • David


    Depending on how you make the measurement, the input impedance of the ADS131M04 might be a factor on the lower reading. From your last excel file, your error was -0.78% based on the average reading. I'll show a screen shot here:

    If you're still reading voltage divider from the 10k potentiometer, the you have something like this when you're looking at it with the DMM:

    I'm assuming that you have a 1.5V battery as the source. The DMM has a relatively high input impedance. The input impedance is likely greater than 10MOhms, which wouldn't affect the output of the divider. When this pot is set to output 200mV, this will still be 200mV with or without the multimeter attached. However, once you connect the ADC, the ADC itself has an input impedance that loads the divider. The input impedance of the ADS131M04 is only about 300kOhms, which now makes the circuit look like this:

    Because of the ADC loading, the output now looks a little low. You can calculate the equivalent parallel combination of the ADC input impedance and the lower part of the voltage divider. However, the output of the divider comes to something about 0.19923V. That's about -0.39% low and it's about half of the error that you're seeing from the excel spreadsheet. The remaining error is about the same which comes to -0.39%.

    In comparison, the total error of the DMM is about 0.5%, and the error of the ADC is about 0.1%. At this point, you won't be able to discern which error is which. In one of my earlier posts, I mentioned that you would need a better multimeter. I have the benefit of using a multimeter and a good precision source when I need it. I think these are really important tools to get the best precision out of the design. For your setup, it's good for some minor debugging, but if you need to get more exact measurements, you'll need both the precision multimeter and source. I had originally suggested the battery as a driver, but you might need something buffered to prevent the loading of the ADC. 


    Joseph Wu