There is 20 bit 2'complement number (which is read with 3 x 8 bit) and it needs to be converted in 32bit signed int.
Could someone please explain this piece of code:
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample /= 1L << 12;
So now in 32bit signed integer from right the right side there is 24 values and then:
sample /= 1L << 12;
How this works?
Link for the full code is at:
https://github.com/circuitar/Nanoshield_LoadCell/blob/master/src/Nanoshield_LoadCell.cpp
In general, bit-wise shift operations should be done on unsigned integer types because:
If you are careful to avoid all of the above, bit-wise shift operations can be used portably on signed integer types as in the following 1 :
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample >>= 4;
// 'sample' contains a 20-bit, 2's complement value. Sign-extend to a 32-bit signed value.
if (sample >= (INT32_C(1) << 19))
sample -= (INT32_C(1) << 20);
The if (sample >=...
sign-extension part might not be branch-free, depending on the compiler. An alternative sign-extension conversion from 20-bit 2's complement to 32-bit signed is:
sample = (sample ^ (INT32_C(1) << 19)) - (INT32_C(1) << 20);
The XOR operation converts the 2's complement value to an offset binary value. That operation could be merged into the value of the byte from the first SPI transfer (the most significant 8 bits of the 20-bit sample value) as follows:
int32_t sample = 0;
sample |= SPI.transfer(0) ^ 0x80; // convert 2's complement to offset binary
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample >>= 4;
// 'sample' contains a 20-bit, offset binary value. Convert to 32-bit, signed value.
sample -= INT32_C(1) << 20;
1 "Portably" here as long as int32_t
is provided by the implementation. If not, then int_least32_t
can be used instead.
How this works?
If SPI.transfer(0)
returns 0-255, it "works" when the 20-bit number is in the upper 24 bits of data read. Then shifting that into the 32-bit type sign-bit relies on UB to form the correct value that when divided but 1 << 12
is the sought after value.
To convert a 20-bit 2's complement number to a int32_t
, test the sign bit.
// Alternative without UB nor implementation defined behavior:
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
// if input is in upper 20 bits of the 24 read (OP is not explicit on that)
if (1) {
sample >>= 4;
}
assert(sample >= 0 && sample <= 0xFFFFF);
if (sample & 0x80000) { // Test for the 20-bit 2's complement sign bit
sample -= 0x100000;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.