Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Unsigned int to signed int conversion

Other Parts Discussed in Thread: MSP430G2553

I have uint16_t type of data from ADC conversion register, which can take value from 0 - 30000. This is after multiplication by some constant.

Now I have to print it on graph, & have to level shift from mid point so I got negative value range i.e -15000 to +15000.

What should be correct conversion method like

uint16_t val;

int16_t conv_val;

if( val > 32767 )

{

val = 32767;          /* limit it for avoiding saturation as conversion to signed is needed */

}

conv_val = (int16_t)val; //is it correct way

  • This is a C question, not a MSP430 question.

    Regards,

    Peppe

  • Aamir Ali said:
    is it correct way

    There are multiple ways.

    You may as well cast the signed into to an unsigned long, just to assing it to the signed int then. The compiler will take care of the range and sign problem then.

    conv_val = (int16_t)((int32_t)val);

    I haven't tested it but it should do.

  • I would just subtract an offset of 32768 (allowing for the correct data types) like so:

    #include <msp430G2553.h>
    volatile long int lsnum1;
    volatile long int lsnum2;
    volatile unsigned int usnum1;
    volatile unsigned int usnum2;
    volatile unsigned long int uslval;
    volatile int conv_val1;
    volatile int conv_val2;
    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;
        while (1)
        {
             usnum1= 32769;
             usnum2= 32767;
            lsnum1 = usnum1 - 32768;
            lsnum2 = usnum2 - 32768;

            conv_val1 = (int)(long)(usnum1)-32768; //I had to subtract the offset
            conv_val2 = (int)(long)(usnum2)-32768; //from Jens' method too.
        }
    }

  • Aamir Ali said:

    I have uint16_t type of data from ADC conversion register, which can take value from 0 - 30000. This is after multiplication by some constant.

    Now I have to print it on graph, & have to level shift from mid point so I got negative value range i.e -15000 to +15000.

    What should be correct conversion method like

    uint16_t val;

    int16_t conv_val;

    if( val > 32767 )

    {

    val = 32767;          /* limit it for avoiding saturation as conversion to signed is needed */

    }

    conv_val = (int16_t)val; //is it correct way

    If val is always from 0-30000, there is no need to do if (val > 32767) ... and you can also treat it as conv_val without any conversion.

    union
    {
      unsigned int val;
      signed int conv_val;
    } samething;

    Do you ADC and multiply with val. But do you level shifting and plotting with:

    Conv_val -= 15000;

    The “conversion” is done effortlessly and invisibly.

  • Joseph Raslavsky said:
            conv_val2 = (int)(long)(usnum2)-32768; //from Jens' method too.

    Try again with conv_val2 = (int)((long)usnum2)-32768;
    It's possible that the compiler will 'optimize' the (int)(long) sequence to just (int) if you don't put the (long) and the original value into brackets.
    I'm not that firm regarding these details of the C language.

  • Jens-Michael Gross said:

            conv_val2 = (int)(long)(usnum2)-32768; //from Jens' method too.

    Try again with conv_val2 = (int)((long)usnum2)-32768;
    It's possible that the compiler will 'optimize' the (int)(long) sequence to just (int) if you don't put the (long) and the original value into brackets.
    I'm not that firm regarding these details of the C language.

    [/quote]

    Yes, but the offset of 32768 is essential.

    Well I had to review how negative numbers are expressed in binary. And one way, and apparently the way the compiler does it, is the 2's complement where all positive values are straight binary for the range where the msb is '0'. The negative values are formed by inverting all bits and then adding 1 resulting in the msb becoming '1'.

    So the compiler interprets the binary values at the transition values 01111111 and 10000000 in unsigned mode as 32767 and 32768. But in signed mode the interpretation is 32767 and -32768 for the two values, a discrete offset at that mid-point.

    Thus telling the compiler to just convert from unsigned to signed will not work for the OP since he does not want such a discontinuous jump of 32767 to -32768 at the mid-point of his binary numbers, but rather wants a continuum starting from -32768 to 32767, or in his case -15000 to 15000.

    Or just do as ocy says and simply offset the range of binary numbers:

    union
    {
     
    unsigned int val;
     
    signed int conv_val;
    } samething;

    Do you ADC and multiply with val. But do you level shifting and plotting with:

    Conv_val -= 15000;

  • Joseph Raslavsky said:
    Yes, but the offset of 32768 is essential.

    Well, depends. I agree that my proposed method would discard the uppe rbits. When casting an unsigned long to a signed int, the result cannot be negative, while a binary reintrpretation like the union, would interpret the former BIT15 of the positive value as sign bit of the result.

    However, the original request was about shifting a value from 0 to 30000 by 15000.
    Thiis is simple: If 0 means -15000, 15000 means 0 and 30000 means 15000, then simply subtract 15000 from the value. Both, original range and result nicely fits into signed int.
    So in case of using the union approach, ensure by design or by test that val is < 32768 before shifting conv_val.

**Attention** This is a public forum