avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] [Bug] Initialization for _delay_loop_2 Optimized Out


From: Dave Hansen
Subject: [avr-gcc-list] [Bug] Initialization for _delay_loop_2 Optimized Out
Date: Wed, 23 Jul 2003 18:29:06 -0400

This is my first post to the list. Please forgive me if I do something wrong...

I'm using WinAVR on Win98.

C:\Dave>avr-gcc -v
Reading specs from C:\WINAVR\BIN\..\lib\gcc-lib\avr\3.3\specs
Configured with: ../configure --prefix=/e/avrdev/install --target=avr --enable-l
anguages=c,c++ --disable-nls
Thread model: single
gcc version 3.3 20030421 (prerelease)

The command line options from my makefile are as follows:
CC          =   avr-gcc
MCU         =   atmega32
HZ          =   12000000
APPDEFS     =
CFLAGS      =   -mmcu=$(MCU) -D OSC_FREQ=$(HZ) $(APPDEFS) -I.\
               -g -Os -funsigned-char -funsigned-bitfields -fpack-struct \
-fshort-enums -Wall -Wstrict-prototypes -Wa,-ahlms=$(<:.c=.lst)
%.o : %.c
        $(CC) -c $(CFLAGS) $< -o $@ 2> $(<:.c=.err)

The bug is demonstrated by the following code:

--- begin included file ---
#include <avr/io.h>
#include <avr/delay.h>

typedef unsigned int U16;

#define CLOCKS_PER_US   ((U16)(OSC_FREQ/1000000))
#define CLOCKS_PER_LOOP 4

#define delay_us1(t) do{U16 c = (t)*CLOCKS_PER_US/CLOCKS_PER_LOOP; \
                     _delay_loop_2(c); }while(0);


static inline void
my_delay_loop(unsigned int __count)
{
   if (__count)
   {
       asm volatile (
           "1: sbiw %0,1" "\n\t"
           "brne 1b"
           : "=w" (__count)
           : "0" (__count)
       );
   }
}

#define delay_us2(t) do{U16 c = (t)*CLOCKS_PER_US/CLOCKS_PER_LOOP; \
                     my_delay_loop(c); }while(0);

int main(void)
{
   PORTA = 0;
   DDRA = 1;
   while(1)
   {
       PORTA ^= 1;
       delay_us1(1);
       delay_us2(1);
   }

   return 0;
}
--- end included file ---

When compiled, the code for the loop in main looks like this (from the .LSS file)

--- begin included file ---
   while(1)
   {
       PORTA ^= 1;
 9c:    8b b3           in      r24, 0x1b       ; 27
 9e:    91 e0           ldi     r25, 0x01       ; 1
 a0:    89 27           eor     r24, r25
 a2:    8b bb           out     0x1b, r24       ; 27
/* 16-bit count, 4 cycles/loop */
static inline void
_delay_loop_2(unsigned int __count)
{
        asm volatile (
 a4:    31 97           sbiw    r30, 0x01       ; 1
 a6:    f1 f7           brne    .-4             ; 0xa4
       delay_us1(1);
       delay_us2(1);
 a8:    83 e0           ldi     r24, 0x03       ; 3
 aa:    90 e0           ldi     r25, 0x00       ; 0
 ac:    01 97           sbiw    r24, 0x01       ; 1
 ae:    f1 f7           brne    .-4             ; 0xac
 b0:    f5 cf           rjmp    .-22            ; 0x9c
--- end included file ---

Note that my_delay_loop is a copy of _delay_loop_2 from avr/delay.h, with the test for __count != 0 added.

Note also that the call to delay_us1 (which uses _delay_loop_2) does not initialize r30 before decrementing it. Not good. Using delay_us2, which uses my_delay_loop rather than _delay_loop_2, results in correct code.

I suspect that since __count is not used in _delay_loop_2 other than in the inline assembly, it is essentially being optimized out, leaving r30 uninitialized. By adding the test for __count != 0 in my_delay_loop, I'm using the parameter in the C code, so it keeps the initialization. That's my guess anyway.

My workaround is to use my_delay_loop rather than _delay_loop_2. This provides the additional benefit that passing zero to the delay function does not wait the maximum amount of time (about 5.5 ms in my case).

Regards,
  -=Dave

_________________________________________________________________
The new MSN 8: advanced junk mail protection and 2 months FREE* http://join.msn.com/?page=features/junkmail



reply via email to

[Prev in Thread] Current Thread [Next in Thread]