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.

  • TI Thinks Resolved

ADS131M04: Help with sample code

Prodigy 200 points

Replies: 34

Views: 267

Part Number: ADS131M04

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

  • In reply to 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?

  • In reply to David Taliaferro:

    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

  • In reply to 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...

  • In reply to David Taliaferro:

    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

  • In reply to 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.

  • In reply to David Taliaferro:

    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.


  • In reply to David Taliaferro:

    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?  

  • In reply to David Taliaferro:


    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

  • In reply to 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!

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.