>Working, with library!< Interfacing ADS1213 22-bit ADC

I was very interested to find this thread, as I have been playing around with the Linear Tech LTC2440, a 24-bit sigma-delta ADC. The best I could do using a SSOP->DIP adaptor on a solderless breadboard with everything inside a metal can, was about 500 nV rms noise, while the part is spec'd to 200 nV rms (at the maximum resolution, 6.9 Hz output rate). I've been tempted to just buy the LT2440 demo board to verify that is true. Their board is a 4-layer PCB with 2 oz copper and laid out very cleanly, but can't justify the $50 price just for the curiosity.

At the time I was looking around, the LTC244x family had the highest true dynamic range I could find, with 24+ bits of resolution advertised at the slowest output rate. I found when looking closely at the data sheets that "24 bit" converters from other vendors are often not true 24 bits, with one or more LSB of noise even in the slowest and most accurate modes.

Hey Murdock,
I was wondering how deep into the code your clock calculations go. I was wanting to not use the internal clock because Mark Thoren, that I mentioned earlier from linear technology, told me that if your clocks are at the same frequency then the adc will pick up noise from the other devices. I would prefer not using the arduino clock for that reason. I am worried in your code the clock speed affects how the the arduino sends and recieve data.

I also looked at the multiplexing chanenls because I wasn't sure if it made you reset the oversampling each time, nor did I know the different chanel schemes. They are on page 13 of Mixed-signal and digital signal processing ICs | Analog Devices.

In order to change the speed/resolution or input channel, the first three bits shifted into the device are 101. This is compatible with the programming sequence of all LTC multichannel differential input ?? ADCs. If the sequence is set to 000 or 100, the following input data is ignored (don’t care) and the previously selected speed/resolution and channel remain valid for the next conversion. Combinations other than 101, 100, and 000 of the three control bits should be avoided. If the first three bits shifted into the device are 101, then the following five bits select the input channel for the following conversion (see Tables 3 and 4). The next five bits select the speed/resolution and mode 1X (no Latency) 2X (double output rate with one conversion latency), see Table 4. If these five bits are set to all 0’s, the previous speed
remains selected for the next conversion. This is useful in applications requiring a fixed output rate/resolution but
need to change the input channel.

I am trying to interface with ADS1211 ADC IC. I am currently using Cypress PSoC 1 MCU. Is the code for the Adruino comapatable with Cypress? The Cypress internal ADC was not accurant enough for the application.
I just want to use the SPI to read voltages to my Cypress MCU.

I am currently using Cypress PSoC 1 MCU.

I don't often stop in the Chevy dealership to ask questions about my Harley.

Why are you here?

I thought I could find some smart people. But I guessed wrong.

hey,
I want to use geophone sensor with this ADS chip.
The output of the sensor is AC voltage varying in the amplitude
It has 2 terminal, positive and negative
How to connect its terminal to ADS1213 input??

should I connect its positive terminal to Non-Inverting Input AND its negative terminal to Inverting Input ?
or
positive terminal to Non-Inverting Input AND negative terminal to GROUND ?

I am a newbie here.

How to control the Multiplexer inside ADS1213 ??
I want to use 4 geophone sensor with 1 ADS1213
How much is the maximum frequency of ADS1213 multiplexer ??

Thank You

People seem to have trouble with Arduino 1.0. That's because they changed the standard Wiring.h library to Arduino.h. To make any library compatible with both previous Arduino versions and version 1.0, the following needs to be done:

Replace this:
#include <Wiring.h>

By this:
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

The new version of the library (with this changed) which is therefore compatible with Arduino 1.0 as well as previous versions, is attached to this post.

ADS1213.zip (1.03 MB)

Hello,

trying to use ADS1211P with Murdocks' library, but keep receiving zeroes :frowning:

I am reading the values from load cell and displacement tranducer, which output 0 to 5 V.
Tried single input as well as differential input without any changes :frowning:

I used 10Mhz crystal, as in datasheet Figure 12 they were using the 10Mhz crystal as default for examples, with turbo mode 1, and gain 1.

Can not figure out what am I doing wrong?
Also, there is no mentioning in Murdocks' readme file about sdout pin from ads1213. Doesn't he use it?

the figure 12 from the crystal is attached to the message.

figure12.png

Hi V_king,
I don't use the SDOUT pin because the SDIO pin can be used as both an input and output pin. If you look in the code and check out the 'read' function, you will see this line: DDRB &= ~_BV(_IO);
That sets the DDRB (data direction register) to input for the specified _IO pin. _BV(_IO) can be substituted for 1>>_IO. If you want to know exactly how it works, learn more about bit math and port manipulation.

I don't know what is wrong with your setup. Obviously, the communication with the ADS1211 doesn't succeed. Try using lower clock values, maybe that'll work. And try to write to and read from non-critical setting registers within the ADS1211. Try reading first.

Hello Murdock,

thank you for the repy. The code in your first posts make some sence with register writing, but when I opened the library, the code is out of my league :slight_smile:

Found some info in arduino site about bit math and port manipulation, and will try studying that. thanx for the reference.

EDIT:
Rebuild the circuit again, and got the chip working. might need new prototyping board :frowning:

Getting stable 16 bit, 1000 Hz results at tmb 8 and dr 77. there is quite a bit of noise though :frowning:

I wonder if anyone could suggest any cicuits for unipolar single ended sensors input to this differential adc? should I just simply ground the inverting pin? or maybe someone has tried and tested op-amp circuit (i am novice with op-amps).

hello everyone,

been busy reading datasheets and thinking of using TI external voltage reference like REF5025, hopefully to reduce noise.

Played with settings and simple RC filter( 10k resistor and 0.2 uF capacitor seems to work best), at the moment I get 2 mV fluctuation, reading arduino 3.3V output. I need at least 1mV accuracy and 0.5 mV would be perfect.

Also I wonder if op-amp on each channel would improve the signal quality?
There is a reference circuit in the TI REF50XX voltage reference datasheet, for data acquisition, attached in the file. They use OP365 opamp to filter the signal.
Those OP365 op amps are quite expensive (around £4 each :frowning: ). Don't feel like cashing out to find out that they are useless. Maybe there are cheaper alternatives?

Nn the other hand, the whole circuit is on breadboard, near the computer, so it might be picking up the noise from surroundings ?

Finally, ramped up the sampling rate up to 100 kHz (using delayMicroseconds(10) ) and it looks like the results are more stable. Or is it just the same readings being shown? :slight_smile:

opa365.png

Murdock's library is obviously wrong. If you try to use the set clock function, it does not operate at 2 MHz. It operates at 8 MHz which is the wrong timing for ADC.

Great that you have taken the time to look through the code and seem to have found a bug, but please elaborate. I cannot find a fault in the code.

Datasheet pages 22 and 23 list the desired serial clock frequency, which is a maximum of 1/10th the clock speed. I try to achieve that by using delayMicroseconds() to delay the write and read code. The whole code takes a bit longer in reality but this method makes sure that the code is never faster than the ADS1213.

This code (from the initalization routine) calculates the desired delay in microseconds for half a clock cycle (the cycle is delayed twice: once for clock high, once for clock low):
int _tscaler = (clockspdMHz)10;
byte _SCLKdelay = 5
10/_tscaler+1;

clockspdMHz is a float which is given in the initialization routine. If you give 2.0, _tscaler will be 20. _SCLKdelay will then be 3, giving a maximum SCLK frequency of 166kHz.

So I don't see what you mean, it doesn't run at 8MHz. If you use the ATMega's built-in SPI (= TWI) hardware, then it runs at 8MHz standard. My code doesn't use that.

I realize this is an old thread at this point and I hope some are still following it as I have a question about interfacing with an ADS1211. After reading through several posts including this one, I am trying to use the library Murdock posted on Apr 19, 2011 (ADS1213) to log data from a geophone. I've read through the spec sheet for the ADS1211 several times and think I have a beginners handle on how it works.

I followed the wiring diagram from the first post on this thread, including using the arduino's internal timer but all I get out is a bunch of 0's. I also tried to follow nadabro's post (Arduino Forum) as he is working with the same sensors and ADC. Is there anyhting that I might be missing? I would like to use the internal clock instead of an external crystal if possible but if that is my problem please let me know.

I'm sure you need more information to help me so please let me know what you need. Right now my code is the example code for switching channels in the library (I like to start with the examples until I understand them enough to change them for my needs). Thanks for any help you can provide.

Hi dkolbay, the latest version of the library (compatible with Arduino 1.0) is here (from the march 28th 2012 post up there ^).

With these kind of problems, it's always wise to take a step back in order to analyze the problem, then determine the simplest test possible, and then try to get it working.

Yours is obviously not working correctly or it wouldn't be spewing out zeroes. There can be problems somewhere in the communication, but the most obvious problem is that the clock signal (not serial clock) you are feeding to the ADS1211 is not correct. But let's first devise a simple test, as your sketch right now involves multiple write and read operations, too many opportunities for errors.

The simplest test would involve as few operations as possible and as simple feedback as possible. This could be 1) writing to the command register that Vbias must be on, making Vbias output some voltage and 2) reading this voltage with an analog Arduino pin. You can make a sketch to do this test and make it output a victorious message when the test succeeds.

If you want to feed a clock signal to the ADS1211, you'll have to configure one of Arduino's timers to do so. Timers are quite simple pieces of hardware, they simply count and when they reach a number, they do something. You can read all about it in the Atmega328's datasheet (it might seem overwhelming but keep in mind that timers are very simple devices, albeit with many configuration options). What you want is to 1) take a timer that controls a port that is not used by the library and 2) make it produce a square wave (thus output 0v and 5v with equal periods).

So if you have the test sketch that outputs a square wave to the ADS1211's clock input, writes to the command register and sets the Vbias high, and then reads the Vbias voltage on an analog Arduino pin, you can hook everything up and start testing. If it still doesn't work, you only have a few things to check. If it does work, hooray, and you can start expanding the code to fit your needs.

I dug in my sketches folders and found some code to output a square wave on a pin using a timer, I use it for producing tones with a speaker. The .h file (it's just a C file, you can open it with the Arduino IDE) contains the functions that set the timer and set tones. The .ino file houses an example sketch. It does a lot of direct register manipulation using bit math. The constants like "TCCR2A" that you see in the code are defined in the avr/io.h file (Arduino includes it automatically I believe), they are simply bits of code that write or read a register (in the "TCCR2A" case) or define where a port bit is in the register with a number between 0 and 7 (in the "OC2A" case), and _BV(n) is function that shifts a binary 1 n places to the left (1<<n).

I hope this helps you solve the problem, and if not, come back here with some more details.

Hey Murdock,

I've also been trying to use the library and the wiring diagram that you provided in the original post. The library I'm using is the one from March 28th, 2012 so I know it's compatible with Arduino 1.0 software. The problem I am having is that the code seems to get stuck on the constructor portion of the code and I've found that it starts to fail at the point when defining the high/low instructions for the data ready portion.

I believe be code is something like while(!(PIND & _BV(_DRDY))); - don't have the code in front of me as I'm typing this so typing from memory. I've measured the voltage coming out of the data ready pin and its low until the serial monitor is brought up and then it jumps up to high which I assume is fine. I'm not sure why the constructor is failing at that particular point and was wondering if maybe it has to do with where the data ready pin is located? I've set the data ready pin to 4 on the arduino so I know that it falls between the constraints you have in the constructor and can't for the life of me figure out why it won't go past this point in the constructor. Any help would be greatly appreciated.

Some basic information:

  • wired it to the same wiring diagram you provided earlier with the crystal in being located on pin 3
  • data ready pin 4
  • IO pin 10
  • Sout pin 12
  • Sclk pin 13
  • CS pin 8
  • Running the standard deviation example you provided running into noninverting channel 1 and grounded the inverting channel 1
  • "Debugged" by using the pin 13 LED to turn on and just went through section by section.
  • haven't gotten to the rest of the code thou because the constructor is failing right now and therefore can't go beyond that point.

Hi MrInternet, good that you're debugging step-by-step. There is no while loop in the constructor itself, but it does call the 'write' function to write the settings to the register. The while loop in the write function looks like this:

  while (!(PIND & _BV(_DRDY)));  // wait for ready to go high
  while (PIND & _BV(_DRDY));     // wait for ready to go low

It is in there to make sure that you're writing to the register at the beginning of a 'low' DRDY period, because if you're only starting to write at the end of the DRDY period, it might end before the commands are written.

I don't understand why invoking the serial monitor would have anything to do with the DRDY pin of the ADS1213. Invoking it just restarts the Arduino.

It seems that you're having the problem that the DRDY pin is not following the standard pattern of high/low, it must be high or low all the time, resulting in the statement within the while loop always being true, thus causing an infinite loop. However, if the ADS1213 is functioning correctly, the DRDY pin will go high/low in a certain pattern (which you can find in the datasheet).

You have been debugging down to a basic level: you've been testing a simple case of communication between the Arduino and ADS1213. But as the DRDY pin of the ADS1213 might not function correctly, it's wise to check if the ADS1213 itself is even working properly, there might be a problem with the crystal for example. So what you can do is write a simple script for the Arduino that polls the ADS1213's DRDY pin and then tells you something about the signal, like how many times it went high/low in the last second. Then, you can see if the ADS1213 is working or not.

Thanks for the response,

I was testing the DRDY pin at the exit from the ADS itself and was noticing that it would be low, which would indicate data being ready, until I opened the serial monitor itself which would force the DRDY pin to go high, Data not ready, and stay there. This wouldn't change according to a normal pattern and would just be a single fluctuating (a couple of millivolts) value. I did try changing out the ADS1213 to make sure it wasn't an issue with the pin itself and thankfully the other ADS had the same issue.

I'll make sure to check that the crystal it properly working as well because that may be the issue. Thank you again for your response and for the library.

Hi,

First of all, thanks for all your work you put into this.
I am trying to use this library with a ads1211 and a arduino mega 2560, but no luck so far.
Basically I'm connecting the ads1211 as shown here and using the channel shift example sketch that comes with the library.
I am using Pin 13 and 11 for SDIO and SCLK, and Pin 20 for DRDY.
I am using a 2MHz crystal and have also tried 4 and 8 MHz too.
My problem is that it doesn't do anything, the sketch stops at the CMRwrite command (as it doesn't print "done with setup").
Does the library work with the Arduino mega 2560 and the ads1211?
If yes, what could I be doing wrong?

Greetings,

Tillman

chillman, I'm curious if you ever got this working. I'm getting the same symptoms when trying to interface an ADS1211P with a UNO.

Connected exactly as per Murdock's other thread. Sometimes the Uno won't even get as far as "ADC_ext.CMRwrite(3,B001,1,16,300);", I put a println in before it to debug where it's locking up, and it seems to happen fairly regularly when running "ADS1213 ADC_ext(2.0,true,13,11,2,5);".

I put the include and the above line into a blink sketch, and it froze that too. Pin 13 never sets as output.

I don't have the necessay skillset to debug any further, hopefully someone else has seen and fixed this issue.