chipKIT® Development Platform

Inspired by Arduino™

Trouble converting integers to bytes and vicecersa

Created Sat, 12 Nov 2011 18:37:29 +0000 by Pepe


Pepe

Sat, 12 Nov 2011 18:37:29 +0000

Hi everybody,

I've been working with Arduino boards for almost 2 years and when I learned about Chipkit I decided to buy a board immediately.

To test it, I used code I wrote to communicate with an accelerometer using I2C. On the Arduino platform it worked nicely, but on Chipkit it was unusable. I started looking for the problem and at the end I concluded that converting the bytes read sequentially from the accelerometer to an integer was the underlying problem.

I would appreciate any suggestion as to the problem I observed is a real issue. I am attaching a sample code that runs nicely on the Arduino but fails on Chipkit.

Regards.

/ TEST PROGRAM FOR SPLITTING INT IN BYTES / ASSEMBLYING BYTES INTO INT

boolean done = false; byte hb, lb; int aux;

void setup(){ // SERIAL PORTS INITIALIZATION Serial.begin(9600);
}

void loop() { static boolean led; byte lb, hb; int aux, n, newn;

if (done == false)

}

void splitint( int x) { Serial.print("NUMBER = "); Serial.print(x); lb = lowByte(x); aux = lb; Serial.print(" : LB = "); Serial.print(aux); hb = highByte(x); aux = hb; Serial.print(" HB = "); Serial.println(aux); Serial.println();
}

void assembly(void) { int newn; aux = lb; Serial.print("LB = "); Serial.print(aux); aux = hb; Serial.print(" HB = "); Serial.print(aux);
newn = word(hb, lb); Serial.print(" : WORD = "); Serial.println(newn); Serial.println(); }


lloyddean

Sat, 12 Nov 2011 19:57:28 +0000

On Arduino boards an 'int' is 2 bytes in length.

On the ChipKit boards an 'int' is 4 bytes in length.

Try outputting the sizeof(int) to verify for yourself.

unsigned char   bytes[sizeof(int)];

void assembly()
{
    int n = 0;
    for (int i = 0; i < sizeof(int); i++)
    {
        n |= (bytes[i] << (i * 8));
    }

    Serial.print("\nNUMBER = 0x");
    Serial.print(n, HEX);
}

void splitint(int n)
{
    Serial.print("\nNUMBER = 0x");
    Serial.print(n, HEX);

    Serial.print("\tLSB to MSB");
    for (int i = 0; i < sizeof(int); i++)
    {
        Serial.print(" ");
        bytes[i] = n & 0xFF;
        n >>= 8;

        Serial.print(bytes[i], HEX);
    }
}

void loop()
{
    static bool fLooped = false;
    int n;

    if ( ! fLooped )
    {
        n = 1500;
        splitint(n);
        assembly();
    
        Serial.println();
    
        n = -1500;
        splitint(n);
        assembly();
        
        fLooped = true;
    }
} 

void setup()
{
    Serial.begin(9600); 
}

avenue33

Sat, 12 Nov 2011 21:41:23 +0000

Don't use the [color=#FF0000]int[/color] type!

It means [color=#0000FF]int16_t[/color] on Arduino but **[color=#0000FF]int32_t[/color]**on chipKIT because the micro-controller is 32 bits.

Use instead the [color=#FF0000][ u ] int ( 8 | 16 | 32 ) _t[/color] types.

I experienced the same problem. Find more about Arduino / chipKit tips and tricks :arrow: here.


lloyddean

Sat, 12 Nov 2011 22:31:50 +0000

I was leading him into understanding that very thing.

One should never use the intrinsic built-in data types and assume their size and value ranges and expect the code to be portable.


WestfW

Sun, 13 Nov 2011 01:41:46 +0000

So does this mean that the standard Arduino functions word(h,l), lowByte(x) and highByte(x) are broken in the chipKit distribution? I didn't see the original poster writing any of his own code that assumed particular word lengths...

That can be fixed! Though I can't figure out what highByte(int) should return on a system with 32bit ints; presumably it should be (re)defined to operate only on 16bit types.


lloyddean

Sun, 13 Nov 2011 04:01:18 +0000

While I haven't tested any of the functions word(h,l), lowByte(x) or highByte(x) I have output the size of the 'word' type and it is 4 bytes.

A 'word' is traditionally defined as the native register size. On the MIP32 the register widths are 4 bytes.


WestfW

Sun, 13 Nov 2011 09:54:24 +0000

The complaint is about the reassembled word?

On Arduino Uno:
NUMBER = 1500 : LB = 220 HB = 5
LB = 220 HB = 5 : WORD = 1500

NUMBER = -1500 : LB = 36 HB = 250
LB = 36 HB = 250 : WORD = -1500
On ChipKit:
NUMBER = 1500 : LB = 220 HB = 5
LB = 220 HB = 5 : WORD = 1500

NUMBER = -1500 : LB = 36 HB = 250
LB = 36 HB = 250 : WORD = 64036

In this case, the problem is that word() (via makeWord()) returns an unsigned 16 bit quantity, which is then assigned to a signed int variable (aux) This (rather understandably) works differently if ints are 16 bits or 32bits.

You can fix this in the original sketch, in way that is portable between Arduino and ChipKit, by changing the calls to word():

newn = (int16_t)word(hb, lb);

Note that this isn't ALWAYS the correct thing to do; it will depend on whether you're trying to assemble a value that was originally signed, or originally unsigned.

Or you can make newn be an int16_t, which is "more correct"

BTW, note that the "byte" type goes away in Arduino 1.0...


Pepe

Mon, 14 Nov 2011 20:24:50 +0000

Hi

Thanks a lot for your prompt replies.

I found the contributions quite interesting and enlightening.

I was not aware than on the Chipkit platform the int type is 4 bytes long. This clarifies the situation.

Starting from this premise, I was able to write a routine to convert the positive and negative values (2 bytes) read from the accelerometer into a corresponding positive or negative integer 4 bytes long.

Thanks again for your support.