"General" Typecast from int32 to int16?

Status
Not open for further replies.

hyperjm

Member
Hello!

So I have been working on porting fabio varesano's "free-imu" arduino code over to teensy 3.0, and have realised that it's a real nightmare to switch from the old 16bit int to the new 32 bit ints when using the I2C "Wire" library. I am not looking forward to spending hours poring over old code looking for all of them and correctly replacing them. I'm asking if there is any way we can force the teensy 3.0 to "redefine" the default "int" as a 16 bit signed integer? Or must I typecast everything? I don't mind losing performance(if I do lose any).

Cheers!
jeremy
 
polite bump.. I don't know why no one has brought this up before, maybe I'm the only one with problems but when porting over from ATmega to teensy, has anyone else had a bad experience with floats? I have now successfully "type-casted" all integers to int16_t, and have no problems with displaying raw int values, but when it comes to floats it seems that formatting is also vastly different, but I have no idea what to typecast them as. Most floats displayed come out as 0000CDEF(#0x notation), instead of filling them all out as before(eg. 3FE2A3D1)

I have tried float32_t, and it doesn't seem to work. As far as i know, Arduino AVR Atmegas use 32 bit floats. Does teensy 3's ARM floats use 32, 64 or 128 bits? If so, how should I go about changing(type-casting) all these old floats to work with Arduino's old 32 bit floats?
 
I have tried float32_t, and it doesn't seem to work. As far as i know, Arduino AVR Atmegas use 32 bit floats. Does teensy 3's ARM floats use 32, 64 or 128 bits? If so, how should I go about changing(type-casting) all these old floats to work with Arduino's old 32 bit floats?
Arm tends to use IEEE single precision (32-bit) for the 'float' type, and IEEE double precision (64-bit) for both 'double' and 'long double' types. Arduino uses IEEE single precision for all three types.

My take is you should not be using int16_t, int32_t, etc. directly, except in structures where you need to get an exact layout for communicating with an external device or program, but instead use one or more types that you create in a global header file that is based on #ifdef so that you can easily change this at compile time:

Code:
#if defined(__arm__)
typedef int32_t normal_int_t;

#elif defined(__AVR_ARCH__)
typedef int16_t normal_int_t;

#else
#error "Please update #ifdef to target the machine"
#endif

C was originally written on a machine where double was more efficient than float, so floating constants without a 'f' suffix are treated as double values, and when passed, floats are converted to double (for unprototyped functions or for stdarg functions like printf). You might be running into the implicit conversion of float to double if you are using printf to display the type.
 
Last edited:
Could you post a link to the FreeIMU library?

Usually porting the code, if any porting is needed at all, is pretty simple. With these movement sensors that returned 2's complement 16 bit numbers, if the author used "int" instead of "int16_t" for the variable that receives the bytes, the edit is very simple. From there, the IMU math is usually very portable.

We can talk about this theory at length... but I usually prefer to just look at the code, and if necessary buy or build the hardware and test it. Porting code really isn't that difficult, and I'm happy to do it. But you need to give me a link to the specific code (any please not to a launchpad.net page without a clearly indicated download link).
 
thank you so much for offering to help. I'll try to make this easy for you..
Here's the download link to the entire library
http://bazaar.launchpad.net/~fabio-varesano/freeimu/trunk/revision/31
"download tarball"

I'm using the HMC5883 3-axis magnetometer and the MPU6050 6-axis acc/gyro with FreeIMU libraries.

Here's the original code for the MPU6050 :
http://bazaar.launchpad.net/~fabio-varesano/freeimu/trunk/view/head:/libraries/MPU60X0/MPU60X0.cpp

Data types in the MPU6050 library are already quite clearly defined, with most of the ints being int16_t.
My original issue was with line 1746 (getMotion6), because the main code that calls this MPU6050 library assigns int* to the function instead of int16_t.

Here is the main code :
http://bazaar.launchpad.net/~fabio-varesano/freeimu/trunk/view/head:/libraries/FreeIMU/FreeIMU.cpp

it calls getMotion6() at line 257. This has been fixed somewhat with typecasting, i still get different values from with Duemilanove but it is not as significant as before.
However, converting these values to floats is still a problem, at line 480 (getQ(float*)) this returns the abovementioned "0000CDEF" values when printed to serial(byte-converted to chars) via the communication utils() serialPrintFloatArray() function in:

http://bazaar.launchpad.net/~fabio-...ead:/libraries/FreeIMU/CommunicationUtils.cpp



Here is the magnetometer library:
http://bazaar.launchpad.net/~fabio-varesano/freeimu/trunk/view/head:/libraries/HMC58X3/HMC58X3.cpp

I have problems with line 304(getRaw(int)) and 327(getValues(float))
On the Arduino Duemilanove it returns the values just fine. On the Teensy 3.0 it always returns zeros, despite typecasting to getRaw(int16_t)
The same problems occur with using getValues(float) as above.

thank you in advance!
I hope this will also help anyone else porting over to teensy 3's 32-bit ARM

Cheers
Jeremy
 
thank you! the
#if defined(__arm__)
typedef int32_t normal_int_t

I was going to be lazy and use "typedef int16_t normal_int_t" so my entire application runs on int16_t but I have since replaced each and every int in the program with int16_t.

IT DOES WORK! somewhat.. I suspect the difference in values might also somehow be due to hardware(pull-up resistors), 3.3V instead of 5V SDA/SCL bus etc.
But yeah now my problems are with floats, as detailed below. If ARM does also specify floats as 32bits, then I cannot see why ARM/Arduino's floats are any different. I read somewhere else that the way they bit-shift is different, but I cannot yet understand that difference. I found that here:

http://www.adafruit.com/blog/2012/10/19/teensy-3-0-software-update/

Well just taking things easy now and hopefully I'll get the entirely library ported by next week! (If I do manage it I'll be sure to post it somewhere here for sharing)
FreeIMU seems to be quite popular with the quadcopter hobby community.

Cheers and thanks for great help
jeremy
 
Not that it may be relevant here but I noticed Teensy 3 actually implements double precision floats as doubles, rather than double == single precision floats like AVR-based Arduinos. (I was looking at accumulated noise statistics in a high-resolution ADC, where using doubles actually made a measurable difference.)
 
Looking at the code, yes, there are some issues. It seems getMotion6 needs to be changed to take int16_t pointers. The calling code is already using an array of int16_t and the code in getMotion6 uses int16_t, but the function getMotion6 is improperly defined.

Hopefully Fabio will be willing to update the code? I think that's a far better solution.

I didn't dig into the float issue. I really need some real data to be able to work on this.....

I ordered a set of PCBs from OSH Park and I got the 2 main chips on order from Digikey and Component Distributors. I couldn't find an easy way to buy the pressure sensor chip, but maybe that doesn't matter. When all this stuff arrives, I'll build up one of these boards so I can do some real testing.
 
Looking at the code, yes, there are some issues. It seems getMotion6 needs to be changed to take int16_t pointers. The calling code is already using an array of int16_t and the code in getMotion6 uses int16_t, but the function getMotion6 is improperly defined.

Hopefully Fabio will be willing to update the code? I think that's a far better solution.

I didn't dig into the float issue. I really need some real data to be able to work on this.....

I ordered a set of PCBs from OSH Park and I got the 2 main chips on order from Digikey and Component Distributors. I couldn't find an easy way to buy the pressure sensor chip, but maybe that doesn't matter. When all this stuff arrives, I'll build up one of these boards so I can do some real testing.

oh wow I wasn't expecting you to buy anything. I basically got the GY-86 inertial measurement unit from Alibaba, if that helps. It's similar to the freeimu. Hope you didnt waste any money!
 
Looking at the code, yes, there are some issues. It seems getMotion6 needs to be changed to take int16_t pointers. The calling code is already using an array of int16_t and the code in getMotion6 uses int16_t, but the function getMotion6 is improperly defined.

Hopefully Fabio will be willing to update the code? I think that's a far better solution.

I didn't dig into the float issue. I really need some real data to be able to work on this.....

I ordered a set of PCBs from OSH Park and I got the 2 main chips on order from Digikey and Component Distributors. I couldn't find an easy way to buy the pressure sensor chip, but maybe that doesn't matter. When all this stuff arrives, I'll build up one of these boards so I can do some real testing.

Hello!
I have found the problem! But I am not sure of how to solve it correctly... the wire and i2c libraries work perfectly, and int16ts are coming in nicely. But the floats do not print and therefore do not compute in the host application(made with processing) properly because of the following function:

void serialFloatPrint(float f) {
byte * b = (byte *) &f;
for(int i=0; i<4; i++) {

byte b1 = (b >> 4) & 0x0f;
byte b2 = (b & 0x0f);

char c1 = (b1 < 10) ? ('0' + b1) : 'A' + b1 - 10;
char c2 = (b2 < 10) ? ('0' + b2) : 'A' + b2 - 10;

Serial.print(c1);
Serial.print(c2);
}
}

I am unsure of how this function works to convert from float to char, but it works for the Atmega328. I am quite sure, after revising the code many times, that this is the most likely cause of the float errors. Any idea what it should be for teensy 3.0?

Regards,
Jeremy
 
I'm working with FreeIMU today. I quickly got to the point where the code compiled, but I get all zeros.

The problem appears to be in the invSqrt() function.

Here's a redesign of that function, which seems to work on Teensy 3.0 and hopefully should be much more portable.

Code:
float invSqrt(float number) {
  union {
    float f;
    int32_t i;
  } y;

  y.f = number;
  y.i = 0x5f375a86 - (y.i >> 1);
  y.f = y.f * ( 1.5f - ( number * 0.5f * y.f * y.f ) );
  return y.f;
}

This seems to work. But I haven't calibrated my hardware or done anything other than look casually at the numbers in the serial monitor while tilting my breadboard.

If anyone is still following this thread, please let me know if this truly solves the problems?
 
Status
Not open for further replies.
Back
Top