Show Posts
Pages: [1] 2
1  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: May 16, 2013, 04:51:24 am
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:
Code:
  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.
2  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: May 01, 2013, 05:34:02 am
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.
3  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: August 25, 2012, 05:43:51 am
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.
4  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: July 16, 2012, 05:33:49 am
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.
5  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: March 28, 2012, 10:09:58 am
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.
6  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: July 19, 2011, 11:22:30 am
Mike, I'm using the Freescale sensors. For pressure I'm using the 6115. It's available in many different packages, I use the smallest (SSOP I believe). It's perfect for measuring atmospheric pressure. For speed I'm using the 5010 dual port.

Brock, that LTC2442 looks great too. I think they won't differ much as both companies produce great ADC's. Though I believe that its multiplexing mode sends values of all channels in order and can't be set to one channel, though I haven't read through its datasheet yet. The great thing about TI's ADC's is that they can be set to one channel, then get some 100 values from it and set it to the next channel. This way you can get more accuracy from some channels by sampling them more.
The code should indeed be easily adaptable to the LTC2442. I made my own board using Eagle and toner transfer as well, my first board was double sided and right the first time. Toner transfer is really awesome and easy.
7  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: July 09, 2011, 02:11:00 am
marioR, thanks! No problem.

TI's ADS1211 is indeed better than the ADS1213. I only saw that after ordering the 1213. However, for my latest project, I chose an even better one: the ADS1256. Soldering it will be quite hard because it only comes in a SSOP package but it should be manageable. I eventually want to make a library for it as well. It features 30kSPS, 24 bits and low noise.
8  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: May 04, 2011, 11:54:24 am
I just uploaded the bugfixed library I talked about earlier. Took a while but I have a good excuse: I was learning processing by making an educational game: www.flyingstyro.nl (temporary link). I study aerospace engineering and it's fun to play with orbital mechanics and Hohmann transfer orbits in an interactive way.

Also, I expanded the processing application to show max/min window values and incorporate low-pass filtering. With a Freescale MP3H6115A pressure sensor I am able to sense a difference of 10cm in height (using the lowpass reference line of course) and to sense ones heartbeat by placing a thumb on the sensor.

Looking at the numbers while playing with the pressure sensor, the resolution when using a low-pass filter with a value of .005 and ADC settings of about 1000SPS seems to be about 16 noise-free bits. I am designing a PCB for the ADS1213, 2 pressure sensors and a temperature sensor, as well as an integrated 'duino. It will have a quad op-amp to invert the pressure and temperature voltages and be battery-fed. I expect the resolution to increase because the battery introduces no noise into the system and using the negative input of the ADS1213 by using the op-amp (hopefully the op-amp will not introduce noise), resolution will probably nearly double. I'm not going to use two separate power supplies for the analog and digital part, I hope that using a battery and proper filtering will be enough.

The Processing sketch is attached. For some reason it calculates the proper low-pass and min/max values, but draws it inverted. Will have to look into that.
9  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: April 21, 2011, 09:47:00 am
Lefty, it would indeed be awesome if some vendor would design a shield with all the appropriate filters for maximum resolution and accuracy. I'm afraid such a board would get quite expensive though, for example SparkFun usually kind of doubles or triples the cost of a single sensor. It would probably run something like 20-30$, if they do it real good (e.g. separate power supplies for the analog and digital part, filters for all channels and channel inverting on board) it will probably be more like 30$.

Ben, thanks for clearing that up. Persistence indeed pays off, and the reward is great smiley . The use of that structure and union is indeed quite clear and less prone to errors. Another example: I just corrected a bug in the library that set the wrong byte (second CMR byte instead of MSB) when setting the offset binary/two's complement bit. Can't upload the updated version until monday though.

Giantsfan, thanks. School work's often in my way too smiley . How are you measuring the stability of your ADC? You say it's 19 bits, but are those the absolute noise-free bits which don't change, or is that after extensive filtering?

Noise doesn't have to be a bad thing, in fact if you induce (predictable, sinusoid) noise to a lower precision ADC, you can count the times that the noise makes the value higher and lower, and then calculate the average. With no noise a signal would for example be hovering just below a certain value, with noise you would be able to determine the mean which is slightly below the measured value. But all noise in a 24-bit system is bad anyway, because you're not going to get higher precision... It's first in applying the correct analog filters, then in software filtering to get the best accuracy though.

I'm very interested in the noise levels too, especially to be able to design the best software filter to get fast readings but also the best accuracy. I wrote a small sketch that returns the mean value and standard deviation from that mean value to the serial port, but unfortunately just like the library I can't upload it until monday (different PC, forgot to put it on dropbox).
The standard deviations I got with settings: channel 3, normal input connected to thermistor, inverted input connected to Vref (so half the dynamic range), offset binary, gain 1, turbo mode rate 16 and Decimation Ratio of about 400 were between 500 and 1000. The mean was around 8 million (voltage divider of 10k thermistor and 10k resistor).

I did also write, however, a small processing sketch which visualizes the data and automatically adjusts the minimum and maximum values of the y axis. Processing turns out to be really easy to learn too, and it's a lot of fun visualizing stuff! The Arduino sends the values at the maximum speed to the serial port (plain values, then a line break) and Processing listens to it.

It turns out that there's quite a lot of noise but it seems to be plain equally distributed noise. From inspecting it visually, the noise seems to have a constant amplitude. When holding my hand about 5cm from the thermistor, I can easily see the value changing. Pretty cool!

Here's the Arduino sketch for sending the readings as fast as possible to the serial port:
Code:
#include <ADS1213.h>

ADS1213 ADC_ext(2,true,13,11,2,0);

void setup() {
  Serial.begin(115200);
  ADC_ext.CMRwrite(3,B001,1,16,200);
  delay(50); // Disregard the first few readings after calibration.
}

void loop() {
  Serial.println(ADC_ext.read(B000,3),DEC);
}

And here's the Processing sketch for listening to Arduino on the serial port (do change the 1 in Serial.list()[1] to match the number of the item in the list of serial devices that gets printed that represents your Arduino). Clicking on the left half of the screen pauses the data flow (stops new data from being drawn) and clicking on the right half of the screen resets the Y axis scale. The automatic Y axis scaling and the resetting of the Y axis scale are effective on the next redraw (so the line can disappear way below or above the screen until the next redraw).
Code:
import processing.serial.*;
 Serial myArduino;
 
 int WritingXlastPosition = 0;
 int WritingXposition = 0;
 int LastYval = 0;
 
 void setup() {
 size(1000,600);
 println(Serial.list());
 myArduino = new Serial(this, Serial.list()[1], 115200);
 myArduino.bufferUntil('\n');
 background(150,150,150);
 fill(255,140,0);
 }
 
 void draw() {

 }

 int MaxValCount = 0;
 int MinValCount = 0;
 int CurrentMaxVal = 0;
 int CurrentMinVal = 0;
 int MaxVal=0;
 int MinVal=2147483640;
 
 void serialEvent(Serial myPort) {
     if (mousePressed && mouseX < width/2) return;
     String ADCstring = myArduino.readStringUntil('\n');
     if (ADCstring != null) {
     ADCstring = trim(ADCstring);
     int CurrentYval = int(ADCstring);
     if (CurrentYval>MaxVal) {MaxValCount++;
       if (MaxValCount==20) {MaxVal = CurrentYval; MaxValCount = 0;}
     }
     if (CurrentYval<MinVal) {MinValCount++;
       if (MinValCount==20) {MinVal = CurrentYval; MinValCount = 0;}
     }
     if(WritingXposition == 0) {CurrentMinVal = MinVal; CurrentMaxVal = MaxVal;}
     CurrentYval = int(map(CurrentYval,CurrentMinVal,CurrentMaxVal,0,height));
     stroke(255,255,255);
     rect(WritingXposition,0,width/20,height); // Draw rect from upper left corner to erase previous data
     // Draw data line:
     stroke(0,0,0);
     line(WritingXlastPosition,LastYval,WritingXposition,CurrentYval);
     
     WritingXlastPosition = WritingXposition;
     WritingXposition += 1;
     if (WritingXposition > width) {
       WritingXposition = 0;
       WritingXlastPosition = 0;
     }
     LastYval = CurrentYval;
   }
 }
 
 void mouseReleased() {
    if (mouseX < width/2) return;
    MaxVal=0;
    MinVal=429496729;
 }

I'm working on a more advanced version of this, which includes a x and y axis with minimum and maximum values and scale, as well as different filters to compare them, like low-pass, average of some 50 values etc. I think that will provide an invaluable tool to design the most efficient software filter. First I'm gonna have to learn a bit more about Processing and how to draw text.
10  Using Arduino / Networking, Protocols, and Devices / Re: >Working, with library!< Interfacing ADS1213 22-bit ADC on: April 19, 2011, 06:28:56 pm
I decided to write a library for the ADS1213. I think it could benefit many people who are looking for a multiple-channel, very accurate external ADC as there are a lot of projects out there that need fast and accurate analog to digital conversions and the ADS1213 is a really powerful ADC with a lot of functions.
It includes some functions to be able to easily set the various settings without having to define the bytes by hand. It also includes a function to be able to change channel really quickly, and a function to read the signed output in either 1, 2 or 3 bytes.

Any bugs found or suggestions for improvement are of course welcome. [EDIT 4 may '11: bugfixed version uploaded, offset binary/two's complement option was written to the wrong bit]

The library is attached and includes a readme file which documents all functions in more detail and an example which reads signed values of all ports sequentially, as well as the datasheet itself. Place it in the library folder of your Arduino installation.

The library can be easily adjusted to be used with other TI ADC chips.

It's possible to use multiple ADS1213 chips by using separate Chip Select pins.

The library allows for different clock speeds and different pins (while still using direct port manipulation of course). The restrictions are:
SCLK pin can be from pin 8 to pin 13
IO pin can be from pin 8 to pin 13
DRDY pin can be from pin 2 to pin 7
CS pin can be any pin and is OPTIONAL (if not used (you pull CS LOW) use 0)

The constructor:
ADS1213(clockspeed in MHz (e.g. 2 or 1.6), Offset Binary true/false, SCLK pin, IO pin, DRDY pin, CS pin (0 if not in use))
Clock speed automatically adjusts the timings. It's conservative and can be cranked up for faster transfer. Reading will be the first thing failing when cranked up too high. Reset is probably even more sensitive to it and should be adjusted by hand in ADS1213.cpp for the real clock frequency when over-cranking.

Writing:
write(address, number of bytes, (name of) array with bytes)

Easy writing to the Command Register:
CMRwrite(channel, mode, gain, Turbo Mode Rate, Decimation Ratio)
See datasheet p.19-21 for explanation about mode, gain, TMR and DR. All are set using decimal numbers, except for mode which is set by bytes (e.g. B001 = self calibration, 0 is normal mode). Gain and TMR can be 1,2,4,8 and 16. Decimation Ratio can be from 19 to 8000 (= the number of samples taken for each conversion result).

Change the channel:
channel(number of channel)
Channel can be from 1 to 4.

Reading if Offset binary = true: ( - full scale = 0, mid range = maximum value / 2, + full scale = maximum value)
read(start address, number of bytes, (optional) synchronize)
Returns an unsigned long. If synchronize is left out, the function automatically waits for DRDY to go high and low again. If 'false', it does not wait (if you've already accounted for it in your own code).

Reading if Offset binary = false (using two's complement, - full scale = - min. value, mid range = 0, + full scale = + max. value):
readSigned(number of bytes)
Returns a signed long. When only reading 1 or 2 bytes instead of 3, the maximum and minimum values will be closer to 0 than when reading 3 bytes because the bytes get placed at the end of the long. When reading 1 byte the resolution is very low (8 bits), when reading 2 bytes the resolution is already very good for most projects (16 bits).

reset(): Resets the chip. Happens automatically at initialization.

Here's a sample sketch which cycles through all channels:
Code:
// This sketch demonstrates the use of the ADS1213 library by first initializing
// it with the neccesary parameters, then reading it every half second while cycling through the channels.

#include <ADS1213.h>

ADS1213 ADC_ext(2,false,13,11,2,0);
// clock speed MHz, true=offset binary (false=two's complement (can be negative)), SCLK pin, IO pin, DRDY pin, CS pin (0 if not in use)

void setup() {
  Serial.begin(115200);
  ADC_ext.CMRwrite(3,B001,1,1,255);
  // channel 3, mode 001 (self-calibration), gain 1, TMR 1, DR 255
  Serial.println("Done with setup");
}

void loop() {
  static byte Channel=1;
  Serial.print(Channel,DEC); Serial.print(" ch ");
  Serial.println(ADC_ext.readSigned(3),DEC); // Read and print the signed value
  Channel += 1;
  if (Channel>4) Channel = 1;
  ADC_ext.channel(Channel); // Set the current (incremented) channel by using the channel() function
  delay(500);
}
11  Using Arduino / Programming Questions / Re: Set Button Questions on: April 14, 2011, 08:04:44 pm
Code:
    if (analogRead(HourSet) == 1)
    {
      clockHourSet++;
    }
   
    if (analogRead(MinsSet) == 1)
    {
      clockMinSet++;
    }
The problem you are having is that you use "if (analogRead(HourSet) == 1)". AnalogRead reads a value from 0 to 1023 depending on a voltage. You are using a switch which has two positions: logic 0 or logic 1, which is 0 or 5v, so 0 or 1023 in analogRead. You then ask if analogRead is equal to 1. I hope you see the problem here. I'm very surprised that it actually does anything, as it shouldn't even pass ==1 of analogRead.

The 'bouncing' of a switch (when you press it, the two strips of metal might hit, then bounce back, then hit again without you knowing it but the superfast Arduino does notice it) can cause the digits to pass 1 multiple times so increase quickly.

You should not use == 1 but instead nothing, the if loop will then evaluate if analogRead() returns anything at all, so any non-zero value will trigger the loop. Even better is to use digitalRead(HourSet) with a digital pin. If you insist on using the analog pins you can use digitalRead and reference the analog pins as A0 and A5. It is simply faster than calling analogRead and easier to use.

Ironically, the analogRead() function kept the numbers from increasing extremely rapidly (every time Arduino passes the if statement, which is a lot of times per second) because it stayed at 1023 when the button was pressed. To avoid this and to avoid bouncing, you can, for example, record the time of the last increment by using millis() and then wait until something like 400ms (very reasonable value for minute increase, for hours you can take a little bit more, just for ease of use) has passed before accepting the next increase. Alternatively, you can count the times the if loop was passed and the button was pushed and after a certain amount increment the value, but this has the disadvantage of only responding after holding the button for one increase period.

You are also using millis() for time management. Please be aware that the unsigned long that holds millis() will roll over after approximately 50 days. If you want to run your clock longer, you can do two things: 1) implement a function that sees if millis() is near its maximum value of 4,294,967,295 and then stores the time as an offset. 2) Use the great Time library which is easy to use and doesn't roll over. This is the better option because it has direct calls for minutes and seconds making the coding easier.
12  Using Arduino / Networking, Protocols, and Devices / Re: Interfacing ADS1213, external 22-bit ADC on: April 14, 2011, 07:24:20 pm
So I have been checking my original code to see what the problem was... and guess what: it works fine, the problem was ONE CHARACTER. One tiny, lousy little character.

Because when setting the Chip Select pin low before writing, I had this:
Code:
PORTB |= ~B00000001;

Instead of this:
Code:
PORTB &= ~B00000001;

The former obviously writes all PORTB pins high EXCEPT for the right one! Correcting it made the code run perfectly and show a beautiful 700 on the serial output showing that the Vbias was set.

So lesson learnt: as BenF already stated, a step back and cleaning up of the code is often in order after having problems. I already took a step back by limiting the code to only write a command register bit and then determining if it had worked by very simply polling the Vbias pin. What I should have done after that, was cleaning up the code as much as possible, rationalizing what should work and what not and then going over the small details of the code once again. Or starting a new sketch and copy-pasting everything in while thoroughly re-writing and cleaning it. Also, I could've just pulled the CS pin low which would also have showed that it worked (that's how I discovered it in the first place).

It's good to know that my original code worked though, and that I was thinking in the right direction and adhered to the datasheet pretty well. I was beginning to think that external peripherals were just a big pain in the behind and SPI was some sort of black magic involving quantum computing and big spell books in the form of datasheets. Luckily it's all simpler than I thought, SPI is no black magic but just bits and bytes and common sense, and external peripherals are a great way to expand an Arduino to become even more functional.
13  Using Arduino / Networking, Protocols, and Devices / Re: Interfacing ADS1213, external 22-bit ADC on: April 14, 2011, 06:13:23 pm
BenF, a tremendous thanks for your write-up. It makes everything really clear, the code is really well structured. Now it WORKS! Writing settings and reading settings or data goes perfectly now. Thanks again. The accuracy is not much better than 12 bits yet, but that's because of my extremely noisy desktop power supply and the breadboard with long leads doesn't make things better either.

You seem to use a lot of C specific code, I could understand and look up most (PORTB |= _BV(PORTB5); is a really handy way of port manipulation!) but there's a few parts I don't understand yet and couldn't find anywhere:
Code:
typedef struct _insr_type {
  uint8_t adr :5;        // high-bit unused
  uint8_t count :2;
  uint8_t rw :1;         // 0=write, 1=read
} insr_type;

typedef union {
    insr_type t;
    byte b;
} insr_union;
I don't get this part. It provides the framework for the insruction bit later on, but how does 'adr :5;' for example write the address bits from bit 5-8 in the top part of the write function?
And what does 'insr_type t;' specify in the 'typedef union' definition?
Defining it this way is purely a personal preference and could also be done with bitshifts right?

Here's the working code, adjusted for an ADS1213 with 2MHz external clock (timings are indicated for easy adjustment and function to supply the clock with an internal timer is included, output for channel 3 and samples per second are displayed).
Code:
// ADS1213, 2MHz external clock source: Xin = .5 microseconds

const byte biasPin = 1; // Analog pin where ADS Vbias pin is connected, just for testing

/* Pin info:
Serial clock = PORTB5 = pin 13
Digital In/Out = PORTB3 = pin 11
DRDY = PIND2 = pin 2
*/

long Value;
byte CommandBytes[] = {B01100000,B00100010,B01000000};
// First byte: default except for Data Format (offset binary)
// Second byte: default except for mode (self-calibrate) and channel (3)
// Third byte: default except for turbo mode (4)

void setup() {
  // OPTIONAL: Supply the ADS1213 with a 2MHz clock from PIND3 (pin 3) by uncommenting the next line
  //set_clock();
  Serial.begin(115200);
  DDRB |= _BV(PORTB5); // Set Serial clock as output
  reset_ADC;
  spi_write(B0100,sizeof(CommandBytes),CommandBytes);
}

void loop() {
  // Uncomment the following line and make sure the first bit of the first (MSB) command byte is a 1
  // to test if writing to the command register is possible (the value should read about 700)
  //Serial.println(analogRead(biasPin),DEC);
  static int numberOfSamples = 400; // WARNING: 'Value' might overflow if set higher than 255
  unsigned long ValueAccum = 0;
  unsigned long SPSbegin = micros();
  for (int i=1; i<=numberOfSamples; i++) {
    spi_read(B0000,3,true);
    ValueAccum += Value;
  }
  int SPS = 1000000*numberOfSamples/(micros() - SPSbegin); // Calculates samples per second
  ValueAccum = ValueAccum/numberOfSamples; // Takes the average of the 100 values
 
  Serial.println(ValueAccum,DEC);
  Serial.print("SPS: "); Serial.println(SPS,DEC);
}

// ********************ADC declare data structures********************
#define WRITE 0
#define READ 1

typedef struct _insr_type {
  uint8_t adr :5;        // high-bit unused
  uint8_t count :2;
  uint8_t rw :1;         // 0=write, 1=read
} insr_type;

typedef union {
    insr_type t;
    byte b;
} insr_union;

// ********************ADC write section********************
void spi_write(byte adr, byte count, byte val[])
{
  insr_union insr;
 
  insr.t.adr = adr;
  insr.t.count = count - 1;
  insr.t.rw = WRITE;

  while (!(PIND & _BV(PIND2)));  // wait for ready to go high
  while (PIND & _BV(PIND2));     // wait for ready to go low
 
  // clock out instruction byte
  DDRB |= _BV(PORTB3);
  delayMicroseconds(6); //t38// 11 x Xin
  for (byte mask = 0x80; mask; mask >>= 1) {
    if (mask & insr.b) PORTB |= _BV(PORTB3); else PORTB &= ~_BV(PORTB3);
    PORTB |= _BV(PORTB5);
    delayMicroseconds(3); //t10// 5 x Xin
    PORTB &= ~_BV(PORTB5);
    delayMicroseconds(3); //t11// 5 x Xin
  }
 
  delayMicroseconds(4); //t19// 13 x Xin (t11 adds up)
  // clock out bits, MSB first
  for (byte i = 0; i < count; i++) {
    for (byte mask = 0x80; mask; mask >>= 1) {
      if (mask & val[i]) PORTB |= _BV(PORTB3); else PORTB &= ~_BV(PORTB3);
      PORTB |= _BV(PORTB5);
      delayMicroseconds(3); //t10// 5 x Xin
      PORTB &= ~_BV(PORTB5);
      delayMicroseconds(3); //t11// 5 x Xin
    }
  }
  DDRB &= ~_BV(PORTB3);
}

// ********************ADC read section********************
void spi_read(byte adr, byte count, boolean sync)
{
  insr_union insr;
 
  insr.t.adr = adr;
  insr.t.count = count - 1;
  insr.t.rw = READ;
 
  if (sync) {
    while (!(PIND & _BV(PIND2)));  // wait for ready to go high
    while (PIND & _BV(PIND2));     // wait for ready to go low
  }
 
  // clock out instruction byte
  DDRB |= _BV(PORTB3);
  delayMicroseconds(6); //t38// 11 x Xin
  for (byte mask = 0x80; mask; mask >>= 1) {
    if (mask & insr.b) PORTB |= _BV(PORTB3); else PORTB &= ~_BV(PORTB3);
    PORTB |= _BV(PORTB5);
    delayMicroseconds(3); //t10// 5 x Xin
    PORTB &= ~_BV(PORTB5);
    delayMicroseconds(3); //t11// 5 x Xin
  }
 
  DDRB &= ~_BV(PORTB3);
  PORTB &= ~_BV(PORTB3);
 
  delayMicroseconds(4); //t19// 13 x Xin (t11 adds up)
  Value = 0;
    for (byte j = 0; j < (8*count); j++) {
      PORTB |= _BV(PORTB5);
      delayMicroseconds(3); //t10// 5 x Xin
      Value <<= 1;
      if (PINB & _BV(PINB3)) Value |= 1;
      PORTB &= ~_BV(PORTB5);
      delayMicroseconds(3); //t11// 5 x Xin
    }
}

// ********************Reset ADC function********************
void reset_ADC() {
  PORTB |= _BV(PORTB5);
  delayMicroseconds(512+1);  //t3// 1024 x Xin
  PORTB &= ~_BV(PORTB5);
  delayMicroseconds(5+1);//t2// 10 x Xin
  PORTB |= _BV(PORTB5);
  delayMicroseconds(256+1);  //t1// 512 x Xin
  PORTB &= ~_BV(PORTB5);
  delayMicroseconds(5+1);//t2//
  PORTB |= _BV(PORTB5);
  delayMicroseconds(512+1); //t3// 1024 x Xin
  PORTB &= ~_BV(PORTB5);
  delayMicroseconds(5+1);//t2//
  PORTB |= _BV(PORTB5);
  delayMicroseconds(1024+1); //t4// 2048 x Xin
  PORTB &= ~_BV(PORTB5);
}

// ********************Set clock function********************
void set_clock() {  // Configures timer2 for 8MHz output on PD3
  TCCR2B = _BV(CS20);  // prescaler = F_CPU/1
  OCR2A = 2;  // clear timer at 2 count, f = F_CPU/8
  TCCR2A = _BV(COM2B0) | _BV(WGM21);  // toggle PD3 on compare match
  DDRD |= _BV(PORTD3);  // start clock output on XIN/PD3
}
14  Using Arduino / Networking, Protocols, and Devices / Re: Interfacing ADS1213, external 22-bit ADC on: April 07, 2011, 03:59:40 pm
Giantsfan, I'd really appreciate that.
I've seen that one, but I need at least 18 bits of resolution and I want to measure temperature, an analog pressure sensor (height) and another one for airspeed. So I need at least 3 channels with 18 bits, and then I also need to be able to read them really fast, in the order of at least 100SPS per channel as I want to do some data filtering to get extremely accurate results. The microchip one only has 3.75SPS for 18 bits which is way too slow.
15  Using Arduino / Networking, Protocols, and Devices / Re: Interfacing ADS1213, external 22-bit ADC on: April 07, 2011, 01:42:38 pm
Lefty, thanks for that link. That seems to be a great ADC, but it is only single channel. There's a couple fundamental differences between that ADS1252 and this ADS1213: he doesn't have to write instructions to the command register as it doesn't have one, and therefore he can use the SPI library to read stuff.

Such an approach would also be possible with the ADS1213 (using continuous read mode), but for my application I really need to be able to switch between channels. Maybe I'll write some code to be able to get data from it while only receiving though, just for testing.
Pages: [1] 2