Problems delaying with NOPs in AVR-GCC

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

Hi,

this might be more an AVR-GCC related question, but here goes anyway:

I would like to use NOP instructions for delaying 2 and 4 microseconds (at 8 MHz), since I'd like to control the delay more accurately than with the _delay_xxx functions (macros) in /util/delay.h allow. I am using the latest WinAVR package.

However no matter how I use the NOP in C (one example given in /compat/ina90.h), the compiler refuses to generate the NOP instructions, and thus they are not seen in the .lst file, and thus there is no delay. Fiddling around with optimization flags don't help, although I don't know if removing -O2 is sufficient.

How can I use the NOPs in my C code, or do I have to use the _delay_xxx macros?

Basically this is just a test of doing capacitive proximity sensing using charge transfer bursts like QProx chips do, but in software. I could do it with assembler too just for example, but it is just too easy to use printf to output something to serial port as a debugging measure ;-)

Thanks in advance,
- Jani

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

How are you attempting to generate NOPs? The C code:

  asm("nop");

should work and indeed clearly does:

19:       int main(void) { 
+0000005C:   E5CF        LDI     R28,0x5F         Load immediate
+0000005D:   E0D8        LDI     R29,0x08         Load immediate
+0000005E:   BFDE        OUT     0x3E,R29         Out to I/O location
+0000005F:   BFCD        OUT     0x3D,R28         Out to I/O location
20:       	asm("nop");
+00000060:   0000        NOP                      No operation
21:       	asm("nop");
+00000061:   0000        NOP                      No operation
22:       	asm("nop");
+00000062:   0000        NOP                      No operation
23:          DDRB = 0xFF; 
+00000063:   EF8F        SER     R24              Set Register
+00000064:   BB87        OUT     0x17,R24         Out to I/O location
2

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
asm volatile("nop");

The _delay_1() function is accurate to three CPU cycles, so you need at
most up to two additional NOPs I think.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Quote:
should work and indeed clearly does:

This is only guaranteed with optimizations turned off. As Jörg says, use volatile.

Regards,
Steve A.

The Board helps those that help themselves.

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

Hi all,

Thank you for your replies.

It is funny that saying

 asm("nop") 

directly in code works if optimizations are off.

Also saying

 asm volatile ("nop") 

directly in code works also when optimizations are on (-O2). I can live with that.

But what really puzzles me, is that if I have a define like

 #define nop() asm volatile ("nop")

, the nops are not generated when

 nop(); nop(); 

is written. This is also true when the ina90.h header is included and the nop define there is called :

 #define _NOP() do { __asm__ __volatile__ ("nop"); } while (0)
.
.
_NOP(); _NOP(); // this will not generate any nops  

OK, now I got the hang of the logic here. With or without optimizations, one

 asm volatile ("nop"); 

generates one nop in assembler. Writing several

 asm volatile ("nop"); 

lines will not generate any nops, with or without optimizations.

Should it be so? I know I'd like to generate multiple nops in a row :)

- Jani

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

What makes you believe it wouldn't work? It works perfectly:

foo.c:

#define nop() asm volatile("nop")

void
delay(void)
{
        nop();
        nop();
        nop();
}

Compiled with:

avr-gcc -O2 -mmcu=atmega128 -S foo.c

yields foo.s:

        .file   "foo.c"
        .arch atmega128
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
        .global __do_copy_data
        .global __do_clear_bss
        .text
.global delay
        .type   delay, @function
delay:
/* prologue: frame size=0 */
/* prologue end (size=0) */
/* #APP */
        nop
        nop
        nop
/* #NOAPP */
/* epilogue: frame size=0 */
        ret
/* epilogue end (size=1) */
/* function delay size 7 (6) */
        .size   delay, .-delay
/* File "foo.c": code    7 = 0x0007 (   6), prologues   0, epilogues   1 */

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Koshchi wrote:
This is only guaranteed with optimizations turned off. As Jörg says, use volatile.

I wondered about that and yet my example above was built with -Os and they remained and now I just rebuilt with all of -O0, -O1, -O2, -O3 and they remained in all cases too? So in what cirumstances will the optimiser remove them if not "volatile" ?

Cliff

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

> So in what cirumstances will the optimiser remove them if not "volatile"?

They will never be removed, but without the volatile, the compiler is free
to move the asm statements to a different location within the function
as it sees fit. At least, that's the description they gave in the GCC manual.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

dl8dtl wrote:
> So in what cirumstances will the optimiser remove them if not "volatile"? They will never be removed, but without the volatile, the compiler is free to move the asm statements to a different location within the function as it sees fit. At least, that's the description they gave in the GCC manual.
Not quite.

A non-volatile asm can be moved or removed in accordance with the as-if rule.

The compiler is still free to move. but not remove reachable asm volatile statements in accordance with the as-if rule.

The volatile is a warning to the compiler that the statement has invisible side effects.

Apparently gcc ignores those side effects when deciding to where an asm volatile can be moved.

There is no volatile-specific rule that prevents gcc from reordering asm volatiles with respect to each other,

but IO constraints might accomplish that task.

 

An asm without outputs is treated as implicitly volatile.

 

 

Edit: just noted that I replied to a rather old thread.  gcc might have changed since then.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

Last Edited: Wed. May 3, 2017 - 06:41 AM