Noticed a mistake in the AVR toolchain!

Hi all,

I've found that the "[b]_BV()[/b]" macro fails if the bit position is larger than 14.

This is because the _BV macro is defined wrong.

If you want to fix yours, locate the file [b]sfr_defs.h[/b] in your AVR toolchain. Around line 208 in the file (varies depending on which version of GCC you have in your toolchain), locate the line highlighted in red:


[b]/** \def _BV
    \ingroup avr_sfr

    \code #include <avr/io.h>\endcode

    Converts a bit number into a byte value.

    \note The bit shift is performed by the compiler which then inserts the
    result into the code. Thus, there is no run-time overhead when using
    _BV(). */

[color=red]#define _BV(bit) (1 << (bit))[/color]

/*@}*/[/b]

Change that line to this (the change is highlighted in red):

** **#define _BV(bit) (1[color=red]ULL[/color] << (bit))** **

That is, add "ULL" after the "1".

The reason the original fails is that "1" all by itself in a define is an INT, and being a signed 16 bit number cannot be shifted left more than 14 times without trashing it's value.

Changing it explicitly to "1ULL" makes in an unsigned long-long (i.e. a 64 bit number) which can accurately shift left up to 63 bits.

The error shows itself in code such as this:

    // send 32 bit frequency tuning word
    for (n = 0; n < 32; n++) {
        (_freq & _BV(n)) ? *_DATA_PORT |= _DATA_BIT : *_DATA_PORT &= ~_DATA_BIT; // send a bit
        *_CLOCK_PORT |= _CLOCK_BIT; // clock it in
        *_CLOCK_PORT &= ~_CLOCK_BIT;
    }

The value of "_BV(n)" fails when "n" is larger than 14, which makes the code fail. Patching the _BV macro fixes the problem.

Hope this helps someone.....

We have discussed this at least once before...

http://forum.arduino.cc/index.php?topic=283916.0

(You really need to force yourself to forget about _BV and just use bit.)

Or you can use the bit operators directly like a real C programmer.
/flame

I must be getting old and senile. I didn't recall ever discussing this before... until I looked at the old thread you linked to.

When you say "use bit"... the "bit" macro is defined in Arduino.h and it's the same thing as _BV() (except for the "UL" thing).

I'm so used to using _BV that it will be difficult to change my ways :slight_smile:

Do you think using "UL" is better than using "ULL"? Do you know... will the compiler optimize it to less than 64 bits if, say, 8 or 16 or 32 bits are used?

Thanks......

krupski:
I'm so used to using _BV that it will be difficult to change my ways :slight_smile:

You could add something like this to Arduino.h or, even better, to a header file completely under your control...

#undef _BV
#define _BV(v) bit(v)

...or...

#undef _BV
#define _BV(v) (1UL<<(v))

Do you think using "UL" is better than using "ULL"?

Absolutely!

Do you know... will the compiler optimize it to less than 64 bits if, say, 8 or 16 or 32 bits are used?

It works the other way around. You would be forcing the compiler to use 64 bit arithmetic. A typecast ((uint8_t)_BV(3); where _BV(v) is (1ULL<<(v))) solves that problem but you have to remember to include a typecast with every _BV.

Alternatively you could use something like @robtillaart proposed: a macro the expands to different datatypes depending on the parameter. I have not tested it so I cannot say if it is a good idea. It is definitely a bad idea for variables (like your example above).