I can use a fresh set of eyes here - am getting 3 bytes back from a 16 bit ADC.
Format is
0000UUUU MMMMMMMM LLLL0000
where the upper byte has 4 leading zeros, and the lower byte has 4 trailng zeros.
#include <SPI.h>
byte cs = 10;
byte upper;
byte middle;
byte lower;
unsigned long combined;
void setup(){
pinMode (cs, OUTPUT);
Serial1.begin(9600);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV16); // 2 MHz operation
SPI.setDataMode(SPI_MODE2);
}
void loop(){
digitalWrite(cs, LOW);
upper = SPI.transfer(0);
middle = SPI.transfer(0);
lower = SPI.transfer (0);
digitalWrite (cs, HIGH);
Serial1.print(" U ");
Serial1.print(upper, HEX);
Serial1.print(" M ");
Serial1.print(middle, HEX);
Serial1.print(" L ");
Serial1.print(lower, HEX);
combined =(upper<<16) + (middle<<8)+ lower;
//combined = combined >>4;
Serial1.print(" C ");
Serial1.println(combined,HEX);
delay(500);
}
I can see the data coming back as
U 5 M 35 L 5 C 3500
The Upper nibble 5 seems to get dropped.
If I uncomment the final >>4
//combined = combined >>4;
then I get
U 5 M 35 L 5 C 355
I can't seem to get the upper 4 bits.
What am I doing wrong?
Data is coming from AD7680,feeding it with the output of a pot.
See page 17
May not have the SPI mode set right, but I don't think that affects manipulating the 3 bytes down into 2.
AD7680 16bit ADC SPI.pdf (295 KB)
In the section, Reading from A/D...
I think this is the old 16-bit integer arithmetic problem.
Try:
combined =((long)upper<<16) + (middle<<8)+ lower;
I can't remember if "byte" means "unsigned char". If it means a signed char then you should also do this to avoid more problems when you have bytes with the high order bit set:
unsigned char upper;
unsigned char middle;
unsigned char lower;
[edit]
or avoid the signed/unsigned problem by combining the parts using a logical operator with:
combined =((long)upper<<16) | (middle<<8) | lower;
Pete
Got it worked out - had to redo it in several stages tho
Not clear to me why.
void loop(){
digitalWrite(cs, LOW);
upper = SPI.transfer(0);
middle = SPI.transfer(0);
lower = SPI.transfer (0);
digitalWrite (cs, HIGH);
Serial1.print(" U ");
Serial1.print(upper, HEX);
Serial1.print(" M ");
Serial1.print(middle, HEX);
Serial1.print(" L ");
Serial1.print(lower, HEX);
combined = upper;
combined =(combined<<8) + middle;
combined = (combined<<8) +lower;
combined = combined >>4;
Serial1.print(" C ");
Serial1.println(combined,HEX);
delay(500);
}
CrossRoads:
Format is
0000UUUU MMMMMMMM LLLL0000
where the upper byte has 4 leading zeros, and the lower byte has 4 trailing zeros.
...
I can see the data coming back as
U 5 M 35 L 5 C 3500
But L should never be a number less than 0x10.
This should fix the original issue:
combined = ( (unsigned long)upper << 16) + (middle << 8) + lower;
combined = combined >> 4;
Or in one statement, using a 16-bit integer instead of 32-bit:
unsigned int combined2 = (upper << 12) + (middle << 4) + (lower >> 4);
had to redo it in several stages tho
Not clear to me why
Because by breaking it into stages, you forced each stage to be computed as a 32-bit integer.
Intermediate computations are done as 16-bit integers unless you force them to be otherwise. In this:
combined =(upper<<16) + (middle<<8)+ lower;
"upper" is shifted left beyond the top of a 16-bit integer, so it's result is zero.
When doing logical operations you should also use logical operators instead of arithmetic ones. Use | instead of +.
Pete
That works too.
Any ideas why the ADC is outputting 0-FFFF and then jumping back to 0 and going up to FFFF again at the halfway voltage?
Neither one has a 2X mode that I can see.
Use 4.5V as Vdd, right around 2.2V it flips over.