simple logic error combining bytes?

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.