Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Raw 14 bit Two's Complement to Signed 16 bit Integer

I am doing some work in embedded C with an accelerometer that returns data as a 14 bit 2's complement number. I am storing this result directly into a uint16_t. Later in my code I am trying to convert this "raw" form of the data into a signed integer to represent / work with in the rest of my code.

I am having trouble getting the compiler to understand what I am trying to do. In the following code I'm checking if the 14th bit is set (meaning the number is negative) and then I want to invert the bits and add 1 to get the magnitude of the number.

int16_t fxls8471qr1_convert_raw_accel_to_mag(uint16_t raw, enum fxls8471qr1_fs_range range) {
  int16_t raw_signed;
  if(raw & _14BIT_SIGN_MASK) {
    // Convert 14 bit 2's complement to 16 bit 2's complement
    raw |= (1 << 15) | (1 << 14); // 2's complement extension
    raw_signed = -(~raw + 1);
  }
  else {
    raw_signed = raw;
  }
  uint16_t divisor;
  if(range == FXLS8471QR1_FS_RANGE_2G) {
    divisor = FS_DIV_2G;
  }
  else if(range == FXLS8471QR1_FS_RANGE_4G) {
    divisor = FS_DIV_4G;
  }
  else {
    divisor = FS_DIV_8G;
  }

  return ((int32_t)raw_signed * RAW_SCALE_FACTOR) / divisor;
}

This code unfortunately doesn't work. The disassembly shows me that for some reason the compiler is optimizing out my statement raw_signed = -(~raw + 1); How do I acheive the result I desire?

The math works out on paper, but I feel like for some reason the compiler is fighting with me :(.

like image 480
secretformula Avatar asked Dec 03 '15 20:12

secretformula


People also ask

What will be the 16 bit 2s complement?

16 in binary is 1 0000 . Add some leading 0 's, so that the number has eight digits, 0001 0000 . That's 16 in the two's complement notation.

What is a range of 16 bit signed integer?

Signed Integer: A 16-bit signed integer ranging from -32,768 to +32,767.

How do you convert 2s complement to binary?

To get 2's complement of binary number is 1's complement of given number plus 1 to the least significant bit (LSB). For example 2's complement of binary number 10010 is (01101) + 1 = 01110.

What is the 2s complement of 33?

Therefore, the two's complement of the number – 33 is (1101 1111)2.


1 Answers

I would do simple arithmetic instead. The result is 14-bit signed, which is represented as a number from 0 to 2^14 - 1. Test if the number is 2^13 or above (signifying a negative) and then subtract 2^14.

int16_t fxls8471qr1_convert_raw_accel_to_mag(uint16_t raw, enum fxls8471qr1_fs_range range) 
{
  int16_t raw_signed = raw;
  if(raw_signed >= 1 << 13) {
    raw_signed -= 1 << 14;
  }

  uint16_t divisor;
  if(range == FXLS8471QR1_FS_RANGE_2G) {
    divisor = FS_DIV_2G;
  }
  else if(range == FXLS8471QR1_FS_RANGE_4G) {
    divisor = FS_DIV_4G;
  }
  else {
    divisor = FS_DIV_8G;
  }

  return ((int32_t)raw_signed * RAW_SCALE_FACTOR) / divisor;
}

Please check my arithmetic. (Do I have 13 and 14 correct?)

like image 93
uncleO Avatar answered Sep 18 '22 09:09

uncleO