Combining two 32-bit values into one 64-bit value: unexpected result

PaulS

Well-known member
While I was playing with I2S data, I ran into a (for me) unexpected result.
This minimal sketch shows the issue:
C++:
int32_t leftSample = 0xAA0055FF;
int32_t rightSample = 0x55AA00FF;
int64_t LRsample = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);
  LRsample = ((int64_t)leftSample << 32 | rightSample);
  Serial.println(LRsample, HEX);
}

void loop() {
}

The above code shows this result in the serial monitor: AA0055FF55AA00FF, as expected.
Now when I change the rightSample into int32_t rightSample = 0xFF55AA00;, the result is FFFFFFFFFF55AA00.
Am I overlooking something fundamental?

Teensy 4.0, Arduino 2.2.1, Teensyduino 1.58.1.

Thanks,
Paul
 
Converting a signed int32 to signed int64 performs sign extension.
Consider if rightSample was -1 and it wasn't sign extended, it would become 4294967295...
 
Ah, allright, I understand.
My use case is outputting data to a stereo I2S DAC that accepts two int32 left & right samples as one 64-bit value (the DAC being a TI PCM5102A).

Thanks,
Paul
 
Hmm probably this would work:
Code:
  LRsample = (((int64_t)leftSample << 32) | ((int64_t)rightSample & 0x0FFFFFFFFLL));
 
You can obviously fix that by using
C:
LRsample = (((uint64_t)((uint32_t)leftSample)) << 32) | ((uint32_t)rightSample);
It is important to first cast the value to the same size but unsigned, to prevent sign extension. You can safely assign an unsigned expression to a signed variable of the same size, no information is lost.

Yes, some of the parentheses in that expression are superfluous, but keeping them there makes everything explicit and unambiguous, so I like 'em.
 
Back
Top