2022-12-23

How to convert two's complement to an int - using C?

I'm trying to read a register from an INA260 using a Pico microcontroller. My program is in C. The register I'm having trouble with contains the value of the electrical current measured by the INA260. Since the INA260 accommodates measurement of current flowing in either direction, the mfr decided to cast the two bytes of measurement data in two's complement. This allows for a "negative" current - meaning only that the current is flowing in one direction instead of the other. I can appreciate this is a clever solution from a hardware perspective, but from the software perspective, I am very fuzzy on two's complement.

In an effort to help frame my question & give it some context, here's how I read & process the INA260's measured electrical current in the designated register. This code may not be elegant, but it gives the correct answer:

    uint8_t rcvdata[2];

/*  Read the Current Register (01h); INA260_MILAMP_REG _u(0x01)  */

    reg = INA260_MILAMP_REG;
    i2c_write_blocking (i2c_default, ADDR, &reg, 1, true);
    i2c_read_blocking(i2c_default, ADDR, rcvdata, 2, false);
    int milliamps = rcvdata[1] | rcvdata[0] << 8;
    printf("\ninteger value in register: %d milliamps", milliamps);
    printf("\nmeasure current by INA260: %.*f amps\n", 2, milliamps*1.25/1000);

In summary:

  • define the data register location (reg) & send that to the INA260 at its bus address
  • read 2 bytes (MSB first) into the rcvdata array
  • convert the 2 byte unsigned data to an integer
  • convert the result to amps (from milliamps; 1.25mA is one unit), and print
  • Register bytes are sent via I2C interface, MSB first.

Following is the output from this code:

integer value in register 0x01: 39 
measured current at IN+ pin: 0.05 amps (i.e. 47.5 mA)

The code above yielded the correct answer in this case. In other words, as I have the INA260 wired, the current flows in the direction designated as positive by the manufacturer. As I understand it, the two's complement format is exactly the same as unsigned data when the value is positive, and so I "got lucky". However, there will be other situations when the INA260 is wired in such a way that the current is considered "negative", and I'm in a fog as to how to deal with two's complement when the value is negative.

Now then, at last, my questions are these:

  1. What changes are needed to the code listed above so that it can recover the negative integer value? i.e. what do I need to do instead of int milliamps = rcvdata[1] | rcvdata[0] << 8; to get the negative value?

  2. As I understand it, two's complement format is not covered by a standard, nor is it a data type in C. If that's true, how one can know if a block of data is cast as two's complement?



No comments:

Post a Comment