I'm trying to use this code for attiny10. Here, I try to use _delay_loop_2
but it does not work sometime.
#include <avr/io.h>
#include <util/delay.h>
#define LED_PIN PB0
#define DELAY_MAX 512
#define DELAY_MIN 1
int
main(void)
{
uint16_t delay = DELAY_MIN;
uint8_t dir = 0;
/* setup */
DDRB = 0b00000001; // set LED pin as OUTPUT
PORTB = 0b00000001; // set LED pin to HIGH
/* loop */
while (1) {
PORTB &= ~(_BV(LED_PIN)); // LED off
_delay_loop_2(delay);
PORTB |= _BV(LED_PIN); // LED on
_delay_loop_2(DELAY_MAX - delay);
if (dir) { // fade-in
if (++delay >= (DELAY_MAX - 1)) dir = 0;
} else { // fade-out
if (--delay <= DELAY_MIN) dir = 1;
}
}
}
But sometimes I get the error.
Processing attiny10 (platform: atmelavr; board: attiny10)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/attiny10.html
PLATFORM: Atmel AVR (4.0.0) > ATtiny10
HARDWARE: ATTINY10 1MHz, 32B RAM, 1KB Flash
PACKAGES:
- toolchain-atmelavr @ 1.50400.190710 (5.4.0)
LDF: Library Dependency Finder ->
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio/build/attiny10/src/main.o
Linking .pio/build/attiny10/firmware.elf
src/main.cpp: In function 'main':
/Users/user/.platformio/packages/[email protected]/avr/include/util/delay_basic.h:110:3: error: inconsistent operand constraints in an 'asm'
);
^
/Users/user/.platformio/packages/[email protected]/avr/include/util/delay_basic.h:110:3: error: inconsistent operand constraints in an 'asm'
);
^
lto-wrapper: fatal error: avr-g++ returned 1 exit status
compilation terminated.
/Users/user/.platformio/packages/[email protected]/bin/../lib/gcc/avr/5.4.0/../../../../avr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
*** [.pio/build/attiny10/firmware.elf] Error 1
My investigation showed the problem is here.
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
But if I change _delay_loop_2 on _delay_loop_1. There is no error anymore. Why does it happen? I use virtual studio and PlatformIO.
There is this bug reported against AVR-LibC: Extend _delay_loop_2 so it works with AVR_TINY.
Well, it's a pull request actually, so you see the solution to the bug. After applying the patch to include/util/delay_basic.h
, _delay_loop_2
will read:
void
_delay_loop_2 (uint16_t __count)
{
#if defined (__AVR_TINY__)
__asm__ volatile (
"1: subi %A0,1" "\n\t"
" sbci %B0,0" "\n\t"
"brne 1b"
: "+d" (__count)
);
#else
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "+w" (__count)
);
#endif /* AVR_TINY */
}
The problem was that register class w
is empty on reduced Cores, thus just fall back to 2-instruction subtraction with register class d
.
Better don't use stuff like _delay_loop_2 which is internal helper.
If you want to delay a specific number of cycles specified at compile-time, better use __builtin_avr_delay_cycles
, see https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/AVR-Built-in-Functions.html