2’s complement data format convertion

Hello.
Currently, I am writing the library for MLX90392 3D magnetometer. It has the temperature sensor installed that I want to include in the library, but I cannot understand how to interpret the data I am receiving.

The temperature data I am getting from the sensor is 2 bytes: LSB and MSB.

The library also states that:

The data format is 2’s complement with 0 lsb corresponding to 0degC
Temperature unit is LSB16/°C

how to correctly convert the data to the integer degrees?

All best,
Mike

A few years ago I wrote this to do the thing with a MLX90393.

void fMLX90393_1( void * pvParameters )
{
  int rx[10] = { 0 };
  int _gain = MLX90393_GAIN_1X;
  int xyResoultion = 0;
  int zResoultion = 1;
  int xRes;
  int yRes;
  int zRes;
  float xAverage = 0.0f;
  esp_err_t intError;
  vTaskDelay( 500 ); // delay to let the other sensor come online 1st
  intError = fWriteSPIdata8bits2( _hMLX90393_1, MLX90393_REG_RT ); // reset
  vTaskDelay( 300 ); // allow reset time to complete
  // set gain
  intError = fWriteSPIdata32bits( _hMLX90393_1, MLX90393_REG_WR, 0x00, (((_gain & 0x7) << MLX90393_GAIN_SHIFT) | MLX90393_HALL_CONF), (MLX90393_CONF1 & 0x3F) << 2 );
  vTaskDelay( 10 );
  // MLX90393_CONF2 for comm mode TRIG_INT_SEL 0x1 + 0x10 use spi + relative measurement 0x1 + temp compensation 0x1 = 0xD0
  intError = fWriteSPIdata32bits( _hMLX90393_1, MLX90393_REG_WR, 0x00, 0xD0, (MLX90393_CONF2 & 0x3f) << 2 ); // using 0x00 for the lower 8 bits of the register
  vTaskDelay( 10 );
  //
  fMLX90393_ChangeResoultion( _hMLX90393_1, 0 );
  vTaskDelay( 10 );
  // read MLX90393_CONF3 for resolution
  intError = fReadSPIdataXbits( _hMLX90393_1, (MLX90393_CONF3 & 0x3F) << 2, rx, 3 );
  // combine response into 16bit
  //  Serial.print ( rx[2], BIN );
  //  Serial.print ( " : ");
  //  Serial.print( rx[1], BIN );
  //  Serial.print ( " " );
  int temp = ( rx[2] << 8) | rx[1];
  //  Serial.print ( temp, BIN );
  //  Serial.print ( " " );
  // find resoultion being used
  temp = temp >> 5;
  //   Serial.print ( temp, BIN );
  //   Serial.print ( " " );
  // extract 1st 2 bits, x resolution
  xRes = temp & 3;
  temp = temp >> 2;
  yRes = temp & 3;
  temp = temp >> 2;
  zRes = temp & 3;
//  Serial.print ( zRes, BIN );
//  Serial.print ( " " );
//  Serial.print ( yRes, BIN );
//  Serial.print ( " " );
//  Serial.print ( xRes, BIN );
//  Serial.println ( );
  attachInterrupt( MLX90393int_1, fMLX90393_triggerReadSensor_1, RISING );
  while (1)
  {
    xEventGroupWaitBits ( eg, evtTriggerMLX90393_1, pdTRUE, pdTRUE, portMAX_DELAY);
    // Serial.println( " wakie wakie 1 ");
    // request a single data read
    intError = fWriteSPIdata8bits2( _hMLX90393_1, MLX90393_REG_SM | MLX90393_AXIS_ALL ); // single measurement all axis and temprature
    //triggered  from void IRAM_ATTR triggerMLX90393read(), when the unit has data available
    xEventGroupWaitBits ( eg, evtfMLX90393_ReadSensor_1, pdTRUE, pdTRUE, portMAX_DELAY );
    intError = fReadSPIdataXbits( _hMLX90393_1, MLX90393_REG_RM | MLX90393_AXIS_ALL, rx, 9 );
    /* rx[0] = status bit
       rx[1] & rx[2] = temprature
       rx[3] & rx[4] x
       rx[5] & rx[6] y
       rx[7] & rx[8] z
    */
    // Convert data to 16 bit
    int16_t xi, yi, zi;
    xi = (rx[3] << 8) | rx[4]; // shift MSB over to the left by 8 & with LSB
    yi = (rx[5] << 8) | rx[6];
    zi = (rx[7] << 8) | rx[8];
    // determine gain being used
    float xT = 0.0f, yT = 0.0f, zT = 0.0f;
    xT = (float)xi *  mlx90393_lsb_lookup[_gain][xRes][xyResoultion];
    yT = (float)yi * mlx90393_lsb_lookup[_gain][yRes][xyResoultion];
    zT = (float)zi * mlx90393_lsb_lookup[_gain][zRes][zResoultion];
    xMag.x -= xT;
    xMag.y -= yT;
    xMag.z -= zT;

    // multiply by 10 for milliGauss
//    Serial.print ( " MLX90393_1 ");
//    Serial.print( " X uT: " );
//    Serial.print( xT , 6 );
//    Serial.print( ", Y uT: " );
//    Serial.print( yT, 6 );
//    Serial.print( ", Z uT: " );
//    Serial.print( zT, 6 );
//    Serial.println();

//    Serial.print ( "Summed readings: " );
    // Serial.print( " X uT: ");
    Serial.print( "DATA," );
    Serial.print( String(xMag.x) );
   Serial.print( ", " );
    // Serial.print( " Y uT: ");
     Serial.print( String(xMag.y) );
     Serial.print( ", " );
    // Serial.print( " Z uT: ");
    Serial.print( String(xMag.z) );
    Serial.print( ", " );
    Serial.print( "AUTOSCROLL_20" );
    Serial.println();

  }
  vTaskDelete(NULL);
}

That's an int value with 0 for 0°C.

I have no clue what the 48/50/52 min/typ/max values mean. Perhaps typically 50 or 50/16 for 1°C difference? Which value do you read at typical ambient temperature?

Here is the data that I just got from the sensor (should be approx. 24C):

LSB: 00011010
MSB: 00000110

So am I understand that correctly, that all what I need is just:

temp = (buff[1] << 8) | buff[0];

where buff[0] is LSB and buff[1] is MSB

convertedTemperature = temp/50;

Is this sound like a plan? :slight_smile:

That's 1562 decimal. Divided by (typ) 50 it could mean 31°C internal temperature.

Thank you DrDiettrich for clearing this out.
I was too scared with 2’s complement :slight_smile:

That's the commonly used signed integer representation. It has a single 0 value and one negative member more than positive members.

The 1's complement has distinct +0 and -0 and the same number of positive and negative members. Like this (sign+magnitude) is still in use with floating point numbers but not with integral numbers.

1 Like