Skip to main content
Arduino

Return to Answer

+ more about the data representation and conversion
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

Edit: Here are more details about the data representation, and about the conversion to 16-bits done by the expression (int16_t)(raw_data << 1) >> 6.

According to the datasheet, the sensor gives the temperature as a 10-bit signed number in two's complement notation. If you fail to acknowledge the fact that the result is signed, and you interpret the 10 bits as an unsigned number, then a temperature of −1 °C will be interpreted as +255 °C, which is obviously very wrong.

Since it's a signed number, increasing the bit width of the temperature to 16 bits has to be done using sign extension , i.e. the missing bit positions have to be filled with copies of the leftmost bit (the "sign bit").

The datasheet also shows that the sensor sends a stream of 16-bits as follows:

0 db9 db8 db7 db6 db5 db4 db3 db2 db1 db0 db0 db0 db0 db0 db0

where the first bit is a padding zero, then come the ten data bits db9 – db0, and then five extra copies of the last data bit. These extra copies can be seen in figure 3 (serial interface digram), and can also be inferred from the sentence "the SDO line remains in the state of the last bit of data clocked out of the AD7314".

The line

uint16_t raw_data = SPI.transfer16(0);

puts this bit pattern into the variable raw_data, which is a 16-bit unsigned integer. Then, the operation raw_data << 1 shifts this pattern one bit position to the left, discarding the leftmost zero and padding with another zero on the right, which gives:

db9 db8 db7 db6 db5 db4 db3 db2 db1 db0 db0 db0 db0 db0 db0 0

This is then cast to a signed number, which doesn't change the bit pattern, but only the interpretation of the leftmost bit, which is now a sign bit. Then, the number is shifted by 6 bit positions to the right. Since this is an arithmetic shift , which does sign extension, the leftmost bit (the "sign bit") is replicated during the shift, which yields:

db9 db9 db9 db9 db9 db9 db9 db8 db7 db6 db5 db4 db3 db2 db1 db0

And this is the expected result: the same numeric value that was originally stored in the "temperature value register" of the sensor, only represented as a 16-bit number.


Edit: Here are more details about the data representation, and about the conversion to 16-bits done by the expression (int16_t)(raw_data << 1) >> 6.

According to the datasheet, the sensor gives the temperature as a 10-bit signed number in two's complement notation. If you fail to acknowledge the fact that the result is signed, and you interpret the 10 bits as an unsigned number, then a temperature of −1 °C will be interpreted as +255 °C, which is obviously very wrong.

Since it's a signed number, increasing the bit width of the temperature to 16 bits has to be done using sign extension , i.e. the missing bit positions have to be filled with copies of the leftmost bit (the "sign bit").

The datasheet also shows that the sensor sends a stream of 16-bits as follows:

0 db9 db8 db7 db6 db5 db4 db3 db2 db1 db0 db0 db0 db0 db0 db0

where the first bit is a padding zero, then come the ten data bits db9 – db0, and then five extra copies of the last data bit. These extra copies can be seen in figure 3 (serial interface digram), and can also be inferred from the sentence "the SDO line remains in the state of the last bit of data clocked out of the AD7314".

The line

uint16_t raw_data = SPI.transfer16(0);

puts this bit pattern into the variable raw_data, which is a 16-bit unsigned integer. Then, the operation raw_data << 1 shifts this pattern one bit position to the left, discarding the leftmost zero and padding with another zero on the right, which gives:

db9 db8 db7 db6 db5 db4 db3 db2 db1 db0 db0 db0 db0 db0 db0 0

This is then cast to a signed number, which doesn't change the bit pattern, but only the interpretation of the leftmost bit, which is now a sign bit. Then, the number is shifted by 6 bit positions to the right. Since this is an arithmetic shift , which does sign extension, the leftmost bit (the "sign bit") is replicated during the shift, which yields:

db9 db9 db9 db9 db9 db9 db9 db8 db7 db6 db5 db4 db3 db2 db1 db0

And this is the expected result: the same numeric value that was originally stored in the "temperature value register" of the sensor, only represented as a 16-bit number.

Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

I see several issues here.

Sensor output

According to the waveforms shown by your logical analyzer, the sensor is outputting 0b0011111111111111. We have to discard the first (a padding zero) and the last five bits (copies of DB0). We then end up with the actual data bits being 0111111111. This has to be interpreted as a signed fixed-point number in s.7.2 format, which gives 127.75 °C: the maximum possible value the sensor can output, and well above its maximum operating temperature.

I cannot tell what is going wrong here. It looks like the sensor is either burning alive, or trying to tell you it's extremely unhappy.

SPI mode

You wrote:

SPISettings(125000, MSBFIRST, SPI_MODE0)

SPI mode 0 seems to be pretty common. In this mode, the data lines are updated on the falling edge of the clock, and they are read on the rising edge. However, according to your sensor's datasheet, it appears this sensor works the other way around: it uses SPI mode 1. Your setting should reflect this.

Decoding the data

You wrote:

myValFromTempSensor = SPI.transfer(0x00);
myValFromTempSensor |= (uint8_t)SPI.transfer(0x00) << 8;

Here you are assuming the least significant byte is transmitted first. This is not the case: you get a stream of 16 bits with the most significant first. Thus, in terms of bytes, it's also MSB first.

Then, 6 of these 16 bits have to be discarded in order to get the actual 10 data bits. Since the Arduino has no 10-bit data type, and the number is signed, it has to be sign-extended to 16-bits. All this can be done in C/C++ by:

  • left-shifting one bit to the left (discarding the zero padding bit)
  • casting to a signed 16-bit integer
  • right-shifting (which gcc implements using sign extension) six bits to the right

Or, in code:

digitalWrite(Slave_PIN, HIGH);
uint16_t raw_data = SPI.transfer16(0);
digitalWrite(Slave_PIN, LOW);
int temperature_reading = (int16_t)(raw_data << 1) >> 6;
default

AltStyle によって変換されたページ (->オリジナル) /