Looking for some guidance. I'm trying to read the value of a strain gauge using an Arduino Mega2560, but the resolution of the 10Bit ADC is too coarse, so I'm adding an external 16Bit ADC over the SPI protocol.
It seems so simple but I'm certain I'm missing something. In the code below, I enable the SPI, then I simply want to read the output of the ADC. Since I'm passively viewing the output, I don't see any need for a data transfer command.
Am I on the right track or have I got it all wrong?
#include <SPI.h>
//Using a strain gage attached to 16-bit ADC, connected to an
//Arduino Mega2560.
/* SPI Pins used:
MISO = 50
SCK = 52
SS = 53
*/
int adcOut = 50; //Output of ADC
int CS = 53; //Chip select output
int SCLK = 52; //System Clock
int adcValue = 0;
void setup(){
SPI.begin();
Serial.begin(9600);
pinMode(adcOut, INPUT);
pinMode(CS, OUTPUT);
pinMode(SCLK, OUTPUT);
}
void loop(){
digitalWrite(CS, LOW);//This pin pulled LOW to enable the ADC
adcValue = digitalRead(adcOut);//Reads the ADC value
Serial.println(adcValue);//Prints the ADC Value to Serial Port
delay(250);
}
adcValue = digitalRead(adcOut);//Reads the ADC value
That is not how you can read from you external ADC SPI chip. You would normally have to find a arduino software library written for your specific external ADC chip that knows how to perform all the low level SPI commands to allow communications with your chip and your sketch code. If you don't have such a library you will have to get the datasheet for the ADC chip and see how you actually communicate between your arduino sketch and the chip.
If it's a single channel ADC, then it might be a 3 byte transfer.
1 byte from Mega to the ADC, and 2 bytes to read back.
digitalWrite (adcCS, LOW);
SPI.transfer(commandByte; // send command
lowerByte = SPI.transfer(0); // read one byte of result back
upperByte = SPI.transfer(0); // read one byte of result back
digitalWrite (acdCS, HIGH);
16bitResult = (upperByte<<8) + lowerByte;
Tweak as needed for your chip.
Don't need a library for that.
CrossRoads:
If it's a single channel ADC, then it might be a 3 byte transfer.
1 byte from Mega to the ADC, and 2 bytes to read back.
digitalWrite (adcCS, LOW);
SPI.transfer(commandByte; // send command
lowerByte = SPI.transfer(0); // read one byte of result back
upperByte = SPI.transfer(0); // read one byte of result back
digitalWrite (acdCS, HIGH);
16bitResult = (upperByte<<8) + lowerByte;
Tweak as needed for your chip.
Don't need a library for that.
Many (most?) SPI ADC chips use configuration setup to set things like desired range, update speed, continuous or one-shot conversions, and other options, and assuming the default setup, if it has one, is compatible with his needs could be a big problem. More helpful if the OP would just tell us the specific chip he is using so a datasheet could be looked at and possible arduino library support can be found.
I wasn't able to find a arduino support library after doing a quick google search. Looking at the datasheet there is at least a device initialization/RESET cycle operation required before being able to read conversions.
device initialization/RESET cycle
The TLC4541/45 each require one RESET cycle after power-on for initialization in order to operate properly.
This RESET cycle is initiated by asserting the CS pin (pin 1) low for a minimum duration of at least one SCLK
falling edge but no more than 8 SCLK falling edges in length. The RESET cycle is terminated by asserting CS
high. If a valid RESET cycle is issued, the data presented on the SDO output during the following cycle is FF00h.
This output code is useful in determining when a valid reset/initialization has occurred.
The TLC4541 has separate CS and FS pins. In this case, it is also possible to initiate the RESET cycle by
asserting FS low if CS is already low. The RESET cycle can be terminated by either asserting CS high (as shown
in the first RESET cycle in Figure 14), or by asserting FS high ( as shown in the second RESET cycle in Figure
14), whichever happens first.
// read out data from prior conversion, provide clocks for next conversion
// FS tied high (Vdd)
// default SPI speed (4 MHz), or high speed (8 MHz) may be used.
digitalWrite (adcCS, LOW);
upperByte = SPI.transfer(0); // read one byte of result back
lowerByte = SPI.transfer(0); // read one byte of result back
dummyByte = SPI.transer(0); // finish providing 24 clocks to complete conversion
digitalWrite (acdCS, HIGH);
16bitResult = (upperByte<<8) + lowerByte; // prior conversion results
This is the latest code. I have an input voltage on pin 4 of .076V and an output voltage on pin6 of about the same. I'm pretty sure the chip is wired correctly and is functioning correctly, however, there may be a bug in the program that I'm not seeing. 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?
Thanks to all-
#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.
Serial.begin(9600);
pinMode(adcCS, OUTPUT);
//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);
}
I'm so close! Just need one more peak from our Arduino experts. Here's my latest code:
#include <SPI.h>
//Using a strain gage 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.
#define adcCS 49//Chip select output. Controls the slave device
#define adcCLK 52 //system clock. We're taking control.
#define MISO_ADC 50//VDO output from ADC, to the Ardiuno.
#define MOSI_ADC 51//
byte upperByte;//Most significant BIT
byte lowerByte;//Least significant BIT
int adcValue = 0;
void setup(){
pinMode(53, OUTPUT);
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); // lower the chip select
digitalWrite (adcCLK, LOW); // clock low
digitalWrite (adcCLK, HIGH); // clock high
digitalWrite (adcCLK, LOW); // clock low
digitalWrite (adcCLK, HIGH); // clock high
digitalWrite (adcCS, HIGH); // rase chip select
}
void loop(){
// read out data from prior conversion, provide clocks for next conversion
digitalWrite (adcCS, LOW); //Enables ADC
delayMicroseconds(500);
digitalWrite(adcCLK, LOW);//clock low
upperByte = SPI.transfer(0); // read one byte of result back
lowerByte = SPI.transfer(0); // read one byte of result back
delayMicroseconds(500);
digitalWrite(adcCLK, HIGH);//clock high
delayMicroseconds(500);
digitalWrite(adcCS, HIGH);//disables ADC
adcValue = (upperByte<<8) + lowerByte; // Moves the upperByte to the left, then adds
//the lowerByte. Combining the two equals the adcValue.
digitalWrite (adcCS, HIGH); //Disables SPI
Serial.println(adcValue, BIN);//Prints the ADC Value to Serial port.
//Converts from binary to decimal.
delay(250);
}