This is a re-post of a question I posed previously about using a 16-bit Analog to Digital converter with an Arduino Mega. This question is more directed at the use of the SPI protocol. I'm using a TLC4541 A to D converter (datasheet: http://www.ti.com/lit/ds/symlink/tlc4545.pdf) and the Mega2560.
As I understand it, the process should be as follows:
Enable SPI
Read the first byte
Read the second byte
Disable SPI
Write the bytes to an integer
Display that integer in the Serial Window
Have I got this right or am I missing something obvious? Here is the code I'm working with:
#include <SPI.h>
//Using a strain gauge attached to 16-bit ADC, connected to an
//Arduino Mega2560.
/* SPI Pins used:
MISO = 50
SCK = 52
SS = 53
*/
// FS tied high (Vdd)
// default SPI speed (4 MHz), or high speed (8 MHz) may be used.
const int adcCS = 53; //Chip select output. Controls the slave device
int adcValue=0;//This is the value in the ADC output register
byte dummyByte;//Byte that does nothing but allows the conversion cycle to complete.
byte upperByte;//Most significant BIT
byte lowerByte;//Least significant BIT
void setup(){
SPI.begin();//Enables the SPI interface
SPI.setDataMode(SPI_MODE1);//Per datasheet for the TLC4541 ADC chip, the SPI interface
//is programmed for CPOL=0, CPHA=1.
pinMode(adcCS, OUTPUT);
Serial.begin(9600);
//Reset cycle for the ADC. Initializes the chip on power up. Occurs only 1 time.
digitalWrite (adcCS, LOW);
dummyByte = SPI.transfer(0); // Initialization/Reset clocks
digitalWrite (adcCS, HIGH);
}
void loop(){
// read out data from prior conversion, provide clocks for next conversion
digitalWrite (adcCS, LOW); //Enables SPI
upperByte = SPI.transfer(0); // read one byte of result back
lowerByte = SPI.transfer(0); // read one byte of result back
dummyByte = SPI.transfer(0); // finish providing 24 clocks to complete conversion
digitalWrite (adcCS, HIGH); //Disables SPI
adcValue = (upperByte<<8) + lowerByte; // Moves the upperByte to the left, then adds
//the lowerByte. Combining the two equals the adcValue.
Serial.println(adcValue, DEC);//Prints the ADC Value to Serial port.
//Converts from binary to decimal.
delay(250);
}
Just a multimeter. I'm getting .076V on pin 4 (Ain) and the same on pin 6 (SDO). I assume that means the circuit is working properly so I'm trying to figure out what I'm doing wrong with the code.
so what is your physical set up- full diagram? this is my assumptions :
i assume your powering your TI properly with GND, VDD same as arduino, you've got some Vref hooked to it, you seem to have Ain hooked to your strain gauge with some small voltage with a resistor somewhere in there...
you've got mega pin 52 hooked to your TI CLK
you need to have pin 53 set to an output cause its the MASTER i would do this as the first line of set up.
i believe after this point you should not be using pin 53 (adcCS),
if you want to manually trigger the CS on the TI chip go for it but don't mess with pin 53- at least not yet.
youve got pin 50 MISO hooked to SDO
youve got the right SPI mode1 for your TI piece.
try MOSI connected to CS and dont manually (adcCS=low/high) start it, I'm not sure how the SPI is set up. but that's what i would try.
also try the manual trigger but not with pin 53.
but i dont really know anything about SPI that's just me looking over the data sheets.
on another note:
Couldn't you just use an analog input on your arduino?
the Arduino has built in 10 bit ADC converter,
do you really need the extra 6 bits of accuracy?
Thanks for the help. I'll start plugging away at your suggestions. The 10bit ADC does not have a fine enough resolution. I'm measuring the change in mV out from a strain gauge, but with an increasing load of 100 lb increments, the mV out is changing by only .01mV. I'm trying to use the 16bit ADC because the resolution is about .07mV per division.
Here's how I arrived at the conclusion that simply amplifying the voltage was not enough:
With the strain gauge at rest, I get 3.4mV out. This voltage is the input to an INA125 amplifier. The output of the amplifier is .076V. This is an amplification of 22.35x.
As the load on the strain gauge increases, the mV out signal increases:
0lbs -- 3.4mV
100lbs -- 3.5mV
200lbs -- 3.6mV...and so on.
With an amplification of 22.35x, I get the following amplified readings:
The resolution of the 10Bit ADC on the Arduino, even with a 1.1V reference, is 1.7mV.
The change in voltage with each increment of +100 lbs is 2.2mV. So if my application is to weigh a piece of steel, as a safety measure, the scale needs to be accurate. There's no way around it. Even with proper amplification, I need a higher resolution. I want accuracy within 0.5 lbs for loads in excess of 2500lbs.
Even if my logic is wrong here, I would still like to know how to properly read data from an external ADC over SPI.
With all that said, does anyone know how to do it? I'm having trouble understanding it.
first balance your gage circuit. 0mV at 0 lbm. now you can amplify the signal and get it to the proper level for inpu to ADC. your gage output changes 0.1mV/100 lb. at 2500 lbm output is 2.5mV. gain ov 200 give 5V at 2500lbm.
let us see the circuit. It depends on if it is a quarter, half or full bridge and how many active gages. as far as SPI interface goes it shouldn't be hard. look at the baro pressure example on how to read from a device and the AD data sheet for register access.
I'm using a full wheatstone bridge SGT-3E/350FB41 from Omega engineering. Also using an INA125 instrumentation amplifier. I'll take another look at the baro example.
Thanks.
I can't see how in your code you are initialising the module. See page 12 of the data sheet. You should bit bang this in the setup function.
Each SPI transfer is only 8 bits so having the dummy bits line with a comment of 24 bits is wrong.
I also can't see how you get the 20 clock edges before the sample is ready.
The whole thing probably requires bit banging.