Looking for a discussion

Status
Not open for further replies.

dave

Active member
Looking for a discussion about porting from 8 bit to ARM

Hi guys,
I m looking everywhere for a discussion opened by Paul (the brain behind Teensy) some years ago.
In this article/discussion Paul is going to explain that the most code used for Arduino (for example for reading sensors from a board like MPU-9150) cannot be directly used or imported in Teensy.
The reason was something like:
"in Arduino (8-bit) you can do something like:
Code:
return (int16_t)((H<<8)+L);
where H is the MSB and L the LSB. But in a ARM microprocessor you cannot do that, because registers are 32 bit. So the above line of code would not work correctly if used in Teensy"

for this reason you should not import libraries used with Arduino just because they are already available and tested. The different register size of a ARM requires to know what one wants to do.

Why I m looking for it? Not because of Arduino.... but because I did some software develop 4-5 years ago and now I want to import my own code to Teensy. I'd like to not have problem like that one.

Regards
 
Last edited:
Where-ever the actual conversation is, that you are trying to find, it isn't that likely to have anything in it like your given example - that methodology is employed in many cases where values using more than 8 bits are transferred via 8 bit interfaces, like I2C for example, such values need to be reconstructed in the receiving code and that method is the most popular way.

I tried to find 'that conversation' or any really good reference for this but I could not, I was hoping to find somewhere anybody posted a reasonable listing of culprit AVR registers some authors directly manipulate(d) in their libraries but I did not.

I'd recommend you install the latest Teensyduino to a nice fresh Arduino and have a look around - I haven't (really) found a library that didn't play nice on Teensy 3.1, amongst the ones Teensyduino installed at least, although I should admit that I have hardly gone to the trouble of trying each and every last one.


What was the platform for your old project anyway?
 
Hi Rob,
thanks for your answer!!
Paul Stoffregen knows very well about that discussion. But I think it was an article posted on internet, somewhere, and Paul did post here in this forum just the link to that.

Anyway: I developed some libraries for Arduino 2009 at the time. The library just read some value coming from the I2C and store them in the right order in a 16 bit register.
Now....I really need to use that libraries again and I m afraid that Teensy by using 32 bit registers (when defining a variable as an Integer) messes up my code and could lead to problems and bugs that are very difficult to find.

Even if the conversation has been deleted, it would be nice to know what should I pay attention for, when porting the software from a 8bit architecture to the ARM.

Regards!
 
Have you tried compiling the old project after selecting Teensy 3.1 as the target?

This will be the quickest way toward updating the code to work with ARM imho - if you try compiling you might get a nice surprise with very little to fix.

If you try it and the problems are very far above your head then you need only show the code and resultant error messages to get help.
 
That's the problem! It compiles without any error.

So the problem is:

a declared int in Arduino is 16 bit
a declared int in ARM is 32 bit wide.

What happen if I tried to copy and shift 8 bit registers in a ARM Architecture like in the example above?
 
Indeed, the common gotcha involves I2C motion sensors, where a pair of bytes represents a 16 bit signed integer.

Several correct ways exist to combine the 2 bytes into the intended 16 bit integer.

What happen if I tried to copy and shift 8 bit registers in a ARM Architecture like in the example above?

This type of question is best answered by actually trying your code on real hardware!

Small details matter (which is why we have the "forum rule"). For example:

Code:
void setup() {
}

int calc(unsigned char H, unsigned char L) {
  return (int16_t)((H<<8)+L);
}

void loop() {
  Serial.println(calc(255, 255));
  Serial.println(calc(4, 1));
  Serial.println();
  delay(1000);
}

This code prints the proper results:


However, if I try the exact same line you posted, with L & H as signed chars, the wrong result is printed.

Code:
void setup() {
}

int calc(signed char H, signed char L) {
  return (int16_t)((H<<8)+L);
}

void loop() {
  Serial.println(calc(255, 255));
  Serial.println(calc(4, 1));
  Serial.println();
  delay(1000);
}

-257
1025

Now, I could write a lengthy message about compiler details and 2's complement number systems and sign extension. But that's not the point I wish to make.

The point is, small details like the types of the variables matter greatly. That's why we have the "forum rule" and generally try to encourage posting of complete code samples that can actually be copied into Arduino and run, rather than just code fragments, and especially code fragments that lack the types of their variables.
 
Ok sorry,
the real intention was to find that article you wrote somewhere. Because I need it as a basis to understand what's going up with the porting of software.

So I think I wrote in the wrong section. Please move the whole thread to Project & guidance, since I have no snippet of code that could be simply run once posted here.
 
Several correct ways exist to combine the 2 bytes into the intended 16 bit integer.

Code:
int calc(unsigned char H, unsigned char L) {
  return (int16_t)((H<<8)+L);
}

What usually gets people into trouble with code to convert 2 unsigned chars into a signed 16-bit integer when going from an 8-bit AVR processor (Arduino Uno for example) is not using the (int16_t) cast. If you don't have the cast, it won't properly sign extend the result:

Code:
int calc(unsigned char H, unsigned char L) {
  return (H<<8)+L;
}

void loop() {
  Serial.println(calc(255, 255));
  Serial.println(calc(4, 1));
  Serial.println();
  delay(1000);
}

On a system with 16-bit integers (Arduino Uno), this prints -1 and 1025. On a system with 32-bit integers (Teensy 3.1) this will print 65535 and 1025. If you put in the explicit type conversion, or change the return type of calc to be int16_t, the compiler will then do an explicit sign conversion operation.

The use of explicit signed char is not typically not as much of an issue, since that would produce the wrong result on Uno's as well. However, other people have run into a different situation where char sign-extends on the AVR platform, and zero-extends on the ARM platform. IMHO, for representing characters it should have been zero-extending, but C was designed in an era by Americans in an era when they/we didn't need to worry about running in the wide world (the US character encoding is 7-bit ASCII, so it doesn't matter whether char is signed or unsigned, and the PDP-11 that C was designed around, always sign extended load byte instructions). Just to be clear, it is useful to have a signed 8-bit type, it is just that type should not be the default type to hold characters. Dennis Ritchie who was one the main inventors of C had said that with the benefit of hind-sight, he thought that it should be zero-extending.

Note, from a standards point of view, the result of the shift left is undefined when int is 16-bits, because you are shifting into the sign bit. However, in any platform you are going to run into, will get the expected results. When the original ANSI C committee was formed to standardize the C language, there were two members that did not use the now traditional 2's complement integer arithmetic on their legacy mainframes, Univac used 1's complement integer arithmetic, and Burroughs used signed magnitude integer arithmetic. By the time the standard came out, the two companies had merged. As an aside, I was there also, and in the early days, I represented a manufacturer (Data General) that had its own set of problems with C (the big issue was the pointer to byte used a different representation than pointer to 16-bit word, but also that hardware did not have signed shift right instructions).

<edit>
Besides the size of int/unsigned int, and sign extension of char, another area that bites people is double on the AVR is the same size/representation as float, while on the ARM, it is double the size and a different representation. In this case, the solution is to only use the float type and not use the double type. However, you will need to add a f suffix to all floating point constants, and call the float version of the math functions (i.e. sinf instead of sin). If you do this, when the Teensy 3.1++ or 4.0 comes out, your code will run much faster, as the hints for that platform say that it will have hardware support for single precision floating point (but not double precision).
 
Last edited:
Status
Not open for further replies.
Back
Top