Compiling a program that uses double for the ATtiny4

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Although I do not really plan on using double, I would like to understand why this is a problem.

 

#include <stdint.h>
#include <avr/io.h>
#include <util/delay.h>

double y[1] = {2.0}; // doesn't work
//static double y[1] = {2.0}; // works
//uint8_t y[1] = {2}; // works
int main(void)
{
    DDRB |= 1 << DDB1;
    while(1)
    {
        if( y[0] > 0)
        {
            PORTB ^= 1 << PORTB1;
        }
        _delay_ms(1000);
    }
    return 0;
}

 

The code above does not compile for the ATtiny4. I try to compile with avr-gcc and options -mmcu=attiny4, -Os, and -DF_CPU=1000000UL. The compiler balks with the following message
/usr/local/Cellar/avr-gcc/6.2.0/lib/gcc/avr/6.2.0/../../../../avr/lib/avrtiny/libm.a(gesf2.o): In function `__gesf2':
(.text.avr-libc.fplib+0x0): undefined reference to `__fp_cmp'
collect2: error: ld returned 1 exit status 

 

The optimization level does not seem to have any affect on it. Changing the declaration of the array y to one of the following fixes things.
 

static double y[1] = {2.0};

or 

uint8_t y[1] = {2};

 

It also works if y is passed to a function.

 

#include <stdint.h>
#include <avr/io.h>
#include <util/delay.h>

double y[1] = {2.0};
void update(double *y)
{
    y[0] = 2.0;
}
int main(void)
{
    DDRB |= 1 << DDB1;
    while( 1)
    {
        update(y);
        if( y[0] > 0)
        {
            PORTB ^= 1 << PORTB1;
        }
        _delay_ms(1000);
    }
    return 0;
}

 

What accounts for these behaviors? Why are things so? Thanks. 

Last Edited: Mon. Dec 19, 2016 - 03:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The minimum support for float arithmetic in AVR (GCC) is 700 bytes which won't fit in your 512 of your micro so there is no float support for +-*/ let alone any of the libm.a functions. 

 

BTW in GCC sizeof(float)==sizeof(double) ==4 so don't expect added accuracy by using double it's all 24bit mantissa giving about 7.5 decimal digits of accuracy. 

 

If you want to use float in a micro then you probably need about 4K or more. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I had to guess, as y is not volatile, the "static" gave the compiler enough information to totally eliminate the trivial comparison which is the only floating point operation that I see.

 

I have no idea whether the toolchain actually supports floating point on that brain-dead family.  In particular as the Tiny4 only has 256 words of flash storage I doubt whether even a trivial program with any actual floating point operation would fit.  So a moot point?

 

[the initial value may well suck up a few more words...]

 

Just for fun, I poked your program into a CodeVision test program, and indeed it fits into 1/2 the flash. ;)  What I suspect is that the FP compare against 0 makes it a trivial comparison.   Changing the comparison to 1.20 instead of the 0 indeed pulls in the full FP comparison routine, but now a bit over 1/2 of flash.

 

 

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Dec 19, 2016 - 03:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you. But why the code with update(y) compiles is a mystery.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
I have no idea whether the toolchain actually supports floating point on that brain-dead family.

 

Thank you. I am just going to stay far away from this. Things appear to work by accident than by design.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But of course your code with update compiles, there's no need for it to include runtime float calculating code because it's a fixed literal known at compile time. I can tell you right now that 2.0 in 32bit IEEE754 format is 0x40000000

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> I have no idea whether the toolchain actually supports floating point on that brain-dead family.

 

It doesn't.

 

At least there is no library support, i.e. for any library function the compiler assumes it exists, you will have to supply your own implementation.

 

If you want to have fum with float (avr-gcc currently has only short double of 32 bits) you'll have to use a more reasonable hardware, i.e. a core with32 SFRs.  Or use the assembler route and write your routines :-)
 

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I can tell you right now that 2.0 in 32bit IEEE754 format is 0x40000000

Certainly what the CV code implied:

                 _update:
                 ;.FSTART _update
                 ;0000 0008     y[0] = 2.0;
000036 93aa      	ST   -Y,R26
                 ;	*y -> Y+0
000037 81a8      	LD   R26,Y
                +
000038 e0e0     +LDI R30 , LOW ( 0x40000000 )
000039 e0f0     +LDI R31 , HIGH ( 0x40000000 )
00003a e060     +LDI R22 , BYTE3 ( 0x40000000 )
00003b e470     +LDI R23 , BYTE4 ( 0x40000000 )
                 	__GETD1N 0x40000000

LogLog wrote:
Things appear to work by accident than by design.

???  Tell more about that.  Now, I'm guessing that your posted code is a stripped-down example that led you to the source of the problem.  Most/many of us would wonder why someone would code a 1-element array, and what the possible use of floating point on a Tiny4 might be.

 

Surely the toolchain that you have chosen to use has a manual that outlines specifications, and what is and is not supported for various chip families.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is the goal to: "Find the avr with the lowest cost that will run this c program with some fp in it"? Or find avr with smallest footprint? Or smallest power consumption? Or fastest performance?

 

Imagecraft compiler user