avr-gcc floating point problems

Are you sure you're not just flat out running out of room?

--
Tim Wescott
Control system and signal processing consulting
www.wescottdesign.com
Reply to
Tim Wescott
Loading thread data ...

On a sunny day (Thu, 18 Mar 2010 13:16:33 -0700 (PDT)) it happened linnix wrote in :

Are you doing fft? (sin cos). I just tried integer fft in C, made 2 versions, one with an 8 bit sine lookup table, and one with a 16 bit table. Fiddled it so all values fit in a 16 bit integer... can do integer math. Now I can port it to PIC.... in asm. The difference is noticable when compared to floating point, but on a 64 bit high display the 'noise' reduces to very little. I mean you need to divide a lot... to fit the maximum... So it all depends, I think my integer fft is good, worth some money too.

Reply to
Jan Panteltje

linnix skrev:

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

Did you report the problem to the WinAVR developers?

--
Best Regards
Ulf Samuelsson
These are my own personal opinions, which may
or may not be shared by my employer Atmel Nordic AB
Reply to
Ulf Samuelsson

it

Should be plenty of Flash and SRAM left.

avr-gcc.exe -I"./.." -I"../conf" -I"../../.." -I"../../../../common" - mmcu=3Datmega32u2 -Wall -gdwarf-2 -Os -fsigned-char -ffunction-sections - MD -MP -MT default/usb_task.o -MF default/dep/usb_task.o.d -c usb_task.c -o default/usb_task.o Linking avr-gcc.exe -mmcu=3Datmega32u2 -Wl,-Map=3Dudip.map,--cref,--gc-sections,-- relax default/main.o default/cdc_task.o default/uart_usb_lib.o default/ usb_descriptors.o default/usb_specific_request.o default/wdt_drv.o default/uart_lib.o default/usb_drv.o default/scheduler.o default/ usb_device_task.o default/usb_standard_request.o default/usb_task.o

-o udip.elf Create hex file AVR Memory Usage

---------------- Device: atmega32u2

Program: 7664 bytes (23.4% Full) (.text + .data + .bootloader)

Data: 877 bytes (85.6% Full) (.data + .bss + .noinit)

Reply to
linnix

I can probably rewrite it in fixed point if necessary. But the target will be ARM anyway, I am just trying it out before the target is ready.

Reply to
linnix

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.

George

Reply to
George Neuner

--------------------------

----------------------------

OK, I think the problem is WinAVR not founding the math library, even with the "-lm" flag. I made a local copy of libm.a to link in explicitly for now. I will check it out for sure before reporting.

Reply to
linnix

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.

Meindert

Reply to
Meindert Sprang

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

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.

mvh.,

David

Reply to
David Brown

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.

Are you listening Chris Hills ?

Michael Kellett

Reply to
MK

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

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.

Habib ...

Reply to
Habib Bouaziz-Viallet

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

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.

I have done exactly that, using the command line:

D:\Micros\WinAVR-20100110\bin\avr-gcc -mmcu=atmega128 -Os -std=gnu99

-Wa,-ahlsd=test.avr.20100110.lst -fverbose-asm test.c -o test.elf

(Obviously the path to avr-gcc will vary).

The relevant assembly code is:

64 .global main 66 main: 67 /* prologue: function */ 68 /* frame size = 0 */ 69 0022 6091 0000 lds r22,f ; f.0, f 70 0026 7091 0000 lds r23,(f)+1 ; f.0, f 71 002a 8091 0000 lds r24,(f)+2 ; f.0, f 72 002e 9091 0000 lds r25,(f)+3 ; f.0, f 73 0032 0E94 0000 call __fixunssfsi ; 74 0036 6093 0000 sts u,r22 ; u, tmp44 75 003a 80E0 ldi r24,lo8(0) ; , 76 003c 90E0 ldi r25,hi8(0) ; , 77 /* epilogue start */ 78 003e 0895 ret

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.

Reply to
David Brown

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

That is exactly the point. Why in the earth someone would need to convert a float (doing sine and cosine) to a unsigned char ???

I said that extracting the integer part of the float is ok when casting a float to an int.

When you make a cast from a float to an unsigned int it would result a zero if the float is negative (not quite sure either ... just conjecture)

BTW i don't know what would be the result if the target has a FPU (like our big bunch desktop machines) ... :-)

Volkwagon have funny noises even fresh out of the factory ... (Just a joke)

Habib.

Reply to
Habib Bouaziz-Viallet

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

I don't think I'm following your argument here.

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:

uint8_t pwmPercent; pwmPercent = 100 * ((sinf(omega * time) + 1) / 2);

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.

Reply to
David Brown

Em 18/3/2010 17:39, linnix escreveu:

I would use round(), trunc(), ceil() or floor() as each could better fit.

--
Cesar Rabak
GNU/Linux User 52247.
Get counted: http://counter.li.org/
Reply to
Cesar Rabak

You're sure of something incorrect there.

That's none of your business. It's perfectly allowed C code, so the compiler _must_ support it.

Well, wrong again. Values from 0 (inclusive) to -1 (exclusive) convert to zero, all other negative values cause undefined behaviour.

That has nothing to do with it, in principle.

Reply to
Hans-Bernhard Bröker

... A bunch of misunderstanding as usual.

But where have you been while others are struggling about that funny business ?

Playing with sine and cosine and casting results to unsigned ... pity ! And you're a pity also comming here and explain me what is permitted as a programmer.

Habib

Reply to
Habib Bouaziz-Viallet

r)f

re)

rt

Why? The result is a phase correction output driving 8 bit D/A. The D/A does not understand float.

There is no problem with the code or compiler. However, WinAVR math library files are not properly setup. Certain floating point ops cause confusions with the linker. I wish the error messages are easier to understand.

Reply to
linnix

-------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------

Did you use the proper -mmcu= option on the GCC command line?

The errors point thet the compiler has generated code for

13 bit addresses (8 kiB memory), and the code exceeds the 13 bit address range.
--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio

--------------------------

----------------------------

Yes, -mmcu=3Datmega32u2

That's why its confusing. Non-existence is also out of range.

I can get around it with including the source or binary for the fp_powodd function.

Reply to
linnix

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.