u = (unsigned int) f; or u = (unsigned int) floor(f); or u = (unsigned int) ceil(f); or { float ipart, fpart; fpart = modf( f, &ipart ); u = (unsigned int) ipart; } or :
It's not the casting, it's what you are casting to. A char type can't (necessarily) hold the range of possible values. It's dangerous to use a char unless you know the value can't exceed 255 (which you may).
WRT the relocation errors you began this thread with, I believe those are an indication that a call/branch is out of range. This can happen on machines that use a branch-to-subroutine type instruction when the image gets large. Sometimes you can get around it using an indirect call through a pointer.
This has nothing to do with the AVR. Looks like an optimisation bug to me. doesn't GCC support some pragmas to exclude code from optimisation? Apart from that, as others have said, u = f should have worked too when the integer part of f is in the range of 0-255.
Normally, comp.arch.embedded is a helpful place, but some of the "answers" is this thread are ridiculous! People are leaping to conclusions like "the avr can't do floating point", "gcc can convert a floating point to an int, but not to a char", "try disabling optimisations", etc.
It seems no one has asked any /relevant/ questions the would have helped you out.
Have you got a minimal code snippet that illustrates the problem, and is valid and compilable C code? In this case, you would probably have something like:
// Use "volatile" so the code won't be optimised away volatile unsigned char u; volatile float f;
int main(void) { u = (unsigned char) f; return 0; }
Working out a minimal code snippet is extremely helpful in isolating the problem, and essential for other people to give more than hand-waving help.
Secondly, we need to know your command line switches. A common source of problems is incorrect switches (such as for those choosing the avr variant).
We also need to know the versions of the tools.
While avr-gcc has very few known issues that could result in wrong code or compile failures, I don't think any compiler claims guarantees of perfection - avr-gcc developers are entirely open about bugs, and very interested to hear if this does turn out to be a compiler bug. But in practice, it's rare that a user's problem is the result of a compiler bug rather than a misunderstanding or error in the user's code or command line.
You will get excellent support for avr-gcc on the avr-gcc mailing list - people there will try to help out with your actual problem rather than telling you your code is "silly", or that you should buy a different compiler and/or microcontroller. Of course, the first thing you will be asked there is the same questions I asked above.
If you don't want to join the mailing list, you can also use the gmane mailing list to newsgroup gateway - you can see it as newsgroup "gmane.comp.hardware.avr.gcc" on news.gmane.org.
Then I guess it's a avr-gcc porting problem. I'll check if arm-gcc works or not.
Perhaps its time to consider the advantages of paid for tools over free/open source ? I stopped using AVR-GCC a long time ago after comparing the machine code it produced with IAR's. I thought things might have improved but perhaps not - IAR works for Vlad on AVR but GCC screws up for the OP.
In that case i'm quite sure gcc promote internally the (unsigned char)f to an int. Differences appears when actually using the u variable (instead of just evaluate like in your code snippet) that's IMHO the initial issue.
Why not verifying this with avr-gcc -S yourfile.c
and read the assembler yourfile.s ...
What makes you think guys down here make ridiculous answers when obviously the initial question is not clearly exposed.
gcc does not promote the "(unsigned char) f" to an int - it would only do that if you were doing maths on the value.
The function used for this conversion is "__fixunssfsi", which converts a float into and unsigned int. gcc then converts this into an unsigned char (by simply taking the lower 8-bit register). But that's not "promotion", and it is a perfectly correct implementation.
You can be pretty confident that gcc gets the promotions and interpretations of the code correct. While the avr port is a relatively "small" compiler, the gcc front-end that interprets the C code is the same for all gcc ports.
But it is certainly possible that issues appear when the value is used - that's why the original poster has to provide a minimal code snippet that shows the problem.
And the elf output is properly linked against the required libraries (automatically - you don't need to specify the library on the command line).
But all I can do here is show that avr-gcc has no problems compiling and linking this code snippet correctly. To help the O/P, we need a snippet that fails for him, not one that works for me. Once he posts that snippet and the command line, people can really start to help him out rather than making wild hand-waving suggestions.
That's kind of the point, really. The OP hasn't given enough information to be able to diagnose his problem and help him out. But instead of asking for more information, people here have given a variety of useless information and suggestions. Not all the answers have been bad - suggestions to break it into steps and to look at the size of the code are good ideas. But none have asked him for the information that's needed.
If I were to post a question in a car newsgroup saying my Volkswagon is making a funny noise, I would expect to be asked to describe the noise, or to say if it was constant or comes and goes, or asked what year and model I have. I would not expect to be told that if I want a noise-free drive I should buy a Ferrari, or that someone else's bus makes a different noise.
An "unsigned char" is just a silly name for an uint8_t - an unsigned integer in the range 0 .. 255. Why do you see this as any different from converting the float to an integer in the range -32768..+32767 ? I presume the OP has made sure that the float in question is within a reasonable range for the conversion - otherwise his data will be invalid (though the program will still compile, link and run) - I don't know how overflows and underflows are handled by the cast-to-integer operations.
To take a simple example, you might want a make a pwm sine wave by:
This is doing floating point calculations and then casting it to an "unsigned char". The results would be exactly the same if pwmPercent were an "int".
It should be the same (to within rounding errors). avr-gcc, like most compilers, implements basic IEEE floating point standards. As far as I know, it doesn't implement NaNs, signed zeros, and other wierdo floating point stuff, just like most other compilers and most hardware FPUs.
As you have said yourself, it sounds like this could be an issue with the linker setup for this particular chip - it's nothing to do with the compiler as such. But you will get far more helpful answers from the avr-gcc mailing list - there is no need for workarounds like this until you have confirmed that it is a bug and not something else.
If it /is/ a bug in the linker setup, then the avr-gcc team would very much like to hear about it - that way it can be fixed for everyone.
And if a workaround of some sort is needed, then there may be better or more convenient alternatives - your fix here may be relying on the luck of the link order, and you could get the same problem later with something else.
Other possibilities are to use different -mmcu flags for compilation and linking - use "-mmcu=atmega32u2" during compilation (that ensures you get the right IO headers, etc.), and a different 32K micro when linking (to work around this possible bug in the atmega32u2 link setup). I've done similar things in the past to work with devices that were not yet supported.
Every C compiler I've seen does not require a cast to get the integer part of a float.
The compile just generates magical code in the background for it
myinteger = myfloat;
Or course, this implies that the C compiler is loading it's default RTL so that it knows how to handle floats, since AVR's to my knowledge, do not have float operations in the cpu..(FPU) etc..
You said that negative float values convert to an unsigned value of 0. Here's what your sample programs shows:
-5.627771
251
-9.410577
247
-9.602361
247
-6.129940
250
Negative float values do not convert to unsigned values of 0. IOW, it doesn't work the way you said it did, and the example program you posted proves it.
I agree that the OP's problem had nothing to do with float/int conversion. The OP's problem is that he ran out of code space.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.